mirror of
				https://github.com/go-gitea/gitea
				synced 2025-09-28 03:28:13 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			614 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			614 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2016 The Gogs Authors. All rights reserved.
 | |
| // Copyright 2023 The Gitea Authors. All rights reserved.
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| package repo
 | |
| 
 | |
| import (
 | |
| 	"net/http"
 | |
| 
 | |
| 	"code.gitea.io/gitea/models/db"
 | |
| 	issues_model "code.gitea.io/gitea/models/issues"
 | |
| 	access_model "code.gitea.io/gitea/models/perm/access"
 | |
| 	repo_model "code.gitea.io/gitea/models/repo"
 | |
| 	"code.gitea.io/gitea/modules/setting"
 | |
| 	api "code.gitea.io/gitea/modules/structs"
 | |
| 	"code.gitea.io/gitea/modules/web"
 | |
| 	"code.gitea.io/gitea/services/context"
 | |
| 	"code.gitea.io/gitea/services/convert"
 | |
| )
 | |
| 
 | |
| // GetIssueDependencies list an issue's dependencies
 | |
| func GetIssueDependencies(ctx *context.APIContext) {
 | |
| 	// swagger:operation GET /repos/{owner}/{repo}/issues/{index}/dependencies issue issueListIssueDependencies
 | |
| 	// ---
 | |
| 	// summary: List an issue's dependencies, i.e all issues that block this issue.
 | |
| 	// produces:
 | |
| 	// - application/json
 | |
| 	// parameters:
 | |
| 	// - name: owner
 | |
| 	//   in: path
 | |
| 	//   description: owner of the repo
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: repo
 | |
| 	//   in: path
 | |
| 	//   description: name of the repo
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: index
 | |
| 	//   in: path
 | |
| 	//   description: index of the issue
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: page
 | |
| 	//   in: query
 | |
| 	//   description: page number of results to return (1-based)
 | |
| 	//   type: integer
 | |
| 	// - name: limit
 | |
| 	//   in: query
 | |
| 	//   description: page size of results
 | |
| 	//   type: integer
 | |
| 	// responses:
 | |
| 	//   "200":
 | |
| 	//     "$ref": "#/responses/IssueList"
 | |
| 	//   "404":
 | |
| 	//     "$ref": "#/responses/notFound"
 | |
| 
 | |
| 	// If this issue's repository does not enable dependencies then there can be no dependencies by default
 | |
| 	if !ctx.Repo.Repository.IsDependenciesEnabled(ctx) {
 | |
| 		ctx.NotFound()
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
 | |
| 	if err != nil {
 | |
| 		if issues_model.IsErrIssueNotExist(err) {
 | |
| 			ctx.NotFound("IsErrIssueNotExist", err)
 | |
| 		} else {
 | |
| 			ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
 | |
| 		}
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// 1. We must be able to read this issue
 | |
| 	if !ctx.Repo.Permission.CanReadIssuesOrPulls(issue.IsPull) {
 | |
| 		ctx.NotFound()
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	page := ctx.FormInt("page")
 | |
| 	if page <= 1 {
 | |
| 		page = 1
 | |
| 	}
 | |
| 	limit := ctx.FormInt("limit")
 | |
| 	if limit == 0 {
 | |
| 		limit = setting.API.DefaultPagingNum
 | |
| 	} else if limit > setting.API.MaxResponseItems {
 | |
| 		limit = setting.API.MaxResponseItems
 | |
| 	}
 | |
| 
 | |
| 	canWrite := ctx.Repo.Permission.CanWriteIssuesOrPulls(issue.IsPull)
 | |
| 
 | |
| 	blockerIssues := make([]*issues_model.Issue, 0, limit)
 | |
| 
 | |
| 	// 2. Get the issues this issue depends on, i.e. the `<#b>`: `<issue> <- <#b>`
 | |
| 	blockersInfo, err := issue.BlockedByDependencies(ctx, db.ListOptions{
 | |
| 		Page:     page,
 | |
| 		PageSize: limit,
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		ctx.Error(http.StatusInternalServerError, "BlockedByDependencies", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	repoPerms := make(map[int64]access_model.Permission)
 | |
| 	repoPerms[ctx.Repo.Repository.ID] = ctx.Repo.Permission
 | |
| 	for _, blocker := range blockersInfo {
 | |
| 		// Get the permissions for this repository
 | |
| 		// If the repo ID exists in the map, return the exist permissions
 | |
| 		// else get the permission and add it to the map
 | |
| 		var perm access_model.Permission
 | |
| 		existPerm, ok := repoPerms[blocker.RepoID]
 | |
| 		if ok {
 | |
| 			perm = existPerm
 | |
| 		} else {
 | |
| 			var err error
 | |
| 			perm, err = access_model.GetUserRepoPermission(ctx, &blocker.Repository, ctx.Doer)
 | |
| 			if err != nil {
 | |
| 				ctx.ServerError("GetUserRepoPermission", err)
 | |
| 				return
 | |
| 			}
 | |
| 			repoPerms[blocker.RepoID] = perm
 | |
| 		}
 | |
| 
 | |
| 		// check permission
 | |
| 		if !perm.CanReadIssuesOrPulls(blocker.Issue.IsPull) {
 | |
| 			if !canWrite {
 | |
| 				hiddenBlocker := &issues_model.DependencyInfo{
 | |
| 					Issue: issues_model.Issue{
 | |
| 						Title: "HIDDEN",
 | |
| 					},
 | |
| 				}
 | |
| 				blocker = hiddenBlocker
 | |
| 			} else {
 | |
| 				confidentialBlocker := &issues_model.DependencyInfo{
 | |
| 					Issue: issues_model.Issue{
 | |
| 						RepoID:   blocker.Issue.RepoID,
 | |
| 						Index:    blocker.Index,
 | |
| 						Title:    blocker.Title,
 | |
| 						IsClosed: blocker.IsClosed,
 | |
| 						IsPull:   blocker.IsPull,
 | |
| 					},
 | |
| 					Repository: repo_model.Repository{
 | |
| 						ID:        blocker.Issue.Repo.ID,
 | |
| 						Name:      blocker.Issue.Repo.Name,
 | |
| 						OwnerName: blocker.Issue.Repo.OwnerName,
 | |
| 					},
 | |
| 				}
 | |
| 				confidentialBlocker.Issue.Repo = &confidentialBlocker.Repository
 | |
| 				blocker = confidentialBlocker
 | |
| 			}
 | |
| 		}
 | |
| 		blockerIssues = append(blockerIssues, &blocker.Issue)
 | |
| 	}
 | |
| 
 | |
| 	ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, blockerIssues))
 | |
| }
 | |
| 
 | |
| // CreateIssueDependency create a new issue dependencies
 | |
| func CreateIssueDependency(ctx *context.APIContext) {
 | |
| 	// swagger:operation POST /repos/{owner}/{repo}/issues/{index}/dependencies issue issueCreateIssueDependencies
 | |
| 	// ---
 | |
| 	// summary: Make the issue in the url depend on the issue in the form.
 | |
| 	// produces:
 | |
| 	// - application/json
 | |
| 	// parameters:
 | |
| 	// - name: owner
 | |
| 	//   in: path
 | |
| 	//   description: owner of the repo
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: repo
 | |
| 	//   in: path
 | |
| 	//   description: name of the repo
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: index
 | |
| 	//   in: path
 | |
| 	//   description: index of the issue
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: body
 | |
| 	//   in: body
 | |
| 	//   schema:
 | |
| 	//     "$ref": "#/definitions/IssueMeta"
 | |
| 	// responses:
 | |
| 	//   "201":
 | |
| 	//     "$ref": "#/responses/Issue"
 | |
| 	//   "404":
 | |
| 	//     description: the issue does not exist
 | |
| 	//   "423":
 | |
| 	//     "$ref": "#/responses/repoArchivedError"
 | |
| 
 | |
| 	// We want to make <:index> depend on <Form>, i.e. <:index> is the target
 | |
| 	target := getParamsIssue(ctx)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// and <Form> represents the dependency
 | |
| 	form := web.GetForm(ctx).(*api.IssueMeta)
 | |
| 	dependency := getFormIssue(ctx, form)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	dependencyPerm := getPermissionForRepo(ctx, target.Repo)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	createIssueDependency(ctx, target, dependency, ctx.Repo.Permission, *dependencyPerm)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, target))
 | |
| }
 | |
| 
 | |
| // RemoveIssueDependency remove an issue dependency
 | |
| func RemoveIssueDependency(ctx *context.APIContext) {
 | |
| 	// swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/dependencies issue issueRemoveIssueDependencies
 | |
| 	// ---
 | |
| 	// summary: Remove an issue dependency
 | |
| 	// produces:
 | |
| 	// - application/json
 | |
| 	// parameters:
 | |
| 	// - name: owner
 | |
| 	//   in: path
 | |
| 	//   description: owner of the repo
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: repo
 | |
| 	//   in: path
 | |
| 	//   description: name of the repo
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: index
 | |
| 	//   in: path
 | |
| 	//   description: index of the issue
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: body
 | |
| 	//   in: body
 | |
| 	//   schema:
 | |
| 	//     "$ref": "#/definitions/IssueMeta"
 | |
| 	// responses:
 | |
| 	//   "200":
 | |
| 	//     "$ref": "#/responses/Issue"
 | |
| 	//   "404":
 | |
| 	//     "$ref": "#/responses/notFound"
 | |
| 	//   "423":
 | |
| 	//     "$ref": "#/responses/repoArchivedError"
 | |
| 
 | |
| 	// We want to make <:index> depend on <Form>, i.e. <:index> is the target
 | |
| 	target := getParamsIssue(ctx)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// and <Form> represents the dependency
 | |
| 	form := web.GetForm(ctx).(*api.IssueMeta)
 | |
| 	dependency := getFormIssue(ctx, form)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	dependencyPerm := getPermissionForRepo(ctx, target.Repo)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	removeIssueDependency(ctx, target, dependency, ctx.Repo.Permission, *dependencyPerm)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, target))
 | |
| }
 | |
