2
0
Files
gitcaddy-server/routers/web/org/setting_packages.go
logikonline 16b47f5362
Some checks failed
Build and Release / Create Release (push) Has been skipped
Build and Release / Unit Tests (push) Failing after 3m5s
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 4m59s
Build and Release / Lint (push) Successful in 5m6s
Build and Release / Build Binaries (amd64, linux, linux-latest) (push) Has been skipped
Build and Release / Build Binaries (amd64, windows, windows-latest) (push) Has been skipped
Build and Release / Build Binaries (amd64, darwin, macos) (push) Has been skipped
Build and Release / Build Binaries (arm64, darwin, macos) (push) Has been skipped
Build and Release / Build Binary (linux/arm64) (push) Has been skipped
feat(packages): add package defaults configuration for orgs
Add ability for organizations to preconfigure default package metadata (authors, company, copyright, icon) that AI tools can use when building packages. Includes database model, org settings UI with icon upload, MCP tool for retrieving defaults with repo-specific URLs, and localization strings.
2026-01-25 22:40:34 -05:00

221 lines
6.6 KiB
Go

// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package org
import (
"fmt"
"io"
"net/http"
packages_model "code.gitcaddy.com/server/v3/models/packages"
"code.gitcaddy.com/server/v3/modules/avatar"
"code.gitcaddy.com/server/v3/modules/setting"
"code.gitcaddy.com/server/v3/modules/storage"
"code.gitcaddy.com/server/v3/modules/templates"
"code.gitcaddy.com/server/v3/modules/typesniffer"
shared "code.gitcaddy.com/server/v3/routers/web/shared/packages"
shared_user "code.gitcaddy.com/server/v3/routers/web/shared/user"
"code.gitcaddy.com/server/v3/services/context"
)
const (
tplSettingsPackages templates.TplName = "org/settings/packages"
tplSettingsPackagesRuleEdit templates.TplName = "org/settings/packages_cleanup_rules_edit"
tplSettingsPackagesRulePreview templates.TplName = "org/settings/packages_cleanup_rules_preview"
)
func Packages(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("packages.title")
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsSettingsPackages"] = true
if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
ctx.ServerError("RenderUserOrgHeader", err)
return
}
defaults, err := packages_model.GetPackageDefaultsByOwnerID(ctx, ctx.ContextUser.ID)
if err != nil {
ctx.ServerError("GetPackageDefaultsByOwnerID", err)
return
}
ctx.Data["PackageDefaults"] = defaults
shared.SetPackagesContext(ctx, ctx.ContextUser)
ctx.HTML(http.StatusOK, tplSettingsPackages)
}
func PackageDefaultsPost(ctx *context.Context) {
defaults, err := packages_model.GetPackageDefaultsByOwnerID(ctx, ctx.ContextUser.ID)
if err != nil {
ctx.ServerError("GetPackageDefaultsByOwnerID", err)
return
}
defaults.Authors = ctx.FormString("authors")
defaults.Company = ctx.FormString("company")
defaults.Copyright = ctx.FormString("copyright")
if err := packages_model.CreateOrUpdatePackageDefaults(ctx, defaults); err != nil {
ctx.ServerError("CreateOrUpdatePackageDefaults", err)
return
}
ctx.Flash.Success(ctx.Tr("packages.settings.preconfigure.saved"))
ctx.Redirect(fmt.Sprintf("%s/org/%s/settings/packages", setting.AppSubURL, ctx.ContextUser.Name))
}
func PackageDefaultsIconPost(ctx *context.Context) {
file, header, err := ctx.Req.FormFile("icon")
if err != nil {
ctx.Flash.Error(ctx.Tr("packages.settings.preconfigure.icon.error"))
ctx.Redirect(fmt.Sprintf("%s/org/%s/settings/packages", setting.AppSubURL, ctx.ContextUser.Name))
return
}
defer file.Close()
if header.Size > setting.Avatar.MaxFileSize {
ctx.Flash.Error(ctx.Tr("settings.uploaded_avatar_is_too_big", header.Size/1024, setting.Avatar.MaxFileSize/1024))
ctx.Redirect(fmt.Sprintf("%s/org/%s/settings/packages", setting.AppSubURL, ctx.ContextUser.Name))
return
}
data, err := io.ReadAll(file)
if err != nil {
ctx.ServerError("io.ReadAll", err)
return
}
st := typesniffer.DetectContentType(data)
if !(st.IsImage() && !st.IsSvgImage()) {
ctx.Flash.Error(ctx.Tr("settings.uploaded_avatar_not_a_image"))
ctx.Redirect(fmt.Sprintf("%s/org/%s/settings/packages", setting.AppSubURL, ctx.ContextUser.Name))
return
}
// Process/resize the image
processedData, err := avatar.ProcessAvatarImage(data)
if err != nil {
ctx.ServerError("ProcessAvatarImage", err)
return
}
// Save to storage
iconPath := fmt.Sprintf("package-icons/%d", ctx.ContextUser.ID)
if err := storage.SaveFrom(storage.Avatars, iconPath, func(w io.Writer) error {
_, err := w.Write(processedData)
return err
}); err != nil {
ctx.ServerError("storage.SaveFrom", err)
return
}
// Update database
defaults, err := packages_model.GetPackageDefaultsByOwnerID(ctx, ctx.ContextUser.ID)
if err != nil {
ctx.ServerError("GetPackageDefaultsByOwnerID", err)
return
}
defaults.IconPath = iconPath
if err := packages_model.CreateOrUpdatePackageDefaults(ctx, defaults); err != nil {
ctx.ServerError("CreateOrUpdatePackageDefaults", err)
return
}
ctx.Flash.Success(ctx.Tr("packages.settings.preconfigure.icon.saved"))
ctx.Redirect(fmt.Sprintf("%s/org/%s/settings/packages", setting.AppSubURL, ctx.ContextUser.Name))
}
func PackagesRuleAdd(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("packages.title")
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsSettingsPackages"] = true
if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
ctx.ServerError("RenderUserOrgHeader", err)
return
}
shared.SetRuleAddContext(ctx)
ctx.HTML(http.StatusOK, tplSettingsPackagesRuleEdit)
}
func PackagesRuleEdit(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("packages.title")
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsSettingsPackages"] = true
if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
ctx.ServerError("RenderUserOrgHeader", err)
return
}
shared.SetRuleEditContext(ctx, ctx.ContextUser)
ctx.HTML(http.StatusOK, tplSettingsPackagesRuleEdit)
}
func PackagesRuleAddPost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("packages.title")
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsSettingsPackages"] = true
shared.PerformRuleAddPost(
ctx,
ctx.ContextUser,
fmt.Sprintf("%s/org/%s/settings/packages", setting.AppSubURL, ctx.ContextUser.Name),
tplSettingsPackagesRuleEdit,
)
}
func PackagesRuleEditPost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("packages.title")
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsSettingsPackages"] = true
shared.PerformRuleEditPost(
ctx,
ctx.ContextUser,
fmt.Sprintf("%s/org/%s/settings/packages", setting.AppSubURL, ctx.ContextUser.Name),
tplSettingsPackagesRuleEdit,
)
}
func PackagesRulePreview(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("packages.title")
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsSettingsPackages"] = true
if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
ctx.ServerError("RenderUserOrgHeader", err)
return
}
shared.SetRulePreviewContext(ctx, ctx.ContextUser)
ctx.HTML(http.StatusOK, tplSettingsPackagesRulePreview)
}
func InitializeCargoIndex(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("packages.title")
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsSettingsPackages"] = true
shared.InitializeCargoIndex(ctx, ctx.ContextUser)
ctx.Redirect(fmt.Sprintf("%s/org/%s/settings/packages", setting.AppSubURL, ctx.ContextUser.Name))
}
func RebuildCargoIndex(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("packages.title")
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsSettingsPackages"] = true
shared.RebuildCargoIndex(ctx, ctx.ContextUser)
ctx.Redirect(fmt.Sprintf("%s/org/%s/settings/packages", setting.AppSubURL, ctx.ContextUser.Name))
}