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

vocdoni / saas-backend / 16522415145

25 Jul 2025 12:49PM UTC coverage: 57.876% (+0.06%) from 57.815%
16522415145

Pull #198

github

emmdim
db: Fixes bug in calculating duplicate members during data validation
Pull Request #198: all: removes censusType from CreateCensus requests. Updates setCensus…

34 of 41 new or added lines in 4 files covered. (82.93%)

4 existing lines in 1 file now uncovered.

5236 of 9047 relevant lines covered (57.88%)

26.85 hits per line

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

95.65
/db/types.go
1
package db
2

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

5
import (
6
        "time"
7

8
        "github.com/ethereum/go-ethereum/common"
9
        "github.com/vocdoni/saas-backend/internal"
10
        "go.mongodb.org/mongo-driver/bson/primitive"
11
)
12

13
type User struct {
14
        ID            uint64             `json:"id" bson:"_id"`
15
        Email         string             `json:"email" bson:"email"`
16
        Password      string             `json:"password" bson:"password"`
17
        FirstName     string             `json:"firstName" bson:"firstName"`
18
        LastName      string             `json:"lastName" bson:"lastName"`
19
        Organizations []OrganizationUser `json:"organizations" bson:"organizations"`
20
        Verified      bool               `json:"verified" bson:"verified"`
21
}
22

23
type CodeType string
24

25
type UserVerification struct {
26
        ID         uint64    `json:"id" bson:"_id"`
27
        Code       string    `json:"code" bson:"code"`
28
        Type       CodeType  `json:"type" bson:"type"`
29
        Expiration time.Time `json:"expiration" bson:"expiration"`
30
}
31

32
// TODO this is the default role function while it should be
33
// used only when it is not necessary to consult the DB
34
func (u *User) HasRoleFor(address common.Address, role UserRole) bool {
209✔
35
        for _, org := range u.Organizations {
517✔
36
                if org.Address == address &&
308✔
37
                        // Check if the role matches the organization role
308✔
38
                        string(org.Role) == string(role) {
448✔
39
                        return true
140✔
40
                }
140✔
41
        }
42
        return false
69✔
43
}
44

45
type UserRole string
46

47
type OrganizationType string
48

49
type OrganizationUser struct {
50
        Address common.Address `json:"address" bson:"_id"` // common.Address is serialized as bytes in the db
51
        Role    UserRole       `json:"role" bson:"role"`
52
}
53

54
type Organization struct {
55
        Address         common.Address           `json:"address" bson:"_id"` // common.Address is serialized as bytes in the db
56
        Website         string                   `json:"website" bson:"website"`
57
        Type            OrganizationType         `json:"type" bson:"type"`
58
        Creator         string                   `json:"creator" bson:"creator"`
59
        CreatedAt       time.Time                `json:"createdAt" bson:"createdAt"`
60
        Nonce           string                   `json:"nonce" bson:"nonce"`
61
        Size            string                   `json:"size" bson:"size"`
62
        Color           string                   `json:"color" bson:"color"`
63
        Subdomain       string                   `json:"subdomain" bson:"subdomain"`
64
        Country         string                   `json:"country" bson:"country"`
65
        Timezone        string                   `json:"timezone" bson:"timezone"`
66
        Active          bool                     `json:"active" bson:"active"`
67
        Communications  bool                     `json:"communications" bson:"communications"`
68
        TokensPurchased uint64                   `json:"tokensPurchased" bson:"tokensPurchased"`
69
        TokensRemaining uint64                   `json:"tokensRemaining" bson:"tokensRemaining"`
70
        Parent          common.Address           `json:"parent" bson:"parent"`
71
        Meta            map[string]any           `json:"meta" bson:"meta"`
72
        Subscription    OrganizationSubscription `json:"subscription" bson:"subscription"`
73
        Counters        OrganizationCounters     `json:"counters" bson:"counters"`
74
}
75

76
type PlanLimits struct {
77
        Users        int `json:"users" bson:"users"`
78
        SubOrgs      int `json:"subOrgs" bson:"subOrgs"`
79
        MaxProcesses int `json:"maxProcesses" bson:"maxProcesses"`
80
        MaxCensus    int `json:"maxCensus" bson:"maxCensus"`
81
        // Max process duration in days
82
        MaxDuration int  `json:"maxDuration" bson:"maxDuration"`
83
        CustomURL   bool `json:"customURL" bson:"customURL"`
84
        Drafts      int  `json:"drafts" bson:"drafts"`
85
}
86

