• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vocdoni / saas-backend / 18739492213

23 Oct 2025 06:17AM UTC coverage: 60.079% (-0.2%) from 60.245%
18739492213

push

github

altergui
db: dedup pagination code using paginatedDocuments

33 of 41 new or added lines in 5 files covered. (80.49%)

307 existing lines in 7 files now uncovered.

6113 of 10175 relevant lines covered (60.08%)

36.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.25
/api/organization_groups.go
1
package api
2

3
import (
4
        "encoding/json"
5
        "net/http"
6

7
        "github.com/go-chi/chi/v5"
8
        "github.com/vocdoni/saas-backend/api/apicommon"
9
        "github.com/vocdoni/saas-backend/db"
10
        "github.com/vocdoni/saas-backend/errors"
11
        "go.vocdoni.io/dvote/log"
12
)
13

14
// organizationMemberGroupsHandler godoc
15
//
16
//        @Summary                Get organization member groups
17
//        @Description        Get the list of groups and their info of the organization
18
//        @Description        Does not return the members of the groups, only the groups themselves.
19
//        @Description        Needs admin or manager role
20
//        @Tags                        organizations
21
//        @Accept                        json
22
//        @Produce                json
23
//        @Security                BearerAuth
24
//        @Param                        address        path                string        true        "Organization address"
25
//        @Param                        page        query                integer        false        "Page number (default: 1)"
26
//        @Param                        limit        query                integer        false        "Number of items per page (default: 10)"
27
//        @Success                200                {object}        apicommon.OrganizationMemberGroupsResponse
28
//        @Failure                400                {object}        errors.Error        "Invalid input data"
29
//        @Failure                401                {object}        errors.Error        "Unauthorized"
30
//        @Failure                404                {object}        errors.Error        "Organization not found"
31
//        @Failure                500                {object}        errors.Error        "Internal server error"
32
//        @Router                        /organizations/{address}/groups [get]
33
func (a *API) organizationMemberGroupsHandler(w http.ResponseWriter, r *http.Request) {
6✔
34
        // get the user from the request context
6✔
35
        user, ok := apicommon.UserFromContext(r.Context())
6✔
36
        if !ok {
6✔
UNCOV
37
                errors.ErrUnauthorized.Write(w)
×
38
                return
×
39
        }
×
40
        // get the organization info from the request context
41
        org, _, ok := a.organizationFromRequest(r)
6✔
42
        if !ok {
7✔
43
                errors.ErrNoOrganizationProvided.Write(w)
1✔
44
                return
1✔
45
        }
1✔
46
        if !user.HasRoleFor(org.Address, db.AdminRole) && !user.HasRoleFor(org.Address, db.ManagerRole) {
6✔
47
                // if the user is not admin or manager of the organization, return an error
1✔
48
                errors.ErrUnauthorized.Withf("user is not admin of organization").Write(w)
1✔
49
                return
1✔
50
        }
1✔
51
        params, err := parsePaginationParams(r.URL.Query().Get(ParamPage), r.URL.Query().Get(ParamLimit))
4✔
52
        if err != nil {
4✔
UNCOV
53
                errors.ErrMalformedURLParam.WithErr(err).Write(w)
×
UNCOV
54
                return
×
UNCOV
55
        }
×
56
        // send the organization back to the user
57
        totalItems, groups, err := a.db.OrganizationMemberGroups(org.Address, params.Page, params.Limit)
4✔
58
        if err != nil {
4✔
59
                errors.ErrGenericInternalServerError.Withf("could not get organization members: %v", err).Write(w)
×
60
                return
×
UNCOV
61
        }
×
62
        pagination, err := calculatePagination(params.Page, params.Limit, totalItems)
4✔
63
        if err != nil {
4✔
64
                errors.ErrMalformedURLParam.WithErr(err).Write(w)
×
65
                return
×
66
        }
×
67

68
        memberGroups := apicommon.OrganizationMemberGroupsResponse{
4✔
69
                Pagination: pagination,
4✔
70
                Groups:     make([]*apicommon.OrganizationMemberGroupInfo, 0, len(groups)),
4✔
71
        }
4✔
72
        for _, group := range groups {
11✔
73
                memberGroups.Groups = append(memberGroups.Groups, &apicommon.OrganizationMemberGroupInfo{
7✔
74
                        ID:           group.ID.Hex(),
7✔
75
                        Title:        group.Title,
7✔
76
                        Description:  group.Description,
7✔
77
                        CreatedAt:    group.CreatedAt,
7✔
78
                        UpdatedAt:    group.UpdatedAt,
7✔
79
                        CensusIDs:    group.CensusIDs,
7✔
80
                        MembersCount: len(group.MemberIDs),
7✔
81
                })
7✔
82
        }
7✔
83
        apicommon.HTTPWriteJSON(w, memberGroups)
4✔
84
}
85

