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

vocdoni / saas-backend / 16170371097

09 Jul 2025 01:15PM UTC coverage: 56.05% (+0.1%) from 55.944%
16170371097

Pull #176

github

altergui
db: check MatchedCount on methods that do UpdateOne

until now, they succeeded even when nothing was updated, leading to
hard to understand bugs.

* UpdateOrganizationUserRole
* RemoveOrganizationUser
* SetOrganizationSubscription
* AddOrganizationMeta
Pull Request #176: db: check MatchedCount on methods that do UpdateOne

10 of 12 new or added lines in 1 file covered. (83.33%)

121 existing lines in 5 files now uncovered.

4910 of 8760 relevant lines covered (56.05%)

24.47 hits per line

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

72.79
/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
// OrganizationMembers represents a list of users of an organization
73
// swagger:model OrganizationMembers
74
//
75
// Deprecated: use OrganizationUsers instead.
76
type OrganizationMembers struct {
77
        // List of organization users
78
        Members []*OrganizationUser `json:"members"`
79
}
80

81
// OrganizationUser represents a user of an organization with their role.
82
// swagger:model OrganizationUser
83
type OrganizationUser struct {
84
        // User information
85
        Info *UserInfo `json:"info"`
86

87
        // The role of the user in the organization
88
        Role string `json:"role"`
89
}
90

91
// OrganizationAddresses represents a list of blockchain addresses of organizations.
92
// swagger:model OrganizationAddresses
93
type OrganizationAddresses struct {
94
        // List of organization blockchain addresses
95
        Addresses []string `json:"addresses"`
96
}
97

98
// UserOrganization represents the organization of a user including their role.
99
// swagger:model UserOrganization
100
type UserOrganization struct {
101
        // The role of the user in the organization
102
        Role string `json:"role"`
103

104
        // Organization information
105
        Organization *OrganizationInfo `json:"organization"`
106
}
107

108
// OrganizationRole represents a role that can be assigned to organization users.
109
// swagger:model OrganizationRole
110
type OrganizationRole struct {
111
        // Role identifier
112
        Role string `json:"role"`
113

114
        // Human-readable name of the role
115
        Name string `json:"name"`
116

117
        // Whether this role has write permissions
118
        WritePermission bool `json:"writePermission"`
119
}
120

121
// OrganizationRoleList represents a list of organization roles.
122
// swagger:model OrganizationRoleList
123
type OrganizationRoleList struct {
124
        // List of organization roles
125
        Roles []*OrganizationRole `json:"roles"`
126
}
127

128
// OrganizationType represents a type of organization.
129
// swagger:model OrganizationType
130
type OrganizationType struct {
131
        // Type identifier
132
        Type string `json:"type"`
133

134
        // Human-readable name of the type
135
        Name string `json:"name"`
136
}
137

138
// OrganizationTypeList represents a list of organization types.
139
// swagger:model OrganizationTypeList
140
type OrganizationTypeList struct {
141
        // List of organization types
142
        Types []*OrganizationType `json:"types"`
143
}
144

145
// OrganizationAddMetaRequest represents a request to add or update meta information for an organization.
146
// swagger:model OrganizationAddMetaRequest
147
type OrganizationAddMetaRequest struct {
148
        // Set of key-value pairs to add or update in the organization's meta information
149
        Meta map[string]any `json:"meta"`
150
}
151

152
// OrganizationMetaResponse represents the meta information of an organization.
153
// swagger:model OrganizationMetaResponse
154
type OrganizationMetaResponse struct {
155
        // Meta information of the organization
156
        Meta map[string]any `json:"meta"`
157
}
158

159
// OrganizationDeleteMetaRequest represents a request to delete a set of keys from the meta information
160
// for an organization.
161
// swagger:model OrganizationDeleteMetaRequest
162
type OrganizationDeleteMetaRequest struct {
163
        // List of keys to delete from the organization's meta information
164
        Keys []string `json:"keys"`
165
}
166

167
// UpdateOrganizationUserRoleRequest represents a request to update the role of an organization user.
168
// swagger:model UpdateOrganizationUserRoleRequest
169
type UpdateOrganizationUserRoleRequest struct {
170
        // The new role to assign to the user
171
        Role string `json:"role"`
172
}
173

