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

vocdoni / saas-backend / 16598457312

29 Jul 2025 02:04PM UTC coverage: 58.003% (-0.02%) from 58.021%
16598457312

Pull #203

github

emmdim
api: Adds `GET /census/{id}/participants` endpoint to retrieve the memberIDs of the participants of a census
Pull Request #203: api: Adds `GET /census/{id}/participants` endpoint to retrieve the memberIDs of the participants of a census

21 of 39 new or added lines in 2 files covered. (53.85%)

2 existing lines in 1 file now uncovered.

5327 of 9184 relevant lines covered (58.0%)

26.93 hits per line

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

74.82
/api/apicommon/types.go
1
package apicommon
2

3
//revive:disable:max-public-structs
4

5
import (
6
        "time"
7

8
        "github.com/ethereum/go-ethereum/common"
9
        "github.com/google/uuid"
10
        "github.com/vocdoni/saas-backend/db"
11
        "github.com/vocdoni/saas-backend/internal"
12
        "github.com/vocdoni/saas-backend/notifications"
13
        "go.mongodb.org/mongo-driver/bson/primitive"
14
        "go.vocdoni.io/dvote/log"
15
)
16

17
// OrganizationInfo represents an organization in the API.
18
// swagger:model OrganizationInfo
19
type OrganizationInfo struct {
20
        // The organization's blockchain address
21
        Address common.Address `json:"address"`
22

23
        // The organization's website URL
24
        Website string `json:"website"`
25

26
        // Creation timestamp in RFC3339 format
27
        CreatedAt string `json:"createdAt"`
28

29
        // The type of organization
30
        Type string `json:"type"`
31

32
        // The size category of the organization
33
        Size string `json:"size"`
34

35
        // The organization's brand color in hex format
36
        Color string `json:"color"`
37

38
        // The organization's subdomain
39
        Subdomain string `json:"subdomain"`
40

41
        // The country where the organization is based
42
        Country string `json:"country"`
43

44
        // The organization's timezone
45
        Timezone string `json:"timezone"`
46

47
        // Whether the organization is active
48
        Active bool `json:"active"`
49

50
        // Whether the organization has enabled communications
51
        Communications bool `json:"communications"`
52

53
        // Subscription details for the organization
54
        Subscription *SubscriptionDetails `json:"subscription"`
55

56
        // Usage counters for the organization
57
        Counters *SubscriptionUsage `json:"counters"`
58

59
        // Parent organization if this is a sub-organization
60
        Parent *OrganizationInfo `json:"parent"`
61

62
        // Arbitrary key value fields with metadata regarding the organization
63
        Meta map[string]any `json:"meta"`
64
}
65

66
// OrganizationUsers represents a list of users of an organization.
67
// swagger:model OrganizationUsers
68
type OrganizationUsers struct {
69
        // List of organization users
70
        Users []*OrganizationUser `json:"users"`
71
}
72

73
// OrganizationUser represents a user of an organization with their role.
74
// swagger:model OrganizationUser
75
type OrganizationUser struct {
76
        // User information
77
        Info *UserInfo `json:"info"`
78

79
        // The role of the user in the organization
80
        Role string `json:"role"`
81
}
82

83
// OrganizationAddresses represents a list of blockchain addresses of organizations.
84
// swagger:model OrganizationAddresses
85
type OrganizationAddresses struct {
86
        // List of organization blockchain addresses
87
        Addresses []common.Address `json:"addresses"`
88
}
89

90
// UserOrganization represents the organization of a user including their role.
91
// swagger:model UserOrganization
92
type UserOrganization struct {
93
        // The role of the user in the organization
94
        Role string `json:"role"`
95

96
        // Organization information
97
        Organization *OrganizationInfo `json:"organization"`
98
}
99

100
// OrganizationRole represents a role that can be assigned to organization users.
101
// swagger:model OrganizationRole
102
type OrganizationRole struct {
103
        // Role identifier
104
        Role string `json:"role"`
105

106
        // Human-readable name of the role
107
        Name string `json:"name"`
108

109
        // Whether this role has write permissions
110
        WritePermission bool `json:"writePermission"`
111
}
112

113
// OrganizationRoleList represents a list of organization roles.
114
// swagger:model OrganizationRoleList
115
type OrganizationRoleList struct {
116
        // List of organization roles
117
        Roles []*OrganizationRole `json:"roles"`
118
}
119

120
// OrganizationType represents a type of organization.
121
// swagger:model OrganizationType
122
type OrganizationType struct {
123
        // Type identifier
124
        Type string `json:"type"`
125

126
        // Human-readable name of the type
127
        Name string `json:"name"`
128
}
129

130
// OrganizationTypeList represents a list of organization types.
131
// swagger:model OrganizationTypeList
132
type OrganizationTypeList struct {
133
        // List of organization types
134
        Types []*OrganizationType `json:"types"`
135
}
136

137
// OrganizationAddMetaRequest represents a request to add or update meta information for an organization.
138
// swagger:model OrganizationAddMetaRequest
139
type OrganizationAddMetaRequest struct {
140
        // Set of key-value pairs to add or update in the organization's meta information
141
        Meta map[string]any `json:"meta"`
142
}
143

