code.gitea.io/gitea@v1.21.7/routers/api/v1/repo/issue_label.go (about)

     1  // Copyright 2016 The Gogs Authors. All rights reserved.
     2  // Copyright 2018 The Gitea Authors. All rights reserved.
     3  // SPDX-License-Identifier: MIT
     4  
     5  package repo
     6  
     7  import (
     8  	"net/http"
     9  
    10  	issues_model "code.gitea.io/gitea/models/issues"
    11  	"code.gitea.io/gitea/modules/context"
    12  	api "code.gitea.io/gitea/modules/structs"
    13  	"code.gitea.io/gitea/modules/web"
    14  	"code.gitea.io/gitea/services/convert"
    15  	issue_service "code.gitea.io/gitea/services/issue"
    16  )
    17  
    18  // ListIssueLabels list all the labels of an issue
    19  func ListIssueLabels(ctx *context.APIContext) {
    20  	// swagger:operation GET /repos/{owner}/{repo}/issues/{index}/labels issue issueGetLabels
    21  	// ---
    22  	// summary: Get an issue's labels
    23  	// produces:
    24  	// - application/json
    25  	// parameters:
    26  	// - name: owner
    27  	//   in: path
    28  	//   description: owner of the repo
    29  	//   type: string
    30  	//   required: true
    31  	// - name: repo
    32  	//   in: path
    33  	//   description: name of the repo
    34  	//   type: string
    35  	//   required: true
    36  	// - name: index
    37  	//   in: path
    38  	//   description: index of the issue
    39  	//   type: integer
    40  	//   format: int64
    41  	//   required: true
    42  	// responses:
    43  	//   "200":
    44  	//     "$ref": "#/responses/LabelList"
    45  	//   "404":
    46  	//     "$ref": "#/responses/notFound"
    47  
    48  	issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
    49  	if err != nil {
    50  		if issues_model.IsErrIssueNotExist(err) {
    51  			ctx.NotFound()
    52  		} else {
    53  			ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
    54  		}
    55  		return
    56  	}
    57  
    58  	if err := issue.LoadAttributes(ctx); err != nil {
    59  		ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
    60  		return
    61  	}
    62  
    63  	ctx.JSON(http.StatusOK, convert.ToLabelList(issue.Labels, ctx.Repo.Repository, ctx.Repo.Owner))
    64  }
    65  
    66  // AddIssueLabels add labels for an issue
    67  func AddIssueLabels(ctx *context.APIContext) {
    68  	// swagger:operation POST /repos/{owner}/{repo}/issues/{index}/labels issue issueAddLabel
    69  	// ---
    70  	// summary: Add a label to an issue
    71  	// consumes:
    72  	// - application/json
    73  	// produces:
    74  	// - application/json
    75  	// parameters:
    76  	// - name: owner
    77  	//   in: path
    78  	//   description: owner of the repo
    79  	//   type: string
    80  	//   required: true
    81  	// - name: repo
    82  	//   in: path
    83  	//   description: name of the repo
    84  	//   type: string
    85  	//   required: true
    86  	// - name: index
    87  	//   in: path
    88  	//   description: index of the issue
    89  	//   type: integer
    90  	//   format: int64
    91  	//   required: true
    92  	// - name: body
    93  	//   in: body
    94  	//   schema:
    95  	//     "$ref": "#/definitions/IssueLabelsOption"
    96  	// responses:
    97  	//   "200":
    98  	//     "$ref": "#/responses/LabelList"
    99  	//   "403":
   100  	//     "$ref": "#/responses/forbidden"
   101  	//   "404":
   102  	//     "$ref": "#/responses/notFound"
   103  
   104  	form := web.GetForm(ctx).(*api.IssueLabelsOption)
   105  	issue, labels, err := prepareForReplaceOrAdd(ctx, *form)
   106  	if err != nil {
   107  		return
   108  	}
   109  
   110  	if err = issue_service.AddLabels(ctx, issue, ctx.Doer, labels); err != nil {
   111  		ctx.Error(http.StatusInternalServerError, "AddLabels", err)
   112  		return
   113  	}
   114  
   115  	labels, err = issues_model.GetLabelsByIssueID(ctx, issue.ID)
   116  	if err != nil {
   117  		ctx.Error(http.StatusInternalServerError, "GetLabelsByIssueID", err)
   118  		return
   119  	}
   120  
   121  	ctx.JSON(http.StatusOK, convert.ToLabelList(labels, ctx.Repo.Repository, ctx.Repo.Owner))
   122  }
   123  
   124  // DeleteIssueLabel delete a label for an issue
   125  func DeleteIssueLabel(ctx *context.APIContext) {
   126  	// swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/labels/{id} issue issueRemoveLabel
   127  	// ---
   128  	// summary: Remove a label from an issue
   129  	// produces:
   130  	// - application/json
   131  	// parameters:
   132  	// - name: owner
   133  	//   in: path
   134  	//   description: owner of the repo
   135  	//   type: string
   136  	//   required: true
   137  	// - name: repo
   138  	//   in: path
   139  	//   description: name of the repo
   140  	//   type: string
   141  	//   required: true
   142  	// - name: index
   143  	//   in: path
   144  	//   description: index of the issue
   145  	//   type: integer
   146  	//   format: int64
   147  	//   required: true
   148  	// - name: id
   149  	//   in: path
   150  	//   description: id of the label to remove
   151  	//   type: integer
   152  	//   format: int64
   153  	//   required: true
   154  	// responses:
   155  	//   "204":
   156  	//     "$ref": "#/responses/empty"
   157  	//   "403":
   158  	//     "$ref": "#/responses/forbidden"
   159  	//   "404":
   160  	//     "$ref": "#/responses/notFound"
   161  	//   "422":
   162  	//     "$ref": "#/responses/validationError"
   163  
   164  	issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
   165  	if err != nil {
   166  		if issues_model.IsErrIssueNotExist(err) {
   167  			ctx.NotFound()
   168  		} else {
   169  			ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
   170  		}
   171  		return
   172  	}
   173  
   174  	if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
   175  		ctx.Status(http.StatusForbidden)
   176  		return
   177  	}
   178  
   179  	label, err := issues_model.GetLabelByID(ctx, ctx.ParamsInt64(":id"))
   180  	if err != nil {
   181  		if issues_model.IsErrLabelNotExist(err) {
   182  			ctx.Error(http.StatusUnprocessableEntity, "", err)
   183  		} else {
   184  			ctx.Error(http.StatusInternalServerError, "GetLabelByID", err)
   185  		}
   186  		return
   187  	}
   188  
   189  	if err := issue_service.RemoveLabel(ctx, issue, ctx.Doer, label); err != nil {
   190  		ctx.Error(http.StatusInternalServerError, "DeleteIssueLabel", err)
   191  		return
   192  	}
   193  
   194  	ctx.Status(http.StatusNoContent)
   195  }
   196  
   197  // ReplaceIssueLabels replace labels for an issue
   198  func ReplaceIssueLabels(ctx *context.APIContext) {
   199  	// swagger:operation PUT /repos/{owner}/{repo}/issues/{index}/labels issue issueReplaceLabels
   200  	// ---
   201  	// summary: Replace an issue's labels
   202  	// consumes:
   203  	// - application/json
   204  	// produces:
   205  	// - application/json
   206  	// parameters:
   207  	// - name: owner
   208  	//   in: path
   209  	//   description: owner of the repo
   210  	//   type: string
   211  	//   required: true
   212  	// - name: repo
   213  	//   in: path
   214  	//   description: name of the repo
   215  	//   type: string
   216  	//   required: true
   217  	// - name: index
   218  	//   in: path
   219  	//   description: index of the issue
   220  	//   type: integer
   221  	//   format: int64
   222  	//   required: true
   223  	// - name: body
   224  	//   in: body
   225  	//   schema:
   226  	//     "$ref": "#/definitions/IssueLabelsOption"
   227  	// responses:
   228  	//   "200":
   229  	//     "$ref": "#/responses/LabelList"
   230  	//   "403":
   231  	//     "$ref": "#/responses/forbidden"
   232  	//   "404":
   233  	//     "$ref": "#/responses/notFound"
   234  	form := web.GetForm(ctx).(*api.IssueLabelsOption)
   235  	issue, labels, err := prepareForReplaceOrAdd(ctx, *form)
   236  	if err != nil {
   237  		return
   238  	}
   239  
   240  	if err := issue_service.ReplaceLabels(ctx, issue, ctx.Doer, labels); err != nil {
   241  		ctx.Error(http.StatusInternalServerError, "ReplaceLabels", err)
   242  		return
   243  	}
   244  
   245  	labels, err = issues_model.GetLabelsByIssueID(ctx, issue.ID)
   246  	if err != nil {
   247  		ctx.Error(http.StatusInternalServerError, "GetLabelsByIssueID", err)
   248  		return
   249  	}
   250  
   251  	ctx.JSON(http.StatusOK, convert.ToLabelList(labels, ctx.Repo.Repository, ctx.Repo.Owner))
   252  }
   253  
   254  // ClearIssueLabels delete all the labels for an issue
   255  func ClearIssueLabels(ctx *context.APIContext) {
   256  	// swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/labels issue issueClearLabels
   257  	// ---
   258  	// summary: Remove all labels from an issue
   259  	// produces:
   260  	// - application/json
   261  	// parameters:
   262  	// - name: owner
   263  	//   in: path
   264  	//   description: owner of the repo
   265  	//   type: string
   266  	//   required: true
   267  	// - name: repo
   268  	//   in: path
   269  	//   description: name of the repo
   270  	//   type: string
   271  	//   required: true
   272  	// - name: index
   273  	//   in: path
   274  	//   description: index of the issue
   275  	//   type: integer
   276  	//   format: int64
   277  	//   required: true
   278  	// responses:
   279  	//   "204":
   280  	//     "$ref": "#/responses/empty"
   281  	//   "403":
   282  	//     "$ref": "#/responses/forbidden"
   283  	//   "404":
   284  	//     "$ref": "#/responses/notFound"
   285  
   286  	issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
   287  	if err != nil {
   288  		if issues_model.IsErrIssueNotExist(err) {
   289  			ctx.NotFound()
   290  		} else {
   291  			ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
   292  		}
   293  		return
   294  	}
   295  
   296  	if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
   297  		ctx.Status(http.StatusForbidden)
   298  		return
   299  	}
   300  
   301  	if err := issue_service.ClearLabels(ctx, issue, ctx.Doer); err != nil {
   302  		ctx.Error(http.StatusInternalServerError, "ClearLabels", err)
   303  		return
   304  	}
   305  
   306  	ctx.Status(http.StatusNoContent)
   307  }
   308  
   309  func prepareForReplaceOrAdd(ctx *context.APIContext, form api.IssueLabelsOption) (*issues_model.Issue, []*issues_model.Label, error) {
   310  	issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
   311  	if err != nil {
   312  		if issues_model.IsErrIssueNotExist(err) {
   313  			ctx.NotFound()
   314  		} else {
   315  			ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
   316  		}
   317  		return nil, nil, err
   318  	}
   319  
   320  	labels, err := issues_model.GetLabelsByIDs(ctx, form.Labels, "id", "repo_id", "org_id", "name", "exclusive")
   321  	if err != nil {
   322  		ctx.Error(http.StatusInternalServerError, "GetLabelsByIDs", err)
   323  		return nil, nil, err
   324  	}
   325  
   326  	if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
   327  		ctx.Status(http.StatusForbidden)
   328  		return nil, nil, nil
   329  	}
   330  
   331  	return issue, labels, err
   332  }