/
remove_child.go
116 lines (105 loc) · 3.76 KB
/
remove_child.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package groups
import (
"net/http"
"github.com/go-chi/render"
"github.com/France-ioi/AlgoreaBackend/app/database"
"github.com/France-ioi/AlgoreaBackend/app/service"
)
// swagger:operation DELETE /groups/{parent_group_id}/relations/{child_group_id} group-memberships groupRemoveChild
//
// ---
// summary: Remove a subgroup
// description: >
// Removes a child group from a parent group and optionally deletes that group and its subgroups.
//
//
// Deletes the relation from `groups_groups`. If `{delete_orphans}` is true and the child group becomes an orphan
// then the service also deletes that group, its parent-child relations, and recursively deletes each
// new orphaned group.
//
//
// If `{delete_orphans}` is false and the child removal makes it an orphan (it doesn't have other parent groups),
// the service deletes the relation keeping the orphaned child group.
//
//
// If a group gets deleted, the service also deletes `groups_groups`, `attempts`, `results`,
// `group_membership_changes`, `group_pending_requests`,
// `permissions_granted`, `permissions_generated`, and `filters` linked to the group.
// Access rights are updated accordingly too.
//
//
// Restrictions (otherwise the 'forbidden' error is returned):
// * the authenticated user should be a manager of both `{parent_group_id}` and `{child_group_id}`,
// * the authenticated user should have `can_manage` >= 'memberships' on the `{parent_group_id}`,
// * the parent group should not be of type "User" or "Team",
// * the child group should not be of types "Base" or "User"
// (since there are more appropriate services for removing users from groups: groupLeave and groupRemoveMembers).
// parameters:
// - name: parent_group_id
// in: path
// type: integer
// format: int64
// required: true
// - name: child_group_id
// in: path
// type: integer
// format: int64
// required: true
// - name: delete_orphans
// in: query
// type: integer
// enum: [0,1]
// default: 0
// responses:
// "201":
// "$ref": "#/responses/deletedResponse"
// "400":
// "$ref": "#/responses/badRequestResponse"
// "401":
// "$ref": "#/responses/unauthorizedResponse"
// "403":
// "$ref": "#/responses/forbiddenResponse"
// "500":
// "$ref": "#/responses/internalErrorResponse"
func (srv *Service) removeChild(w http.ResponseWriter, r *http.Request) service.APIError {
parentGroupID, err := service.ResolveURLQueryPathInt64Field(r, "parent_group_id")
if err != nil {
return service.ErrInvalidRequest(err)
}
childGroupID, err := service.ResolveURLQueryPathInt64Field(r, "child_group_id")
if err != nil {
return service.ErrInvalidRequest(err)
}
shouldDeleteOrphans := false
if len(r.URL.Query()["delete_orphans"]) > 0 {
shouldDeleteOrphans, err = service.ResolveURLQueryGetBoolField(r, "delete_orphans")
if err != nil {
return service.ErrInvalidRequest(err)
}
}
user := srv.GetUser(r)
apiErr := service.NoError
err = srv.GetStore(r).InTransaction(func(s *database.DataStore) error {
apiErr = checkThatUserHasRightsForDirectRelation(s, user, parentGroupID, childGroupID, deleteRelation)
if apiErr != service.NoError {
return apiErr.Error // rollback
}
// Check that the relation exists
var result []struct{}
service.MustNotBeError(s.ActiveGroupGroups().WithWriteLock().
Where("parent_group_id = ?", parentGroupID).
Where("child_group_id = ?", childGroupID).
Take(&result).Error())
if len(result) == 0 {
apiErr = service.InsufficientAccessRightsError
return apiErr.Error // rollback
}
return s.GroupGroups().DeleteRelation(parentGroupID, childGroupID, shouldDeleteOrphans)
})
if apiErr != service.NoError {
return apiErr
}
service.MustNotBeError(err)
service.MustNotBeError(render.Render(w, r, service.DeletionSuccess(nil)))
return service.NoError
}