@@ -5,7 +5,7 @@ Gogs(Go Git Service) is a painless self-hosted Git Service written in Go. | |||
![Demo](http://gowalker.org/public/gogs_demo.gif) | |||
##### Current version: 0.4.7 Alpha | |||
##### Current version: 0.4.7 Beta | |||
### NOTICES | |||
@@ -33,6 +33,7 @@ The goal of this project is to make the easiest, fastest and most painless way t | |||
- SSH/HTTP(S) protocol support | |||
- SMTP/LDAP/reverse proxy authentication support | |||
- Register/delete/rename account | |||
- Create/manage/delete organization with team management | |||
- Create/migrate/mirror/delete/watch/rename/transfer public/private repository | |||
- Repository viewer/release/issue tracker/webhooks | |||
- Add/remove repository collaborators | |||
@@ -41,7 +42,7 @@ The goal of this project is to make the easiest, fastest and most painless way t | |||
- Administration panel | |||
- Supports MySQL, PostgreSQL and SQLite3 | |||
- Social account login(GitHub, Google, QQ, Weibo) | |||
- Multi-language support(English, Chinese, etc.) | |||
- Multi-language support(English, Chinese, Germany etc.) | |||
## System Requirements | |||
@@ -5,7 +5,7 @@ Gogs(Go Git Service) 是一个基于 Go 语言的自助 Git 服务。 | |||
![Demo](http://gowalker.org/public/gogs_demo.gif) | |||
##### 当前版本:0.4.7 Alpha | |||
##### 当前版本:0.4.7 Beta | |||
## 开发目的 | |||
@@ -23,16 +23,17 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自 | |||
- 活动时间线 | |||
- 支持 SSH/HTTP(S) 协议 | |||
- 支持 SMTP/LDAP/反向代理 用户认证 | |||
- 注册/删除/重命名用户 | |||
- 注册/删除/重命名 用户 | |||
- 创建/管理/删除 组织以及团队管理功能 | |||
- 创建/迁移/镜像/删除/关注/重命名/转移 公开/私有 仓库 | |||
- 仓库 浏览器/发布/缺陷管理/Web 钩子 | |||
- 仓库 浏览/发布/工单管理/Web 钩子 | |||
- 添加/删除 仓库协作者 | |||
- Gravatar 以及缓存支持 | |||
- 邮件服务(注册、Issue) | |||
- 管理员面板 | |||
- 支持 MySQL、PostgreSQL 以及 SQLite3 数据库 | |||
- 社交帐号登录(GitHub、Google、QQ、微博) | |||
- 多语言支持(英文、简体中文等等) | |||
- 多语言支持(英文、简体中文、德语等等) | |||
## 系统要求 | |||
@@ -200,7 +200,7 @@ func runWeb(*cli.Context) { | |||
r.Post("/new", bindIgnErr(auth.RegisterForm{}), admin.NewUserPost) | |||
r.Get("/:userid", admin.EditUser) | |||
r.Post("/:userid", bindIgnErr(auth.AdminEditUserForm{}), admin.EditUserPost) | |||
r.Get("/:userid/delete", admin.DeleteUser) | |||
r.Post("/:userid/delete", admin.DeleteUser) | |||
}, adminReq) | |||
m.Group("/admin/auths", func(r *macaron.Router) { |
@@ -340,6 +340,26 @@ dashboard.total_gc_pause = Total GC Pause | |||
dashboard.last_gc_pause = Last GC Pause | |||
dashboard.gc_times = GC Times | |||
users.user_manage_panel = User Manage Panel | |||
users.new_account = Create New Account | |||
users.name = Name | |||
users.email = E-mail | |||
users.activated = Activated | |||
users.admin = Admin | |||
users.repos = Repos | |||
users.created = Created | |||
users.edit = Edit | |||
users.auth_source = Auth Source | |||
users.local = Local | |||
users.auth_login_name = Auth Login Name | |||
users.update_profile_success = Account profile has been successfully updated. | |||
users.edit_account = Edit Account | |||
users.is_activated = This account is activated | |||
users.is_admin = This account has administrator permissions | |||
users.update_profile = Update Account Profile | |||
users.delete_account = Delete This Account | |||
users.still_own_repo = This account still have ownership of repository, you have to delete or transfer them first. | |||
[action] | |||
create_repo = created repository <a href="/%s">%s</a> | |||
commit_repo = pushed to <a href="/%s/src/%s">%s</a> at <a href="/%s">%s</a> |
@@ -340,6 +340,25 @@ dashboard.total_gc_pause = GC 暂停时间总量 | |||
dashboard.last_gc_pause = 上次 GC 暂停时间 | |||
dashboard.gc_times = GC 执行次数 | |||
users.user_manage_panel = 用户管理面板 | |||
users.new_account = 创建新的帐户 | |||
users.name = 用户名 | |||
users.email = 邮箱 | |||
users.activated = 已激活 | |||
users.admin = 管理员 | |||
users.repos = 仓库数 | |||
users.created = 创建时间 | |||
users.edit = 编辑 | |||
users.auth_source = 认证源 | |||
users.local = 本地 | |||
users.auth_login_name = 认证登录名 | |||
users.update_profile_success = 该用户信息已经更新成功! | |||
users.edit_account = 编辑用户信息 | |||
users.is_activated = 该用户已被激活 | |||
users.is_admin = 该用户具有管理员权限 | |||
users.update_profile = 更新用户信息 | |||
users.delete_account = 删除该用户 | |||
[action] | |||
create_repo = 创建了仓库 <a href="/%s">%s</a> | |||
commit_repo = 推送了 <a href="/%s/src/%s">%s</a> 分支的代码到 <a href="/%s">%s</a> |
@@ -17,7 +17,7 @@ import ( | |||
"github.com/gogits/gogs/modules/setting" | |||
) | |||
const APP_VER = "0.4.7.0827 Alpha" | |||
const APP_VER = "0.4.7.0829 Alpha" | |||
func init() { | |||
runtime.GOMAXPROCS(runtime.NumCPU()) |
@@ -13,7 +13,7 @@ import ( | |||
type AdminEditUserForm struct { | |||
Email string `form:"email" binding:"Required;Email;MaxSize(50)"` | |||
Passwd string `form:"passwd"` | |||
Passwd string `form:"password"` | |||
Website string `form:"website" binding:"MaxSize(50)"` | |||
Location string `form:"location" binding:"MaxSize(50)"` | |||
Avatar string `form:"avatar" binding:"Required;Email;MaxSize(50)"` |
@@ -249,9 +249,22 @@ img.avatar-100 { | |||
padding: 8px; | |||
vertical-align: top; | |||
} | |||
th { | |||
.table th { | |||
text-align: left; | |||
} | |||
.table-striped > tbody > tr:nth-child(odd) > td, | |||
.table-striped > tbody > tr:nth-child(odd) > th { | |||
background-color: #f9f9f9; | |||
} | |||
.pagination { | |||
display: inline-block; | |||
padding-left: 0; | |||
margin: 20px 0; | |||
border-radius: 4px; | |||
} | |||
.pagination li { | |||
display: inline; | |||
} | |||
.markdown { | |||
background-color: white; | |||
font-size: 16px; | |||
@@ -1925,11 +1938,14 @@ textarea#issue-add-content { | |||
height: 40px; | |||
line-height: 40px; | |||
} | |||
.admin-panel { | |||
padding: 10px 20px; | |||
} | |||
.admin-desc { | |||
padding: 10px 20px; | |||
} | |||
.admin-table { | |||
padding: 15px 20px 5px 20px; | |||
padding: 15px 0 5px 0; | |||
} | |||
.dl-horizontal dt { | |||
float: left; |
@@ -427,6 +427,31 @@ function initTeamRepositoriesList() { | |||
}); | |||
} | |||
function initAdmin() { | |||
// Create account. | |||
$('#login-type').on("change",function(){ | |||
var v = $(this).val(); | |||
if(v.indexOf("0-")+1){ | |||
$('.auth-name').toggleHide(); | |||
$(".pwd").find("input").attr("required","required") | |||
.end().toggleShow(); | |||
}else{ | |||
$(".pwd").find("input").removeAttr("required") | |||
.end().toggleHide(); | |||
$('.auth-name').toggleShow(); | |||
} | |||
}); | |||
// Delete account. | |||
$('#user-delete').click(function (e) { | |||
if (!confirm('This account is going to be deleted, do you want to continue?')) { | |||
e.preventDefault(); | |||
return true; | |||
} | |||
var $form = $('user-profile-form'); | |||
$form.attr('action', $form.data('delete-url')); | |||
}); | |||
} | |||
$(document).ready(function () { | |||
initCore(); | |||
if ($('#user-profile-setting').length) { | |||
@@ -453,6 +478,9 @@ $(document).ready(function () { | |||
if ($('#team-repositories-list').length) { | |||
initTeamRepositoriesList(); | |||
} | |||
if ($('#admin-setting').length) { | |||
initAdmin(); | |||
} | |||
Tabs('#dashboard-sidebar-menu'); | |||
@@ -1,8 +1,11 @@ | |||
.admin-panel { | |||
padding: 10px 20px; | |||
} | |||
.admin-desc { | |||
padding: 10px 20px; | |||
} | |||
.admin-table { | |||
padding: 15px 20px 5px 20px; | |||
padding: 15px 0 5px 0; | |||
} | |||
.dl-horizontal dt { | |||
float: left; |
@@ -254,18 +254,33 @@ clear: both; | |||
.table { | |||
width: 100%; | |||
max-width: 100%; | |||
> thead > tr > th, | |||
> tbody > tr > th, | |||
> tfoot > tr > th, | |||
> thead > tr > td, | |||
> tbody > tr > td, | |||
> tfoot > tr > td { | |||
border-top: 1px solid #e7eaec; | |||
line-height: 1.42857; | |||
padding: 8px; | |||
vertical-align: top; | |||
} | |||
th { | |||
text-align: left; | |||
} | |||
} | |||
.table-striped { | |||
>tbody>tr:nth-child(odd)>td, | |||
>tbody>tr:nth-child(odd)>th { | |||
background-color: #f9f9f9; | |||
} | |||
} | |||
.table > thead > tr > th, | |||
.table > tbody > tr > th, | |||
.table > tfoot > tr > th, | |||
.table > thead > tr > td, | |||
.table > tbody > tr > td, | |||
.table > tfoot > tr > td { | |||
border-top: 1px solid #e7eaec; | |||
line-height: 1.42857; | |||
padding: 8px; | |||
vertical-align: top; | |||
} | |||
th { | |||
text-align: left; | |||
.pagination { | |||
display: inline-block; | |||
padding-left: 0; | |||
margin: 20px 0; | |||
border-radius: 4px; | |||
li { | |||
display: inline; | |||
} | |||
} |
@@ -23,7 +23,6 @@ import ( | |||
const ( | |||
DASHBOARD base.TplName = "admin/dashboard" | |||
USERS base.TplName = "admin/users" | |||
REPOS base.TplName = "admin/repos" | |||
AUTHS base.TplName = "admin/auths" | |||
CONFIG base.TplName = "admin/config" | |||
@@ -157,35 +156,6 @@ func Dashboard(ctx *middleware.Context) { | |||
ctx.HTML(200, DASHBOARD) | |||
} | |||
func Users(ctx *middleware.Context) { | |||
ctx.Data["Title"] = "User Management" | |||
ctx.Data["PageIsUsers"] = true | |||
p := com.StrTo(ctx.Query("p")).MustInt() | |||
if p < 1 { | |||
p = 1 | |||
} | |||
pageNum := 50 | |||
count := models.CountUsers() | |||
curCount := int64((p-1)*pageNum + pageNum) | |||
if curCount > count { | |||
p = int(count) / pageNum | |||
} else if count > curCount { | |||
ctx.Data["NextPageNum"] = p + 1 | |||
} | |||
if p > 1 { | |||
ctx.Data["LastPageNum"] = p - 1 | |||
} | |||
var err error | |||
ctx.Data["Users"], err = models.GetUsers(pageNum, (p-1)*pageNum) | |||
if err != nil { | |||
ctx.Handle(500, "admin.Users(GetUsers)", err) | |||
return | |||
} | |||
ctx.HTML(200, USERS) | |||
} | |||
func Repositories(ctx *middleware.Context) { | |||
ctx.Data["Title"] = "Repository Management" | |||
ctx.Data["PageIsRepos"] = true |
@@ -1,193 +0,0 @@ | |||
// 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 admin | |||
import ( | |||
"strings" | |||
"github.com/Unknwon/com" | |||
"github.com/gogits/gogs/models" | |||
"github.com/gogits/gogs/modules/auth" | |||
"github.com/gogits/gogs/modules/base" | |||
"github.com/gogits/gogs/modules/log" | |||
"github.com/gogits/gogs/modules/middleware" | |||
) | |||
const ( | |||
USER_NEW base.TplName = "admin/user/new" | |||
USER_EDIT base.TplName = "admin/user/edit" | |||
) | |||
func NewUser(ctx *middleware.Context) { | |||
ctx.Data["Title"] = "New Account" | |||
ctx.Data["PageIsUsers"] = true | |||
auths, err := models.GetAuths() | |||
if err != nil { | |||
ctx.Handle(500, "admin.user.NewUser(GetAuths)", err) | |||
return | |||
} | |||
ctx.Data["LoginSources"] = auths | |||
ctx.HTML(200, USER_NEW) | |||
} | |||
func NewUserPost(ctx *middleware.Context, form auth.RegisterForm) { | |||
ctx.Data["Title"] = "New Account" | |||
ctx.Data["PageIsUsers"] = true | |||
if ctx.HasError() { | |||
ctx.HTML(200, USER_NEW) | |||
return | |||
} | |||
if form.Password != form.Retype { | |||
ctx.Data["Err_Password"] = true | |||
ctx.Data["Err_RetypePasswd"] = true | |||
ctx.RenderWithErr("Password and re-type password are not same.", "admin/users/new", &form) | |||
return | |||
} | |||
u := &models.User{ | |||
Name: form.UserName, | |||
Email: form.Email, | |||
Passwd: form.Password, | |||
IsActive: true, | |||
LoginType: models.PLAIN, | |||
} | |||
if len(form.LoginType) > 0 { | |||
// NOTE: need rewrite. | |||
fields := strings.Split(form.LoginType, "-") | |||
tp, _ := com.StrTo(fields[0]).Int() | |||
u.LoginType = models.LoginType(tp) | |||
u.LoginSource, _ = com.StrTo(fields[1]).Int64() | |||
u.LoginName = form.LoginName | |||
} | |||
if err := models.CreateUser(u); err != nil { | |||
switch err { | |||
case models.ErrUserAlreadyExist: | |||
ctx.RenderWithErr("Username has been already taken", USER_NEW, &form) | |||
case models.ErrEmailAlreadyUsed: | |||
ctx.RenderWithErr("E-mail address has been already used", USER_NEW, &form) | |||
case models.ErrUserNameIllegal: | |||
ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), USER_NEW, &form) | |||
default: | |||
ctx.Handle(500, "admin.user.NewUser(CreateUser)", err) | |||
} | |||
return | |||
} | |||
log.Trace("%s User created by admin(%s): %s", ctx.Req.RequestURI, | |||
ctx.User.LowerName, strings.ToLower(form.UserName)) | |||
ctx.Redirect("/admin/users") | |||
} | |||
func EditUser(ctx *middleware.Context) { | |||
ctx.Data["Title"] = "Edit Account" | |||
ctx.Data["PageIsUsers"] = true | |||
uid, err := com.StrTo(ctx.Params(":userid")).Int() | |||
if err != nil { | |||
ctx.Handle(404, "admin.user.EditUser", err) | |||
return | |||
} | |||
u, err := models.GetUserById(int64(uid)) | |||
if err != nil { | |||
ctx.Handle(500, "admin.user.EditUser(GetUserById)", err) | |||
return | |||
} | |||
ctx.Data["User"] = u | |||
auths, err := models.GetAuths() | |||
if err != nil { | |||
ctx.Handle(500, "admin.user.NewUser(GetAuths)", err) | |||
return | |||
} | |||
ctx.Data["LoginSources"] = auths | |||
ctx.HTML(200, USER_EDIT) | |||
} | |||
func EditUserPost(ctx *middleware.Context, form auth.AdminEditUserForm) { | |||
ctx.Data["Title"] = "Edit Account" | |||
ctx.Data["PageIsUsers"] = true | |||
uid, err := com.StrTo(ctx.Params(":userid")).Int() | |||
if err != nil { | |||
ctx.Handle(404, "admin.user.EditUserPost", err) | |||
return | |||
} | |||
u, err := models.GetUserById(int64(uid)) | |||
if err != nil { | |||
ctx.Handle(500, "admin.user.EditUserPost(GetUserById)", err) | |||
return | |||
} | |||
if ctx.HasError() { | |||
ctx.HTML(200, USER_EDIT) | |||
return | |||
} | |||
if form.Passwd != "" { | |||
u.Passwd = form.Passwd | |||
u.Rands = models.GetUserSalt() | |||
u.Salt = models.GetUserSalt() | |||
u.EncodePasswd() | |||
} | |||
u.Email = form.Email | |||
u.Website = form.Website | |||
u.Location = form.Location | |||
u.Avatar = base.EncodeMd5(form.Avatar) | |||
u.AvatarEmail = form.Avatar | |||
u.IsActive = form.Active | |||
u.IsAdmin = form.Admin | |||
if err := models.UpdateUser(u); err != nil { | |||
ctx.Handle(500, "admin.user.EditUserPost(UpdateUser)", err) | |||
return | |||
} | |||
log.Trace("%s User profile updated by admin(%s): %s", ctx.Req.RequestURI, | |||
ctx.User.LowerName, ctx.User.LowerName) | |||
ctx.Data["User"] = u | |||
ctx.Flash.Success("Account profile has been successfully updated.") | |||
ctx.Redirect("/admin/users/" + ctx.Params(":userid")) | |||
} | |||
func DeleteUser(ctx *middleware.Context) { | |||
ctx.Data["Title"] = "Delete Account" | |||
ctx.Data["PageIsUsers"] = true | |||
//log.Info("delete") | |||
uid, err := com.StrTo(ctx.Params(":userid")).Int() | |||
if err != nil { | |||
ctx.Handle(404, "admin.user.DeleteUser", err) | |||
return | |||
} | |||
u, err := models.GetUserById(int64(uid)) | |||
if err != nil { | |||
ctx.Handle(500, "admin.user.DeleteUser(GetUserById)", err) | |||
return | |||
} | |||
if err = models.DeleteUser(u); err != nil { | |||
switch err { | |||
case models.ErrUserOwnRepos: | |||
ctx.Flash.Error("This account still has ownership of repository, owner has to delete or transfer them first.") | |||
ctx.Redirect("/admin/users/" + ctx.Params(":userid")) | |||
default: | |||
ctx.Handle(500, "admin.user.DeleteUser", err) | |||
} | |||
return | |||
} | |||
log.Trace("%s User deleted by admin(%s): %s", ctx.Req.RequestURI, | |||
ctx.User.LowerName, ctx.User.LowerName) | |||
ctx.Redirect("/admin/users") | |||
} |
@@ -0,0 +1,224 @@ | |||
// 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 admin | |||
import ( | |||
"strings" | |||
"github.com/Unknwon/com" | |||
"github.com/gogits/gogs/models" | |||
"github.com/gogits/gogs/modules/auth" | |||
"github.com/gogits/gogs/modules/base" | |||
"github.com/gogits/gogs/modules/log" | |||
"github.com/gogits/gogs/modules/middleware" | |||
) | |||
const ( | |||
USERS base.TplName = "admin/user/list" | |||
USER_NEW base.TplName = "admin/user/new" | |||
USER_EDIT base.TplName = "admin/user/edit" | |||
) | |||
func Users(ctx *middleware.Context) { | |||
ctx.Data["Title"] = ctx.Tr("admin.users") | |||
ctx.Data["PageIsAdmin"] = true | |||
ctx.Data["PageIsAdminUsers"] = true | |||
p := com.StrTo(ctx.Query("p")).MustInt() | |||
if p < 1 { | |||
p = 1 | |||
} | |||
pageNum := 50 | |||
count := models.CountUsers() | |||
curCount := int64((p-1)*pageNum + pageNum) | |||
if curCount > count { | |||
p = int(count) / pageNum | |||
} else if count > curCount { | |||
ctx.Data["NextPageNum"] = p + 1 | |||
} | |||
if p > 1 { | |||
ctx.Data["LastPageNum"] = p - 1 | |||
} | |||
var err error | |||
ctx.Data["Users"], err = models.GetUsers(pageNum, (p-1)*pageNum) | |||
if err != nil { | |||
ctx.Handle(500, "admin.Users(GetUsers)", err) | |||
return | |||
} | |||
ctx.HTML(200, USERS) | |||
} | |||
func NewUser(ctx *middleware.Context) { | |||
ctx.Data["Title"] = ctx.Tr("admin.users.new_account") | |||
ctx.Data["PageIsAdmin"] = true | |||
ctx.Data["PageIsAdminUsers"] = true | |||
auths, err := models.GetAuths() | |||
if err != nil { | |||
ctx.Handle(500, "GetAuths", err) | |||
return | |||
} | |||
ctx.Data["LoginSources"] = auths | |||
ctx.HTML(200, USER_NEW) | |||
} | |||
func NewUserPost(ctx *middleware.Context, form auth.RegisterForm) { | |||
ctx.Data["Title"] = ctx.Tr("admin.users.new_account") | |||
ctx.Data["PageIsAdmin"] = true | |||
ctx.Data["PageIsAdminUsers"] = true | |||
if ctx.HasError() { | |||
ctx.HTML(200, USER_NEW) | |||
return | |||
} | |||
if form.Password != form.Retype { | |||
ctx.Data["Err_Password"] = true | |||
ctx.RenderWithErr(ctx.Tr("form.password_not_match"), USER_NEW, &form) | |||
return | |||
} | |||
u := &models.User{ | |||
Name: form.UserName, | |||
Email: form.Email, | |||
Passwd: form.Password, | |||
IsActive: true, | |||
LoginType: models.PLAIN, | |||
} | |||
if len(form.LoginType) > 0 { | |||
// NOTE: need rewrite. | |||
fields := strings.Split(form.LoginType, "-") | |||
tp, _ := com.StrTo(fields[0]).Int() | |||
u.LoginType = models.LoginType(tp) | |||
u.LoginSource, _ = com.StrTo(fields[1]).Int64() | |||
u.LoginName = form.LoginName | |||
} | |||
if err := models.CreateUser(u); err != nil { | |||
switch err { | |||
case models.ErrUserAlreadyExist: | |||
ctx.Data["Err_UserName"] = true | |||
ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), USER_NEW, &form) | |||
case models.ErrEmailAlreadyUsed: | |||
ctx.Data["Err_Email"] = true | |||
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), USER_NEW, &form) | |||
case models.ErrUserNameIllegal: | |||
ctx.Data["Err_UserName"] = true | |||
ctx.RenderWithErr(ctx.Tr("form.illegal_username"), USER_NEW, &form) | |||
default: | |||
ctx.Handle(500, "CreateUser", err) | |||
} | |||
return | |||
} | |||
log.Trace("Account created by admin(%s): %s", ctx.User.Name, u.Name) | |||
ctx.Redirect("/admin/users") | |||
} | |||
func EditUser(ctx *middleware.Context) { | |||
ctx.Data["Title"] = ctx.Tr("admin.users.edit_account") | |||
ctx.Data["PageIsAdmin"] = true | |||
ctx.Data["PageIsAdminUsers"] = true | |||
uid := com.StrTo(ctx.Params(":userid")).MustInt64() | |||
if uid == 0 { | |||
ctx.Handle(404, "EditUser", nil) | |||
return | |||
} | |||
u, err := models.GetUserById(uid) | |||
if err != nil { | |||
ctx.Handle(500, "GetUserById", err) | |||
return | |||
} | |||
ctx.Data["User"] = u | |||
auths, err := models.GetAuths() | |||
if err != nil { | |||
ctx.Handle(500, "GetAuths", err) | |||
return | |||
} | |||
ctx.Data["LoginSources"] = auths | |||
ctx.HTML(200, USER_EDIT) | |||
} | |||
func EditUserPost(ctx *middleware.Context, form auth.AdminEditUserForm) { | |||
ctx.Data["Title"] = ctx.Tr("admin.users.edit_account") | |||
ctx.Data["PageIsAdmin"] = true | |||
ctx.Data["PageIsAdminUsers"] = true | |||
uid := com.StrTo(ctx.Params(":userid")).MustInt64() | |||
if uid == 0 { | |||
ctx.Handle(404, "EditUser", nil) | |||
return | |||
} | |||
u, err := models.GetUserById(uid) | |||
if err != nil { | |||
ctx.Handle(500, "GetUserById", err) | |||
return | |||
} | |||
if ctx.HasError() { | |||
ctx.HTML(200, USER_EDIT) | |||
return | |||
} | |||
// NOTE: need password length check? | |||
if len(form.Passwd) > 0 { | |||
u.Passwd = form.Passwd | |||
u.Salt = models.GetUserSalt() | |||
u.EncodePasswd() | |||
} | |||
u.Email = form.Email | |||
u.Website = form.Website | |||
u.Location = form.Location | |||
if len(form.Avatar) == 0 { | |||
form.Avatar = form.Email | |||
} | |||
u.Avatar = base.EncodeMd5(form.Avatar) | |||
u.AvatarEmail = form.Avatar | |||
u.IsActive = form.Active | |||
u.IsAdmin = form.Admin | |||
if err := models.UpdateUser(u); err != nil { | |||
ctx.Handle(500, "UpdateUser", err) | |||
return | |||
} | |||
log.Trace("Account profile updated by admin(%s): %s", ctx.User.Name, u.Name) | |||
ctx.Data["User"] = u | |||
ctx.Flash.Success(ctx.Tr("admin.users.update_profile_success")) | |||
ctx.Redirect("/admin/users/" + ctx.Params(":userid")) | |||
} | |||
func DeleteUser(ctx *middleware.Context) { | |||
uid := com.StrTo(ctx.Params(":userid")).MustInt64() | |||
if uid == 0 { | |||
ctx.Handle(404, "DeleteUser", nil) | |||
return | |||
} | |||
u, err := models.GetUserById(uid) | |||
if err != nil { | |||
ctx.Handle(500, "GetUserById", err) | |||
return | |||
} | |||
if err = models.DeleteUser(u); err != nil { | |||
switch err { | |||
case models.ErrUserOwnRepos: | |||
ctx.Flash.Error(ctx.Tr("admin.users.still_own_repo")) | |||
ctx.Redirect("/admin/users/" + ctx.Params(":userid")) | |||
default: | |||
ctx.Handle(500, "DeleteUser", err) | |||
} | |||
return | |||
} | |||
log.Trace("Account deleted by admin(%s): %s", ctx.User.Name, u.Name) | |||
ctx.Redirect("/admin/users") | |||
} |
@@ -1 +1 @@ | |||
0.4.7.0827 Alpha | |||
0.4.7.0829 Alpha |
@@ -22,7 +22,7 @@ | |||
<div class="panel-header"> | |||
<strong>{{.i18n.Tr "admin.dashboard.operations"}}</strong> | |||
</div> | |||
<div class="panel-body"> | |||
<div class="panel-body admin-panel"> | |||
<div class="admin-table"> | |||
<table class="table"> | |||
<thead> |
@@ -1,110 +1,78 @@ | |||
{{template "base/head" .}} | |||
{{template "base/navbar" .}} | |||
<div id="body" class="container" data-page="admin"> | |||
{{template "admin/nav" .}} | |||
<div id="admin-container" class="col-md-9"> | |||
<div class="panel panel-default"> | |||
<div class="panel-heading"> | |||
Edit Account | |||
</div> | |||
<div class="panel-body"> | |||
<br/> | |||
<form action="/admin/users/{{.User.Id}}" method="post" class="form-horizontal"> | |||
{{.CsrfTokenHtml}} | |||
{{template "base/alert" .}} | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">Auth Source: </label> | |||
<div class="col-md-7"> | |||
<select name="logintype" class="form-control"> | |||
<option value="0-0">Local</option> | |||
{{$tp := .User.LoginSource}} | |||
{{range $key, $val := .LoginSources}} | |||
<option value="{{$val.Type}}-{{$val.Id}}"{{if eq $val.Id $tp}} selected{{end}}>{{$val.Name}}</option> | |||
{{end}} | |||
</select> | |||
</div> | |||
</div> | |||
<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="{{.User.LoginName}}"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">Username: </label> | |||
<label class="control-label">{{.User.Name}}</label> | |||
</div> | |||
<div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}"> | |||
<label class="col-md-3 control-label">Email<strong class="text-danger">*</strong></label> | |||
<div class="col-md-7"> | |||
<input name="email" class="form-control" placeholder="Type account's e-mail address" value="{{.User.Email}}" required="required"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">Password</label> | |||
<div class="col-md-7"> | |||
<input name="passwd" type="password" class="form-control" placeholder="Type account's new password or leave unfilled"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">Website</label> | |||
<div class="col-md-7"> | |||
<input name="website" class="form-control" placeholder="Type account's website URL" value="{{.User.Website}}"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">Location</label> | |||
<div class="col-md-7"> | |||
<input name="location" class="form-control" placeholder="Type account's current location" value="{{.User.Location}}"> | |||
</div> | |||
</div> | |||
<div class="form-group {{if .Err_Avatar}}has-error has-feedback{{end}}"> | |||
<label class="col-md-3 control-label">Gravatar Email<strong class="text-danger">*</strong></label> | |||
<div class="col-md-7"> | |||
<input name="avatar" class="form-control" placeholder="Type account's Gravatar e-mail address" required="required" value="{{.User.AvatarEmail}}"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-7 col-md-offset-3"> | |||
<div class="checkbox"> | |||
<label> | |||
{{template "ng/base/head" .}} | |||
{{template "ng/base/header" .}} | |||
<div id="admin-wrapper"> | |||
<div id="setting-wrapper" class="main-wrapper"> | |||
<div id="admin-setting" class="container clear"> | |||
{{template "admin/nav" .}} | |||
<div class="grid-4-5 left"> | |||
<div class="setting-content"> | |||
{{template "ng/base/alert" .}} | |||
<div id="setting-content"> | |||
<div class="panel panel-radius"> | |||
<div class="panel-header"> | |||
<strong>{{.i18n.Tr "admin.users.edit_account"}}</strong> | |||
</div> | |||
<form class="form form-align panel-body" id="user-profile-form" action="/admin/users/{{.User.Id}}" method="post" data-delete-url="/admin/users/{{.User.Id}}/delete"> | |||
{{.CsrfTokenHtml}} | |||
<div class="field"> | |||
<label class="req">{{.i18n.Tr "admin.users.auth_source"}}</label> | |||
<select id="login-type" name="logintype"> | |||
<option value="0-0">{{.i18n.Tr "admin.users.local"}}</option> | |||
{{$tp := .User.LoginSource}} | |||
{{range $key, $val := .LoginSources}} | |||
<option value="{{$val.Type}}-{{$val.Id}}"{{if eq $val.Id $tp}} selected{{end}}>{{$val.Name}}</option> | |||
{{end}} | |||
</select> | |||
</div> | |||
<div class="field"> | |||
<label for="loginname">{{.i18n.Tr "admin.users.auth_login_name"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_LoginName}}ipt-error{{end}}" id="loginname" name="loginname" value="{{.User.LoginName}}" /> | |||
</div> | |||
<div class="field"> | |||
<label>{{.i18n.Tr "username"}}</label> | |||
<label>{{.User.Name}}</label> | |||
</div> | |||
<div class="field"> | |||
<label class="req" for="email">{{.i18n.Tr "email"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_Email}}ipt-error{{end}}" id="email" name="email" type="email" value="{{.User.Email}}" required/> | |||
</div> | |||
<div class="field pwd"> | |||
<label for="password">{{.i18n.Tr "password"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_Password}}ipt-error{{end}}" id="password" name="password" type="password" /> | |||
</div> | |||
<div class="field"> | |||
<label for="website">{{.i18n.Tr "settings.website"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_Website}}ipt-error{{end}}" id="website" name="website" type="url" value="{{.User.Website}}" /> | |||
</div> | |||
<div class="field"> | |||
<label for="location">{{.i18n.Tr "settings.location"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_Location}}ipt-error{{end}}" id="location" name="location" type="text" value="{{.User.Location}}" /> | |||
</div> | |||
<div class="field"> | |||
<label for="gravatar-email">Gravatar {{.i18n.Tr "email"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_Avatar}}ipt-error{{end}}" id="gravatar-email" name="avatar" type="text" value="{{.User.AvatarEmail}}" /> | |||
</div> | |||
<div class="field"> | |||
<label></label> | |||
<input type="checkbox" name="active" {{if .User.IsActive}}checked{{end}}> | |||
<strong>This account is activated</strong> | |||
</label> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-7 col-md-offset-3"> | |||
<div class="checkbox"> | |||
<label> | |||
<strong>{{.i18n.Tr "admin.users.is_activated"}}</strong> | |||
<br> | |||
<label></label> | |||
<input type="checkbox" name="admin" {{if .User.IsAdmin}}checked{{end}}> | |||
<strong>This account has administrator permissions</strong> | |||
</label> | |||
</div> | |||
</div> | |||
</div> | |||
<hr/> | |||
<div class="form-group"> | |||
<div class="col-md-offset-3 col-md-6"> | |||
<button type="submit" class="btn btn-lg btn-primary btn-block">Update account profile</button> | |||
<a type="button" href="/admin/users/{{.User.Id}}/delete" class="btn btn-lg btn-danger btn-block">Delete this account</a> | |||
</div> | |||
</div> | |||
</form> | |||
</div> | |||
</div> | |||
<strong>{{.i18n.Tr "admin.users.is_admin"}}</strong> | |||
</div> | |||
<div class="field"> | |||
<label></label> | |||
<button class="btn btn-green btn-large btn-radius">{{.i18n.Tr "admin.users.update_profile"}}</button> | |||
| |||
<button class="btn btn-large btn-red btn-radius" id="user-delete">{{.i18n.Tr "admin.users.delete_account"}}</button> | |||
</div> | |||
</form> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} | |||
{{template "ng/base/footer" .}} |
@@ -0,0 +1,62 @@ | |||
{{template "ng/base/head" .}} | |||
{{template "ng/base/header" .}} | |||
<div id="admin-wrapper"> | |||
<div id="setting-wrapper" class="main-wrapper"> | |||
<div id="admin-setting" class="container clear"> | |||
{{template "admin/nav" .}} | |||
<div class="grid-4-5 left"> | |||
<div class="setting-content"> | |||
{{template "ng/base/alert" .}} | |||
<div id="setting-content"> | |||
<div class="panel panel-radius"> | |||
<div class="panel-header"> | |||
<strong>{{.i18n.Tr "admin.users.user_manage_panel"}}</strong> | |||
</div> | |||
<div class="panel-body admin-panel"> | |||
<a class="btn-blue btn-medium btn-link btn-radius" href="/admin/users/new">{{.i18n.Tr "admin.users.new_account"}}</a> | |||
<div class="admin-table"> | |||
<table class="table table-striped"> | |||
<thead> | |||
<tr> | |||
<th>Id</th> | |||
<th>{{.i18n.Tr "admin.users.name"}}</th> | |||
<th>{{.i18n.Tr "admin.users.email"}}</th> | |||
<th>{{.i18n.Tr "admin.users.activated"}}</th> | |||
<th>{{.i18n.Tr "admin.users.admin"}}</th> | |||
<th>{{.i18n.Tr "admin.users.repos"}}</th> | |||
<th>{{.i18n.Tr "admin.users.created"}}</th> | |||
<th>{{.i18n.Tr "admin.users.edit"}}</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{{range .Users}} | |||
<tr> | |||
<td>{{.Id}}</td> | |||
<td><a href="/user/{{.Name}}">{{.Name}}</a></td> | |||
<td>{{.Email}}</td> | |||
<td><i class="fa fa{{if .IsActive}}-check{{end}}-square-o"></i></td> | |||
<td><i class="fa fa{{if .IsAdmin}}-check{{end}}-square-o"></i></td> | |||
<td>{{.NumRepos}}</td> | |||
<td>{{DateFormat .Created "M d, Y"}}</td> | |||
<td><a href="/admin/users/{{.Id}}"><i class="fa fa-pencil-square-o"></i></a></td> | |||
</tr> | |||
{{end}} | |||
</tbody> | |||
</table> | |||
{{if or .LastPageNum .NextPageNum}} | |||
<ul class="pagination"> | |||
{{if .LastPageNum}}<li><a class="btn btn-medium btn-gray btn-radius" href="/admin/users?p={{.LastPageNum}}">« Prev.</a></li>{{end}} | |||
{{if .NextPageNum}}<li><a class="btn btn-medium btn-gray btn-radius" href="/admin/users?p={{.NextPageNum}}">» Next</a></li>{{end}} | |||
</ul> | |||
{{end}} | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "ng/base/footer" .}} |
@@ -1,94 +1,58 @@ | |||
{{template "base/head" .}} | |||
{{template "base/navbar" .}} | |||
<div id="body" class="container" data-page="admin"> | |||
{{template "admin/nav" .}} | |||
<div id="admin-container" class="col-md-9"> | |||
<div class="panel panel-default"> | |||
<div class="panel-heading"> | |||
New Account | |||
</div> | |||
<div class="panel-body"> | |||
<br/> | |||
<form action="/admin/users/new" method="post" class="form-horizontal"> | |||
{{.CsrfTokenHtml}} | |||
{{template "base/alert" .}} | |||
<div class="form-group"> | |||
<label class="col-md-3 control-label">Auth Source: </label> | |||
<div class="col-md-7"> | |||
<select name="logintype" class="form-control" id="login-type"> | |||
<option value="0-0">Local</option> | |||
{{range $key, $val := .LoginSources}} | |||
<option value="{{$val.Type}}-{{$val.Id}}">{{$val.Name}}</option> | |||
{{end}} | |||
</select> | |||
</div> | |||
</div> | |||
<div class="auth-name hidden"> | |||
<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}}"> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}"> | |||
<label class="col-md-3 control-label">Username: </label> | |||
<div class="col-md-7"> | |||
<input name="username" class="form-control" placeholder="Type account's username" value="{{.username}}" required="required"> | |||
</div> | |||
</div> | |||
<div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}"> | |||
<label class="col-md-3 control-label">Email: </label> | |||
<div class="col-md-7"> | |||
<input name="email" class="form-control" placeholder="Type account's e-mail address" value="{{.email}}" required="required" title="Email is not valid"> | |||
</div> | |||
</div> | |||
<div class="pwd"> | |||
<div class="form-group {{if .Err_Password}}has-error has-feedback{{end}}"> | |||
<label class="col-md-3 control-label">Password: </label> | |||
<div class="col-md-7"> | |||
<input name="passwd" type="password" class="form-control" placeholder="Type account's password" required="required" title="Password must contain at least 6 characters"> | |||
{{template "ng/base/head" .}} | |||
{{template "ng/base/header" .}} | |||
<div id="admin-wrapper"> | |||
<div id="setting-wrapper" class="main-wrapper"> | |||
<div id="admin-setting" class="container clear"> | |||
{{template "admin/nav" .}} | |||
<div class="grid-4-5 left"> | |||
<div class="setting-content"> | |||
{{template "ng/base/alert" .}} | |||
<div id="setting-content"> | |||
<div class="panel panel-radius"> | |||
<div class="panel-header"> | |||
<strong>{{.i18n.Tr "admin.users.new_account"}}</strong> | |||
</div> | |||
</div> | |||
<div class="form-group {{if .Err_RetypePasswd}}has-error has-feedback{{end}}"> | |||
<label class="col-md-3 control-label">Re-type: </label> | |||
<div class="col-md-7"> | |||
<input name="retypepasswd" type="password" class="form-control" placeholder="Re-type account's password" required="required" title="Re-type Password must be same to Password"> | |||
</div> | |||
</div> | |||
</div> | |||
<hr/> | |||
<div class="form-group"> | |||
<div class="col-md-offset-3 col-md-7"> | |||
<button type="submit" class="btn btn-lg btn-primary">Create new account</button> | |||
<form class="form form-align panel-body" id="repo-setting-form" action="/admin/users/new" method="post"> | |||
{{.CsrfTokenHtml}} | |||
<div class="field"> | |||
<label class="req">{{.i18n.Tr "admin.users.auth_source"}}</label> | |||
<select id="login-type" name="logintype"> | |||
<option value="0-0">{{.i18n.Tr "admin.users.local"}}</option> | |||
{{range $key, $val := .LoginSources}} | |||
<option value="{{$val.Type}}-{{$val.Id}}">{{$val.Name}}</option> | |||
{{end}} | |||
</select> | |||
</div> | |||
<div class="field auth-name hidden"> | |||
<label class="req" for="loginname">{{.i18n.Tr "admin.users.auth_login_name"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_LoginName}}ipt-error{{end}}" id="loginname" name="loginname" value="{{.loginname}}" /> | |||
</div> | |||
<div class="field"> | |||
<label class="req" for="username">{{.i18n.Tr "username"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_UserName}}ipt-error{{end}}" id="username" name="uname" type="text" value="{{.uname}}" required /> | |||
</div> | |||
<div class="field"> | |||
<label class="req" for="email">{{.i18n.Tr "email"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_Email}}ipt-error{{end}}" id="email" name="email" type="email" value="{{.email}}" required/> | |||
</div> | |||
<div class="field pwd"> | |||
<label class="req" for="password">{{.i18n.Tr "password"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_Password}}ipt-error{{end}}" id="password" name="password" type="password" value="{{.password}}" required/> | |||
</div> | |||
<div class="field"> | |||
<label class="req" for="re-type">{{.i18n.Tr "re_type"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_Password}}ipt-error{{end}}" id="re-type" name="retype" type="password" required/> | |||
</div> | |||
<div class="field"> | |||
<span class="form-label"></span> | |||
<button class="btn btn-blue btn-large btn-radius">{{.i18n.Tr "admin.users.new_account"}}</button> | |||
</div> | |||
</form> | |||
</div> | |||
</div> | |||
</form> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<script> | |||
$(function(){ | |||
$('#login-type').on("change",function(){ | |||
var v = $(this).val(); | |||
if(v.indexOf("0-")+1){ | |||
$('.auth-name').toggleHide(); | |||
$(".pwd").find("input").attr("required","required") | |||
.end().toggleShow(); | |||
}else{ | |||
$(".pwd").find("input").removeAttr("required") | |||
.end().toggleHide(); | |||
$('.auth-name').toggleShow(); | |||
} | |||
}); | |||
}); | |||
</script> | |||
{{template "base/footer" .}} | |||
{{template "ng/base/footer" .}} |
@@ -1,49 +0,0 @@ | |||
{{template "base/head" .}} | |||
{{template "base/navbar" .}} | |||
<div id="body" class="container" data-page="admin"> | |||
{{template "admin/nav" .}} | |||
<div id="admin-container" class="col-md-10"> | |||
<div class="panel panel-default"> | |||
<div class="panel-heading"> | |||
User Management | |||
</div> | |||
<div class="panel-body"> | |||
<a href="/admin/users/new" class="btn btn-primary">New Account</a> | |||
<table class="table table-striped"> | |||
<thead> | |||
<tr> | |||
<th>Id</th> | |||
<th>Name</th> | |||
<th>E-mail</th> | |||
<th>Actived</th> | |||
<th>Admin</th> | |||
<th>Repos</th> | |||
<th>Join</th> | |||
<th>Edit</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{{range .Users}} | |||
<tr> | |||
<td>{{.Id}}</td> | |||
<td><a href="/user/{{.Name}}">{{.Name}}</a></td> | |||
<td>{{.Email}}</td> | |||
<td><i class="fa fa{{if .IsActive}}-check{{end}}-square-o"></i></td> | |||
<td><i class="fa fa{{if .IsAdmin}}-check{{end}}-square-o"></i></td> | |||
<td>{{.NumRepos}}</td> | |||
<td>{{DateFormat .Created "M d, Y"}}</td> | |||
<td><a href="/admin/users/{{.Id}}"><i class="fa fa-pencil-square-o"></i></a></td> | |||
</tr> | |||
{{end}} | |||
</tbody> | |||
</table> | |||
<ul class="pagination"> | |||
{{if .LastPageNum}}<li><a href="/admin/users?p={{.LastPageNum}}">« Prev.</a></li>{{end}} | |||
{{if .NextPageNum}}<li><a href="/admin/users?p={{.NextPageNum}}">» Next</a></li>{{end}} | |||
</ul> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -7,19 +7,26 @@ | |||
<meta name="description" content="Gogs(Go Git Service) a painless self-hosted Git Service written in Go" /> | |||
<meta name="keywords" content="go, git, self-hosted, gogs"> | |||
<meta name="_csrf" content="{{.CsrfToken}}" /> | |||
{{if .Repository.IsGoget}}<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}">{{end}} | |||
<link rel="shortcut icon" href="/img/favicon.png" /> | |||
{{if CdnMode}} | |||
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css"> | |||
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script> | |||
{{else}} | |||
<link rel="stylesheet" href="/css/font-awesome.min.css"> | |||
<script src="/ng/js/lib/jquery-1.11.1.min.js"></script> | |||
{{end}} | |||
<!-- Stylesheet --> | |||
<link rel="stylesheet" href="/ng/css/ui.css"> | |||
<link rel="stylesheet" href="/ng/css/gogs.css"> | |||
<link rel="stylesheet" href="/css/font-awesome.min.css"> | |||
<link rel="stylesheet" href="/ng/fonts/octicons.css"> | |||
<!-- <link rel="stylesheet" href="http://cdn.bootcss.com/highlight.js/8.1/styles/github.min.css"> --> | |||
<link rel="stylesheet" href="/css/github.min.css"> | |||
<!-- JavaScript --> | |||
<script src="/ng/js/lib/jquery-1.11.1.min.js"></script> | |||
<script src="/ng/js/lib/tabs.js"></script> | |||
<script src="/ng/js/lib/lib.js"></script> | |||
<script src="/ng/js/gogs.js"></script> |
@@ -1,75 +0,0 @@ | |||
{{template "base/head" .}} | |||
{{template "base/navbar" .}} | |||
<div id="body-nav" class="org-nav org-nav-auto"> | |||
<div class="container clearfix"> | |||
<div id="org-nav-wrapper"> | |||
<ul class="nav nav-pills pull-right"> | |||
<li><a href="#"><i class="fa fa-users"></i>Members | |||
<span class="label label-default">5</span></a> | |||
</li> | |||
<li class="active"><a href="#"><i class="fa fa-tags"></i>Teams | |||
<span class="label label-default">2</span></a> | |||
</li> | |||
</ul> | |||
<img class="pull-left org-small-logo" src="https://avatars3.githubusercontent.com/u/6656686?s=140" alt="" width="60"/> | |||
<div id="org-nav-info"> | |||
<h2 class="org-name">Organization Name</h2> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div id="body" class="container"> | |||
<div id="org"> | |||
<form id="org-teams-edit" class="form-horizontal card"> | |||
<h3>Edit team</h3> | |||
<div class="form-group"> | |||
<label class="col-md-2 control-label">Team Name<strong class="text-danger">*</strong></label> | |||
<div class="col-md-8"> | |||
<input name="team" type="text" class="form-control" placeholder="Type your team name" value="" required="required"> | |||
<span class="help-block">You'll use this name to mention this team in conversations.</span> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-2 control-label">Description</label> | |||
<div class="col-md-8"> | |||
<input name="desc" type="text" class="form-control" placeholder="Type your team description (optional)" value=""> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-2 control-label">Permission</label> | |||
<div class="col-md-8"> | |||
<div class="radio"> | |||
<label> | |||
<input type="radio" name="permission" value="pull" checked=""> | |||
<strong>Read & Clone</strong> | |||
</label> | |||
<p>This team will be able to view and clone its repositories.</p> | |||
</div> | |||
<div class="radio"> | |||
<label> | |||
<input type="radio" name="permission" value="push"> | |||
<strong>Push, Read & Clone</strong> | |||
</label> | |||
<p>This team will be able to read its repositories, as well as push to them.</p> | |||
</div> | |||
<div class="radio"> | |||
<label> | |||
<input type="radio" name="permission" value="admin"> | |||
<strong>Collaboration, Push, Read & Clone</strong> | |||
</label> | |||
<p>This team will be able to push/pull to its repositories, as well as add other collaborators to them.</p> | |||
</div> | |||
</div> | |||
</div> | |||
<hr/> | |||
<div class="form-group"> | |||
<label class="col-md-2"> </label> | |||
<div class="col-md-8"> | |||
<button class="btn btn-primary">Edit this team</button> | |||
<button class="btn btn-danger pull-right" value="delete" name="delete">Delete this team</button> | |||
</div> | |||
</div> | |||
</form> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -1,106 +0,0 @@ | |||
{{template "base/head" .}} | |||
{{template "base/navbar" .}} | |||
<div id="body-nav" class="org-nav org-nav-auto"> | |||
<div class="container clearfix"> | |||
<div id="org-nav-wrapper"> | |||
<ul class="nav nav-pills pull-right"> | |||
<li><a href="#"><i class="fa fa-users"></i>Members | |||
<span class="label label-default">5</span></a> | |||
</li> | |||
<li class="active"><a href="#"><i class="fa fa-tags"></i>Teams | |||
<span class="label label-default">2</span></a> | |||
</li> | |||
</ul> | |||
<img class="pull-left org-small-logo" src="https://avatars3.githubusercontent.com/u/6656686?s=140" alt="" width="60"/> | |||
<div id="org-nav-info"> | |||
<h2 class="org-name">Organization Name</h2> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div id="body" class="container"> | |||
<div id="org"> | |||
<div id="org-team"> | |||
<div id="org-team-card" class="col-md-3"> | |||
<h3 class="title">Team name</h3> | |||
<p class="desc">team description</p> | |||
<hr/> | |||
<div class="meta"> | |||
<div class="col-md-6"> | |||
<a href="#"><span class="num"><strong>1</strong></span> | |||
<br/>Member</a> | |||
</div> | |||
<div class="col-md-6"> | |||
<a href="#"><span class="num"><strong>1</strong></span> | |||
<br/>Repository</a> | |||
</div> | |||
</div> | |||
<hr style="width: 100%"/> | |||
<div class="action"> | |||
<a href="#"> | |||
<button class="btn btn-danger">Leave</button> | |||
</a> | |||
<a href="#"> | |||
<button class="btn btn-success">Edit</button> | |||
</a> | |||
<a href="#"> | |||
<button class="btn btn-default">Setting</button> | |||
</a> | |||
</div> | |||
<hr/> | |||
<p>This team grants <strong>Push, Read & Clone</strong> access: members can read from and push to the team's repositories.</p> | |||
</div> | |||
<div id="org-team-content" class="col-md-9"> | |||
<div class="header"> | |||
<div class="header-tab col-md-4"> | |||
<div class="btn-group"> | |||
<a class="btn btn-primary" href="#">Members</a> | |||
<a class="btn btn-default" href="#">Repositories</a> | |||
</div> | |||
</div> | |||
<form id="org-team-add-user-form" action="url" class="col-md-4 pull-right open" method="post"> | |||
<input type="text" class="form-control" name="user" placeholder="add user to teams" id="org-team-add-user"/> | |||
<div class="dropdown-menu"> | |||
<ul class="list-unstyled"></ul> | |||
</div> | |||
<input type="hidden" name="team" value="team-id"/> | |||
</form> | |||
</div> | |||
<div class="content" id="org-team-members"> | |||
<div class="member"> | |||
<div class="avatar col-md-1"> | |||
<img src="https://avatars3.githubusercontent.com/u/2142787?s=140" alt=""> | |||
</div> | |||
<div class="name col-md-4"> | |||
<a href="#"><strong>fuxiaohei</strong><span class="nick">傅小黑</span></a> | |||
</div> | |||
<a class="remove btn btn-danger pull-right" href="#">Remove</a> | |||
</div> | |||
</div> | |||
<!---------------------- for ?member or ?repo ----------> | |||
<div class="header"> | |||
<div class="header-tab col-md-4"> | |||
<div class="btn-group"> | |||
<a class="btn btn-default" href="#">Members</a> | |||
<a class="btn btn-primary" href="#">Repositories</a> | |||
</div> | |||
</div> | |||
<form id="org-team-add-repo-form" action="url" class="col-md-4 pull-right open" method="post"> | |||
<input type="text" class="form-control" name="repo" placeholder="add repository to teams" id="org-team-add-repo"/> | |||
<div class="dropdown-menu"> | |||
<ul class="list-unstyled"></ul> | |||
</div> | |||
<input type="hidden" name="team" value="team-id"/> | |||
</form> | |||
</div> | |||
<div class="content" id="org-team-repos"> | |||
<div class="repo"> | |||
<a href="#" class="repo-name"><i class="fa fa-book"></i> repo-name</a> | |||
<a class="remove btn btn-danger pull-right" href="#">Remove</a> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -16,7 +16,7 @@ | |||
</div> | |||
<div class="field"> | |||
<label class="req" for="email">{{.i18n.Tr "email"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_Email}}ipt-error{{end}}" id="email" name="email" type="email" value="{{.email}}"required/> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_Email}}ipt-error{{end}}" id="email" name="email" type="email" value="{{.email}}" required /> | |||
</div> | |||
<div class="field"> | |||
<label class="req" for="password">{{.i18n.Tr "password"}}</label> |
@@ -39,7 +39,7 @@ | |||
<input class="ipt ipt-large ipt-radius {{if .Err_Avatar}}ipt-error{{end}}" id="gravatar-email" name="avatar" type="text" value="{{.SignedUser.AvatarEmail}}" /> | |||
</div> | |||
<div class="field"> | |||
<span class="form-label"></span> | |||
<label></label> | |||
<button class="btn btn-green btn-large btn-radius">{{.i18n.Tr "settings.update_profile"}}</button> | |||
</div> | |||
</form> |