diff options
author | jloup <jeanloup.jamet@gmail.com> | 2018-05-11 13:57:29 +0200 |
---|---|---|
committer | jloup <jeanloup.jamet@gmail.com> | 2018-05-11 13:57:29 +0200 |
commit | 2da5b12c31074591eaf16929b760322b98f189e8 (patch) | |
tree | 407b699688edddca381ca80e5ecea9458d748cc1 | |
parent | 299b6b6d9fb879c06e675ef240f361348629ff6c (diff) | |
download | Front-2da5b12c31074591eaf16929b760322b98f189e8.tar.gz Front-2da5b12c31074591eaf16929b760322b98f189e8.tar.zst Front-2da5b12c31074591eaf16929b760322b98f189e8.zip |
Mails.
-rw-r--r-- | Gopkg.lock | 100 | ||||
-rw-r--r-- | Gopkg.toml | 4 | ||||
-rw-r--r-- | api/api.go | 19 | ||||
-rw-r--r-- | api/mail.go | 103 | ||||
-rw-r--r-- | api/password_reset.go | 7 | ||||
-rw-r--r-- | api/routes.go | 9 | ||||
-rw-r--r-- | api/user.go | 71 | ||||
-rw-r--r-- | cmd/app/main.go | 4 | ||||
-rw-r--r-- | cmd/web/js/api.js | 10 | ||||
-rw-r--r-- | cmd/web/js/main.jsx | 25 | ||||
-rw-r--r-- | db/user.go | 6 |
11 files changed, 353 insertions, 5 deletions
@@ -8,12 +8,30 @@ | |||
8 | version = "v0.3.0" | 8 | version = "v0.3.0" |
9 | 9 | ||
10 | [[projects]] | 10 | [[projects]] |
11 | name = "github.com/Masterminds/semver" | ||
12 | packages = ["."] | ||
13 | revision = "c7af12943936e8c39859482e61f0574c2fd7fc75" | ||
14 | version = "v1.4.2" | ||
15 | |||
16 | [[projects]] | ||
17 | name = "github.com/Masterminds/sprig" | ||
18 | packages = ["."] | ||
19 | revision = "6b2a58267f6a8b1dc8e2eb5519b984008fa85e8c" | ||
20 | version = "v2.15.0" | ||
21 | |||
22 | [[projects]] | ||
11 | name = "github.com/Sirupsen/logrus" | 23 | name = "github.com/Sirupsen/logrus" |
12 | packages = ["."] | 24 | packages = ["."] |
13 | revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc" | 25 | revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc" |
14 | version = "v1.0.5" | 26 | version = "v1.0.5" |
15 | 27 | ||
16 | [[projects]] | 28 | [[projects]] |
29 | name = "github.com/aokoli/goutils" | ||
30 | packages = ["."] | ||
31 | revision = "3391d3790d23d03408670993e957e8f408993c34" | ||
32 | version = "v1.0.1" | ||
33 | |||
34 | [[projects]] | ||
17 | name = "github.com/boombuler/barcode" | 35 | name = "github.com/boombuler/barcode" |
18 | packages = [ | 36 | packages = [ |
19 | ".", | 37 | ".", |
@@ -104,6 +122,30 @@ | |||
104 | version = "v1.1.0" | 122 | version = "v1.1.0" |
105 | 123 | ||
106 | [[projects]] | 124 | [[projects]] |
125 | name = "github.com/google/uuid" | ||
126 | packages = ["."] | ||
127 | revision = "064e2069ce9c359c118179501254f67d7d37ba24" | ||
128 | version = "0.2" | ||
129 | |||
130 | [[projects]] | ||
131 | name = "github.com/huandu/xstrings" | ||
132 | packages = ["."] | ||
133 | revision = "2bf18b218c51864a87384c06996e40ff9dcff8e1" | ||
134 | version = "v1.0.0" | ||
135 | |||
136 | [[projects]] | ||
137 | name = "github.com/imdario/mergo" | ||
138 | packages = ["."] | ||
139 | revision = "7fe0c75c13abdee74b09fcacef5ea1c6bba6a874" | ||
140 | version = "0.2.4" | ||
141 | |||
142 | [[projects]] | ||
143 | branch = "master" | ||
144 | name = "github.com/jaytaylor/html2text" | ||
145 | packages = ["."] | ||
146 | revision = "64a82a6d140778896f13303121a49d8cb8007034" | ||
147 | |||
148 | [[projects]] | ||
107 | branch = "master" | 149 | branch = "master" |
108 | name = "github.com/jinzhu/inflection" | 150 | name = "github.com/jinzhu/inflection" |
109 | packages = ["."] | 151 | packages = ["."] |
@@ -122,12 +164,30 @@ | |||
122 | revision = "3e7b2ea67e9637d153f53ef5ff148f23ee5274d4" | 164 | revision = "3e7b2ea67e9637d153f53ef5ff148f23ee5274d4" |
123 | 165 | ||
124 | [[projects]] | 166 | [[projects]] |
167 | name = "github.com/matcornic/hermes" | ||
168 | packages = ["."] | ||
169 | revision = "23ab47deb5a321481be0c4936b810c1420da2262" | ||
170 | version = "1.1.1" | ||
171 | |||
172 | [[projects]] | ||
125 | name = "github.com/mattn/go-isatty" | 173 | name = "github.com/mattn/go-isatty" |
126 | packages = ["."] | 174 | packages = ["."] |
127 | revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" | 175 | revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" |
128 | version = "v0.0.3" | 176 | version = "v0.0.3" |
129 | 177 | ||
130 | [[projects]] | 178 | [[projects]] |
179 | name = "github.com/mattn/go-runewidth" | ||
180 | packages = ["."] | ||
181 | revision = "9e777a8366cce605130a531d2cd6363d07ad7317" | ||
182 | version = "v0.0.2" | ||
183 | |||
184 | [[projects]] | ||
185 | branch = "master" | ||
186 | name = "github.com/olekukonko/tablewriter" | ||
187 | packages = ["."] | ||
188 | revision = "d4647c9c7a84d847478d890b816b7d8b62b0b279" | ||
189 | |||
190 | [[projects]] | ||
131 | name = "github.com/pquerna/otp" | 191 | name = "github.com/pquerna/otp" |
132 | packages = [ | 192 | packages = [ |
133 | ".", | 193 | ".", |
@@ -144,6 +204,18 @@ | |||
144 | revision = "2df3e6ddaf6e9531dd02d7b6337f2d310f5e4f22" | 204 | revision = "2df3e6ddaf6e9531dd02d7b6337f2d310f5e4f22" |
145 | 205 | ||
146 | [[projects]] | 206 | [[projects]] |
207 | branch = "master" | ||
208 | name = "github.com/shurcooL/sanitized_anchor_name" | ||
209 | packages = ["."] | ||
210 | revision = "86672fcb3f950f35f2e675df2240550f2a50762f" | ||
211 | |||
212 | [[projects]] | ||
213 | branch = "master" | ||
214 | name = "github.com/ssor/bom" | ||
215 | packages = ["."] | ||
216 | revision = "6386211fdfcf24c0bfbdaceafd02849ed9a8a509" | ||
217 | |||
218 | [[projects]] | ||
147 | name = "github.com/ugorji/go" | 219 | name = "github.com/ugorji/go" |
148 | packages = ["codec"] | 220 | packages = ["codec"] |
149 | revision = "b4c50a2b199d93b13dc15e78929cfb23bfdf21ab" | 221 | revision = "b4c50a2b199d93b13dc15e78929cfb23bfdf21ab" |
@@ -155,6 +227,8 @@ | |||
155 | packages = [ | 227 | packages = [ |
156 | "bcrypt", | 228 | "bcrypt", |
157 | "blowfish", | 229 | "blowfish", |
230 | "pbkdf2", | ||
231 | "scrypt", | ||
158 | "ssh/terminal" | 232 | "ssh/terminal" |
159 | ] | 233 | ] |
160 | revision = "8b1d31080a7692e075c4681cb2458454a1fe0706" | 234 | revision = "8b1d31080a7692e075c4681cb2458454a1fe0706" |
@@ -162,7 +236,11 @@ | |||
162 | [[projects]] | 236 | [[projects]] |
163 | branch = "master" | 237 | branch = "master" |
164 | name = "golang.org/x/net" | 238 | name = "golang.org/x/net" |
165 | packages = ["websocket"] | 239 | packages = [ |
240 | "html", | ||
241 | "html/atom", | ||
242 | "websocket" | ||
243 | ] | ||
166 | revision = "640f4622ab692b87c2f3a94265e6f579fe38263d" | 244 | revision = "640f4622ab692b87c2f3a94265e6f579fe38263d" |
167 | 245 | ||
168 | [[projects]] | 246 | [[projects]] |
@@ -175,12 +253,30 @@ | |||
175 | revision = "78d5f264b493f125018180c204871ecf58a2dce1" | 253 | revision = "78d5f264b493f125018180c204871ecf58a2dce1" |
176 | 254 | ||
177 | [[projects]] | 255 | [[projects]] |
256 | branch = "v3" | ||
257 | name = "gopkg.in/alexcesaro/quotedprintable.v3" | ||
258 | packages = ["."] | ||
259 | revision = "2caba252f4dc53eaf6b553000885530023f54623" | ||
260 | |||
261 | [[projects]] | ||
178 | name = "gopkg.in/go-playground/validator.v8" | 262 | name = "gopkg.in/go-playground/validator.v8" |
179 | packages = ["."] | 263 | packages = ["."] |
180 | revision = "5f1438d3fca68893a817e4a66806cea46a9e4ebf" | 264 | revision = "5f1438d3fca68893a817e4a66806cea46a9e4ebf" |
181 | version = "v8.18.2" | 265 | version = "v8.18.2" |
182 | 266 | ||
183 | [[projects]] | 267 | [[projects]] |
268 | name = "gopkg.in/gomail.v2" | ||
269 | packages = ["."] | ||
270 | revision = "41f3572897373c5538c50a2402db15db079fa4fd" | ||
271 | version = "2.0.0" | ||
272 | |||
273 | [[projects]] | ||
274 | name = "gopkg.in/russross/blackfriday.v2" | ||
275 | packages = ["."] | ||
276 | revision = "cadec560ec52d93835bf2f15bd794700d3a2473b" | ||
277 | version = "v2.0.0" | ||
278 | |||
279 | [[projects]] | ||
184 | name = "gopkg.in/yaml.v2" | 280 | name = "gopkg.in/yaml.v2" |
185 | packages = ["."] | 281 | packages = ["."] |
186 | revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" | 282 | revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" |
@@ -189,6 +285,6 @@ | |||
189 | [solve-meta] | 285 | [solve-meta] |
190 | analyzer-name = "dep" | 286 | analyzer-name = "dep" |
191 | analyzer-version = 1 | 287 | analyzer-version = 1 |
192 | inputs-digest = "5c987f56ef837352173d0a50f12d6c58ac72831b5e90d34ca0a283bee71fb1a2" | 288 | inputs-digest = "9df92ae3bbf81638f86228e1daacd75bd4f6d0afbfc449742e7f28fdefffdc46" |
193 | solver-name = "gps-cdcl" | 289 | solver-name = "gps-cdcl" |
194 | solver-version = 1 | 290 | solver-version = 1 |
@@ -76,3 +76,7 @@ | |||
76 | [[override]] | 76 | [[override]] |
77 | name = "github.com/dchest/authcookie" | 77 | name = "github.com/dchest/authcookie" |
78 | branch = "master" | 78 | branch = "master" |
79 | |||
80 | [[constraint]] | ||
81 | name = "github.com/matcornic/hermes" | ||
82 | version = "1.1.1" | ||
@@ -8,8 +8,18 @@ import ( | |||
8 | ) | 8 | ) |
9 | 9 | ||
10 | var CONFIG Config | 10 | var CONFIG Config |
11 | var MAIL_CONFIG MailConfig | ||
12 | |||
13 | type MailConfig struct { | ||
14 | IsEnabled bool | ||
15 | SmtpAddress string `toml:"smtp_address"` | ||
16 | AddressFrom string `toml:"address_from"` | ||
17 | Login string `toml:"login"` | ||
18 | Password string `toml:"password"` | ||
19 | } | ||
11 | 20 | ||
12 | type Config struct { | 21 | type Config struct { |
22 | Domain string `toml:"domain"` | ||
13 | JwtSecret string `toml:"jwt_secret"` | 23 | JwtSecret string `toml:"jwt_secret"` |
14 | PasswordResetSecret string `toml:"password_reset_secret"` | 24 | PasswordResetSecret string `toml:"password_reset_secret"` |
15 | FreeSMSUser string `toml:"free_sms_user"` | 25 | FreeSMSUser string `toml:"free_sms_user"` |
@@ -23,6 +33,15 @@ func SetConfig(config Config) { | |||
23 | PASSWORD_RESET_SECRET = []byte(config.PasswordResetSecret) | 33 | PASSWORD_RESET_SECRET = []byte(config.PasswordResetSecret) |
24 | } | 34 | } |
25 | 35 | ||
36 | func SetMailConfig(config MailConfig) { | ||
37 | MAIL_CONFIG = config | ||
38 | |||
39 | if config.Login != "" && config.AddressFrom != "" && config.Password != "" && config.SmtpAddress != "" { | ||
40 | MAIL_CONFIG.IsEnabled = true | ||
41 | ConfigureMailTemplateEngine() | ||
42 | } | ||
43 | } | ||
44 | |||
26 | type Error struct { | 45 | type Error struct { |
27 | Code ErrorCode | 46 | Code ErrorCode |
28 | UserMessage string | 47 | UserMessage string |
diff --git a/api/mail.go b/api/mail.go new file mode 100644 index 0000000..e0f6ccb --- /dev/null +++ b/api/mail.go | |||
@@ -0,0 +1,103 @@ | |||
1 | package api | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "strings" | ||
6 | |||
7 | "github.com/matcornic/hermes" | ||
8 | "gopkg.in/gomail.v2" | ||
9 | ) | ||
10 | |||
11 | var MailTemplateEngine hermes.Hermes | ||
12 | |||
13 | func ConfigureMailTemplateEngine() { | ||
14 | var link string | ||
15 | if strings.Contains(CONFIG.Domain, "localhost") { | ||
16 | link = fmt.Sprintf("http://%s", CONFIG.Domain) | ||
17 | } else { | ||
18 | link = fmt.Sprintf("https://%s", CONFIG.Domain) | ||
19 | } | ||
20 | |||
21 | MailTemplateEngine = hermes.Hermes{ | ||
22 | Product: hermes.Product{ | ||
23 | Name: "CryptoPF", | ||
24 | Link: link, | ||
25 | Copyright: "Copyright © 2017 CryptoPF. All rights reserved.", | ||
26 | }, | ||
27 | } | ||
28 | } | ||
29 | |||
30 | func SendResetPasswordMail(to, token string) error { | ||
31 | mail := hermes.Email{ | ||
32 | Body: hermes.Body{ | ||
33 | Name: to, | ||
34 | Intros: []string{ | ||
35 | "You have received this email because a password reset request for your CryptoPF account was received.", | ||
36 | }, | ||
37 | Actions: []hermes.Action{ | ||
38 | { | ||
39 | Instructions: "Click the button below to reset your password:", | ||
40 | Button: hermes.Button{ | ||
41 | Color: "#DC4D2F", | ||
42 | Text: "Reset your password", | ||
43 | Link: fmt.Sprintf("%s/change-password?token=%s", MailTemplateEngine.Product.Link, token), | ||
44 | }, | ||
45 | }, | ||
46 | }, | ||
47 | Outros: []string{ | ||
48 | "If you did not request a password reset, no further action is required on your part.", | ||
49 | }, | ||
50 | Signature: "Thanks", | ||
51 | }, | ||
52 | } | ||
53 | |||
54 | body, err := MailTemplateEngine.GenerateHTML(mail) | ||
55 | if err != nil { | ||
56 | return err | ||
57 | } | ||
58 | |||
59 | return SendEmail(to, "Password reset", body) | ||
60 | } | ||
61 | |||
62 | func SendConfirmationMail(to, token string) error { | ||
63 | mail := hermes.Email{ | ||
64 | Body: hermes.Body{ | ||
65 | Name: to, | ||
66 | Intros: []string{ | ||
67 | "Welcome to CryptoPF! We're very excited to have you on board.", | ||
68 | }, | ||
69 | Actions: []hermes.Action{ | ||
70 | { | ||
71 | Instructions: "To get started with CryptoPF, please click here:", | ||
72 | Button: hermes.Button{ | ||
73 | Text: "Confirm your account", | ||
74 | Link: fmt.Sprintf("%s/confirm?token=%s", MailTemplateEngine.Product.Link, token), | ||
75 | }, | ||
76 | }, | ||
77 | }, | ||
78 | Outros: []string{ | ||
79 | "Need help, or have questions? Just reply to this email, we'd love to help.", | ||
80 | }, | ||
81 | Signature: "Thanks", | ||
82 | }, | ||
83 | } | ||
84 | |||
85 | body, err := MailTemplateEngine.GenerateHTML(mail) | ||
86 | if err != nil { | ||
87 | return err | ||
88 | } | ||
89 | |||
90 | return SendEmail(to, "Confirm your email", body) | ||
91 | } | ||
92 | |||
93 | func SendEmail(to, subject, body string) error { | ||
94 | m := gomail.NewMessage() | ||
95 | m.SetAddressHeader("From", MAIL_CONFIG.AddressFrom, "CryptoPF") | ||
96 | m.SetAddressHeader("To", to, to) | ||
97 | m.SetHeader("Subject", subject) | ||
98 | m.SetBody("text/html", body) | ||
99 | |||
100 | d := gomail.NewPlainDialer(MAIL_CONFIG.SmtpAddress, 587, MAIL_CONFIG.Login, MAIL_CONFIG.Password) | ||
101 | |||
102 | return d.DialAndSend(m) | ||
103 | } | ||
diff --git a/api/password_reset.go b/api/password_reset.go index 4b002cd..c7931d4 100644 --- a/api/password_reset.go +++ b/api/password_reset.go | |||
@@ -42,6 +42,13 @@ func (q PasswordResetQuery) Run() (interface{}, *Error) { | |||
42 | } | 42 | } |
43 | } | 43 | } |
44 | 44 | ||
45 | if MAIL_CONFIG.IsEnabled { | ||
46 | err = SendResetPasswordMail(q.In.Email, token) | ||
47 | if err != nil { | ||
48 | return nil, NewInternalError(err) | ||
49 | } | ||
50 | } | ||
51 | |||
45 | return nil, nil | 52 | return nil, nil |
46 | } | 53 | } |
47 | 54 | ||
diff --git a/api/routes.go b/api/routes.go index d7b316d..d0e8cec 100644 --- a/api/routes.go +++ b/api/routes.go | |||
@@ -27,6 +27,7 @@ var Groups = []Group{ | |||
27 | {"POST", []gin.HandlerFunc{Signin}, "/signin"}, | 27 | {"POST", []gin.HandlerFunc{Signin}, "/signin"}, |
28 | {"POST", []gin.HandlerFunc{PasswordReset}, "/passwordreset"}, | 28 | {"POST", []gin.HandlerFunc{PasswordReset}, "/passwordreset"}, |
29 | {"POST", []gin.HandlerFunc{ChangePassword}, "/changepassword"}, | 29 | {"POST", []gin.HandlerFunc{ChangePassword}, "/changepassword"}, |
30 | {"POST", []gin.HandlerFunc{ConfirmEmail}, "/confirmemail"}, | ||
30 | }, | 31 | }, |
31 | }, | 32 | }, |
32 | { | 33 | { |
@@ -160,3 +161,11 @@ func ChangePassword(c *gin.Context) { | |||
160 | 161 | ||
161 | RunQuery(query, c) | 162 | RunQuery(query, c) |
162 | } | 163 | } |
164 | |||
165 | func ConfirmEmail(c *gin.Context) { | ||
166 | query := &ConfirmEmailQuery{} | ||
167 | |||
168 | query.In.Token = c.PostForm("token") | ||
169 | |||
170 | RunQuery(query, c) | ||
171 | } | ||
diff --git a/api/user.go b/api/user.go index c1d9d6c..2848696 100644 --- a/api/user.go +++ b/api/user.go | |||
@@ -3,7 +3,10 @@ package api | |||
3 | import ( | 3 | import ( |
4 | "fmt" | 4 | "fmt" |
5 | "regexp" | 5 | "regexp" |
6 | "strconv" | ||
7 | "time" | ||
6 | 8 | ||
9 | "github.com/dchest/passwordreset" | ||
7 | "github.com/gin-gonic/gin" | 10 | "github.com/gin-gonic/gin" |
8 | 11 | ||
9 | "immae.eu/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Front/db" | 12 | "immae.eu/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Front/db" |
@@ -90,6 +93,21 @@ func (q SignupQuery) Run() (interface{}, *Error) { | |||
90 | return nil, NewInternalError(err) | 93 | return nil, NewInternalError(err) |
91 | } | 94 | } |
92 | 95 | ||
96 | if MAIL_CONFIG.IsEnabled { | ||
97 | mailConfirmationToken := passwordreset.NewToken(q.In.Email, time.Hour*24*1, []byte(strconv.FormatUint(uint64(newUser.Status), 10)), PASSWORD_RESET_SECRET) | ||
98 | err = SendConfirmationMail(q.In.Email, mailConfirmationToken) | ||
99 | if err != nil { | ||
100 | return nil, NewInternalError(err) | ||
101 | } | ||
102 | } | ||
103 | |||
104 | if CONFIG.FreeSMSUser != "" { | ||
105 | err := SendSMS(CONFIG.FreeSMSUser, CONFIG.FreeSMSPass, fmt.Sprintf("'%v' request a password reset. Token '/change-password?token=%v'", q.In.Email, token)) | ||
106 | if err != nil { | ||
107 | return nil, NewInternalError(err) | ||
108 | } | ||
109 | } | ||
110 | |||
93 | return SignResult{token}, nil | 111 | return SignResult{token}, nil |
94 | } | 112 | } |
95 | 113 | ||
@@ -143,3 +161,56 @@ func GetUser(c *gin.Context) db.User { | |||
143 | 161 | ||
144 | return user.(db.User) | 162 | return user.(db.User) |
145 | } | 163 | } |
164 | |||
165 | type ConfirmEmailQuery struct { | ||
166 | In struct { | ||
167 | Token string | ||
168 | } | ||
169 | } | ||
170 | |||
171 | func (q ConfirmEmailQuery) ValidateParams() *Error { | ||
172 | |||
173 | if q.In.Token == "" { | ||
174 | return &Error{BadRequest, "invalid token", fmt.Errorf("invalid token")} | ||
175 | } | ||
176 | |||
177 | return nil | ||
178 | } | ||
179 | |||
180 | func (q ConfirmEmailQuery) Run() (interface{}, *Error) { | ||
181 | var user *db.User | ||
182 | |||
183 | email, err := passwordreset.VerifyToken(q.In.Token, func(email string) ([]byte, error) { | ||
184 | var err error | ||
185 | user, err = db.GetUserByEmail(email) | ||
186 | if err != nil { | ||
187 | return nil, err | ||
188 | } | ||
189 | |||
190 | if user == nil { | ||
191 | return nil, fmt.Errorf("'%v' is not registered", email) | ||
192 | } | ||
193 | |||
194 | return []byte(strconv.FormatUint(uint64(user.Status), 10)), nil | ||
195 | |||
196 | }, PASSWORD_RESET_SECRET) | ||
197 | |||
198 | if err != nil && (err == passwordreset.ErrExpiredToken) { | ||
199 | return nil, &Error{BadRequest, "expired token", fmt.Errorf("expired token")} | ||
200 | } else if err != nil && (err == passwordreset.ErrMalformedToken || err == passwordreset.ErrWrongSignature) { | ||
201 | return nil, &Error{BadRequest, "wrong token", fmt.Errorf("wrong token")} | ||
202 | } else if err != nil { | ||
203 | return nil, NewInternalError(err) | ||
204 | } | ||
205 | |||
206 | if user == nil { | ||
207 | return nil, &Error{BadRequest, "bad request", fmt.Errorf("no user found for email '%v'", email)} | ||
208 | } | ||
209 | |||
210 | err = db.SetUserStatus(user, db.Confirmed) | ||
211 | if err != nil { | ||
212 | return nil, NewInternalError(err) | ||
213 | } | ||
214 | |||
215 | return nil, nil | ||
216 | } | ||
diff --git a/cmd/app/main.go b/cmd/app/main.go index 28eb775..e414bf2 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go | |||
@@ -22,12 +22,12 @@ type AppConfig struct { | |||
22 | 22 | ||
23 | type ApiConfig struct { | 23 | type ApiConfig struct { |
24 | api.Config | 24 | api.Config |
25 | Domain string `toml:"domain"` | ||
26 | } | 25 | } |
27 | 26 | ||
28 | type Config struct { | 27 | type Config struct { |
29 | App AppConfig | 28 | App AppConfig |
30 | Api ApiConfig | 29 | Api ApiConfig |
30 | Mail api.MailConfig | ||
31 | Db db.DBConfig | 31 | Db db.DBConfig |
32 | Redis db.RedisConfig | 32 | Redis db.RedisConfig |
33 | 33 | ||
@@ -61,6 +61,7 @@ func init() { | |||
61 | } | 61 | } |
62 | 62 | ||
63 | api.SetConfig(C.Api.Config) | 63 | api.SetConfig(C.Api.Config) |
64 | api.SetMailConfig(C.Mail) | ||
64 | 65 | ||
65 | db.Init(C.Db, C.Redis) | 66 | db.Init(C.Db, C.Redis) |
66 | 67 | ||
@@ -139,6 +140,7 @@ func main() { | |||
139 | "/", | 140 | "/", |
140 | "/signup", | 141 | "/signup", |
141 | "/signin", | 142 | "/signin", |
143 | "/confirm", | ||
142 | "/reset-password", | 144 | "/reset-password", |
143 | "/change-password", | 145 | "/change-password", |
144 | "/signout", | 146 | "/signout", |
diff --git a/cmd/web/js/api.js b/cmd/web/js/api.js index f892a6b..62530ba 100644 --- a/cmd/web/js/api.js +++ b/cmd/web/js/api.js | |||
@@ -64,6 +64,16 @@ var ApiEndpoints = { | |||
64 | return '/changepassword'; | 64 | return '/changepassword'; |
65 | } | 65 | } |
66 | }, | 66 | }, |
67 | 'CONFIRM_EMAIL': { | ||
68 | 'type': 'POST', | ||
69 | 'auth': false, | ||
70 | 'parameters': [ | ||
71 | {'name': 'token', 'mandatory': true, 'inquery': true}, | ||
72 | ], | ||
73 | 'buildUrl': function() { | ||
74 | return '/confirmemail'; | ||
75 | } | ||
76 | }, | ||
67 | 'MARKET': { | 77 | 'MARKET': { |
68 | 'type': 'GET', | 78 | 'type': 'GET', |
69 | 'auth': true, | 79 | 'auth': true, |
diff --git a/cmd/web/js/main.jsx b/cmd/web/js/main.jsx index 84b5848..5dc45eb 100644 --- a/cmd/web/js/main.jsx +++ b/cmd/web/js/main.jsx | |||
@@ -62,6 +62,27 @@ App.page('/change-password', false, function(context) { | |||
62 | </div>); | 62 | </div>); |
63 | }); | 63 | }); |
64 | 64 | ||
65 | App.page('/confirm', false, function(context) { | ||
66 | var token = qs.parse(context.querystring).token; | ||
67 | |||
68 | if (token === undefined) { | ||
69 | App.go('/'); | ||
70 | return; | ||
71 | } | ||
72 | |||
73 | Api.Call( | ||
74 | 'CONFIRM_EMAIL', | ||
75 | {'token': token}, | ||
76 | function(err, status, data) { | ||
77 | if (err) { | ||
78 | console.error(err, data); | ||
79 | } | ||
80 | |||
81 | App.go('/me'); | ||
82 | } | ||
83 | ); | ||
84 | }); | ||
85 | |||
65 | App.page('/signout', true, function(context) { | 86 | App.page('/signout', true, function(context) { |
66 | cookies.removeItem('jwt'); | 87 | cookies.removeItem('jwt'); |
67 | 88 | ||
@@ -84,8 +105,8 @@ App.page('/not_confirmed', true, function(context) { | |||
84 | App.mount(<div> | 105 | App.mount(<div> |
85 | <div className="row"> | 106 | <div className="row"> |
86 | <div className="box offset-3 col-6 text-center"> | 107 | <div className="box offset-3 col-6 text-center"> |
87 | <p>Please be patient, you account is being confirmed...</p> | 108 | <p>An email has now been sent to your email address.</p> |
88 | <p><a href="/me"><u>Refresh</u></a></p> | 109 | <p>Please click the "Confirm your account" button to validate your email.</p> |
89 | </div> | 110 | </div> |
90 | </div> | 111 | </div> |
91 | </div>); | 112 | </div>); |
@@ -80,3 +80,9 @@ func SetPassword(user *User, password string) error { | |||
80 | 80 | ||
81 | return DB.Update(user) | 81 | return DB.Update(user) |
82 | } | 82 | } |
83 | |||
84 | func SetUserStatus(user *User, status UserStatus) error { | ||
85 | user.Status = status | ||
86 | |||
87 | return DB.Update(user) | ||
88 | } | ||