/
user.go
149 lines (128 loc) · 3.64 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
package prago
import (
"context"
"crypto/md5"
"errors"
"fmt"
"io"
"regexp"
"strings"
"time"
"golang.org/x/crypto/bcrypt"
)
var usernameRegex = regexp.MustCompile("^[a-z0-9.]{1,20}$")
// User represents admin user account
// TODO: better handle isactive user
type user struct {
ID int64 `prago-order-desc:"true"`
Username string `prago-preview:"true"`
Name string `prago-preview:"true"`
Email string `prago-unique:"true" prago-preview:"true"`
Role string `prago-preview:"true" prago-type:"role"`
Password string `prago-can-view:"nobody"`
Locale string `prago-can-view:"sysadmin"`
//IsActive bool `prago-preview:"true"`
LoggedInIP string `prago-can-view:"sysadmin" prago-preview:"true"`
LoggedInUseragent string `prago-can-view:"sysadmin" prago-preview:"true"`
LoggedInTime time.Time `prago-can-view:"sysadmin"`
EmailConfirmedAt time.Time `prago-can-view:"sysadmin"`
EmailRenewedAt time.Time `prago-can-view:"sysadmin"`
CreatedAt time.Time
UpdatedAt time.Time `prago-can-view:"sysadmin" prago-preview:"true"`
}
func fixEmail(in string) string {
return strings.ToLower(in)
}
func (user *user) LongName() string {
ret := user.Name
if ret == "" {
ret = user.Email
}
return ret
}
func (user *user) GetName(string) string {
var ret string
if user.Username != "" {
ret = user.Username + " "
}
ret += fmt.Sprintf("%s %s", user.Name, user.Email)
return ret
}
func (user *user) isPassword(password string) bool {
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
if err != nil {
return false
} else {
return true
}
}
// TODO: better comparison
func (user *user) emailConfirmed() bool {
if user.EmailConfirmedAt.Before(time.Now().AddDate(-1000, 0, 0)) {
return false
} else {
return true
}
}
func (user *user) newPassword(password string) error {
if len(password) < 7 {
return errors.New("short password")
}
passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), 12)
if err != nil {
return err
}
user.Password = string(passwordHash)
return nil
}
func (user user) emailToken(ctx context.Context, app *App) string {
randomness := app.mustGetSetting("random")
h := md5.New()
io.WriteString(h, fmt.Sprintf("%s%s", user.Email, randomness))
return fmt.Sprintf("%x", h.Sum(nil))
}
func (app *App) initUserResource() {
resource := NewResource[user](app)
app.UsersResource = resource
resource.Name(
messages.GetNameFunction("admin_user"),
messages.GetNameFunction("admin_users"),
)
resource.PermissionUpdate(sysadminPermission)
resource.PermissionCreate(nobodyPermission)
resource.PermissionDelete(sysadminPermission)
resource.PermissionExport(sysadminPermission)
resource.Icon("glyphicons-basic-4-user.svg")
resource.Validation(func(vc ValidationContext) {
username := vc.GetValue("username")
if username == "" {
return
}
if !usernameRegex.MatchString(username) {
vc.AddItemError("username", "Špatný formát uživatelského jména")
}
var isUsed bool
sameUsernameUsers := Query[user](app).Is("username", username).List()
for _, sameUser := range sameUsernameUsers {
if vc.GetValue("id") != fmt.Sprintf("%d", sameUser.ID) {
isUsed = true
}
}
if isUsed {
vc.AddItemError("username", fmt.Sprintf("Uživatelské jméno %s je již použito", username))
}
})
initUserRegistration(app)
initUserLogin(app)
initUserSettings(app)
initUserRenew(app)
}
func (app *App) GetCachedUserEmail(_ context.Context, id int64) string {
return <-Cached(app, fmt.Sprintf("cached-user-email-%d", id), func() string {
user := Query[user](app).ID(id)
if user == nil {
return ""
}
return user.Email
})
}