| 
 | |
| // GetIssueBlocks list issues that are blocked by this issue
 | |
| func GetIssueBlocks(ctx *context.APIContext) {
 | |
| 	// swagger:operation GET /repos/{owner}/{repo}/issues/{index}/blocks issue issueListBlocks
 | |
| 	// ---
 | |
| 	// summary: List issues that are blocked by this issue
 | |
| 	// produces:
 | |
| 	// - application/json
 | |
| 	// parameters:
 | |
| 	// - name: owner
 | |
| 	//   in: path
 | |
| 	//   description: owner of the repo
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: repo
 | |
| 	//   in: path
 | |
| 	//   description: name of the repo
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: index
 | |
| 	//   in: path
 | |
| 	//   description: index of the issue
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: page
 | |
| 	//   in: query
 | |
| 	//   description: page number of results to return (1-based)
 | |
| 	//   type: integer
 | |
| 	// - name: limit
 | |
| 	//   in: query
 | |
| 	//   description: page size of results
 | |
| 	//   type: integer
 | |
| 	// responses:
 | |
| 	//   "200":
 | |
| 	//     "$ref": "#/responses/IssueList"
 | |
| 	//   "404":
 | |
| 	//     "$ref": "#/responses/notFound"
 | |
| 
 | |
| 	// We need to list the issues that DEPEND on this issue not the other way round
 | |
| 	// Therefore whether dependencies are enabled or not in this repository is potentially irrelevant.
 | |
| 
 | |
| 	issue := getParamsIssue(ctx)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if !ctx.Repo.Permission.CanReadIssuesOrPulls(issue.IsPull) {
 | |
| 		ctx.NotFound()
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	page := ctx.FormInt("page")
 | |
| 	if page <= 1 {
 | |
| 		page = 1
 | |
| 	}
 | |
| 	limit := ctx.FormInt("limit")
 | |
| 	if limit <= 1 {
 | |
| 		limit = setting.API.DefaultPagingNum
 | |
| 	}
 | |
| 
 | |
| 	skip := (page - 1) * limit
 | |
| 	max := page * limit
 | |
| 
 | |
| 	deps, err := issue.BlockingDependencies(ctx)
 | |
| 	if err != nil {
 | |
| 		ctx.Error(http.StatusInternalServerError, "BlockingDependencies", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	var issues []*issues_model.Issue
 | |
| 
 | |
| 	repoPerms := make(map[int64]access_model.Permission)
 | |
| 	repoPerms[ctx.Repo.Repository.ID] = ctx.Repo.Permission
 | |
| 
 | |
| 	for i, depMeta := range deps {
 | |
| 		if i < skip || i >= max {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		// Get the permissions for this repository
 | |
| 		// If the repo ID exists in the map, return the exist permissions
 | |
| 		// else get the permission and add it to the map
 | |
| 		var perm access_model.Permission
 | |
| 		existPerm, ok := repoPerms[depMeta.RepoID]
 | |
| 		if ok {
 | |
| 			perm = existPerm
 | |
| 		} else {
 | |
| 			var err error
 | |
| 			perm, err = access_model.GetUserRepoPermission(ctx, &depMeta.Repository, ctx.Doer)
 | |
| 			if err != nil {
 | |
| 				ctx.ServerError("GetUserRepoPermission", err)
 | |
| 				return
 | |
| 			}
 | |
| 			repoPerms[depMeta.RepoID] = perm
 | |
| 		}
 | |
| 
 | |
| 		if !perm.CanReadIssuesOrPulls(depMeta.Issue.IsPull) {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		depMeta.Issue.Repo = &depMeta.Repository
 | |
| 		issues = append(issues, &depMeta.Issue)
 | |
| 	}
 | |
| 
 | |
| 	ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues))
 | |
| }
 | |
| 
 | |
| // CreateIssueBlocking block the issue given in the body by the issue in path
 | |
| func CreateIssueBlocking(ctx *context.APIContext) {
 | |
| 	// swagger:operation POST /repos/{owner}/{repo}/issues/{index}/blocks issue issueCreateIssueBlocking
 | |
| 	// ---
 | |
| 	// summary: Block the issue given in the body by the issue in path
 | |
| 	// produces:
 | |
| 	// - application/json
 | |
| 	// parameters:
 | |
| 	// - name: owner
 | |
| 	//   in: path
 | |
| 	//   description: owner of the repo
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: repo
 | |
| 	//   in: path
 | |
| 	//   description: name of the repo
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: index
 | |
| 	//   in: path
 | |
| 	//   description: index of the issue
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: body
 | |
| 	//   in: body
 | |
| 	//   schema:
 | |
| 	//     "$ref": "#/definitions/IssueMeta"
 | |
| 	// responses:
 | |
| 	//   "201":
 | |
| 	//     "$ref": "#/responses/Issue"
 | |
| 	//   "404":
 | |
| 	//     description: the issue does not exist
 | |
| 
 | |
| 	dependency := getParamsIssue(ctx)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	form := web.GetForm(ctx).(*api.IssueMeta)
 | |
| 	target := getFormIssue(ctx, form)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	targetPerm := getPermissionForRepo(ctx, target.Repo)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	createIssueDependency(ctx, target, dependency, *targetPerm, ctx.Repo.Permission)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, dependency))
 | |
| }
 | |
| 
 | |
| // RemoveIssueBlocking unblock the issue given in the body by the issue in path
 | |
| func RemoveIssueBlocking(ctx *context.APIContext) {
 | |
| 	// swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/blocks issue issueRemoveIssueBlocking
 | |
| 	// ---
 | |
| 	// summary: Unblock the issue given in the body by the issue in path
 | |
| 	// produces:
 | |
| 	// - application/json
 | |
| 	// parameters:
 | |
| 	// - name: owner
 | |
| 	//   in: path
 | |
| 	//   description: owner of the repo
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: repo
 | |
| 	//   in: path
 | |
| 	//   description: name of the repo
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: index
 | |
| 	//   in: path
 | |
| 	//   description: index of the issue
 | |
| 	//   type: string
 | |
| 	//   required: true
 | |
| 	// - name: body
 | |
| 	//   in: body
 | |
| 	//   schema:
 | |
| 	//     "$ref": "#/definitions/IssueMeta"
 | |
| 	// responses:
 | |
| 	//   "200":
 | |
| 	//     "$ref": "#/responses/Issue"
 | |
| 	//   "404":
 | |
| 	//     "$ref": "#/responses/notFound"
 | |
| 
 | |
| 	dependency := getParamsIssue(ctx)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	form := web.GetForm(ctx).(*api.IssueMeta)
 | |
| 	target := getFormIssue(ctx, form)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	targetPerm := getPermissionForRepo(ctx, target.Repo)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	removeIssueDependency(ctx, target, dependency, *targetPerm, ctx.Repo.Permission)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, dependency))
 | |