86
// organizationMemberGroupHandler godoc
87
//
88
//        @Summary                Get the information of an organization member group
89
//        @Description        Get the information of an organization member group by its ID
90
//        @Description        Needs admin or manager role
91
//        @Tags                        organizations
92
//        @Accept                        json
93
//        @Produce                json
94
//        @Security                BearerAuth
95
//        @Param                        address        path                string        true        "Organization address"
96
//        @Param                        groupID        path                string        true        "Group ID"
97
//        @Success                200                {object}        apicommon.OrganizationMemberGroupInfo
98
//        @Failure                400                {object}        errors.Error        "Invalid input data"
99
//        @Failure                401                {object}        errors.Error        "Unauthorized"
100
//        @Failure                404                {object}        errors.Error        "Organization or group not found"
101
//        @Failure                500                {object}        errors.Error        "Internal server error"
102
//        @Router                        /organizations/{address}/groups/{groupID} [get]
103
func (a *API) organizationMemberGroupHandler(w http.ResponseWriter, r *http.Request) {
9✔
104
        // get the group ID from the request path
9✔
105
        groupID := chi.URLParam(r, "groupID")
9✔
106
        if groupID == "" {
9✔
UNCOV
107
                errors.ErrInvalidData.Withf("group ID is required").Write(w)
×
UNCOV
108
                return
×
UNCOV
109
        }
×
110
        // get the user from the request context
111
        user, ok := apicommon.UserFromContext(r.Context())
9✔
112
        if !ok {
9✔
UNCOV
113
                errors.ErrUnauthorized.Write(w)
×
UNCOV
114
                return
×
115
        }
×
116
        // get the organization info from the request context
117
        org, _, ok := a.organizationFromRequest(r)
9✔
118
        if !ok {
9✔
UNCOV
119
                errors.ErrNoOrganizationProvided.Write(w)
×
UNCOV
120
                return
×
121
        }
×
122
        if !user.HasRoleFor(org.Address, db.AdminRole) && !user.HasRoleFor(org.Address, db.ManagerRole) {
9✔
123
                // if the user is not admin or manager of the organization, return an error
×
UNCOV
124
                errors.ErrUnauthorized.Withf("user is not admin of organization").Write(w)
×
UNCOV
125
                return
×
UNCOV
126
        }
×
127

128
        group, err := a.db.OrganizationMemberGroup(groupID, org.Address)
9✔
129
        if err != nil {
11✔
130
                if err == db.ErrNotFound {
3✔
131
                        errors.ErrInvalidData.Withf("group not found").Write(w)
1✔
132
                        return
1✔
133
                }
1✔
134
                errors.ErrGenericInternalServerError.Withf("could not get organization member group: %v", err).Write(w)
1✔
135
                return
1✔
136
        }
137
        apicommon.HTTPWriteJSON(w, &apicommon.OrganizationMemberGroupInfo{
7✔
138
                ID:          group.ID.Hex(),
7✔
139
                Title:       group.Title,
7✔
140
                Description: group.Description,
7✔
141
                MemberIDs:   group.MemberIDs,
7✔
142
                CensusIDs:   group.CensusIDs,
7✔
143
                CreatedAt:   group.CreatedAt,
7✔
144
                UpdatedAt:   group.UpdatedAt,
7✔
145
        })
7✔
146
}
147