174
// CreateOrganizationMemberGroupRequest represents a request to create a new organization member group.
175
// swagger:model CreateOrganizationMemberGroupRequest
176
type CreateOrganizationMemberGroupRequest struct {
177
        // Title of the group
178
        Title string `json:"title"`
179
        // Description of the group
180
        Description string `json:"description"`
181
        // The IDs of the members to add to the group
182
        MemberIDs []string `json:"memberIds"`
183
}
184

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

206
// OrganizationMemberGroupsResponse represents the response for listing organization member groups.
207
// swagger:model OrganizationMemberGroupsResponse
208
type OrganizationMemberGroupsResponse struct {
209
        // Total number of pages
210
        TotalPages int `json:"totalPages"`
211
        // Current page number
212
        CurrentPage int `json:"currentPage"`
213
        // List of organization member groups
214
        Groups []*OrganizationMemberGroupInfo `json:"groups"`
215
}
216

217
// UpdateOrganizationMemberGroupsRequest represents a request to update an organization member group
218
// title, description or members.
219
// swagger:model UpdateOrganizationMemberGroupsRequest
220
type UpdateOrganizationMemberGroupsRequest struct {
221
        // Updated Title
222
        Title string `json:"title"`
223
        // Updated Description
224
        Description string `json:"description"`
225
        // The IDs of the members to add to the group
226
        AddMembers []string `json:"addMembers"`
227
        // The IDs of the members to remove from the group
228
        RemoveMembers []string `json:"removeMembers"`
229
}
230

231
// ListOrganizationMemberGroupResponse represents the response for listing the members of an  organization group.
232
// swagger:model ListOrganizationMemberGroupResponse
233
type ListOrganizationMemberGroupResponse struct {
234
        // Total number of pages
235
        TotalPages int `json:"totalPages"`
236
        // Current page number
237
        CurrentPage int `json:"currentPage"`
238
        // List of organization group members
239
        Members []OrgMember `json:"members"`
240
}
241

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

250
        // User's password (not returned in responses)
251
        Password string `json:"password,omitempty"`
252

253
        // User's first name
254
        FirstName string `json:"firstName,omitempty"`
255

256
        // User's last name
257
        LastName string `json:"lastName,omitempty"`
258

259
        // Whether the user's email is verified
260
        Verified bool `json:"verified,omitempty"`
261

262
        // Organizations the user belongs to
263
        Organizations []*UserOrganization `json:"organizations"`
264
}
265

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

272
        // Email address of the invitee
273
        Email string `json:"email"`
274

275
        // Role to be assigned to the invitee
276
        Role string `json:"role"`
277

278
        // Expiration time of the invitation
279
        Expiration time.Time `json:"expiration"`
280
}
281

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

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

295
        // User information for registration or identification
296
        User *UserInfo `json:"user"`
297
}
298

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

305
        // New password
306
        NewPassword string `json:"newPassword"`
307
}
308

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

315
        // Verification code
316
        Code string `json:"code,omitempty"`
317

318
        // Expiration time of the verification code
319
        Expiration time.Time `json:"expiration,omitempty"`
320

321
        // Whether the verification is valid
322
        Valid bool `json:"valid"`
323
}
324

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

331
        // Password reset code
332
        Code string `json:"code"`
333

334
        // New password
335
        NewPassword string `json:"newPassword"`
336
}
337

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

344
        // Token expiration time
345
        Expirity time.Time `json:"expirity"`
346
}
347

348
// TransactionData contains the data of a transaction to be signed or a signed transaction.
349
// swagger:model TransactionData
350
type TransactionData struct {
351
        // Blockchain address
352
        Address internal.HexBytes `json:"address" swaggertype:"string" format:"hex" example:"deadbeef"`
353

354
        // Transaction payload bytes
355
        TxPayload []byte `json:"txPayload" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
356
}
357

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

364
        // Message payload bytes
365
        Payload []byte `json:"payload,omitempty" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
366

367
        // Cryptographic signature
368
        Signature internal.HexBytes `json:"signature,omitempty" swaggertype:"string" format:"hex" example:"deadbeef"`
369
}
370

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

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

407
        // Current usage metrics
408
        Usage SubscriptionUsage `json:"usage"`
409