| }
 | |
| 
 | |
| func getParamsIssue(ctx *context.APIContext) *issues_model.Issue {
 | |
| 	issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
 | |
| 	if err != nil {
 | |
| 		if issues_model.IsErrIssueNotExist(err) {
 | |
| 			ctx.NotFound("IsErrIssueNotExist", err)
 | |
| 		} else {
 | |
| 			ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
 | |
| 		}
 | |
| 		return nil
 | |
| 	}
 | |
| 	issue.Repo = ctx.Repo.Repository
 | |
| 	return issue
 | |
| }
 | |
| 
 | |
| func getFormIssue(ctx *context.APIContext, form *api.IssueMeta) *issues_model.Issue {
 | |
| 	var repo *repo_model.Repository
 | |
| 	if form.Owner != ctx.Repo.Repository.OwnerName || form.Name != ctx.Repo.Repository.Name {
 | |
| 		if !setting.Service.AllowCrossRepositoryDependencies {
 | |
| 			ctx.JSON(http.StatusBadRequest, "CrossRepositoryDependencies not enabled")
 | |
| 			return nil
 | |
| 		}
 | |
| 		var err error
 | |
| 		repo, err = repo_model.GetRepositoryByOwnerAndName(ctx, form.Owner, form.Name)
 | |
| 		if err != nil {
 | |
| 			if repo_model.IsErrRepoNotExist(err) {
 | |
| 				ctx.NotFound("IsErrRepoNotExist", err)
 | |
| 			} else {
 | |
| 				ctx.Error(http.StatusInternalServerError, "GetRepositoryByOwnerAndName", err)
 | |
| 			}
 | |
| 			return nil
 | |
| 		}
 | |
| 	} else {
 | |
| 		repo = ctx.Repo.Repository
 | |
| 	}
 | |
| 
 | |
| 	issue, err := issues_model.GetIssueByIndex(ctx, repo.ID, form.Index)
 | |
| 	if err != nil {
 | |
| 		if issues_model.IsErrIssueNotExist(err) {
 | |
| 			ctx.NotFound("IsErrIssueNotExist", err)
 | |
| 		} else {
 | |
| 			ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
 | |
| 		}
 | |
| 		return nil
 | |
| 	}
 | |
| 	issue.Repo = repo
 | |
| 	return issue
 | |
| }
 | |