87
type VotingTypes struct {
88
        Single     bool `json:"single" bson:"single"`
89
        Multiple   bool `json:"multiple" bson:"multiple"`
90
        Approval   bool `json:"approval" bson:"approval"`
91
        Cumulative bool `json:"cumulative" bson:"cumulative"`
92
        Ranked     bool `json:"ranked" bson:"ranked"`
93
        Weighted   bool `json:"weighted" bson:"weighted"`
94
}
95

96
type Features struct {
97
        Anonymous       bool `json:"anonymous" bson:"anonymous"`
98
        Overwrite       bool `json:"overwrite" bson:"overwrite"`
99
        LiveResults     bool `json:"liveResults" bson:"liveResults"`
100
        Personalization bool `json:"personalization" bson:"personalization"`
101
        EmailReminder   bool `json:"emailReminder" bson:"emailReminder"`
102
        SmsNotification bool `json:"smsNotification" bson:"smsNotification"`
103
        WhiteLabel      bool `json:"whiteLabel" bson:"whiteLabel"`
104
        LiveStreaming   bool `json:"liveStreaming" bson:"liveStreaming"`
105
        PhoneSupport    bool `json:"phoneSupport" bson:"phoneSupport"`
106
}
107

108
type Plan struct {
109
        ID              uint64      `json:"id" bson:"_id"`
110
        Name            string      `json:"name" bson:"name"`
111
        StripeID        string      `json:"stripeID" bson:"stripeID"`
112
        StripePriceID   string      `json:"stripePriceID" bson:"stripePriceID"`
113
        StartingPrice   int64       `json:"startingPrice" bson:"startingPrice"`
114
        Default         bool        `json:"default" bson:"default"`
115
        Organization    PlanLimits  `json:"organization" bson:"organization"`
116
        VotingTypes     VotingTypes `json:"votingTypes" bson:"votingTypes"`
117
        Features        Features    `json:"features" bson:"features"`
118
        CensusSizeTiers []PlanTier  `json:"censusSizeTiers" bson:"censusSizeTiers"`
119
}
120

121
type PlanTier struct {
122
        Amount int64 `json:"amount" bson:"amount"`
123
        UpTo   int64 `json:"upTo" bson:"upTo"`
124
}
125

126
type OrganizationSubscription struct {
127
        PlanID          uint64    `json:"planID" bson:"planID"`
128
        StartDate       time.Time `json:"startDate" bson:"startDate"`
129
        RenewalDate     time.Time `json:"renewalDate" bson:"renewalDate"`
130
        LastPaymentDate time.Time `json:"lastPaymentDate" bson:"lastPaymentDate"`
131
        Active          bool      `json:"active" bson:"active"`
132
        MaxCensusSize   int       `json:"maxCensusSize" bson:"maxCensusSize"`
133
        Email           string    `json:"email" bson:"email"`
134
}
135

136
type OrganizationCounters struct {
137
        SentSMS    int `json:"sentSMS" bson:"sentSMS"`
138
        SentEmails int `json:"sentEmails" bson:"sentEmails"`
139
        SubOrgs    int `json:"subOrgs" bson:"subOrgs"`
140
        Users      int `json:"users" bson:"users"`
141
        Processes  int `json:"processes" bson:"processes"`
142
}
143

144
type OrganizationInvite struct {
145
        ID                  primitive.ObjectID `json:"id" bson:"_id,omitempty"`
146
        InvitationCode      string             `json:"invitationCode" bson:"invitationCode"`
147
        OrganizationAddress common.Address     `json:"organizationAddress" bson:"organizationAddress"`
148
        CurrentUserID       uint64             `json:"currentUserID" bson:"currentUserID"`
149
        NewUserEmail        string             `json:"newUserEmail" bson:"newUserEmail"`
150
        Role                UserRole           `json:"role" bson:"role"`
151
        Expiration          time.Time          `json:"expiration" bson:"expiration"`
152
}
153

