]> source.dussan.org Git - gitea.git/commitdiff
Finsih add/remove repo in organization
authorUnknwon <joe2010xtmf@163.com>
Tue, 26 Aug 2014 10:11:15 +0000 (18:11 +0800)
committerUnknwon <joe2010xtmf@163.com>
Tue, 26 Aug 2014 10:11:15 +0000 (18:11 +0800)
19 files changed:
cmd/web.go
conf/locale/locale_en-US.ini
conf/locale/locale_zh-CN.ini
gogs.go
models/access.go
models/org.go
models/repo.go
models/user.go
public/ng/css/gogs.css
public/ng/js/gogs.js
public/ng/less/gogs/organization.less
public/ng/less/gogs/repository.less
routers/api/v1/repos.go [new file with mode: 0644]
routers/api/v1/repositories.go [deleted file]
routers/api/v1/users.go
routers/org/teams.go
templates/.VERSION
templates/org/team/repositories.tmpl
templates/org/team/sidebar.tmpl

index 0b3b84ab6a6c767c813140b9bc3a503d8a436e1d..cc9fa385c316cb0e589470924da7c61c08ceaf93 100644 (file)
@@ -141,7 +141,7 @@ func runWeb(*cli.Context) {
                        r.Get("/users/search", v1.SearchUsers)
 
                        // Repositories.
-                       r.Get("/orgs/:org/repos/search", v1.SearchOrgRepositoreis)
+                       r.Get("/repos/search", v1.SearchRepos)
 
                        r.Any("/*", func(ctx *middleware.Context) {
                                ctx.JSON(404, &base.ApiJsonErr{"Not Found", v1.DOC_URL})
@@ -236,7 +236,9 @@ func runWeb(*cli.Context) {
 
                        r.Get("/teams", org.Teams)
                        r.Get("/teams/:team", org.TeamMembers)
+                       r.Get("/teams/:team/repositories", org.TeamRepositories)
                        r.Get("/teams/:team/action/:action", org.TeamsAction)
+                       r.Get("/teams/:team/action/repo/:action", org.TeamsRepoAction)
                }, middleware.OrgAssignment(true, true))
 
                m.Group("/:org", func(r *macaron.Router) {
index 9437bfd19706b111ec0d33dd7791ba0a8d94fe45..25384b03fe94fb13f9f8004843db6cbe553d5eec 100644 (file)
@@ -290,6 +290,9 @@ teams.delete_team_success = Given team has been successfully deleted.
 teams.read_permission_desc = This team grants <strong>Read</strong> access: members can view and clone the team's repositories.
 teams.write_permission_desc = This team grants <strong>Write</strong> access: members can read from and push to the team's repositories.
 teams.admin_permission_desc = This team grants <strong>Admin</strong> access: members can read from, push to, and add collaborators to the team's repositories.
+teams.repositories = Team Repositories
+teams.add_team_repository = Add Team Repository
+teams.remove_repo = Remove
 
 [action]
 create_repo = created repository <a href="/%s">%s</a>
index dbc94f3a0c6a704dfe15c3edff7c449865889d48..1b3329e6f83e442a1b4f57f71fbd61e0434bc8f3 100644 (file)
@@ -290,6 +290,9 @@ teams.delete_team_success = 指定团队已经被成功删除!
 teams.read_permission_desc = 该团队拥有对所属仓库的 <strong>读取</strong> 权限,团队成员可以进行查看和克隆等只读操作。
 teams.write_permission_desc = 该团队拥有对所属仓库的 <strong>读取</strong> 和 <strong>写入</strong> 的权限。
 teams.admin_permission_desc = 该团队拥有一定的 <strong>管理</strong> 权限,团队成员可以读取、克隆、推送以及添加其它仓库协作者。
+teams.repositories = 团队仓库
+teams.add_team_repository = 添加团队仓库
+teams.remove_repo = 移除仓库
 
 [action]
 create_repo = 创建了仓库 <a href="/%s">%s</a>
diff --git a/gogs.go b/gogs.go
index bdd19cfffeeb96a72b1ca176e99a0a5d898a41e7..4adac90b99a38443e4182f261b0072b43bb69bc9 100644 (file)
--- a/gogs.go
+++ b/gogs.go
@@ -17,7 +17,7 @@ import (
        "github.com/gogits/gogs/modules/setting"
 )
 
-const APP_VER = "0.4.7.0825 Alpha"
+const APP_VER = "0.4.7.0826 Alpha"
 
 func init() {
        runtime.GOMAXPROCS(runtime.NumCPU())
index 5238daba32ee52c931086a974d805d1bcfad784c..81aa43dc785f6dd11626bdc6d8fe3da809709cd1 100644 (file)
@@ -21,10 +21,10 @@ const (
 // Access represents the accessibility of user to repository.
 type Access struct {
        Id       int64
-       UserName string     `xorm:"unique(s)"`
-       RepoName string     `xorm:"unique(s)"` // <user name>/<repo name>
-       Mode     AccessType `xorm:"unique(s)"`
-       Created  time.Time  `xorm:"created"`
+       UserName string     `xorm:"UNIQUE(s)"`
+       RepoName string     `xorm:"UNIQUE(s)"` // <user name>/<repo name>
+       Mode     AccessType `xorm:"UNIQUE(s)"`
+       Created  time.Time  `xorm:"CREATED"`
 }
 
 // AddAccess adds new access record.
index 27228382d362ee3b46b081bbece2644a93fb515b..5d73cf3ff26c145def90366b9faa84ebf9f8045f 100644 (file)
@@ -369,6 +369,13 @@ const (
        ORG_ADMIN
 )
 
+func AuthorizeToAccessType(auth AuthorizeType) AccessType {
+       if auth == ORG_READABLE {
+               return READABLE
+       }
+       return WRITABLE
+}
+
 const OWNER_TEAM = "Owners"
 
 // Team represents a organization team.
@@ -433,6 +440,142 @@ func (t *Team) RemoveMember(uid int64) error {
        return RemoveTeamMember(t.OrgId, t.Id, uid)
 }
 
+// addAccessWithAuthorize inserts or updates access with given mode.
+func addAccessWithAuthorize(sess *xorm.Session, access *Access, mode AccessType) error {
+       has, err := x.Get(access)
+       if err != nil {
+               return fmt.Errorf("fail to get access: %v", err)
+       }
+       access.Mode = mode
+       if has {
+               if _, err = sess.Id(access.Id).Update(access); err != nil {
+                       return fmt.Errorf("fail to update access: %v", err)
+               }
+       } else {
+               if _, err = sess.Insert(access); err != nil {
+                       return fmt.Errorf("fail to insert access: %v", err)
+               }
+       }
+       return nil
+}
+
+// AddRepository adds new repository to team of organization.
+func (t *Team) AddRepository(repo *Repository) (err error) {
+       idStr := "$" + com.ToStr(repo.Id) + "|"
+       if repo.OwnerId != t.OrgId {
+               return errors.New("Repository not belong to organization")
+       } else if strings.Contains(t.RepoIds, idStr) {
+               return nil
+       }
+
+       if err = repo.GetOwner(); err != nil {
+               return err
+       } else if err = t.GetMembers(); err != nil {
+               return err
+       }
+
+       sess := x.NewSession()
+       defer sess.Close()
+       if err = sess.Begin(); err != nil {
+               return err
+       }
+
+       t.NumRepos++
+       t.RepoIds += idStr
+       if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
+               sess.Rollback()
+               return err
+       }
+
+       // Give access to team members.
+       mode := AuthorizeToAccessType(t.Authorize)
+
+       for _, u := range t.Members {
+               auth, err := GetHighestAuthorize(t.OrgId, u.Id, t.Id, repo.Id)
+               if err != nil {
+                       sess.Rollback()
+                       return err
+               }
+
+               access := &Access{
+                       UserName: u.LowerName,
+                       RepoName: path.Join(repo.Owner.LowerName, repo.LowerName),
+               }
+               if auth == 0 {
+                       access.Mode = mode
+                       if _, err = sess.Insert(access); err != nil {
+                               sess.Rollback()
+                               return fmt.Errorf("fail to insert access: %v", err)
+                       }
+               } else if auth < t.Authorize {
+                       if err = addAccessWithAuthorize(sess, access, mode); err != nil {
+                               sess.Rollback()
+                               return err
+                       }
+               }
+       }
+       return sess.Commit()
+}
+
+// RemoveRepository removes repository from team of organization.
+func (t *Team) RemoveRepository(repoId int64) error {
+       idStr := "$" + com.ToStr(repoId) + "|"
+       if !strings.Contains(t.RepoIds, idStr) {
+               return nil
+       }
+
+       repo, err := GetRepositoryById(repoId)
+       if err != nil {
+               return err
+       }
+
+       if err = repo.GetOwner(); err != nil {
+               return err
+       } else if err = t.GetMembers(); err != nil {
+               return err
+       }
+
+       sess := x.NewSession()
+       defer sess.Close()
+       if err = sess.Begin(); err != nil {
+               return err
+       }
+
+       t.NumRepos--
+       t.RepoIds = strings.Replace(t.RepoIds, idStr, "", 1)
+       if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
+               sess.Rollback()
+               return err
+       }
+
+       // Remove access to team members.
+       for _, u := range t.Members {
+               auth, err := GetHighestAuthorize(t.OrgId, u.Id, t.Id, repo.Id)
+               if err != nil {
+                       sess.Rollback()
+                       return err
+               }
+
+               access := &Access{
+                       UserName: u.LowerName,
+                       RepoName: path.Join(repo.Owner.LowerName, repo.LowerName),
+               }
+               if auth == 0 {
+                       if _, err = sess.Delete(access); err != nil {
+                               sess.Rollback()
+                               return fmt.Errorf("fail to delete access: %v", err)
+                       }
+               } else if auth < t.Authorize {
+                       if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil {
+                               sess.Rollback()
+                               return err
+                       }
+               }
+       }
+
+       return sess.Commit()
+}
+
 // NewTeam creates a record of new team.
 // It's caller's responsibility to assign organization ID.
 func NewTeam(t *Team) error {
@@ -554,16 +697,10 @@ func UpdateTeam(t *Team, authChanged bool) (err error) {
                        return err
                }
 
-               mode := READABLE
-               if t.Authorize > ORG_READABLE {
-                       mode = WRITABLE
-               }
-               access := &Access{
-                       Mode: mode,
-               }
+               // Update access.
+               mode := AuthorizeToAccessType(t.Authorize)
 
                for _, repo := range t.Repos {
-                       access.RepoName = path.Join(org.LowerName, repo.LowerName)
                        for _, u := range t.Members {
                                // ORG_WRITABLE is the highest authorize level for now.
                                // Skip checking others if current team has this level.
@@ -578,8 +715,11 @@ func UpdateTeam(t *Team, authChanged bool) (err error) {
                                        }
                                }
 
-                               access.UserName = u.LowerName
-                               if _, err = sess.Update(access); err != nil {
+                               access := &Access{
+                                       UserName: u.LowerName,
+                                       RepoName: path.Join(org.LowerName, repo.LowerName),
+                               }
+                               if err = addAccessWithAuthorize(sess, access, mode); err != nil {
                                        sess.Rollback()
                                        return err
                                }
@@ -617,36 +757,26 @@ func DeleteTeam(t *Team) error {
        }
 
        // Delete all accesses.
-       mode := READABLE
-       if t.Authorize > ORG_READABLE {
-               mode = WRITABLE
-       }
-       access := new(Access)
-
        for _, repo := range t.Repos {
-               access.RepoName = path.Join(org.LowerName, repo.LowerName)
                for _, u := range t.Members {
-                       access.UserName = u.LowerName
-                       access.Mode = mode
                        auth, err := GetHighestAuthorize(org.Id, u.Id, t.Id, repo.Id)
                        if err != nil {
                                sess.Rollback()
                                return err
                        }
 
+                       access := &Access{
+                               UserName: u.LowerName,
+                               RepoName: path.Join(org.LowerName, repo.LowerName),
+                       }
                        if auth == 0 {
                                if _, err = sess.Delete(access); err != nil {
                                        sess.Rollback()
-                                       return err
+                                       return fmt.Errorf("fail to delete access: %v", err)
                                }
                        } else if auth < t.Authorize {
                                // Downgrade authorize level.
-                               mode := READABLE
-                               if auth > ORG_READABLE {
-                                       mode = WRITABLE
-                               }
-                               access.Mode = mode
-                               if _, err = sess.Update(access); err != nil {
+                               if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil {
                                        sess.Rollback()
                                        return err
                                }
@@ -779,15 +909,6 @@ func AddTeamMember(orgId, teamId, uid int64) error {
                TeamId: teamId,
        }
 
-       mode := READABLE
-       if t.Authorize > ORG_READABLE {
-               mode = WRITABLE
-       }
-       access := &Access{
-               UserName: u.LowerName,
-               Mode:     mode,
-       }
-
        if _, err = sess.Insert(tu); err != nil {
                sess.Rollback()
                return err
@@ -797,6 +918,7 @@ func AddTeamMember(orgId, teamId, uid int64) error {
        }
 
        // Give access to team repositories.
+       mode := AuthorizeToAccessType(t.Authorize)
        for _, repo := range t.Repos {
                auth, err := GetHighestAuthorize(orgId, uid, teamId, repo.Id)
                if err != nil {
@@ -804,22 +926,24 @@ func AddTeamMember(orgId, teamId, uid int64) error {
                        return err
                }
 
-               access.Id = 0
-               access.RepoName = path.Join(org.LowerName, repo.LowerName)
+               access := &Access{
+                       UserName: u.LowerName,
+                       RepoName: path.Join(org.LowerName, repo.LowerName),
+               }
                // Equal 0 means given access doesn't exist.
                if auth == 0 {
+                       access.Mode = mode
                        if _, err = sess.Insert(access); err != nil {
                                sess.Rollback()
-                               return err
+                               return fmt.Errorf("fail to insert access: %v", err)
                        }
                } else if auth < t.Authorize {
-                       if _, err = sess.Update(access); err != nil {
+                       if err = addAccessWithAuthorize(sess, access, mode); err != nil {
                                sess.Rollback()
                                return err
                        }
                }
        }
-       fmt.Println("kao")
 
        // We make sure it exists before.
        ou := new(OrgUser)
@@ -889,10 +1013,6 @@ func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) erro
        }
 
        // Delete access to team repositories.
-       access := &Access{
-               UserName: u.LowerName,
-       }
-
        for _, repo := range t.Repos {
                auth, err := GetHighestAuthorize(orgId, uid, teamId, repo.Id)
                if err != nil {
@@ -900,22 +1020,22 @@ func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) erro
                        return err
                }
 
+               access := &Access{
+                       UserName: u.LowerName,
+                       RepoName: path.Join(org.LowerName, repo.LowerName),
+               }
                // Delete access if this is the last team user belongs to.
                if auth == 0 {
-                       access.RepoName = path.Join(org.LowerName, repo.LowerName)
-                       _, err = sess.Delete(access)
+                       if _, err = sess.Delete(access); err != nil {
+                               sess.Rollback()
+                               return fmt.Errorf("fail to delete access: %v", err)
+                       }
                } else if auth < t.Authorize {
                        // Downgrade authorize level.
-                       mode := READABLE
-                       if auth > ORG_READABLE {
-                               mode = WRITABLE
+                       if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil {
+                               sess.Rollback()
+                               return err
                        }
-                       access.Mode = mode
-                       _, err = sess.Update(access)
-               }
-               if err != nil {
-                       sess.Rollback()
-                       return err
                }
        }
 
index f5d1ca834e29cc6512084e0f9855ef51bb05338f..c3e9423f451ae5594a106efa1ca795b40733eac1 100644 (file)
@@ -519,12 +519,11 @@ func CreateRepository(u *User, name, desc, lang, license string, private, mirror
                        sess.Rollback()
                        return nil, err
                }
-               us, err := GetTeamMembers(u.Id, t.Id)
-               if err != nil {
+               if err = t.GetMembers(); err != nil {
                        sess.Rollback()
                        return nil, err
                }
-               for _, u := range us {
+               for _, u := range t.Members {
                        access.Id = 0
                        access.UserName = u.LowerName
                        if _, err = sess.Insert(access); err != nil {
@@ -963,6 +962,37 @@ func GetCollaborators(repoName string) (us []*User, err error) {
        return us, nil
 }
 
+type SearchOption struct {
+       Keyword string
+       Uid     int64
+       Limit   int
+}
+
+// SearchRepositoryByName returns given number of repositories whose name contains keyword.
+func SearchRepositoryByName(opt SearchOption) (repos []*Repository, err error) {
+       // Prevent SQL inject.
+       opt.Keyword = strings.TrimSpace(opt.Keyword)
+       if len(opt.Keyword) == 0 {
+               return repos, nil
+       }
+
+       opt.Keyword = strings.Split(opt.Keyword, " ")[0]
+       if len(opt.Keyword) == 0 {
+               return repos, nil
+       }
+       opt.Keyword = strings.ToLower(opt.Keyword)
+
+       repos = make([]*Repository, 0, opt.Limit)
+
+       // Append conditions.
+       sess := x.Limit(opt.Limit)
+       if opt.Uid > 0 {
+               sess.Where("owner_id=?", opt.Uid)
+       }
+       sess.And("lower_name like '%" + opt.Keyword + "%'").Find(&repos)
+       return repos, err
+}
+
 // Watch is connection request for receiving repository notifycation.
 type Watch struct {
        Id     int64
index e8db1ad157985cd3af0b676dbe7f0cf9b82aff89..a74d803972067e28888eb3d117022abc580bb3af 100644 (file)
@@ -521,21 +521,21 @@ func GetUserByEmail(email string) (*User, error) {
 }
 
 // SearchUserByName returns given number of users whose name contains keyword.
-func SearchUserByName(key string, limit int) (us []*User, err error) {
+func SearchUserByName(opt SearchOption) (us []*User, err error) {
        // Prevent SQL inject.
-       key = strings.TrimSpace(key)
-       if len(key) == 0 {
+       opt.Keyword = strings.TrimSpace(opt.Keyword)
+       if len(opt.Keyword) == 0 {
                return us, nil
        }
 
-       key = strings.Split(key, " ")[0]
-       if len(key) == 0 {
+       opt.Keyword = strings.Split(opt.Keyword, " ")[0]
+       if len(opt.Keyword) == 0 {
                return us, nil
        }
-       key = strings.ToLower(key)
+       opt.Keyword = strings.ToLower(opt.Keyword)
 
-       us = make([]*User, 0, limit)
-       err = x.Limit(limit).Where("type=0").And("lower_name like '%" + key + "%'").Find(&us)
+       us = make([]*User, 0, opt.Limit)
+       err = x.Limit(opt.Limit).Where("type=0").And("lower_name like '%" + opt.Keyword + "%'").Find(&us)
        return us, err
 }
 
index 48468c7e80b8a28130b9f7a96368a0bda3cd741f..5ea7cf8f2dae7d46d86815c002f30d6a86897f36 100644 (file)
@@ -1298,32 +1298,38 @@ The register and sign-in page style
 .repo-setting-zone {
   padding: 30px;
 }
+#team-repositories-list,
 #team-members-list,
 #repo-collab-list {
   list-style: none;
   padding: 10px 0 5px 0;
 }
+#team-repositories-list li.collab,
 #team-members-list li.collab,
 #repo-collab-list li.collab {
   clear: both;
   height: 50px;
   padding: 0 15px 0 15px;
 }
+#team-repositories-list a.member,
 #team-members-list a.member,
 #repo-collab-list a.member {
   color: #444;
   height: 50px;
   line-height: 50px;
 }
+#team-repositories-list a.member:hover,
 #team-members-list a.member:hover,
 #repo-collab-list a.member:hover {
   color: #4183C4;
 }
+#team-repositories-list .avatar,
 #team-members-list .avatar,
 #repo-collab-list .avatar {
   margin-right: 1em;
   width: 40px;
 }
+#team-repositories-list .remove-collab,
 #team-members-list .remove-collab,
 #repo-collab-list .remove-collab {
   color: #DD4B39;
@@ -1877,14 +1883,26 @@ textarea#issue-add-content {
 #org-team-card .panel-footer {
   padding: 10px 20px;
 }
+#team-repositories-list .panel-body .search,
 #team-members-list .panel-body .search {
   padding: 4px 0 10px 10px;
   border-bottom: 1px solid #dddddd;
 }
+#team-repositories-list li.collab,
 #team-members-list li.collab {
   padding-top: 10px !important;
   border-bottom: 1px solid #dddddd;
 }
-#team-members-list li.collab:last-child {
-  border-bottom: 0;
+#team-repositories-list li:last-child,
+#team-members-list li:last-child {
+  border-bottom: 0 !important;
+}
+#team-repositories-list li a .octicon {
+  color: #888;
+}
+#team-repositories-list li .member {
+  color: #428bca;
+  font-size: 14px;
+  height: 40px;
+  line-height: 40px;
 }
index 52000f3664cc37753510b60d29b68e3b95145190..d4c3224eee8942befccd166da47329787e1a0dae 100644 (file)
@@ -218,6 +218,26 @@ var Gogs = {};
             }
         });
     }
+
+    // Search repositories by keyword.
+    Gogs.searchRepos = function (val, $target, $param) {
+        $.ajax({
+            url: '/api/v1/repos/search?q=' + val + '&' + $param,
+            dataType: "json",
+            success: function (json) {
+                if (json.ok && json.data.length) {
+                    var html = '';
+                    $.each(json.data, function (i, item) {
+                        html += '<li><a><span class="octicon octicon-repo"></span> ' + item.repolink + '</a></li>';
+                    });
+                    $target.html(html);
+                    $target.toggleShow();
+                } else {
+                    $target.toggleHide();
+                }
+            }
+        });
+    }
 })(jQuery);
 
 function initCore() {
@@ -358,7 +378,7 @@ function initOrgTeamCreate() {
             e.preventDefault();
             return true;
         }
-        var $form = $('#team-create-form')
+        var $form = $('#team-create-form');
         $form.attr('action', $form.data('delete-url'));
     });
 }
@@ -383,7 +403,28 @@ function initTeamMembersList() {
         $('#org-team-members-add').val($(this).text());
         $ul.toggleHide();
     });