148
// createOrganizationMemberGroupHandler godoc
149
//
150
//        @Summary                Create an organization member group
151
//        @Description        Create an organization member group with the given members or all members
152
//        @Description        Needs admin or manager role
153
//        @Tags                        organizations
154
//        @Accept                        json
155
//        @Produce                json
156
//        @Security                BearerAuth
157
//        @Param                        address        path                string                                                                                        true        "Organization address"
158
//        @Param                        group        body                apicommon.CreateOrganizationMemberGroupRequest        true        "Group info to create"
159
//        @Success                200                {object}        apicommon.OrganizationMemberGroupInfo
160
//        @Failure                400                {object}        errors.Error        "Invalid input data"
161
//        @Failure                401                {object}        errors.Error        "Unauthorized"
162
//        @Failure                404                {object}        errors.Error        "Organization not found"
163
//        @Failure                500                {object}        errors.Error        "Internal server error"
164
//        @Router                        /organizations/{address}/groups [post]
165
func (a *API) createOrganizationMemberGroupHandler(w http.ResponseWriter, r *http.Request) {
21✔
166
        // get the user from the request context
21✔
167
        user, ok := apicommon.UserFromContext(r.Context())
21✔
168
        if !ok {
21✔
UNCOV
169
                errors.ErrUnauthorized.Write(w)
×
UNCOV
170
                return
×
UNCOV
171
        }
×
172
        // get the organization info from the request context
173
        org, _, ok := a.organizationFromRequest(r)
21✔
174
        if !ok {
22✔
175
                errors.ErrNoOrganizationProvided.Write(w)
1✔
176
                return
1✔
177
        }
1✔
178
        if !user.HasRoleFor(org.Address, db.AdminRole) && !user.HasRoleFor(org.Address, db.ManagerRole) {
22✔
179
                // if the user is not admin or manager of the organization, return an error
2✔
180
                errors.ErrUnauthorized.Withf("user is not admin of organization").Write(w)
2✔
181
                return
2✔
182
        }
2✔
183

184
        var toCreate apicommon.CreateOrganizationMemberGroupRequest
18✔
185
        if err := json.NewDecoder(r.Body).Decode(&toCreate); err != nil {
18✔
UNCOV
186
                errors.ErrMalformedBody.Write(w)
×
UNCOV
187
                return
×
UNCOV
188
        }
×
189

190
        var memberIDs []string
18✔
191
        var err error
18✔
192

18✔
193
        // Check if we should include all members
18✔
194
        if toCreate.IncludeAllMembers {
21✔
195
                // Get all member IDs from the database
3✔
196
                memberIDs, err = a.db.GetAllOrgMemberIDs(org.Address)
3✔
197
                if err != nil {
3✔
UNCOV
198
                        errors.ErrGenericInternalServerError.Withf("could not get all org member IDs: %v", err).Write(w)
×
UNCOV
199
                        return
×
UNCOV
200
                }
×
201
                log.Infow("creating group with all organization members",
3✔
202
                        "org", org.Address.Hex(),
3✔
203
                        "count", len(memberIDs),
3✔
204
                        "user", user.Email,
3✔
205
                        "title", toCreate.Title)
3✔
206
        } else {
15✔
207
                // Use the provided member IDs
15✔
208
                memberIDs = toCreate.MemberIDs
15✔
209
        }
15✔
210

211
        newMemberGroup := &db.OrganizationMemberGroup{
18✔
212
                Title:       toCreate.Title,
18✔
213
                Description: toCreate.Description,
18✔
214
                MemberIDs:   memberIDs,
18✔
215
                OrgAddress:  org.Address,
18✔
216
        }
18✔
217

18✔
218
        groupID, err := a.db.CreateOrganizationMemberGroup(newMemberGroup)
18✔
219
        if err != nil {
20✔
220
                if err == db.ErrNotFound {
2✔
UNCOV
221
                        errors.ErrInvalidData.Withf("organization not found").Write(w)
×
UNCOV
222
                        return
×
UNCOV
223
                }
×
224
                errors.ErrGenericInternalServerError.Withf("could not create organization member group: %v", err).Write(w)
2✔
225
                return
2✔
226
        }
227
        apicommon.HTTPWriteJSON(w, &apicommon.OrganizationMemberGroupInfo{
16✔
228
                ID: groupID,
16✔
229
        })
16✔
230
}
231

