diff options
author | Unknwon <joe2010xtmf@163.com> | 2014-08-16 16:21:17 +0800 |
---|---|---|
committer | Unknwon <joe2010xtmf@163.com> | 2014-08-16 16:21:17 +0800 |
commit | bba707de36d9bfbdb3001e3e89fac0c072aa14e9 (patch) | |
tree | 2b3ee7fc662baea04cecdf14b8a2758c108f83cc | |
parent | 78add502d71dca43bb59ab9ad91745c64d0bf74d (diff) | |
download | gitea-bba707de36d9bfbdb3001e3e89fac0c072aa14e9.tar.gz gitea-bba707de36d9bfbdb3001e3e89fac0c072aa14e9.zip |
Finish team list, create new team, join/leave team page
33 files changed, 533 insertions, 358 deletions
diff --git a/cmd/web.go b/cmd/web.go index 03e5e86066..064a0358f9 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -236,6 +236,7 @@ func runWeb(*cli.Context) { r.Get("/teams", org.Teams) r.Get("/teams/:team", org.SingleTeam) + r.Get("/teams/:team/action/:action", org.TeamsAction) }, middleware.OrgAssignment(true, true)) m.Group("/:org", func(r *macaron.Router) { @@ -248,11 +249,9 @@ func runWeb(*cli.Context) { r.Post("", bindIgnErr(auth.UpdateOrgSettingForm{}), org.SettingsPost) 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)) + }, middleware.OrgAssignment(true, true, true)) }, reqSignIn) // Repository routers. diff --git a/conf/locale/locale_en-US.ini b/conf/locale/locale_en-US.ini index d44dca081b..4e191dca40 100644 --- a/conf/locale/locale_en-US.ini +++ b/conf/locale/locale_en-US.ini @@ -79,6 +79,7 @@ Retype = Re-type password SSHTitle = SSH key name HttpsUrl = HTTPS URL PayloadUrl = Payload URL +TeamName = Team name require_error = ` cannot be empty.` alpha_dash_error = ` must be valid alpha or numeric or dash(-_) characters.` @@ -94,16 +95,19 @@ password_not_match = Password and re-type password are not same. username_been_taken = Username has been already taken. repo_name_been_taken = Repository name has been already taken. org_name_been_taken = Organization name has been already taken. +team_name_been_taken = Team name has been already taken. email_been_used = E-mail address has been already used. ssh_key_been_used = Public key name has been used. illegal_username = Your username contains illegal characters. illegal_repo_name = Repository name contains illegal characters. illegal_org_name = Organization name contains illegal characters. +illegal_team_name = Team name contains illegal characters. username_password_incorrect = Username or password is not correct. enterred_invalid_repo_name = Please make sure you entered repository name is correct. enterred_invalid_owner_name = Please make sure you entered owner name is correct. enterred_invalid_password = Please make sure you entered password is correct. user_not_exist = Given user does not exist. +last_org_owner = The user to remove is the last member in owner team. There must be another owner. invalid_ssh_key = Sorry, we're not able to verify your SSH key: %s auth_failed = Authentication failed: %v @@ -237,6 +241,11 @@ lower_members = members lower_repositories = repositories create_new_team = Create New Team org_desc = Description +team_name = Team Name +team_desc = Description +team_name_helper = You'll use this name to mention this team in conversations. +team_desc_helper = What is this team all about? +team_permission_desc = What permission level should this team have? settings = Settings settings.options = Options @@ -258,9 +267,19 @@ members.owner = Owner members.member = Member members.conceal = Conceal members.remove = Remove +members.leave = Leave members.invite_desc = Start typing a username to invite a new member to %s: members.invite_now = Invite Now +teams.join = Join +teams.leave = Leave +teams.read_access = Read Access +teams.read_access_helper = This team will be able to view and clone its repositories. +teams.write_access = Write Access +teams.write_access_helper = This team will be able to read its repositories, as well as push to them. +teams.admin_access = Admin Access +teams.admin_access_helper = This team will be able to push/pull to its repositories, as well as add other collaborators to them. + [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> diff --git a/conf/locale/locale_zh-CN.ini b/conf/locale/locale_zh-CN.ini index b84aca3d9e..e3607d8e6e 100644 --- a/conf/locale/locale_zh-CN.ini +++ b/conf/locale/locale_zh-CN.ini @@ -79,6 +79,7 @@ Retype = 确认密码 SSHTitle = SSH 密钥名称 HttpsUrl = HTTPS URL 地址 PayloadUrl = 推送地址 +TeamName = 团队名称 require_error = 不能为空。 alpha_dash_error = 必须为英文字母、阿拉伯数字或横线(-_)。 @@ -94,16 +95,19 @@ password_not_match = 密码与确认密码未匹配。 username_been_taken = 用户名已经被占用。 repo_name_been_taken = 仓库名称已经被占用。 org_name_been_taken = 组织名称已经被占用。 +team_name_been_taken = 团队名称已经被占用。 email_been_used = 邮箱地址已经被使用。 ssh_key_been_used = SSH 密钥已经被使用。 illegal_username = 您的用户名包含非法字符。 illegal_repo_name = 仓库名称包含非法字符。 illegal_org_name = 组织名称包含非法字符。 +illegal_team_name = 团队名称包含非法字符。 username_password_incorrect = 用户名或密码不正确。 enterred_invalid_repo_name = 请检查您输入的仓库名称是正确。 enterred_invalid_owner_name = 请检查您输入的新所有者用户名是否正确。 enterred_invalid_password = 请检查您输入的密码是否正确。 user_not_exist = 被操作的用户不存在! +last_org_owner = 被移除用户为最后一位管理员。请添加一位新的管理员再进行移除成员操作! invalid_ssh_key = 很抱歉,我们无法验证您输入的 SSH 密钥:%s auth_failed = 授权验证失败:%v @@ -237,6 +241,11 @@ lower_members = 名成员 lower_repositories = 个仓库 create_new_team = 创建新的团队 org_desc = 组织描述 +team_name = 团队名称 +team_desc = 团队描述 +team_name_helper = 您可以使用该名称来通知改组全体成员。 +team_desc_helper = 一句话描述这个团队是做什么的。 +team_permission_desc = 请选择该团队所具有的权限等级: settings = 组织设置 settings.options = 基本设置 @@ -258,9 +267,19 @@ members.owner = 管理员 members.member = 普通成员 members.conceal = 隐藏身份 members.remove = 移除成员 +members.leave = 离开组织 members.invite_desc = 请输入被邀请到组织 %s 的用户名称: members.invite_now = 立即邀请 +teams.join = 加入团队 +teams.leave = 离开团队 +teams.read_access = 读取权限 +teams.read_access_helper = 这个团队将拥有查看和克隆所属仓库的权限。 +teams.write_access = 写入权限 +teams.write_access_helper = 这个团队将拥有查看、克隆和推送所属仓库的权限。 +teams.admin_access = 管理权限 +teams.admin_access_helper = 这个团队将拥有查看、克隆、推送和添加其他组织成员到团队的权限。 + [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.0815 Alpha" +const APP_VER = "0.4.7.0816 Alpha" func init() { runtime.GOMAXPROCS(runtime.NumCPU()) diff --git a/models/org.go b/models/org.go index b40b313bc3..b810422280 100644 --- a/models/org.go +++ b/models/org.go @@ -15,6 +15,9 @@ import ( var ( ErrOrgNotExist = errors.New("Organization does not exist") ErrTeamAlreadyExist = errors.New("Team already exist") + ErrTeamNotExist = errors.New("Team does not exist") + ErrTeamNameIllegal = errors.New("Team name contains illegal characters") + ErrLastOrgOwner = errors.New("The user to remove is the last member in owner team") ) // IsOrgOwner returns true if given user is in the owner team. @@ -27,14 +30,14 @@ func (org *User) IsOrgMember(uid int64) bool { return IsOrganizationMember(org.Id, uid) } +// GetTeam returns named team of organization. +func (org *User) GetTeam(name string) (*Team, error) { + return GetTeam(org.Id, name) +} + // GetOwnerTeam returns owner team of organization. func (org *User) GetOwnerTeam() (*Team, error) { - t := &Team{ - OrgId: org.Id, - Name: OWNER_TEAM, - } - _, err := x.Get(t) - return t, err + return org.GetTeam(OWNER_TEAM) } // GetTeams returns all teams that belong to organization. @@ -179,96 +182,6 @@ func DeleteOrganization(org *User) (err error) { return sess.Commit() } -// ___________ -// \__ ___/___ _____ _____ -// | |_/ __ \\__ \ / \ -// | |\ ___/ / __ \| Y Y \ -// |____| \___ >____ /__|_| / -// \/ \/ \/ - -type AuthorizeType int - -const ( - ORG_READABLE AuthorizeType = iota + 1 - ORG_WRITABLE - ORG_ADMIN -) - -const OWNER_TEAM = "Owners" - -// Team represents a organization team. -type Team struct { - Id int64 - OrgId int64 `xorm:"INDEX"` - LowerName string - Name string - Description string - Authorize AuthorizeType - RepoIds string `xorm:"TEXT"` - NumMembers int - NumRepos int - Members []*User `xorm:"-"` -} - -// IsTeamMember returns true if given user is a member of team. -func (t *Team) IsMember(uid int64) bool { - return IsTeamMember(t.OrgId, t.Id, uid) -} - -// GetMembers returns all members in given team of organization. -func (t *Team) GetMembers() (err error) { - t.Members, err = GetTeamMembers(t.OrgId, t.Id) - return err -} - -// NewTeam creates a record of new team. -// It's caller's responsibility to assign organization ID. -func NewTeam(t *Team) error { - has, err := x.Id(t.OrgId).Get(new(User)) - if err != nil { - return err - } else if !has { - return ErrOrgNotExist - } - - t.LowerName = strings.ToLower(t.Name) - has, err = x.Where("org_id=?", t.OrgId).And("lower_name=?", t.LowerName).Get(new(Team)) - if err != nil { - return err - } else if has { - return ErrTeamAlreadyExist - } - - sess := x.NewSession() - defer sess.Close() - if err = sess.Begin(); err != nil { - return err - } - - if _, err = sess.Insert(t); err != nil { - sess.Rollback() - return err - } - - // Update organization number of teams. - if _, err = sess.Exec("UPDATE `user` SET num_teams = num_teams + 1 WHERE id = ?", t.OrgId); err != nil { - sess.Rollback() - return err - } - return sess.Commit() -} - -// UpdateTeam updates information of team. -func UpdateTeam(t *Team) error { - if len(t.Description) > 255 { - t.Description = t.Description[:255] - } - - t.LowerName = strings.ToLower(t.Name) - _, err := x.Id(t.Id).AllCols().Update(t) - return err -} - // ________ ____ ___ // \_____ \_______ ____ | | \______ ___________ // / | \_ __ \/ ___\| | / ___// __ \_ __ \ @@ -372,6 +285,21 @@ func RemoveOrgUser(orgId, uid int64) error { return nil } + // Check if the user to delete is the last member in owner team. + if IsOrganizationOwner(orgId, uid) { + org, err := GetUserById(orgId) + if err != nil { + return err + } + t, err := org.GetOwnerTeam() + if err != nil { + return err + } + if t.NumMembers == 1 { + return ErrLastOrgOwner + } + } + sess := x.NewSession() defer sess.Close() if err := sess.Begin(); err != nil { @@ -389,6 +317,127 @@ func RemoveOrgUser(orgId, uid int64) error { return sess.Commit() } +// ___________ +// \__ ___/___ _____ _____ +// | |_/ __ \\__ \ / \ +// | |\ ___/ / __ \| Y Y \ +// |____| \___ >____ /__|_| / +// \/ \/ \/ + +type AuthorizeType int + +const ( + ORG_READABLE AuthorizeType = iota + 1 + ORG_WRITABLE + ORG_ADMIN +) + +const OWNER_TEAM = "Owners" + +// Team represents a organization team. +type Team struct { + Id int64 + OrgId int64 `xorm:"INDEX"` + LowerName string + Name string + Description string + Authorize AuthorizeType + RepoIds string `xorm:"TEXT"` + NumMembers int + NumRepos int + Members []*User `xorm:"-"` +} + +// IsTeamMember returns true if given user is a member of team. +func (t *Team) IsMember(uid int64) bool { + return IsTeamMember(t.OrgId, t.Id, uid) +} + +// GetMembers returns all members in given team of organization. +func (t *Team) GetMembers() (err error) { + t.Members, err = GetTeamMembers(t.OrgId, t.Id) + return err +} + +// NewTeam creates a record of new team. +// It's caller's responsibility to assign organization ID. +func NewTeam(t *Team) error { + if !IsLegalName(t.Name) { + return ErrTeamNameIllegal + } + + has, err := x.Id(t.OrgId).Get(new(User)) + if err != nil { + return err + } else if !has { + return ErrOrgNotExist + } + + t.LowerName = strings.ToLower(t.Name) + has, err = x.Where("org_id=?", t.OrgId).And("lower_name=?", t.LowerName).Get(new(Team)) + if err != nil { + return err + } else if has { + return ErrTeamAlreadyExist + } + + sess := x.NewSession() + defer sess.Close() + if err = sess.Begin(); err != nil { + return err + } + + if _, err = sess.Insert(t); err != nil { + sess.Rollback() + return err + } + + // Update organization number of teams. + if _, err = sess.Exec("UPDATE `user` SET num_teams = num_teams + 1 WHERE id = ?", t.OrgId); err != nil { + sess.Rollback() + return err + } + return sess.Commit() +} + +// GetTeam returns team by given team name and organization. +func GetTeam(orgId int64, name string) (*Team, error) { + t := &Team{ + OrgId: orgId, + LowerName: strings.ToLower(name), + } + has, err := x.Get(t) + if err != nil { + return nil, err + } else if !has { + return nil, ErrTeamNotExist + } + return t, nil +} + +// GetTeamById returns team by given ID. +func GetTeamById(teamId int64) (*Team, error) { + t := new(Team) + has, err := x.Id(teamId).Get(t) + if err != nil { + return nil, err + } else if !has { + return nil, ErrTeamNotExist + } + return t, nil +} + +// UpdateTeam updates information of team. +func UpdateTeam(t *Team) error { + if len(t.Description) > 255 { + t.Description = t.Description[:255] + } + + t.LowerName = strings.ToLower(t.Name) + _, err := x.Id(t.Id).AllCols().Update(t) + return err +} + // ___________ ____ ___ // \__ ___/___ _____ _____ | | \______ ___________ // | |_/ __ \\__ \ / \| | / ___// __ \_ __ \ @@ -427,3 +476,68 @@ func GetTeamMembers(orgId, teamId int64) ([]*User, error) { } return us, nil } + +// AddTeamMember adds new member to given team of given organization. +func AddTeamMember(orgId, teamId, uid int64) error { + if !IsOrganizationMember(orgId, uid) || IsTeamMember(orgId, teamId, uid) { + return nil + } + + // We can use raw SQL here but we also want to vertify there is a such team. + t, err := GetTeamById(teamId) + if err != nil { + return err + } + t.NumMembers++ + + sess := x.NewSession() + defer sess.Close() + if err = sess.Begin(); err != nil { + return err + } + + tu := &TeamUser{ + Uid: uid, + OrgId: orgId, + TeamId: teamId, + } + + if _, err = sess.Insert(tu); err != nil { + sess.Rollback() + return err + } else if _, err = sess.Id(t.Id).Update(t); err != nil { + sess.Rollback() + return err + } + + return sess.Commit() +} + +// RemoveMember removes member from given team of given organization. +func RemoveMember(orgId, teamId, uid int64) error { + if !IsTeamMember(orgId, teamId, uid) { + return nil + } + + sess := x.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return err + } + + tu := &TeamUser{ + Uid: uid, + OrgId: orgId, + TeamId: teamId, + } + + if _, err := sess.Delete(tu); err != nil { + sess.Rollback() + return err + } else if _, err = sess.Exec("UPDATE `team` SET num_members = num_members - 1 WHERE id = ?", teamId); err != nil { + sess.Rollback() + return err + } + + return sess.Commit() +} diff --git a/modules/auth/org.go b/modules/auth/org.go index 9598e6f834..6183e8c826 100644 --- a/modules/auth/org.go +++ b/modules/auth/org.go @@ -49,7 +49,7 @@ func (f *UpdateOrgSettingForm) Validate(ctx *macaron.Context, errs *binding.Erro // \/ \/ \/ type CreateTeamForm struct { - TeamName string `form:"name" binding:"Required;AlphaDashDot;MaxSize(30)"` + TeamName string `form:"team_name" binding:"Required;AlphaDashDot;MaxSize(30)"` Description string `form:"desc" binding:"MaxSize(255)"` Permission string `form:"permission"` } diff --git a/modules/middleware/context.go b/modules/middleware/context.go index 6ce0f6e1f7..80975e999e 100644 --- a/modules/middleware/context.go +++ b/modules/middleware/context.go @@ -71,6 +71,8 @@ type Context struct { IsAdminTeam bool // In owner team or team that has admin permission level. Organization *models.User OrgLink string + + Team *models.Team } } diff --git a/modules/middleware/org.go b/modules/middleware/org.go index 77e999a328..c85221a5ab 100644 --- a/modules/middleware/org.go +++ b/modules/middleware/org.go @@ -41,15 +41,16 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler { } return } - ctx.Data["Org"] = ctx.Org.Organization + org := ctx.Org.Organization + ctx.Data["Org"] = org if ctx.IsSigned { - ctx.Org.IsOwner = ctx.Org.Organization.IsOrgOwner(ctx.User.Id) + ctx.Org.IsOwner = org.IsOrgOwner(ctx.User.Id) if ctx.Org.IsOwner { ctx.Org.IsMember = true ctx.Org.IsAdminTeam = true } else { - if ctx.Org.Organization.IsOrgMember(ctx.User.Id) { + if org.IsOrgMember(ctx.User.Id) { ctx.Org.IsMember = true // TODO: ctx.Org.IsAdminTeam } @@ -64,7 +65,24 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler { ctx.Data["IsAdminTeam"] = ctx.Org.IsAdminTeam ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner - ctx.Org.OrgLink = "/org/" + ctx.Org.Organization.Name + ctx.Org.OrgLink = "/org/" + org.Name ctx.Data["OrgLink"] = ctx.Org.OrgLink + + // Team. + teamName := ctx.Params(":team") + if len(teamName) > 0 { + ctx.Org.Team, err = org.GetTeam(teamName) + if err != nil { + if err == models.ErrTeamNotExist { + ctx.Handle(404, "GetTeam", err) + } else if redirect { + ctx.Redirect("/") + } else { + ctx.Handle(500, "GetTeam", err) + } + return + } + ctx.Data["Team"] = ctx.Org.Team + } } } diff --git a/public/ng/css/gogs.css b/public/ng/css/gogs.css index 6b400df28c..3d784fab21 100644 --- a/public/ng/css/gogs.css +++ b/public/ng/css/gogs.css @@ -1172,28 +1172,34 @@ The register and sign-in page style width: 520px; } /* repository create */ +#team-create-form, #repo-migrate-form, #repo-create-form { width: 800px; margin: 60px auto auto auto; background: white; } +#team-create-form h2, #repo-migrate-form h2, #repo-create-form h2 { margin: .5em 1em; } +#team-create-form .field, #repo-migrate-form .field, #repo-create-form .field { margin: 1.2em 0 2em 0; } +#team-create-form .ipt, #repo-migrate-form .ipt, #repo-create-form .ipt { width: 540px; } +#team-create-form textarea, #repo-migrate-form textarea, #repo-create-form textarea { height: 120px; } +#team-create-form .avatar, #repo-migrate-form .avatar, #repo-create-form .avatar { vertical-align: middle; @@ -1201,6 +1207,7 @@ The register and sign-in page style width: 28px; height: 28px; } +#team-create-form:hover, #repo-migrate-form:hover, #repo-create-form:hover { box-shadow: 0px 0px 6px #CCC; @@ -1681,6 +1688,9 @@ textarea#issue-add-content { box-sizing: border-box; height: 120px; } +.org-header-alert .alert { + margin-top: 10px; +} .org-header { padding: 16px 0; background-color: #FFF; @@ -1767,10 +1777,10 @@ textarea#issue-add-content { .org-sidebar .panel-footer { padding: .8em 1.2em; } -#org-member-avatar-group { +.org-sidebar .member-avatar-group { padding: 15px; } -#org-member-avatar-group img { +.org-sidebar .member-avatar-group img { width: 59px; height: 59px; border-radius: 3px; @@ -1801,13 +1811,14 @@ textarea#issue-add-content { margin-bottom: 0; color: #777; } -#org-member-toolbar { +.org-toolbar { padding: 10px 0; + border-bottom: 1px solid #eee; } #org-member-list .org-member-item { height: 50px; line-height: 50px; - border-top: 1px solid #eee; + border-bottom: 1px solid #eee; padding: 15px 20px; } #org-member-list .org-member-item .member-name { @@ -1832,3 +1843,19 @@ textarea#issue-add-content { #org-member-list-block { padding-top: 2px; } +.org-team-list .org-team-list-item { + float: left; + padding: 15px; + width: 555px; +} +.org-team-list .org-team-list-item .member-avatar-group { + padding: 5px 15px; +} +.org-team-list .org-team-list-item .member-avatar-group img { + width: 38px; + height: 38px; + border-radius: 3px; +} +#team-create-form .note { + margin-left: 153px; +} diff --git a/public/ng/less/gogs/organization.less b/public/ng/less/gogs/organization.less index 3805829532..e8063f2328 100644 --- a/public/ng/less/gogs/organization.less +++ b/public/ng/less/gogs/organization.less @@ -1,3 +1,6 @@ +.org-header-alert .alert { + margin-top: 10px; +} .org-header { padding: 16px 0; background-color: #FFF; @@ -91,13 +94,13 @@ .panel-footer { padding: .8em 1.2em; } -} -#org-member-avatar-group { - padding: 15px; - img { - width: 59px; - height: 59px; - border-radius: 3px; + .member-avatar-group { + padding: 15px; + img { + width: 59px; + height: 59px; + border-radius: 3px; + } } } #org-home-team-list { @@ -126,14 +129,15 @@ margin-bottom: 0; color: #777; } -#org-member-toolbar { +.org-toolbar { padding: 10px 0; + border-bottom: 1px solid #eee; } #org-member-list { .org-member-item { height: 50px; line-height: 50px; - border-top: 1px solid #eee; + border-bottom: 1px solid #eee; padding: 15px 20px; .member-name { padding-left: 15px; @@ -158,4 +162,24 @@ } #org-member-list-block { padding-top: 2px; +} +.org-team-list { + .org-team-list-item { + float: left; + padding: 15px; + width: 555px; + .member-avatar-group { + padding: 5px 15px; + img { + width: 38px; + height: 38px; + border-radius: 3px; + } + } + } +} +#team-create-form { + .note { + margin-left: 153px; + } }
\ No newline at end of file diff --git a/public/ng/less/gogs/repository.less b/public/ng/less/gogs/repository.less index 0aa19a04a9..8f9a97fa02 100644 --- a/public/ng/less/gogs/repository.less +++ b/public/ng/less/gogs/repository.less @@ -310,6 +310,7 @@ border-top-right-radius: .25em; } /* repository create */ +#team-create-form, #repo-migrate-form, #repo-create-form { width: 800px; diff --git a/routers/org/members.go b/routers/org/members.go index d98061765a..1e249e8be2 100644 --- a/routers/org/members.go +++ b/routers/org/members.go @@ -14,13 +14,13 @@ import ( ) const ( - MEMBERS base.TplName = "org/members" - INVITE base.TplName = "org/invite" + MEMBERS base.TplName = "org/member/members" + MEMBER_INVITE base.TplName = "org/member/invite" ) func Members(ctx *middleware.Context) { org := ctx.Org.Organization - ctx.Data["Title"] = org.Name + ctx.Data["Title"] = org.FullName ctx.Data["PageIsOrgMembers"] = true if err := org.GetMembers(); err != nil { @@ -60,6 +60,18 @@ func MembersAction(ctx *middleware.Context) { return } err = org.RemoveMember(uid) + if err == models.ErrLastOrgOwner { + ctx.Flash.Error(ctx.Tr("form.last_org_owner")) + ctx.Redirect(ctx.Org.OrgLink + "/members") + return + } + case "leave": + err = org.RemoveMember(ctx.User.Id) + if err == models.ErrLastOrgOwner { + ctx.Flash.Error(ctx.Tr("form.last_org_owner")) + ctx.Redirect(ctx.Org.OrgLink + "/members") + return + } } if err != nil { @@ -75,7 +87,7 @@ func MembersAction(ctx *middleware.Context) { func Invitation(ctx *middleware.Context) { org := ctx.Org.Organization - ctx.Data["Title"] = org.Name + ctx.Data["Title"] = org.FullName ctx.Data["PageIsOrgMembers"] = true if ctx.Req.Method == "POST" { @@ -101,5 +113,5 @@ func Invitation(ctx *middleware.Context) { return } - ctx.HTML(200, INVITE) + ctx.HTML(200, MEMBER_INVITE) } diff --git a/routers/org/org.go b/routers/org/org.go index 254ba8148f..27ccf02d3f 100644 --- a/routers/org/org.go +++ b/routers/org/org.go @@ -19,7 +19,7 @@ const ( func Home(ctx *middleware.Context) { org := ctx.Org.Organization - ctx.Data["Title"] = org.Name + ctx.Data["Title"] = org.FullName repos, err := models.GetRepositories(org.Id, ctx.IsSigned && org.IsOrgMember(ctx.User.Id)) if err != nil { diff --git a/routers/org/teams.go b/routers/org/teams.go index d494ddc04d..bc12a97160 100644 --- a/routers/org/teams.go +++ b/routers/org/teams.go @@ -13,31 +13,22 @@ import ( ) const ( - TEAMS base.TplName = "org/teams" - TEAM_NEW base.TplName = "org/team_new" + TEAMS base.TplName = "org/team/teams" + TEAM_NEW base.TplName = "org/team/new" ) func Teams(ctx *middleware.Context) { - ctx.Data["Title"] = "Organization " + ctx.Params(":org") + " Teams" + org := ctx.Org.Organization + ctx.Data["Title"] = org.FullName + ctx.Data["PageIsOrgTeams"] = true - org, err := models.GetUserByName(ctx.Params(":org")) - if err != nil { - if err == models.ErrUserNotExist { - ctx.Handle(404, "org.Teams(GetUserByName)", err) - } else { - ctx.Handle(500, "org.Teams(GetUserByName)", err) - } - return - } - ctx.Data["Org"] = org - - if err = org.GetTeams(); err != nil { - ctx.Handle(500, "org.Teams(GetTeams)", err) + if err := org.GetTeams(); err != nil { + ctx.Handle(500, "GetTeams", err) return } for _, t := range org.Teams { - if err = t.GetMembers(); err != nil { - ctx.Handle(500, "org.Home(GetMembers)", err) + if err := t.GetMembers(); err != nil { + ctx.Handle(500, "GetMembers", err) return } } @@ -46,44 +37,39 @@ func Teams(ctx *middleware.Context) { ctx.HTML(200, TEAMS) } -func NewTeam(ctx *middleware.Context) { - org, err := models.GetUserByName(ctx.Params(":org")) - if err != nil { - if err == models.ErrUserNotExist { - ctx.Handle(404, "org.NewTeam(GetUserByName)", err) - } else { - ctx.Handle(500, "org.NewTeam(GetUserByName)", err) - } - return +func TeamsAction(ctx *middleware.Context) { + var err error + switch ctx.Params(":action") { + case "join": + err = models.AddTeamMember(ctx.Org.Organization.Id, ctx.Org.Team.Id, ctx.User.Id) + case "leave": + err = models.RemoveMember(ctx.Org.Organization.Id, ctx.Org.Team.Id, ctx.User.Id) } - ctx.Data["Org"] = org - // Check ownership of organization. - if !org.IsOrgOwner(ctx.User.Id) { - ctx.Error(403) + 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 + "/teams") +} +func NewTeam(ctx *middleware.Context) { + ctx.Data["Title"] = ctx.Org.Organization.FullName + ctx.Data["PageIsOrgTeams"] = true + ctx.Data["PageIsOrgTeamsNew"] = true + ctx.Data["Team"] = &models.Team{} ctx.HTML(200, TEAM_NEW) } func NewTeamPost(ctx *middleware.Context, form auth.CreateTeamForm) { - org, err := models.GetUserByName(ctx.Params(":org")) - if err != nil { - if err == models.ErrUserNotExist { - ctx.Handle(404, "org.NewTeamPost(GetUserByName)", err) - } else { - ctx.Handle(500, "org.NewTeamPost(GetUserByName)", err) - } - return - } - ctx.Data["Org"] = org - - // Check ownership of organization. - if !org.IsOrgOwner(ctx.User.Id) { - ctx.Error(403) - return - } + ctx.Data["Title"] = ctx.Org.Organization.FullName + ctx.Data["PageIsOrgTeams"] = true + ctx.Data["PageIsOrgTeamsNew"] = true + ctx.Data["Team"] = &models.Team{} if ctx.HasError() { ctx.HTML(200, TEAM_NEW) @@ -104,23 +90,29 @@ func NewTeamPost(ctx *middleware.Context, form auth.CreateTeamForm) { return } + org := ctx.Org.Organization + t := &models.Team{ OrgId: org.Id, Name: form.TeamName, Description: form.Description, Authorize: auth, } - if err = models.NewTeam(t); err != nil { - if err == models.ErrTeamAlreadyExist { + if err := models.NewTeam(t); err != nil { + switch err { + case models.ErrTeamNameIllegal: + ctx.Data["Err_TeamName"] = true + ctx.RenderWithErr(ctx.Tr("form.illegal_team_name"), TEAM_NEW, &form) + case models.ErrTeamAlreadyExist: ctx.Data["Err_TeamName"] = true - ctx.RenderWithErr("Team name has already been used", TEAM_NEW, &form) - } else { - ctx.Handle(500, "org.NewTeamPost(NewTeam)", err) + ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), TEAM_NEW, &form) + default: + ctx.Handle(500, "NewTeam", err) } return } - log.Trace("%s Team created: %s/%s", ctx.Req.RequestURI, org.Name, t.Name) - ctx.Redirect("/org/" + org.LowerName + "/teams/" + t.LowerName) + log.Trace("Team created: %s/%s", org.Name, t.Name) + ctx.Redirect(ctx.Org.OrgLink + "/teams/" + t.LowerName) } func EditTeam(ctx *middleware.Context) { diff --git a/routers/user/auth.go b/routers/user/auth.go index 404b22f24d..231ee66279 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -20,12 +20,11 @@ import ( ) const ( - SIGNIN base.TplName = "user/signin" - SIGNUP base.TplName = "user/signup" - DELETE base.TplName = "user/delete" - ACTIVATE base.TplName = "user/activate" - FORGOT_PASSWORD base.TplName = "user/forgot_passwd" - RESET_PASSWORD base.TplName = "user/reset_passwd" + SIGNIN base.TplName = "user/auth/signin" + SIGNUP base.TplName = "user/auth/signup" + ACTIVATE base.TplName = "user/auth/activate" + FORGOT_PASSWORD base.TplName = "user/auth/forgot_passwd" + RESET_PASSWORD base.TplName = "user/auth/reset_passwd" ) func SignIn(ctx *middleware.Context) { diff --git a/templates/.VERSION b/templates/.VERSION index 906c01dc84..48fe58b179 100644 --- a/templates/.VERSION +++ b/templates/.VERSION @@ -1 +1 @@ -0.4.7.0815 Alpha
\ No newline at end of file +0.4.7.0816 Alpha
\ No newline at end of file diff --git a/templates/org/header.tmpl b/templates/org/base/header.tmpl index 8566d0a3c5..8566d0a3c5 100644 --- a/templates/org/header.tmpl +++ b/templates/org/base/header.tmpl diff --git a/templates/org/home.tmpl b/templates/org/home.tmpl index d96624010f..afd695ec7d 100644 --- a/templates/org/home.tmpl +++ b/templates/org/home.tmpl @@ -4,7 +4,10 @@ <div class="container clear"> <img class="avatar-100 left" src="{{.Org.AvatarLink}}?s=140"/> <div id="org-home-header-info"> - <h2>{{.Org.FullName}} <a class="text-grey" href="/org/{{.Org.LowerName}}/settings"><span class="octicon octicon-gear"></span></a></h2> + <h2> + {{.Org.FullName}} + {{if .IsOrganizationOwner}}<a class="text-grey" href="{{.OrgLink}}/settings"><span class="octicon octicon-gear"></span></a>{{end}} + </h2> {{if .Org.Description}}<p>{{.Org.Description}}</p>{{end}} <ul class="text-grey"> {{if .Org.Location}}<li><span class="octicon octicon-location"></span> <span>{{.Org.Location}}</span></li>{{end}} @@ -17,7 +20,7 @@ <div class="container"> <div id="org-home-repo-list" class="left grid-2-3"> <div class="clear"> - {{if .IsAdminTeam}} + {{if .IsOrganizationOwner}} <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> @@ -42,12 +45,12 @@ <a class="text-grey right" href="/org/{{.Org.LowerName}}/members"><strong>{{.Org.NumMembers}}</strong><span class="octicon octicon-chevron-right"></span></a> <strong>{{.i18n.Tr "org.people"}}</strong> </div> - <div class="panel-body" id="org-member-avatar-group"> + <div class="panel-body member-avatar-group"> {{range .Members}} - <a href="/{{.Name}}"><img src="{{.AvatarLink}}"></a> + <a href="/{{.Name}}" title="{{.Name}}"><img src="{{.AvatarLink}}"></a> {{end}} </div> - {{if .IsAdminTeam}} + {{if .IsOrganizationOwner}} <div class="panel-footer"> <a class="btn btn-medium btn-blue btn-link btn-radius" href="/org/{{.Org.LowerName}}/invitations/new">{{.i18n.Tr "org.invite_someone"}}</a> </div> diff --git a/templates/org/invite.tmpl b/templates/org/member/invite.tmpl index b9901aeb48..bff1b98b4c 100644 --- a/templates/org/invite.tmpl +++ b/templates/org/member/invite.tmpl @@ -1,6 +1,6 @@ {{template "ng/base/head" .}} {{template "ng/base/header" .}} -{{template "org/header" .}} +{{template "org/base/header" .}} <div class="container"> <div class="invite-box" id="invite-box"> {{template "ng/base/alert" .}} diff --git a/templates/org/members.tmpl b/templates/org/member/members.tmpl index bea4340ffb..3ab92bbfc0 100644 --- a/templates/org/members.tmpl +++ b/templates/org/member/members.tmpl @@ -1,9 +1,11 @@ {{template "ng/base/head" .}} {{template "ng/base/header" .}} -{{template "org/header" .}} +{{template "org/base/header" .}} <div class="container"> - {{template "ng/base/alert" .}} - <div class="clear" id="org-member-toolbar"> + <div class="org-header-alert"> + {{template "ng/base/alert" .}} + </div> + <div class="org-toolbar clear"> {{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}} @@ -25,15 +27,19 @@ {{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}} + {{if eq $.SignedUser.Id .Id}} + <li class="grid-1-6 right"> + <a class="btn btn-red btn-link btn-radius" href="{{$.OrgLink}}/members/action/leave?uid={{.Id}}">{{$.i18n.Tr "org.members.leave"}}</a> + </li> + {{else 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> diff --git a/templates/org/settings/delete.tmpl b/templates/org/settings/delete.tmpl index 7e24f85144..828389d6ff 100644 --- a/templates/org/settings/delete.tmpl +++ b/templates/org/settings/delete.tmpl @@ -1,5 +1,6 @@ {{template "ng/base/head" .}} {{template "ng/base/header" .}} +{{template "org/header" .}} <div id="setting-wrapper" class="main-wrapper"> <div id="org-setting" class="container clear"> {{template "org/settings/nav" .}} diff --git a/templates/org/settings/options.tmpl b/templates/org/settings/options.tmpl index 7548ad5aef..c5c6a7e221 100644 --- a/templates/org/settings/options.tmpl +++ b/templates/org/settings/options.tmpl @@ -1,5 +1,6 @@ {{template "ng/base/head" .}} {{template "ng/base/header" .}} +{{template "org/header" .}} <div id="setting-wrapper" class="main-wrapper"> <div id="org-setting" class="container clear"> {{template "org/settings/nav" .}} diff --git a/templates/org/team/new.tmpl b/templates/org/team/new.tmpl new file mode 100644 index 0000000000..f02512e052 --- /dev/null +++ b/templates/org/team/new.tmpl @@ -0,0 +1,48 @@ +{{template "ng/base/head" .}} +{{template "ng/base/header" .}} +{{template "org/base/header" .}} +<div id="repo-wrapper"> + <form id="team-create-form" class="form form-align panel panel-radius" action="{{.OrgLink}}/teams/new" method="post"> + {{.CsrfTokenHtml}} + <div class="panel-header"> + <h2>{{.i18n.Tr "org.create_new_team"}}</h2> + </div> + <div class="panel-content"> + {{template "ng/base/alert" .}} + <div class="field"> + <label class="req" for="team-name">{{.i18n.Tr "org.team_name"}}</label> + <input class="ipt ipt-large ipt-radius {{if .Err_TeamName}}ipt-error{{end}}" id="team-name" name="team_name" value="{{.team_name}}" required /> + <span class="form-label"></span> + <span class="help">{{.i18n.Tr "org.team_name_helper"}}</span> + </div> + <div class="field"> + <label for="desc">{{.i18n.Tr "org.team_desc"}}</label> + <input class="ipt ipt-large ipt-radius {{if .Err_Description}}ipt-error{{end}}" id="desc" name="desc" value="{{.desc}}" /> + <span class="form-label"></span> + <span class="help">{{.i18n.Tr "org.team_desc_helper"}}</span> + </div> + <div class="field"> + <h4 class="text-center">{{.i18n.Tr "org.team_permission_desc"}}</h4> + <label></label> + <input name="permission" type="radio" value="read" {{if or .PageIsOrgTeamsNew (eq .Team.Authorize 1)}}checked{{end}}> {{.i18n.Tr "org.teams.read_access"}} + <label></label> + <p class="text-grey note">{{.i18n.Tr "org.teams.read_access_helper"}}</p> + <label></label> + <input name="permission" type="radio" value="write" {{if eq .Team.Authorize 2}}checked{{end}}> {{.i18n.Tr "org.teams.write_access"}} + <label></label> + <p class="text-grey note">{{.i18n.Tr "org.teams.write_access_helper"}}</p> + <label></label> + <input name="permission" type="radio" value="admin" {{if eq .Team.Authorize 3}}checked{{end}}> {{.i18n.Tr "org.teams.admin_access"}} + <label></label> + <p class="text-grey note">{{.i18n.Tr "org.teams.admin_access_helper"}}</p> + </div> + <hr> + <div class="field"> + <label></label> + <button class="btn btn-large btn-blue btn-radius">{{.i18n.Tr "org.create_new_team"}}</button> + <a class="btn btn-small btn-gray btn-radius" id="repo-create-cancel" href="{{.OrgLink}}/teams"><strong>{{.i18n.Tr "cancel"}}</strong></a> + </div> + </div> + </form> +</div> +{{template "ng/base/footer" .}}
\ No newline at end of file diff --git a/templates/org/team/teams.tmpl b/templates/org/team/teams.tmpl new file mode 100644 index 0000000000..3e0846d652 --- /dev/null +++ b/templates/org/team/teams.tmpl @@ -0,0 +1,42 @@ +{{template "ng/base/head" .}} +{{template "ng/base/header" .}} +{{template "org/base/header" .}} +<div class="container"> + <div class="org-header-alert"> + {{template "ng/base/alert" .}} + </div> + <div class="org-toolbar clear"> + {{if .IsAdminTeam}} + <a class="btn btn-green btn-large btn-link btn-radius right" href="{{.OrgLink}}/teams/new"><i class="octicon octicon-repo-create"></i> {{.i18n.Tr "org.create_new_team"}}</a> + {{end}} + </div> + <div class="org-team-list"> + {{range .Teams}} + <div class="org-team-list-item"> + <div class="panel panel-radius"> + <div class="panel-header"> + {{if .IsMember $.SignedUser.Id}} + <a class="btn btn-small btn-red btn-header btn-radius right" href="{{$.OrgLink}}/teams/{{.LowerName}}/action/leave">{{$.i18n.Tr "org.teams.leave"}}</a> + {{else}} + <a class="btn btn-small btn-blue btn-header btn-radius right" href="{{$.OrgLink}}/teams/{{.LowerName}}/action/join">{{$.i18n.Tr "org.teams.join"}}</a> + {{end}} + <a class="text-black" href="{{$.OrgLink}}/teams/{{.LowerName}}"><strong>{{.Name}}</strong></a> + </div> + {{if .NumMembers}} + <div class="panel-body member-avatar-group"> + {{range .Members}} + <a href="/{{.Name}}" title="{{.Name}}"> + <img src="{{.AvatarLink}}"> + </a> + {{end}} + </div> + {{end}} + <div class="panel-footer"> + <p class="team-meta">{{.NumMembers}} {{$.i18n.Tr "org.lower_members"}} · {{.NumRepos}} {{$.i18n.Tr "org.lower_repositories"}}</p> + </div> + </div> + </div> + {{end}} + </div> +</div> +{{template "ng/base/footer" .}}
\ No newline at end of file diff --git a/templates/org/team_new.tmpl b/templates/org/team_new.tmpl deleted file mode 100644 index 0936ec29b3..0000000000 --- a/templates/org/team_new.tmpl +++ /dev/null @@ -1,79 +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="/org/{{.Org.Name}}/members"><i class="fa fa-users"></i>Members - <span class="label label-default">{{.Org.NumMembers}}</span></a> - </li> - <li class="active"><a href="/org/{{.Org.Name}}/teams"><i class="fa fa-tags"></i>Teams - <span class="label label-default">{{.Org.NumTeams}}</span></a> - </li> - </ul> - <img class="pull-left org-small-logo" src="{{.Org.AvatarLink}}?s=140" alt="" width="60"/> - <div id="org-nav-info"> - <h2 class="org-name">{{.Org.FullName}}</h2> - </div> - </div> - </div> -</div> - -<div id="body" class="container"> - <div id="org"> - <form action="/org/{{.Org.Name}}/teams/new" method="post" id="org-teams-create" class="form-horizontal card"> - {{.CsrfTokenHtml}} - <h3>Create new team</h3> - {{template "base/alert" .}} - <div class="form-group{{if .Err_TeamName}} has-error has-feedback{{end}}"> - <label class="col-md-2 control-label">Team Name<strong class="text-danger">*</strong></label> - <div class="col-md-8"> - <input name="name" type="text" class="form-control" placeholder="Type your team name" value="{{.name}}" required="required"> - <span class="help-block">You'll use this name to mention this team in conversations.</span> - </div> - </div> - - <div class="form-group{{if .Err_Description}} has-error has-feedback{{end}}"> - <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="{{.desc}}"> - </div> - </div> - - <div class="form-group{{if .Err_Permission}} has-error has-feedback{{end}}"> - <label class="col-md-2 control-label">Permission</label> - <div class="col-md-8"> - <div class="radio"> - <label> - <input type="radio" name="permission" value="read" checked=""> - <strong>Read Access</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="write"> - <strong>Write Access</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>Admin Access</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">Create team</button> - </div> - </div> - </form> - </div> -</div> -{{template "base/footer" .}} diff --git a/templates/org/teams.tmpl b/templates/org/teams.tmpl deleted file mode 100644 index 90ee209c0a..0000000000 --- a/templates/org/teams.tmpl +++ /dev/null @@ -1,58 +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="/org/{{.Org.Name}}/members"><i class="fa fa-users"></i>Members - <span class="label label-default">{{.Org.NumMembers}}</span></a> - </li> - <li class="active"><a href="/org/{{.Org.Name}}/teams"><i class="fa fa-tags"></i>Teams - <span class="label label-default">{{.Org.NumTeams}}</span></a> - </li> - </ul> - <img class="pull-left org-small-logo" src="{{.Org.AvatarLink}}?s=140" alt="" width="60"/> - <div id="org-nav-info"> - <h2 class="org-name">{{.Org.FullName}}</h2> - </div> - </div> - </div> -</div> - -<div id="body" class="container"> - <div id="org"> - <div id="org-teams"> - <div id="org-teams-action"> - <div class="col-md-12"> - <a href="/org/{{.Org.Name}}/teams/new"><button class="btn btn-success"><i class="fa fa-plus-square"></i>New Team</button></a> - <hr/> - </div> - </div> - {{range .Teams}} - <div class="org-team col-md-6"> - <div class="panel panel-default"> - <h2 class="panel-heading org-team-name"><a href="/org/{{$.Org.Name}}/teams/{{.LowerName}}"><strong>{{.Name}}</strong></a></h2> - <div class="panel-body"> - <p class="org-team-meta">{{.NumMembers}} members · {{.NumRepos}} repositories</p> - <p class="org-team-members"> - {{range .Members}} - <a href="/user/{{.LowerName}}"> - <img class="img-thumbnail" src="{{.AvatarLink}}?s=60" alt=""/> - </a> - {{end}} - </p> - </div> - <div class="panel-footer"> - {{if .IsMember $.SignedUser.Id}} - <a class="pull-right btn btn-danger" href="/org/{{$.Org.Name}}/teams/{{.LowerName}}?action=leave">Leave</a> - {{else}} - <a class="pull-right btn btn-default" href="/org/{{$.Org.Name}}/teams/{{.LowerName}}?action=join">Join</a> - {{end}} - </div> - </div> - </div> - {{end}} - </div> - </div> -</div> -{{template "base/footer" .}} diff --git a/templates/repo/create.tmpl b/templates/repo/create.tmpl index b5a8ea4e47..6baa6d31e0 100644 --- a/templates/repo/create.tmpl +++ b/templates/repo/create.tmpl @@ -3,7 +3,9 @@ <div id="repo-wrapper"> <form id="repo-create-form" class="form form-align panel panel-radius" action="/repo/create" method="post"> {{.CsrfTokenHtml}} - <div class="panel-header"><h2>{{.i18n.Tr "new_repo"}}</h2></div> + <div class="panel-header"> + <h2>{{.i18n.Tr "new_repo"}}</h2> + </div> <div class="panel-content"> {{template "ng/base/alert" .}} <div class="field"> diff --git a/templates/user/activate.tmpl b/templates/user/auth/activate.tmpl index acdad9e80b..acdad9e80b 100644 --- a/templates/user/activate.tmpl +++ b/templates/user/auth/activate.tmpl diff --git a/templates/user/forgot_passwd.tmpl b/templates/user/auth/forgot_passwd.tmpl index 3b5512673b..3b5512673b 100644 --- a/templates/user/forgot_passwd.tmpl +++ b/templates/user/auth/forgot_passwd.tmpl diff --git a/templates/user/reset_passwd.tmpl b/templates/user/auth/reset_passwd.tmpl index d17abde2ba..d17abde2ba 100644 --- a/templates/user/reset_passwd.tmpl +++ b/templates/user/auth/reset_passwd.tmpl diff --git a/templates/user/signin.tmpl b/templates/user/auth/signin.tmpl index c2f6ef877a..c2f6ef877a 100644 --- a/templates/user/signin.tmpl +++ b/templates/user/auth/signin.tmpl diff --git a/templates/user/signup.tmpl b/templates/user/auth/signup.tmpl index b4736a07ce..b4736a07ce 100644 --- a/templates/user/signup.tmpl +++ b/templates/user/auth/signup.tmpl diff --git a/templates/user/stars.tmpl b/templates/user/stars.tmpl deleted file mode 100644 index 253efd6eec..0000000000 --- a/templates/user/stars.tmpl +++ /dev/null @@ -1,17 +0,0 @@ -{{template "base/head" .}} -{{template "base/navbar" .}} -<div id="body-nav"> - <div class="container"> - <ul class="nav nav-pills pull-right"> - <li><a href="/">Feed</a></li> - <li><a href="/issues">Issues</a></li> - <li><a href="/pulls">Pull Requests</a></li> - <li class="active"><a href="/stars">Stars</a></li> - </ul> - <h3>Stars</h3> - </div> -</div> -<div id="body" class="container" data-page="user"> - {{if .HasInfo}}<div class="alert alert-info">{{.InfoMsg}}</div>{{end}} -</div> -{{template "base/footer" .}}
\ No newline at end of file |