144
// OrganizationMetaResponse represents the meta information of an organization.
145
// swagger:model OrganizationMetaResponse
146
type OrganizationMetaResponse struct {
147
        // Meta information of the organization
148
        Meta map[string]any `json:"meta"`
149
}
150

151
// OrganizationDeleteMetaRequest represents a request to delete a set of keys from the meta information
152
// for an organization.
153
// swagger:model OrganizationDeleteMetaRequest
154
type OrganizationDeleteMetaRequest struct {
155
        // List of keys to delete from the organization's meta information
156
        Keys []string `json:"keys"`
157
}
158

159
// UpdateOrganizationUserRoleRequest represents a request to update the role of an organization user.
160
// swagger:model UpdateOrganizationUserRoleRequest
161
type UpdateOrganizationUserRoleRequest struct {
162
        // The new role to assign to the user
163
        Role string `json:"role"`
164
}
165

166
// CreateOrganizationMemberGroupRequest represents a request to create a new organization member group.
167
// swagger:model CreateOrganizationMemberGroupRequest
168
type CreateOrganizationMemberGroupRequest struct {
169
        // Title of the group
170
        Title string `json:"title"`
171
        // Description of the group
172
        Description string `json:"description"`
173
        // The IDs of the members to add to the group
174
        MemberIDs []string `json:"memberIds"`
175
}
176

177
// OrganizationMemberGroupInfo represents detailed information about an organization member group.
178
// swagger:model OrganizationMemberGroupInfo
179
type OrganizationMemberGroupInfo struct {
180
        // Unique identifier for the group
181
        ID string `json:"id,omitempty" bson:"_id"`
182
        // Title of the group
183
        Title string `json:"title,omitempty" bson:"title"`
184
        // Description of the group
185
        Description string `json:"description,omitempty" bson:"description"`
186
        // Creation timestamp
187
        CreatedAt time.Time `json:"createdAt,omitempty" bson:"createdAt"`
188
        // Last updated timestamp
189
        UpdatedAt time.Time `json:"updatedAt,omitempty" bson:"updatedAt"`
190
        // List of member IDs in the group
191
        MemberIDs []string `json:"memberIds,omitempty" bson:"memberIds"`
192
        // List of census IDs associated with the group
193
        CensusIDs []string `json:"censusIds,omitempty" bson:"censusIds"`
194
        // Count of members in the group
195
        MembersCount int `json:"membersCount,omitempty" bson:"membersCount"`
196
}
197

198
// OrganizationMemberGroupsResponse represents the response for listing organization member groups.
199
// swagger:model OrganizationMemberGroupsResponse
200
type OrganizationMemberGroupsResponse struct {
201
        // Total number of pages
202
        TotalPages int `json:"totalPages"`
203
        // Current page number
204
        CurrentPage int `json:"currentPage"`
205
        // List of organization member groups
206
        Groups []*OrganizationMemberGroupInfo `json:"groups"`
207
}
208

209
// UpdateOrganizationMemberGroupsRequest represents a request to update an organization member group
210
// title, description or members.
211
// swagger:model UpdateOrganizationMemberGroupsRequest
212
type UpdateOrganizationMemberGroupsRequest struct {
213
        // Updated Title
214
        Title string `json:"title"`
215
        // Updated Description
216
        Description string `json:"description"`
217
        // The IDs of the members to add to the group
218
        AddMembers []string `json:"addMembers"`
219
        // The IDs of the members to remove from the group
220
        RemoveMembers []string `json:"removeMembers"`
221
}
222

223
// ListOrganizationMemberGroupResponse represents the response for listing the members of an  organization group.
224
// swagger:model ListOrganizationMemberGroupResponse
225
type ListOrganizationMemberGroupResponse struct {
226
        // Total number of pages
227
        TotalPages int `json:"totalPages"`
228
        // Current page number
229
        CurrentPage int `json:"currentPage"`
230
        // List of organization group members
231
        Members []OrgMember `json:"members"`
232
}
233

234
// ValidateMemberGroupRequest validates the request for creating or updating an organization member group.
235
// Validates that either AuthFields or TwoFaFields are provided and checks for duplicates or empty fields.
236
// swagger:model ValidateMemberGroupRequest
237
type ValidateMemberGroupRequest struct {
238
        // Defines which member data should be used for authentication
239
        AuthFields db.OrgMemberAuthFields `json:"authFields,omitempty"`
240

241
        // Defines which member data should be used for two-factor authentication
242
        TwoFaFields db.OrgMemberTwoFaFields `json:"twoFaFields,omitempty"`
243
}
244

245
// UserInfo represents user information and is used for user registration.
246
// swagger:model UserInfo
247
type UserInfo struct {
248
        // User ID as generated by the backend
249
        ID uint64 `json:"id,omitempty"`
250
        // User's email address
251
        Email string `json:"email,omitempty"`
252

253
        // User's password (not returned in responses)
254
        Password string `json:"password,omitempty"`
255

256
        // User's first name
257
        FirstName string `json:"firstName,omitempty"`
258

259
        // User's last name
260
        LastName string `json:"lastName,omitempty"`
261

262
        // Whether the user's email is verified
263
        Verified bool `json:"verified,omitempty"`
264

265
        // Organizations the user belongs to
266
        Organizations []*UserOrganization `json:"organizations"`
267
}
268

