@@ -11,14 +11,17 @@ github.com/codegangsta/cli = | |||
github.com/go-sql-driver/mysql = | |||
github.com/go-xorm/core = | |||
github.com/go-xorm/xorm = | |||
github.com/gogits/cache = | |||
github.com/gogits/gfm = | |||
github.com/gogits/git = | |||
github.com/gogits/oauth2 = | |||
github.com/juju2013/goldap = | |||
github.com/lib/pq = | |||
github.com/macaron-contrib/cache = | |||
github.com/macaron-contrib/captcha = | |||
github.com/macaron-contrib/csrf = | |||
github.com/macaron-contrib/i18n = | |||
github.com/macaron-contrib/session = | |||
github.com/macaron-contrib/toolbox = | |||
github.com/nfnt/resize = | |||
[res] | |||
@@ -232,6 +232,7 @@ func runWeb(*cli.Context) { | |||
m.Group("/:org", func(r *macaron.Router) { | |||
r.Get("/dashboard", user.Dashboard) | |||
r.Get("/members", org.Members) | |||
r.Get("/members/action/:action", org.MembersAction) | |||
r.Get("/teams", org.Teams) | |||
r.Get("/teams/:team", org.SingleTeam) | |||
@@ -248,6 +249,10 @@ func runWeb(*cli.Context) { | |||
r.Route("/delete", "GET,POST", org.SettingsDelete) | |||
}) | |||
}, middleware.OrgAssignment(true, true, true)) | |||
m.Group("/:org", func(r *macaron.Router) { | |||
r.Route("/invitations/new", "GET,POST", org.Invitation) | |||
}, middleware.OrgAssignment(true, false, false, true)) | |||
}, reqSignIn) | |||
// Repository routers. | |||
@@ -254,5 +254,5 @@ DRIVER = | |||
CONN = | |||
[i18n] | |||
LANGS = en-US,zh-CN | |||
NAMES = English,简体中文 | |||
LANGS = en-US,zh-CN,de-DE | |||
NAMES = English,简体中文,Deutsch |
@@ -250,6 +250,17 @@ settings.delete_account = Delete This Organization | |||
settings.delete_prompt = The operation will delete this organization permanently, and <strong>CANNOT</strong> be undo! | |||
settings.confirm_delete_account = Confirm Deletion | |||
members.public = Public | |||
members.public_helper = make private | |||
members.private = Private | |||
members.private_helper = make public | |||
members.owner = Owner | |||
members.member = Member | |||
members.conceal = Conceal | |||
members.remove = Remove | |||
members.invite_desc = Start typing a username to invite a new member to %s: | |||
members.invite_now = Invite Now | |||
[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> | |||
@@ -250,6 +250,17 @@ settings.delete_account = 删除当前组织 | |||
settings.delete_prompt = 删除操作会永久清除该组织的信息,并且 <strong>不可恢复</strong>! | |||
settings.confirm_delete_account = 确认删除组织 | |||
members.public = 公开成员 | |||
members.public_helper = 设为私有 | |||
members.private = 私有成员 | |||
members.private_helper = 设为公开 | |||
members.owner = 管理员 | |||
members.member = 普通成员 | |||
members.conceal = 隐藏身份 | |||
members.remove = 移除成员 | |||
members.invite_desc = 请输入被邀请到组织 %s 的用户名称: | |||
members.invite_now = 立即邀请 | |||
[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.0814 Alpha" | |||
const APP_VER = "0.4.7.0815 Alpha" | |||
func init() { | |||
runtime.GOMAXPROCS(runtime.NumCPU()) | |||
@@ -59,6 +59,16 @@ func (org *User) GetMembers() error { | |||
return nil | |||
} | |||
// AddMember adds new member to organization. | |||
func (org *User) AddMember(uid int64) error { | |||
return AddOrgUser(org.Id, uid) | |||
} | |||
// RemoveMember removes member from organization. | |||
func (org *User) RemoveMember(uid int64) error { | |||
return RemoveOrgUser(org.Id, uid) | |||
} | |||
// CreateOrganization creates record of a new organization. | |||
func CreateOrganization(org, owner *User) (*User, error) { | |||
if !IsLegalName(org.Name) { | |||
@@ -241,8 +251,7 @@ func NewTeam(t *Team) error { | |||
} | |||
// Update organization number of teams. | |||
rawSql := "UPDATE `user` SET num_teams = num_teams + 1 WHERE id = ?" | |||
if _, err = sess.Exec(rawSql, t.OrgId); err != nil { | |||
if _, err = sess.Exec("UPDATE `user` SET num_teams = num_teams + 1 WHERE id = ?", t.OrgId); err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
@@ -270,8 +279,8 @@ func UpdateTeam(t *Team) error { | |||
// OrgUser represents an organization-user relation. | |||
type OrgUser struct { | |||
Id int64 | |||
Uid int64 `xorm:"INDEX"` | |||
OrgId int64 `xorm:"INDEX"` | |||
Uid int64 `xorm:"INDEX UNIQUE(s)"` | |||
OrgId int64 `xorm:"INDEX UNIQUE(s)"` | |||
IsPublic bool | |||
IsOwner bool | |||
NumTeam int | |||
@@ -289,6 +298,12 @@ func IsOrganizationMember(orgId, uid int64) bool { | |||
return has | |||
} | |||
// IsPublicMembership returns ture if given user public his/her membership. | |||
func IsPublicMembership(orgId, uid int64) bool { | |||
has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).And("is_public=?", true).Get(new(OrgUser)) | |||
return has | |||
} | |||
// GetOrgUsersByUserId returns all organization-user relations by user ID. | |||
func GetOrgUsersByUserId(uid int64) ([]*OrgUser, error) { | |||
ous := make([]*OrgUser, 0, 10) | |||
@@ -303,6 +318,77 @@ func GetOrgUsersByOrgId(orgId int64) ([]*OrgUser, error) { | |||
return ous, err | |||
} | |||
// ChangeOrgUserStatus changes public or private membership status. | |||
func ChangeOrgUserStatus(orgId, uid int64, public bool) error { | |||
ou := new(OrgUser) | |||
has, err := x.Where("uid=?", uid).And("org_id=?", orgId).Get(ou) | |||
if err != nil { | |||
return err | |||
} else if !has { | |||
return nil | |||
} | |||
ou.IsPublic = public | |||
_, err = x.Id(ou.Id).AllCols().Update(ou) | |||
return err | |||
} | |||
// AddOrgUser adds new user to given organization. | |||
func AddOrgUser(orgId, uid int64) error { | |||
if IsOrganizationMember(orgId, uid) { | |||
return nil | |||
} | |||
ou := &OrgUser{ | |||
Uid: uid, | |||
OrgId: orgId, | |||
} | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
if err := sess.Begin(); err != nil { | |||
return err | |||
} | |||
if _, err := sess.Insert(ou); err != nil { | |||
sess.Rollback() | |||
return err | |||
} else if _, err = sess.Exec("UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgId); err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
return sess.Commit() | |||
} | |||
// RemoveOrgUser removes user from given organization. | |||
func RemoveOrgUser(orgId, uid int64) error { | |||
ou := new(OrgUser) | |||
has, err := x.Where("uid=?", uid).And("org_id=?", orgId).Get(ou) | |||
if err != nil { | |||
return err | |||
} else if !has { | |||
return nil | |||
} | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
if err := sess.Begin(); err != nil { | |||
return err | |||
} | |||
if _, err := sess.Id(ou.Id).Delete(ou); err != nil { | |||
sess.Rollback() | |||
return err | |||
} else if _, err = sess.Exec("UPDATE `user` SET num_members = num_members - 1 WHERE id = ?", orgId); err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
return sess.Commit() | |||
} | |||
// ___________ ____ ___ | |||
// \__ ___/___ _____ _____ | | \______ ___________ | |||
// | |_/ __ \\__ \ / \| | / ___// __ \_ __ \ | |||
@@ -128,6 +128,16 @@ func (u *User) IsOrganization() bool { | |||
return u.Type == ORGANIZATION | |||
} | |||
// IsUserOrgOwner returns true if user is in the owner team of given organization. | |||
func (u *User) IsUserOrgOwner(orgId int64) bool { | |||
return IsOrganizationOwner(orgId, u.Id) | |||
} | |||
// IsPublicMember returns true if user public his/her membership in give organization. | |||
func (u *User) IsPublicMember(orgId int64) bool { | |||
return IsPublicMembership(orgId, u.Id) | |||
} | |||
// GetOrganizationCount returns count of membership of organization of user. | |||
func (u *User) GetOrganizationCount() (int64, error) { | |||
return x.Where("uid=?", u.Id).Count(new(OrgUser)) | |||
@@ -68,7 +68,9 @@ type Context struct { | |||
Org struct { | |||
IsOwner bool | |||
IsMember bool | |||
IsAdminTeam bool // In owner team or team that has admin permission level. | |||
Organization *models.User | |||
OrgLink string | |||
} | |||
} | |||
@@ -181,7 +183,6 @@ func Contexter() macaron.Handler { | |||
Flash: f, | |||
Session: sess, | |||
} | |||
// Compute current URL for real-time change language. | |||
link := ctx.Req.RequestURI | |||
i := strings.Index(link, "?") | |||
@@ -13,8 +13,9 @@ import ( | |||
func OrgAssignment(redirect bool, args ...bool) macaron.Handler { | |||
return func(ctx *Context) { | |||
var ( | |||
requireMember bool | |||
requireOwner bool | |||
requireMember bool | |||
requireOwner bool | |||
requireAdminTeam bool | |||
) | |||
if len(args) >= 1 { | |||
requireMember = args[0] | |||
@@ -22,6 +23,9 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler { | |||
if len(args) >= 2 { | |||
requireOwner = args[1] | |||
} | |||
if len(args) >= 3 { | |||
requireAdminTeam = args[2] | |||
} | |||
orgName := ctx.Params(":org") | |||
@@ -43,13 +47,24 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler { | |||
ctx.Org.IsOwner = ctx.Org.Organization.IsOrgOwner(ctx.User.Id) | |||
if ctx.Org.IsOwner { | |||
ctx.Org.IsMember = true | |||
ctx.Org.IsAdminTeam = true | |||
} else { | |||
ctx.Org.IsMember = ctx.Org.Organization.IsOrgMember(ctx.User.Id) | |||
if ctx.Org.Organization.IsOrgMember(ctx.User.Id) { | |||
ctx.Org.IsMember = true | |||
// TODO: ctx.Org.IsAdminTeam | |||
} | |||
} | |||
} | |||
if (requireMember && !ctx.Org.IsMember) || (requireOwner && !ctx.Org.IsOwner) { | |||
if (requireMember && !ctx.Org.IsMember) || | |||
(requireOwner && !ctx.Org.IsOwner) || | |||
(requireAdminTeam && !ctx.Org.IsAdminTeam) { | |||
ctx.Handle(404, "OrgAssignment", err) | |||
return | |||
} | |||
ctx.Data["IsAdminTeam"] = ctx.Org.IsAdminTeam | |||
ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner | |||
ctx.Org.OrgLink = "/org/" + ctx.Org.Organization.Name | |||
ctx.Data["OrgLink"] = ctx.Org.OrgLink | |||
} | |||
} |
@@ -146,6 +146,7 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { | |||
} | |||
ctx.Repo.GitRepo = gitRepo | |||
ctx.Repo.RepoLink = "/" + u.Name + "/" + repo.Name | |||
ctx.Data["RepoLink"] = ctx.Repo.RepoLink | |||
tags, err := ctx.Repo.GitRepo.GetTags() | |||
if err != nil { | |||
@@ -157,7 +158,6 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { | |||
ctx.Data["Title"] = u.Name + "/" + repo.Name | |||
ctx.Data["Repository"] = repo | |||
ctx.Data["Owner"] = ctx.Repo.Repository.Owner | |||
ctx.Data["RepoLink"] = ctx.Repo.RepoLink | |||
ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner | |||
ctx.Data["IsRepositoryTrueOwner"] = ctx.Repo.IsTrueOwner | |||
@@ -851,6 +851,7 @@ The dashboard page style | |||
margin-left: 1em; | |||
} | |||
#dashboard-news .push-news .news-content li img { | |||
vertical-align: inherit; | |||
margin-bottom: -2px; | |||
} | |||
/* | |||
@@ -1691,6 +1692,30 @@ textarea#issue-add-content { | |||
#org-home-header { | |||
min-height: 100px; | |||
} | |||
#org-header { | |||
height: 48px; | |||
} | |||
#org-header .org-name { | |||
padding-left: 10px; | |||
font-size: 1.4em; | |||
height: 50px; | |||
line-height: 50px; | |||
margin-bottom: 0; | |||
} | |||
#org-header > div > .menu-line > li.right > a { | |||
font-size: 1.2em; | |||
color: #444444; | |||
} | |||
#org-header > div > .menu-line > li.right > a:hover { | |||
background-color: transparent; | |||
color: #d9453d; | |||
} | |||
#org-header > div > .menu-line > li.right > a .octicon { | |||
margin-right: 6px; | |||
} | |||
#org-header > div > .menu-line > li.right .current { | |||
border-bottom: 2px solid #D26911; | |||
} | |||
#org-home-header-info { | |||
padding-top: 10px; | |||
} | |||
@@ -1776,3 +1801,30 @@ textarea#issue-add-content { | |||
margin-bottom: 0; | |||
color: #777; | |||
} | |||
#org-member-toolbar { | |||
padding: 10px 0; | |||
} | |||
#org-member-list .org-member-item { | |||
height: 50px; | |||
line-height: 50px; | |||
border-top: 1px solid #eee; | |||
padding: 15px 20px; | |||
} | |||
#org-member-list .org-member-item .member-name { | |||
padding-left: 15px; | |||
} | |||
#org-member-list .org-member-item ul { | |||
list-style: none; | |||
} | |||
#org-member-list .org-member-item ul li { | |||
text-align: center; | |||
display: inline-block; | |||
} | |||
.invite-box { | |||
padding: 50px 0; | |||
min-height: 130px; | |||
text-align: center; | |||
} | |||
.invite-box input { | |||
width: 250px; | |||
} |
@@ -251,6 +251,7 @@ The dashboard page style | |||
.news-content li { | |||
margin-left: 1em; | |||
img { | |||
vertical-align: inherit; | |||
margin-bottom: -2px; | |||
} | |||
} | |||
@@ -9,6 +9,38 @@ | |||
#org-home-header { | |||
min-height: 100px; | |||
} | |||
#org-header { | |||
height: 48px; | |||
.org-name { | |||
padding-left: 10px; | |||
font-size: 1.4em; | |||
height: 50px; | |||
line-height: 50px; | |||
margin-bottom: 0; | |||
} | |||
> div { | |||
> .menu-line { | |||
> li { | |||
&.right { | |||
> a { | |||
font-size: 1.2em; | |||
color: @dashboardHeaderLinkColor; | |||
&:hover { | |||
background-color: transparent; | |||
color: @dashboardHeaderLinkHoverColor; | |||
} | |||
.octicon { | |||
margin-right: 6px; | |||
} | |||
} | |||
.current { | |||
border-bottom: 2px solid #D26911; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
#org-home-header-info { | |||
padding-top: 10px; | |||
h2 { | |||
@@ -93,4 +125,33 @@ | |||
margin-top: 0; | |||
margin-bottom: 0; | |||
color: #777; | |||
} | |||
#org-member-toolbar { | |||
padding: 10px 0; | |||
} | |||
#org-member-list { | |||
.org-member-item { | |||
height: 50px; | |||
line-height: 50px; | |||
border-top: 1px solid #eee; | |||
padding: 15px 20px; | |||
.member-name { | |||
padding-left: 15px; | |||
} | |||
ul { | |||
list-style: none; | |||
li { | |||
text-align: center; | |||
display: inline-block; | |||
} | |||
} | |||
} | |||
} | |||
.invite-box { | |||
padding: 50px 0; | |||
min-height: 130px; | |||
text-align: center; | |||
input { | |||
width: 250px; | |||
} | |||
} |
@@ -1,8 +1,8 @@ | |||
@import "var"; | |||
.label { | |||
padding: 2px 6px; | |||
color: @labelFontColor; | |||
padding: 2px 6px; | |||
color: @labelFontColor; | |||
} | |||
.label-red { | |||
@@ -30,7 +30,7 @@ | |||
} | |||
.label-radius{ | |||
border-radius: .2em; | |||
border-radius: .2em; | |||
} | |||
.label-link{ | |||
@@ -5,10 +5,101 @@ | |||
package org | |||
import ( | |||
"github.com/Unknwon/com" | |||
"github.com/gogits/gogs/models" | |||
"github.com/gogits/gogs/modules/base" | |||
"github.com/gogits/gogs/modules/log" | |||
"github.com/gogits/gogs/modules/middleware" | |||
) | |||
const ( | |||
MEMBERS base.TplName = "org/members" | |||
INVITE base.TplName = "org/invite" | |||
) | |||
func Members(ctx *middleware.Context) { | |||
ctx.Data["Title"] = "Organization " + ctx.Params(":org") + " Members" | |||
ctx.HTML(200, "org/members") | |||
org := ctx.Org.Organization | |||
ctx.Data["Title"] = org.Name | |||
ctx.Data["PageIsOrgMembers"] = true | |||
if err := org.GetMembers(); err != nil { | |||
ctx.Handle(500, "GetMembers", err) | |||
return | |||
} | |||
ctx.Data["Members"] = org.Members | |||
ctx.HTML(200, MEMBERS) | |||
} | |||
func MembersAction(ctx *middleware.Context) { | |||
uid := com.StrTo(ctx.Query("uid")).MustInt64() | |||
if uid == 0 { | |||
ctx.Redirect(ctx.Org.OrgLink + "/members") | |||
return | |||
} | |||
org := ctx.Org.Organization | |||
var err error | |||
switch ctx.Params(":action") { | |||
case "private": | |||
if ctx.User.Id != uid && !ctx.Org.IsOwner { | |||
ctx.Error(404) | |||
return | |||
} | |||
err = models.ChangeOrgUserStatus(org.Id, uid, false) | |||
case "public": | |||
if ctx.User.Id != uid { | |||
ctx.Error(404) | |||
return | |||
} | |||
err = models.ChangeOrgUserStatus(org.Id, uid, true) | |||
case "remove": | |||
if !ctx.Org.IsOwner { | |||
ctx.Error(404) | |||
return | |||
} | |||
err = org.RemoveMember(uid) | |||
} | |||
if err != nil { | |||
log.Error(4, "Action(%s): %v", ctx.Params(":action"), err) | |||
ctx.JSON(200, map[string]interface{}{ | |||
"ok": false, | |||
"err": err.Error(), | |||
}) | |||
return | |||
} | |||
ctx.Redirect(ctx.Org.OrgLink + "/members") | |||
} | |||
func Invitation(ctx *middleware.Context) { | |||
org := ctx.Org.Organization | |||
ctx.Data["Title"] = org.Name | |||
ctx.Data["PageIsOrgMembers"] = true | |||
if ctx.Req.Method == "POST" { | |||
uname := ctx.Query("uname") | |||
u, err := models.GetUserByName(uname) | |||
if err != nil { | |||
if err == models.ErrUserNotExist { | |||
ctx.Flash.Error(ctx.Tr("form.user_not_exist")) | |||
ctx.Redirect(ctx.Org.OrgLink + "/invitations/new") | |||
} else { | |||
ctx.Handle(500, " GetUserByName", err) | |||
} | |||
return | |||
} | |||
if err = org.AddMember(u.Id); err != nil { | |||
ctx.Handle(500, " AddMember", err) | |||
return | |||
} | |||
log.Trace("New member added(%s): %s", org.Name, u.Name) | |||
ctx.Redirect(ctx.Org.OrgLink + "/members") | |||
return | |||
} | |||
ctx.HTML(200, INVITE) | |||
} |
@@ -227,7 +227,7 @@ func Action(ctx *middleware.Context) { | |||
} | |||
if err != nil { | |||
log.Error(4, "repo.Action(%s): %v", ctx.Params(":action"), err) | |||
log.Error(4, "Action(%s): %v", ctx.Params(":action"), err) | |||
ctx.JSON(200, map[string]interface{}{ | |||
"ok": false, | |||
"err": err.Error(), | |||
@@ -1 +1 @@ | |||
0.4.7.0814 Alpha | |||
0.4.7.0815 Alpha |
@@ -0,0 +1,16 @@ | |||
<div class="org-header" id="org-header"> | |||
<div class="container"> | |||
<a class="text-black left" href="/org/{{.Org.LowerName}}"> | |||
<img class="avatar-48 left" src="{{.Org.AvatarLink}}?s=100"> | |||
<span class="org-name">{{.Org.FullName}}</span> | |||
</a> | |||
<ul class="menu menu-line container"> | |||
<li class="right"> | |||
<a {{if .PageIsOrgTeams}}class="current"{{end}} href="{{.OrgLink}}/teams"><i class="octicon octicon-jersey"></i> {{.i18n.Tr "org.teams"}} <span class="label label-gray label-radius">{{.Org.NumTeams}}</span></a> | |||
</li> | |||
<li class="right"> | |||
<a {{if .PageIsOrgMembers}}class="current"{{end}} href="{{.OrgLink}}/members"><i class="octicon octicon-organization"></i> {{.i18n.Tr "org.people"}} <span class="label label-gray label-radius">{{.Org.NumMembers}}</span></a> | |||
</li> | |||
</ul> | |||
</div> | |||
</div> |
@@ -17,7 +17,9 @@ | |||
<div class="container"> | |||
<div id="org-home-repo-list" class="left grid-2-3"> | |||
<div class="clear"> | |||
{{if .IsAdminTeam}} | |||
<a class="btn btn-green btn-large btn-link btn-radius right" href="/repo/create?org={{.Org.Id}}"><i class="octicon octicon-repo-create"></i> {{.i18n.Tr "new_repo"}}</a> | |||
{{end}} | |||
</div> | |||
<div id="org-repo-list"> | |||
{{range .Repos}} | |||
@@ -45,9 +47,11 @@ | |||
<a href="/{{.Name}}"><img src="{{.AvatarLink}}"></a> | |||
{{end}} | |||
</div> | |||
{{if .IsAdminTeam}} | |||
<div class="panel-footer"> | |||
<a class="btn btn-medium btn-blue btn-link btn-radius" href="">{{.i18n.Tr "org.invite_someone"}}</a> | |||
<a class="btn btn-medium btn-blue btn-link btn-radius" href="/org/{{.Org.LowerName}}/invitations/new">{{.i18n.Tr "org.invite_someone"}}</a> | |||
</div> | |||
{{end}} | |||
</div> | |||
<br> | |||
<div class="panel panel-radius"> | |||
@@ -65,9 +69,12 @@ | |||
{{end}} | |||
</ul> | |||
</div> | |||
{{if .IsOrganizationOwner}} | |||
<div class="panel-footer"> | |||
<a class="btn btn-medium btn-blue btn-link btn-radius" href="/org/{{$.Org.LowerName}}/teams/new">{{.i18n.Tr "org.create_new_team"}}</a> | |||
</div> | |||
{{end}} | |||
</div> | |||
</div> | |||
</div> | |||
@@ -0,0 +1,15 @@ | |||
{{template "ng/base/head" .}} | |||
{{template "ng/base/header" .}} | |||
{{template "org/header" .}} | |||
<div class="container"> | |||
<div class="invite-box"> | |||
{{template "ng/base/alert" .}} | |||
<h3>{{.i18n.Tr "org.members.invite_desc" .Org.FullName}}</h3> | |||
<form action="{{.OrgLink}}/invitations/new" method="post"> | |||
{{.CsrfTokenHtml}} | |||
<input class="ipt ipt-large ipt-radius" name="uname" required> | |||
<button class="btn btn-blue btn-large btn-radius">{{.i18n.Tr "org.members.invite_now"}}</button> | |||
</form> | |||
</div> | |||
</div> | |||
{{template "ng/base/footer" .}} |
@@ -1,56 +1,43 @@ | |||
{{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 class="active"><a href="#"><i class="fa fa-users"></i>Members | |||
<span class="label label-default">5</span></a> | |||
</li> | |||
<li><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> | |||
{{template "ng/base/head" .}} | |||
{{template "ng/base/header" .}} | |||
{{template "org/header" .}} | |||
<div class="container"> | |||
{{template "ng/base/alert" .}} | |||
<div class="clear" id="org-member-toolbar"> | |||
{{if .IsAdminTeam}} | |||
<a class="btn btn-green btn-large btn-link btn-radius right" href="{{.OrgLink}}/invitations/new"><i class="octicon octicon-repo-create"></i> {{.i18n.Tr "org.invite_someone"}}</a> | |||
{{end}} | |||
</div> | |||
<div id="org-member-list"> | |||
{{range .Members}} | |||
<div class="org-member-item"> | |||
<img class="avatar-48 left" src="{{.AvatarLink}}?s=100"> | |||
<a class="text-black" href="/{{.Name}}"><span class="member-name"><strong>{{.FullName}}</strong>({{.Name}})</span></a> | |||
<ul class="grid-6-12 right"> | |||
<li class="grid-1-3"> | |||
{{ $isPublic := .IsPublicMember $.Org.Id}} | |||
{{if $isPublic}} | |||
{{$.i18n.Tr "org.members.public"}} | |||
{{if eq $.SignedUser.Id .Id}}(<a href="{{$.OrgLink}}/members/action/private?uid={{.Id}}">{{$.i18n.Tr "org.members.public_helper"}}</a>){{end}} | |||
{{else}} | |||
{{$.i18n.Tr "org.members.private"}} | |||
{{if eq $.SignedUser.Id .Id}}(<a href="{{$.OrgLink}}/members/action/public?uid={{.Id}}">{{$.i18n.Tr "org.members.private_helper"}}</a>){{end}} | |||
{{end}} | |||
</li> | |||
<li class="grid-1-4">{{if .IsUserOrgOwner $.Org.Id}}<strong>{{$.i18n.Tr "org.members.owner"}}</strong>{{else}}{{$.i18n.Tr "org.members.member"}}{{end}}</li> | |||
{{if $.IsOrganizationOwner}} | |||
<li class="grid-1-6 right"> | |||
<a class="btn btn-red btn-link btn-radius" href="{{$.OrgLink}}/members/action/remove?uid={{.Id}}">{{$.i18n.Tr "org.members.remove"}}</a> | |||
</li> | |||
{{if $isPublic}} | |||
<li class="grid-1-6 right"> | |||
<a class="btn btn-blue btn-link btn-radius" href="{{$.OrgLink}}/members/action/private?uid={{.Id}}">{{$.i18n.Tr "org.members.conceal"}}</a> | |||
</li> | |||
{{end}} | |||
{{end}} | |||
</ul> | |||
</div> | |||
{{end}} | |||
</div> | |||
</div> | |||
<div id="body" class="container"> | |||
<div id="org"> | |||
<div id="org-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> | |||
<div class="role col-md-2 pull-right"> | |||
<strong>Member</strong> | |||
</div> | |||
<div class="status col-md-1 pull-right"> | |||
<strong>Public</strong> | |||
</div> | |||
</div> | |||
<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> | |||
<div class="role col-md-2 pull-right"> | |||
<strong><i class="fa fa-user"></i>Owner</strong> | |||
</div> | |||
<div class="status col-md-1 pull-right"> | |||
<i class="fa fa-lock"></i>Private | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} | |||
{{template "ng/base/footer" .}} |
@@ -1,130 +0,0 @@ | |||
{{template "base/head" .}} | |||
{{template "base/navbar" .}} | |||
<div id="body-nav"> | |||
<div class="container"> | |||
<div class="btn-group pull-left" id="dashboard-switch"> | |||
<button type="button" class="btn btn-default"> | |||
<img src="{{.Org.AvatarLink}}?s=28" alt="user-avatar" title="username"> | |||
{{.Org.Name}} | |||
</button> | |||
</div> | |||
<ul class="nav nav-pills pull-right"> | |||
<li><a href="/org/{{.Org.Name}}/dashboard/">News Feed</a></li> | |||
<li><a href="/org/{{.Org.Name}}/dashboard/issues">Issues</a></li> | |||
<li class="active"><a href="/org/{{.Org.Name}}/settings">Settings</a></li> | |||
<!-- <li><a href="/pulls">Pull Requests</a></li> | |||
<li><a href="/stars">Stars</a></li> --> | |||
</ul> | |||
</div> | |||
</div> | |||
<div id="body" class="container" data-page="org"> | |||
<div id="user-setting-nav" class="col-md-2 repo-setting-nav"> | |||
<ul class="list-group"> | |||
<li class="list-group-item active"><a href="#">Options</a></li> | |||
</ul> | |||
</div> | |||
<div id="repo-setting-container" class="col-md-10"> | |||
{{template "base/alert" .}} | |||
<div class="panel panel-default"> | |||
<div class="panel-heading"> | |||
Organization Options | |||
</div> | |||
<div class="panel-body"> | |||
<form action="/org/{{.Org.Name}}/settings" method="post" class="form-horizontal"> | |||
{{.CsrfTokenHtml}} | |||
<input type="hidden" name="action" value="update"> | |||
<div class="form-group{{if .Err_DisplayName}} has-error has-feedback{{end}}"> | |||
<label class="col-md-3 text-right" for="org-setting-name">Display Name</label> | |||
<div class="col-md-9"> | |||
<input class="form-control" name="display_name" value="{{.Org.FullName}}" title="" id="org-setting-name"/> | |||
</div> | |||
</div> | |||
<div class="form-group{{if .Err_Email}} has-error has-feedback{{end}}"> | |||
<label class="col-md-3 text-right" for="org-email">Email</label> | |||
<div class="col-md-9"> | |||
<input class="form-control" name="email" value="{{.Org.Email}}" title="" id="org-email" type="email"/> | |||
</div> | |||
</div> | |||
<div class="form-group{{if .Err_Description}} has-error has-feedback{{end}}"> | |||
<label class="col-md-3 text-right" for="org-desc">Description</label> | |||
<div class="col-md-9"> | |||
<textarea class="form-control" name="desc" id="org-desc" rows="3">{{.Org.Description}}</textarea> | |||
</div> | |||
</div> | |||
<div class="form-group{{if .Err_Website}} has-error has-feedback{{end}}"> | |||
<label class="col-md-3 text-right" for="org-site">Official Site</label> | |||
<div class="col-md-9"> | |||
<input type="url" class="form-control" name="site" value="{{.Org.Website}}" id="org-site"/> | |||
</div> | |||
</div> | |||
<div class="form-group{{if .Err_Location}} has-error has-feedback{{end}}"> | |||
<label class="col-md-3 text-right" for="org-location">Location</label> | |||
<div class="col-md-9"> | |||
<input class="form-control" name="location" value="{{.Org.Location}}" title="" id="org-location"/> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-9 col-md-offset-3"> | |||
<button class="btn btn-primary" type="submit">Save Options</button> | |||
</div> | |||
</div> | |||
</form> | |||
</div> | |||
</div> | |||
<div class="panel panel-warning"> | |||
<div class="panel-heading"> | |||
Danger Zone | |||
</div> | |||
<div class="panel-body"> | |||
<button type="button" class="btn btn-default pull-right" href="#delete-org-modal" data-toggle="modal"> | |||
Delete this organization | |||
</button> | |||
<dd> | |||
<dt>Delete this organization</dt> | |||
<dl>Once you delete this organization and all repositories in, there is no going back. Please be | |||
certain. | |||
</dl> | |||
</dd> | |||
<div class="modal fade" id="delete-org-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" | |||
aria-hidden="true"> | |||
<div class="modal-dialog"> | |||
<form action="/org/{{.Org.Name}}/settings/delete" method="post" | |||
class="modal-content"> | |||
{{.CsrfTokenHtml}} | |||
<div class="modal-header"> | |||
<button type="button" class="close" data-dismiss="modal" | |||
aria-hidden="true">×</button> | |||
<h4 class="modal-title" id="myModalLabel">Delete organization</h4> | |||
</div> | |||
<div class="modal-body"> | |||
<div class="form-group"> | |||
<label>Make sure your are owner of this organization. Please enter your password.<strong class="text-danger">*</strong></label> | |||
<input name="password" class="form-control" type="password" placeholder="Type your account password" required="required"> | |||
</div> | |||
</div> | |||
<div class="modal-footer"> | |||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> | |||
<button class="btn btn-danger btn-lg">I understand the consequences, delete this | |||
organization | |||
</button> | |||
</div> | |||
</form> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -30,7 +30,7 @@ | |||
{{ $push := ActionContent2Commits .}} | |||
{{ $repoLink := .GetRepoLink}} | |||
{{range $push.Commits}} | |||
<li><img src="{{AvatarLink .AuthorEmail}}?s=16"> <a href="/{{$repoLink}}/commit/{{.Sha1}}">{{ShortSha .Sha1}}</a> {{.Message}}</li> | |||
<li><img class="avatar-16" src="{{AvatarLink .AuthorEmail}}?s=16"> <a href="/{{$repoLink}}/commit/{{.Sha1}}">{{ShortSha .Sha1}}</a> {{.Message}}</li> | |||
{{end}} | |||
</ul> | |||
</div> | |||