232
// updateOrganizationMemberGroupHandler godoc
233
//
234
//        @Summary                Update an organization member group
235
//        @Description        Update an organization member group changing the info, and adding or removing members
236
//        @Description        Needs admin or manager role
237
//        @Tags                        organizations
238
//        @Accept                        json
239
//        @Produce                json
240
//        @Security                BearerAuth
241
//        @Param                        address        path                string                                                                                        true        "Organization address"
242
//        @Param                        groupID        path                string                                                                                        true        "Group ID"
243
//        @Param                        group        body                apicommon.UpdateOrganizationMemberGroupsRequest        true        "Group info to update"
244
//        @Success                200                {string}        string                                                                                        "OK"
245
//        @Failure                400                {object}        errors.Error                                                                        "Invalid input data"
246
//        @Failure                401                {object}        errors.Error                                                                        "Unauthorized"
247
//        @Failure                404                {object}        errors.Error                                                                        "Organization or group not found"
248
//        @Failure                500                {object}        errors.Error                                                                        "Internal server error"
249
//        @Router                        /organizations/{address}/groups/{groupID} [put]
250
func (a *API) updateOrganizationMemberGroupHandler(w http.ResponseWriter, r *http.Request) {
5✔
251
        // get the group ID from the request path
5✔
252
        groupID := chi.URLParam(r, "groupID")
5✔
253
        if groupID == "" {
5✔
UNCOV
254
                errors.ErrInvalidData.Withf("group ID is required").Write(w)
×
UNCOV
255
                return
×
UNCOV
256
        }
×
257
        // get the user from the request context
258
        user, ok := apicommon.UserFromContext(r.Context())
5✔
259
        if !ok {
5✔
UNCOV
260
                errors.ErrUnauthorized.Write(w)
×
UNCOV
261
                return
×
262
        }
×
263
        // get the organization info from the request context
264
        org, _, ok := a.organizationFromRequest(r)
5✔
265
        if !ok {
5✔
UNCOV
266
                errors.ErrNoOrganizationProvided.Write(w)
×
UNCOV
267
                return
×
268
        }
×
269
        if !user.HasRoleFor(org.Address, db.AdminRole) && !user.HasRoleFor(org.Address, db.ManagerRole) {
6✔
270
                // if the user is not admin or manager of the organization, return an error
1✔
271
                errors.ErrUnauthorized.Withf("user is not admin of organization").Write(w)
1✔
272
                return
1✔
273
        }
1✔
274

275
        var toUpdate apicommon.UpdateOrganizationMemberGroupsRequest
4✔
276
        if err := json.NewDecoder(r.Body).Decode(&toUpdate); err != nil {
4✔
UNCOV
277
                errors.ErrMalformedBody.Write(w)
×
UNCOV
278
                return
×
UNCOV
279
        }
×
280

281
        err := a.db.UpdateOrganizationMemberGroup(
4✔
282
                groupID,
4✔
283
                org.Address,
4✔
284
                toUpdate.Title,
4✔
285
                toUpdate.Description,
4✔
286
                toUpdate.AddMembers,
4✔
287
                toUpdate.RemoveMembers,
4✔
288
        )
4✔
289
        if err != nil {
5✔
290
                if err == db.ErrNotFound {
1✔
UNCOV
291
                        errors.ErrInvalidData.Withf("group not found").Write(w)
×
UNCOV
292
                        return
×
UNCOV
293
                }
×
294
                errors.ErrGenericInternalServerError.Withf("could not update organization member group: %v", err).Write(w)
1✔
295
                return
1✔
296
        }
297
        apicommon.HTTPWriteOK(w)
3✔
298
}
299