| 
 | |
| func getPermissionForRepo(ctx *context.APIContext, repo *repo_model.Repository) *access_model.Permission {
 | |
| 	if repo.ID == ctx.Repo.Repository.ID {
 | |
| 		return &ctx.Repo.Permission
 | |
| 	}
 | |
| 
 | |
| 	perm, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
 | |
| 	if err != nil {
 | |
| 		ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	return &perm
 | |
| }
 | |
| 
 | |
| func createIssueDependency(ctx *context.APIContext, target, dependency *issues_model.Issue, targetPerm, dependencyPerm access_model.Permission) {
 | |
| 	if target.Repo.IsArchived || !target.Repo.IsDependenciesEnabled(ctx) {
 | |
| 		// The target's repository doesn't have dependencies enabled
 | |
| 		ctx.NotFound()
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if !targetPerm.CanWriteIssuesOrPulls(target.IsPull) {
 | |
| 		// We can't write to the target
 | |
| 		ctx.NotFound()
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if !dependencyPerm.CanReadIssuesOrPulls(dependency.IsPull) {
 | |
| 		// We can't read the dependency
 | |
| 		ctx.NotFound()
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	err := issues_model.CreateIssueDependency(ctx, ctx.Doer, target, dependency)
 | |
| 	if err != nil {
 | |
| 		ctx.Error(http.StatusInternalServerError, "CreateIssueDependency", err)
 | |
| 		return
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func removeIssueDependency(ctx *context.APIContext, target, dependency *issues_model.Issue, targetPerm, dependencyPerm access_model.Permission) {
 | |
| 	if target.Repo.IsArchived || !target.Repo.IsDependenciesEnabled(ctx) {
 | |
| 		// The target's repository doesn't have dependencies enabled
 | |
| 		ctx.NotFound()
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if !targetPerm.CanWriteIssuesOrPulls(target.IsPull) {
 | |
| 		// We can't write to the target
 | |
| 		ctx.NotFound()
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if !dependencyPerm.CanReadIssuesOrPulls(dependency.IsPull) {
 | |
| 		// We can't read the dependency
 | |
| 		ctx.NotFound()
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	err := issues_model.RemoveIssueDependency(ctx, ctx.Doer, target, dependency, issues_model.DependencyTypeBlockedBy)
 | |
| 	if err != nil {
 | |
| 		ctx.Error(http.StatusInternalServerError, "CreateIssueDependency", err)
 | |
| 		return
 | |
| 	}
 | |
| }
 |