+}
 
+function initTeamRepositoriesList() {
+    // Add team repository.
+    var $ul = $('#org-team-repositories-list');
+    $('#org-team-repositories-add').on('keyup', function () {
+        var $this = $(this);
+        if (!$this.val()) {
+            $ul.toggleHide();
+            return;
+        }
+        Gogs.searchRepos($this.val(), $ul, 'uid=' + $this.data('uid'));
+    }).on('focus', function () {
+        if (!$(this).val()) {
+            $ul.toggleHide();
+        } else {
+            $ul.toggleShow();
+        }
+    }).next().next().find('ul').on("click", 'li', function () {
+        $('#org-team-repositories-add').val($(this).text());
+        $ul.toggleHide();
+    });
 }
 
 $(document).ready(function () {
@@ -409,6 +450,9 @@ $(document).ready(function () {
     if ($('#team-members-list').length) {
         initTeamMembersList();
     }
+    if ($('#team-repositories-list').length) {
+        initTeamRepositoriesList();
+    }
 
     Tabs('#dashboard-sidebar-menu');
 
index a62dcbb3e043ac0ff0333f26bfeb8b643548a9dc..b6e31940a59bc84b28d8205031a7756de04d96e7 100644 (file)
@@ -1,3 +1,4 @@
+@import "../ui/var";
 .org-header-alert .alert {
        margin-top: 10px;
 }
                padding: 10px 20px;
        }
 }
+#team-repositories-list,
 #team-members-list {
        .panel-body .search {
                padding: 4px 0 10px 10px;
                border-bottom: 1px solid #dddddd;
        }
-}
-#team-members-list {
-       li.collab {
-               padding-top: 10px !important;
-               border-bottom: 1px solid #dddddd;
+       li {
+               &.collab {
+                       padding-top: 10px !important;
+                       border-bottom: 1px solid #dddddd;
+               }
                &:last-child {
-                       border-bottom: 0;
+                       border-bottom: 0 !important;
+               }
+       }
+}
+#team-repositories-list {
+       li {
+               a .octicon {
+                       color: #888;
+               }
+               .member {
+                       color: @linkColor;
+                       font-size: 14px;
+                       height: 40px;
+                       line-height: 40px;
                }
        }
 }