300
// deleteOrganizationMemberGroupHandler godoc
301
//
302
//        @Summary                Delete an organization member group
303
//        @Description        Delete an organization member group by its ID
304
//        @Tags                        organizations
305
//        @Accept                        json
306
//        @Produce                json
307
//        @Security                BearerAuth
308
//        @Param                        address        path                string                        true        "Organization address"
309
//        @Param                        groupID        path                string                        true        "Group ID"
310
//        @Success                200                {string}        string                        "OK"
311
//        @Failure                400                {object}        errors.Error        "Invalid input data"
312
//        @Failure                401                {object}        errors.Error        "Unauthorized"
313
//        @Failure                404                {object}        errors.Error        "Organization or group not found"
314
//        @Failure                500                {object}        errors.Error        "Internal server error"
315
//        @Router                        /organizations/{address}/groups/{groupID} [delete]
316
func (a *API) deleteOrganizationMemberGroupHandler(w http.ResponseWriter, r *http.Request) {
5✔
317
        // get the member ID from the request path
5✔
318
        groupID := chi.URLParam(r, "groupID")
5✔
319
        if groupID == "" {
5✔
UNCOV
320
                errors.ErrInvalidData.Withf("group ID is required").Write(w)
×
UNCOV
321
                return
×
UNCOV
322
        }
×
323
        // get the user from the request context
324
        user, ok := apicommon.UserFromContext(r.Context())
5✔
325
        if !ok {
5✔
UNCOV
326
                errors.ErrUnauthorized.Write(w)
×
UNCOV
327
                return
×
328
        }
×
329
        // get the organization info from the request context
330
        org, _, ok := a.organizationFromRequest(r)
5✔
331
        if !ok {
5✔
UNCOV
332
                errors.ErrNoOrganizationProvided.Write(w)
×
UNCOV
333
                return
×
334
        }
×
335
        if !user.HasRoleFor(org.Address, db.AdminRole) && !user.HasRoleFor(org.Address, db.ManagerRole) {
6✔
336
                // if the user is not admin or manager of the organization, return an error
1✔
337
                errors.ErrUnauthorized.Withf("user is not admin of organization").Write(w)
1✔
338
                return
1✔
339
        }
1✔
340
        if err := a.db.DeleteOrganizationMemberGroup(groupID, org.Address); err != nil {
5✔
341
                if err == db.ErrNotFound {
1✔
342
                        errors.ErrInvalidData.Withf("group not found").Write(w)
×
UNCOV
343
                        return
×
UNCOV
344
                }
×
345
                errors.ErrGenericInternalServerError.Withf("could not delete organization member group: %v", err).Write(w)
1✔
346
                return
1✔
347
        }
348
        apicommon.HTTPWriteOK(w)
3✔
349
}
350

