22586b7a06
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 1s
PR RC Release / Build RC Release (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Branch Cleanup / Delete merged branch (pull_request) Failing after 2s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || 'development' }}) (pull_request) Failing after 50s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Status and priority are first-class fields, not custom fields. They must always show in the sidebar without requiring manual setup. When an org has no definitions, the standard presets are auto-created on first access.
118 lines
4.3 KiB
Go
118 lines
4.3 KiB
Go
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package issues
|
|
|
|
import (
|
|
"context"
|
|
|
|
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
|
|
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
|
|
)
|
|
|
|
func init() {
|
|
db.RegisterModel(new(IssuePriorityDef))
|
|
}
|
|
|
|
// IssuePriorityDef defines a custom issue priority at the org level.
|
|
type IssuePriorityDef struct {
|
|
ID int64 `xorm:"pk autoincr"`
|
|
OrgID int64 `xorm:"INDEX NOT NULL DEFAULT 0 'org_id'"`
|
|
Name string `xorm:"NOT NULL"`
|
|
Color string `xorm:"VARCHAR(7)"`
|
|
Description string `xorm:"TEXT"`
|
|
SortOrder int `xorm:"NOT NULL DEFAULT 0 'sort_order'"`
|
|
IsDefault bool `xorm:"NOT NULL DEFAULT false 'is_default'"`
|
|
IsActive bool `xorm:"NOT NULL DEFAULT true 'is_active'"`
|
|
CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED 'created_unix'"`
|
|
UpdatedUnix timeutil.TimeStamp `xorm:"UPDATED 'updated_unix'"`
|
|
}
|
|
|
|
func (IssuePriorityDef) TableName() string {
|
|
return "issue_priority_def"
|
|
}
|
|
|
|
// GetIssuePriorityDefsByOrg returns active priority definitions for an org.
|
|
// If none exist, seeds the org with default priorities automatically.
|
|
func GetIssuePriorityDefsByOrg(ctx context.Context, orgID int64) ([]*IssuePriorityDef, error) {
|
|
defs := make([]*IssuePriorityDef, 0, 10)
|
|
if err := db.GetEngine(ctx).
|
|
Where("org_id = ? AND is_active = ?", orgID, true).
|
|
OrderBy("sort_order ASC, id ASC").
|
|
Find(&defs); err != nil {
|
|
return nil, err
|
|
}
|
|
if len(defs) == 0 && orgID > 0 {
|
|
if err := seedDefaultIssuePriorities(ctx, orgID); err != nil {
|
|
return defs, nil // non-fatal
|
|
}
|
|
return GetIssuePriorityDefsByOrg(ctx, orgID)
|
|
}
|
|
return defs, nil
|
|
}
|
|
|
|
// seedDefaultIssuePriorities creates the standard priority presets for an org.
|
|
func seedDefaultIssuePriorities(ctx context.Context, orgID int64) error {
|
|
defaults := []*IssuePriorityDef{
|
|
{OrgID: orgID, Name: "Critical", Color: "#dc2626", Description: "Requires immediate attention", SortOrder: 1, IsActive: true},
|
|
{OrgID: orgID, Name: "High", Color: "#f97316", Description: "Should be addressed soon", SortOrder: 2, IsActive: true},
|
|
{OrgID: orgID, Name: "Medium", Color: "#eab308", Description: "Normal priority", SortOrder: 3, IsDefault: true, IsActive: true},
|
|
{OrgID: orgID, Name: "Low", Color: "#2563eb", Description: "Can wait", SortOrder: 4, IsActive: true},
|
|
}
|
|
for _, d := range defaults {
|
|
if _, err := db.GetEngine(ctx).Insert(d); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetAllIssuePriorityDefsByOrg returns all priority definitions (including inactive).
|
|
func GetAllIssuePriorityDefsByOrg(ctx context.Context, orgID int64) ([]*IssuePriorityDef, error) {
|
|
defs := make([]*IssuePriorityDef, 0, 10)
|
|
return defs, db.GetEngine(ctx).
|
|
Where("org_id = ?", orgID).
|
|
OrderBy("sort_order ASC, id ASC").
|
|
Find(&defs)
|
|
}
|
|
|
|
// GetIssuePriorityDefByID returns a single priority definition.
|
|
func GetIssuePriorityDefByID(ctx context.Context, id int64) (*IssuePriorityDef, error) {
|
|
def := new(IssuePriorityDef)
|
|
has, err := db.GetEngine(ctx).ID(id).Get(def)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !has {
|
|
return nil, db.ErrNotExist{Resource: "IssuePriorityDef", ID: id}
|
|
}
|
|
return def, nil
|
|
}
|
|
|
|
// CreateIssuePriorityDef creates a new priority definition.
|
|
func CreateIssuePriorityDef(ctx context.Context, def *IssuePriorityDef) error {
|
|
_, err := db.GetEngine(ctx).Insert(def)
|
|
return err
|
|
}
|
|
|
|
// UpdateIssuePriorityDef updates a priority definition.
|
|
func UpdateIssuePriorityDef(ctx context.Context, def *IssuePriorityDef) error {
|
|
_, err := db.GetEngine(ctx).ID(def.ID).AllCols().Update(def)
|
|
return err
|
|
}
|
|
|
|
// DeleteIssuePriorityDef deletes a priority definition and clears references on issues.
|
|
func DeleteIssuePriorityDef(ctx context.Context, id int64) error {
|
|
if _, err := db.GetEngine(ctx).Exec("UPDATE issue SET priority_id = 0 WHERE priority_id = ?", id); err != nil {
|
|
return err
|
|
}
|
|
_, err := db.GetEngine(ctx).ID(id).Delete(new(IssuePriorityDef))
|
|
return err
|
|
}
|
|
|
|
// SetIssuePriorityID updates the priority_id on an issue.
|
|
func SetIssuePriorityID(ctx context.Context, issueID, priorityID int64) error {
|
|
_, err := db.GetEngine(ctx).Exec("UPDATE issue SET priority_id = ? WHERE id = ?", priorityID, issueID)
|
|
return err
|
|
}
|