@@ -96,7 +96,7 @@ func runWeb(*cli.Context) { | |||
m.Get("/avatar/:hash", avt.ServeHTTP) | |||
m.Group("/user", func(r martini.Router) { | |||
r.Get("/login", user.SignIn) // TODO | |||
r.Get("/login", user.SignIn) | |||
r.Post("/login", bindIgnErr(auth.LogInForm{}), user.SignInPost) | |||
r.Get("/login/:name", user.SocialSignIn) | |||
r.Get("/sign_up", user.SignUp) | |||
@@ -130,7 +130,7 @@ func runWeb(*cli.Context) { | |||
m.Get("/user/:username", ignSignIn, user.Profile) | |||
m.Group("/repo", func(r martini.Router) { | |||
r.Get("/create", repo.Create) | |||
r.Get("/create", repo.Create) // TODO | |||
r.Post("/create", bindIgnErr(auth.CreateRepoForm{}), repo.CreatePost) | |||
r.Get("/migrate", repo.Migrate) | |||
r.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), repo.MigratePost) |
@@ -74,3 +74,9 @@ func GetOauthByUserId(uid int64) (oas []*Oauth2, err error) { | |||
err = orm.Find(&oas, Oauth2{Uid: uid}) | |||
return oas, err | |||
} | |||
// DeleteOauth2ById deletes a oauth2 by ID. | |||
func DeleteOauth2ById(id int64) error { | |||
_, err := orm.Delete(&Oauth2{Id: id}) | |||
return err | |||
} |
@@ -22,19 +22,12 @@ type MarkdownForm struct { | |||
Context string `form:"context"` | |||
} | |||
func (f *MarkdownForm) Name(field string) string { | |||
names := map[string]string{ | |||
"Text": "text", | |||
} | |||
return names[field] | |||
} | |||
func (f *MarkdownForm) Validate(errs *binding.BindingErrors, req *http.Request, ctx martini.Context) { | |||
data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | |||
validateApiReq(errs, data, f) | |||
} | |||
func validateApiReq(errs *binding.BindingErrors, data base.TmplData, f auth.Form) { | |||
func validateApiReq(errs *binding.BindingErrors, data base.TmplData, f interface{}) { | |||
if errs.Count() == 0 { | |||
return | |||
} else if len(errs.Overall) > 0 { | |||
@@ -64,22 +57,21 @@ func validateApiReq(errs *binding.BindingErrors, data base.TmplData, f auth.Form | |||
} | |||
if err, ok := errs.Fields[field.Name]; ok { | |||
data["Err_"+field.Name] = true | |||
switch err { | |||
case binding.BindingRequireError: | |||
data["ErrorMsg"] = f.Name(field.Name) + " cannot be empty" | |||
data["ErrorMsg"] = fieldName + " cannot be empty" | |||
case binding.BindingAlphaDashError: | |||
data["ErrorMsg"] = f.Name(field.Name) + " must be valid alpha or numeric or dash(-_) characters" | |||
data["ErrorMsg"] = fieldName + " must be valid alpha or numeric or dash(-_) characters" | |||
case binding.BindingAlphaDashDotError: | |||
data["ErrorMsg"] = f.Name(field.Name) + " must be valid alpha or numeric or dash(-_) or dot characters" | |||
data["ErrorMsg"] = fieldName + " must be valid alpha or numeric or dash(-_) or dot characters" | |||
case binding.BindingMinSizeError: | |||
data["ErrorMsg"] = f.Name(field.Name) + " must contain at least " + auth.GetMinMaxSize(field) + " characters" | |||
data["ErrorMsg"] = fieldName + " must contain at least " + auth.GetMinMaxSize(field) + " characters" | |||
case binding.BindingMaxSizeError: | |||
data["ErrorMsg"] = f.Name(field.Name) + " must contain at most " + auth.GetMinMaxSize(field) + " characters" | |||
data["ErrorMsg"] = fieldName + " must contain at most " + auth.GetMinMaxSize(field) + " characters" | |||
case binding.BindingEmailError: | |||
data["ErrorMsg"] = f.Name(field.Name) + " is not a valid e-mail address" | |||
data["ErrorMsg"] = fieldName + " is not a valid e-mail address" | |||
case binding.BindingUrlError: | |||
data["ErrorMsg"] = f.Name(field.Name) + " is not a valid URL" | |||
data["ErrorMsg"] = fieldName + " is not a valid URL" | |||
default: | |||
data["ErrorMsg"] = "Unknown error: " + err | |||
} |
@@ -39,29 +39,15 @@ func (f *RegisterForm) Name(field string) string { | |||
return names[field] | |||
} | |||
func (f *RegisterForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { | |||
if req.Method == "GET" || errors.Count() == 0 { | |||
return | |||
} | |||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | |||
data["HasError"] = true | |||
AssignForm(f, data) | |||
if len(errors.Overall) > 0 { | |||
for _, err := range errors.Overall { | |||
log.Error("RegisterForm.Validate: %v", err) | |||
} | |||
return | |||
} | |||
validate(errors, data, f) | |||
func (f *RegisterForm) Validate(errs *binding.BindingErrors, req *http.Request, ctx martini.Context) { | |||
data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | |||
validate(errs, data, f) | |||
} | |||
type LogInForm struct { | |||
UserName string `form:"username" binding:"Required;MaxSize(35)"` | |||
Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"` | |||
Remember string `form:"remember"` | |||
Remember bool `form:"remember"` | |||
} | |||
func (f *LogInForm) Name(field string) string { | |||
@@ -72,23 +58,9 @@ func (f *LogInForm) Name(field string) string { | |||
return names[field] | |||
} | |||
func (f *LogInForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { | |||
if req.Method == "GET" || errors.Count() == 0 { | |||
return | |||
} | |||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | |||
data["HasError"] = true | |||
AssignForm(f, data) | |||
if len(errors.Overall) > 0 { | |||
for _, err := range errors.Overall { | |||
log.Error("LogInForm.Validate: %v", err) | |||
} | |||
return | |||
} | |||
validate(errors, data, f) | |||
func (f *LogInForm) Validate(errs *binding.BindingErrors, req *http.Request, ctx martini.Context) { | |||
data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | |||
validate(errs, data, f) | |||
} | |||
func GetMinMaxSize(field reflect.StructField) string { | |||
@@ -100,9 +72,21 @@ func GetMinMaxSize(field reflect.StructField) string { | |||
return "" | |||
} | |||
func validate(errors *binding.BindingErrors, data base.TmplData, form Form) { | |||
typ := reflect.TypeOf(form) | |||
val := reflect.ValueOf(form) | |||
func validate(errs *binding.BindingErrors, data base.TmplData, f Form) { | |||
if errs.Count() == 0 { | |||
return | |||
} else if len(errs.Overall) > 0 { | |||
for _, err := range errs.Overall { | |||
log.Error("%s: %v", reflect.TypeOf(f), err) | |||
} | |||
return | |||
} | |||
data["HasError"] = true | |||
AssignForm(f, data) | |||
typ := reflect.TypeOf(f) | |||
val := reflect.ValueOf(f) | |||
if typ.Kind() == reflect.Ptr { | |||
typ = typ.Elem() | |||
@@ -118,23 +102,23 @@ func validate(errors *binding.BindingErrors, data base.TmplData, form Form) { | |||
continue | |||
} | |||
if err, ok := errors.Fields[field.Name]; ok { | |||
if err, ok := errs.Fields[field.Name]; ok { | |||
data["Err_"+field.Name] = true | |||
switch err { | |||
case binding.BindingRequireError: | |||
data["ErrorMsg"] = form.Name(field.Name) + " cannot be empty" | |||
data["ErrorMsg"] = f.Name(field.Name) + " cannot be empty" | |||
case binding.BindingAlphaDashError: | |||
data["ErrorMsg"] = form.Name(field.Name) + " must be valid alpha or numeric or dash(-_) characters" | |||
data["ErrorMsg"] = f.Name(field.Name) + " must be valid alpha or numeric or dash(-_) characters" | |||
case binding.BindingAlphaDashDotError: | |||
data["ErrorMsg"] = form.Name(field.Name) + " must be valid alpha or numeric or dash(-_) or dot characters" | |||
data["ErrorMsg"] = f.Name(field.Name) + " must be valid alpha or numeric or dash(-_) or dot characters" | |||
case binding.BindingMinSizeError: | |||
data["ErrorMsg"] = form.Name(field.Name) + " must contain at least " + GetMinMaxSize(field) + " characters" | |||
data["ErrorMsg"] = f.Name(field.Name) + " must contain at least " + GetMinMaxSize(field) + " characters" | |||
case binding.BindingMaxSizeError: | |||
data["ErrorMsg"] = form.Name(field.Name) + " must contain at most " + GetMinMaxSize(field) + " characters" | |||
data["ErrorMsg"] = f.Name(field.Name) + " must contain at most " + GetMinMaxSize(field) + " characters" | |||
case binding.BindingEmailError: | |||
data["ErrorMsg"] = form.Name(field.Name) + " is not a valid e-mail address" | |||
data["ErrorMsg"] = f.Name(field.Name) + " is not a valid e-mail address" | |||
case binding.BindingUrlError: | |||
data["ErrorMsg"] = form.Name(field.Name) + " is not a valid URL" | |||
data["ErrorMsg"] = f.Name(field.Name) + " is not a valid URL" | |||
default: | |||
data["ErrorMsg"] = "Unknown error: " + err | |||
} |
@@ -7,12 +7,10 @@ package auth | |||
import ( | |||
"net/http" | |||
"reflect" | |||
"strings" | |||
"github.com/go-martini/martini" | |||
"github.com/gogits/gogs/modules/base" | |||
"github.com/gogits/gogs/modules/log" | |||
"github.com/gogits/gogs/modules/middleware/binding" | |||
) | |||
@@ -31,24 +29,5 @@ func (f *AddSSHKeyForm) Name(field string) string { | |||
func (f *AddSSHKeyForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { | |||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | |||
AssignForm(f, data) | |||
if req.Method == "GET" || errors.Count() == 0 { | |||
if req.Method == "POST" && | |||
(len(f.KeyContent) < 100 || !strings.HasPrefix(f.KeyContent, "ssh-rsa")) { | |||
data["HasError"] = true | |||
data["ErrorMsg"] = "SSH key content is not valid" | |||
} | |||
return | |||
} | |||
data["HasError"] = true | |||
if len(errors.Overall) > 0 { | |||
for _, err := range errors.Overall { | |||
log.Error("AddSSHKeyForm.Validate: %v", err) | |||
} | |||
return | |||
} | |||
validate(errors, data, f) | |||
} |
@@ -78,7 +78,7 @@ type UpdateProfileForm struct { | |||
UserName string `form:"username" binding:"Required;AlphaDash;MaxSize(30)"` | |||
FullName string `form:"fullname" binding:"MaxSize(40)"` | |||
Email string `form:"email" binding:"Required;Email;MaxSize(50)"` | |||
Website string `form:"website" binding:"MaxSize(50)"` | |||
Website string `form:"website" binding:"Url;MaxSize(50)"` | |||
Location string `form:"location" binding:"MaxSize(50)"` | |||
Avatar string `form:"avatar" binding:"Required;Email;MaxSize(50)"` | |||
} | |||
@@ -94,22 +94,9 @@ func (f *UpdateProfileForm) Name(field string) string { | |||
return names[field] | |||
} | |||
func (f *UpdateProfileForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { | |||
if req.Method == "GET" || errors.Count() == 0 { | |||
return | |||
} | |||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | |||
data["HasError"] = true | |||
if len(errors.Overall) > 0 { | |||
for _, err := range errors.Overall { | |||
log.Error("UpdateProfileForm.Validate: %v", err) | |||
} | |||
return | |||
} | |||
validate(errors, data, f) | |||
func (f *UpdateProfileForm) Validate(errs *binding.BindingErrors, req *http.Request, ctx martini.Context) { | |||
data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | |||
validate(errs, data, f) | |||
} | |||
type UpdatePasswdForm struct { | |||
@@ -127,20 +114,7 @@ func (f *UpdatePasswdForm) Name(field string) string { | |||
return names[field] | |||
} | |||
func (f *UpdatePasswdForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { | |||
if req.Method == "GET" || errors.Count() == 0 { | |||
return | |||
} | |||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | |||
data["HasError"] = true | |||
if len(errors.Overall) > 0 { | |||
for _, err := range errors.Overall { | |||
log.Error("UpdatePasswdForm.Validate: %v", err) | |||
} | |||
return | |||
} | |||
validate(errors, data, f) | |||
func (f *UpdatePasswdForm) Validate(errs *binding.BindingErrors, req *http.Request, ctx martini.Context) { | |||
data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | |||
validate(errs, data, f) | |||
} |
@@ -93,6 +93,7 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{ | |||
"DiffLineTypeToStr": DiffLineTypeToStr, | |||
"ShortSha": ShortSha, | |||
"Oauth2Icon": Oauth2Icon, | |||
"Oauth2Name": Oauth2Name, | |||
} | |||
type Actioner interface { | |||
@@ -217,3 +218,19 @@ func Oauth2Icon(t int) string { | |||
} | |||
return "" | |||
} | |||
func Oauth2Name(t int) string { | |||
switch t { | |||
case 1: | |||
return "GitHub" | |||
case 2: | |||
return "Google" | |||
case 3: | |||
return "Twitter" | |||
case 4: | |||
return "Tencent QQ" | |||
case 5: | |||
return "Weibo" | |||
} | |||
return "" | |||
} |
@@ -1,6 +1,4 @@ | |||
var Gogits = { | |||
"PageIsSignup": false | |||
}; | |||
var Gogits = {}; | |||
(function ($) { | |||
// extend jQuery ajax, set csrf token value | |||
@@ -333,32 +331,6 @@ function initCore() { | |||
Gogits.renderCodeView(); | |||
} | |||
function initRegister() { | |||
$.getScript("/js/jquery.validate.min.js", function () { | |||
Gogits.validateForm("#login-card", { | |||
rules: { | |||
"username": { | |||
required: true, | |||
maxlength: 30 | |||
}, | |||
"email": { | |||
required: true, | |||
email: true | |||
}, | |||
"passwd": { | |||
required: true, | |||
minlength: 6, | |||
maxlength: 30 | |||
}, | |||
"re-passwd": { | |||
required: true, | |||
equalTo: "input[name=passwd]" | |||
} | |||
} | |||
}); | |||
}); | |||
} | |||
function initUserSetting() { | |||
// ssh confirmation | |||
$('#ssh-keys .delete').confirmation({ | |||
@@ -626,9 +598,6 @@ function initRepoSetting() { | |||
$(function () { | |||
initCore(); | |||
var body = $("#body"); | |||
if (body.data("page") == "user-signup") { | |||
initRegister(); | |||
} | |||
if (body.data("page") == "user") { | |||
initUserSetting(); | |||
} |
@@ -5,7 +5,7 @@ | |||
package user | |||
import ( | |||
"strconv" | |||
"strings" | |||
"github.com/gogits/gogs/models" | |||
"github.com/gogits/gogs/modules/auth" | |||
@@ -22,11 +22,10 @@ func Setting(ctx *middleware.Context) { | |||
ctx.HTML(200, "user/setting") | |||
} | |||
// Render user setting page (email, website modify) | |||
func SettingPost(ctx *middleware.Context, form auth.UpdateProfileForm) { | |||
ctx.Data["Title"] = "Setting" | |||
ctx.Data["PageIsUserSetting"] = true // For navbar arrow. | |||
ctx.Data["IsUserPageSetting"] = true // For setting nav highlight. | |||
ctx.Data["PageIsUserSetting"] = true | |||
ctx.Data["IsUserPageSetting"] = true | |||
user := ctx.User | |||
ctx.Data["Owner"] = user | |||
@@ -74,9 +73,22 @@ 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 | |||
} | |||
socials, err := models.GetOauthByUserId(ctx.User.Id) | |||
if err != nil { | |||
ctx.Handle(500, "user.SettingSocial", err) | |||
ctx.Handle(500, "user.SettingSocial(GetOauthByUserId)", err) | |||
return | |||
} | |||
@@ -108,9 +120,9 @@ func SettingPasswordPost(ctx *middleware.Context, form auth.UpdatePasswdForm) { | |||
} | |||
tmpUser.EncodePasswd() | |||
if user.Passwd != tmpUser.Passwd { | |||
ctx.Flash.Error("Old password is not correct") | |||
ctx.Flash.Error("Old password is not correct.") | |||
} else if form.NewPasswd != form.RetypePasswd { | |||
ctx.Flash.Error("New password and re-type password are not same") | |||
ctx.Flash.Error("New password and re-type password are not same.") | |||
} else { | |||
user.Passwd = form.NewPasswd | |||
user.Salt = models.GetUserSalt() | |||
@@ -128,10 +140,12 @@ func SettingPasswordPost(ctx *middleware.Context, form auth.UpdatePasswdForm) { | |||
func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) { | |||
ctx.Data["Title"] = "SSH Keys" | |||
ctx.Data["PageIsUserSetting"] = true | |||
ctx.Data["IsUserPageSettingSSH"] = true | |||
// Delete SSH key. | |||
if ctx.Req.Method == "DELETE" || ctx.Query("_method") == "DELETE" { | |||
id, err := strconv.ParseInt(ctx.Query("id"), 10, 64) | |||
id, err := base.StrTo(ctx.Query("id")).Int64() | |||
if err != nil { | |||
log.Error("ssh.DelPublicKey: %v", err) | |||
ctx.JSON(200, map[string]interface{}{ | |||
@@ -160,6 +174,14 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) { | |||
return | |||
} | |||
// List existed SSH keys. | |||
keys, err := models.ListPublicKey(ctx.User.Id) | |||
if err != nil { | |||
ctx.Handle(500, "ssh.ListPublicKey", err) | |||
return | |||
} | |||
ctx.Data["Keys"] = keys | |||
// Add new SSH key. | |||
if ctx.Req.Method == "POST" { | |||
if ctx.HasError() { | |||
@@ -167,6 +189,12 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) { | |||
return | |||
} | |||
if len(form.KeyContent) < 100 || !strings.HasPrefix(form.KeyContent, "ssh-rsa") { | |||
ctx.Flash.Error("SSH key content is not valid.") | |||
ctx.Redirect("/user/settings/ssh") | |||
return | |||
} | |||
k := &models.PublicKey{ | |||
OwnerId: ctx.User.Id, | |||
Name: form.KeyName, | |||
@@ -188,16 +216,6 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) { | |||
} | |||
} | |||
// List existed SSH keys. | |||
keys, err := models.ListPublicKey(ctx.User.Id) | |||
if err != nil { | |||
ctx.Handle(200, "ssh.ListPublicKey", err) | |||
return | |||
} | |||
ctx.Data["PageIsUserSetting"] = true | |||
ctx.Data["IsUserPageSettingSSH"] = true | |||
ctx.Data["Keys"] = keys | |||
ctx.HTML(200, "user/publickey") | |||
} | |||
@@ -49,14 +49,14 @@ func SignIn(ctx *middleware.Context) { | |||
user, err := models.GetUserByName(userName) | |||
if err != nil { | |||
ctx.HTML(500, "user/signin") | |||
ctx.Handle(500, "user.SignIn(GetUserByName)", err) | |||
return | |||
} | |||
secret := base.EncodeMd5(user.Rands + user.Passwd) | |||
value, _ := ctx.GetSecureCookie(secret, base.CookieRememberName) | |||
if value != user.Name { | |||
ctx.HTML(500, "user/signin") | |||
ctx.HTML(200, "user/signin") | |||
return | |||
} | |||
@@ -85,6 +85,7 @@ func SignInPost(ctx *middleware.Context, form auth.LogInForm) { | |||
} | |||
if ctx.HasError() { | |||
println("shit") | |||
ctx.HTML(200, "user/signin") | |||
return | |||
} | |||
@@ -112,7 +113,7 @@ func SignInPost(ctx *middleware.Context, form auth.LogInForm) { | |||
return | |||
} | |||
if form.Remember == "on" { | |||
if form.Remember { | |||
secret := base.EncodeMd5(user.Rands + user.Passwd) | |||
days := 86400 * base.LogInRememberDays | |||
ctx.SetCookie(base.CookieUserName, user.Name, days) | |||
@@ -208,16 +209,15 @@ func SignUpPost(ctx *middleware.Context, form auth.RegisterForm) { | |||
ctx.Data["IsSocialLogin"] = true | |||
} | |||
if ctx.HasError() { | |||
ctx.HTML(200, "user/signup") | |||
return | |||
} | |||
if form.Password != form.RetypePasswd { | |||
ctx.Data["HasError"] = true | |||
ctx.Data["Err_Password"] = true | |||
ctx.Data["Err_RetypePasswd"] = true | |||
ctx.Data["ErrorMsg"] = "Password and re-type password are not same" | |||
auth.AssignForm(form, ctx.Data) | |||
} | |||
if ctx.HasError() { | |||
ctx.HTML(200, "user/signup") | |||
ctx.RenderWithErr("Password and re-type password are not same", "user/signup", &form) | |||
return | |||
} | |||
@@ -415,7 +415,6 @@ func ResetPasswd(ctx *middleware.Context) { | |||
return | |||
} | |||
ctx.Data["Code"] = code | |||
ctx.Data["IsResetForm"] = true | |||
ctx.HTML(200, "user/reset_passwd") | |||
} |
@@ -10,6 +10,7 @@ | |||
<div class="panel-heading"> | |||
Collaborators | |||
</div> | |||
<div class="panel-body"> | |||
<ul id="repo-collab-list" class="list-unstyled"> | |||
{{range .Collaborators}} | |||
@@ -24,6 +25,7 @@ | |||
{{end}} | |||
</ul> | |||
</div> | |||
<div class="panel-footer"> | |||
<form action="{{.RepoLink}}/settings/collaboration" method="post" class="form-horizontal" id="repo-collab-form"> | |||
{{.CsrfTokenHtml}} |
@@ -2,12 +2,19 @@ | |||
{{template "base/navbar" .}} | |||
<div id="body" class="container" data-page="user"> | |||
{{template "user/setting_nav" .}} | |||
<div id="user-setting-container" class="col-md-9"> | |||
<h4>Delete Account</h4> | |||
<div id="repo-setting-container" class="col-md-10"> | |||
{{template "base/alert" .}} | |||
{{if not .Flash.ErrorMsg}}<p class="alert alert-danger">The operation will delete your account permanently. Sorry to see you go, but we know you'll back soon.</p>{{end}} | |||
<div class="form-group"> | |||
<button type="submit" class="btn btn-danger btn-lg" href="#delete-account-modal" id="delete-account" data-toggle="modal">Delete Account</button> | |||
<div class="panel panel-warning"> | |||
<div class="panel-heading"> | |||
Delete Account | |||
</div> | |||
<div class="panel-body"> | |||
{{if not .Flash.ErrorMsg}}<p class="alert alert-danger">The operation will delete your account permanently. Sorry to see you go, but we know you'll back soon.</p>{{end}} | |||
<div class="form-group"> | |||
<button type="submit" class="btn btn-danger btn-lg" href="#delete-account-modal" id="delete-account" data-toggle="modal">Delete Account</button> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
@@ -2,40 +2,47 @@ | |||
{{template "base/navbar" .}} | |||
<div id="body" class="container" data-page="user"> | |||
{{template "user/setting_nav" .}} | |||
<div id="user-setting-container" class="col-md-9"> | |||
<div id="setting-pwd"> | |||
<h4>Password</h4> | |||
<form class="form-horizontal" id="password-form" method="post" action="/user/settings/password"> | |||
{{.CsrfTokenHtml}} | |||
{{template "base/alert" .}} | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">Old Password<strong class="text-danger">*</strong></label> | |||
<div class="col-md-7"> | |||
<input type="password" name="oldpasswd" class="form-control" placeholder="Type your current password" required="required"> | |||
</div> | |||
</div> | |||
<div id="repo-setting-container" class="col-md-10"> | |||
{{template "base/alert" .}} | |||
<div class="panel panel-default"> | |||
<div class="panel-heading"> | |||
Password | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">New Password<strong class="text-danger">*</strong></label> | |||
<div class="col-md-7"> | |||
<input type="password" name="newpasswd" class="form-control" placeholder="Type your new password" required="required"> | |||
</div> | |||
</div> | |||
<div class="panel-body"> | |||
<div class="col-md-8"> | |||
<form class="form-horizontal" id="password-form" method="post" action="/user/settings/password"> | |||
{{.CsrfTokenHtml}} | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">Old Password<strong class="text-danger">*</strong></label> | |||
<div class="col-md-7"> | |||
<input type="password" name="oldpasswd" class="form-control" placeholder="Type your current password" required="required"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">Re-Type<strong class="text-danger">*</strong></label> | |||
<div class="col-md-7"> | |||
<input type="password" name="retypepasswd" class="form-control" placeholder="Re-type your new password" required="required"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">New Password<strong class="text-danger">*</strong></label> | |||
<div class="col-md-7"> | |||
<input type="password" name="newpasswd" class="form-control" placeholder="Type your new password" required="required"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">Re-Type<strong class="text-danger">*</strong></label> | |||
<div class="col-md-7"> | |||
<input type="password" name="retypepasswd" class="form-control" placeholder="Re-type your new password" required="required"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-offset-3 col-md-7"> | |||
<button type="submit" class="btn btn-primary">Change Password</button> | |||
<a href="/user/forget_password/">Forgot your password?</a> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-offset-3 col-md-7"> | |||
<button type="submit" class="btn btn-primary">Change Password</button> | |||
<a href="/user/forget_password/">Forgot your password?</a> | |||
</div> | |||
</div> | |||
</form> | |||
</div> | |||
</form> | |||
</div> | |||
</div> | |||
</div> | |||
</div> |
@@ -9,6 +9,7 @@ | |||
{{if .Owner.FullName}}<span id="user-full-name" class="center-block">{{.Owner.FullName}}</span>{{end}} | |||
<span id="user-name" class="center-block">{{.Owner.Name}}</span> | |||
</div> | |||
<div class="profile-info"> | |||
<ul class="list-group"> | |||
{{if .Owner.Location}} |
@@ -2,56 +2,63 @@ | |||
{{template "base/navbar" .}} | |||
<div id="body" class="container" data-page="user"> | |||
{{template "user/setting_nav" .}} | |||
<div id="user-setting-container" class="col-md-9"> | |||
<div id="ssh-keys"> | |||
<h4>SSH Keys</h4> | |||
{{template "base/alert" .}} | |||
<ul id="ssh-keys-list" class="list-group"> | |||
<li class="list-group-item"><span class="name">SSH Key's name</span></li> | |||
{{range .Keys}} | |||
<li class="list-group-item"> | |||
<span class="name">{{.Name}}</span> | |||
<span class="print">({{.Fingerprint}})</span> | |||
<button href="#" class="btn btn-danger delete pull-right" rel="{{.Id}}" data-del="{{.Id}}">Delete</button> | |||
</li> | |||
{{end}} | |||
<li class="list-group-item"> | |||
<a class="btn btn-link btn-primary" href="#ssh-add-modal" id="ssh-add" data-toggle="modal">Add SSH Key</a> | |||
</li> | |||
</ul> | |||
<div class="modal fade" id="ssh-add-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> | |||
<div class="modal-dialog"> | |||
<form class="modal-content form-horizontal" id="ssh-form" method="post" action="/user/settings/ssh/"> | |||
{{.CsrfTokenHtml}} | |||
<div class="modal-header"> | |||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> | |||
<h4 class="modal-title" id="myModalLabel">Add SSH Key</h4> | |||
</div> | |||
<div id="repo-setting-container" class="col-md-10"> | |||
{{template "base/alert" .}} | |||
<div class="panel panel-default"> | |||
<div class="panel-heading"> | |||
SSH Keys | |||
</div> | |||
<div class="modal-body"> | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">Key Name<strong class="text-danger">*</strong></label> | |||
<div class="col-md-8"> | |||
<input name="keyname" class="form-control" placeholder="Type your preferred name" required="required"> | |||
<div class="panel-body"> | |||
<div id="ssh-keys"> | |||
<ul id="ssh-keys-list" class="list-group"> | |||
<li class="list-group-item"><span class="name">SSH Key's name</span></li> | |||
{{range .Keys}} | |||
<li class="list-group-item"> | |||
<span class="name">{{.Name}}</span> | |||
<span class="print">({{.Fingerprint}})</span> | |||
<button href="#" class="btn btn-danger delete pull-right" rel="{{.Id}}" data-del="{{.Id}}">Delete</button> | |||
</li> | |||
{{end}} | |||
<li class="list-group-item"> | |||
<a class="btn btn-link btn-primary" href="#ssh-add-modal" id="ssh-add" data-toggle="modal">Add SSH Key</a> | |||
</li> | |||
</ul> | |||
<div class="modal fade" id="ssh-add-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> | |||
<div class="modal-dialog"> | |||
<form class="modal-content form-horizontal" id="ssh-form" method="post" action="/user/settings/ssh/"> | |||
{{.CsrfTokenHtml}} | |||
<div class="modal-header"> | |||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> | |||
<h4 class="modal-title" id="myModalLabel">Add SSH Key</h4> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">SSH Key<strong class="text-danger">*</strong></label> | |||
<div class="col-md-8"> | |||
<textarea name="key_content" class="form-control" placeholder="Type your key content" required="required"></textarea> | |||
<div class="modal-body"> | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">Key Name<strong class="text-danger">*</strong></label> | |||
<div class="col-md-8"> | |||
<input name="keyname" class="form-control" placeholder="Type your preferred name" required="required"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">SSH Key<strong class="text-danger">*</strong></label> | |||
<div class="col-md-8"> | |||
<textarea name="key_content" class="form-control" placeholder="Type your key content" required="required"></textarea> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="modal-footer"> | |||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> | |||
<button type="submit" class="btn btn-primary">Save SSH Key</button> | |||
<div class="modal-footer"> | |||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> | |||
<button type="submit" class="btn btn-primary">Save SSH Key</button> | |||
</div> | |||
</form> | |||
</div> | |||
</form> | |||
</div> | |||
<p><strong>Need help?</strong> Check out the guide to <a href="https://help.github.com/articles/generating-ssh-keys" target="_blank">generating SSH keys</a> or troubleshoot <a href="https://help.github.com/ssh-issues/" target="_blank">common SSH Problems</a></p> | |||
</div> | |||
</div> | |||
<p><strong>Need help?</strong> Check out the guide to <a href="https://help.github.com/articles/generating-ssh-keys" target="_blank">generating SSH keys</a> or troubleshoot <a href="https://help.github.com/ssh-issues/" target="_blank">common SSH Problems</a></p> | |||
</div> | |||
</div> | |||
</div> |
@@ -2,62 +2,67 @@ | |||
{{template "base/navbar" .}} | |||
<div id="body" class="container" data-page="user"> | |||
{{template "user/setting_nav" .}} | |||
<div id="user-setting-container" class="col-md-9"> | |||
<div id="setting-pwd"> | |||
<h4>Account Profile</h4> | |||
<form class="form-horizontal" id="password-form" method="post" action="/user/settings"> | |||
{{.CsrfTokenHtml}} | |||
{{template "base/alert" .}} | |||
<p>Your Email address is public and will be used for any account related notifications, and any web based operations made via the site.</p> | |||
<div class="form-group"> | |||
<label class="col-md-2 control-label" for="user-setting-username">Username<strong class="text-danger">*</strong></label> | |||
<div class="col-md-8"> | |||
<input name="username" class="form-control" placeholder="Type your user name" required="required" value="{{.SignedUser.Name}}" title="{{.SignedUser.Name}}" id="user-setting-username"> | |||
<p class="help-block hidden"><span class="text-danger">Caution : </span>your username is changing !</p> | |||
<div id="repo-setting-container" class="col-md-10"> | |||
{{template "base/alert" .}} | |||
<div class="panel panel-default"> | |||
<div class="panel-heading"> | |||
Account Profile | |||
</div> | |||
<div class="panel-body"> | |||
<form class="form-horizontal" id="password-form" method="post" action="/user/settings"> | |||
{{.CsrfTokenHtml}} | |||
<p>Your Email address is public and will be used for any account related notifications, and any web based operations made via the site.</p> | |||
<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}"> | |||
<label class="col-md-2 control-label" for="user-setting-username">Username<strong class="text-danger">*</strong></label> | |||
<div class="col-md-8"> | |||
<input name="username" class="form-control" placeholder="Type your user name" required="required" value="{{.SignedUser.Name}}" title="{{.SignedUser.Name}}" id="user-setting-username"> | |||
<p class="help-block hidden"><span class="text-danger">Caution : </span>your username is changing !</p> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-2 control-label">Full Name</label> | |||
<div class="col-md-8"> | |||
<input name="fullname" class="form-control" placeholder="Type your full name" value="{{.SignedUser.FullName}}"> | |||
<div class="form-group {{if .Err_FullName}}has-error has-feedback{{end}}"> | |||
<label class="col-md-2 control-label">Full Name</label> | |||
<div class="col-md-8"> | |||
<input name="fullname" class="form-control" placeholder="Type your full name" value="{{.SignedUser.FullName}}"> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-2 control-label">Email<strong class="text-danger">*</strong></label> | |||
<div class="col-md-8"> | |||
<input name="email" class="form-control" placeholder="Type your e-mail address" required="required" value="{{.SignedUser.Email}}"> | |||
<div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}"> | |||
<label class="col-md-2 control-label">Email<strong class="text-danger">*</strong></label> | |||
<div class="col-md-8"> | |||
<input name="email" class="form-control" placeholder="Type your e-mail address" required="required" value="{{.SignedUser.Email}}"> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-2 control-label">Website</label> | |||
<div class="col-md-8"> | |||
<input name="website" class="form-control" placeholder="Type your website URL" value="{{.SignedUser.Website}}"> | |||
<div class="form-group {{if .Err_Website}}has-error has-feedback{{end}}"> | |||
<label class="col-md-2 control-label">Website</label> | |||
<div class="col-md-8"> | |||
<input name="website" class="form-control" placeholder="Type your website URL" value="{{.SignedUser.Website}}"> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-2 control-label">Location</label> | |||
<div class="col-md-8"> | |||
<input name="location" class="form-control" placeholder="Type your current location" value="{{.SignedUser.Location}}"> | |||
<div class="form-group {{if .Err_Location}}has-error has-feedback{{end}}"> | |||
<label class="col-md-2 control-label">Location</label> | |||
<div class="col-md-8"> | |||
<input name="location" class="form-control" placeholder="Type your current location" value="{{.SignedUser.Location}}"> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="form-group {{if .Err_Avatar}}has-error has-feedback{{end}}"> | |||
<label class="col-md-2 control-label">Gravatar Email<strong class="text-danger">*</strong></label> | |||
<div class="col-md-8"> | |||
<input name="avatar" class="form-control" placeholder="Type your Gravatar e-mail address" required="required" value="{{.SignedUser.AvatarEmail}}"> | |||
<div class="form-group {{if .Err_Avatar}}has-error has-feedback{{end}}"> | |||
<label class="col-md-2 control-label">Gravatar Email<strong class="text-danger">*</strong></label> | |||
<div class="col-md-8"> | |||
<input name="avatar" class="form-control" placeholder="Type your Gravatar e-mail address" required="required" value="{{.SignedUser.AvatarEmail}}"> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-offset-2 col-md-8"> | |||
<button type="submit" class="btn btn-primary">Update Profile</button> | |||
<div class="form-group"> | |||
<div class="col-md-offset-2 col-md-8"> | |||
<button type="submit" class="btn btn-primary">Update Profile</button> | |||
</div> | |||
</div> | |||
</div> | |||
</form> | |||
</form> | |||
</div> | |||
</div> | |||
</div> | |||
</div> |
@@ -1,12 +1,11 @@ | |||
<div id="user-setting-nav" class="col-md-3"> | |||
<h4>Account Settings</h4> | |||
<div id="user-setting-nav" class="col-md-2 repo-setting-nav"> | |||
<ul class="list-group"> | |||
<li class="list-group-item{{if .IsUserPageSetting}} list-group-item-success{{end}}"><a href="/user/settings">Account Profile</a></li> | |||
<li class="list-group-item{{if .IsUserPageSettingSocial}} list-group-item-success{{end}}"><a href="/user/settings/social">Social Account</a></li> | |||
<li class="list-group-item{{if .IsUserPageSettingPasswd}} list-group-item-success{{end}}"><a href="/user/settings/password">Password</a></li> | |||
<!-- <li class="list-group-item{{if .IsUserPageSettingNotify}} list-group-item-success{{end}}"><a href="/user/setting/notification">Notifications</a></li> --> | |||
<li class="list-group-item{{if .IsUserPageSettingSSH}} list-group-item-success{{end}}"><a href="/user/settings/ssh/">SSH Keys</a></li> | |||
<!-- <li class="list-group-item{{if .IsUserPageSettingSecurity}} list-group-item-success{{end}}"><a href="/user/setting/security">Security</a></li> --> | |||
<li class="list-group-item{{if .IsUserPageSettingDelete}} list-group-item-success{{end}}"><a href="/user/delete">Delete Account</a></li> | |||
<li class="list-group-item{{if .IsUserPageSetting}} active{{end}}"><a href="/user/settings">Account Profile</a></li> | |||
<li class="list-group-item{{if .IsUserPageSettingSocial}} active{{end}}"><a href="/user/settings/social">Social Account</a></li> | |||
<li class="list-group-item{{if .IsUserPageSettingPasswd}} active{{end}}"><a href="/user/settings/password">Password</a></li> | |||
<!-- <li class="list-group-item{{if .IsUserPageSettingNotify}} active{{end}}"><a href="/user/setting/notification">Notifications</a></li> --> | |||
<li class="list-group-item{{if .IsUserPageSettingSSH}} active{{end}}"><a href="/user/settings/ssh/">SSH Keys</a></li> | |||
<!-- <li class="list-group-item{{if .IsUserPageSettingSecurity}} active{{end}}"><a href="/user/setting/security">Security</a></li> --> | |||
<li class="list-group-item{{if .IsUserPageSettingDelete}} active{{end}}"><a href="/user/delete">Delete Account</a></li> | |||
</ul> | |||
</div> |
@@ -21,21 +21,21 @@ | |||
<div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}"> | |||
<label class="col-md-4 control-label">Email: </label> | |||
<div class="col-md-6"> | |||
<input name="email" class="form-control" placeholder="Type your e-mail address" value="{{.email}}" required="required" title="Email is not valid"> | |||
<input name="email" class="form-control" placeholder="Type your e-mail address" value="{{.email}}" required="required"> | |||
</div> | |||
</div> | |||
<div class="form-group {{if .Err_Password}}has-error has-feedback{{end}}"> | |||
<label class="col-md-4 control-label">Password: </label> | |||
<div class="col-md-6"> | |||
<input name="passwd" type="password" class="form-control" placeholder="Type your password" required="required" title="Password must contain at least 6 characters"> | |||
<input name="passwd" type="password" class="form-control" placeholder="Type your password" required="required"> | |||
</div> | |||
</div> | |||
<div class="form-group {{if .Err_RetypePasswd}}has-error has-feedback{{end}}"> | |||
<label class="col-md-4 control-label">Re-type: </label> | |||
<div class="col-md-6"> | |||
<input name="retypepasswd" type="password" class="form-control" placeholder="Re-type your password" required="required" title="Re-type Password must be same to Password"> | |||
<input name="retypepasswd" type="password" class="form-control" placeholder="Re-type your password" required="required"> | |||
</div> | |||
</div> | |||
@@ -2,15 +2,35 @@ | |||
{{template "base/navbar" .}} | |||
<div id="body" class="container" data-page="user"> | |||
{{template "user/setting_nav" .}} | |||
<div id="user-setting-container" class="col-md-9"> | |||
<div id="ssh-keys"> | |||
<h4>Social Account</h4> | |||
{{template "base/alert" .}} | |||
<ul id="ssh-keys-list" class="list-group"> | |||
{{range .Socials}} | |||
<i class="fa {{Oauth2Icon .Type}} fa-3x"></i> | |||
{{end}} | |||
</ul> | |||
<div id="repo-setting-container" class="col-md-10"> | |||
{{template "base/alert" .}} | |||
<div class="panel panel-default"> | |||
<div class="panel-heading"> | |||
Social Account | |||
</div> | |||
<div class="panel-body"> | |||
<table class="table"> | |||
<thead> | |||
<tr> | |||
<th></th> | |||
<th>Name</th> | |||
<th>Identity</th> | |||
<th>Op.</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{{range .Socials}} | |||
<tr> | |||
<td><i class="fa {{Oauth2Icon .Type}} fa-2x"></i></td> | |||
<td>{{Oauth2Name .Type}}</td> | |||
<td>{{.Identity}}</td> | |||
<td><a href="/user/settings/social?remove={{.Id}}">Unbind</a></td> | |||
</tr> | |||
{{end}} | |||
</tbody> | |||
</table> | |||
</div> | |||
</div> | |||
</div> | |||
</div> |