c572fcfe04
Rename the Go module path from code.gitea.io/gitea to git.mokoconsulting.tech/MokoConsulting/MokoGitea across the entire codebase. Scope: - go.mod module declaration - 2,235 Go source files (import paths) - Dockerfile WORKDIR and COPY paths - Swagger API templates - golangci.yml linter config External dependencies (code.gitea.io/gitea-vet, code.gitea.io/sdk/gitea, gitea.com/gitea/act, etc.) are intentionally NOT renamed — they are separate upstream modules. Closes #132 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
115 lines
4.3 KiB
Go
115 lines
4.3 KiB
Go
// Copyright 2026 Moko Consulting. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package issues
|
|
|
|
import (
|
|
"context"
|
|
|
|
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
|
|
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
|
|
)
|
|
|
|
// CustomFieldDefinition defines a custom field for a repository's issues
|
|
type CustomFieldDefinition struct {
|
|
ID int64 `xorm:"pk autoincr" json:"id"`
|
|
RepoID int64 `xorm:"INDEX NOT NULL" json:"repo_id"`
|
|
Name string `xorm:"NOT NULL" json:"name"`
|
|
FieldType string `xorm:"NOT NULL" json:"field_type"` // text, number, date, dropdown, checkbox
|
|
Description string `json:"description"`
|
|
Required bool `xorm:"NOT NULL DEFAULT false" json:"required"`
|
|
Position int `xorm:"NOT NULL DEFAULT 0" json:"position"`
|
|
Options string `xorm:"TEXT" json:"options"` // JSON array for dropdown options
|
|
DefaultVal string `json:"default_value"`
|
|
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created" json:"created_at"`
|
|
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated" json:"updated_at"`
|
|
}
|
|
|
|
func init() {
|
|
db.RegisterModel(new(CustomFieldDefinition))
|
|
db.RegisterModel(new(CustomFieldValue))
|
|
}
|
|
|
|
// CustomFieldValue stores the value of a custom field for a specific issue
|
|
type CustomFieldValue struct {
|
|
ID int64 `xorm:"pk autoincr" json:"id"`
|
|
IssueID int64 `xorm:"INDEX NOT NULL" json:"issue_id"`
|
|
FieldID int64 `xorm:"INDEX NOT NULL" json:"field_id"`
|
|
Value string `xorm:"TEXT" json:"value"`
|
|
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created" json:"created_at"`
|
|
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated" json:"updated_at"`
|
|
}
|
|
|
|
// GetCustomFieldsByRepoID returns all custom field definitions for a repo
|
|
func GetCustomFieldsByRepoID(ctx context.Context, repoID int64) ([]*CustomFieldDefinition, error) {
|
|
fields := make([]*CustomFieldDefinition, 0)
|
|
return fields, db.GetEngine(ctx).Where("repo_id = ?", repoID).OrderBy("position ASC").Find(&fields)
|
|
}
|
|
|
|
// GetCustomFieldByID returns a custom field definition by ID
|
|
func GetCustomFieldByID(ctx context.Context, id int64) (*CustomFieldDefinition, error) {
|
|
field := &CustomFieldDefinition{ID: id}
|
|
has, err := db.GetEngine(ctx).Get(field)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !has {
|
|
return nil, nil
|
|
}
|
|
return field, nil
|
|
}
|
|
|
|
// CreateCustomField creates a new custom field definition
|
|
func CreateCustomField(ctx context.Context, field *CustomFieldDefinition) error {
|
|
_, err := db.GetEngine(ctx).Insert(field)
|
|
return err
|
|
}
|
|
|
|
// UpdateCustomField updates a custom field definition
|
|
func UpdateCustomField(ctx context.Context, field *CustomFieldDefinition) error {
|
|
_, err := db.GetEngine(ctx).ID(field.ID).AllCols().Update(field)
|
|
return err
|
|
}
|
|
|
|
// DeleteCustomField deletes a custom field and all its values
|
|
func DeleteCustomField(ctx context.Context, id int64) error {
|
|
sess := db.GetEngine(ctx)
|
|
if _, err := sess.Where("field_id = ?", id).Delete(&CustomFieldValue{}); err != nil {
|
|
return err
|
|
}
|
|
_, err := sess.ID(id).Delete(&CustomFieldDefinition{})
|
|
return err
|
|
}
|
|
|
|
// GetCustomFieldValues returns all custom field values for an issue
|
|
func GetCustomFieldValues(ctx context.Context, issueID int64) ([]*CustomFieldValue, error) {
|
|
values := make([]*CustomFieldValue, 0)
|
|
return values, db.GetEngine(ctx).Where("issue_id = ?", issueID).Find(&values)
|
|
}
|
|
|
|
// SetCustomFieldValue sets or updates a custom field value for an issue
|
|
func SetCustomFieldValue(ctx context.Context, issueID, fieldID int64, value string) error {
|
|
existing := &CustomFieldValue{}
|
|
has, err := db.GetEngine(ctx).Where("issue_id = ? AND field_id = ?", issueID, fieldID).Get(existing)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if has {
|
|
existing.Value = value
|
|
_, err = db.GetEngine(ctx).ID(existing.ID).Cols("value").Update(existing)
|
|
return err
|
|
}
|
|
_, err = db.GetEngine(ctx).Insert(&CustomFieldValue{
|
|
IssueID: issueID,
|
|
FieldID: fieldID,
|
|
Value: value,
|
|
})
|
|
return err
|
|
}
|
|
|
|
// DeleteCustomFieldValue deletes a specific custom field value
|
|
func DeleteCustomFieldValue(ctx context.Context, issueID, fieldID int64) error {
|
|
_, err := db.GetEngine(ctx).Where("issue_id = ? AND field_id = ?", issueID, fieldID).Delete(&CustomFieldValue{})
|
|
return err
|
|
}
|