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

vocdoni / saas-backend / 16301338771

15 Jul 2025 06:29PM UTC coverage: 56.793% (+0.7%) from 56.082%
16301338771

Pull #165

github

emmdim
refactor:  census creation

- Removed the PublishedCensus type and added it as Census parameter.
- Introduced new OrgMemberAuthFields defining the data options for member authentication.
- Added the `CheckOrgMemberAuthFields` function that checks a set of members and given auth fields empties an
d duplicates
- Add the option to create a census through the api based on a given group
Pull Request #165: Implements group based census creation

250 of 399 new or added lines in 9 files covered. (62.66%)

4 existing lines in 3 files now uncovered.

5104 of 8987 relevant lines covered (56.79%)

25.32 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/google/uuid"
9
        "github.com/vocdoni/saas-backend/db"
10
        "github.com/vocdoni/saas-backend/internal"
11
        "github.com/vocdoni/saas-backend/notifications"
12
        "go.mongodb.org/mongo-driver/bson/primitive"
13
        "go.vocdoni.io/dvote/log"
14
)
15

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

233
// UserInfo represents user information and is used for user registration.
234
// swagger:model UserInfo
235
type UserInfo struct {
236
        // User ID as generated by the backend
237
        ID uint64 `json:"id,omitempty"`
238
        // User's email address
239
        Email string `json:"email,omitempty"`
240

241
        // User's password (not returned in responses)
242
        Password string `json:"password,omitempty"`
243

244
        // User's first name
245
        FirstName string `json:"firstName,omitempty"`
246

247
        // User's last name
248
        LastName string `json:"lastName,omitempty"`
249

250
        // Whether the user's email is verified
251
        Verified bool `json:"verified,omitempty"`
252

253
        // Organizations the user belongs to
254
        Organizations []*UserOrganization `json:"organizations"`
255
}
256

257
// OrganizationInvite represents an invitation to join an organization.
258
// swagger:model OrganizationInvite
259
type OrganizationInvite struct {
260
        // Unique identifier for the invitation
261
        ID string `json:"id"`
262

263
        // Email address of the invitee
264
        Email string `json:"email"`
265

266
        // Role to be assigned to the invitee
267
        Role string `json:"role"`
268

269
        // Expiration time of the invitation
270
        Expiration time.Time `json:"expiration"`
271
}
272

273
// OrganizationInviteList represents a list of pending organization invitations.
274
// swagger:model OrganizationInviteList
275
type OrganizationInviteList struct {
276
        // List of pending invitations
277
        Invites []*OrganizationInvite `json:"pending"`
278
}
279

280
// AcceptOrganizationInvitation represents a request to accept an organization invitation.
281
// swagger:model AcceptOrganizationInvitation
282
type AcceptOrganizationInvitation struct {
283
        // Invitation code
284
        Code string `json:"code"`
285

286
        // User information for registration or identification
287
        User *UserInfo `json:"user"`
288
}
289

290
// UserPasswordUpdate represents a request to update a user's password.
291
// swagger:model UserPasswordUpdate
292
type UserPasswordUpdate struct {
293
        // Current password
294
        OldPassword string `json:"oldPassword"`
295

296
        // New password
297
        NewPassword string `json:"newPassword"`
298
}
299

300
// UserVerification represents user verification information.
301
// swagger:model UserVerification
302
type UserVerification struct {
303
        // User's email address
304
        Email string `json:"email,omitempty"`
305

306
        // Verification code
307
        Code string `json:"code,omitempty"`
308

309
        // Expiration time of the verification code
310
        Expiration time.Time `json:"expiration,omitempty"`
311

312
        // Whether the verification is valid
313
        Valid bool `json:"valid"`
314
}
315

316
// UserPasswordReset represents a request to reset a user's password.
317
// swagger:model UserPasswordReset
318
type UserPasswordReset struct {
319
        // User's email address
320
        Email string `json:"email"`
321

322
        // Password reset code
323
        Code string `json:"code"`
324

325
        // New password
326
        NewPassword string `json:"newPassword"`
327
}
328

