func()

in lib/scim/scim_group.go [253:326]


func (h *GroupHandler) Patch(r *http.Request, name string) (proto.Message, error) {
	h.save = &spb.Group{}
	proto.Merge(h.save, h.item)
	memberCounter := 0
	for i, patch := range h.patch.Operations {
		path := patch.Path
		if memberPathRE.MatchString(path) {
			path = "member"
		}
		src := ""
		var dst *string
		switch path {
		case "displayName":
			src = patchSource(patch.Value)
			dst = &h.save.DisplayName
			if patch.Op == "remove" || len(src) == 0 {
				return nil, errutil.NewIndexError(codes.InvalidArgument, errutil.ErrorPath("scim", "groups", name, path), i, fmt.Sprintf("value must not be empty"))
			}

		case "members":
			if patch.Op != "add" {
				return nil, errutil.NewIndexError(codes.InvalidArgument, errutil.ErrorPath("scim", "groups", name, path), i, fmt.Sprintf("op %q is not valid", patch.Op))
			}
			member, err := h.patchMember(patch.Object, name, memberCounter)
			if err != nil {
				return nil, err
			}
			memberCounter++
			if err := h.store.WriteTx(storage.GroupMemberDatatype, getRealm(r), name, member.Value, storage.LatestRev, member, nil, h.tx); err != nil {
				return nil, errutil.NewIndexError(codes.InvalidArgument, errutil.ErrorPath("scim", "groups", name, path), i, err.Error())
			}

		case "member":
			if patch.Op != "remove" {
				return nil, errutil.NewIndexError(codes.InvalidArgument, errutil.ErrorPath("scim", "groups", name, path), i, fmt.Sprintf("op %q is not valid", patch.Op))
			}
			match := memberPathRE.FindStringSubmatch(patch.Path)
			if len(match) < 2 {
				return nil, errutil.NewIndexError(codes.InvalidArgument, errutil.ErrorPath("scim", "groups", name, path), i, fmt.Sprintf("invalid member path %q", patch.Path))
			}
			memberName := match[1]
			if err := h.store.DeleteTx(storage.GroupMemberDatatype, getRealm(r), name, memberName, storage.LatestRev, h.tx); err != nil {
				if storage.ErrNotFound(err) {
					return nil, errutil.NewIndexError(codes.InvalidArgument, errutil.ErrorPath("scim", "groups", name, path), i, fmt.Sprintf("%q is not a member of the group", memberName))
				}
				return nil, errutil.NewIndexError(codes.InvalidArgument, errutil.ErrorPath("scim", "groups", name, path), i, err.Error())
			}

		default:
			return nil, errutil.NewIndexError(codes.InvalidArgument, errutil.ErrorPath("scim", "groups", name, path), i, fmt.Sprintf("invalid path %q", patch.Path))
		}
		if dst == nil {
			continue
		}
		if patch.Op != "remove" && len(src) == 0 {
			return nil, errutil.NewIndexError(codes.InvalidArgument, errutil.ErrorPath("scim", "groups", name, path), i, fmt.Sprintf("cannot set an empty value"))
		}
		switch patch.Op {
		case "add":
			fallthrough
		case "replace":
			*dst = src
		case "remove":
			*dst = ""
		default:
			return nil, errutil.NewIndexError(codes.InvalidArgument, errutil.ErrorPath("scim", "groups", name, path), i, fmt.Sprintf("invalid op %q", patch.Op))
		}
	}
	// Output the new result: Get() will return contents from h.item with the latest edits from h.save.
	// Needs a deep copy since h.save as the item saved will not include members once Save() is called
	// but the item returned to the client will include members.
	h.item = proto.Clone(h.save).(*spb.Group)
	return h.Get(r, name)
}