generated from broadinstitute/golang-project-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
user.go
127 lines (117 loc) · 3.88 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
package v2models
import (
"fmt"
"github.com/broadinstitute/sherlock/internal/auth/auth_models"
"github.com/broadinstitute/sherlock/internal/errors"
"github.com/broadinstitute/sherlock/internal/models/model_actions"
"github.com/broadinstitute/sherlock/internal/utils"
"gorm.io/gorm"
"strconv"
"strings"
)
type User struct {
gorm.Model
auth_models.StoredControlledUserFields
auth_models.StoredMutableUserFields
}
func (u User) TableName() string {
return "v2_users"
}
func (u User) getID() uint {
return u.ID
}
var userStore *internalModelStore[User]
func init() {
userStore = &internalModelStore[User]{
selectorToQueryModel: userSelectorToQuery,
modelToSelectors: userToSelectors,
errorIfForbidden: userErrorIfForbidden,
validateModel: validateUser,
editsMayChangeSelectors: true,
}
}
func userSelectorToQuery(_ *gorm.DB, selector string) (User, error) {
if len(selector) == 0 {
return User{}, fmt.Errorf("(%s) user selector cannot be empty", errors.BadRequest)
}
var query User
if utils.IsNumeric(selector) { // ID
id, err := strconv.Atoi(selector)
if err != nil {
return User{}, fmt.Errorf("(%s) string to int conversion error of '%s': %v", errors.BadRequest, selector, err)
}
query.ID = uint(id)
return query, nil
} else if strings.Contains(selector, "@") { // email
query.Email = selector
return query, nil
} else if strings.HasPrefix(selector, "google-id/") { // "google-id/" + Google Subject ID
query.GoogleID = strings.TrimPrefix(selector, "google-id/")
return query, nil
} else if strings.HasPrefix(selector, "github/") { // "github/" + GitHub Username
githubUsername := strings.TrimPrefix(selector, "github/")
query.GithubUsername = &githubUsername
return query, nil
} else if strings.HasPrefix(selector, "github-id/") { // "github-id/" + GitHub ID
githubID := strings.TrimPrefix(selector, "github-id/")
query.GithubID = &githubID
return query, nil
}
return User{}, fmt.Errorf("(%s) invalid user selector '%s'", errors.BadRequest, selector)
}
func userToSelectors(user *User) []string {
var selectors []string
if user != nil {
if user.ID != 0 {
selectors = append(selectors, fmt.Sprintf("%d", user.ID))
}
if user.Email != "" {
selectors = append(selectors, user.Email)
}
if user.GoogleID != "" {
selectors = append(selectors, fmt.Sprintf("google-id/%s", user.GoogleID))
}
if user.GithubUsername != nil {
selectors = append(selectors, fmt.Sprintf("github/%s", *user.GithubUsername))
}
if user.GithubID != nil {
selectors = append(selectors, fmt.Sprintf("github-id/%s", *user.GithubID))
}
}
return selectors
}
func userErrorIfForbidden(_ *gorm.DB, modelUser *User, action model_actions.ActionType, user *auth_models.User) error {
switch action {
case model_actions.CREATE:
if user != nil {
// The handler/controller always pass the user, so it being nil means we're still at the auth middleware.
return fmt.Errorf("users can only be created via middleware")
}
case model_actions.EDIT:
if modelUser.Email != user.Email {
return fmt.Errorf("users can only edit themselves")
} else if !user.IsFromAuthMethod(auth_models.AuthMethodIAP) {
return fmt.Errorf("users cannot be edited from non-IAP auth methods")
}
case model_actions.DELETE:
return fmt.Errorf("users cannot be deleted")
}
return nil
}
func validateUser(user *User) error {
if user == nil {
return fmt.Errorf("the model passed was nil")
}
if user.Email == "" {
return fmt.Errorf("a %T must have an email", user)
} else if !strings.Contains(user.Email, "@") {
return fmt.Errorf("a %T must have an email: '%s' did not contain an '@'", user, user.Email)
}
if user.GoogleID == "" {
return fmt.Errorf("a %T must have a Google subject ID", user)
}
if (user.GithubUsername == nil) != (user.GithubID == nil) {
return fmt.Errorf("a %T must either have both a GitHub username and ID set or neither", user)
}
return nil
}