329
// LoginResponse represents the response to a successful login request.
330
// swagger:model LoginResponse
331
type LoginResponse struct {
332
        // JWT authentication token
333
        Token string `json:"token"`
334

335
        // Token expiration time
336
        Expirity time.Time `json:"expirity"`
337
}
338

339
// TransactionData contains the data of a transaction to be signed or a signed transaction.
340
// swagger:model TransactionData
341
type TransactionData struct {
342
        // Blockchain address
343
        Address internal.HexBytes `json:"address" swaggertype:"string" format:"hex" example:"deadbeef"`
344

345
        // Transaction payload bytes
346
        TxPayload []byte `json:"txPayload" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
347
}
348

349
// MessageSignature contains a payload and its signature.
350
// swagger:model MessageSignature
351
type MessageSignature struct {
352
        // Blockchain address
353
        Address string `json:"address" swaggertype:"string" format:"hex" example:"deadbeef"`
354

355
        // Message payload bytes
356
        Payload []byte `json:"payload,omitempty" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
357

358
        // Cryptographic signature
359
        Signature internal.HexBytes `json:"signature,omitempty" swaggertype:"string" format:"hex" example:"deadbeef"`
360
}
361

362
// OrganizationFromDB converts a db.Organization to an OrganizationInfo, if the parent
363
// organization is provided it will be included in the response.
364
func OrganizationFromDB(dbOrg, parent *db.Organization) *OrganizationInfo {
29✔
365
        if dbOrg == nil {
29✔
366
                return nil
×
367
        }
×
368
        var parentOrg *OrganizationInfo
29✔
369
        if parent != nil {
29✔
370
                parentOrg = OrganizationFromDB(parent, nil)
×
371
        }
×
372
        details := SubscriptionDetailsFromDB(&dbOrg.Subscription)
29✔
373
        usage := SubscriptionUsageFromDB(&dbOrg.Counters)
29✔
374
        return &OrganizationInfo{
29✔
375
                Address:        dbOrg.Address,
29✔
376
                Website:        dbOrg.Website,
29✔
377
                CreatedAt:      dbOrg.CreatedAt.Format(time.RFC3339),
29✔
378
                Type:           string(dbOrg.Type),
29✔
379
                Size:           dbOrg.Size,
29✔
380
                Color:          dbOrg.Color,
29✔
381
                Subdomain:      dbOrg.Subdomain,
29✔
382
                Country:        dbOrg.Country,
29✔
383
                Timezone:       dbOrg.Timezone,
29✔
384
                Active:         dbOrg.Active,
29✔
385
                Communications: dbOrg.Communications,
29✔
386
                Parent:         parentOrg,
29✔
387
                Subscription:   &details,
29✔
388
                Counters:       &usage,
29✔
389
        }
29✔
390
}
391

392
// OrganizationSubscriptionInfo provides detailed information about an organization's subscription.
393
// swagger:model OrganizationSubscriptionInfo
394
type OrganizationSubscriptionInfo struct {
395
        // Subscription details
396
        SubcriptionDetails SubscriptionDetails `json:"subscriptionDetails"`
397

398
        // Current usage metrics
399
        Usage SubscriptionUsage `json:"usage"`
400

401
        // Subscription plan details
402
        Plan SubscriptionPlan `json:"plan"`
403
}
404

