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