From 7bfa54672f3fc3ff796015f7ee55d0c7de9fa8d6 Mon Sep 17 00:00:00 2001 From: eyad-hussein Date: Sat, 13 Jul 2024 01:01:04 +0300 Subject: [PATCH] api: implement logic and endpoint for moving issues between projects in repos --- routers/api/v1/api.go | 20 +++++++++++++++++++ routers/api/v1/repo/project.go | 36 +++++++++++++++++++--------------- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 3788a0117e..4ca08d3fc6 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -417,6 +417,18 @@ func reqRepoWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) { } } +// reqRepoWriterOr returns a middleware for requiring repository write to one of the unit permission +func reqRepoWriterOr(unitTypes ...unit.Type) func(ctx *context.APIContext) { + return func(ctx *context.APIContext) { + for _, unitType := range unitTypes { + if ctx.Repo.CanWrite(unitType) { + return + } + } + ctx.NotFound(ctx.Req.URL.RequestURI(), nil) + } +} + // reqRepoBranchWriter user should have a permission to write to a branch, or be a site admin func reqRepoBranchWriter(ctx *context.APIContext) { options, ok := web.GetForm(ctx).(api.FileOptionInterface) @@ -1060,6 +1072,10 @@ func Routes() *web.Router { }) }, reqRepoWriter(unit.TypeProjects), mustNotBeArchived) }, individualPermsChecker) + + m.Group("/{type:issues|pulls}", func() { + m.Post("/projects", reqRepoWriterOr(unit.TypeIssues, unit.TypePullRequests), reqRepoWriter(unit.TypeProjects), repo.UpdateIssueProject) + }, individualPermsChecker) }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryRepository), reqToken(), repoAssignment(), reqRepoReader(unit.TypeProjects), mustEnableRepoProjects) // Organizations (requires orgs scope) @@ -1116,6 +1132,10 @@ func Routes() *web.Router { }) }, reqRepoWriter(unit.TypeProjects), mustNotBeArchived) }) + + m.Group("/{type:issues|pulls}", func() { + m.Post("/projects", reqRepoWriterOr(unit.TypeIssues, unit.TypePullRequests), reqRepoWriter(unit.TypeProjects), repo.UpdateIssueProject) + }, reqRepoWriter(unit.TypeProjects), mustNotBeArchived) }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization, auth_model.AccessTokenScopeCategoryRepository), reqToken(), repoAssignment(), reqRepoReader(unit.TypeProjects), mustEnableRepoProjects) // Users (requires user scope) diff --git a/routers/api/v1/repo/project.go b/routers/api/v1/repo/project.go index 268842d43b..aa81407c85 100644 --- a/routers/api/v1/repo/project.go +++ b/routers/api/v1/repo/project.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "log" "net/http" "strings" @@ -460,24 +461,13 @@ func MoveIssues(ctx *context.APIContext) { ctx.JSON(http.StatusOK, map[string]string{"message": "issues moved successfully"}) } -func getActionIssues(ctx *context.APIContext) issues_model.IssueList { - type updateIssuesForm struct { - Issues []int64 `json:"issues"` - } +func getActionIssues(ctx *context.APIContext, issuesIDs []int64) issues_model.IssueList { - form := &updateIssuesForm{} - - if err := json.NewDecoder(ctx.Req.Body).Decode(&form); err != nil { - ctx.ServerError("DecodeMovedIssuesForm", err) + if len(issuesIDs) == 0 { return nil } - if len(form.Issues) == 0 { - return nil - } - - issueIDs := form.Issues - issues, err := issues_model.GetIssuesByIDs(ctx, issueIDs) + issues, err := issues_model.GetIssuesByIDs(ctx, issuesIDs) if err != nil { ctx.ServerError("GetIssuesByIDs", err) return nil @@ -504,7 +494,21 @@ func getActionIssues(ctx *context.APIContext) issues_model.IssueList { // UpdateIssueProject change an issue's project func UpdateIssueProject(ctx *context.APIContext) { - issues := getActionIssues(ctx) + type updateIssuesForm struct { + ProjectID int64 `json:"project_id"` + Issues []int64 `json:"issues"` + } + + form := &updateIssuesForm{} + + if err := json.NewDecoder(ctx.Req.Body).Decode(&form); err != nil { + ctx.ServerError("DecodeMovedIssuesForm", err) + return + } + + log.Println("form", form) + log.Println(ctx.Repo.Repository.ID) + issues := getActionIssues(ctx, form.Issues) if ctx.Written() { return } @@ -518,7 +522,7 @@ func UpdateIssueProject(ctx *context.APIContext) { return } - projectID := ctx.FormInt64("project_id") + projectID := form.ProjectID for _, issue := range issues { if issue.Project != nil && issue.Project.ID == projectID { continue