405
// SubscriptionPlan represents a subscription plan in the API.
406
// It is the mirror struct of db.Plan.
407
// swagger:model SubscriptionPlan
408
type SubscriptionPlan struct {
409
        // Unique identifier for the plan
410
        ID uint64 `json:"id"`
411

412
        // Human-readable name of the plan
413
        Name string `json:"name"`
414

415
        // Stripe product ID
416
        StripeID string `json:"stripeId"`
417

418
        // Stripe price ID
419
        StripePriceID string `json:"stripePriceId"`
420

421
        // Starting price in cents
422
        StartingPrice int64 `json:"startingPrice"`
423

424
        // Whether this is the default plan
425
        Default bool `json:"default"`
426

427
        // Organization limits for this plan
428
        Organization SubscriptionPlanLimits `json:"organization"`
429

430
        // Voting types available in this plan
431
        VotingTypes SubscriptionVotingTypes `json:"votingTypes"`
432

433
        // Features available in this plan
434
        Features SubscriptionFeatures `json:"features"`
435

436
        // Census size tiers and pricing
437
        CensusSizeTiers []SubscriptionPlanTier `json:"censusSizeTiers"`
438
}
439

440
// SubscriptionPlanFromDB converts a db.Plan to a SubscriptionPlan.
441
func SubscriptionPlanFromDB(plan *db.Plan) SubscriptionPlan {
×
442
        if plan == nil {
×
443
                return SubscriptionPlan{}
×
444
        }
×
445
        tiers := make([]SubscriptionPlanTier, 0, len(plan.CensusSizeTiers))
×
446
        for _, t := range plan.CensusSizeTiers {
×
447
                tiers = append(tiers, SubscriptionPlanTier{
×
448
                        Amount: t.Amount,
×
449
                        UpTo:   t.UpTo,
×
450
                })
×
451
        }
×
452
        return SubscriptionPlan{
×
453
                ID:              plan.ID,
×
454
                Name:            plan.Name,
×
455
                StripeID:        plan.StripeID,
×
456
                StripePriceID:   plan.StripePriceID,
×
457
                StartingPrice:   plan.StartingPrice,
×
458
                Default:         plan.Default,
×
459
                Organization:    SubscriptionPlanLimits(plan.Organization),
×
460
                VotingTypes:     SubscriptionVotingTypes(plan.VotingTypes),
×
461
                Features:        SubscriptionFeatures(plan.Features),
×
462
                CensusSizeTiers: tiers,
×
463
        }
×
464
}
465

466
// SubscriptionPlanLimits represents the limits of a subscription plan.
467
// It is the mirror struct of db.PlanLimits.
468
// swagger:model SubscriptionPlanLimits
469
type SubscriptionPlanLimits struct {
470
        // Maximum number of users allowed
471
        Users int `json:"users"`
472

473
        // Maximum number of sub-organizations allowed
474
        SubOrgs int `json:"subOrgs"`
475

476
        // Maximum number of voting processes allowed
477
        MaxProcesses int `json:"maxProcesses"`
478

479
        // Maximum number of census allowed
480
        MaxCensus int `json:"maxCensus"`
481

482
        // Maximum duration of voting processes in days
483
        MaxDuration int `json:"maxDuration"`
484

485
        // Whether custom URLs are allowed
486
        CustomURL bool `json:"customURL"`
487

488
        // Maximum number of draft processes allowed
489
        Drafts int `json:"drafts"`
490
}
491

492
// SubscriptionVotingTypes represents the voting types available in a subscription plan.
493
// It is the mirror struct of db.VotingTypes.
494
// swagger:model SubscriptionVotingTypes
495
type SubscriptionVotingTypes struct {
496
        // Whether single choice voting is available
497
        Single bool `json:"single"`
498

499
        // Whether multiple choice voting is available
500
        Multiple bool `json:"multiple"`
501

502
        // Whether approval voting is available
503
        Approval bool `json:"approval"`
504

505
        // Whether cumulative voting is available
506
        Cumulative bool `json:"cumulative"`
507

508
        // Whether ranked choice voting is available
509
        Ranked bool `json:"ranked"`
510

511
        // Whether weighted voting is available
512
        Weighted bool `json:"weighted"`
513
}
514