269
// OrganizationInvite represents an invitation to join an organization.
270
// swagger:model OrganizationInvite
271
type OrganizationInvite struct {
272
        // Unique identifier for the invitation
273
        ID string `json:"id"`
274

275
        // Email address of the invitee
276
        Email string `json:"email"`
277

278
        // Role to be assigned to the invitee
279
        Role string `json:"role"`
280

281
        // Expiration time of the invitation
282
        Expiration time.Time `json:"expiration"`
283
}
284

285
// OrganizationInviteList represents a list of pending organization invitations.
286
// swagger:model OrganizationInviteList
287
type OrganizationInviteList struct {
288
        // List of pending invitations
289
        Invites []*OrganizationInvite `json:"pending"`
290
}
291

292
// AcceptOrganizationInvitation represents a request to accept an organization invitation.
293
// swagger:model AcceptOrganizationInvitation
294
type AcceptOrganizationInvitation struct {
295
        // Invitation code
296
        Code string `json:"code"`
297

298
        // User information for registration or identification
299
        User *UserInfo `json:"user"`
300
}
301

302
// UserPasswordUpdate represents a request to update a user's password.
303
// swagger:model UserPasswordUpdate
304
type UserPasswordUpdate struct {
305
        // Current password
306
        OldPassword string `json:"oldPassword"`
307

308
        // New password
309
        NewPassword string `json:"newPassword"`
310
}
311

312
// UserVerification represents user verification information.
313
// swagger:model UserVerification
314
type UserVerification struct {
315
        // User's email address
316
        Email string `json:"email,omitempty"`
317

318
        // Verification code
319
        Code string `json:"code,omitempty"`
320

321
        // Expiration time of the verification code
322
        Expiration time.Time `json:"expiration,omitempty"`
323

324
        // Whether the verification is valid
325
        Valid bool `json:"valid"`
326
}
327

328
// UserPasswordReset represents a request to reset a user's password.
329
// swagger:model UserPasswordReset
330
type UserPasswordReset struct {
331
        // User's email address
332
        Email string `json:"email"`
333

334
        // Password reset code
335
        Code string `json:"code"`
336

337
        // New password
338
        NewPassword string `json:"newPassword"`
339
}
340

341
// LoginResponse represents the response to a successful login request.
342
// swagger:model LoginResponse
343
type LoginResponse struct {
344
        // JWT authentication token
345
        Token string `json:"token"`
346

347
        // Token expiration time
348
        Expirity time.Time `json:"expirity"`
349
}
350

351
// TransactionData contains the data of a transaction to be signed or a signed transaction.
352
// swagger:model TransactionData
353
type TransactionData struct {
354
        // Blockchain address
355
        Address common.Address `json:"address" swaggertype:"string" format:"hex" example:"deadbeef"`
356

357
        // Transaction payload bytes
358
        TxPayload []byte `json:"txPayload" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
359
}
360

361
// MessageSignature contains a payload and its signature.
362
// swagger:model MessageSignature
363
type MessageSignature struct {
364
        // Blockchain address
365
        Address common.Address `json:"address" swaggertype:"string" format:"hex" example:"deadbeef"`
366

367
        // Message payload bytes
368
        Payload []byte `json:"payload,omitempty" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
369

370
        // Cryptographic signature
371
        Signature internal.HexBytes `json:"signature,omitempty" swaggertype:"string" format:"hex" example:"deadbeef"`
372
}
373

374
// OrganizationFromDB converts a db.Organization to an OrganizationInfo, if the parent
375
// organization is provided it will be included in the response.
376
func OrganizationFromDB(dbOrg, parent *db.Organization) *OrganizationInfo {
30✔
377
        if dbOrg == nil {
30✔
378
                return nil
×
379
        }
×
380
        var parentOrg *OrganizationInfo
30✔
381
        if parent != nil {
30✔
382
                parentOrg = OrganizationFromDB(parent, nil)
×
383
        }
×
384
        details := SubscriptionDetailsFromDB(&dbOrg.Subscription)
30✔
385
        usage := SubscriptionUsageFromDB(&dbOrg.Counters)
30✔
386
        return &OrganizationInfo{
30✔
387
                Address:        dbOrg.Address,
30✔
388
                Website:        dbOrg.Website,
30✔
389
                CreatedAt:      dbOrg.CreatedAt.Format(time.RFC3339),
30✔
390
                Type:           string(dbOrg.Type),
30✔
391
                Size:           dbOrg.Size,
30✔
392
                Color:          dbOrg.Color,
30✔
393
                Subdomain:      dbOrg.Subdomain,
30✔
394
                Country:        dbOrg.Country,
30✔
395
                Timezone:       dbOrg.Timezone,
30✔
396
                Active:         dbOrg.Active,
30✔
397
                Communications: dbOrg.Communications,
30✔
398
                Parent:         parentOrg,
30✔
399
                Subscription:   &details,
30✔
400
                Counters:       &usage,
30✔
401
        }
30✔
402
}
403