410
        // Subscription plan details
411
        Plan SubscriptionPlan `json:"plan"`
412
}
413

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

421
        // Human-readable name of the plan
422
        Name string `json:"name"`
423

424
        // Stripe product ID
425
        StripeID string `json:"stripeID"`
426

427
        // Stripe price ID
428
        StripePriceID string `json:"stripePriceID"`
429

430
        // Starting price in cents
431
        StartingPrice int64 `json:"startingPrice"`
432

433
        // Whether this is the default plan
434
        Default bool `json:"default"`
435

436
        // Organization limits for this plan
437
        Organization SubscriptionPlanLimits `json:"organization"`
438

439
        // Voting types available in this plan
440
        VotingTypes SubscriptionVotingTypes `json:"votingTypes"`
441

442
        // Features available in this plan
443
        Features SubscriptionFeatures `json:"features"`
444

445
        // Census size tiers and pricing
446
        CensusSizeTiers []SubscriptionPlanTier `json:"censusSizeTiers"`
447
}
448

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

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

482
        // Maximum number of sub-organizations allowed
483
        SubOrgs int `json:"subOrgs"`
484

485
        // Maximum number of voting processes allowed
486
        MaxProcesses int `json:"maxProcesses"`
487

488
        // Maximum number of census allowed
489
        MaxCensus int `json:"maxCensus"`
490

491
        // Maximum duration of voting processes in days
492
        MaxDuration int `json:"maxDuration"`
493

494
        // Whether custom URLs are allowed
495
        CustomURL bool `json:"customURL"`
496

497
        // Maximum number of draft processes allowed
498
        Drafts int `json:"drafts"`
499
}
500

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

508
        // Whether multiple choice voting is available
509
        Multiple bool `json:"multiple"`
510

511
        // Whether approval voting is available
512
        Approval bool `json:"approval"`
513

514
        // Whether cumulative voting is available
515
        Cumulative bool `json:"cumulative"`
516

517
        // Whether ranked choice voting is available
518
        Ranked bool `json:"ranked"`
519

520
        // Whether weighted voting is available
521
        Weighted bool `json:"weighted"`
522
}
523

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

531
        // Whether census overwrite is allowed
532
        Overwrite bool `json:"overwrite"`
533

534
        // Whether live results are available
535
        LiveResults bool `json:"liveResults"`
536

537
        // Whether UI personalization is available
538
        Personalization bool `json:"personalization"`
539

540
        // Whether email reminders are available
541
        EmailReminder bool `json:"emailReminder"`
542

543
        // Whether SMS notifications are available
544
        SmsNotification bool `json:"smsNotification"`
545

546
        // Whether white labeling is available
547
        WhiteLabel bool `json:"whiteLabel"`
548

549
        // Whether live streaming is available
550
        LiveStreaming bool `json:"liveStreaming"`
551

552
        // Whether eligible for phone support
553
        PhoneSupport bool `json:"phoneSupport"`
554
}
555

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

563
        // Maximum census size for this tier
564
        UpTo int64 `json:"upTo"`
565
}
566

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

574
        // Date when the subscription started
575
        StartDate time.Time `json:"startDate"`
576

577
        // Date when the subscription will renew
578
        RenewalDate time.Time `json:"renewalDate"`
579

580
        // Date of the last payment
581
        LastPaymentDate time.Time `json:"lastPaymentDate"`
582

583
        // Whether the subscription is active
584
        Active bool `json:"active"`
585

586
        // Maximum census size allowed
587
        MaxCensusSize int `json:"maxCensusSize"`
588

589
        // Email associated with the subscription
590
        Email string `json:"email"`
591
}
592

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

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

616
        // Number of emails sent
617
        SentEmails int `json:"sentEmails"`
618

619
        // Number of sub-organizations created
620
        SubOrgs int `json:"subOrgs"`
621

622
        // Number of users in the organization
623
        Users int `json:"users"`
624

625
        // Number of voting processes created
626
        Processes int `json:"processes"`
627
}
628

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

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

649
        // URL to return to after checkout
650
        ReturnURL string `json:"returnURL"`
651

652
        // Amount in cents
653
        Amount int64 `json:"amount"`
654

655
        // Organization address
656
        Address string `json:"address"`
657