515
// SubscriptionFeatures represents the features available in a subscription plan.
516
// It is the mirror struct of db.Features.
517
// swagger:model SubscriptionFeatures
518
type SubscriptionFeatures struct {
519
        // Whether anonymous voting is available
520
        Anonymous bool `json:"anonymous"`
521

522
        // Whether census overwrite is allowed
523
        Overwrite bool `json:"overwrite"`
524

525
        // Whether live results are available
526
        LiveResults bool `json:"liveResults"`
527

528
        // Whether UI personalization is available
529
        Personalization bool `json:"personalization"`
530

531
        // Whether email reminders are available
532
        EmailReminder bool `json:"emailReminder"`
533

534
        // Whether SMS notifications are available
535
        SmsNotification bool `json:"smsNotification"`
536

537
        // Whether white labeling is available
538
        WhiteLabel bool `json:"whiteLabel"`
539

540
        // Whether live streaming is available
541
        LiveStreaming bool `json:"liveStreaming"`
542

543
        // Whether eligible for phone support
544
        PhoneSupport bool `json:"phoneSupport"`
545
}
546

547
// SubscriptionPlanTier represents a pricing tier of a subscription plan.
548
// It is the mirror struct of db.PlanTier.
549
// swagger:model SubscriptionPlanTier
550
type SubscriptionPlanTier struct {
551
        // Price amount in cents
552
        Amount int64 `json:"amount"`
553

554
        // Maximum census size for this tier
555
        UpTo int64 `json:"upTo"`
556
}
557

558
// SubscriptionDetails represents the details of an organization's subscription.
559
// It is the mirror struct of db.OrganizationSubscription.
560
// swagger:model SubscriptionDetails
561
type SubscriptionDetails struct {
562
        // ID of the subscription plan
563
        PlanID uint64 `json:"planId"`
564

565
        // Date when the subscription started
566
        StartDate time.Time `json:"startDate"`
567

568
        // Date when the subscription will renew
569
        RenewalDate time.Time `json:"renewalDate"`
570

571
        // Date of the last payment
572
        LastPaymentDate time.Time `json:"lastPaymentDate"`
573

574
        // Whether the subscription is active
575
        Active bool `json:"active"`
576

577
        // Maximum census size allowed
578
        MaxCensusSize int `json:"maxCensusSize"`
579

580
        // Email associated with the subscription
581
        Email string `json:"email"`
582
}
583

584
// SubscriptionDetailsFromDB converts a db.OrganizationSubscription to a SubscriptionDetails.
585
func SubscriptionDetailsFromDB(details *db.OrganizationSubscription) SubscriptionDetails {
29✔
586
        if details == nil {
29✔
587
                return SubscriptionDetails{}
×
588
        }
×
589
        return SubscriptionDetails{
29✔
590
                PlanID:          details.PlanID,
29✔
591
                StartDate:       details.StartDate,
29✔
592
                RenewalDate:     details.RenewalDate,
29✔
593
                LastPaymentDate: details.LastPaymentDate,
29✔
594
                Active:          details.Active,
29✔
595
                MaxCensusSize:   details.MaxCensusSize,
29✔
596
                Email:           details.Email,
29✔
597
        }
29✔
598
}
599

600
// SubscriptionUsage represents the usage metrics of an organization's subscription.
601
// It is the mirror struct of db.OrganizationCounters.
602
// swagger:model SubscriptionUsage
603
type SubscriptionUsage struct {
604
        // Number of SMS messages sent
605
        SentSMS int `json:"sentSMS"`
606

607
        // Number of emails sent
608
        SentEmails int `json:"sentEmails"`
609

610
        // Number of sub-organizations created
611
        SubOrgs int `json:"subOrgs"`
612

613
        // Number of users in the organization
614
        Users int `json:"users"`
615

616
        // Number of voting processes created
617
        Processes int `json:"processes"`
618
}
619

