summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--README_ZH.md1
-rw-r--r--models/access.go6
-rw-r--r--models/repo.go14
-rwxr-xr-xpublic/css/gogs.css1
-rw-r--r--routers/repo/setting.go88
-rw-r--r--templates/repo/collaboration.tmpl26
-rw-r--r--templates/repo/setting.tmpl9
-rw-r--r--templates/repo/setting_nav.tmpl7
-rw-r--r--web.go3
10 files changed, 118 insertions, 38 deletions
diff --git a/README.md b/README.md
index 8e00be5265..ec3621c838 100644
--- a/README.md
+++ b/README.md
@@ -36,6 +36,7 @@ More importantly, Gogs only needs one binary to setup your own project hosting o
- Register/delete/rename account.
- Create/migrate/mirror/delete/watch/rename/transfer public/private repository.
- Repository viewer/release/issue tracker.
+- Add/remove repository collaborators.
- Gravatar and cache support.
- Mail service(register, issue).
- Administration panel.
diff --git a/README_ZH.md b/README_ZH.md
index e4c92685fe..5d2da44aa4 100644
--- a/README_ZH.md
+++ b/README_ZH.md
@@ -27,6 +27,7 @@ Gogs 完全使用 Go 语言来实现对 Git 数据的操作,实现 **零** 依
- 注册/删除/重命名用户
- 创建/迁移/镜像/删除/关注/重命名/转移 公开/私有 仓库
- 仓库 浏览器/发布/缺陷追踪
+- 添加/删除 仓库协作者
- Gravatar 以及缓存支持
- 邮件服务(注册、Issue)
- 管理员面板
diff --git a/models/access.go b/models/access.go
index 970f4a941f..749a2604d5 100644
--- a/models/access.go
+++ b/models/access.go
@@ -42,6 +42,12 @@ func UpdateAccess(access *Access) error {
return err
}
+// DeleteAccess deletes access record.
+func DeleteAccess(access *Access) error {
+ _, err := orm.Delete(access)
+ return err
+}
+
// UpdateAccess updates access information with session for rolling back.
func UpdateAccessWithSession(sess *xorm.Session, access *Access) error {
if _, err := sess.Id(access.Id).Update(access); err != nil {
diff --git a/models/repo.go b/models/repo.go
index 5e19378721..be889cba5f 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -712,6 +712,20 @@ func GetRepositoryCount(user *User) (int64, error) {
return orm.Count(&Repository{OwnerId: user.Id})
}
+// GetCollaborators returns a list of user name of repository's collaborators.
+func GetCollaborators(repoName string) ([]string, error) {
+ accesses := make([]*Access, 0, 10)
+ if err := orm.Find(&accesses, &Access{RepoName: strings.ToLower(repoName)}); err != nil {
+ return nil, err
+ }
+
+ names := make([]string, len(accesses))
+ for i := range accesses {
+ names[i] = accesses[i].UserName
+ }
+ return names, nil
+}
+
// Watch is connection request for receiving repository notifycation.
type Watch struct {
Id int64
diff --git a/public/css/gogs.css b/public/css/gogs.css
index b4855d7805..e84eb1ef14 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -398,6 +398,7 @@ html, body {
background-color: #FFF;
border: 1px solid #CCC;
padding: 0;
+ padding-top: 10px;
}
#user-setting-nav > h4, #user-setting-container > h4, #user-setting-container > div > h4,
diff --git a/routers/repo/setting.go b/routers/repo/setting.go
index bb36260912..8f7b84b694 100644
--- a/routers/repo/setting.go
+++ b/routers/repo/setting.go
@@ -6,7 +6,10 @@ package repo
import (
"fmt"
+ "strings"
+
"github.com/gogits/git"
+
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
@@ -20,13 +23,7 @@ func Setting(ctx *middleware.Context) {
}
ctx.Data["IsRepoToolbarSetting"] = true
-
- var title string
- if t, ok := ctx.Data["Title"].(string); ok {
- title = t
- }
-
- ctx.Data["Title"] = title + " - settings"
+ ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - settings"
ctx.HTML(200, "repo/setting")
}
@@ -128,17 +125,82 @@ func SettingPost(ctx *middleware.Context) {
func Collaboration(ctx *middleware.Context) {
if !ctx.Repo.IsOwner {
- ctx.Handle(404, "repo.Setting", nil)
+ ctx.Error(404)
return
}
- ctx.Data["IsRepoToolbarSetting"] = true
+ repoLink := strings.TrimPrefix(ctx.Repo.RepoLink, "/")
+ ctx.Data["IsRepoToolbarCollaboration"] = true
+ ctx.Data["Title"] = repoLink + " - collaboration"
+
+ // Delete collaborator.
+ remove := strings.ToLower(ctx.Query("remove"))
+ if len(remove) > 0 && remove != ctx.Repo.Owner.LowerName {
+ if err := models.DeleteAccess(&models.Access{UserName: remove, RepoName: repoLink}); err != nil {
+ ctx.Handle(500, "repo.Collaboration(DeleteAccess)", err)
+ return
+ }
+ ctx.Flash.Success("Collaborator has been removed.")
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
+ return
+ }
+
+ names, err := models.GetCollaborators(repoLink)
+ if err != nil {
+ ctx.Handle(500, "repo.Collaboration(GetCollaborators)", err)
+ return
+ }
- var title string
- if t, ok := ctx.Data["Title"].(string); ok {
- title = t
+ us := make([]*models.User, len(names))
+ for i, name := range names {
+ us[i], err = models.GetUserByName(name)
+ if err != nil {
+ ctx.Handle(500, "repo.Collaboration(GetUserByName)", err)
+ return
+ }
}
- ctx.Data["Title"] = title + " - collaboration"
+ ctx.Data["Collaborators"] = us
ctx.HTML(200, "repo/collaboration")
}
+
+func CollaborationPost(ctx *middleware.Context) {
+ if !ctx.Repo.IsOwner {
+ ctx.Error(404)
+ return
+ }
+
+ repoLink := strings.TrimPrefix(ctx.Repo.RepoLink, "/")
+ name := strings.ToLower(ctx.Query("collaborator"))
+ if len(name) == 0 || ctx.Repo.Owner.LowerName == name {
+ ctx.Redirect(ctx.Req.RequestURI)
+ return
+ }
+ has, err := models.HasAccess(name, repoLink, models.AU_WRITABLE)
+ if err != nil {
+ ctx.Handle(500, "repo.CollaborationPost(HasAccess)", err)
+ return
+ } else if has {
+ ctx.Redirect(ctx.Req.RequestURI)
+ return
+ }
+
+ isExist, err := models.IsUserExist(name)
+ if err != nil {
+ ctx.Handle(500, "repo.CollaborationPost(IsUserExist)", err)
+ return
+ } else if !isExist {
+ ctx.Flash.Error("Given user does not exist.")
+ ctx.Redirect(ctx.Req.RequestURI)
+ return
+ }
+
+ if err := models.AddAccess(&models.Access{UserName: name, RepoName: repoLink,
+ Mode: models.AU_WRITABLE}); err != nil {
+ ctx.Handle(500, "repo.CollaborationPost(AddAccess)", err)
+ return
+ }
+
+ ctx.Flash.Success("New collaborator has been added.")
+ ctx.Redirect(ctx.Req.RequestURI)
+}
diff --git a/templates/repo/collaboration.tmpl b/templates/repo/collaboration.tmpl
index ec0b832a42..8ede9d4321 100644
--- a/templates/repo/collaboration.tmpl
+++ b/templates/repo/collaboration.tmpl
@@ -3,14 +3,7 @@
{{template "repo/nav" .}}
{{template "repo/toolbar" .}}
<div id="body" class="container">
- <div id="user-setting-nav" class="col-md-2 repo-setting-nav">
- <ul class="list-group">
- <li class="list-group-item"><a href="/{{.Owner.Name}}/{{.Repository.Name}}/settings">Options</a></li>
- <li class="list-group-item active"><a href="/{{.Owner.Name}}/{{.Repository.Name}}/collaboration">Collaborators</a></li>
- <!--<li class="list-group-item"><a href="#">Notifications</a></li>-->
- </ul>
- </div>
-
+ {{template "repo/setting_nav" .}}
<div id="repo-setting-container" class="col-md-10">
{{template "base/alert" .}}
<div class="panel panel-default">
@@ -19,23 +12,24 @@
</div>
<div class="panel-body">
<ul id="repo-collab-list" class="list-unstyled">
- <li>No Collaborators</li>
+ {{range .Collaborators}}
<li class="collab">
- <a href="/{{.Owner.Name}}/{{.Repository.Name}}/remove_member?name=" class="remove-collab pull-right"><i class="fa fa-times"></i></a>
- <a class="member" href="#">
- <img alt="无闻" class="pull-left avatar" src="https://avatars2.githubusercontent.com/u/2946214?s=140">
- <strong class="access-member-fullname">无闻</strong><br/>
- Unknwon
+ {{if not (eq .LowerName $.Owner.LowerName)}}<a href="{{$.RepoLink}}/settings/collaboration?remove={{.Name}}" class="remove-collab pull-right"><i class="fa fa-times"></i></a>{{end}}
+ <a class="member" href="/user/{{.Name}}">
+ <img alt="{{.Name}}" class="pull-left avatar" src="{{.AvatarLink}}">
+ <strong class="access-member-fullname">{{.FullName}}</strong><br/>
+ {{.Name}}
</a>
</li>
+ {{end}}
</ul>
</div>
<div class="panel-footer">
- <form action="/{{.Owner.Name}}/{{.Repository.Name}}/collaboration" method="post" class="form-horizontal" id="repo-collab-form">
+ <form action="{{.RepoLink}}/settings/collaboration" method="post" class="form-horizontal" id="repo-collab-form">
{{.CsrfTokenHtml}}
<div class="form-group" style="margin-bottom: 0">
<div class="col-md-4">
- <input type="text" name="collaborator" class="form-control dropdown-toggle" id="repo-collaborator" required="required" data-toggle="dropdown"/>
+ <input type="text" name="collaborator" class="form-control dropdown-toggle" id="repo-collaborator" autocomplete="off" required="required" data-toggle="dropdown"/>
<div class="dropdown-menu">
<ul class="list-unstyled"></ul>
</div>
diff --git a/templates/repo/setting.tmpl b/templates/repo/setting.tmpl
index 6672e90b59..afa66d1de1 100644
--- a/templates/repo/setting.tmpl
+++ b/templates/repo/setting.tmpl
@@ -3,14 +3,7 @@
{{template "repo/nav" .}}
{{template "repo/toolbar" .}}
<div id="body" class="container">
- <div id="user-setting-nav" class="col-md-2 repo-setting-nav">
- <ul class="list-group">
- <li class="list-group-item active"><a href="/{{.Owner.Name}}/{{.Repository.Name}}/settings">Options</a></li>
- <li class="list-group-item"><a href="/{{.Owner.Name}}/{{.Repository.Name}}/collaboration">Collaborators</a></li>
- <!--<li class="list-group-item"><a href="#">Notifications</a></li>-->
- </ul>
- </div>
-
+ {{template "repo/setting_nav" .}}
<div id="repo-setting-container" class="col-md-10">
{{template "base/alert" .}}
<div class="panel panel-default">
diff --git a/templates/repo/setting_nav.tmpl b/templates/repo/setting_nav.tmpl
new file mode 100644
index 0000000000..4e558a76ef
--- /dev/null
+++ b/templates/repo/setting_nav.tmpl
@@ -0,0 +1,7 @@
+<div id="user-setting-nav" class="col-md-2 repo-setting-nav">
+ <ul class="list-group">
+ <li class="list-group-item{{if .IsRepoToolbarSetting}} active{{end}}"><a href="/{{.Owner.Name}}/{{.Repository.Name}}/settings">Options</a></li>
+ <li class="list-group-item{{if .IsRepoToolbarCollaboration}} active{{end}}"><a href="/{{.Owner.Name}}/{{.Repository.Name}}/settings/collaboration">Collaborators</a></li>
+ <!--<li class="list-group-item"><a href="#">Notifications</a></li>-->
+ </ul>
+</div> \ No newline at end of file
diff --git a/web.go b/web.go
index 49ad004008..0ee89c3ca9 100644
--- a/web.go
+++ b/web.go
@@ -150,7 +150,8 @@ func runWeb(*cli.Context) {
m.Group("/:username/:reponame", func(r martini.Router) {
r.Get("/settings", repo.Setting)
r.Post("/settings", repo.SettingPost)
- r.Get("/collaboration", repo.Collaboration)
+ r.Get("/settings/collaboration", repo.Collaboration)
+ r.Post("/settings/collaboration", repo.CollaborationPost)
r.Get("/action/:action", repo.Action)
r.Get("/issues/new", repo.CreateIssue)
r.Post("/issues/new", bindIgnErr(auth.CreateIssueForm{}), repo.CreateIssuePost)