]> source.dussan.org Git - gitea.git/commitdiff
Collaborator
authorUnknown <joe2010xtmf@163.com>
Thu, 1 May 2014 15:32:12 +0000 (11:32 -0400)
committerUnknown <joe2010xtmf@163.com>
Thu, 1 May 2014 15:32:12 +0000 (11:32 -0400)
README.md
README_ZH.md
models/access.go
models/repo.go
public/css/gogs.css
routers/repo/setting.go
templates/repo/collaboration.tmpl
templates/repo/setting.tmpl
templates/repo/setting_nav.tmpl [new file with mode: 0644]
web.go

index 8e00be5265da272cabe5804cfee52c40cfd4b3ef..ec3621c83829b0bf8c563213daa5c5fc3c2d4a98 100644 (file)
--- 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.
index e4c92685fee9ceee59cc32cefe897ad9c852ff90..5d2da44aa4a6d684a985577604d7aeb852f39762 100644 (file)
@@ -27,6 +27,7 @@ Gogs 完全使用 Go 语言来实现对 Git 数据的操作,实现 **零** 依
 - 注册/删除/重命名用户
 - 创建/迁移/镜像/删除/关注/重命名/转移 公开/私有 仓库
 - 仓库 浏览器/发布/缺陷追踪
+- 添加/删除 仓库协作者
 - Gravatar 以及缓存支持
 - 邮件服务(注册、Issue)
 - 管理员面板
index 970f4a941f9b1a3c2a6216596b35a44d412db0d2..749a2604d5a4388528c2fb08eec0b7d41c0c80c8 100644 (file)
@@ -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 {
index 5e193787219f37fc22547b8f995a3085c10650d9..be889cba5f69cefa8387ef43983214b61420d852 100644 (file)
@@ -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
index b4855d7805c7c00a6b8d5e86a2001a6659d1de14..e84eb1ef14944af1e1e04ca445800dcacdf2131f 100755 (executable)
@@ -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,
index bb3626091240ca264292767211eb5fdf5a1560b7..8f7b84b6944cfb692e33870a6dabc23c94de12c1 100644 (file)
@@ -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)
+}
index ec0b832a4297bfab92fcd6e4477245ed1a5f18d5..8ede9d4321603cdef06937a66ebc6a685657236b 100644 (file)
@@ -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">
             </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>
index 6672e90b5969353d47ce70c69c2de4e886682bea..afa66d1de14c011efb81773ce4fe1aa57fc34624 100644 (file)
@@ -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 (file)
index 0000000..4e558a7
--- /dev/null
@@ -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 49ad0040084d0f7d9ab486fb67c80df4e88f361f..0ee89c3ca9a8445ea5bd12a2f9400898743ce2c7 100644 (file)
--- 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)