620
// SubscriptionUsageFromDB converts a db.OrganizationCounters to a SubscriptionUsage.
621
func SubscriptionUsageFromDB(usage *db.OrganizationCounters) SubscriptionUsage {
29✔
622
        if usage == nil {
29✔
623
                return SubscriptionUsage{}
×
624
        }
×
625
        return SubscriptionUsage{
29✔
626
                SentSMS:    usage.SentSMS,
29✔
627
                SentEmails: usage.SentEmails,
29✔
628
                SubOrgs:    usage.SubOrgs,
29✔
629
                Users:      usage.Users,
29✔
630
                Processes:  usage.Processes,
29✔
631
        }
29✔
632
}
633

634
// SubscriptionCheckout represents the details required for a subscription checkout process.
635
// swagger:model SubscriptionCheckout
636
type SubscriptionCheckout struct {
637
        // Plan lookup key
638
        LookupKey uint64 `json:"lookupKey"`
639

640
        // URL to return to after checkout
641
        ReturnURL string `json:"returnURL"`
642

643
        // Amount in cents
644
        Amount int64 `json:"amount"`
645

646
        // Organization address
647
        Address string `json:"address"`
648

649
        // Locale for the checkout page
650
        Locale string `json:"locale"`
651
}
652

653
// MemberNotification represents a notification sent to a member.
654
// swagger:model MemberNotification
655
type MemberNotification struct {
656
        // ID of the voting process
657
        ProcessID []byte `json:"processId" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
658

659
        // Notification details
660
        Notification notifications.Notification `json:"notification"`
661

662
        // Whether the notification was sent
663
        Sent bool `json:"sent"`
664

665
        // When the notification was sent
666
        SentAt time.Time `json:"sentAt"`
667
}
668

669
// OrganizationCensus represents a census of an organization.
670
// It is the mirror struct of db.Census.
671
// swagger:model OrganizationCensus
672
type OrganizationCensus struct {
673
        // Unique identifier for the census
674
        ID string `json:"censusId"`
675

676
        // Type of census
677
        Type db.CensusType `json:"type"`
678

679
        // Organization address
680
        OrgAddress string `json:"orgAddress"`
681

682
        // Optional for creating a census based on an organization member group
683
        GroupID string `json:"groupID,omitempty"`
684

685
        // Optional for defining which member data should be used for authentication
686
        AuthFields db.OrgMemberAuthFields `json:"authFields,omitempty"`
687

688
        // Optional for defining which member data should be used for two-factor authentication
689
        TwoFaFields db.OrgMemberTwoFaFields `json:"twoFaFields,omitempty"`
690
}
691

692
// CreateCensusRequest represents a request to create a new census for an organization.
693
// swagger:model CreateCensusRequest
694
type CreateCensusRequest struct {
695
        // Type of census to create
696
        Type db.CensusType `json:"type"`
697

698
        // Organization address
699
        OrgAddress string `json:"orgAddress"`
700

701
        // Optional for creating a census based on an organization member group
702
        GroupID string `json:"groupID,omitempty"`
703

704
        // Optional for defining which member data should be used for authentication
705
        AuthFields db.OrgMemberAuthFields `json:"authFields,omitempty"`
706

707
        // Optional for defining which member data should be used for two-factor authentication
708
        TwoFaFields db.OrgMemberTwoFaFields `json:"twoFaFields,omitempty"`
709
}
710

711
type CreateCensusResponse struct {
712
        // Unique identifier for the census
713
        ID string `json:"censusID,omitempty"`
714

715
        MemberWarnings db.OrgMemberAggregationResults `json:"memberWarnings,omitempty"`
716
}
717

718
// PublishCensusRequest represents a request to create a new census for an organization.
719
// swagger:model PublishCensusRequest
720
type PublishCensusRequest struct {
721
        // Type of census to create
722
        Type db.CensusType `json:"type"`
723
}
724

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

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

735
// OrganizationCensusFromDB converts a db.Census to an OrganizationCensus.
736
func OrganizationCensusFromDB(census *db.Census) OrganizationCensus {
1✔
737
        if census == nil {
1✔
NEW
738
                return OrganizationCensus{}
×
NEW
739
        }
×
740
        return OrganizationCensus{
1✔
741
                ID:          census.ID.Hex(),
1✔
742
                Type:        census.Type,
1✔
743
                OrgAddress:  census.OrgAddress,
1✔
744
                GroupID:     census.GroupID.Hex(),
1✔
745
                TwoFaFields: census.TwoFaFields,
1✔
746
                AuthFields:  census.AuthFields,
1✔
747
        }
1✔
748
}
749

750
// OrganizationCensuses wraps a list of censuses of an organization.
751
// swagger:model OrganizationCensuses
752
type OrganizationCensuses struct {
753
        // List of organization censuses
754
        Censuses []OrganizationCensus `json:"censuses"`
755
}
756

757
// AddMembersRequest defines the payload for adding members to a census.
758
// swagger:model AddMembersRequest
759
type AddMembersRequest struct {
760
        // List of members to add
761
        Members []OrgMember `json:"members"`
762
}
763

764
// DbOrgMembers converts the members in the request to db.OrgMember objects.
765
func (r *AddMembersRequest) DbOrgMembers(orgAddress string) []db.OrgMember {
12✔
766
        members := make([]db.OrgMember, 0, len(r.Members))
12✔
767
        for _, p := range r.Members {
38✔
768
                members = append(members, p.ToDb(orgAddress))
26✔
769
        }
26✔
770
        return members
12✔
771
}
772

773
type DeleteMembersRequest struct {
774
        // List of member internal ids numbers to delete
775
        IDs []string `json:"ids"`
776
}
777
type DeleteMembersResponse struct {
778
        // Number of members deleted
779
        Count int `json:"count"`
780
}
781

782
// OrgMember defines the structure of a member in the API.
783
// It is the mirror struct of db.OrgMember.
784
// swagger:model OrgMember
785
type OrgMember struct {
786
        // Member's internal unique internal ID
787
        ID string `json:"id"`
788
        // Unique member number as defined by the organization
789
        MemberNumber string `json:"memberNumber"`
790

791
        // Member's name
792
        Name string `json:"name,omitempty"`
793

794
        // Member's surname
795
        Surname string `json:"surname,omitempty"`
796

797
        // Member's National ID No
798
        NationalID string `json:"nationalId,omitempty"`
799

800
        // Member's date of birth in format YYYY-MM-DD
801
        BirthDate string `json:"birthDate,omitempty"`
802

803
        // Member's email address
804
        Email string `json:"email,omitempty"`
805

806
        // Member's phone number
807
        Phone string `json:"phone,omitempty"`
808

809
        // Member's password (for authentication)
810
        Password string `json:"password,omitempty"`
811

812
        // Additional custom fields
813
        Other map[string]any `json:"other"`
814
}
815

816
// ToDb converts an OrgMember to a db.OrgMember.
817
func (p *OrgMember) ToDb(orgAddress string) db.OrgMember {
26✔
818
        parsedBirthDate := time.Time{}
26✔
819
        if len(p.BirthDate) > 0 {
33✔
820
                // Parse the birth date from string to time.Time
7✔
821
                var err error
7✔
822
                parsedBirthDate, err = time.Parse("2006-01-02", p.BirthDate)
7✔
823
                if err != nil {
8✔
824
                        log.Warnf("Failed to parse birth date %s for member %s: %v", p.BirthDate, p.MemberNumber, err)
1✔
825
                }
1✔
826
        }
827
        id := primitive.NilObjectID
26✔
828
        if len(p.ID) > 0 {
27✔
829
                // Convert the ID from string to ObjectID
1✔
830
                var err error
1✔
831
                id, err = primitive.ObjectIDFromHex(p.ID)
1✔
832
                if err != nil {
1✔
833
                        log.Warnf("Failed to convert member ID %s to ObjectID: %v", p.ID, err)
×
834
                }
×
835
        }
836
        return db.OrgMember{
26✔
837
                ID:             id,
26✔
838
                OrgAddress:     orgAddress,
26✔
839
                MemberNumber:   p.MemberNumber,
26✔
840
                Name:           p.Name,
26✔
841
                Surname:        p.Surname,
26✔
842
                NationalID:     p.NationalID,
26✔
843
                BirthDate:      p.BirthDate,
26✔
844
                ParsedBirtDate: parsedBirthDate,
26✔
845
                Email:          p.Email,
26✔
846
                Phone:          p.Phone,
26✔
847
                Password:       p.Password,
26✔
848
                Other:          p.Other,
26✔
849
        }
26✔
850
}
851

852
func OrgMemberFromDb(p db.OrgMember) OrgMember {
34✔
853
        hashedPhone := string(p.HashedPhone)
34✔
854
        if len(hashedPhone) > 0 {
66✔
855
                // If the phone is hashed, we return the last 6 characters
32✔
856
                hashedPhone = hashedPhone[len(hashedPhone)-6:]
32✔
857
        }
32✔
858
        // if p.BirthDate != nil {
859

860
        return OrgMember{
34✔
861
                ID:           p.ID.Hex(),
34✔
862
                MemberNumber: p.MemberNumber,
34✔
863
                Name:         p.Name,
34✔
864
                Surname:      p.Surname,
34✔
865
                NationalID:   p.NationalID,
34✔
866
                BirthDate:    p.BirthDate,
34✔
867
                Email:        p.Email,
34✔
868
                Phone:        hashedPhone,
34✔
869
                Other:        p.Other,
34✔
870
        }
34✔
871
}
872

873
type OrganizationMembersResponse struct {
874
        // Total number of pages available
875
        Pages int `json:"pages"`
876

877
        // Current page number
878
        Page int `json:"page"`
879

880
        // Total number of members in the organization
881
        Members []OrgMember `json:"members"`
882
}
883

884
// AddMembersResponse defines the response for successful member addition.
885
// swagger:model AddMembersResponse
886
type AddMembersResponse struct {
887
        // Number of members added
888
        Count uint32 `json:"count"`
889

890
        // Errors encountered during job
891
        Errors []error `json:"errors"`
892

893
        // Job ID for tracking the addition process
894
        JobID internal.HexBytes `json:"jobId" swaggertype:"string" format:"hex" example:"deadbeef"`
895
}
896

897
// Request types for process operations
898

899
// CreateProcessRequest defines the payload for creating a new voting process.
900
// swagger:model CreateProcessRequest
901
type CreateProcessRequest struct {
902
        // Merkle root of the published census
903
        PublishedCensusRoot internal.HexBytes `json:"censusRoot" swaggertype:"string" format:"hex" example:"deadbeef"`
904

905
        // URI of the published census
906
        PublishedCensusURI string `json:"censusUri"`
907

908
        // Census ID
909
        CensusID internal.HexBytes `json:"censusId" swaggertype:"string" format:"hex" example:"deadbeef"`
910

911
        // Additional metadata for the process
912
        // Can be any key-value pairs
913
        Metadata []byte `json:"metadata,omitempty" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
914
}
915