154
// Object represents a user uploaded object Includes user defined ID and the data
155
// as a byte array.
156
type Object struct {
157
        ID          string    `json:"id" bson:"_id"`
158
        Name        string    `json:"name" bson:"name"`
159
        Data        []byte    `json:"data" bson:"data" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
160
        CreatedAt   time.Time `json:"createdAt" bson:"createdAt"`
161
        UserID      string    `json:"userId" bson:"userId"`
162
        ContentType string    `json:"contentType" bson:"contentType"`
163
}
164

165
// CensusType defines the type of census.
166
type CensusType string
167

168
const (
169
        // CensusTypeMail is used when the organizer uploads a list of names, memberIDs and e‑mails.
170
        CensusTypeAuthOnly  CensusType = "auth"
171
        CensusTypeMail      CensusType = "mail"
172
        CensusTypeSMS       CensusType = "sms"
173
        CensusTypeSMSorMail CensusType = "sms_or_mail"
174
)
175

176
// Census represents the information of a set of census participants
177
type Census struct {
178
        ID          primitive.ObjectID   `json:"id" bson:"_id,omitempty"`
179
        OrgAddress  common.Address       `json:"orgAddress" bson:"orgAddress"`
180
        Type        CensusType           `json:"type" bson:"type"`
181
        GroupID     primitive.ObjectID   `json:"groupId" bson:"groupId"`
182
        Published   PublishedCensus      `json:"published" bson:"published"`
183
        AuthFields  OrgMemberAuthFields  `json:"orgMemberAuthFields" bson:"orgMemberAuthFields"`
184
        TwoFaFields OrgMemberTwoFaFields `json:"orgMemberTwoFaFields" bson:"orgMemberTwoFaFields"`
185

186
        CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
187
        UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
188
}
189

190
// An org member belongs to an organization and her details that will be
191
// used for verification and/or authentication
192
// A member is tied to an organization by the orgAddress
193
//
194
//nolint:lll
195
type OrgMember struct {
196
        // Also referred to as member UID
197
        ID primitive.ObjectID `json:"id" bson:"_id,omitempty"`
198
        // OrgAddress can be used for future sharding
199
        OrgAddress     common.Address `json:"orgAddress" bson:"orgAddress"`
200
        Email          string         `json:"email" bson:"email"`
201
        Phone          string         `json:"phone" bson:"phone"`
202
        HashedPhone    []byte         `json:"hashedPhone" bson:"hashedPhone" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
203
        MemberNumber   string         `json:"memberNumber" bson:"memberNumber"`
204
        NationalID     string         `json:"nationalID" bson:"nationalID"`
205
        Name           string         `json:"name" bson:"name"`
206
        Surname        string         `json:"surname" bson:"surname"`
207
        BirthDate      string         `json:"birthDate" bson:"birthDate"`
208
        ParsedBirtDate time.Time      `json:"parsedBirthDate" bson:"parsedBirthDate"`
209
        Password       string         `json:"password" bson:"password"`
210
        HashedPass     []byte         `json:"pass" bson:"pass" swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
211
        Other          map[string]any `json:"other" bson:"other"`
212
        CreatedAt      time.Time      `json:"createdAt" bson:"createdAt"`
213
        UpdatedAt      time.Time      `json:"updatedAt" bson:"updatedAt"`
214
}
215

216
// OrgMemberAuthFields defines the fields that can be used for member authentication.
217
type OrgMemberAuthField string
218

219
const (
220
        OrgMemberAuthFieldsName         OrgMemberAuthField = "name"
221
        OrgMemberAuthFieldsSurname      OrgMemberAuthField = "surname"
222
        OrgMemberAuthFieldsMemberNumber OrgMemberAuthField = "memberNumber"
223
        OrgMemberAuthFieldsNationalID   OrgMemberAuthField = "nationalID"
224
        OrgMemberAuthFieldsBirthDate    OrgMemberAuthField = "birthDate"
225
)
226

227
// OrgMemberAuthFields is a list of fields that can be used for member authentication.
228
type OrgMemberAuthFields []OrgMemberAuthField
229

230
// OrgMemberTwoFaField defines the fields that can be used for two-factor authentication.
231
type OrgMemberTwoFaField string
232

233
const (
234
        OrgMemberTwoFaFieldEmail OrgMemberTwoFaField = "email"
235
        OrgMemberTwoFaFieldPhone OrgMemberTwoFaField = "phone"
236
)
237

238
// OrgMemberTwoFaFields is a list of fields that can be used for two-factor authentication.
239
type OrgMemberTwoFaFields []OrgMemberTwoFaField
240

241
// Contains checks if the field is present in the OrgMemberAuthFields.
242
func (f OrgMemberTwoFaFields) Contains(field OrgMemberTwoFaField) bool {
96✔
243
        for _, v := range f {
150✔
244
                if v == field {
75✔
245
                        return true
21✔
246
                }
21✔
247
        }
248
        return false
75✔
249
}
250

251
func (f OrgMemberTwoFaFields) GetCensusType() CensusType {
32✔
252
        if f.Contains(OrgMemberTwoFaFieldPhone) && f.Contains(OrgMemberTwoFaFieldEmail) {
32✔
NEW
253
                return CensusTypeSMSorMail
×
254
        } else if f.Contains(OrgMemberTwoFaFieldPhone) {
35✔
255
                return CensusTypeSMS
3✔
256
        } else if f.Contains(OrgMemberTwoFaFieldEmail) {
47✔
257
                return CensusTypeMail
15✔
258
        }
15✔
259
        return CensusTypeAuthOnly
14✔
260
}
261

262
type OrgMemberAggregationResults struct {
263
        // MemberIDs is a list of member IDs that are result of the aggregation
264
        Members []primitive.ObjectID `json:"memberIds" bson:"memberIds"`
265
        // Duplicates is a list of member IDs that were found to be duplicates
266
        Duplicates []primitive.ObjectID `json:"duplicates" bson:"duplicates"`
267
        // MissingData is a list of member IDs that had columns found to be empty
268
        MissingData []primitive.ObjectID `json:"missingData" bson:"missingData"`
269
}
270

271
// An Organization members' group is a precursor of a census, and is simply a
272
// collection of members that are grouped together for a specific purpose
273
type OrganizationMemberGroup struct {
274
        ID          primitive.ObjectID `json:"id" bson:"_id,omitempty"`
275
        OrgAddress  common.Address     `json:"orgAddress" bson:"orgAddress"`
276
        Title       string             `json:"title" bson:"title"`
277
        Description string             `json:"description" bson:"description"`
278
        MemberIDs   []string           `json:"memberIds" bson:"memberIds"`
279
        CreatedAt   time.Time          `json:"createdAt" bson:"createdAt"`
280
        UpdatedAt   time.Time          `json:"updatedAt" bson:"updatedAt"`
281
        CensusIDs   []string           `json:"censusIds" bson:"censusIds"`
282
}
283

284
// Relates an OrgMember to a Census
285
// The censusID is the hex format in string of the objectID
286
type CensusParticipant struct {
287
        ParticipantID string    `json:"participantID" bson:"participantID"`
288
        CensusID      string    `json:"censusId" bson:"censusId"`
289
        CreatedAt     time.Time `json:"createdAt" bson:"createdAt"`
290
        UpdatedAt     time.Time `json:"updatedAt" bson:"updatedAt"`
291
}
292

293
// Represents a published census as a census is represented in the vochain
294
// The publishedCensus is tied to a Census
295
type PublishedCensus struct {
296
        URI       string            `json:"uri" bson:"uri"`
297
        Root      internal.HexBytes `json:"root" bson:"root"`
298
        CreatedAt time.Time         `json:"createdAt" bson:"createdAt"`
299
}
300

301
// Process represents a voting process in the vochain
302
// A process is tied to an organization by the orgAddress
303
// and to a publishedCensus
304
//
305
//nolint:lll
306
type Process struct {
307
        ID         internal.HexBytes `json:"id" bson:"_id"  swaggertype:"string" format:"hex" example:"deadbeef"`
308
        OrgAddress common.Address    `json:"orgAdress" bson:"orgAddress"`
309
        Census     Census            `json:"census" bson:"census"`
310
        Metadata   []byte            `json:"metadata,omitempty"  bson:"metadata"  swaggertype:"string" format:"base64" example:"aGVsbG8gd29ybGQ="`
311
}
312

313
// ProcessesBundle represents a group of voting processes that share a common census.
314
// This allows users to participate in multiple voting processes using the same authentication mechanism.
315
//
316
//nolint:lll
317
type ProcessesBundle struct {
318
        ID         primitive.ObjectID  `json:"id" bson:"_id,omitempty"`                                                               // Unique identifier for the bundle
319
        Census     Census              `json:"census" bson:"census"`                                                                  // The census associated with this bundle
320
        OrgAddress common.Address      `json:"orgAddress" bson:"orgAddress"`                                                          // The organization that owns this bundle
321
        Processes  []internal.HexBytes `json:"processes" bson:"processes" swaggertype:"array,string" format:"hex" example:"deadbeef"` // Array of process IDs included in this bundle
322
}
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