// Copyright 2026 Moko Consulting // SPDX-License-Identifier: GPL-3.0-or-later package org import ( "net/http" "strconv" issues_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/issues" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/templates" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/context" ) const tplOrgCustomFields templates.TplName = "org/settings/custom_fields" // SettingsCustomFields shows the org-level custom fields management page. func SettingsCustomFields(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("org.settings.custom_fields") ctx.Data["PageIsOrgSettings"] = true ctx.Data["PageIsSettingsCustomFields"] = true fields, err := issues_model.GetAllCustomFieldsByOwner(ctx, ctx.Org.Organization.ID) if err != nil { ctx.ServerError("GetAllCustomFieldsByOwner", err) return } ctx.Data["CustomFields"] = fields ctx.HTML(http.StatusOK, tplOrgCustomFields) } // SettingsCustomFieldsCreatePost creates a new org-level custom field. func SettingsCustomFieldsCreatePost(ctx *context.Context) { sortOrder, _ := strconv.Atoi(ctx.FormString("sort_order")) scope := issues_model.CustomFieldScope(ctx.FormString("scope")) if scope != issues_model.CustomFieldScopeIssue && scope != issues_model.CustomFieldScopeRepo { scope = issues_model.CustomFieldScopeIssue } field := &issues_model.CustomFieldDef{ OwnerID: ctx.Org.Organization.ID, RepoID: 0, // org-level Scope: scope, Name: ctx.FormString("name"), FieldType: issues_model.CustomFieldType(ctx.FormString("field_type")), Description: ctx.FormString("description"), Options: ctx.FormString("options"), Required: ctx.FormString("required") == "on", SortOrder: sortOrder, IsActive: true, } if field.Name == "" { ctx.Flash.Error("Field name is required") ctx.Redirect(ctx.Org.OrgLink + "/settings/custom-fields") return } if err := issues_model.CreateCustomFieldDef(ctx, field); err != nil { ctx.ServerError("CreateCustomFieldDef", err) return } ctx.Flash.Success(ctx.Tr("org.settings.custom_field_created")) ctx.Redirect(ctx.Org.OrgLink + "/settings/custom-fields") } // SettingsCustomFieldsEditPost updates an org-level custom field. func SettingsCustomFieldsEditPost(ctx *context.Context) { id := ctx.PathParamInt64("id") field, err := issues_model.GetCustomFieldDefByID(ctx, id) if err != nil { ctx.ServerError("GetCustomFieldDefByID", err) return } if field.OwnerID != ctx.Org.Organization.ID { ctx.NotFound(nil) return } field.Name = ctx.FormString("name") field.FieldType = issues_model.CustomFieldType(ctx.FormString("field_type")) field.Description = ctx.FormString("description") field.Options = ctx.FormString("options") field.Required = ctx.FormString("required") == "on" field.IsActive = ctx.FormString("is_active") == "on" sortOrder, _ := strconv.Atoi(ctx.FormString("sort_order")) field.SortOrder = sortOrder if err := issues_model.UpdateCustomFieldDef(ctx, field); err != nil { ctx.ServerError("UpdateCustomFieldDef", err) return } ctx.Flash.Success(ctx.Tr("org.settings.custom_field_updated")) ctx.Redirect(ctx.Org.OrgLink + "/settings/custom-fields") } // SettingsCustomFieldsDeletePost deletes an org-level custom field. func SettingsCustomFieldsDeletePost(ctx *context.Context) { id := ctx.PathParamInt64("id") field, err := issues_model.GetCustomFieldDefByID(ctx, id) if err != nil { ctx.ServerError("GetCustomFieldDefByID", err) return } if field.OwnerID != ctx.Org.Organization.ID { ctx.NotFound(nil) return } if err := issues_model.DeleteCustomFieldDef(ctx, id); err != nil { ctx.ServerError("DeleteCustomFieldDef", err) return } ctx.Flash.Success(ctx.Tr("org.settings.custom_field_deleted")) ctx.Redirect(ctx.Org.OrgLink + "/settings/custom-fields") }