code.gitea.io/gitea@v1.21.7/routers/web/repo/setting/collaboration.go (about) 1 // Copyright 2023 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package setting 5 6 import ( 7 "net/http" 8 "strings" 9 10 "code.gitea.io/gitea/models/db" 11 "code.gitea.io/gitea/models/organization" 12 "code.gitea.io/gitea/models/perm" 13 repo_model "code.gitea.io/gitea/models/repo" 14 unit_model "code.gitea.io/gitea/models/unit" 15 user_model "code.gitea.io/gitea/models/user" 16 "code.gitea.io/gitea/modules/context" 17 "code.gitea.io/gitea/modules/log" 18 repo_module "code.gitea.io/gitea/modules/repository" 19 "code.gitea.io/gitea/modules/setting" 20 "code.gitea.io/gitea/routers/utils" 21 "code.gitea.io/gitea/services/mailer" 22 org_service "code.gitea.io/gitea/services/org" 23 repo_service "code.gitea.io/gitea/services/repository" 24 ) 25 26 // Collaboration render a repository's collaboration page 27 func Collaboration(ctx *context.Context) { 28 ctx.Data["Title"] = ctx.Tr("repo.settings.collaboration") 29 ctx.Data["PageIsSettingsCollaboration"] = true 30 31 users, err := repo_model.GetCollaborators(ctx, ctx.Repo.Repository.ID, db.ListOptions{}) 32 if err != nil { 33 ctx.ServerError("GetCollaborators", err) 34 return 35 } 36 ctx.Data["Collaborators"] = users 37 38 teams, err := organization.GetRepoTeams(ctx, ctx.Repo.Repository) 39 if err != nil { 40 ctx.ServerError("GetRepoTeams", err) 41 return 42 } 43 ctx.Data["Teams"] = teams 44 ctx.Data["Repo"] = ctx.Repo.Repository 45 ctx.Data["OrgID"] = ctx.Repo.Repository.OwnerID 46 ctx.Data["OrgName"] = ctx.Repo.Repository.OwnerName 47 ctx.Data["Org"] = ctx.Repo.Repository.Owner 48 ctx.Data["Units"] = unit_model.Units 49 50 ctx.HTML(http.StatusOK, tplCollaboration) 51 } 52 53 // CollaborationPost response for actions for a collaboration of a repository 54 func CollaborationPost(ctx *context.Context) { 55 name := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.FormString("collaborator"))) 56 if len(name) == 0 || ctx.Repo.Owner.LowerName == name { 57 ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath()) 58 return 59 } 60 61 u, err := user_model.GetUserByName(ctx, name) 62 if err != nil { 63 if user_model.IsErrUserNotExist(err) { 64 ctx.Flash.Error(ctx.Tr("form.user_not_exist")) 65 ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath()) 66 } else { 67 ctx.ServerError("GetUserByName", err) 68 } 69 return 70 } 71 72 if !u.IsActive { 73 ctx.Flash.Error(ctx.Tr("repo.settings.add_collaborator_inactive_user")) 74 ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath()) 75 return 76 } 77 78 // Organization is not allowed to be added as a collaborator. 79 if u.IsOrganization() { 80 ctx.Flash.Error(ctx.Tr("repo.settings.org_not_allowed_to_be_collaborator")) 81 ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath()) 82 return 83 } 84 85 if got, err := repo_model.IsCollaborator(ctx, ctx.Repo.Repository.ID, u.ID); err == nil && got { 86 ctx.Flash.Error(ctx.Tr("repo.settings.add_collaborator_duplicate")) 87 ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration") 88 return 89 } 90 91 // find the owner team of the organization the repo belongs too and 92 // check if the user we're trying to add is an owner. 93 if ctx.Repo.Repository.Owner.IsOrganization() { 94 if isOwner, err := organization.IsOrganizationOwner(ctx, ctx.Repo.Repository.Owner.ID, u.ID); err != nil { 95 ctx.ServerError("IsOrganizationOwner", err) 96 return 97 } else if isOwner { 98 ctx.Flash.Error(ctx.Tr("repo.settings.add_collaborator_owner")) 99 ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath()) 100 return 101 } 102 } 103 104 if err = repo_module.AddCollaborator(ctx, ctx.Repo.Repository, u); err != nil { 105 ctx.ServerError("AddCollaborator", err) 106 return 107 } 108 109 if setting.Service.EnableNotifyMail { 110 mailer.SendCollaboratorMail(u, ctx.Doer, ctx.Repo.Repository) 111 } 112 113 ctx.Flash.Success(ctx.Tr("repo.settings.add_collaborator_success")) 114 ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath()) 115 } 116 117 // ChangeCollaborationAccessMode response for changing access of a collaboration 118 func ChangeCollaborationAccessMode(ctx *context.Context) { 119 if err := repo_model.ChangeCollaborationAccessMode( 120 ctx, 121 ctx.Repo.Repository, 122 ctx.FormInt64("uid"), 123 perm.AccessMode(ctx.FormInt("mode"))); err != nil { 124 log.Error("ChangeCollaborationAccessMode: %v", err) 125 } 126 } 127 128 // DeleteCollaboration delete a collaboration for a repository 129 func DeleteCollaboration(ctx *context.Context) { 130 if err := repo_service.DeleteCollaboration(ctx, ctx.Repo.Repository, ctx.FormInt64("id")); err != nil { 131 ctx.Flash.Error("DeleteCollaboration: " + err.Error()) 132 } else { 133 ctx.Flash.Success(ctx.Tr("repo.settings.remove_collaborator_success")) 134 } 135 136 ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings/collaboration") 137 } 138 139 // AddTeamPost response for adding a team to a repository 140 func AddTeamPost(ctx *context.Context) { 141 if !ctx.Repo.Owner.RepoAdminChangeTeamAccess && !ctx.Repo.IsOwner() { 142 ctx.Flash.Error(ctx.Tr("repo.settings.change_team_access_not_allowed")) 143 ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration") 144 return 145 } 146 147 name := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.FormString("team"))) 148 if len(name) == 0 { 149 ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration") 150 return 151 } 152 153 team, err := organization.OrgFromUser(ctx.Repo.Owner).GetTeam(ctx, name) 154 if err != nil { 155 if organization.IsErrTeamNotExist(err) { 156 ctx.Flash.Error(ctx.Tr("form.team_not_exist")) 157 ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration") 158 } else { 159 ctx.ServerError("GetTeam", err) 160 } 161 return 162 } 163 164 if team.OrgID != ctx.Repo.Repository.OwnerID { 165 ctx.Flash.Error(ctx.Tr("repo.settings.team_not_in_organization")) 166 ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration") 167 return 168 } 169 170 if organization.HasTeamRepo(ctx, ctx.Repo.Repository.OwnerID, team.ID, ctx.Repo.Repository.ID) { 171 ctx.Flash.Error(ctx.Tr("repo.settings.add_team_duplicate")) 172 ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration") 173 return 174 } 175 176 if err = org_service.TeamAddRepository(ctx, team, ctx.Repo.Repository); err != nil { 177 ctx.ServerError("TeamAddRepository", err) 178 return 179 } 180 181 ctx.Flash.Success(ctx.Tr("repo.settings.add_team_success")) 182 ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration") 183 } 184 185 // DeleteTeam response for deleting a team from a repository 186 func DeleteTeam(ctx *context.Context) { 187 if !ctx.Repo.Owner.RepoAdminChangeTeamAccess && !ctx.Repo.IsOwner() { 188 ctx.Flash.Error(ctx.Tr("repo.settings.change_team_access_not_allowed")) 189 ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration") 190 return 191 } 192 193 team, err := organization.GetTeamByID(ctx, ctx.FormInt64("id")) 194 if err != nil { 195 ctx.ServerError("GetTeamByID", err) 196 return 197 } 198 199 if err = repo_service.RemoveRepositoryFromTeam(ctx, team, ctx.Repo.Repository.ID); err != nil { 200 ctx.ServerError("team.RemoveRepositorys", err) 201 return 202 } 203 204 ctx.Flash.Success(ctx.Tr("repo.settings.remove_team_success")) 205 ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings/collaboration") 206 }