]> source.dussan.org Git - gitea.git/commitdiff
Finish verify email
authorUnknown <joe2010xtmf@163.com>
Wed, 19 Mar 2014 16:50:44 +0000 (12:50 -0400)
committerUnknown <joe2010xtmf@163.com>
Wed, 19 Mar 2014 16:50:44 +0000 (12:50 -0400)
14 files changed:
models/user.go
modules/base/conf.go
modules/base/template.go
modules/base/tool.go
modules/mailer/mail.go
modules/middleware/auth.go
routers/dev/template.go [new file with mode: 0644]
routers/user/user.go
templates/mail/auth/active_email.html [deleted file]
templates/mail/auth/active_email.tmpl [new file with mode: 0644]
templates/mail/auth/register_success.tmpl
templates/mail/base.html [deleted file]
templates/user/active.tmpl
web.go

index 5f08f9e92d61bb5c77f1460f0fa180b401ded009..3c31b3aff4a3ec0f5143587da2583fa0cbde819b 100644 (file)
@@ -5,6 +5,7 @@
 package models
 
 import (
+       "encoding/hex"
        "errors"
        "fmt"
        "os"
@@ -17,6 +18,7 @@ import (
        "github.com/gogits/git"
 
        "github.com/gogits/gogs/modules/base"
+       "github.com/gogits/gogs/modules/log"
 )
 
 // User types.
@@ -139,9 +141,43 @@ func RegisterUser(user *User) (*User, error) {
        return user, nil
 }
 
+// get user by erify code
+func getVerifyUser(code string) (user *User) {
+       if len(code) <= base.TimeLimitCodeLength {
+               return nil
+       }
+
+       // use tail hex username query user
+       hexStr := code[base.TimeLimitCodeLength:]
+       if b, err := hex.DecodeString(hexStr); err == nil {
+               if user, err = GetUserByName(string(b)); user != nil {
+                       return user
+               }
+               log.Error("user.getVerifyUser: %v", err)
+       }
+
+       return nil
+}
+
+// verify active code when active account
+func VerifyUserActiveCode(code string) (user *User) {
+       minutes := base.Service.ActiveCodeLives
+
+       if user = getVerifyUser(code); user != nil {
+               // time limit code
+               prefix := code[:base.TimeLimitCodeLength]
+               data := base.ToStr(user.Id) + user.Email + user.LowerName + user.Passwd + user.Rands
+
+               if base.VerifyTimeLimitCode(data, minutes, prefix) {
+                       return user
+               }
+       }
+       return nil
+}
+
 // UpdateUser updates user's information.
 func UpdateUser(user *User) (err error) {
-       _, err = orm.Id(user.Id).Update(user)
+       _, err = orm.Id(user.Id).UseBool().Update(user)
        return err
 }
 
index 64c97028b9a2b72b26e1a081e7fd36eb7e4c86a5..41226459d9990c62642f0a11e583e5eeacb8c7fa 100644 (file)
@@ -131,15 +131,15 @@ func newMailService() {
        }
 }
 
