| @@ -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> | |||