package models
import (
+ "encoding/hex"
"errors"
"fmt"
"os"
"github.com/gogits/git"
"github.com/gogits/gogs/modules/base"
+ "github.com/gogits/gogs/modules/log"
)
// User types.
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
}
}
}
-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() {
newService()
newLogService()
newMailService()
- newRegisterService()
+ newRegisterMailService()
}
"container/list"
"fmt"
"html/template"
+ "strings"
"time"
)
"ActionDesc": ActionDesc,
"DateFormat": DateFormat,
"List": List,
+ "Mail2Domain": func(mail string) string {
+ return "mail." + strings.Split(mail, "@")[1]
+ },
}
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 {
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
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
// 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))
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
import (
"github.com/codegangsta/martini"
+
+ "github.com/gogits/gogs/modules/base"
)
// SignInRequire requires user to sign in.
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
}
}
}
--- /dev/null
+// 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)
+}
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)
}
+++ /dev/null
-{{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
--- /dev/null
+<!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
<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>
+++ /dev/null
-<!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
{{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/>
"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"
)
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"))