916
// InitiateAuthRequest defines the payload for participant authentication.
917
// swagger:model InitiateAuthRequest
918
type InitiateAuthRequest struct {
919
        // Unique participant ID
920
        ParticipantID string `json:"participantId"`
921

922
        // Participant's email address (optional)
923
        Email string `json:"email,omitempty"`
924

925
        // Participant's phone number (optional)
926
        Phone string `json:"phone,omitempty"`
927

928
        // Participant's password (optional)
929
        Password string `json:"password,omitempty"`
930
}
931

932
// VerifyAuthRequest defines the payload for auth code verification.
933
// swagger:model VerifyAuthRequest
934
type VerifyAuthRequest struct {
935
        // Authentication token
936
        Token string `json:"token"`
937

938
        // Verification code
939
        Code string `json:"code"`
940
}
941

942
// GenerateProofRequest defines the payload for generating voting proof.
943
// swagger:model GenerateProofRequest
944
type GenerateProofRequest struct {
945
        // Authentication token
946
        Token string `json:"token"`
947

948
        // Blinded address for proof generation
949
        BlindedAddress []byte `json:"blindedAddress" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
950
}
951

952
// Two-factor authentication types
953

954
// AuthRequest defines the payload for requesting authentication.
955
// swagger:model AuthRequest
956
type AuthRequest struct {
957
        // Authentication token
958
        AuthToken *uuid.UUID `json:"authToken,omitempty"`
959

960
        // Authentication data (reserved for the auth handler)
961
        AuthData []string `json:"authData,omitempty"`
962
}
963

964
// SignRequest defines the payload for requesting a signature.
965
// swagger:model SignRequest
966
type SignRequest struct {
967
        // Token R value
968
        TokenR internal.HexBytes `json:"tokenR" swaggertype:"string" format:"hex" example:"deadbeef"`
969

970
        // Authentication token
971
        AuthToken *uuid.UUID `json:"authToken"`
972

973
        // Blockchain address
974
        Address string `json:"address,omitempty"`
975

976
        // Payload to sign
977
        Payload string `json:"payload,omitempty"`
978

979
        // Election ID
980
        ElectionID internal.HexBytes `json:"electionId,omitempty" swaggertype:"string" format:"hex" example:"deadbeef"`
981
}
982

983
// CreateProcessBundleRequest defines the payload for creating a new process bundle.
984
// swagger:model CreateProcessBundleRequest
985
type CreateProcessBundleRequest struct {
986
        // Census ID
987
        CensusID string `json:"censusId"`
988

989
        // List of process IDs to include in the bundle
990
        Processes []string `json:"processes"`
991
}
992

993
// CreateProcessBundleResponse defines the response for a successful process bundle creation.
994
// swagger:model CreateProcessBundleResponse
995
type CreateProcessBundleResponse struct {
996
        // URI of the created process bundle
997
        URI string `json:"uri"`
998

999
        // Merkle root of the process bundle
1000
        Root internal.HexBytes `json:"root" swaggertype:"string" format:"hex" example:"deadbeef"`
1001
}
1002

1003
// OAuthLoginRequest defines the payload for register/login through the OAuth service.
1004
// swagger:model OAuthLoginRequest
1005
type OAuthLoginRequest struct {
1006
        // User email address
1007
        Email string `json:"email"`
1008
        // User first name
1009
        FirstName string `json:"firstName"`
1010
        // User last name
1011
        LastName string `json:"lastName"`
1012
        // The signature made by the OAuth service on top of the user email
1013
        OAuthSignature string `json:"oauthSignature"`
1014
        // The signature made by the user on on top of the oauth signature
1015
        UserOAuthSignature string `json:"userOAuthSignature"`
1016
        // The address of the user
1017
        Address string `json:"address"`
1018
}
1019

1020
type OAuthLoginResponse struct {
1021
        // JWT authentication token
1022
        Token string `json:"token"`
1023

1024
        // Token expiration time
1025
        Expirity time.Time `json:"expirity"`
1026

1027
        // Whether the user had to be  registered
1028
        Registered bool `json:"registered"`
1029
}
1030

1031
// OAuthServiceAddressResponse defines the response from the OAuth service containing its address.
1032
type OAuthServiceAddressResponse struct {
1033
        // The address of the OAuth service signer
1034
        Address string `json:"address"`
1035
}
1036

1037
type CreateOrganizationTicketRequest struct {
1038
        // Type of the ticket to create (definded externally)
1039
        TicketType string `json:"type"`
1040

1041
        // Title of the ticket
1042
        Title string `json:"title"`
1043

1044
        // Body of the ticket
1045
        Description string `json:"description"`
1046
}
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