@@ -161,6 +161,13 @@ func GetIssueCountByPoster(uid, rid int64, isClosed bool) int64 { | |||
return count | |||
} | |||
// .___ ____ ___ | |||
// | | ______ ________ __ ____ | | \______ ___________ | |||
// | |/ ___// ___/ | \_/ __ \| | / ___// __ \_ __ \ | |||
// | |\___ \ \___ \| | /\ ___/| | /\___ \\ ___/| | \/ | |||
// |___/____ >____ >____/ \___ >______//____ >\___ >__| | |||
// \/ \/ \/ \/ \/ | |||
// IssueUser represents an issue-user relation. | |||
type IssueUser struct { | |||
Id int64 | |||
@@ -404,6 +411,13 @@ type Label struct { | |||
NumOpenIssues int `xorm:"-"` | |||
} | |||
// _____ .__.__ __ | |||
// / \ |__| | ____ _______/ |_ ____ ____ ____ | |||
// / \ / \| | | _/ __ \ / ___/\ __\/ _ \ / \_/ __ \ | |||
// / Y \ | |_\ ___/ \___ \ | | ( <_> ) | \ ___/ | |||
// \____|__ /__|____/\___ >____ > |__| \____/|___| /\___ > | |||
// \/ \/ \/ \/ \/ | |||
// Milestone represents a milestone of repository. | |||
type Milestone struct { | |||
Id int64 | |||
@@ -517,7 +531,7 @@ func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) { | |||
} | |||
// ChangeMilestoneAssign changes assignment of milestone for issue. | |||
func ChangeMilestoneAssign(oldMid, mid int64, isIssueClosed bool) (err error) { | |||
func ChangeMilestoneAssign(oldMid, mid int64, issue *Issue) (err error) { | |||
sess := orm.NewSession() | |||
defer sess.Close() | |||
if err = sess.Begin(); err != nil { | |||
@@ -531,7 +545,7 @@ func ChangeMilestoneAssign(oldMid, mid int64, isIssueClosed bool) (err error) { | |||
} | |||
m.NumIssues-- | |||
if isIssueClosed { | |||
if issue.IsClosed { | |||
m.NumClosedIssues-- | |||
} | |||
if m.NumIssues > 0 { | |||
@@ -543,6 +557,12 @@ func ChangeMilestoneAssign(oldMid, mid int64, isIssueClosed bool) (err error) { | |||
sess.Rollback() | |||
return err | |||
} | |||
rawSql := "UPDATE `issue_user` SET milestone_id = 0 WHERE issue_id = ?" | |||
if _, err = sess.Exec(rawSql, issue.Id); err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
} | |||
if mid > 0 { | |||
@@ -551,7 +571,7 @@ func ChangeMilestoneAssign(oldMid, mid int64, isIssueClosed bool) (err error) { | |||
return err | |||
} | |||
m.NumIssues++ | |||
if isIssueClosed { | |||
if issue.IsClosed { | |||
m.NumClosedIssues++ | |||
} | |||
m.Completeness = m.NumClosedIssues * 100 / m.NumIssues | |||
@@ -559,6 +579,12 @@ func ChangeMilestoneAssign(oldMid, mid int64, isIssueClosed bool) (err error) { | |||
sess.Rollback() | |||
return err | |||
} | |||
rawSql := "UPDATE `issue_user` SET milestone_id = ? WHERE issue_id = ?" | |||
if _, err = sess.Exec(rawSql, m.Id, issue.Id); err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
} | |||
return sess.Commit() | |||
} | |||
@@ -587,9 +613,22 @@ func DeleteMilestone(m *Milestone) (err error) { | |||
sess.Rollback() | |||
return err | |||
} | |||
rawSql = "UPDATE `issue_user` SET milestone_id = 0 WHERE milestone_id = ?" | |||
if _, err = sess.Exec(rawSql, m.Id); err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
return sess.Commit() | |||
} | |||
// _________ __ | |||
// \_ ___ \ ____ _____ _____ ____ _____/ |_ | |||
// / \ \/ / _ \ / \ / \_/ __ \ / \ __\ | |||
// \ \___( <_> ) Y Y \ Y Y \ ___/| | \ | | |||
// \______ /\____/|__|_| /__|_| /\___ >___| /__| | |||
// \/ \/ \/ \/ \/ | |||
// Issue types. | |||
const ( | |||
IT_PLAIN = iota // Pure comment. | |||
@@ -5,6 +5,7 @@ | |||
package models | |||
import ( | |||
"crypto/tls" | |||
"encoding/json" | |||
"errors" | |||
"fmt" | |||
@@ -133,7 +134,7 @@ func AddSource(source *LoginSource) error { | |||
} | |||
func UpdateSource(source *LoginSource) error { | |||
_, err := orm.AllCols().Id(source.Id).Update(source) | |||
_, err := orm.Id(source.Id).AllCols().Update(source) | |||
return err | |||
} | |||
@@ -197,7 +198,7 @@ func LoginUser(uname, passwd string) (*User, error) { | |||
if err == nil { | |||
return u, nil | |||
} else { | |||
log.Warn("try ldap login", source.Name, "by", uname, "error:", err) | |||
log.Warn("Fail to login(%s) by LDAP(%s): %v", uname, source.Name, err) | |||
} | |||
} else if source.Type == LT_SMTP { | |||
u, err := LoginUserSMTPSource(nil, uname, passwd, | |||
@@ -205,7 +206,7 @@ func LoginUser(uname, passwd string) (*User, error) { | |||
if err == nil { | |||
return u, nil | |||
} else { | |||
log.Warn("try smtp login", source.Name, "by", uname, "error:", err) | |||
log.Warn("Fail to login(%s) by SMTP(%s): %v", uname, source.Name, err) | |||
} | |||
} | |||
} | |||
@@ -217,12 +218,9 @@ func LoginUser(uname, passwd string) (*User, error) { | |||
hasSource, err := orm.Id(u.LoginSource).Get(&source) | |||
if err != nil { | |||
return nil, err | |||
} | |||
if !hasSource { | |||
} else if !hasSource { | |||
return nil, ErrLoginSourceNotExist | |||
} | |||
if !source.IsActived { | |||
} else if !source.IsActived { | |||
return nil, ErrLoginSourceNotActived | |||
} | |||
@@ -296,20 +294,25 @@ var ( | |||
SMTPAuths = []string{SMTP_PLAIN, SMTP_LOGIN} | |||
) | |||
func SmtpAuth(addr string, a smtp.Auth, tls bool) error { | |||
c, err := smtp.Dial(addr) | |||
func SmtpAuth(host string, port int, a smtp.Auth, useTls bool) error { | |||
c, err := smtp.Dial(fmt.Sprintf("%s:%d", host, port)) | |||
if err != nil { | |||
return err | |||
} | |||
defer c.Close() | |||
if tls { | |||
if err = c.Hello("gogs"); err != nil { | |||
return err | |||
} | |||
if useTls { | |||
if ok, _ := c.Extension("STARTTLS"); ok { | |||
if err = c.StartTLS(nil); err != nil { | |||
config := &tls.Config{ServerName: host} | |||
if err = c.StartTLS(config); err != nil { | |||
return err | |||
} | |||
} else { | |||
return errors.New("smtp server unsupported tls") | |||
return errors.New("SMTP server unsupported TLS") | |||
} | |||
} | |||
@@ -333,11 +336,13 @@ func LoginUserSMTPSource(user *User, name, passwd string, sourceId int64, cfg *S | |||
} else if cfg.Auth == SMTP_LOGIN { | |||
auth = LoginAuth(name, passwd) | |||
} else { | |||
return nil, errors.New("Unsupported smtp auth type") | |||
return nil, errors.New("Unsupported SMTP auth type") | |||
} | |||
err := SmtpAuth(fmt.Sprintf("%s:%d", cfg.Host, cfg.Port), auth, cfg.TLS) | |||
if err != nil { | |||
if err := SmtpAuth(cfg.Host, cfg.Port, auth, cfg.TLS); err != nil { | |||
if strings.Contains(err.Error(), "Username and Password not accepted") { | |||
return nil, ErrUserNotExist | |||
} | |||
return nil, err | |||
} | |||
@@ -34,7 +34,7 @@ var ( | |||
ErrUserNameIllegal = errors.New("User name contains illegal characters") | |||
ErrLoginSourceNotExist = errors.New("Login source does not exist") | |||
ErrLoginSourceNotActived = errors.New("Login source is not actived") | |||
ErrUnsupportedLoginType = errors.New("Login source is unknow") | |||
ErrUnsupportedLoginType = errors.New("Login source is unknown") | |||
) | |||
// User represents the object of individual and member of organization. | |||
@@ -72,16 +72,14 @@ func Send(msg *Message) (int, error) { | |||
// 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 { | |||
} else if len(msg.Body) == 0 { | |||
return 0, fmt.Errorf("empty email body") | |||
} | |||
auth := smtp.PlainAuth("", base.MailService.User, base.MailService.Passwd, host[0]) | |||
if msg.Massive { | |||
// send mail to multiple emails one by one | |||
num := 0 | |||
@@ -158,7 +158,7 @@ func EditAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) { | |||
} | |||
log.Trace("%s Authentication changed by admin(%s): %s", ctx.Req.RequestURI, | |||
ctx.User.LowerName, strings.ToLower(form.AuthName)) | |||
ctx.User.LowerName, form.AuthName) | |||
ctx.Redirect("/admin/auths") | |||
} | |||
@@ -426,7 +426,7 @@ func UpdateIssueMilestone(ctx *middleware.Context) { | |||
// Not check for invalid milestone id and give responsibility to owners. | |||
issue.MilestoneId = mid | |||
if err = models.ChangeMilestoneAssign(oldMid, mid, issue.IsClosed); err != nil { | |||
if err = models.ChangeMilestoneAssign(oldMid, mid, issue); err != nil { | |||
ctx.Handle(500, "issue.UpdateIssueMilestone(ChangeMilestoneAssign)", err) | |||
return | |||
} else if err = models.UpdateIssue(issue); err != nil { | |||
@@ -19,7 +19,7 @@ | |||
<th>Actived</th> | |||
<th>Updated</th> | |||
<th>Created</th> | |||
<th>Operation</th> | |||
<th>Edit</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
@@ -115,16 +115,20 @@ | |||
<input name="smtpport" class="form-control" placeholder="Type port number" value="{{.Source.SMTP.Port}}"> | |||
</div> | |||
</div> | |||
<!-- <div class="form-group {{if .Err_TLS}}has-error has-feedback{{end}}"> | |||
<label class="col-md-3 control-label">TLS: </label> | |||
<div class="col-md-7"> | |||
<input name="tls" type="checkbox" class="form-control" {{if .Source.SMTP.TLS}}checked{{end}}> | |||
</div> | |||
</div> --> | |||
{{end}} | |||
<div class="form-group"> | |||
{{if eq $type 3}} | |||
<div class="col-md-offset-3 col-md-7"> | |||
<div class="checkbox"> | |||
<label> | |||
<input name="tls" type="checkbox" class="form-control" {{if .Source.SMTP.TLS}}checked{{end}}> | |||
<strong>Enable TLS Encryption</strong> | |||
</label> | |||
</div> | |||
</div> | |||
{{end}} | |||
<div class="col-md-offset-3 col-md-7"> | |||
<div class="checkbox"> | |||
<label> | |||
@@ -114,16 +114,16 @@ | |||
</div> | |||
</div> | |||
<!-- <div class="form-group"> | |||
<div class="form-group"> | |||
<div class="col-md-offset-3 col-md-7"> | |||
<div class="checkbox"> | |||
<label> | |||
<input name="tls" type="checkbox" {{if .tls}}checked{{end}}> | |||
<strong>Enable Register Confirmation</strong> | |||
<strong>Enable TLS Encryption</strong> | |||
</label> | |||
</div> | |||
</div> | |||
</div> --> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
@@ -148,6 +148,16 @@ | |||
</div> | |||
</div> | |||
<div class="panel panel-info"> | |||
<div class="panel-heading"> | |||
Tips | |||
</div> | |||
<div class="panel-body"> | |||
<h5>GMail Setting:</h5> | |||
<p>Host: smtp.gmail.com, Post: 587, Enable TLS Encryption: true</p> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<script> | |||
@@ -29,7 +29,7 @@ | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">Auth Login Name: </label> | |||
<div class="col-md-7"> | |||
<input name="loginname" class="form-control" placeholder="Type auth login's username" value="{{.loginname}}"> | |||
<input name="loginname" class="form-control" placeholder="Type auth login's username" value="{{.User.LoginName}}"> | |||
</div> | |||
</div> | |||