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  }