658
        // Locale for the checkout page
659
        Locale string `json:"locale"`
660
}
661

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

668
        // Notification details
669
        Notification notifications.Notification `json:"notification"`
670

671
        // Whether the notification was sent
672
        Sent bool `json:"sent"`
673

674
        // When the notification was sent
675
        SentAt time.Time `json:"sentAt"`
676
}
677

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

685
        // Type of census
686
        Type db.CensusType `json:"type"`
687

688
        // Organization address
689
        OrgAddress string `json:"orgAddress"`
690
}
691

692
// OrganizationCensusFromDB converts a db.Census to an OrganizationCensus.
693
func OrganizationCensusFromDB(census *db.Census) OrganizationCensus {
1✔
694
        if census == nil {
1✔
UNCOV
695
                return OrganizationCensus{}
×
UNCOV
696
        }
×
697
        return OrganizationCensus{
1✔
698
                ID:         census.ID.Hex(),
1✔
699
                Type:       census.Type,
1✔
700
                OrgAddress: census.OrgAddress,
1✔
701
        }
1✔
702
}
703

704
// PublishedCensusResponse represents a published census.
705
// swagger:model PublishedCensusResponse
706
type PublishedCensusResponse struct {
707
        // URI of the published census
708
        URI string `json:"uri" bson:"uri"`
709

710
        // Merkle root of the census
711
        Root internal.HexBytes `json:"root" bson:"root" swaggertype:"string" format:"hex" example:"deadbeef"`
712

713
        // Census ID
714
        CensusID internal.HexBytes `json:"censusId" bson:"censusId" swaggertype:"string" format:"hex" example:"deadbeef"`
715
}
716

717
// OrganizationCensuses wraps a list of censuses of an organization.
718
// swagger:model OrganizationCensuses
719
type OrganizationCensuses struct {
720
        // List of organization censuses
721
        Censuses []OrganizationCensus `json:"censuses"`
722
}
723

724
// AddMembersRequest defines the payload for adding members to a census.
725
// swagger:model AddMembersRequest
726
type AddMembersRequest struct {
727
        // List of members to add
728
        Members []OrgMember `json:"members"`
729
}
730

731
// DbOrgMembers converts the members in the request to db.OrgMember objects.
732
func (r *AddMembersRequest) DbOrgMembers(orgAddress string) []db.OrgMember {
9✔
733
        members := make([]db.OrgMember, 0, len(r.Members))
9✔
734
        for _, p := range r.Members {
30✔
735
                members = append(members, p.ToDb(orgAddress))
21✔
736
        }
21✔
737
        return members
9✔
738
}
739

740
type DeleteMembersRequest struct {
741
        // List of member internal ids numbers to delete
742
        IDs []string `json:"ids"`
743
}
744
type DeleteMembersResponse struct {
745
        // Number of members deleted
746
        Count int `json:"count"`
747
}
748

749
// OrgMember defines the structure of a member in the API.
750
// It is the mirror struct of db.OrgMember.
751
// swagger:model OrgMember
752
type OrgMember struct {
753
        // Member's internal unique internal ID
754
        ID string `json:"id"`
755
        // Unique member number as defined by the organization
756
        MemberNumber string `json:"memberNumber"`
757

758
        // Member's name
759
        Name string `json:"name,omitempty"`
760

761
        // Member's surname
762
        Surname string `json:"surname,omitempty"`
763

764
        // Member's National ID No
765
        NationalID string `json:"nationalID,omitempty"`
766

767
        // Member's date of birth in format YYYY-MM-DD
768
        BirthDate string `json:"birthDate,omitempty"`
769

770
        // Member's email address
771
        Email string `json:"email,omitempty"`
772

773
        // Member's phone number
774
        Phone string `json:"phone,omitempty"`
775

776
        // Member's password (for authentication)
777
        Password string `json:"password,omitempty"`
778

779
        // Additional custom fields
780
        Other map[string]any `json:"other"`
781
}
782

