@@ -80,6 +80,18 @@ func GetEmailAddressByID(uid, id int64) (*EmailAddress, error) { | |||
return email, nil | |||
} | |||
// GetEmailAddressByIDAndEmail gets a user's email address by ID and email | |||
func GetEmailAddressByIDAndEmail(uid int64, emailAddr string) (*EmailAddress, error) { | |||
// User ID is required for security reasons | |||
email := &EmailAddress{UID: uid, Email: emailAddr} | |||
if has, err := x.Get(email); err != nil { | |||
return nil, err | |||
} else if !has { | |||
return nil, nil | |||
} | |||
return email, nil | |||
} | |||
func isEmailActive(e Engine, email string, userID, emailID int64) (bool, error) { | |||
if len(email) == 0 { | |||
return true, nil | |||
@@ -590,20 +590,31 @@ func Home(ctx *context.Context) { | |||
if err == nil && contributors != nil { | |||
var contributorInfos []*ContributorInfo | |||
for _, c := range contributors { | |||
// get user info from committer email | |||
user, err := models.GetUserByEmail(c.Email) | |||
if err == nil { | |||
// committer is system user, get info through user's primary email | |||
existedContributorInfo := getContributorInfo(contributorInfos,user.Email) | |||
if existedContributorInfo != nil { | |||
// existed: same primary email, different committer name | |||
existedContributorInfo.CommitCnt += c.CommitCnt | |||
}else{ | |||
// new committer info | |||
contributorInfos = append(contributorInfos, &ContributorInfo{ | |||
user, user.Email,c.CommitCnt, | |||
}) | |||
} | |||
} else { | |||
contributorInfos = append(contributorInfos, &ContributorInfo{ | |||
nil, c.Email,c.CommitCnt, | |||
}) | |||
// committer is not system user | |||
existedContributorInfo := getContributorInfo(contributorInfos,c.Email) | |||
if existedContributorInfo != nil { | |||
// existed: same primary email, different committer name | |||
existedContributorInfo.CommitCnt += c.CommitCnt | |||
}else{ | |||
contributorInfos = append(contributorInfos, &ContributorInfo{ | |||
nil, c.Email,c.CommitCnt, | |||
}) | |||
} | |||
} | |||
} | |||
ctx.Data["ContributorInfo"] = contributorInfos | |||
@@ -1266,6 +1266,15 @@ func Activate(ctx *context.Context) { | |||
log.Error("Error storing session: %v", err) | |||
} | |||
email, err := models.GetEmailAddressByIDAndEmail(user.ID, user.Email) | |||
if err != nil || email == nil{ | |||
log.Error("GetEmailAddressByIDAndEmail failed", ctx.Data["MsgID"]) | |||
} else { | |||
if err := email.Activate(); err != nil { | |||
log.Error("Activate failed: %v", err, ctx.Data["MsgID"]) | |||
} | |||
} | |||
ctx.Flash.Success(ctx.Tr("auth.account_activated")) | |||
ctx.Redirect(setting.AppSubURL + "/") | |||
return | |||
@@ -96,6 +96,18 @@ func ProfilePost(ctx *context.Context, form auth.UpdateProfileForm) { | |||
ctx.User.Location = form.Location | |||
ctx.User.Language = form.Language | |||
ctx.User.Description = form.Description | |||
isUsed, err := models.IsEmailUsed(form.Email) | |||
if err != nil { | |||
ctx.ServerError("IsEmailUsed", err) | |||
return | |||
} | |||
if isUsed { | |||
ctx.Flash.Error(ctx.Tr("form.email_been_used")) | |||
ctx.Redirect(setting.AppSubURL + "/user/settings") | |||
return | |||
} | |||
if err := models.UpdateUserSetting(ctx.User); err != nil { | |||
if _, ok := err.(models.ErrEmailAlreadyUsed); ok { | |||
ctx.Flash.Error(ctx.Tr("form.email_been_used")) | |||
@@ -4,6 +4,48 @@ | |||
font-size: 1.0em; | |||
margin-bottom: 1.0rem; | |||
} | |||
#contributorInfo > a:nth-child(n+25){ | |||
display:none; | |||
} | |||
#contributorInfo > a{ | |||
width: 2.0em; | |||
float: left; | |||
margin: .25em; | |||
} | |||
#contributorInfo > a.circular{ | |||
height: 2.0em; | |||
padding: 0; | |||
overflow: hidden; | |||
letter-spacing:1.0em; | |||
text-indent: 0.6em; | |||
line-height: 2.0em; | |||
text-transform:capitalize; | |||
color: #FFF; | |||
} | |||
#contributorInfo > a.circular:nth-child(9n+1){ | |||
background-color: #4ccdec; | |||
} | |||
#contributorInfo > a.circular:nth-child(9n+2){ | |||
background-color: #e0b265; | |||
} | |||
#contributorInfo > a.circular:nth-child(9n+3){ | |||
background-color: #d884b7; | |||
} | |||
#contributorInfo > a.circular:nth-child(9n+4){ | |||
background-color: #8c6bdc; | |||
} | |||
#contributorInfo > a.circular:nth-child(9n+5){ | |||
background-color: #3cb99f; | |||
} | |||
#contributorInfo > a.circular:nth-child(9n+6){ | |||
background-color: #6995b9; | |||
} | |||
#contributorInfo > a.circular:nth-child(9n+7){ | |||
background-color: #ab91a7; | |||
} | |||
#contributorInfo > a.circular:nth-child(9n+8){ | |||
background-color: #bfd0aa; | |||
} | |||
</style> | |||
<div class="repository file list"> | |||
{{template "repo/header" .}} | |||
@@ -193,17 +235,15 @@ | |||
<h4 class="ui header"> | |||
<strong>贡献者 ({{len .ContributorInfo}})</strong> | |||
<div class="ui right"> | |||
<a class="text grey" href="">全部 {{svg "octicon-chevron-right" 16}}</a> | |||
<a class="membersmore text grey" href="javascript:;">全部 {{svg "octicon-chevron-right" 16}}</a> | |||
</div> | |||
</h4> | |||
<div class="ui members"> | |||
<div class="ui members" id="contributorInfo"> | |||
{{range .ContributorInfo}} | |||
{{/*<img class="ui avatar image" src="{{.UserInfo.RelAvatarLink}}" alt=""/> <a href="{{AppSubUrl}}/{{.UserInfo.Name}}">{{.UserInfo.Name}}</a>*/}} | |||
{{if .UserInfo}} | |||
<a href="{{AppSubUrl}}/{{.UserInfo.Name}}"><img class="ui avatar image" src="{{.UserInfo.RelAvatarLink}}" alt=""/></a> | |||
<a href="{{AppSubUrl}}/{{.UserInfo.Name}}"><img class="ui avatar image" src="{{.UserInfo.RelAvatarLink}}"></a> | |||
{{else if .Email}} | |||
<a href="mailto:{{.Email}}"><img class="ui avatar image" src="{{AvatarLink .Email}}" alt=""/></a> | |||
<a href="mailto:{{.Email}}" class="circular ui button">{{.Email}}</a> | |||
{{end}} | |||
{{end}} | |||
</div> | |||
@@ -215,4 +255,12 @@ | |||
</div> | |||
</div> | |||
<script type="text/javascript"> | |||
$(document).ready(function(){ | |||
$(".membersmore").click(function(){ | |||
$("#contributorInfo > a:nth-child(n+25)").show(); | |||
}); | |||
}); | |||
</script> | |||
{{template "base/footer" .}} |