-
Notifications
You must be signed in to change notification settings - Fork 71
/
user.go
241 lines (186 loc) · 8.27 KB
/
user.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
package diygoapi
import (
"context"
"time"
"golang.org/x/text/language"
"github.com/gilcrest/diygoapi/errs"
"github.com/gilcrest/diygoapi/secure"
"github.com/gilcrest/diygoapi/uuid"
)
// RegisterUserServicer registers a new user
type RegisterUserServicer interface {
SelfRegister(ctx context.Context, adt Audit) error
}
// Person - from Wikipedia: "A person (plural people or persons) is a being that
// has certain capacities or attributes such as reason, morality, consciousness or
// self-consciousness, and being a part of a culturally established form of social
// relations such as kinship, ownership of property, or legal responsibility.
//
// The defining features of personhood and, consequently, what makes a person count
// as a person, differ widely among cultures and contexts."
//
// A Person can have multiple Users.
type Person struct {
// ID: The unique identifier of the Person.
ID uuid.UUID
// ExternalID: unique external identifier of the Person
ExternalID secure.Identifier
// Users: All the users that are linked to the Person
// (e.g. a GitHub user, a Google user, etc.).
Users []*User
}
// Validate determines whether the Person has proper data to be considered valid
func (p Person) Validate() (err error) {
const op errs.Op = "diygoapi/Person.Validate"
switch {
case p.ID == uuid.Nil:
return errs.E(op, errs.Validation, "Person ID cannot be nil")
case p.ExternalID.String() == "":
return errs.E(op, errs.Validation, "Person ExternalID cannot be empty")
}
return nil
}
// UserResponse - from Wikipedia: "A user is a person who utilizes a computer or network service." In the context of this
// project, given that we allow Persons to authenticate with multiple providers, a User is akin to a persona
// (Wikipedia - "The word persona derives from Latin, where it originally referred to a theatrical mask. On the
// social web, users develop virtual personas as online identities.") and as such, a Person can have one or many
// Users (for instance, I can have a GitHub user and a Google user, but I am just one Person).
//
// As a general, practical matter, most operations are considered at the User level. For instance, roles are
// assigned at the user level instead of the Person level, which allows for more fine-grained access control.
type UserResponse struct {
// ID: The unique identifier for the Person's profile
ID uuid.UUID
// ExternalID: unique external identifier of the User
ExternalID secure.Identifier `json:"external_id"`
// NamePrefix: The name prefix for the Profile (e.g. Mx., Ms., Mr., etc.)
NamePrefix string `json:"name_prefix"`
// FirstName: The person's first name.
FirstName string `json:"first_name"`
// MiddleName: The person's middle name.
MiddleName string `json:"middle_name"`
// LastName: The person's last name.
LastName string `json:"last_name"`
// FullName: The person's full name.
FullName string `json:"full_name"`
// NameSuffix: The name suffix for the person's name (e.g. "PhD", "CCNA", "OBE").
// Other examples include generational designations like "Sr." and "Jr." and "I", "II", "III", etc.
NameSuffix string `json:"name_suffix"`
// Nickname: The person's nickname
Nickname string `json:"nickname"`
// Email: The primary email for the User
Email string `json:"email"`
// CompanyName: The Company Name that the person works at
CompanyName string `json:"company_name"`
// CompanyDepartment: is the department at the company that the person works at
CompanyDepartment string `json:"company_department"`
// JobTitle: The person's Job Title
JobTitle string `json:"job_title"`
// BirthDate: The full birthdate of a person (e.g. Dec 18, 1953)
BirthDate time.Time `json:"birth_date"`
// LanguagePreferences is the user's language tag preferences.
LanguagePreferences []language.Tag `json:"language_preferences"`
// HostedDomain: The hosted domain e.g. example.com.
HostedDomain string `json:"hosted_domain"`
// PictureURL: URL of the person's picture image for the profile.
PictureURL string `json:"picture_url"`
// ProfileLink: URL of the profile page.
ProfileLink string `json:"profile_link"`
// Source: The origin of the User (e.g. Google Oauth2, Apple Oauth2, etc.)
Source string `json:"source"`
}
// User - from Wikipedia: "A user is a person who utilizes a computer or network service." In the context of this
// project, given that we allow Persons to authenticate with multiple providers, a User is akin to a persona
// (Wikipedia - "The word persona derives from Latin, where it originally referred to a theatrical mask. On the
// social web, users develop virtual personas as online identities.") and as such, a Person can have one or many
// Users (for instance, I can have a GitHub user and a Google user, but I am just one Person).
//
// As a general, practical matter, most operations are considered at the User level. For instance, roles are
// assigned at the user level instead of the Person level, which allows for more fine-grained access control.
type User struct {
// ID: The unique identifier for the Person's profile
ID uuid.UUID
// ExternalID: unique external identifier of the User
ExternalID secure.Identifier
// NamePrefix: The name prefix for the Profile (e.g. Mx., Ms., Mr., etc.)
NamePrefix string
// FirstName: The person's first name.
FirstName string
// MiddleName: The person's middle name.
MiddleName string
// LastName: The person's last name.
LastName string
// FullName: The person's full name.
FullName string
// NameSuffix: The name suffix for the person's name (e.g. "PhD", "CCNA", "OBE").
// Other examples include generational designations like "Sr." and "Jr." and "I", "II", "III", etc.
NameSuffix string
// Nickname: The person's nickname
Nickname string
// Gender: The user's gender. TODO - setup Gender properly. not binary.
Gender string
// Email: The primary email for the User
Email string
// CompanyName: The Company Name that the person works at
CompanyName string
// CompanyDepartment: is the department at the company that the person works at
CompanyDepartment string
// JobTitle: The person's Job Title
JobTitle string
// BirthDate: The full birthdate of a person (e.g. Dec 18, 1953)
BirthDate time.Time
// LanguagePreferences is the user's language tag preferences.
LanguagePreferences []language.Tag
// HostedDomain: The hosted domain e.g. example.com.
HostedDomain string
// PictureURL: URL of the person's picture image for the profile.
PictureURL string
// ProfileLink: URL of the profile page.
ProfileLink string
// Source: The origin of the User (e.g. Google Oauth2, Apple Oauth2, etc.)
Source string
}
// Validate determines whether the Person has proper data to be considered valid
func (u User) Validate() error {
const op errs.Op = "diygoapi/User.Validate"
switch {
case u.ID == uuid.Nil:
return errs.E(op, errs.Validation, "User ID cannot be nil")
case u.ExternalID.String() == "":
return errs.E(op, errs.Validation, "User ExternalID cannot be empty")
case u.LastName == "":
return errs.E(op, errs.Validation, "User LastName cannot be empty")
case u.FirstName == "":
return errs.E(op, errs.Validation, "User FirstName cannot be empty")
}
return nil
}
// NewUserFromProviderInfo creates a new User struct to be used in db user creation
func NewUserFromProviderInfo(pi *ProviderInfo, lm language.Matcher) *User {
var langPrefs []language.Tag
// Match the user's locale to the supported languages
langPref, _, _ := lm.Match(language.Make(pi.UserInfo.Locale))
// Append the matched language to the language preferences
langPrefs = append(langPrefs, langPref)
// create User from ProviderInfo
u := &User{
ID: uuid.New(),
ExternalID: secure.NewID(),
NamePrefix: pi.UserInfo.NamePrefix,
FirstName: pi.UserInfo.FirstName,
MiddleName: pi.UserInfo.MiddleName,
LastName: pi.UserInfo.LastName,
FullName: pi.UserInfo.FullName,
NameSuffix: pi.UserInfo.NameSuffix,
Nickname: pi.UserInfo.Nickname,
Gender: pi.UserInfo.Gender,
Email: pi.UserInfo.Email,
BirthDate: pi.UserInfo.BirthDate,
LanguagePreferences: langPrefs,
HostedDomain: pi.UserInfo.HostedDomain,
PictureURL: pi.UserInfo.Picture,
ProfileLink: pi.UserInfo.ProfileLink,
Source: pi.Provider.String(),
}
return u
}