diff --git a/models/db/engine.go b/models/db/engine.go index 25f4066ea1..847ba58c26 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -57,6 +57,7 @@ type Engine interface { SumInt(bean any, columnName string) (res int64, err error) Sync(...any) error Select(string) *xorm.Session + SetExpr(string, any) *xorm.Session NotIn(string, ...any) *xorm.Session OrderBy(any, ...any) *xorm.Session Exist(...any) (bool, error) diff --git a/models/project/board.go b/models/project/board.go index aa995caa80..dc4d0561e0 100644 --- a/models/project/board.go +++ b/models/project/board.go @@ -156,6 +156,15 @@ func NewBoard(ctx context.Context, board *Board) error { return fmt.Errorf("bad color code: %s", board.Color) } + var maxSorting int8 + if _, err := db.GetEngine(ctx).Select("Max(sorting)").Table("project_board"). + Where("project_id=?", board.ProjectID).Get(&maxSorting); err != nil { + return err + } + if maxSorting > 0 { + board.Sorting = maxSorting + } + _, err := db.GetEngine(ctx).Insert(board) return err } diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index 9b765e89e8..63473e23b0 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -666,3 +666,70 @@ func MoveIssues(ctx *context.Context) { ctx.JSONOK() } + +// MoveColumns moves or keeps columns in a project and sorts them inside that project +func MoveColumns(ctx *context.Context) { + if ctx.Doer == nil { + ctx.JSON(http.StatusForbidden, map[string]string{ + "message": "Only signed in users are allowed to perform this action.", + }) + return + } + + project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id")) + if err != nil { + if project_model.IsErrProjectNotExist(err) { + ctx.NotFound("ProjectNotExist", nil) + } else { + ctx.ServerError("GetProjectByID", err) + } + return + } + if project.RepoID != ctx.Repo.Repository.ID { + ctx.NotFound("InvalidRepoID", nil) + return + } + + type movedColumnsForm struct { + Columns []struct { + ColumnID int64 `json:"columnID"` + Sorting int64 `json:"sorting"` + } `json:"columns"` + } + + form := &movedColumnsForm{} + if err = json.NewDecoder(ctx.Req.Body).Decode(&form); err != nil { + ctx.ServerError("DecodeMovedColumnsForm", err) + } + + columnIDs := make([]int64, 0, len(form.Columns)) + sortedColumnIDs := make(map[int64]int64) + for _, column := range form.Columns { + columnIDs = append(columnIDs, column.ColumnID) + sortedColumnIDs[column.Sorting] = column.ColumnID + } + movedColumns, err := project_model.GetColumnsByIDs(ctx, columnIDs) + if err != nil { + ctx.NotFoundOrServerError("GetColumnsByIDs", issues_model.IsErrIssueNotExist, err) + return + } + + if len(movedColumns) != len(form.Columns) { + ctx.ServerError("some columns do not exist", errors.New("some columns do not exist")) + return + } + + for _, column := range movedColumns { + if column.ProjectID != project.ID { + ctx.ServerError("Some column's projectID is not equal to project's ID", errors.New("Some column's projectID is not equal to project's ID")) + return + } + } + + if err = project_model.MoveColumnsOnProject(ctx, project, sortedColumnIDs); err != nil { + ctx.ServerError("MoveColumnsOnProject", err) + return + } + + ctx.JSONOK() +} diff --git a/routers/web/web.go b/routers/web/web.go index 3aa1b8aed0..10670ea68c 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1351,10 +1351,12 @@ func registerRoutes(m *web.Route) { m.Get("", repo.Projects) m.Get("/{id}", repo.ViewProject) m.Group("", func() { //nolint:dupl + m.Get("/new", repo.RenderNewProject) m.Post("/new", web.Bind(forms.CreateProjectForm{}), repo.NewProjectPost) m.Group("/{id}", func() { m.Post("", web.Bind(forms.EditProjectBoardForm{}), repo.AddBoardToProjectPost) + m.Post("/move", repo.MoveColumns) m.Post("/delete", repo.DeleteProject) m.Get("/edit", repo.RenderEditProject)