783
// ToDb converts an OrgMember to a db.OrgMember.
784
func (p *OrgMember) ToDb(orgAddress string) db.OrgMember {
21✔
785
        parsedBirthDate := time.Time{}
21✔
786
        if len(p.BirthDate) > 0 {
28✔
787
                // Parse the birth date from string to time.Time
7✔
788
                var err error
7✔
789
                parsedBirthDate, err = time.Parse("2006-01-02", p.BirthDate)
7✔
790
                if err != nil {
7✔
791
                        log.Warnf("Failed to parse birth date %s for member %s: %v", p.BirthDate, p.MemberNumber, err)
×
792
                }
×
793
        }
794
        id := primitive.NilObjectID
21✔
795
        if len(p.ID) > 0 {
22✔
796
                // Convert the ID from string to ObjectID
1✔
797
                var err error
1✔
798
                id, err = primitive.ObjectIDFromHex(p.ID)
1✔
799
                if err != nil {
1✔
UNCOV
800
                        log.Warnf("Failed to convert member ID %s to ObjectID: %v", p.ID, err)
×
UNCOV
801
                }
×
802
        }
803
        return db.OrgMember{
21✔
804
                ID:             id,
21✔
805
                OrgAddress:     orgAddress,
21✔
806
                MemberNumber:   p.MemberNumber,
21✔
807
                Name:           p.Name,
21✔
808
                Surname:        p.Surname,
21✔
809
                NationalID:     p.NationalID,
21✔
810
                BirthDate:      p.BirthDate,
21✔
811
                ParsedBirtDate: parsedBirthDate,
21✔
812
                Email:          p.Email,
21✔
813
                Phone:          p.Phone,
21✔
814
                Password:       p.Password,
21✔
815
                Other:          p.Other,
21✔
816
        }
21✔
817
}
818

819
func OrgMemberFromDb(p db.OrgMember) OrgMember {
23✔
820
        hashedPhone := string(p.HashedPhone)
23✔
821
        if len(hashedPhone) > 0 {
46✔
822
                // If the phone is hashed, we return the last 6 characters
23✔
823
                hashedPhone = hashedPhone[len(hashedPhone)-6:]
23✔
824
        }
23✔
825
        // if p.BirthDate != nil {
826

827
        return OrgMember{
23✔
828
                ID:           p.ID.Hex(),
23✔
829
                MemberNumber: p.MemberNumber,
23✔
830
                Name:         p.Name,
23✔
831
                Surname:      p.Surname,
23✔
832
                NationalID:   p.NationalID,
23✔
833
                BirthDate:    p.BirthDate,
23✔
834
                Email:        p.Email,
23✔
835
                Phone:        hashedPhone,
23✔
836
                Other:        p.Other,
23✔
837
        }
23✔
838
}
839

840
type OrganizationMembersResponse struct {
841
        // Total number of pages available
842
        Pages int `json:"pages"`
843

844
        // Current page number
845
        Page int `json:"page"`
846

847
        // Total number of members in the organization
848
        Members []OrgMember `json:"members"`
849
}
850

851
// AddMembersResponse defines the response for successful member addition.
852
// swagger:model AddMembersResponse
853
type AddMembersResponse struct {
854
        // Number of members added
855
        Count uint32 `json:"count"`
856

857
        // Job ID for tracking the addition process
858
        JobID internal.HexBytes `json:"jobID" swaggertype:"string" format:"hex" example:"deadbeef"`
859
}
860

861
// Request types for process operations
862

863
// CreateProcessRequest defines the payload for creating a new voting process.
864
// swagger:model CreateProcessRequest
865
type CreateProcessRequest struct {
866
        // Merkle root of the published census
867
        PublishedCensusRoot internal.HexBytes `json:"censusRoot" swaggertype:"string" format:"hex" example:"deadbeef"`
868

869
        // URI of the published census
870
        PublishedCensusURI string `json:"censusUri"`
871

872
        // Census ID
873
        CensusID internal.HexBytes `json:"censusID" swaggertype:"string" format:"hex" example:"deadbeef"`
874

875
        // Additional metadata for the process
876
        // Can be any key-value pairs
877
        Metadata []byte `json:"metadata,omitempty" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
878
}
879

880
// InitiateAuthRequest defines the payload for member authentication.
881
// swagger:model InitiateAuthRequest
882
type InitiateAuthRequest struct {
883
        // Unique member number
884
        ParticipantID string `json:"participantID"`
885

886
        // Member's email address (optional)
887
        Email string `json:"email,omitempty"`
888

889
        // Member's phone number (optional)
890
        Phone string `json:"phone,omitempty"`
891

892
        // Member's password (optional)
893
        Password string `json:"password,omitempty"`
894
}
895

896
// VerifyAuthRequest defines the payload for auth code verification.
897
// swagger:model VerifyAuthRequest
898
type VerifyAuthRequest struct {
899
        // Authentication token
900
        Token string `json:"token"`
901

902
        // Verification code
903
        Code string `json:"code"`
904
}
905

906
// GenerateProofRequest defines the payload for generating voting proof.
907
// swagger:model GenerateProofRequest
908
type GenerateProofRequest struct {
909
        // Authentication token
910
        Token string `json:"token"`
911

912
        // Blinded address for proof generation
913
        BlindedAddress []byte `json:"blindedAddress" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
914
}
915

