mirror of
https://github.com/go-gitea/gitea
synced 2025-08-09 02:58:20 +00:00
Add teams to repo on collaboration page. (#8045)
* Add teams to repo on collaboration page. Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Add option for repository admins to change teams access to repo. Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Add comment for functions Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Make RepoAdminChangeTeamAccess default false in xorm and make it default checked in template instead. Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Make proper language strings and fix error redirection. * Add unit tests for adding and deleting team from repository. Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Add database migration Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Fix redirect Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Fix locale string mismatch. Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Move team access mode text logic to template. * Move collaborator access mode text logic to template.
This commit is contained in:
committed by
Lauris BH
parent
63ff61615e
commit
a0e88dfc2e
@@ -490,6 +490,18 @@ func Collaboration(ctx *context.Context) {
|
||||
}
|
||||
ctx.Data["Collaborators"] = users
|
||||
|
||||
teams, err := ctx.Repo.Repository.GetRepoTeams()
|
||||
if err != nil {
|
||||
ctx.ServerError("GetRepoTeams", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Teams"] = teams
|
||||
ctx.Data["Repo"] = ctx.Repo.Repository
|
||||
ctx.Data["OrgID"] = ctx.Repo.Repository.OwnerID
|
||||
ctx.Data["OrgName"] = ctx.Repo.Repository.OwnerName
|
||||
ctx.Data["Org"] = ctx.Repo.Repository.Owner
|
||||
ctx.Data["Units"] = models.Units
|
||||
|
||||
ctx.HTML(200, tplCollaboration)
|
||||
}
|
||||
|
||||
@@ -566,6 +578,77 @@ func DeleteCollaboration(ctx *context.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// AddTeamPost response for adding a team to a repository
|
||||
func AddTeamPost(ctx *context.Context) {
|
||||
if !ctx.Repo.Owner.RepoAdminChangeTeamAccess && !ctx.Repo.IsOwner() {
|
||||
ctx.Flash.Error(ctx.Tr("repo.settings.change_team_access_not_allowed"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||
return
|
||||
}
|
||||
|
||||
name := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.Query("team")))
|
||||
if len(name) == 0 || ctx.Repo.Owner.LowerName == name {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||
return
|
||||
}
|
||||
|
||||
team, err := ctx.Repo.Owner.GetTeam(name)
|
||||
if err != nil {
|
||||
if models.IsErrTeamNotExist(err) {
|
||||
ctx.Flash.Error(ctx.Tr("form.team_not_exist"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||
} else {
|
||||
ctx.ServerError("GetTeam", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if team.OrgID != ctx.Repo.Repository.OwnerID {
|
||||
ctx.Flash.Error(ctx.Tr("repo.settings.team_not_in_organization"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||
return
|
||||
}
|
||||
|
||||
if models.HasTeamRepo(ctx.Repo.Repository.OwnerID, team.ID, ctx.Repo.Repository.ID) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.settings.add_team_duplicate"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||
return
|
||||
}
|
||||
|
||||
if err = team.AddRepository(ctx.Repo.Repository); err != nil {
|
||||
ctx.ServerError("team.AddRepository", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.add_team_success"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||
}
|
||||
|
||||
// DeleteTeam response for deleting a team from a repository
|
||||
func DeleteTeam(ctx *context.Context) {
|
||||
if !ctx.Repo.Owner.RepoAdminChangeTeamAccess && !ctx.Repo.IsOwner() {
|
||||
ctx.Flash.Error(ctx.Tr("repo.settings.change_team_access_not_allowed"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||
return
|
||||
}
|
||||
|
||||
team, err := models.GetTeamByID(ctx.QueryInt64("id"))
|
||||
if err != nil {
|
||||
ctx.ServerError("GetTeamByID", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = team.RemoveRepository(ctx.Repo.Repository.ID); err != nil {
|
||||
ctx.ServerError("team.RemoveRepositorys", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.remove_team_success"))
|
||||
ctx.JSON(200, map[string]interface{}{
|
||||
"redirect": ctx.Repo.RepoLink + "/settings/collaboration",
|
||||
})
|
||||
}
|
||||
|
||||
// parseOwnerAndRepo get repos by owner
|
||||
func parseOwnerAndRepo(ctx *context.Context) (*models.User, *models.Repository) {
|
||||
owner, err := models.GetUserByName(ctx.Params(":username"))
|
||||
|
@@ -185,3 +185,196 @@ func TestCollaborationPost_NonExistentUser(t *testing.T) {
|
||||
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
|
||||
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
|
||||
}
|
||||
|
||||
func TestAddTeamPost(t *testing.T) {
|
||||
models.PrepareTestEnv(t)
|
||||
ctx := test.MockContext(t, "org26/repo43")
|
||||
|
||||
ctx.Req.Form.Set("team", "team11")
|
||||
|
||||
org := &models.User{
|
||||
LowerName: "org26",
|
||||
Type: models.UserTypeOrganization,
|
||||
}
|
||||
|
||||
team := &models.Team{
|
||||
ID: 11,
|
||||
OrgID: 26,
|
||||
}
|
||||
|
||||
re := &models.Repository{
|
||||
ID: 43,
|
||||
Owner: org,
|
||||
OwnerID: 26,
|
||||
}
|
||||
|
||||
repo := &context.Repository{
|
||||
Owner: &models.User{
|
||||
ID: 26,
|
||||
LowerName: "org26",
|
||||
RepoAdminChangeTeamAccess: true,
|
||||
},
|
||||
Repository: re,
|
||||
}
|
||||
|
||||
ctx.Repo = repo
|
||||
|
||||
AddTeamPost(ctx)
|
||||
|
||||
assert.True(t, team.HasRepository(re.ID))
|
||||
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
|
||||
assert.Empty(t, ctx.Flash.ErrorMsg)
|
||||
}
|
||||
|
||||
func TestAddTeamPost_NotAllowed(t *testing.T) {
|
||||
models.PrepareTestEnv(t)
|
||||
ctx := test.MockContext(t, "org26/repo43")
|
||||
|
||||
ctx.Req.Form.Set("team", "team11")
|
||||
|
||||
org := &models.User{
|
||||
LowerName: "org26",
|
||||
Type: models.UserTypeOrganization,
|
||||
}
|
||||
|
||||
team := &models.Team{
|
||||
ID: 11,
|
||||
OrgID: 26,
|
||||
}
|
||||
|
||||
re := &models.Repository{
|
||||
ID: 43,
|
||||
Owner: org,
|
||||
OwnerID: 26,
|
||||
}
|
||||
|
||||
repo := &context.Repository{
|
||||
Owner: &models.User{
|
||||
ID: 26,
|
||||
LowerName: "org26",
|
||||
RepoAdminChangeTeamAccess: false,
|
||||
},
|
||||
Repository: re,
|
||||
}
|
||||
|
||||
ctx.Repo = repo
|
||||
|
||||
AddTeamPost(ctx)
|
||||
|
||||
assert.False(t, team.HasRepository(re.ID))
|
||||
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
|
||||
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
|
||||
|
||||
}
|
||||
|
||||
func TestAddTeamPost_AddTeamTwice(t *testing.T) {
|
||||
models.PrepareTestEnv(t)
|
||||
ctx := test.MockContext(t, "org26/repo43")
|
||||
|
||||
ctx.Req.Form.Set("team", "team11")
|
||||
|
||||
org := &models.User{
|
||||
LowerName: "org26",
|
||||
Type: models.UserTypeOrganization,
|
||||
}
|
||||
|
||||
team := &models.Team{
|
||||
ID: 11,
|
||||
OrgID: 26,
|
||||
}
|
||||
|
||||
re := &models.Repository{
|
||||
ID: 43,
|
||||
Owner: org,
|
||||
OwnerID: 26,
|
||||
}
|
||||
|
||||
repo := &context.Repository{
|
||||
Owner: &models.User{
|
||||
ID: 26,
|
||||
LowerName: "org26",
|
||||
RepoAdminChangeTeamAccess: true,
|
||||
},
|
||||
Repository: re,
|
||||
}
|
||||
|
||||
ctx.Repo = repo
|
||||
|
||||
AddTeamPost(ctx)
|
||||
|
||||
AddTeamPost(ctx)
|
||||
assert.True(t, team.HasRepository(re.ID))
|
||||
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
|
||||
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
|
||||
}
|
||||
|
||||
func TestAddTeamPost_NonExistentTeam(t *testing.T) {
|
||||
models.PrepareTestEnv(t)
|
||||
ctx := test.MockContext(t, "org26/repo43")
|
||||
|
||||
ctx.Req.Form.Set("team", "team-non-existent")
|
||||
|
||||
org := &models.User{
|
||||
LowerName: "org26",
|
||||
Type: models.UserTypeOrganization,
|
||||
}
|
||||
|
||||
re := &models.Repository{
|
||||
ID: 43,
|
||||
Owner: org,
|
||||
OwnerID: 26,
|
||||
}
|
||||
|
||||
repo := &context.Repository{
|
||||
Owner: &models.User{
|
||||
ID: 26,
|
||||
LowerName: "org26",
|
||||
RepoAdminChangeTeamAccess: true,
|
||||
},
|
||||
Repository: re,
|
||||
}
|
||||
|
||||
ctx.Repo = repo
|
||||
|
||||
AddTeamPost(ctx)
|
||||
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
|
||||
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
|
||||
}
|
||||
|
||||
func TestDeleteTeam(t *testing.T) {
|
||||
models.PrepareTestEnv(t)
|
||||
ctx := test.MockContext(t, "org3/team1/repo3")
|
||||
|
||||
ctx.Req.Form.Set("id", "2")
|
||||
|
||||
org := &models.User{
|
||||
LowerName: "org3",
|
||||
Type: models.UserTypeOrganization,
|
||||
}
|
||||
|
||||
team := &models.Team{
|
||||
ID: 2,
|
||||
OrgID: 3,
|
||||
}
|
||||
|
||||
re := &models.Repository{
|
||||
ID: 3,
|
||||
Owner: org,
|
||||
OwnerID: 3,
|
||||
}
|
||||
|
||||
repo := &context.Repository{
|
||||
Owner: &models.User{
|
||||
ID: 3,
|
||||
LowerName: "org3",
|
||||
RepoAdminChangeTeamAccess: true,
|
||||
},
|
||||
Repository: re,
|
||||
}
|
||||
|
||||
ctx.Repo = repo
|
||||
|
||||
DeleteTeam(ctx)
|
||||
|
||||
assert.False(t, team.HasRepository(re.ID))
|
||||
}
|
||||
|
Reference in New Issue
Block a user