| @@ -1,58 +0,0 @@ | |||||
| // Copyright 2014 The Gogs Authors. All rights reserved. | |||||
| // Use of this source code is governed by a MIT-style | |||||
| // license that can be found in the LICENSE file. | |||||
| package auth | |||||
| import ( | |||||
| "encoding/hex" | |||||
| "fmt" | |||||
| "github.com/gogits/gogs/models" | |||||
| "github.com/gogits/gogs/modules/base" | |||||
| "github.com/gogits/gogs/modules/mailer" | |||||
| ) | |||||
| // create a time limit code for user active | |||||
| func CreateUserActiveCode(user *models.User, startInf interface{}) string { | |||||
| hours := base.Service.ActiveCodeLives / 60 | |||||
| data := base.ToStr(user.Id) + user.Email + user.LowerName + user.Passwd + user.Rands | |||||
| code := base.CreateTimeLimitCode(data, hours, startInf) | |||||
| // add tail hex username | |||||
| code += hex.EncodeToString([]byte(user.LowerName)) | |||||
| return code | |||||
| } | |||||
| // Send user register mail with active code | |||||
| func SendRegisterMail(user *models.User) { | |||||
| code := CreateUserActiveCode(user, nil) | |||||
| subject := "Register success, Welcome" | |||||
| data := mailer.GetMailTmplData(user) | |||||
| data["Code"] = code | |||||
| body := base.RenderTemplate("mail/auth/register_success.html", data) | |||||
| msg := mailer.NewMailMessage([]string{user.Email}, subject, body) | |||||
| msg.Info = fmt.Sprintf("UID: %d, send register mail", user.Id) | |||||
| // async send mail | |||||
| mailer.SendAsync(msg) | |||||
| } | |||||
| // Send email verify active email. | |||||
| func SendActiveMail(user *models.User) { | |||||
| code := CreateUserActiveCode(user, nil) | |||||
| subject := "Verify your email address" | |||||
| data := mailer.GetMailTmplData(user) | |||||
| data["Code"] = code | |||||
| body := base.RenderTemplate("mail/auth/active_email.html", data) | |||||
| msg := mailer.NewMailMessage([]string{user.Email}, subject, body) | |||||
| msg.Info = fmt.Sprintf("UID: %d, send email verify mail", user.Id) | |||||
| // async send mail | |||||
| mailer.SendAsync(msg) | |||||
| } | |||||
| @@ -174,6 +174,7 @@ func init() { | |||||
| SecretKey = Cfg.MustValue("security", "SECRET_KEY") | SecretKey = Cfg.MustValue("security", "SECRET_KEY") | ||||
| // Extensions. | // Extensions. | ||||
| newService() | |||||
| newLogService() | newLogService() | ||||
| newMailService() | newMailService() | ||||
| newRegisterService() | newRegisterService() | ||||
| @@ -67,25 +67,6 @@ func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string | |||||
| return code | return code | ||||
| } | } | ||||
| // TODO: | |||||
| func RenderTemplate(TplNames string, Data map[interface{}]interface{}) string { | |||||
| // if beego.RunMode == "dev" { | |||||
| // beego.BuildTemplate(beego.ViewsPath) | |||||
| // } | |||||
| // ibytes := bytes.NewBufferString("") | |||||
| // if _, ok := beego.BeeTemplates[TplNames]; !ok { | |||||
| // panic("can't find templatefile in the path:" + TplNames) | |||||
| // } | |||||
| // err := beego.BeeTemplates[TplNames].ExecuteTemplate(ibytes, TplNames, Data) | |||||
| // if err != nil { | |||||
| // beego.Trace("template Execute err:", err) | |||||
| // } | |||||
| // icontent, _ := ioutil.ReadAll(ibytes) | |||||
| // return string(icontent) | |||||
| return "not implement yet" | |||||
| } | |||||
| // AvatarLink returns avatar link by given e-mail. | // AvatarLink returns avatar link by given e-mail. | ||||
| func AvatarLink(email string) string { | func AvatarLink(email string) string { | ||||
| return "http://1.gravatar.com/avatar/" + EncodeMd5(email) | return "http://1.gravatar.com/avatar/" + EncodeMd5(email) | ||||
| @@ -5,8 +5,13 @@ | |||||
| package mailer | package mailer | ||||
| import ( | import ( | ||||
| "encoding/hex" | |||||
| "fmt" | |||||
| "github.com/gogits/gogs/models" | "github.com/gogits/gogs/models" | ||||
| "github.com/gogits/gogs/modules/base" | "github.com/gogits/gogs/modules/base" | ||||
| "github.com/gogits/gogs/modules/log" | |||||
| "github.com/gogits/gogs/modules/middleware" | |||||
| ) | ) | ||||
| // Create New mail message use MailFrom and MailUser | // Create New mail message use MailFrom and MailUser | ||||
| @@ -22,10 +27,62 @@ func GetMailTmplData(user *models.User) map[interface{}]interface{} { | |||||
| data["AppVer"] = base.AppVer | data["AppVer"] = base.AppVer | ||||
| data["AppUrl"] = base.AppUrl | data["AppUrl"] = base.AppUrl | ||||
| data["AppLogo"] = base.AppLogo | data["AppLogo"] = base.AppLogo | ||||
| data["ActiveCodeLives"] = base.Service.ActiveCodeLives | |||||
| data["ResetPwdCodeLives"] = base.Service.ResetPwdCodeLives | |||||
| data["ActiveCodeLives"] = base.Service.ActiveCodeLives / 60 | |||||
| data["ResetPwdCodeLives"] = base.Service.ResetPwdCodeLives / 60 | |||||
| if user != nil { | if user != nil { | ||||
| data["User"] = user | data["User"] = user | ||||
| } | } | ||||
| return data | return data | ||||
| } | } | ||||
| // create a time limit code for user active | |||||
| func CreateUserActiveCode(user *models.User, startInf interface{}) string { | |||||
| hours := base.Service.ActiveCodeLives / 60 | |||||
| data := base.ToStr(user.Id) + user.Email + user.LowerName + user.Passwd + user.Rands | |||||
| code := base.CreateTimeLimitCode(data, hours, startInf) | |||||
| // add tail hex username | |||||
| code += hex.EncodeToString([]byte(user.LowerName)) | |||||
| return code | |||||
| } | |||||
| // Send user register mail with active code | |||||
| func SendRegisterMail(r *middleware.Render, user *models.User) { | |||||
| code := CreateUserActiveCode(user, nil) | |||||
| subject := "Register success, Welcome" | |||||
| data := GetMailTmplData(user) | |||||
| data["Code"] = code | |||||
| body, err := r.HTMLString("mail/auth/register_success", data) | |||||
| if err != nil { | |||||
| log.Error("mail.SendRegisterMail(fail to render): %v", err) | |||||
| return | |||||
| } | |||||
| msg := NewMailMessage([]string{user.Email}, subject, body) | |||||
| msg.Info = fmt.Sprintf("UID: %d, send register mail", user.Id) | |||||
| // async send mail | |||||
| SendAsync(msg) | |||||
| } | |||||
| // Send email verify active email. | |||||
| func SendActiveMail(r *middleware.Render, user *models.User) { | |||||
| code := CreateUserActiveCode(user, nil) | |||||
| subject := "Verify your email address" | |||||
| data := GetMailTmplData(user) | |||||
| data["Code"] = code | |||||
| body, err := r.HTMLString("mail/auth/active_email.html", data) | |||||
| if err != nil { | |||||
| log.Error("mail.SendActiveMail(fail to render): %v", err) | |||||
| return | |||||
| } | |||||
| msg := NewMailMessage([]string{user.Email}, subject, body) | |||||
| msg.Info = fmt.Sprintf("UID: %d, send email verify mail", user.Id) | |||||
| // async send mail | |||||
| SendAsync(msg) | |||||
| } | |||||
| @@ -14,6 +14,7 @@ import ( | |||||
| "github.com/gogits/gogs/modules/auth" | "github.com/gogits/gogs/modules/auth" | ||||
| "github.com/gogits/gogs/modules/base" | "github.com/gogits/gogs/modules/base" | ||||
| "github.com/gogits/gogs/modules/log" | "github.com/gogits/gogs/modules/log" | ||||
| "github.com/gogits/gogs/modules/mailer" | |||||
| "github.com/gogits/gogs/modules/middleware" | "github.com/gogits/gogs/modules/middleware" | ||||
| ) | ) | ||||
| @@ -152,7 +153,12 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) { | |||||
| // Send confirmation e-mail. | // Send confirmation e-mail. | ||||
| if base.Service.RegisterEmailConfirm { | if base.Service.RegisterEmailConfirm { | ||||
| auth.SendRegisterMail(u) | |||||
| mailer.SendRegisterMail(ctx.Render, u) | |||||
| ctx.Data["IsSendRegisterMail"] = true | |||||
| ctx.Data["Email"] = u.Email | |||||
| ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60 | |||||
| ctx.Render.HTML(200, "user/active", ctx.Data) | |||||
| return | |||||
| } | } | ||||
| ctx.Redirect("/user/login") | ctx.Redirect("/user/login") | ||||
| } | } | ||||
| @@ -228,7 +234,8 @@ func Activate(ctx *middleware.Context) { | |||||
| ctx.Data["IsActivatePage"] = true | ctx.Data["IsActivatePage"] = true | ||||
| // Resend confirmation e-mail. | // Resend confirmation e-mail. | ||||
| if base.Service.RegisterEmailConfirm { | if base.Service.RegisterEmailConfirm { | ||||
| auth.SendRegisterMail(ctx.User) | |||||
| ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60 | |||||
| mailer.SendActiveMail(ctx.Render, ctx.User) | |||||
| } else { | } else { | ||||
| ctx.Data["ServiceNotEnabled"] = true | ctx.Data["ServiceNotEnabled"] = true | ||||
| } | } | ||||
| @@ -0,0 +1,25 @@ | |||||
| {{template "mail/base.html" .}} | |||||
| {{define "title"}} | |||||
| {{if eq .Lang "zh-CN"}} | |||||
| {{.User.NickName}},激活你的账户 | |||||
| {{end}} | |||||
| {{if eq .Lang "en-US"}} | |||||
| {{.User.NickName}}, please active your account | |||||
| {{end}} | |||||
| {{end}} | |||||
| {{define "body"}} | |||||
| {{if eq .Lang "zh-CN"}} | |||||
| <p style="margin:0;padding:0 0 9px 0;">点击链接验证email,{{.ActiveCodeLives}} 分钟内有效</p> | |||||
| <p style="margin:0;padding:0 0 9px 0;"> | |||||
| <a href="{{.AppUrl}}active/{{.Code}}">{{.AppUrl}}active/{{.Code}}</a> | |||||
| </p> | |||||
| <p style="margin:0;padding:0 0 9px 0;">如果链接点击无反应,请复制到浏览器打开。</p> | |||||
| {{end}} | |||||
| {{if eq .Lang "en-US"}} | |||||
| <p style="margin:0;padding:0 0 9px 0;">Please click following link to verify your e-mail in {{.ActiveCodeLives}} hours</p> | |||||
| <p style="margin:0;padding:0 0 9px 0;"> | |||||
| <a href="{{.AppUrl}}active/{{.Code}}">{{.AppUrl}}active/{{.Code}}</a> | |||||
| </p> | |||||
| <p style="margin:0;padding:0 0 9px 0;">Copy and paste it to your browser if it's not working.</p> | |||||
| {{end}} | |||||
| {{end}} | |||||
| @@ -0,0 +1,33 @@ | |||||
| <!DOCTYPE html> | |||||
| <html> | |||||
| <head> | |||||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |||||
| <title>{{.User.Name}}, welcome to {{.AppName}}</title> | |||||
| </head> | |||||
| <body style="background:#eee;"> | |||||
| <div style="color:#555; font:12px/1.5 Tahoma,Arial,sans-serif;; text-shadow:1px 1px #fff; padding:0; margin:0;"> | |||||
| <div style="width:600px;margin:0 auto; padding:40px 0 20px;"> | |||||
| <div style="border:1px solid #d9d9d9;border-radius:3px; background:#fff; box-shadow: 0px 2px 5px rgba(0, 0, 0,.05); -webkit-box-shadow: 0px 2px 5px rgba(0, 0, 0,.05);"> | |||||
| <div style="padding: 20px 15px;"> | |||||
| <h1 style="font-size:20px; padding:10px 0 20px; margin:0; border-bottom:1px solid #ddd;"><a style="color:#333;text-decoration:none;" target="_blank" href="{{.AppUrl}}">{{.AppName}}</a></h1> | |||||
| <div style="padding:40px 15px;"> | |||||
| <div style="font-size:16px; padding-bottom:30px; font-weight:bold;"> | |||||
| {{.User.Name}}, welcome to {{.AppName}} | |||||
| </div> | |||||
| <div style="font-size:14px; padding:0 15px;"> | |||||
| <p style="margin:0;padding:0 0 9px 0;">Please click following link to verify your e-mail in {{.ActiveCodeLives}} hours</p> | |||||
| <p style="margin:0;padding:0 0 9px 0;"> | |||||
| <a href="{{.AppUrl}}activate/code={{.Code}}">{{.AppUrl}}active/{{.Code}}</a> | |||||
| </p> | |||||
| <p style="margin:0;padding:0 0 9px 0;">Copy and paste it to your browser if it's not working.</p> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div style="color:#aaa;padding:10px;text-align:center;"> | |||||
| © 2014 <a style="color:#888;text-decoration:none;" target="_blank" href="{{.AppUrl}}">{{AppName}}</a> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </body> | |||||
| </html> | |||||
| @@ -0,0 +1,25 @@ | |||||
| {{template "mail/base.html" .}} | |||||
| {{define "title"}} | |||||
| {{if eq .Lang "zh-CN"}} | |||||
| {{.User.NickName}},重置账户密码 | |||||
| {{end}} | |||||
| {{if eq .Lang "en-US"}} | |||||
| {{.User.NickName}}, reset your password | |||||
| {{end}} | |||||
| {{end}} | |||||
| {{define "body"}} | |||||
| {{if eq .Lang "zh-CN"}} | |||||
| <p style="margin:0;padding:0 0 9px 0;">点击链接重置密码,{{.ResetPwdCodeLives}} 分钟内有效</p> | |||||
| <p style="margin:0;padding:0 0 9px 0;"> | |||||
| <a href="{{.AppUrl}}reset/{{.Code}}">{{.AppUrl}}reset/{{.Code}}</a> | |||||
| </p> | |||||
| <p style="margin:0;padding:0 0 9px 0;">如果链接点击无反应,请复制到浏览器打开。</p> | |||||
| {{end}} | |||||
| {{if eq .Lang "en-US"}} | |||||
| <p style="margin:0;padding:0 0 9px 0;">Please click following link to reset your password in {{.ResetPwdCodeLives}} hours</p> | |||||
| <p style="margin:0;padding:0 0 9px 0;"> | |||||
| <a href="{{.AppUrl}}reset/{{.Code}}">{{.AppUrl}}reset/{{.Code}}</a> | |||||
| </p> | |||||
| <p style="margin:0;padding:0 0 9px 0;">Copy and paste it to your browser if it's not working.</p> | |||||
| {{end}} | |||||
| {{end}} | |||||
| @@ -0,0 +1,29 @@ | |||||
| <!DOCTYPE html> | |||||
| <html> | |||||
| <head> | |||||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |||||
| <title>{{.Title}} - {{AppName}}</title> | |||||
| </head> | |||||
| <body style="background:#eee;"> | |||||
| <div style="color:#555; font:12px/1.5 Tahoma,Arial,sans-serif;; text-shadow:1px 1px #fff; padding:0; margin:0;"> | |||||
| <div style="width:600px;margin:0 auto; padding:40px 0 20px;"> | |||||
| <div style="border:1px solid #d9d9d9;border-radius:3px; background:#fff; box-shadow: 0px 2px 5px rgba(0, 0, 0,.05); -webkit-box-shadow: 0px 2px 5px rgba(0, 0, 0,.05);"> | |||||
| <div style="padding: 20px 15px;"> | |||||
| <h1 style="font-size:20px; padding:10px 0 20px; margin:0; border-bottom:1px solid #ddd;"><a style="color:#333;text-decoration:none;" target="_blank" href="{{.AppUrl}}">{{AppName}}</a></h1> | |||||
| <div style="padding:40px 15px;"> | |||||
| <div style="font-size:16px; padding-bottom:30px; font-weight:bold;"> | |||||
| {{.Title}} | |||||
| </div> | |||||
| <div style="font-size:14px; padding:0 15px;"> | |||||
| {{template "body" .}} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div style="color:#aaa;padding:10px;text-align:center;"> | |||||
| © 2014 <a style="color:#888;text-decoration:none;" target="_blank" href="{{.AppUrl}}">{{AppName}} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </body> | |||||
| </html> | |||||
| @@ -4,19 +4,23 @@ | |||||
| <form action="/user/activate" method="post" class="form-horizontal gogs-card" id="gogs-login-card"> | <form action="/user/activate" method="post" class="form-horizontal gogs-card" id="gogs-login-card"> | ||||
| <h3>Activate Your Account</h3> | <h3>Activate Your Account</h3> | ||||
| {{if .IsActivatePage}} | {{if .IsActivatePage}} | ||||
| {{if .ServiceNotEnabled}} | |||||
| <p>Sorry, Register Mail Confirmation has been disabled.</p> | |||||
| {{if .ServiceNotEnabled}} | |||||
| <p>Sorry, Register Mail Confirmation has been disabled.</p> | |||||
| {{else}} | |||||
| <p>New confirmation e-mail has been sent to <b>{{.SignedUser.Email}}</b>, please check your inbox within {{.Hours}} hours.</p> | |||||
| {{end}} | |||||
| {{else}} | {{else}} | ||||
| <p>New confirmation e-mail has been sent to <b>{{.SignedUser.Email}}</b>, please check your inbox within 3 days.</p> | |||||
| {{end}} | |||||
| {{else}} | |||||
| <p>Hi, {{.SignedUser.Name}}, you have an unconfirmed email address(<b>{{.SignedUser.Email}}</b>). If you haven't received a confirmation e-mail or need to resend a new one, please click botton below.</p> | |||||
| <hr/> | |||||
| <div class="form-group"> | |||||
| <div class="col-md-offset-4 col-md-6"> | |||||
| <button type="submit" class="btn btn-lg btn-primary">Click here to resend your active e-mail</button> | |||||
| {{if .IsSendRegisterMail}} | |||||
| <p>A confirmation e-mail has been sent to <b>{{.Email}}</b>, please check your inbox within {{.Hours}} hours.</p> | |||||
| {{else}} | |||||
| <p>Hi, {{.SignedUser.Name}}, you have an unconfirmed email address(<b>{{.SignedUser.Email}}</b>). If you haven't received a confirmation e-mail or need to resend a new one, please click botton below.</p> | |||||
| <hr/> | |||||
| <div class="form-group"> | |||||
| <div class="col-md-offset-4 col-md-6"> | |||||
| <button type="submit" class="btn btn-lg btn-primary">Click here to resend your active e-mail</button> | |||||
| </div> | |||||
| </div> | </div> | ||||
| </div> | |||||
| {{end}} | |||||
| {{end}} | {{end}} | ||||
| </form> | </form> | ||||
| </div> | </div> | ||||