-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuser.go
148 lines (124 loc) · 4.74 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
package gorth
import (
"crypto/md5"
"database/sql"
"encoding/hex"
"fmt"
"net/url"
"regexp"
"strings"
"time"
"github.com/ae0000/gorandom"
)
// Statuses for managing what users can and can't do``
const (
StatusActive = "active"
StatusDeleted = "deleted"
StatusPendingConfirmation = "pendingconfirmation"
StatusLocked = "locked"
)
// User roles
const (
RoleSuper = "super"
RoleAdmin = "admin"
RoleNormal = "normal"
)
// MinPasswordLength for how many chars are needed in a valid password
// NOTE: leaving as a var in case people want to edit it
var MinPasswordLength = 8
// Email validation regex
var emailPattern = regexp.MustCompile(`^(((([a-zA-Z]|\d|[!#\$%&'\*\+\-\/=\?\^_` + "`" + `{\|}~]|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])+(\.([a-zA-Z]|\d|[!#\$%&'\*\+\-\/=\?\^_` + "`" + `{\|}~]|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])|(\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-zA-Z]|\d|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])|(([a-zA-Z]|\d|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])([a-zA-Z]|\d|-|\.|_|~|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])*([a-zA-Z]|\d|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])))\.)+(([a-zA-Z]|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])|(([a-zA-Z]|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])([a-zA-Z]|\d|-|\.|_|~|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])*([a-zA-Z]|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])))\.?$`)
// User is used to hold and store the authentication details
type User struct {
ID int64
FirstName string
LastName string
Email string
Password string
Photo string
Status string
Role string
Token string
TokenTimestamp time.Time
LastLogin time.Time
Created time.Time
}
// DefaultStatus sets the default status for a user (if not already set)
func (u *User) DefaultStatus() {
if len(u.Status) == 0 {
u.Status = StatusPendingConfirmation
}
}
// DefaultPhoto sets the users photo to a gravagtar based on their email (if not
// already set)
func (u *User) DefaultPhoto() {
if len(u.Photo) == 0 {
u.Photo = gravatar(u.Email)
}
}
// DefaultRole assigns a role if there is none given
func (u *User) DefaultRole() {
if len(u.Role) == 0 {
u.Role = RoleNormal
}
}
// TokenConfirm sets up a token so that the user can confirm their email address
func (u *User) TokenConfirm() {
// Create a token and send it to the user
u.Token = gorandom.AlphaNumeric(30)
u.TokenTimestamp = time.Now()
}
// Filter will remove any whitespace etc.
func (u *User) Filter() {
u.FirstName = strings.TrimSpace(u.FirstName)
u.LastName = strings.TrimSpace(u.LastName)
u.Email = strings.TrimSpace(u.Email)
}
// Validate that the user contains valid info
func (u *User) Validate() error {
// Validate email
if !emailPattern.MatchString(u.Email) {
return fmt.Errorf("email '%s' is not valid", u.Email)
}
// Validate password length
if len(u.Password) < MinPasswordLength {
return fmt.Errorf("password must be at least %d characters in length", MinPasswordLength)
}
return nil
}
// gravatar returns a gravatar for the given email address with a size of 100,
// rating of "general" and a default image using "identicons"
func gravatar(email string) string {
hasher := md5.New()
hasher.Write([]byte(email))
URL, _ := url.Parse("https://www.gravatar.com/")
URL.Path = fmt.Sprintf("avatar/%v.jpg", hex.EncodeToString(hasher.Sum(nil)))
params := url.Values{}
params.Add("s", fmt.Sprintf("%v", 100))
params.Add("r", fmt.Sprintf("%v", "g"))
params.Add("d", fmt.Sprintf("%v", "identicon"))
URL.RawQuery = params.Encode()
return URL.String()
}
// emailUnique returns true if the email does not exist already in the db
func emailUnique(email string) bool {
var id int
err := db.QueryRow("SELECT ID FROM Users WHERE Email = ? LIMIT 1", email).Scan(&id)
return id == 0 && err == sql.ErrNoRows
}
// GetUserByEmail returns the user specified by the email
func GetUserByEmail(email string) (*User, error) {
u := User{}
selectSQL := `
SELECT ID, FirstName, LastName, Email, Password, Photo, Status, Role, Token,
TokenTimestamp, LastLogin, Created
FROM Users
WHERE Email = ? AND Status != "deleted"`
err := db.QueryRow(selectSQL, email).Scan(&u.ID, &u.FirstName, &u.LastName,
&u.Email, &u.Password, &u.Photo, &u.Status, &u.Role, &u.Token,
&u.TokenTimestamp, &u.LastLogin, &u.Created)
if err != nil {
return nil, err
}
return &u, nil
}