-func newRegisterService() {
+func newRegisterMailService() {
        if !Cfg.MustBool("service", "REGISTER_EMAIL_CONFIRM") {
                return
        } else if MailService == nil {
-               log.Warn("Register Service: Mail Service is not enabled")
+               log.Warn("Register Mail Service: Mail Service is not enabled")
                return
        }
        Service.RegisterEmailConfirm = true
-       log.Info("Register Service Enabled")
+       log.Info("Register Mail Service Enabled")
 }
 
 func init() {
@@ -177,5 +177,5 @@ func init() {
        newService()
        newLogService()
        newMailService()
-       newRegisterService()
+       newRegisterMailService()
 }
index 23d3d27713dc0e0f229808e83e478bea2e9da568..5268da64903cd3c1e96dbe1ba5e342c5201b031d 100644 (file)
@@ -8,6 +8,7 @@ import (
        "container/list"
        "fmt"
        "html/template"
+       "strings"
        "time"
 )
 
@@ -54,4 +55,7 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
        "ActionDesc": ActionDesc,
        "DateFormat": DateFormat,
        "List":       List,
+       "Mail2Domain": func(mail string) string {
+               return "mail." + strings.Split(mail, "@")[1]
+       },
 }
index d0b6bfbfda1575b0a7921c082741d96f24d3f811..8fabb8c531d9ce042046ad5c074e93d637f3e995 100644 (file)
@@ -36,6 +36,35 @@ func GetRandomString(n int) string {
        return string(bytes)
 }
 
+// verify time limit code
+func VerifyTimeLimitCode(data string, minutes int, code string) bool {
+       if len(code) <= 18 {
+               return false
+       }
+
+       // split code
+       start := code[:12]
+       lives := code[12:18]
+       if d, err := StrTo(lives).Int(); err == nil {
+               minutes = d
+       }
+
+       // right active code
+       retCode := CreateTimeLimitCode(data, minutes, start)
+       if retCode == code && minutes > 0 {
+               // check time is expired or not
+               before, _ := DateParse(start, "YmdHi")
+               now := time.Now()
+               if before.Add(time.Minute*time.Duration(minutes)).Unix() > now.Unix() {
+                       return true
+               }
+       }
+
+       return false
+}
+
+const TimeLimitCodeLength = 12 + 6 + 40
+
 // create a time limit code
 // code format: 12 length date time string + 6 minutes string + 40 sha1 encoded string
 func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string {
@@ -283,16 +312,24 @@ func DateFormat(t time.Time, format string) string {
        return t.Format(format)
 }
 
-type argInt []int
+// convert string to specify type
 
-func (a argInt) Get(i int, args ...int) (r int) {
-       if i >= 0 && i < len(a) {
-               r = a[i]
-       }
-       if len(args) > 0 {
-               r = args[0]
+type StrTo string
+
+func (f StrTo) Exist() bool {
+       return string(f) != string(0x1E)
+}
+
+func (f StrTo) Int() (int, error) {
+       v, err := strconv.ParseInt(f.String(), 10, 32)
+       return int(v), err
+}
+
+func (f StrTo) String() string {
+       if f.Exist() {
+               return string(f)
        }
-       return
+       return ""
 }
 
 // convert any type to string
@@ -334,6 +371,18 @@ func ToStr(value interface{}, args ...int) (s string) {
        return s
 }
 
+type argInt []int
+
+func (a argInt) Get(i int, args ...int) (r int) {
+       if i >= 0 && i < len(a) {
+               r = a[i]
+       }
+       if len(args) > 0 {
+               r = args[0]
+       }
+       return
+}
+
 type Actioner interface {
        GetOpType() int
        GetActUserName() string
index de4f24a47dab2c4df616123503ab35550cf05d44..c1d12bba45a0e81212a386c6a3ee3e670312dd5c 100644 (file)
@@ -37,9 +37,9 @@ func GetMailTmplData(user *models.User) map[interface{}]interface{} {
 
 // create a time limit code for user active
 func CreateUserActiveCode(user *models.User, startInf interface{}) string {
-       hours := base.Service.ActiveCodeLives / 60
+       minutes := base.Service.ActiveCodeLives
        data := base.ToStr(user.Id) + user.Email + user.LowerName + user.Passwd + user.Rands
-       code := base.CreateTimeLimitCode(data, hours, startInf)
+       code := base.CreateTimeLimitCode(data, minutes, startInf)
 
        // add tail hex username
        code += hex.EncodeToString([]byte(user.LowerName))
@@ -70,11 +70,11 @@ func SendRegisterMail(r *middleware.Render, user *models.User) {
 func SendActiveMail(r *middleware.Render, user *models.User) {
        code := CreateUserActiveCode(user, nil)
 
-       subject := "Verify your email address"
+       subject := "Verify your e-mail address"
 
        data := GetMailTmplData(user)
        data["Code"] = code
-       body, err := r.HTMLString("mail/auth/active_email.html", data)
+       body, err := r.HTMLString("mail/auth/active_email", data)
        if err != nil {
                log.Error("mail.SendActiveMail(fail to render): %v", err)
                return
index ed847dd83c91742231860edea2a26a0b8460daea..d45a21e988d8d1bbddcfc26f437ba7055f0d1363 100644 (file)
@@ -6,6 +6,8 @@ package middleware
 
 import (
        "github.com/codegangsta/martini"
+
+       "github.com/gogits/gogs/modules/base"
 )
 
 // SignInRequire requires user to sign in.
@@ -16,10 +18,10 @@ func SignInRequire(redirect bool) martini.Handler {
                                ctx.Redirect("/")
                        }
                        return
-               } else if !ctx.User.IsActive {
-                       // ctx.Data["Title"] = "Activate Your Account"
-                       // ctx.Render.HTML(200, "user/active", ctx.Data)
-                       // return
+               } else if !ctx.User.IsActive && base.Service.RegisterEmailConfirm {
+                       ctx.Data["Title"] = "Activate Your Account"
+                       ctx.Render.HTML(200, "user/active", ctx.Data)
+                       return
                }
        }
 }
diff --git a/routers/dev/template.go b/routers/dev/template.go
new file mode 100644 (file)
index 0000000..7d5225e
--- /dev/null
@@ -0,0 +1,25 @@
+// 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 dev
+
+import (
+       "github.com/codegangsta/martini"
+
+       "github.com/gogits/gogs/models"
+       "github.com/gogits/gogs/modules/base"
+       "github.com/gogits/gogs/modules/middleware"
+)
+
+func TemplatePreview(ctx *middleware.Context, params martini.Params) {
+       ctx.Data["User"] = models.User{Name: "Unknown"}
+       ctx.Data["AppName"] = base.AppName
+       ctx.Data["AppVer"] = base.AppVer
+       ctx.Data["AppUrl"] = base.AppUrl
+       ctx.Data["AppLogo"] = base.AppLogo
+       ctx.Data["Code"] = "2014031910370000009fff6782aadb2162b4a997acb69d4400888e0b9274657374"
+       ctx.Data["ActiveCodeLives"] = base.Service.ActiveCodeLives / 60
+       ctx.Data["ResetPwdCodeLives"] = base.Service.ResetPwdCodeLives / 60
+       ctx.HTML(200, params["_1"], ctx.Data)
+}
index da70ced9f5e23ed5542a742fef682cfd49995672..32f458f83554ff5192112a1f0743e7f63e76a3cb 100644 (file)
@@ -243,4 +243,18 @@ func Activate(ctx *middleware.Context) {
                ctx.Render.HTML(200, "user/active", ctx.Data)
                return
        }
+
+       // Verify code.
+       if user := models.VerifyUserActiveCode(code); user != nil {
+               user.IsActive = true
+               user.Rands = models.GetUserSalt()
+               models.UpdateUser(user)
+               ctx.Session.Set("userId", user.Id)
+               ctx.Session.Set("userName", user.Name)
+               ctx.Redirect("/", 302)
+               return
+       }
+
+       ctx.Data["IsActivateFailed"] = true
+       ctx.Render.HTML(200, "user/active", ctx.Data)
 }
diff --git a/templates/mail/auth/active_email.html b/templates/mail/auth/active_email.html
deleted file mode 100644 (file)
index ccb1202..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-{{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}}
\ No newline at end of file
diff --git a/templates/mail/auth/active_email.tmpl b/templates/mail/auth/active_email.tmpl
new file mode 100644 (file)
index 0000000..c04ddc8
--- /dev/null
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>{{.User.Name}}, please activate your account</title>
+</head>
+<body style="background:#eee;">
+<div style="color:#333; 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;"><img src="{{.AppUrl}}/{{.AppLogo}}" style="height: 32px; margin-bottom: -10px;"> <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;">
+                        Hi <span style="color: #00BFFF;">{{.User.Name}}</span>,
+                    </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 address within <b>{{.ActiveCodeLives}} hours</b>.</p>
+                                               <p style="margin:0;padding:0 0 9px 0;">
+                                                       <a href="{{.AppUrl}}user/activate?code={{.Code}}">{{.AppUrl}}user/activate?code={{.Code}}</a>
+                                               </p>
+                                               <p style="margin:0;padding:0 0 9px 0;">Copy and paste it to your browser if the link is 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="http://gogits.org">Gogs: Go Git Service</a>
+        </div>
+    </div>
+</div>
+</body>
+</html>
\ No newline at end of file
index 83c08550510ee8c7be1431a9e9529a4ba0dace2f..0a6928084702da604a68730b2533e29c11c4fe43 100644 (file)
@@ -5,27 +5,27 @@
 <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="color:#333; 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>
+                <h1 style="font-size:20px; padding:10px 0 20px; margin:0; border-bottom:1px solid #ddd;"><img src="{{.AppUrl}}/{{.AppLogo}}" style="height: 32px; margin-bottom: -10px;"> <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}}
+                        Hi <span style="color: #00BFFF;">{{.User.Name}}</span>, welcome to register {{.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;">Please click following link to verify your e-mail address within <b>{{.ActiveCodeLives}} hours</b>.</p>
                                                <p style="margin:0;padding:0 0 9px 0;">
-                                                       <a href="{{.AppUrl}}activate/code={{.Code}}">{{.AppUrl}}active/{{.Code}}</a>
+                                                       <a href="{{.AppUrl}}user/activate?code={{.Code}}">{{.AppUrl}}user/activate?code={{.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>
+                                               <p style="margin:0;padding:0 0 9px 0;">Copy and paste it to your browser if the link is 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>
+            © 2014 <a style="color:#888;text-decoration:none;" target="_blank" href="http://gogits.org">Gogs: Go Git Service</a>
         </div>
     </div>
 </div>
diff --git a/templates/mail/base.html b/templates/mail/base.html
deleted file mode 100644 (file)
index e86c2ad..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<!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>
\ No newline at end of file
index 1ee723ee07466ec130e37adcc443a497d9ef67be..fefd7d3aed131faf3afec2d14927ddc025ece874 100644 (file)
@@ -1,17 +1,23 @@
 {{template "base/head" .}}
 {{template "base/navbar" .}}
 <div id="gogs-body" class="container">
-    <form action="/user/activate" method="post" class="form-horizontal gogs-card" id="gogs-login-card">
+    <form action="/user/activate" method="get" class="form-horizontal gogs-card" id="gogs-login-card">
         <h3>Activate Your Account</h3>
         {{if .IsActivatePage}}
             {{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>
+            <p>New confirmation e-mail has been sent to <b>{{.SignedUser.Email}}</b>, please check your inbox within {{.Hours}} hours to complete your registeration.</p>
+            <hr/>
+            <a href="http://{{Mail2Domain .SignedUser.Email}}" class="btn btn-lg btn-success">Sign in to your e-mail</a>
             {{end}}
         {{else}}
             {{if .IsSendRegisterMail}}
-            <p>A confirmation e-mail has been sent to <b>{{.Email}}</b>, please check your inbox within {{.Hours}} hours.</p>
+            <p>A confirmation e-mail has been sent to <b>{{.Email}}</b>, please check your inbox within {{.Hours}} hours to complete your registeration.</p>
+            <hr/>
+            <a href="http://{{Mail2Domain .Email}}" class="btn btn-lg btn-success">Sign in to your e-mail</a>
+            {{else if .IsActivateFailed}}
+            <p>Sorry, your confirmation code has been exipired or not valid.</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/>
diff --git a/web.go b/web.go
index fe3596e220a5d6332c0c3ebb738f0fc68ba76b69..2cf3ba09321429c48703a2c203f2cd08c21e6d79 100644 (file)
--- a/web.go
+++ b/web.go
@@ -21,6 +21,7 @@ import (
        "github.com/gogits/gogs/modules/log"
        "github.com/gogits/gogs/modules/middleware"
        "github.com/gogits/gogs/routers"
+       "github.com/gogits/gogs/routers/dev"
        "github.com/gogits/gogs/routers/repo"
        "github.com/gogits/gogs/routers/user"
 )
@@ -113,6 +114,10 @@ func runWeb(*cli.Context) {
 
        m.Get("/:username/:reponame", ignSignIn, middleware.RepoAssignment(true), repo.Single)
 
+       if martini.Env == martini.Dev {
+               m.Get("/template/**", dev.TemplatePreview)
+       }
+
        listenAddr := fmt.Sprintf("%s:%s",
                base.Cfg.MustValue("server", "HTTP_ADDR"),
                base.Cfg.MustValue("server", "HTTP_PORT", "3000"))