aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/web.go4
-rw-r--r--conf/locale/locale_en-US.ini3
-rw-r--r--conf/locale/locale_zh-CN.ini3
-rw-r--r--gogs.go2
-rw-r--r--models/access.go8
-rw-r--r--models/org.go230
-rw-r--r--models/repo.go36
-rw-r--r--models/user.go16
-rw-r--r--public/ng/css/gogs.css22
-rw-r--r--public/ng/js/gogs.js46
-rw-r--r--public/ng/less/gogs/organization.less27
-rw-r--r--public/ng/less/gogs/repository.less1
-rw-r--r--routers/api/v1/repos.go57
-rw-r--r--routers/api/v1/repositories.go13
-rw-r--r--routers/api/v1/users.go22
-rw-r--r--routers/org/teams.go51
-rw-r--r--templates/.VERSION2
-rw-r--r--templates/org/team/repositories.tmpl45
-rw-r--r--templates/org/team/sidebar.tmpl4
19 files changed, 485 insertions, 107 deletions
diff --git a/cmd/web.go b/cmd/web.go
index 0b3b84ab6a..cc9fa385c3 100644
--- a/cmd/web.go
+++ b/cmd/web.go
@@ -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) {
diff --git a/conf/locale/locale_en-US.ini b/conf/locale/locale_en-US.ini
index 9437bfd197..25384b03fe 100644
--- a/conf/locale/locale_en-US.ini
+++ b/conf/locale/locale_en-US.ini
@@ -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>
diff --git a/conf/locale/locale_zh-CN.ini b/conf/locale/locale_zh-CN.ini
index dbc94f3a0c..1b3329e6f8 100644
--- a/conf/locale/locale_zh-CN.ini
+++ b/conf/locale/locale_zh-CN.ini
@@ -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 bdd19cfffe..4adac90b99 100644
--- 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())
diff --git a/models/access.go b/models/access.go
index 5238daba32..81aa43dc78 100644
--- a/models/access.go
+++ b/models/access.go
@@ -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.
diff --git a/models/org.go b/models/org.go
index 27228382d3..5d73cf3ff2 100644
--- a/models/org.go
+++ b/models/org.go
@@ -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
}
}
diff --git a/models/repo.go b/models/repo.go
index f5d1ca834e..c3e9423f45 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -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
diff --git a/models/user.go b/models/user.go
index e8db1ad157..a74d803972 100644
--- a/models/user.go
+++ b/models/user.go
@@ -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
}
diff --git a/public/ng/css/gogs.css b/public/ng/css/gogs.css
index 48468c7e80..5ea7cf8f2d 100644
--- a/public/ng/css/gogs.css
+++ b/public/ng/css/gogs.css
@@ -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;
}
diff --git a/public/ng/js/gogs.js b/public/ng/js/gogs.js
index 52000f3664..d4c3224eee 100644
--- a/public/ng/js/gogs.js
+++ b/public/ng/js/gogs.js
@@ -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');
diff --git a/public/ng/less/gogs/organization.less b/public/ng/less/gogs/organization.less
index a62dcbb3e0..b6e31940a5 100644
--- a/public/ng/less/gogs/organization.less
+++ b/public/ng/less/gogs/organization.less
@@ -1,3 +1,4 @@
+@import "../ui/var";
.org-header-alert .alert {
margin-top: 10px;
}
@@ -197,18 +198,32 @@
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
diff --git a/public/ng/less/gogs/repository.less b/public/ng/less/gogs/repository.less
index 2f97289852..4a49ac4368 100644
--- a/public/ng/less/gogs/repository.less
+++ b/public/ng/less/gogs/repository.less
@@ -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
index 0000000000..67cf9e654c
--- /dev/null
+++ b/routers/api/v1/repos.go
@@ -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
index 11c8b6b2e3..0000000000
--- a/routers/api/v1/repositories.go
+++ /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) {
-
-}
diff --git a/routers/api/v1/users.go b/routers/api/v1/users.go
index fe67033748..062c3680fc 100644
--- a/routers/api/v1/users.go
+++ b/routers/api/v1/users.go
@@ -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{}{
diff --git a/routers/org/teams.go b/routers/org/teams.go
index 4c986d4aa0..b0a69da76e 100644
--- a/routers/org/teams.go
+++ b/routers/org/teams.go
@@ -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
diff --git a/templates/.VERSION b/templates/.VERSION
index f4c20dee1e..35fc8ef110 100644
--- a/templates/.VERSION
+++ b/templates/.VERSION
@@ -1 +1 @@
-0.4.7.0825 Alpha \ No newline at end of file
+0.4.7.0826 Alpha \ No newline at end of file
diff --git a/templates/org/team/repositories.tmpl b/templates/org/team/repositories.tmpl
index e69de29bb2..0a3f771068 100644
--- a/templates/org/team/repositories.tmpl
+++ b/templates/org/team/repositories.tmpl
@@ -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
diff --git a/templates/org/team/sidebar.tmpl b/templates/org/team/sidebar.tmpl
index b760e002fc..2015884f45 100644
--- a/templates/org/team/sidebar.tmpl
+++ b/templates/org/team/sidebar.tmpl
@@ -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"}}