404
// OrganizationSubscriptionInfo provides detailed information about an organization's subscription.
405
// swagger:model OrganizationSubscriptionInfo
406
type OrganizationSubscriptionInfo struct {
407
        // Subscription details
408
        SubcriptionDetails SubscriptionDetails `json:"subscriptionDetails"`
409

410
        // Current usage metrics
411
        Usage SubscriptionUsage `json:"usage"`
412

413
        // Subscription plan details
414
        Plan SubscriptionPlan `json:"plan"`
415
}
416

417
// SubscriptionPlan represents a subscription plan in the API.
418
// It is the mirror struct of db.Plan.
419
// swagger:model SubscriptionPlan
420
type SubscriptionPlan struct {
421
        // Unique identifier for the plan
422
        ID uint64 `json:"id"`
423

424
        // Human-readable name of the plan
425
        Name string `json:"name"`
426

427
        // Stripe product ID
428
        StripeID string `json:"stripeId"`
429

430
        // Stripe price ID
431
        StripePriceID string `json:"stripePriceId"`
432

433
        // Starting price in cents
434
        StartingPrice int64 `json:"startingPrice"`
435

436
        // Whether this is the default plan
437
        Default bool `json:"default"`
438

439
        // Organization limits for this plan
440
        Organization SubscriptionPlanLimits `json:"organization"`
441

442
        // Voting types available in this plan
443
        VotingTypes SubscriptionVotingTypes `json:"votingTypes"`
444

445
        // Features available in this plan
446
        Features SubscriptionFeatures `json:"features"`
447

448
        // Census size tiers and pricing
449
        CensusSizeTiers []SubscriptionPlanTier `json:"censusSizeTiers"`
450
}
451

452
// SubscriptionPlanFromDB converts a db.Plan to a SubscriptionPlan.
453
func SubscriptionPlanFromDB(plan *db.Plan) SubscriptionPlan {
×
454
        if plan == nil {
×
455
                return SubscriptionPlan{}
×
456
        }
×
457
        tiers := make([]SubscriptionPlanTier, 0, len(plan.CensusSizeTiers))
×
458
        for _, t := range plan.CensusSizeTiers {
×
459
                tiers = append(tiers, SubscriptionPlanTier{
×
460
                        Amount: t.Amount,
×
461
                        UpTo:   t.UpTo,
×
462
                })
×
463
        }
×
464
        return SubscriptionPlan{
×
465
                ID:              plan.ID,
×
466
                Name:            plan.Name,
×
467
                StripeID:        plan.StripeID,
×
468
                StripePriceID:   plan.StripePriceID,
×
469
                StartingPrice:   plan.StartingPrice,
×
470
                Default:         plan.Default,
×
471
                Organization:    SubscriptionPlanLimits(plan.Organization),
×
472
                VotingTypes:     SubscriptionVotingTypes(plan.VotingTypes),
×
473
                Features:        SubscriptionFeatures(plan.Features),
×
474
                CensusSizeTiers: tiers,
×
475
        }
×
476
}
477

478
// SubscriptionPlanLimits represents the limits of a subscription plan.
479
// It is the mirror struct of db.PlanLimits.
480
// swagger:model SubscriptionPlanLimits
481
type SubscriptionPlanLimits struct {
482
        // Maximum number of users allowed
483
        Users int `json:"users"`
484

485
        // Maximum number of sub-organizations allowed
486
        SubOrgs int `json:"subOrgs"`
487

488
        // Maximum number of voting processes allowed
489
        MaxProcesses int `json:"maxProcesses"`
490

491
        // Maximum number of census allowed
492
        MaxCensus int `json:"maxCensus"`
493

494
        // Maximum duration of voting processes in days
495
        MaxDuration int `json:"maxDuration"`
496

497
        // Whether custom URLs are allowed
498
        CustomURL bool `json:"customURL"`
499

500
        // Maximum number of draft processes allowed
501
        Drafts int `json:"drafts"`
502
}
503

504
// SubscriptionVotingTypes represents the voting types available in a subscription plan.
505
// It is the mirror struct of db.VotingTypes.
506
// swagger:model SubscriptionVotingTypes
507
type SubscriptionVotingTypes struct {
508
        // Whether single choice voting is available
509
        Single bool `json:"single"`
510

511
        // Whether multiple choice voting is available
512
        Multiple bool `json:"multiple"`
513

514
        // Whether approval voting is available
515
        Approval bool `json:"approval"`
516

517
        // Whether cumulative voting is available
518
        Cumulative bool `json:"cumulative"`
519

520
        // Whether ranked choice voting is available
521
        Ranked bool `json:"ranked"`
522

523
        // Whether weighted voting is available
524
        Weighted bool `json:"weighted"`
525
}
526