351
// listOrganizationMemberGroupsHandler godoc
352
//
353
//        @Summary                Get the list of members with details of an organization member group
354
//        @Description        Get the list of members with details of an organization member group
355
//        @Description        Needs admin or manager role
356
//        @Tags                        organizations
357
//        @Accept                        json
358
//        @Produce                json
359
//        @Security                BearerAuth
360
//        @Param                        address        path                string        true        "Organization address"
361
//        @Param                        groupID        path                string        true        "Group ID"
362
//        @Param                        page        query                int                false        "Page number for pagination"
363
//        @Param                        limit        query                int                false        "Number of items per page"
364
//        @Success                200                {object}        apicommon.ListOrganizationMemberGroupResponse
365
//        @Failure                400                {object}        errors.Error        "Invalid input data"
366
//        @Failure                401                {object}        errors.Error        "Unauthorized"
367
//        @Failure                404                {object}        errors.Error        "Organization or group not found"
368
//        @Failure                500                {object}        errors.Error        "Internal server error"
369
//        @Router                        /organizations/{address}/groups/{groupID}/members [get]
370
func (a *API) listOrganizationMemberGroupsHandler(w http.ResponseWriter, r *http.Request) {
6✔
371
        // get the group ID from the request path
6✔
372
        groupID := chi.URLParam(r, "groupID")
6✔
373
        if groupID == "" {
6✔
UNCOV
374
                errors.ErrInvalidData.Withf("group ID is required").Write(w)
×
UNCOV
375
                return
×
UNCOV
376
        }
×
377
        // get the user from the request context
378
        user, ok := apicommon.UserFromContext(r.Context())
6✔
379
        if !ok {
6✔
UNCOV
380
                errors.ErrUnauthorized.Write(w)
×
UNCOV
381
                return
×
382
        }
×
383
        // get the organization info from the request context
384
        org, _, ok := a.organizationFromRequest(r)
6✔
385
        if !ok {
6✔
UNCOV
386
                errors.ErrNoOrganizationProvided.Write(w)
×
UNCOV
387
                return
×
388
        }
×
389
        if !user.HasRoleFor(org.Address, db.AdminRole) && !user.HasRoleFor(org.Address, db.ManagerRole) {
7✔
390
                // if the user is not admin or manager of the organization, return an error
1✔
391
                errors.ErrUnauthorized.Withf("user is not admin of organization").Write(w)
1✔
392
                return
1✔
393
        }
1✔
394

395
        params, err := parsePaginationParams(r.URL.Query().Get(ParamPage), r.URL.Query().Get(ParamLimit))
5✔
396
        if err != nil {
5✔
UNCOV
397
                errors.ErrMalformedURLParam.WithErr(err).Write(w)
×
UNCOV
398
                return
×
UNCOV
399
        }
×
400
        totalItems, members, err := a.db.ListOrganizationMemberGroup(groupID, org.Address,
5✔
401
                params.Page, params.Limit)
5✔
402
        if err != nil {
6✔
403
                if err == db.ErrNotFound {
1✔
UNCOV
404
                        errors.ErrInvalidData.Withf("group not found").Write(w)
×
UNCOV
405
                        return
×
UNCOV
406
                }
×
407
                errors.ErrGenericInternalServerError.Withf("could not get organization member group members: %v", err).Write(w)
1✔
408
                return
1✔
409
        }
410
        // convert the members to the response format
411
        membersResponse := make([]apicommon.OrgMember, 0, len(members))
4✔
412
        for _, m := range members {
10✔
413
                membersResponse = append(membersResponse, apicommon.OrgMemberFromDb(*m))
6✔
414
        }
6✔
415

416
        pagination, err := calculatePagination(params.Page, params.Limit, totalItems)
4✔
417
        if err != nil {
4✔
UNCOV
418
                errors.ErrMalformedURLParam.WithErr(err).Write(w)
×
UNCOV
419
                return
×
UNCOV
420
        }
×
421

422
        apicommon.HTTPWriteJSON(w, &apicommon.ListOrganizationMemberGroupResponse{
4✔
423
                Pagination: pagination,
4✔
424
                Members:    membersResponse,
4✔
425
        })
4✔
426
}
427

