code.gitea.io/gitea@v1.21.7/routers/web/repo/issue_label.go (about) 1 // Copyright 2017 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package repo 5 6 import ( 7 "net/http" 8 9 "code.gitea.io/gitea/models/db" 10 issues_model "code.gitea.io/gitea/models/issues" 11 "code.gitea.io/gitea/models/organization" 12 "code.gitea.io/gitea/modules/base" 13 "code.gitea.io/gitea/modules/context" 14 "code.gitea.io/gitea/modules/label" 15 "code.gitea.io/gitea/modules/log" 16 repo_module "code.gitea.io/gitea/modules/repository" 17 "code.gitea.io/gitea/modules/timeutil" 18 "code.gitea.io/gitea/modules/web" 19 "code.gitea.io/gitea/services/forms" 20 issue_service "code.gitea.io/gitea/services/issue" 21 ) 22 23 const ( 24 tplLabels base.TplName = "repo/issue/labels" 25 ) 26 27 // Labels render issue's labels page 28 func Labels(ctx *context.Context) { 29 ctx.Data["Title"] = ctx.Tr("repo.labels") 30 ctx.Data["PageIsIssueList"] = true 31 ctx.Data["PageIsLabels"] = true 32 ctx.Data["LabelTemplateFiles"] = repo_module.LabelTemplateFiles 33 ctx.HTML(http.StatusOK, tplLabels) 34 } 35 36 // InitializeLabels init labels for a repository 37 func InitializeLabels(ctx *context.Context) { 38 form := web.GetForm(ctx).(*forms.InitializeLabelsForm) 39 if ctx.HasError() { 40 ctx.Redirect(ctx.Repo.RepoLink + "/labels") 41 return 42 } 43 44 if err := repo_module.InitializeLabels(ctx, ctx.Repo.Repository.ID, form.TemplateName, false); err != nil { 45 if label.IsErrTemplateLoad(err) { 46 originalErr := err.(label.ErrTemplateLoad).OriginalError 47 ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, originalErr)) 48 ctx.Redirect(ctx.Repo.RepoLink + "/labels") 49 return 50 } 51 ctx.ServerError("InitializeLabels", err) 52 return 53 } 54 ctx.Redirect(ctx.Repo.RepoLink + "/labels") 55 } 56 57 // RetrieveLabels find all the labels of a repository and organization 58 func RetrieveLabels(ctx *context.Context) { 59 labels, err := issues_model.GetLabelsByRepoID(ctx, ctx.Repo.Repository.ID, ctx.FormString("sort"), db.ListOptions{}) 60 if err != nil { 61 ctx.ServerError("RetrieveLabels.GetLabels", err) 62 return 63 } 64 65 for _, l := range labels { 66 l.CalOpenIssues() 67 } 68 69 ctx.Data["Labels"] = labels 70 71 if ctx.Repo.Owner.IsOrganization() { 72 orgLabels, err := issues_model.GetLabelsByOrgID(ctx, ctx.Repo.Owner.ID, ctx.FormString("sort"), db.ListOptions{}) 73 if err != nil { 74 ctx.ServerError("GetLabelsByOrgID", err) 75 return 76 } 77 for _, l := range orgLabels { 78 l.CalOpenOrgIssues(ctx, ctx.Repo.Repository.ID, l.ID) 79 } 80 ctx.Data["OrgLabels"] = orgLabels 81 82 org, err := organization.GetOrgByName(ctx, ctx.Repo.Owner.LowerName) 83 if err != nil { 84 ctx.ServerError("GetOrgByName", err) 85 return 86 } 87 if ctx.Doer != nil { 88 ctx.Org.IsOwner, err = org.IsOwnedBy(ctx.Doer.ID) 89 if err != nil { 90 ctx.ServerError("org.IsOwnedBy", err) 91 return 92 } 93 ctx.Org.OrgLink = org.AsUser().OrganisationLink() 94 ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner 95 ctx.Data["OrganizationLink"] = ctx.Org.OrgLink 96 } 97 } 98 ctx.Data["NumLabels"] = len(labels) 99 ctx.Data["SortType"] = ctx.FormString("sort") 100 } 101 102 // NewLabel create new label for repository 103 func NewLabel(ctx *context.Context) { 104 form := web.GetForm(ctx).(*forms.CreateLabelForm) 105 ctx.Data["Title"] = ctx.Tr("repo.labels") 106 ctx.Data["PageIsLabels"] = true 107 108 if ctx.HasError() { 109 ctx.Flash.Error(ctx.Data["ErrorMsg"].(string)) 110 ctx.Redirect(ctx.Repo.RepoLink + "/labels") 111 return 112 } 113 114 l := &issues_model.Label{ 115 RepoID: ctx.Repo.Repository.ID, 116 Name: form.Title, 117 Exclusive: form.Exclusive, 118 Description: form.Description, 119 Color: form.Color, 120 ArchivedUnix: timeutil.TimeStamp(0), 121 } 122 if err := issues_model.NewLabel(ctx, l); err != nil { 123 ctx.ServerError("NewLabel", err) 124 return 125 } 126 ctx.Redirect(ctx.Repo.RepoLink + "/labels") 127 } 128 129 // UpdateLabel update a label's name and color 130 func UpdateLabel(ctx *context.Context) { 131 form := web.GetForm(ctx).(*forms.CreateLabelForm) 132 l, err := issues_model.GetLabelInRepoByID(ctx, ctx.Repo.Repository.ID, form.ID) 133 if err != nil { 134 switch { 135 case issues_model.IsErrRepoLabelNotExist(err): 136 ctx.Error(http.StatusNotFound) 137 default: 138 ctx.ServerError("UpdateLabel", err) 139 } 140 return 141 } 142 l.Name = form.Title 143 l.Exclusive = form.Exclusive 144 l.Description = form.Description 145 l.Color = form.Color 146 147 l.SetArchived(form.IsArchived) 148 if err := issues_model.UpdateLabel(ctx, l); err != nil { 149 ctx.ServerError("UpdateLabel", err) 150 return 151 } 152 ctx.Redirect(ctx.Repo.RepoLink + "/labels") 153 } 154 155 // DeleteLabel delete a label 156 func DeleteLabel(ctx *context.Context) { 157 if err := issues_model.DeleteLabel(ctx, ctx.Repo.Repository.ID, ctx.FormInt64("id")); err != nil { 158 ctx.Flash.Error("DeleteLabel: " + err.Error()) 159 } else { 160 ctx.Flash.Success(ctx.Tr("repo.issues.label_deletion_success")) 161 } 162 163 ctx.JSONRedirect(ctx.Repo.RepoLink + "/labels") 164 } 165 166 // UpdateIssueLabel change issue's labels 167 func UpdateIssueLabel(ctx *context.Context) { 168 issues := getActionIssues(ctx) 169 if ctx.Written() { 170 return 171 } 172 173 switch action := ctx.FormString("action"); action { 174 case "clear": 175 for _, issue := range issues { 176 if err := issue_service.ClearLabels(ctx, issue, ctx.Doer); err != nil { 177 ctx.ServerError("ClearLabels", err) 178 return 179 } 180 } 181 case "attach", "detach", "toggle", "toggle-alt": 182 label, err := issues_model.GetLabelByID(ctx, ctx.FormInt64("id")) 183 if err != nil { 184 if issues_model.IsErrRepoLabelNotExist(err) { 185 ctx.Error(http.StatusNotFound, "GetLabelByID") 186 } else { 187 ctx.ServerError("GetLabelByID", err) 188 } 189 return 190 } 191 192 if action == "toggle" { 193 // detach if any issues already have label, otherwise attach 194 action = "attach" 195 if label.ExclusiveScope() == "" { 196 for _, issue := range issues { 197 if issues_model.HasIssueLabel(ctx, issue.ID, label.ID) { 198 action = "detach" 199 break 200 } 201 } 202 } 203 } else if action == "toggle-alt" { 204 // always detach with alt key pressed, to be able to remove 205 // scoped labels 206 action = "detach" 207 } 208 209 if action == "attach" { 210 for _, issue := range issues { 211 if err = issue_service.AddLabel(ctx, issue, ctx.Doer, label); err != nil { 212 ctx.ServerError("AddLabel", err) 213 return 214 } 215 } 216 } else { 217 for _, issue := range issues { 218 if err = issue_service.RemoveLabel(ctx, issue, ctx.Doer, label); err != nil { 219 ctx.ServerError("RemoveLabel", err) 220 return 221 } 222 } 223 } 224 default: 225 log.Warn("Unrecognized action: %s", action) 226 ctx.Error(http.StatusInternalServerError) 227 return 228 } 229 230 ctx.JSONOK() 231 }