916
// Two-factor authentication types
917

918
// AuthRequest defines the payload for requesting authentication.
919
// swagger:model AuthRequest
920
type AuthRequest struct {
921
        // Authentication token
922
        AuthToken *uuid.UUID `json:"authToken,omitempty"`
923

924
        // Authentication data (reserved for the auth handler)
925
        AuthData []string `json:"authData,omitempty"`
926
}
927

928
// SignRequest defines the payload for requesting a signature.
929
// swagger:model SignRequest
930
type SignRequest struct {
931
        // Token R value
932
        TokenR internal.HexBytes `json:"tokenR" swaggertype:"string" format:"hex" example:"deadbeef"`
933

934
        // Authentication token
935
        AuthToken *uuid.UUID `json:"authToken"`
936

937
        // Blockchain address
938
        Address string `json:"address,omitempty"`
939

940
        // Payload to sign
941
        Payload string `json:"payload,omitempty"`
942

943
        // Election ID
944
        ElectionID internal.HexBytes `json:"electionId,omitempty" swaggertype:"string" format:"hex" example:"deadbeef"`
945
}
946

947
// CreateProcessBundleRequest defines the payload for creating a new process bundle.
948
// swagger:model CreateProcessBundleRequest
949
type CreateProcessBundleRequest struct {
950
        // Census ID
951
        CensusID string `json:"censusID"`
952

953
        // List of process IDs to include in the bundle
954
        Processes []string `json:"processes"`
955
}
956

957
// CreateProcessBundleResponse defines the response for a successful process bundle creation.
958
// swagger:model CreateProcessBundleResponse
959
type CreateProcessBundleResponse struct {
960
        // URI of the created process bundle
961
        URI string `json:"uri"`
962

963
        // Merkle root of the process bundle
964
        Root internal.HexBytes `json:"root" swaggertype:"string" format:"hex" example:"deadbeef"`
965
}
966

967
// OAuthLoginRequest defines the payload for register/login through the OAuth service.
968
// swagger:model OAuthLoginRequest
969
type OAuthLoginRequest struct {
970
        // User email address
971
        Email string `json:"email"`
972
        // User first name
973
        FirstName string `json:"firstName"`
974
        // User last name
975
        LastName string `json:"lastName"`
976
        // The signature made by the OAuth service on top of the user email
977
        OAuthSignature string `json:"oauthSignature"`
978
        // The signature made by the user on on top of the oauth signature
979
        UserOAuthSignature string `json:"userOAuthSignature"`
980
        // The address of the user
981
        Address string `json:"address"`
982
}
983

984
type OAuthLoginResponse struct {
985
        // JWT authentication token
986
        Token string `json:"token"`
987

988
        // Token expiration time
989
        Expirity time.Time `json:"expirity"`
990

991
        // Whether the user had to be  registered
992
        Registered bool `json:"registered"`
993
}
994

995
// OAuthServiceAddressResponse defines the response from the OAuth service containing its address.
996
type OAuthServiceAddressResponse struct {
997
        // The address of the OAuth service signer
998
        Address string `json:"address"`
999
}
1000

1001
type CreateOrganizationTicketRequest struct {
1002
        // Type of the ticket to create (definded externally)
1003
        TicketType string `json:"type"`
1004

1005
        // Title of the ticket
1006
        Title string `json:"title"`
1007

1008
        // Body of the ticket
1009
        Description string `json:"description"`
1010
}
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