527
// SubscriptionFeatures represents the features available in a subscription plan.
528
// It is the mirror struct of db.Features.
529
// swagger:model SubscriptionFeatures
530
type SubscriptionFeatures struct {
531
        // Whether anonymous voting is available
532
        Anonymous bool `json:"anonymous"`
533

534
        // Whether census overwrite is allowed
535
        Overwrite bool `json:"overwrite"`
536

537
        // Whether live results are available
538
        LiveResults bool `json:"liveResults"`
539

540
        // Whether UI personalization is available
541
        Personalization bool `json:"personalization"`
542

543
        // Whether email reminders are available
544
        EmailReminder bool `json:"emailReminder"`
545

546
        // Whether SMS notifications are available
547
        SmsNotification bool `json:"smsNotification"`
548

549
        // Whether white labeling is available
550
        WhiteLabel bool `json:"whiteLabel"`
551

552
        // Whether live streaming is available
553
        LiveStreaming bool `json:"liveStreaming"`
554

555
        // Whether eligible for phone support
556
        PhoneSupport bool `json:"phoneSupport"`
557
}
558

559
// SubscriptionPlanTier represents a pricing tier of a subscription plan.
560
// It is the mirror struct of db.PlanTier.
561
// swagger:model SubscriptionPlanTier
562
type SubscriptionPlanTier struct {
563
        // Price amount in cents
564
        Amount int64 `json:"amount"`
565

566
        // Maximum census size for this tier
567
        UpTo int64 `json:"upTo"`
568
}
569

570
// SubscriptionDetails represents the details of an organization's subscription.
571
// It is the mirror struct of db.OrganizationSubscription.
572
// swagger:model SubscriptionDetails
573
type SubscriptionDetails struct {
574
        // ID of the subscription plan
575
        PlanID uint64 `json:"planId"`
576

577
        // Date when the subscription started
578
        StartDate time.Time `json:"startDate"`
579

580
        // Date when the subscription will renew
581
        RenewalDate time.Time `json:"renewalDate"`
582

583
        // Date of the last payment
584
        LastPaymentDate time.Time `json:"lastPaymentDate"`
585

586
        // Whether the subscription is active
587
        Active bool `json:"active"`
588

589
        // Maximum census size allowed
590
        MaxCensusSize int `json:"maxCensusSize"`
591

592
        // Email associated with the subscription
593
        Email string `json:"email"`
594
}
595

596
// SubscriptionDetailsFromDB converts a db.OrganizationSubscription to a SubscriptionDetails.
597
func SubscriptionDetailsFromDB(details *db.OrganizationSubscription) SubscriptionDetails {
30✔
598
        if details == nil {
30✔
599
                return SubscriptionDetails{}
×
600
        }
×
601
        return SubscriptionDetails{
30✔
602
                PlanID:          details.PlanID,
30✔
603
                StartDate:       details.StartDate,
30✔
604
                RenewalDate:     details.RenewalDate,
30✔
605
                LastPaymentDate: details.LastPaymentDate,
30✔
606
                Active:          details.Active,
30✔
607
                MaxCensusSize:   details.MaxCensusSize,
30✔
608
                Email:           details.Email,
30✔
609
        }
30✔
610
}
611

612
// SubscriptionUsage represents the usage metrics of an organization's subscription.
613
// It is the mirror struct of db.OrganizationCounters.
614
// swagger:model SubscriptionUsage
615
type SubscriptionUsage struct {
616
        // Number of SMS messages sent
617
        SentSMS int `json:"sentSMS"`
618

619
        // Number of emails sent
620
        SentEmails int `json:"sentEmails"`
621

622
        // Number of sub-organizations created
623
        SubOrgs int `json:"subOrgs"`
624

625
        // Number of users in the organization
626
        Users int `json:"users"`
627

628
        // Number of voting processes created
629
        Processes int `json:"processes"`
630
}
631

632
// SubscriptionUsageFromDB converts a db.OrganizationCounters to a SubscriptionUsage.
633
func SubscriptionUsageFromDB(usage *db.OrganizationCounters) SubscriptionUsage {
30✔
634
        if usage == nil {
30✔
635
                return SubscriptionUsage{}
×
636
        }
×
637
        return SubscriptionUsage{
30✔
638
                SentSMS:    usage.SentSMS,
30✔
639
                SentEmails: usage.SentEmails,
30✔
640
                SubOrgs:    usage.SubOrgs,
30✔
641
                Users:      usage.Users,
30✔
642
                Processes:  usage.Processes,
30✔
643
        }
30✔
644
}
645

646
// SubscriptionCheckout represents the details required for a subscription checkout process.
647
// swagger:model SubscriptionCheckout
648
type SubscriptionCheckout struct {
649
        // Plan lookup key
650
        LookupKey uint64 `json:"lookupKey"`
651

652
        // URL to return to after checkout
653
        ReturnURL string `json:"returnURL"`
654

655
        // Amount in cents
656
        Amount int64 `json:"amount"`
657

658
        // Organization address
659
        Address common.Address `json:"address"`
660

661
        // Locale for the checkout page
662
        Locale string `json:"locale"`
663
}
664

665
// MemberNotification represents a notification sent to a member.
666
// swagger:model MemberNotification
667
type MemberNotification struct {
668
        // ID of the voting process
669
        ProcessID []byte `json:"processId" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
670

671
        // Notification details
672
        Notification notifications.Notification `json:"notification"`
673

674
        // Whether the notification was sent
675
        Sent bool `json:"sent"`
676

677
        // When the notification was sent
678
        SentAt time.Time `json:"sentAt"`
679
}
680

681
// OrganizationCensus represents a census of an organization.
682
// It is the mirror struct of db.Census.
683
// swagger:model OrganizationCensus
684
type OrganizationCensus struct {
685
        // Unique identifier for the census
686
        ID string `json:"censusId"`
687

688
        // Type of census
689
        Type db.CensusType `json:"type"`
690

691
        // Organization address
692
        OrgAddress common.Address `json:"orgAddress"`
693

694
        // Optional for creating a census based on an organization member group
695
        GroupID string `json:"groupID,omitempty"`
696

697
        // Optional for defining which member data should be used for authentication
698
        AuthFields db.OrgMemberAuthFields `json:"authFields,omitempty"`
699

700
        // Optional for defining which member data should be used for two-factor authentication
701
        TwoFaFields db.OrgMemberTwoFaFields `json:"twoFaFields,omitempty"`
702
}
703

704
// CreateCensusRequest represents a request to create a new census for an organization.
705
// swagger:model CreateCensusRequest
706
type CreateCensusRequest struct {
707
        // Organization address
708
        OrgAddress common.Address `json:"orgAddress"`
709

710
        // Optional for defining which member data should be used for authentication
711
        AuthFields db.OrgMemberAuthFields `json:"authFields,omitempty"`
712

713
        // Optional for defining which member data should be used for two-factor authentication
714
        TwoFaFields db.OrgMemberTwoFaFields `json:"twoFaFields,omitempty"`
715
}
716

717
// CreateCensusResponse represents the response after creating a census returning the census ID.
718
// swagger:model CreateCensusResponse
719
type CreateCensusResponse struct {
720
        // Unique identifier for the census
721
        ID string `json:"id,omitempty"`
722
}
723

724
// PublishedCensusResponse represents a published census.
725
// swagger:model PublishedCensusResponse
726
type PublishedCensusResponse struct {
727
        // URI of the published census
728
        URI string `json:"uri" bson:"uri"`
729

730
        // Merkle root of the census
731
        Root internal.HexBytes `json:"root" bson:"root" swaggertype:"string" format:"hex" example:"deadbeef"`
732
}
733

734
// CensusParticipantsResponse returns the memberIDs of the participants of a census.
735
// swagger:model CensusParticipantsResponse
736
type CensusParticipantsResponse struct {
737
        // Unique identifier for the census
738
        CensusID string `json:"censusId"`
739
        // List of member IDs of the participants
740
        MemberIDs []string `json:"memberIds"`
741
}
742

743
// OrganizationCensusFromDB converts a db.Census to an OrganizationCensus.
744
func OrganizationCensusFromDB(census *db.Census) OrganizationCensus {
1✔
745
        if census == nil {
1✔
UNCOV
746
                return OrganizationCensus{}
×
UNCOV
747
        }
×
748
        return OrganizationCensus{
1✔
749
                ID:          census.ID.Hex(),
1✔
750
                Type:        census.Type,
1✔
751
                OrgAddress:  census.OrgAddress,
1✔
752
                GroupID:     census.GroupID.Hex(),
1✔
753
                AuthFields:  census.AuthFields,
1✔
754
                TwoFaFields: census.TwoFaFields,
1✔
755
        }
1✔
756
}
757

758
// OrganizationCensuses wraps a list of censuses of an organization.
759
// swagger:model OrganizationCensuses
760
type OrganizationCensuses struct {
761
        // List of organization censuses
762
        Censuses []OrganizationCensus `json:"censuses"`
763
}
764

765
// AddMembersRequest defines the payload for adding members to a census.
766
// swagger:model AddMembersRequest
767
type AddMembersRequest struct {
768
        // List of members to add
769
        Members []OrgMember `json:"members"`
770
}
771

772
// DbOrgMembers converts the members in the request to db.OrgMember objects.
773
func (r *AddMembersRequest) DbOrgMembers(orgAddress common.Address) []db.OrgMember {
14✔
774
        members := make([]db.OrgMember, 0, len(r.Members))
14✔
775
        for _, p := range r.Members {
44✔
776
                members = append(members, p.ToDb(orgAddress))
30✔
777
        }
30✔
778
        return members
14✔
779
}
780

781
type DeleteMembersRequest struct {
782
        // List of member internal ids numbers to delete
783
        IDs []string `json:"ids"`
784
}
785

786
type DeleteMembersResponse struct {
787
        // Number of members deleted
788
        Count int `json:"count"`
789
}
790

791
// OrgMember defines the structure of a member in the API.
792
// It is the mirror struct of db.OrgMember.
793
// swagger:model OrgMember
794
type OrgMember struct {
795
        // Member's internal unique internal ID
796
        ID string `json:"id"`
797
        // Unique member number as defined by the organization
798
        MemberNumber string `json:"memberNumber"`
799

800
        // Member's name
801
        Name string `json:"name,omitempty"`
802

803
        // Member's surname
804
        Surname string `json:"surname,omitempty"`
805

806
        // Member's National ID No
807
        NationalID string `json:"nationalId,omitempty"`
808

809
        // Member's date of birth in format YYYY-MM-DD
810
        BirthDate string `json:"birthDate,omitempty"`
811

812
        // Member's email address
813
        Email string `json:"email,omitempty"`
814

815
        // Member's phone number
816
        Phone string `json:"phone,omitempty"`
817

818
        // Member's password (for authentication)
819
        Password string `json:"password,omitempty"`
820

821
        // Additional custom fields
822
        Other map[string]any `json:"other"`
823
}
824

825
// ToDb converts an OrgMember to a db.OrgMember.
826
func (p *OrgMember) ToDb(orgAddress common.Address) db.OrgMember {
30✔
827
        parsedBirthDate := time.Time{}
30✔
828
        if len(p.BirthDate) > 0 {
37✔
829
                // Parse the birth date from string to time.Time
7✔
830
                var err error
7✔
831
                parsedBirthDate, err = time.Parse("2006-01-02", p.BirthDate)
7✔
832
                if err != nil {
9✔
833
                        log.Warnf("Failed to parse birth date %s for member %s: %v", p.BirthDate, p.MemberNumber, err)
2✔
834
                }
2✔
835
        }
836
        id := primitive.NilObjectID
30✔
837
        if len(p.ID) > 0 {
31✔
838
                // Convert the ID from string to ObjectID
1✔
839
                var err error
1✔
840
                id, err = primitive.ObjectIDFromHex(p.ID)
1✔
841
                if err != nil {
1✔
842
                        log.Warnf("Failed to convert member ID %s to ObjectID: %v", p.ID, err)
×
843
                }
×
844
        }
845
        return db.OrgMember{
30✔
846
                ID:             id,
30✔
847
                OrgAddress:     orgAddress,
30✔
848
                MemberNumber:   p.MemberNumber,
30✔
849
                Name:           p.Name,
30✔
850
                Surname:        p.Surname,
30✔
851
                NationalID:     p.NationalID,
30✔
852
                BirthDate:      p.BirthDate,
30✔
853
                ParsedBirtDate: parsedBirthDate,
30✔
854
                Email:          p.Email,
30✔
855
                Phone:          p.Phone,
30✔
856
                Password:       p.Password,
30✔
857
                Other:          p.Other,
30✔
858
        }
30✔
859
}
860

861
func OrgMemberFromDb(p db.OrgMember) OrgMember {
74✔
862
        hashedPhone := string(p.HashedPhone)
74✔
863
        if len(hashedPhone) > 0 {
114✔
864
                // If the phone is hashed, we return the last 6 characters
40✔
865
                hashedPhone = hashedPhone[len(hashedPhone)-6:]
40✔
866
        }
40✔
867
        // if p.BirthDate != nil {
868

869
        return OrgMember{
74✔
870
                ID:           p.ID.Hex(),
74✔
871
                MemberNumber: p.MemberNumber,
74✔
872
                Name:         p.Name,
74✔
873
                Surname:      p.Surname,
74✔
874
                NationalID:   p.NationalID,
74✔
875
                BirthDate:    p.BirthDate,
74✔
876
                Email:        p.Email,
74✔
877
                Phone:        hashedPhone,
74✔
878
                Other:        p.Other,
74✔
879
        }
74✔
880
}
881

882
type OrganizationMembersResponse struct {
883
        // Total number of pages available
884
        Pages int `json:"pages"`
885

886
        // Current page number
887
        Page int `json:"page"`
888

889
        // Total number of members in the organization
890
        Members []OrgMember `json:"members"`
891
}
892

893
// AddMembersResponse defines the response for successful member addition
894
// swagger:model AddMembersResponse
895
type AddMembersResponse struct {
896
        // Number of members added
897
        Added uint32 `json:"added"`
898

899
        // Errors encountered during job
900
        Errors []string `json:"errors"`
901

902
        // Job ID for tracking the addition process
903
        JobID internal.HexBytes `json:"jobId,omitempty" swaggertype:"string" format:"hex" example:"deadbeef"`
904
}
905

906
// AddMembersJobResponse defines the response for the status of an async job of member addition
907
// swagger:model AddMembersJobResponse
908
type AddMembersJobResponse struct {
909
        // Number of members added
910
        Added uint32 `json:"added"`
911

912
        // Errors encountered during job
913
        Errors []string `json:"errors"`
914

915
        // Progress equals Added / Total * 100
916
        Progress uint32 `json:"progress"`
917

918
        // Total members in this job
919
        Total uint32 `json:"total"`
920
}
921

922
// Request types for process operations
923

924
// CreateProcessRequest defines the payload for creating a new voting process.
925
// swagger:model CreateProcessRequest
926
type CreateProcessRequest struct {
927
        // Merkle root of the published census
928
        PublishedCensusRoot internal.HexBytes `json:"censusRoot" swaggertype:"string" format:"hex" example:"deadbeef"`
929

930
        // URI of the published census
931
        PublishedCensusURI string `json:"censusUri"`
932

933
        // Census ID
934
        CensusID internal.HexBytes `json:"censusId" swaggertype:"string" format:"hex" example:"deadbeef"`
935

936
        // Additional metadata for the process
937
        // Can be any key-value pairs
938
        Metadata []byte `json:"metadata,omitempty" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
939
}
940

941
// InitiateAuthRequest defines the payload for participant authentication.
942
// swagger:model InitiateAuthRequest
943
type InitiateAuthRequest struct {
944
        // Unique participant ID
945
        ParticipantID string `json:"participantId"`
946

947
        // Participant's email address (optional)
948
        Email string `json:"email,omitempty"`
949

950
        // Participant's phone number (optional)
951
        Phone string `json:"phone,omitempty"`
952

953
        // Participant's password (optional)
954
        Password string `json:"password,omitempty"`
955
}
956

957
// VerifyAuthRequest defines the payload for auth code verification.
958
// swagger:model VerifyAuthRequest
959
type VerifyAuthRequest struct {
960
        // Authentication token
961
        Token string `json:"token"`
962

963
        // Verification code
964
        Code string `json:"code"`
965
}
966

967
// GenerateProofRequest defines the payload for generating voting proof.
968
// swagger:model GenerateProofRequest
969
type GenerateProofRequest struct {
970
        // Authentication token
971
        Token string `json:"token"`
972

973
        // Blinded address for proof generation
974
        BlindedAddress []byte `json:"blindedAddress" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
975
}
976

977
// Two-factor authentication types
978

979
// AuthRequest defines the payload for requesting authentication.
980
// swagger:model AuthRequest
981
type AuthRequest struct {
982
        // Authentication token
983
        AuthToken *uuid.UUID `json:"authToken,omitempty"`
984

985
        // Authentication data (reserved for the auth handler)
986
        AuthData []string `json:"authData,omitempty"`
987
}
988

989
// SignRequest defines the payload for requesting a signature.
990
// swagger:model SignRequest
991
type SignRequest struct {
992
        // Token R value
993
        TokenR internal.HexBytes `json:"tokenR" swaggertype:"string" format:"hex" example:"deadbeef"`
994

995
        // Authentication token
996
        AuthToken *uuid.UUID `json:"authToken"`
997

998
        // Blockchain address
999
        Address string `json:"address,omitempty"`
1000

1001
        // Payload to sign
1002
        Payload string `json:"payload,omitempty"`
1003

1004
        // Election ID
1005
        ElectionID internal.HexBytes `json:"electionId,omitempty" swaggertype:"string" format:"hex" example:"deadbeef"`
1006
}
1007

1008
// CreateProcessBundleRequest defines the payload for creating a new process bundle.
1009
// swagger:model CreateProcessBundleRequest
1010
type CreateProcessBundleRequest struct {
1011
        // Census ID
1012
        CensusID string `json:"censusId"`
1013

1014
        // List of process IDs to include in the bundle
1015
        Processes []string `json:"processes"`
1016
}
1017

1018
// CreateProcessBundleResponse defines the response for a successful process bundle creation.
1019
// swagger:model CreateProcessBundleResponse
1020
type CreateProcessBundleResponse struct {
1021
        // URI of the created process bundle
1022
        URI string `json:"uri"`
1023

1024
        // Merkle root of the process bundle
1025
        Root internal.HexBytes `json:"root" swaggertype:"string" format:"hex" example:"deadbeef"`
1026
}
1027

1028
// OAuthLoginRequest defines the payload for register/login through the OAuth service.
1029
// swagger:model OAuthLoginRequest
1030
type OAuthLoginRequest struct {
1031
        // User email address
1032
        Email string `json:"email"`
1033
        // User first name
1034
        FirstName string `json:"firstName"`
1035
        // User last name
1036
        LastName string `json:"lastName"`
1037
        // The signature made by the OAuth service on top of the user email
1038
        OAuthSignature string `json:"oauthSignature"`
1039
        // The signature made by the user on on top of the oauth signature
1040
        UserOAuthSignature string `json:"userOAuthSignature"`
1041
        // The address of the user
1042
        Address string `json:"address"`
1043
}
1044

1045
type OAuthLoginResponse struct {
1046
        // JWT authentication token
1047
        Token string `json:"token"`
1048

1049
        // Token expiration time
1050
        Expirity time.Time `json:"expirity"`
1051

1052
        // Whether the user had to be  registered
1053
        Registered bool `json:"registered"`
1054
}
1055

1056
// OAuthServiceAddressResponse defines the response from the OAuth service containing its address.
1057
type OAuthServiceAddressResponse struct {
1058
        // The address of the OAuth service signer
1059
        Address string `json:"address"`
1060
}
1061

1062
type CreateOrganizationTicketRequest struct {
1063
        // Type of the ticket to create (definded externally)
1064
        TicketType string `json:"type"`
1065

1066
        // Title of the ticket
1067
        Title string `json:"title"`
1068

1069
        // Body of the ticket
1070
        Description string `json:"description"`
1071
}
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

© 2025 Coveralls, Inc