428
// organizationMemberGroupValidateHandler godoc
429
//
430
//        @Summary                Validate organization group members data
431
//        @Description        Checks the AuthFields for duplicates or empty fields and the TwoFaFields for empty ones.
432
//        @Tags                        organizations
433
//        @Accept                        json
434
//        @Produce                json
435
//        @Security                BearerAuth
436
//        @Param                        address        path                string                                                                        true        "Organization address"
437
//        @Param                        groupID        path                string                                                                        true        "Group ID"
438
//        @Param                        members        body                apicommon.ValidateMemberGroupRequest        true        "Members validation request"
439
//        @Success                200                {string}        string                                                                        "OK"
440
//        @Failure                400                {object}        errors.Error                                                        "Invalid input data"
441
//        @Failure                401                {object}        errors.Error                                                        "Unauthorized"
442
//        @Failure                404                {object}        errors.Error                                                        "Organization or group not found"
443
//        @Failure                500                {object}        errors.Error                                                        "Internal server error"
444
//
445
//        @Router                        /organizations/{address}/groups/{groupID}/validate [post]
446
func (a *API) organizationMemberGroupValidateHandler(w http.ResponseWriter, r *http.Request) {
9✔
447
        // get the group ID from the request path
9✔
448
        groupID := chi.URLParam(r, "groupID")
9✔
449
        if groupID == "" {
9✔
UNCOV
450
                errors.ErrInvalidData.Withf("group ID is required").Write(w)
×
UNCOV
451
                return
×
UNCOV
452
        }
×
453
        // get the user from the request context
454
        user, ok := apicommon.UserFromContext(r.Context())
9✔
455
        if !ok {
9✔
UNCOV
456
                errors.ErrUnauthorized.Write(w)
×
UNCOV
457
                return
×
UNCOV
458
        }
×
459
        // get the organization info from the request context
460
        org, _, ok := a.organizationFromRequest(r)
9✔
461
        if !ok {
9✔
UNCOV
462
                errors.ErrNoOrganizationProvided.Write(w)
×
UNCOV
463
                return
×
UNCOV
464
        }
×
465
        if !user.HasRoleFor(org.Address, db.AdminRole) && !user.HasRoleFor(org.Address, db.ManagerRole) {
10✔
466
                // if the user is not admin or manager of the organization, return an error
1✔
467
                errors.ErrUnauthorized.Withf("user is not admin of organization").Write(w)
1✔
468
                return
1✔
469
        }
1✔
470

471
        var membersRequest apicommon.ValidateMemberGroupRequest
8✔
472
        if err := json.NewDecoder(r.Body).Decode(&membersRequest); err != nil {
8✔
473
                errors.ErrMalformedBody.Write(w)
×
474
                return
×
UNCOV
475
        }
×
476

477
        if len(membersRequest.AuthFields) == 0 && len(membersRequest.TwoFaFields) == 0 {
9✔
478
                errors.ErrInvalidData.Withf("missing both AuthFields and TwoFaFields").Write(w)
1✔
479
                return
1✔
480
        }
1✔
481

482
        // check the org members to veriy tha the OrgMemberAuthFields can be used for authentication
483
        aggregationResults, err := a.db.CheckGroupMembersFields(
7✔
484
                org.Address,
7✔
485
                groupID,
7✔
486
                membersRequest.AuthFields,
7✔
487
                membersRequest.TwoFaFields,
7✔
488
        )
7✔
489
        if err != nil {
8✔
490
                errors.ErrGenericInternalServerError.WithErr(err).Write(w)
1✔
491
                return
1✔
492
        }
1✔
493
        if len(aggregationResults.Duplicates) > 0 || len(aggregationResults.MissingData) > 0 {
9✔
494
                // if there are incorrect members, return an error with the IDs of the incorrect members
3✔
495
                errors.ErrInvalidData.WithData(aggregationResults).Write(w)
3✔
496
                return
3✔
497
        }
3✔
498

499
        apicommon.HTTPWriteOK(w)
3✔
500
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc