diff --git a/conf/locale/locale_en-US.ini b/conf/locale/locale_en-US.ini index 42fffa08da..9e2302195d 100644 --- a/conf/locale/locale_en-US.ini +++ b/conf/locale/locale_en-US.ini @@ -5,6 +5,7 @@ dashboard = Dashboard explore = Explore help = Help sign_in = Sign In +social_sign_in = Social Sign In: 2nd Step associate account sign_out = Sign Out sign_up = Sign Up register = Register @@ -49,6 +50,7 @@ my_mirrors = My Mirrors [auth] create_new_account = Create New Account register_hepler_msg = Already have an account? Sign in now! +social_register_hepler_msg = Already have an account? Bind now! disable_register_prompt = Sorry, registration has been disabled. Please contact the site administrator. remember_me = Remember Me forget_password = Fotget password? @@ -129,8 +131,12 @@ add_on = Added on last_used = Last used on no_activity = No recent activity -manage_orgs = Manage Organizations manage_social = Manage Associated Social Accounts +social_desc = This is a list of associated social accounts. Remove any binding that you do not recognize. +unbind = Unbind +unbind_success = Social account has been unbinded. + +manage_orgs = Manage Organizations delete_account = Delete Your Account delete_prompt = The operation will delete your account permanently, and CANNOT be undo! diff --git a/conf/locale/locale_zh-CN.ini b/conf/locale/locale_zh-CN.ini index fb49ade8c4..31b99c6024 100644 --- a/conf/locale/locale_zh-CN.ini +++ b/conf/locale/locale_zh-CN.ini @@ -49,6 +49,7 @@ my_mirrors = 我的镜像 [auth] create_new_account = 创建帐户 register_hepler_msg = 已经注册?立即登录! +social_register_hepler_msg = 已经注册?立即绑定! disable_register_prompt = 对不起,注册功能已被关闭。请联系网站管理员。 remember_me = 记住登录 forget_password = 忘记密码? @@ -129,8 +130,12 @@ add_on = 增加于 last_used = 上次使用在 no_activity = 没有最近活动 -manage_orgs = 管理我的组织 manage_social = 管理关联社交帐户 +social_desc = 以下是与您帐户所关联的社交帐号,如果您发现有陌生的关联,请立即解除绑定! +unbind = 解除绑定 +unbind_success = 社交帐号解除绑定成功! + +manage_orgs = 管理我的组织 delete_account = 删除当前帐户 delete_prompt = 删除操作会永久清除您的帐户信息,并且 不可恢复! diff --git a/models/oauth2.go b/models/oauth2.go index 4b024a26e4..46e8e492a3 100644 --- a/models/oauth2.go +++ b/models/oauth2.go @@ -6,6 +6,7 @@ package models import ( "errors" + "time" ) type OauthType int @@ -26,12 +27,15 @@ var ( ) type Oauth2 struct { - Id int64 - Uid int64 `xorm:"unique(s)"` // userId - User *User `xorm:"-"` - Type int `xorm:"unique(s) unique(oauth)"` // twitter,github,google... - Identity string `xorm:"unique(s) unique(oauth)"` // id.. - Token string `xorm:"TEXT not null"` + Id int64 + Uid int64 `xorm:"unique(s)"` // userId + User *User `xorm:"-"` + Type int `xorm:"unique(s) unique(oauth)"` // twitter,github,google... + Identity string `xorm:"unique(s) unique(oauth)"` // id.. + Token string `xorm:"TEXT not null"` + Created time.Time `xorm:"CREATED"` + Updated time.Time + HasRecentActivity bool `xorm:"-"` } func BindUserOauth2(userId, oauthId int64) error { @@ -69,10 +73,24 @@ func GetOauth2ById(id int64) (oa *Oauth2, err error) { return oa, nil } +// UpdateOauth2 updates given OAuth2. +func UpdateOauth2(oa *Oauth2) error { + _, err := x.Id(oa.Id).AllCols().Update(oa) + return err +} + // GetOauthByUserId returns list of oauthes that are releated to given user. -func GetOauthByUserId(uid int64) (oas []*Oauth2, err error) { - err = x.Find(&oas, Oauth2{Uid: uid}) - return oas, err +func GetOauthByUserId(uid int64) ([]*Oauth2, error) { + socials := make([]*Oauth2, 0, 5) + err := x.Find(&socials, Oauth2{Uid: uid}) + if err != nil { + return nil, err + } + + for _, social := range socials { + social.HasRecentActivity = social.Updated.Add(7 * 24 * time.Hour).After(time.Now()) + } + return socials, err } // DeleteOauth2ById deletes a oauth2 by ID. diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go index 16bd7defb8..e1c5c68c75 100644 --- a/modules/middleware/repo.go +++ b/modules/middleware/repo.go @@ -253,7 +253,10 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { } if ctx.IsSigned { - ctx.Repo.IsWatching = models.IsWatching(ctx.User.Id, repo.Id) + ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.Id) + } + if ctx.Repo.Repository.IsBare { + return } ctx.Data["TagName"] = ctx.Repo.TagName @@ -276,7 +279,6 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { ctx.Data["BranchName"] = ctx.Repo.BranchName ctx.Data["CommitId"] = ctx.Repo.CommitId - ctx.Data["IsWatchingRepo"] = ctx.Repo.IsWatching } } diff --git a/public/ng/css/gogs.css b/public/ng/css/gogs.css index 0c3a40db38..9633ed2791 100644 --- a/public/ng/css/gogs.css +++ b/public/ng/css/gogs.css @@ -1365,32 +1365,38 @@ The register and sign-in page style } #repo-hooks-panel, #repo-hooks-history-panel, +#user-social-panel, #user-ssh-panel { margin-bottom: 20px; } #repo-hooks-panel .setting-list, #repo-hooks-history-panel .setting-list, +#user-social-panel .setting-list, #user-ssh-panel .setting-list { background-color: #FFF; } #repo-hooks-panel .setting-list li, #repo-hooks-history-panel .setting-list li, +#user-social-panel .setting-list li, #user-ssh-panel .setting-list li { padding: 8px 20px; border-bottom: 1px solid #eaeaea; } #repo-hooks-panel .setting-list li.ssh:hover, #repo-hooks-history-panel .setting-list li.ssh:hover, +#user-social-panel .setting-list li.ssh:hover, #user-ssh-panel .setting-list li.ssh:hover { background-color: #ffffEE; } #repo-hooks-panel .setting-list li i, #repo-hooks-history-panel .setting-list li i, +#user-social-panel .setting-list li i, #user-ssh-panel .setting-list li i { padding-right: 5px; } #repo-hooks-panel .active-icon, #repo-hooks-history-panel .active-icon, +#user-social-panel .active-icon, #user-ssh-panel .active-icon { width: 10px; height: 10px; @@ -1401,24 +1407,29 @@ The register and sign-in page style } #repo-hooks-panel .ssh-content, #repo-hooks-history-panel .ssh-content, +#user-social-panel .ssh-content, #user-ssh-panel .ssh-content { margin-left: 24px; } #repo-hooks-panel .ssh-content .octicon, #repo-hooks-history-panel .ssh-content .octicon, +#user-social-panel .ssh-content .octicon, #user-ssh-panel .ssh-content .octicon { margin-right: 4px; } #repo-hooks-panel .ssh-content .print, #repo-hooks-history-panel .ssh-content .print, +#user-social-panel .ssh-content .print, #user-ssh-panel .ssh-content .print, #repo-hooks-panel .ssh-content .activity, #repo-hooks-history-panel .ssh-content .activity, +#user-social-panel .ssh-content .activity, #user-ssh-panel .ssh-content .activity { color: #888; } #repo-hooks-panel .ssh-delete-btn, #repo-hooks-history-panel .ssh-delete-btn, +#user-social-panel .ssh-delete-btn, #user-ssh-panel .ssh-delete-btn { margin-top: 6px; } diff --git a/public/ng/less/gogs/settings.less b/public/ng/less/gogs/settings.less index af38ca28f5..1a492b03c2 100644 --- a/public/ng/less/gogs/settings.less +++ b/public/ng/less/gogs/settings.less @@ -53,6 +53,7 @@ #repo-hooks-panel, #repo-hooks-history-panel, +#user-social-panel, #user-ssh-panel { margin-bottom: 20px; .setting-list { diff --git a/routers/user/auth.go b/routers/user/auth.go index 710d048f39..191da0a219 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -14,7 +14,7 @@ import ( "github.com/gogits/gogs/modules/auth" "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" - // "github.com/gogits/gogs/modules/mailer" + "github.com/gogits/gogs/modules/mailer" "github.com/gogits/gogs/modules/middleware" "github.com/gogits/gogs/modules/setting" ) @@ -157,23 +157,22 @@ func SignOut(ctx *middleware.Context) { } func oauthSignUp(ctx *middleware.Context, sid int64) { - // ctx.Data["Title"] = "OAuth Sign Up" - // ctx.Data["PageIsSignUp"] = true + ctx.Data["Title"] = ctx.Tr("sign_up") - // if _, err := models.GetOauth2ById(sid); err != nil { - // if err == models.ErrOauth2RecordNotExist { - // ctx.Handle(404, "user.oauthSignUp(GetOauth2ById)", err) - // } else { - // ctx.Handle(500, "user.oauthSignUp(GetOauth2ById)", err) - // } - // return - // } + if _, err := models.GetOauth2ById(sid); err != nil { + if err == models.ErrOauth2RecordNotExist { + ctx.Handle(404, "GetOauth2ById", err) + } else { + ctx.Handle(500, "GetOauth2ById", err) + } + return + } - // ctx.Data["IsSocialLogin"] = true - // ctx.Data["username"] = strings.Replace(ctx.Session.Get("socialName").(string), " ", "", -1) - // ctx.Data["email"] = ctx.Session.Get("socialEmail") - // log.Trace("user.oauthSignUp(social ID): %v", ctx.Session.Get("socialId")) - // ctx.HTML(200, SIGNUP) + ctx.Data["IsSocialLogin"] = true + ctx.Data["uname"] = strings.Replace(ctx.Session.Get("socialName").(string), " ", "", -1) + ctx.Data["email"] = ctx.Session.Get("socialEmail") + log.Trace("social ID: %v", ctx.Session.Get("socialId")) + ctx.HTML(200, SIGNUP) } func SignUp(ctx *middleware.Context) { @@ -202,10 +201,10 @@ func SignUpPost(ctx *middleware.Context, cpt *captcha.Captcha, form auth.Registe } isOauth := false - // sid, isOauth := ctx.Session.Get("socialId").(int64) - // if isOauth { - // ctx.Data["IsSocialLogin"] = true - // } + sid, isOauth := ctx.Session.Get("socialId").(int64) + if isOauth { + ctx.Data["IsSocialLogin"] = true + } // May redirect from home page. if ctx.Query("from") == "home" { @@ -268,28 +267,28 @@ func SignUpPost(ctx *middleware.Context, cpt *captcha.Captcha, form auth.Registe log.Trace("Account created: %s", u.Name) // Bind social account. - // if isOauth { - // if err = models.BindUserOauth2(u.Id, sid); err != nil { - // ctx.Handle(500, "user.SignUp(BindUserOauth2)", err) - // return - // } - // ctx.Session.Delete("socialId") - // log.Trace("%s OAuth binded: %s -> %d", ctx.Req.RequestURI, form.UserName, sid) - // } + if isOauth { + if err := models.BindUserOauth2(u.Id, sid); err != nil { + ctx.Handle(500, "BindUserOauth2", err) + return + } + ctx.Session.Delete("socialId") + log.Trace("%s OAuth binded: %s -> %d", ctx.Req.RequestURI, form.UserName, sid) + } // Send confirmation e-mail, no need for social account. - // if !isOauth && setting.Service.RegisterEmailConfirm && u.Id > 1 { - // mailer.SendRegisterMail(ctx.Render, u) - // ctx.Data["IsSendRegisterMail"] = true - // ctx.Data["Email"] = u.Email - // ctx.Data["Hours"] = setting.Service.ActiveCodeLives / 60 - // ctx.HTML(200, "user/activate") + if !isOauth && setting.Service.RegisterEmailConfirm && u.Id > 1 { + mailer.SendRegisterMail(ctx.Render, u) + ctx.Data["IsSendRegisterMail"] = true + ctx.Data["Email"] = u.Email + ctx.Data["Hours"] = setting.Service.ActiveCodeLives / 60 + ctx.HTML(200, "user/activate") - // if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { - // log.Error("Set cache(MailResendLimit) fail: %v", err) - // } - // return - // } + if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { + log.Error(4, "Set cache(MailResendLimit) fail: %v", err) + } + return + } ctx.Redirect("/user/login") } diff --git a/routers/user/setting.go b/routers/user/setting.go index 761052144f..739a30d032 100644 --- a/routers/user/setting.go +++ b/routers/user/setting.go @@ -200,36 +200,29 @@ func SettingsSSHKeysPost(ctx *middleware.Context, form auth.AddSSHKeyForm) { ctx.HTML(200, SETTINGS_SSH_KEYS) } -// func SettingSocial(ctx *middleware.Context) { -// ctx.Data["Title"] = "Social Account" -// ctx.Data["PageIsUserSetting"] = true -// ctx.Data["IsUserPageSettingSocial"] = true - -// // Unbind social account. -// remove, _ := base.StrTo(ctx.Query("remove")).Int64() -// if remove > 0 { -// if err := models.DeleteOauth2ById(remove); err != nil { -// ctx.Handle(500, "user.SettingSocial(DeleteOauth2ById)", err) -// return -// } -// ctx.Flash.Success("OAuth2 has been unbinded.") -// ctx.Redirect("/user/settings/social") -// return -// } - -// var err error -// ctx.Data["Socials"], err = models.GetOauthByUserId(ctx.User.Id) -// if err != nil { -// ctx.Handle(500, "user.SettingSocial(GetOauthByUserId)", err) -// return -// } -// ctx.HTML(200, SOCIAL) -// } - func SettingsSocial(ctx *middleware.Context) { ctx.Data["Title"] = ctx.Tr("settings") ctx.Data["PageIsUserSettings"] = true ctx.Data["PageIsSettingsSocial"] = true + + // Unbind social account. + remove, _ := com.StrTo(ctx.Query("remove")).Int64() + if remove > 0 { + if err := models.DeleteOauth2ById(remove); err != nil { + ctx.Handle(500, "DeleteOauth2ById", err) + return + } + ctx.Flash.Success(ctx.Tr("settings.unbind_success")) + ctx.Redirect("/user/settings/social") + return + } + + socials, err := models.GetOauthByUserId(ctx.User.Id) + if err != nil { + ctx.Handle(500, "GetOauthByUserId", err) + return + } + ctx.Data["Socials"] = socials ctx.HTML(200, SETTINGS_SOCIAL) } diff --git a/routers/user/social.go b/routers/user/social.go index ef83cd5b42..d7486dad2b 100644 --- a/routers/user/social.go +++ b/routers/user/social.go @@ -10,6 +10,7 @@ import ( "fmt" "net/url" "strings" + "time" "github.com/gogits/gogs/models" "github.com/gogits/gogs/modules/log" @@ -67,8 +68,8 @@ func SocialSignIn(ctx *middleware.Context) { oa, err := models.GetOauth2(ui.Identity) switch err { case nil: - ctx.Session.Set("userId", oa.User.Id) - ctx.Session.Set("userName", oa.User.Name) + ctx.Session.Set("uid", oa.User.Id) + ctx.Session.Set("uname", oa.User.Name) case models.ErrOauth2RecordNotExist: raw, _ := json.Marshal(tk) oa = &models.Oauth2{ @@ -89,6 +90,11 @@ func SocialSignIn(ctx *middleware.Context) { return } + oa.Updated = time.Now() + if err = models.UpdateOauth2(oa); err != nil { + log.Error(4, "UpdateOauth2: %v", err) + } + ctx.Session.Set("socialId", oa.Id) ctx.Session.Set("socialName", ui.Name) ctx.Session.Set("socialEmail", ui.Email) diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index e6ebb9aa22..4cc67c9d57 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -30,6 +30,7 @@

+ {{if not .Repository.IsBare}}
+ {{end}} {{if .Repository.IsMirror}}
diff --git a/templates/user/settings/social.tmpl b/templates/user/settings/social.tmpl index 7ff2ea237f..bcbc1fc567 100644 --- a/templates/user/settings/social.tmpl +++ b/templates/user/settings/social.tmpl @@ -7,8 +7,23 @@
{{template "ng/base/alert" .}}
-
-

{{.i18n.Tr "settings.manage_social"}}

+
+
{{.i18n.Tr "settings.manage_social"}}
+
    +
  • {{.i18n.Tr "settings.social_desc"}}
  • + {{range .Socials}} +
  • + + +
    +

    {{Oauth2Name .Type}}

    +

    {{.Identity}}

    +

    {{$.i18n.Tr "settings.add_on"}} {{DateFormat .Created "M d, Y"}} — {{$.i18n.Tr "settings.last_used"}} {{DateFormat .Updated "M d, Y"}}

    +
    + {{$.i18n.Tr "settings.unbind"}} +
  • + {{end}} +
diff --git a/templates/user/signin.tmpl b/templates/user/signin.tmpl index 9db98cd008..bc5c0c0c86 100644 --- a/templates/user/signin.tmpl +++ b/templates/user/signin.tmpl @@ -3,7 +3,7 @@
-

{{.i18n.Tr "sign_in"}}

+

{{if .IsSocialLogin}}{{.i18n.Tr "social_sign_in" | Str2html}}{{else}}{{.i18n.Tr "sign_in"}}{{end}}

{{template "ng/base/alert" .}} @@ -15,15 +15,18 @@

+ {{if not .IsSocialLogin}}

    {{.i18n.Tr "auth.remember_me"}}

+ {{end}}

     - {{.i18n.Tr "auth.forget_password"}} + {{if not .IsSocialLogin}}{{.i18n.Tr "auth.forget_password"}}{{end}}

+ {{if not .IsSocialLogin}}

{{.i18n.Tr "auth.sign_up_now" | Str2html}} @@ -34,6 +37,7 @@ {{template "ng/base/social" .}}

{{end}} + {{end}}
diff --git a/templates/user/signup.tmpl b/templates/user/signup.tmpl index 723314956c..8d4a572ef5 100644 --- a/templates/user/signup.tmpl +++ b/templates/user/signup.tmpl @@ -3,7 +3,7 @@
-

{{.i18n.Tr "sign_up"}}

+

{{if .IsSocialLogin}}{{.i18n.Tr "social_sign_in" | Str2html}}{{else}}{{.i18n.Tr "sign_up"}}{{end}}

diff --git a/templates/user/social.tmpl b/templates/user/social.tmpl deleted file mode 100644 index 7814cc0956..0000000000 --- a/templates/user/social.tmpl +++ /dev/null @@ -1,37 +0,0 @@ -{{template "base/head" .}} -{{template "base/navbar" .}} -
- {{template "user/setting_nav" .}} -
- {{template "base/alert" .}} -
-
- Social Account -
- -
- - - - - - - - - - - {{range .Socials}} - - - - - - - {{end}} - -
NameIdentityOp.
{{Oauth2Name .Type}}{{.Identity}}Unbind
-
-
-
-
-{{template "base/footer" .}} \ No newline at end of file