\ No newline at end of file
index 2f97289852e085652b341f76fb8a535742b2e587..4a49ac4368b45bfed3d09423c85920ce3d76883b 100644 (file)
@@ -426,6 +426,7 @@ border-top-right-radius: .25em;
 .repo-setting-zone {
        padding: 30px;
 }
+#team-repositories-list,
 #team-members-list,
 #repo-collab-list {
        list-style: none;
diff --git a/routers/api/v1/repos.go b/routers/api/v1/repos.go
new file mode 100644 (file)
index 0000000..67cf9e6
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package v1
+
+import (
+       "path"
+
+       "github.com/Unknwon/com"
+
+       "github.com/gogits/gogs/models"
+       "github.com/gogits/gogs/modules/middleware"
+)
+
+type repo struct {
+       RepoLink string `json:"repolink"`
+}
+
+func SearchRepos(ctx *middleware.Context) {
+       opt := models.SearchOption{
+               Keyword: path.Base(ctx.Query("q")),
+               Uid:     com.StrTo(ctx.Query("uid")).MustInt64(),
+               Limit:   com.StrTo(ctx.Query("limit")).MustInt(),
+       }
+       if opt.Limit == 0 {
+               opt.Limit = 10
+       }
+
+       repos, err := models.SearchRepositoryByName(opt)
+       if err != nil {
+               ctx.JSON(500, map[string]interface{}{
+                       "ok":    false,
+                       "error": err.Error(),
+               })
+               return
+       }
+
+       results := make([]*repo, len(repos))
+       for i := range repos {
+               if err = repos[i].GetOwner(); err != nil {
+                       ctx.JSON(500, map[string]interface{}{
+                               "ok":    false,
+                               "error": err.Error(),
+                       })
+                       return
+               }
+               results[i] = &repo{
+                       RepoLink: path.Join(repos[i].Owner.Name, repos[i].Name),
+               }
+       }
+
+       ctx.Render.JSON(200, map[string]interface{}{
+               "ok":   true,
+               "data": results,
+       })
+}
diff --git a/routers/api/v1/repositories.go b/routers/api/v1/repositories.go
deleted file mode 100644 (file)
index 11c8b6b..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2014 The Gogs Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package v1
-
-import (
-       "github.com/gogits/gogs/modules/middleware"
-)
-
-func SearchOrgRepositoreis(ctx *middleware.Context) {
-
-}
index fe67033748d327fe04494f76442f1c822dea2dd4..062c3680fcb26c900edb85899a1c0377b1825957 100644 (file)
@@ -17,21 +17,29 @@ type user struct {
 }
 
 func SearchUsers(ctx *middleware.Context) {
-       q := ctx.Query("q")
-       limit, err := com.StrTo(ctx.Query("limit")).Int()
-       if err != nil {
-               limit = 10
+       opt := models.SearchOption{
+               Keyword: ctx.Query("q"),
+               Limit:   com.StrTo(ctx.Query("limit")).MustInt(),
+       }
+       if opt.Limit == 0 {
+               opt.Limit = 10
        }
 
-       us, err := models.SearchUserByName(q, limit)
+       us, err := models.SearchUserByName(opt)
        if err != nil {
-               ctx.JSON(500, nil)
+               ctx.JSON(500, map[string]interface{}{
+                       "ok":    false,
+                       "error": err.Error(),
+               })
                return
        }
 
        results := make([]*user, len(us))
        for i := range us {
-               results[i] = &user{us[i].Name, us[i].AvatarLink()}
+               results[i] = &user{
+                       UserName:   us[i].Name,
+                       AvatarLink: us[i].AvatarLink(),
+               }
        }
 
        ctx.Render.JSON(200, map[string]interface{}{
index 4c986d4aa0c5c51b2fa07a1a03cd2405399c1aa0..b0a69da76e288b3ed6bb654174ba6d08bb8f9a9a 100644 (file)
@@ -5,6 +5,8 @@
 package org
 
 import (
+       "path"
+
        "github.com/Unknwon/com"
 
        "github.com/gogits/gogs/models"
@@ -15,9 +17,10 @@ import (
 )
 
 const (
-       TEAMS        base.TplName = "org/team/teams"
-       TEAM_NEW     base.TplName = "org/team/new"
-       TEAM_MEMBERS base.TplName = "org/team/members"
+       TEAMS             base.TplName = "org/team/teams"
+       TEAM_NEW          base.TplName = "org/team/new"
+       TEAM_MEMBERS      base.TplName = "org/team/members"
+       TEAM_REPOSITORIES base.TplName = "org/team/repositories"
 )
 
 func Teams(ctx *middleware.Context) {
@@ -108,6 +111,38 @@ func TeamsAction(ctx *middleware.Context) {
        }
 }
 
+func TeamsRepoAction(ctx *middleware.Context) {
+       if !ctx.Org.IsOwner {
+               ctx.Error(404)
+               return
+       }
+
+       var err error
+       switch ctx.Params(":action") {
+       case "add":
+               repoName := path.Base(ctx.Query("repo-name"))
+               var repo *models.Repository
+               repo, err = models.GetRepositoryByName(ctx.Org.Organization.Id, repoName)
+               if err != nil {
+                       ctx.Handle(500, "GetRepositoryByName", err)
+                       return
+               }
+               err = ctx.Org.Team.AddRepository(repo)
+       case "remove":
+               err = ctx.Org.Team.RemoveRepository(com.StrTo(ctx.Query("repoid")).MustInt64())
+       }
+
+       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/" + ctx.Org.Team.LowerName + "/repositories")
+}
+
 func NewTeam(ctx *middleware.Context) {
        ctx.Data["Title"] = ctx.Org.Organization.FullName
        ctx.Data["PageIsOrgTeams"] = true
@@ -176,6 +211,16 @@ func TeamMembers(ctx *middleware.Context) {
        ctx.HTML(200, TEAM_MEMBERS)
 }
 
+func TeamRepositories(ctx *middleware.Context) {
+       ctx.Data["Title"] = ctx.Org.Team.Name
+       ctx.Data["PageIsOrgTeams"] = true
+       if err := ctx.Org.Team.GetRepositories(); err != nil {
+               ctx.Handle(500, "GetRepositories", err)
+               return
+       }
+       ctx.HTML(200, TEAM_REPOSITORIES)
+}
+
 func EditTeam(ctx *middleware.Context) {
        ctx.Data["Title"] = ctx.Org.Organization.FullName
        ctx.Data["PageIsOrgTeams"] = true
index f4c20dee1e285ab702eb1811e0673ecb6dea9c83..35fc8ef1104b8d97f9dcc8478b246bb412bdd279 100644 (file)
@@ -1 +1 @@
-0.4.7.0825 Alpha
\ No newline at end of file
+0.4.7.0826 Alpha
\ No newline at end of file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0a3f771068df152f406d5759fc081a38844907e6 100644 (file)
@@ -0,0 +1,45 @@
+{{template "ng/base/head" .}}
+{{template "ng/base/header" .}}
+{{template "org/base/header" .}}
+<div id="setting-wrapper" class="main-wrapper">
+    <div id="team-members-list" class="container clear">
+               {{template "ng/base/alert" .}}
+               {{template "org/team/sidebar" .}}
+               <div class="grid-2-3 left">
+                       <div class="setting-content">
+                               <div class="panel panel-radius">
+                                       <div class="panel-header">
+                                               {{.i18n.Tr "org.teams.repositories"}}
+                                       </div>
+                                       {{$canAddRemove := and $.IsOrganizationOwner (not (eq $.Team.LowerName "owners"))}}
+                    <ul class="panel-body setting-list" id="team-repositories-list">
+                       {{if $canAddRemove}}
+                                               <li class="search">
+                                       <form class="form form-align" action="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/add" id="repo-collab-form">
+                                           {{.CsrfTokenHtml}}
+                                <input class="ipt ipt-large ipt-radius" id="org-team-repositories-add" name="repo-name" autocomplete="off" data-uid="{{.Org.Id}}" required />
+                                <button class="btn btn-blue btn-large btn-radius">{{.i18n.Tr "org.teams.add_team_repository"}}</button>
+                                                               <div class="repo-user-list-block">
+                                                                       <ul class="menu-down-show menu-vertical menu-radius switching-list user-list" id="org-team-repositories-list"></ul>
+                                                               </div>
+                                       </form>
+                                               </li>
+                                               {{end}}
+                               {{range .Team.Repos}}
+                               <li class="collab">
+                                       {{if $canAddRemove}}
+                                                       <a class="btn btn-small btn-red btn-radius right" href="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/remove?repoid={{.Id}}">{{$.i18n.Tr "org.teams.remove_repo"}}</a>
+                                                       {{end}}
+                                                       <a class="member" href="/{{$.Org.Name}}/{{.Name}}">
+                                <i class="octicon octicon-{{if .IsPrivate}}lock{{else if .IsFork}}repo-forked{{else if .IsMirror}}repo-clone{{else}}repo{{end}}"></i>
+                                                           <strong>{{$.Org.Name}}/{{.Name}}</strong>
+                                                       </a>
+                               </li>
+                               {{end}}
+                    </ul>
+                               </div>
+                       </div>
+               </div>
+       </div>
+</div>
+{{template "ng/base/footer" .}}
\ No newline at end of file
index b760e002fc8c6b32d66837e039be220900c5a294..2015884f457c3334a7c321369031b470ff781210 100644 (file)
@@ -11,8 +11,8 @@
        <p class="desc">{{if .Team.Description}}{{.Team.Description}}{{else}}{{.i18n.Tr "org.teams.no_desc"}}{{end}}</p>
        <hr>
        <div class="team-stats">
-               <a class="text-black" href="{{.OrgLink}}/teams/{{.Team.LowerName}}"><strong>{{.Team.NumMembers}}</strong> {{$.i18n.Tr "org.lower_members"}}</a> ·
-               <a class="text-black" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/repositories"><strong>{{.Team.NumRepos}}</strong> {{$.i18n.Tr "org.lower_repositories"}}</a>
+               <a class="text-black" href="{{.OrgLink}}/teams/{{.Team.LowerName}}"><span class="octicon octicon-person"></span> <strong>{{.Team.NumMembers}}</strong> {{$.i18n.Tr "org.lower_members"}}</a> ·
+               <a class="text-black" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/repositories"><span class="octicon octicon-repo"></span> <strong>{{.Team.NumRepos}}</strong> {{$.i18n.Tr "org.lower_repositories"}}</a>
        </div>
        <p class="desc">
                {{if eq .Team.LowerName "owners"}}