summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUnknown <joe2010xtmf@163.com>2014-03-19 08:27:27 -0400
committerUnknown <joe2010xtmf@163.com>2014-03-19 08:27:27 -0400
commitde087c7b4a31cb0643d5432ec9d6b26e208baff2 (patch)
treed85449d68cea28a6e208dc1a56acda1a50b82a10
parentfbbae2b721c04be740d67b9d227a7578030f93b9 (diff)
downloadgitea-de087c7b4a31cb0643d5432ec9d6b26e208baff2.tar.gz
gitea-de087c7b4a31cb0643d5432ec9d6b26e208baff2.zip
Add send register confirm mail
-rw-r--r--README.md1
-rw-r--r--conf/app.ini5
-rw-r--r--models/user.go25
-rw-r--r--modules/auth/mail.go11
-rw-r--r--modules/base/conf.go4
-rw-r--r--modules/base/tool.go55
-rw-r--r--modules/mailer/mail.go7
-rw-r--r--modules/mailer/mailer.go112
-rw-r--r--routers/repo/repo.go2
-rw-r--r--routers/user/user.go10
10 files changed, 204 insertions, 28 deletions
diff --git a/README.md b/README.md
index 08d9787189..c0cd9cceb2 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,7 @@ There are two ways to install Gogs:
## Acknowledgments
+- Mail service is based on [WeTalk](https://github.com/beego/wetalk).
- Logo inspired by [martini](https://github.com/martini-contrib).
## Contributors
diff --git a/conf/app.ini b/conf/app.ini
index 82d78d2334..c2c299cf63 100644
--- a/conf/app.ini
+++ b/conf/app.ini
@@ -35,14 +35,17 @@ SECRET_KEY = !#@FDEWREWR&*(
ACTIVE_CODE_LIVE_MINUTES = 180
RESET_PASSWD_CODE_LIVE_MINUTES = 180
; User need to confirm e-mail for registration
-REGISTER_EMAIL_CONFIRM = true
+REGISTER_EMAIL_CONFIRM = false
[mailer]
ENABLED = false
; Name displayed in mail title
SUBJECT = %(APP_NAME)s
; Mail server
+; Gmail: smtp.gmail.com:587
HOST =
+; Mail from address
+FROM =
; Mailer user name and password
USER =
PASSWD =
diff --git a/models/user.go b/models/user.go
index 579f6a7486..5f08f9e92d 100644
--- a/models/user.go
+++ b/models/user.go
@@ -105,19 +105,19 @@ func GetUserSalt() string {
}
// RegisterUser creates record of a new user.
-func RegisterUser(user *User) (err error) {
+func RegisterUser(user *User) (*User, error) {
isExist, err := IsUserExist(user.Name)
if err != nil {
- return err
+ return nil, err
} else if isExist {
- return ErrUserAlreadyExist
+ return nil, ErrUserAlreadyExist
}
isExist, err = IsEmailUsed(user.Email)
if err != nil {
- return err
+ return nil, err
} else if isExist {
- return ErrEmailAlreadyUsed
+ return nil, ErrEmailAlreadyUsed
}
user.LowerName = strings.ToLower(user.Name)
@@ -126,22 +126,17 @@ func RegisterUser(user *User) (err error) {
user.Expired = time.Now().Add(3 * 24 * time.Hour)
user.Rands = GetUserSalt()
if err = user.EncodePasswd(); err != nil {
- return err
+ return nil, err
} else if _, err = orm.Insert(user); err != nil {
- return err
+ return nil, err
} else if err = os.MkdirAll(UserPath(user.Name), os.ModePerm); err != nil {
if _, err := orm.Id(user.Id).Delete(&User{}); err != nil {
- return errors.New(fmt.Sprintf(
+ return nil, errors.New(fmt.Sprintf(
"both create userpath %s and delete table record faild: %v", user.Name, err))
}
- return err
- }
-
- // Send confirmation e-mail.
- if base.Service.RegisterEmailConfitm {
-
+ return nil, err
}
- return nil
+ return user, nil
}
// UpdateUser updates user's information.
diff --git a/modules/auth/mail.go b/modules/auth/mail.go
index 6f6bf20a06..cdfcce4f99 100644
--- a/modules/auth/mail.go
+++ b/modules/auth/mail.go
@@ -16,7 +16,7 @@ import (
// create a time limit code for user active
func CreateUserActiveCode(user *models.User, startInf interface{}) string {
hours := base.Service.ActiveCodeLives / 60
- data := fmt.Sprintf("%d", user.Id) + user.Email + user.LowerName + user.Passwd + user.Rands
+ data := base.ToStr(user.Id) + user.Email + user.LowerName + user.Passwd + user.Rands
code := base.CreateTimeLimitCode(data, hours, startInf)
// add tail hex username
@@ -32,11 +32,10 @@ func SendRegisterMail(user *models.User) {
data := mailer.GetMailTmplData(user)
data["Code"] = code
body := base.RenderTemplate("mail/auth/register_success.html", data)
- _, _, _ = code, subject, body
- // msg := mailer.NewMailMessage([]string{user.Email}, subject, body)
- // msg.Info = fmt.Sprintf("UID: %d, send register mail", user.Id)
+ 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)
+ // async send mail
+ mailer.SendAsync(msg)
}
diff --git a/modules/base/conf.go b/modules/base/conf.go
index ee5638ed68..24ee1d7f06 100644
--- a/modules/base/conf.go
+++ b/modules/base/conf.go
@@ -37,7 +37,7 @@ var (
)
var Service struct {
- RegisterEmailConfitm bool
+ RegisterEmailConfirm bool
ActiveCodeLives int
ResetPwdCodeLives int
}
@@ -138,7 +138,7 @@ func newRegisterService() {
log.Warn("Register Service: Mail Service is not enabled")
return
}
- Service.RegisterEmailConfitm = true
+ Service.RegisterEmailConfirm = true
log.Info("Register Service Enabled")
}
diff --git a/modules/base/tool.go b/modules/base/tool.go
index 2a989b377d..fc3b4c45b8 100644
--- a/modules/base/tool.go
+++ b/modules/base/tool.go
@@ -13,6 +13,7 @@ import (
"encoding/json"
"fmt"
"math"
+ "strconv"
"strings"
"time"
)
@@ -59,13 +60,14 @@ func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string
// create sha1 encode string
sh := sha1.New()
- sh.Write([]byte(data + SecretKey + startStr + endStr + fmt.Sprintf("%d", minutes)))
+ sh.Write([]byte(data + SecretKey + startStr + endStr + ToStr(minutes)))
encoded := hex.EncodeToString(sh.Sum(nil))
code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded)
return code
}
+// TODO:
func RenderTemplate(TplNames string, Data map[interface{}]interface{}) string {
// if beego.RunMode == "dev" {
// beego.BuildTemplate(beego.ViewsPath)
@@ -300,6 +302,57 @@ func DateFormat(t time.Time, format string) string {
return t.Format(format)
}
+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
+}
+
+// convert any type to string
+func ToStr(value interface{}, args ...int) (s string) {
+ switch v := value.(type) {
+ case bool:
+ s = strconv.FormatBool(v)
+ case float32:
+ s = strconv.FormatFloat(float64(v), 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 32))
+ case float64:
+ s = strconv.FormatFloat(v, 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 64))
+ case int:
+ s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
+ case int8:
+ s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
+ case int16:
+ s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
+ case int32:
+ s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
+ case int64:
+ s = strconv.FormatInt(v, argInt(args).Get(0, 10))
+ case uint:
+ s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
+ case uint8:
+ s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
+ case uint16:
+ s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
+ case uint32:
+ s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
+ case uint64:
+ s = strconv.FormatUint(v, argInt(args).Get(0, 10))
+ case string:
+ s = v
+ case []byte:
+ s = string(v)
+ default:
+ s = fmt.Sprintf("%v", v)
+ }
+ return s
+}
+
type Actioner interface {
GetOpType() int
GetActUserName() string
diff --git a/modules/mailer/mail.go b/modules/mailer/mail.go
index fe74af9eef..cc4fd6d059 100644
--- a/modules/mailer/mail.go
+++ b/modules/mailer/mail.go
@@ -9,6 +9,13 @@ import (
"github.com/gogits/gogs/modules/base"
)
+// Create New mail message use MailFrom and MailUser
+func NewMailMessage(To []string, subject, body string) Message {
+ msg := NewHtmlMessage(To, base.MailService.User, subject, body)
+ msg.User = base.MailService.User
+ return msg
+}
+
func GetMailTmplData(user *models.User) map[interface{}]interface{} {
data := make(map[interface{}]interface{}, 10)
data["AppName"] = base.AppName
diff --git a/modules/mailer/mailer.go b/modules/mailer/mailer.go
new file mode 100644
index 0000000000..cc76acb26f
--- /dev/null
+++ b/modules/mailer/mailer.go
@@ -0,0 +1,112 @@
+// 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 mailer
+
+import (
+ "fmt"
+ "net/smtp"
+ "strings"
+
+ "github.com/gogits/gogs/modules/base"
+ "github.com/gogits/gogs/modules/log"
+)
+
+type Message struct {
+ To []string
+ From string
+ Subject string
+ Body string
+ User string
+ Type string
+ Massive bool
+ Info string
+}
+
+// create mail content
+func (m Message) Content() string {
+ // set mail type
+ contentType := "text/plain; charset=UTF-8"
+ if m.Type == "html" {
+ contentType = "text/html; charset=UTF-8"
+ }
+
+ // create mail content
+ content := "From: " + m.User + "<" + m.From +
+ ">\r\nSubject: " + m.Subject + "\r\nContent-Type: " + contentType + "\r\n\r\n" + m.Body
+ return content
+}
+
+// Direct Send mail message
+func Send(msg Message) (int, error) {
+ log.Trace("Sending mails to: %s", strings.Join(msg.To, "; "))
+ host := strings.Split(base.MailService.Host, ":")
+
+ // get message body
+ content := msg.Content()
+
+ auth := smtp.PlainAuth("", base.MailService.User, base.MailService.Passwd, host[0])
+
+ if len(msg.To) == 0 {
+ return 0, fmt.Errorf("empty receive emails")
+ }
+
+ if len(msg.Body) == 0 {
+ return 0, fmt.Errorf("empty email body")
+ }
+
+ if msg.Massive {
+ // send mail to multiple emails one by one
+ num := 0
+ for _, to := range msg.To {
+ body := []byte("To: " + to + "\r\n" + content)
+ err := smtp.SendMail(base.MailService.Host, auth, msg.From, []string{to}, body)
+ if err != nil {
+ return num, err
+ }
+ num++
+ }
+ return num, nil
+ } else {
+ body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content)
+
+ // send to multiple emails in one message
+ err := smtp.SendMail(base.MailService.Host, auth, msg.From, msg.To, body)
+ if err != nil {
+ return 0, err
+ } else {
+ return 1, nil
+ }
+ }
+}
+
+// Async Send mail message
+func SendAsync(msg Message) {
+ // TODO may be need pools limit concurrent nums
+ go func() {
+ num, err := Send(msg)
+ tos := strings.Join(msg.To, "; ")
+ info := ""
+ if err != nil {
+ if len(msg.Info) > 0 {
+ info = ", info: " + msg.Info
+ }
+ // log failed
+ log.Error(fmt.Sprintf("Async sent email %d succeed, not send emails: %s%s err: %s", num, tos, info, err))
+ return
+ }
+ log.Trace(fmt.Sprintf("Async sent email %d succeed, sent emails: %s%s", num, tos, info))
+ }()
+}
+
+// Create html mail message
+func NewHtmlMessage(To []string, From, Subject, Body string) Message {
+ return Message{
+ To: To,
+ From: From,
+ Subject: Subject,
+ Body: Body,
+ Type: "html",
+ }
+}
diff --git a/routers/repo/repo.go b/routers/repo/repo.go
index 08fe1ed15b..61bf47c1f5 100644
--- a/routers/repo/repo.go
+++ b/routers/repo/repo.go
@@ -50,10 +50,10 @@ func SettingPost(ctx *middleware.Context) {
if err := models.DeleteRepository(ctx.User.Id, ctx.Repo.Repository.Id, ctx.User.LowerName); err != nil {
ctx.Handle(200, "repo.Delete", err)
- log.Trace("%s Repository deleted: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, ctx.Repo.Repository.LowerName)
return
}
}
+ log.Trace("%s Repository deleted: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, ctx.Repo.Repository.LowerName)
ctx.Render.Redirect("/", 302)
}
diff --git a/routers/user/user.go b/routers/user/user.go
index 05aeac60ec..2d6bcedce5 100644
--- a/routers/user/user.go
+++ b/routers/user/user.go
@@ -134,10 +134,11 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) {
Name: form.UserName,
Email: form.Email,
Passwd: form.Password,
- IsActive: !base.Service.RegisterEmailConfitm,
+ IsActive: !base.Service.RegisterEmailConfirm,
}
- if err := models.RegisterUser(u); err != nil {
+ var err error
+ if u, err = models.RegisterUser(u); err != nil {
switch err.Error() {
case models.ErrUserAlreadyExist.Error():
ctx.RenderWithErr("Username has been already taken", "user/signup", &form)
@@ -150,6 +151,11 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) {
}
log.Trace("%s User created: %s", ctx.Req.RequestURI, strings.ToLower(form.UserName))
+
+ // Send confirmation e-mail.
+ if base.Service.RegisterEmailConfirm {
+ auth.SendRegisterMail(u)
+ }
ctx.Render.Redirect("/user/login")
}