@@ -31,6 +31,7 @@ type Backend interface {
3131 ListAddressBooks (ctx context.Context ) ([]AddressBook , error )
3232 GetAddressBook (ctx context.Context , path string ) (* AddressBook , error )
3333 CreateAddressBook (ctx context.Context , addressBook * AddressBook ) error
34+ UpdateAddressBook (ctx context.Context , addressBook * AddressBook ) error
3435 DeleteAddressBook (ctx context.Context , path string ) error
3536 GetAddressObject (ctx context.Context , path string , req * AddressDataRequest ) (* AddressObject , error )
3637 ListAddressObjects (ctx context.Context , path string , req * AddressDataRequest ) ([]AddressObject , error )
@@ -614,43 +615,160 @@ func (b *backend) propFindAllAddressObjects(ctx context.Context, propfind *inter
614615}
615616
616617func (b * backend ) PropPatch (r * http.Request , update * internal.PropertyUpdate ) (* internal.Response , error ) {
617- homeSetPath , err := b .Backend .AddressBookHomeSetPath (r .Context ())
618- if err != nil {
619- return nil , err
620- }
621-
618+ resType := b .resourceTypeAtPath (r .URL .Path )
622619 resp := internal .NewOKResponse (r .URL .Path )
623620
624- if r .URL .Path == homeSetPath {
625- // TODO: support PROPPATCH for address books
621+ switch resType {
622+ case resourceTypeAddressBook :
623+ ab , err := b .Backend .GetAddressBook (r .Context (), r .URL .Path )
624+ if err != nil {
625+ return nil , err
626+ }
627+ err = b .propPatchAddressBook (r .Context (), update , ab , resp )
628+ if err != nil {
629+ return nil , err
630+ }
631+ err = b .Backend .UpdateAddressBook (r .Context (), ab )
632+ if err != nil {
633+ return nil , err
634+ }
635+ case resourceTypeAddressObject :
636+ dataReq := AddressDataRequest {AllProp : true }
637+ ao , err := b .Backend .GetAddressObject (r .Context (), r .URL .Path , & dataReq )
638+ if err != nil {
639+ return nil , err
640+ }
641+ // TODO: support PROPPATCH for address objects
642+ err = b .propPatchAddressObject (r .Context (), update , ao , resp )
643+ if err != nil {
644+ return nil , err
645+ }
646+ // TODO: interface for updating contacts?
647+ //err = b.Backend.UpdateAddressObject(r.Context(), ab)
648+ //if err != nil {
649+ // return nil, err
650+ //}
651+ default :
626652 for _ , prop := range update .Remove {
627- emptyVal := internal .NewRawXMLElement (prop .Prop .XMLName , nil , nil )
628- if err := resp .EncodeProp (http .StatusNotImplemented , emptyVal ); err != nil {
629- return nil , err
653+ for _ , raw := range prop .Prop .Raw {
654+ rxn , ok := raw .XMLName ()
655+ if ! ok {
656+ return nil , fmt .Errorf ("failed to parse properties" )
657+ }
658+ emptyVal := internal .NewRawXMLElement (rxn , nil , nil )
659+ if err := resp .EncodeProp (http .StatusMethodNotAllowed , emptyVal ); err != nil {
660+ return nil , err
661+ }
630662 }
631663 }
632664 for _ , prop := range update .Set {
633- emptyVal := internal .NewRawXMLElement (prop .Prop .XMLName , nil , nil )
634- if err := resp .EncodeProp (http .StatusNotImplemented , emptyVal ); err != nil {
635- return nil , err
665+ for _ , raw := range prop .Prop .Raw {
666+ rxn , ok := raw .XMLName ()
667+ if ! ok {
668+ return nil , fmt .Errorf ("failed to parse properties" )
669+ }
670+ emptyVal := internal .NewRawXMLElement (rxn , nil , nil )
671+ if err := resp .EncodeProp (http .StatusMethodNotAllowed , emptyVal ); err != nil {
672+ return nil , err
673+ }
636674 }
637675 }
638- } else {
639- for _ , prop := range update .Remove {
640- emptyVal := internal .NewRawXMLElement (prop .Prop .XMLName , nil , nil )
641- if err := resp .EncodeProp (http .StatusMethodNotAllowed , emptyVal ); err != nil {
642- return nil , err
676+ }
677+ return resp , nil
678+ }
679+
680+ func (b * backend ) propPatchAddressBook (ctx context.Context , update * internal.PropertyUpdate , ab * AddressBook , resp * internal.Response ) error {
681+ // TODO handle all properties
682+ var (
683+ name internal.DisplayName
684+ desc addressbookDescription
685+ )
686+ for _ , prop := range update .Remove {
687+ for _ , raw := range prop .Prop .Raw {
688+ rxn , ok := raw .XMLName ()
689+ if ! ok {
690+ return fmt .Errorf ("failed to parse properties" )
691+ }
692+ switch rxn {
693+ case internal .DisplayNameName :
694+ ab .Name = ""
695+ if err := resp .EncodeProp (http .StatusOK , internal.DisplayName {}); err != nil {
696+ return err
697+ }
698+ case addressBookDescriptionName :
699+ ab .Description = ""
700+ if err := resp .EncodeProp (http .StatusOK , desc ); err != nil {
701+ return err
702+ }
703+ default :
704+ emptyVal := internal .NewRawXMLElement (rxn , nil , nil )
705+ if err := resp .EncodeProp (http .StatusNotImplemented , emptyVal ); err != nil {
706+ return err
707+ }
643708 }
644709 }
645- for _ , prop := range update .Set {
646- emptyVal := internal .NewRawXMLElement (prop .Prop .XMLName , nil , nil )
647- if err := resp .EncodeProp (http .StatusMethodNotAllowed , emptyVal ); err != nil {
648- return nil , err
710+ }
711+ for _ , prop := range update .Set {
712+ for _ , raw := range prop .Prop .Raw {
713+ rxn , ok := raw .XMLName ()
714+ if ! ok {
715+ return fmt .Errorf ("failed to parse properties" )
716+ }
717+ switch rxn {
718+ case internal .DisplayNameName :
719+ if err := raw .Decode (& name ); err != nil {
720+ return err
721+ }
722+ ab .Name = name .Name
723+ if err := resp .EncodeProp (http .StatusOK , internal.DisplayName {}); err != nil {
724+ return err
725+ }
726+ case addressBookDescriptionName :
727+ if err := raw .Decode (& desc ); err != nil {
728+ return err
729+ }
730+ ab .Description = desc .Description
731+ if err := resp .EncodeProp (http .StatusOK , desc ); err != nil {
732+ return err
733+ }
734+ default :
735+ emptyVal := internal .NewRawXMLElement (rxn , nil , nil )
736+ if err := resp .EncodeProp (http .StatusNotImplemented , emptyVal ); err != nil {
737+ return err
738+ }
649739 }
650740 }
651741 }
742+ return nil
743+ }
652744
653- return resp , nil
745+ func (b * backend ) propPatchAddressObject (ctx context.Context , update * internal.PropertyUpdate , ao * AddressObject , resp * internal.Response ) error {
746+ // TODO: support PROPPATCH for address objects
747+ for _ , prop := range update .Remove {
748+ for _ , raw := range prop .Prop .Raw {
749+ rxn , ok := raw .XMLName ()
750+ if ! ok {
751+ return fmt .Errorf ("failed to parse properties" )
752+ }
753+ emptyVal := internal .NewRawXMLElement (rxn , nil , nil )
754+ if err := resp .EncodeProp (http .StatusNotImplemented , emptyVal ); err != nil {
755+ return err
756+ }
757+ }
758+ }
759+ for _ , prop := range update .Set {
760+ for _ , raw := range prop .Prop .Raw {
761+ rxn , ok := raw .XMLName ()
762+ if ! ok {
763+ return fmt .Errorf ("failed to parse properties" )
764+ }
765+ emptyVal := internal .NewRawXMLElement (rxn , nil , nil )
766+ if err := resp .EncodeProp (http .StatusNotImplemented , emptyVal ); err != nil {
767+ return err
768+ }
769+ }
770+ }
771+ return nil
654772}
655773
656774func (b * backend ) Put (r * http.Request ) (* internal.Href , error ) {
0 commit comments