feat(updates): per-repo platform + require-key + platform buttons #286
@@ -24,6 +24,8 @@ type UpdateStreamConfig struct {
|
||||
OwnerID int64 `xorm:"INDEX NOT NULL"` // org or user
|
||||
RepoID int64 `xorm:"INDEX NOT NULL DEFAULT 0"` // 0 = org-level default
|
||||
StreamMode string `xorm:"NOT NULL DEFAULT 'joomla'"` // joomla, custom
|
||||
Platform string `xorm:"NOT NULL DEFAULT 'joomla'"` // joomla, dolibarr, both
|
||||
RequireKey bool `xorm:"NOT NULL DEFAULT false"` // require license key for update feed
|
||||
// CustomStreams is a JSON array of stream definitions.
|
||||
// Each entry: {"name":"lts","suffix":"-lts","description":"Long-term support"}
|
||||
CustomStreams string `xorm:"TEXT"`
|
||||
|
||||
@@ -414,6 +414,8 @@ func prepareMigrationTasks() []*migration {
|
||||
newMigration(334, "Add actions user whitelist to protected branches", v1_27.AddActionsUserWhitelistToProtectedBranch),
|
||||
newMigration(335, "Add license key tables for update server", v1_27.AddLicenseKeyTables),
|
||||
newMigration(336, "Add update stream config table", v1_27.AddUpdateStreamConfigTable),
|
||||
newMigration(337, "Add key_plain column to license_key", v1_27.AddKeyPlainToLicenseKey),
|
||||
newMigration(338, "Add platform and require_key to update_stream_config", v1_27.AddPlatformAndRequireKeyToStreamConfig),
|
||||
}
|
||||
return preparedMigrations
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package v1_27
|
||||
|
||||
import "xorm.io/xorm"
|
||||
|
||||
type licenseKey337 struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
KeyPlain string `xorm:""`
|
||||
}
|
||||
|
||||
func (licenseKey337) TableName() string {
|
||||
return "license_key"
|
||||
}
|
||||
|
||||
// AddKeyPlainToLicenseKey adds the key_plain column to license_key table.
|
||||
func AddKeyPlainToLicenseKey(x *xorm.Engine) error {
|
||||
return x.Sync(new(licenseKey337))
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package v1_27
|
||||
|
||||
import "xorm.io/xorm"
|
||||
|
||||
type updateStreamConfig338 struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Platform string `xorm:"NOT NULL DEFAULT 'joomla'"`
|
||||
RequireKey bool `xorm:"NOT NULL DEFAULT false"`
|
||||
}
|
||||
|
||||
func (updateStreamConfig338) TableName() string {
|
||||
return "update_stream_config"
|
||||
}
|
||||
|
||||
// AddPlatformAndRequireKeyToStreamConfig adds platform and require_key
|
||||
// columns to update_stream_config.
|
||||
func AddPlatformAndRequireKeyToStreamConfig(x *xorm.Engine) error {
|
||||
return x.Sync(new(updateStreamConfig338))
|
||||
}
|
||||
@@ -2147,7 +2147,10 @@
|
||||
"repo.settings.unit_visibility": "Visibility",
|
||||
"repo.settings.unit_visibility_private": "Private (follow repo visibility)",
|
||||
"repo.settings.unit_visibility_public": "Public (anyone can read)",
|
||||
"repo.settings.unit_visibility_releases_help": "Update feeds (updates.xml, dolibarr.json) are always accessible regardless of this setting. Set to Public to also show the releases page to anonymous visitors.",
|
||||
"repo.settings.unit_visibility_releases_help": "Controls whether the releases page is visible to anonymous visitors.",
|
||||
"repo.settings.update_platform": "Update Server Platform",
|
||||
"repo.settings.update_platform_both": "Both (Joomla + Dolibarr)",
|
||||
"repo.settings.require_update_key": "Require license key for update feed access",
|
||||
"repo.settings.packages_desc": "Enable Repository Packages Registry",
|
||||
"repo.settings.projects_desc": "Enable Projects",
|
||||
"repo.settings.projects_mode_desc": "Projects Mode (which kinds of projects to show)",
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
|
||||
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/organization"
|
||||
licenses_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/licenses"
|
||||
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/perm"
|
||||
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
|
||||
unit_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unit"
|
||||
@@ -100,6 +101,8 @@ func SettingsCtxData(ctx *context.Context) {
|
||||
|
||||
// Settings show a repository's settings page
|
||||
func Settings(ctx *context.Context) {
|
||||
repoCfg, _ := licenses_model.GetRepoConfig(ctx, ctx.Repo.Repository.ID)
|
||||
ctx.Data["RepoUpdateConfig"] = repoCfg
|
||||
ctx.HTML(http.StatusOK, tplSettingsOptions)
|
||||
}
|
||||
|
||||
@@ -672,6 +675,22 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
}
|
||||
// Save update server platform and require-key settings.
|
||||
updatePlatform := form.UpdatePlatform
|
||||
if updatePlatform == "" {
|
||||
updatePlatform = "joomla"
|
||||
}
|
||||
updateCfg := &licenses_model.UpdateStreamConfig{
|
||||
OwnerID: repo.OwnerID,
|
||||
RepoID: repo.ID,
|
||||
Platform: updatePlatform,
|
||||
RequireKey: form.RequireUpdateKey,
|
||||
StreamMode: "joomla", // inherit org default
|
||||
}
|
||||
if err := licenses_model.SaveConfig(ctx, updateCfg); err != nil {
|
||||
log.Error("SaveConfig: %v", err)
|
||||
}
|
||||
|
||||
log.Trace("Repository advanced settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
||||
|
||||
@@ -23,7 +23,13 @@ func validateUpdateKey(ctx *context.Context) (allowedChannels []string, ok bool)
|
||||
}
|
||||
|
||||
if rawKey == "" {
|
||||
// No key provided — allow public access (all channels).
|
||||
// Check if this repo requires a key for update feed access.
|
||||
repoCfg, _ := licenses.GetRepoConfig(ctx, ctx.Repo.Repository.ID)
|
||||
if repoCfg != nil && repoCfg.RequireKey {
|
||||
// Key required but not provided — return empty.
|
||||
return nil, false
|
||||
}
|
||||
// No key required — allow public access (all channels).
|
||||
return nil, true
|
||||
}
|
||||
|
||||
|
||||
@@ -614,6 +614,14 @@ func repoAssignmentPrepareTemplateData(ctx *Context, data *repoAssignmentPrepare
|
||||
ctx.Data["EnableLicenses"] = numLicensePackages > 0
|
||||
ctx.Data["IsRepoAdmin"] = ctx.Repo.Permission.IsAdmin()
|
||||
|
||||
// Load repo update config for platform-aware UI.
|
||||
repoUpdateCfg, _ := licenses_model.GetRepoConfig(ctx, repo.ID)
|
||||
if repoUpdateCfg != nil {
|
||||
ctx.Data["RepoUpdatePlatform"] = repoUpdateCfg.Platform
|
||||
} else {
|
||||
ctx.Data["RepoUpdatePlatform"] = "joomla"
|
||||
}
|
||||
|
||||
ctx.Data["Title"] = repo.Owner.Name + "/" + repo.Name
|
||||
ctx.Data["PageTitleCommon"] = repo.Name + " - " + setting.AppName
|
||||
ctx.Data["Repository"] = repo
|
||||
|
||||
@@ -133,6 +133,8 @@ type RepoSettingForm struct {
|
||||
|
||||
EnableReleases bool
|
||||
ReleasesVisibility string
|
||||
UpdatePlatform string
|
||||
RequireUpdateKey bool
|
||||
|
||||
EnablePackages bool
|
||||
|
||||
|
||||
@@ -17,9 +17,16 @@
|
||||
</a>
|
||||
{{end}}
|
||||
{{if not .PageIsTagList}}
|
||||
<a class="ui small button" href="{{.RepoLink}}/updates.xml" target="_blank">
|
||||
{{svg "octicon-download" 16}} {{ctx.Locale.Tr "repo.release.update_feed"}}
|
||||
</a>
|
||||
{{if or (eq .RepoUpdatePlatform "joomla") (eq .RepoUpdatePlatform "both") (eq .RepoUpdatePlatform "")}}
|
||||
<a class="ui small button" href="{{.RepoLink}}/updates.xml" target="_blank">
|
||||
{{svg "octicon-download" 16}} Joomla XML
|
||||
</a>
|
||||
{{end}}
|
||||
{{if or (eq .RepoUpdatePlatform "dolibarr") (eq .RepoUpdatePlatform "both")}}
|
||||
<a class="ui small button" href="{{.RepoLink}}/updates/dolibarr.json" target="_blank">
|
||||
{{svg "octicon-download" 16}} Dolibarr JSON
|
||||
</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if and (not .PageIsTagList) .CanCreateRelease}}
|
||||
<a class="ui small primary button" href="{{$.RepoLink}}/releases/new{{if .PageIsSingleTag}}?tag={{.SingleReleaseTagName}}{{end}}">
|
||||
|
||||
@@ -514,6 +514,20 @@
|
||||
</select>
|
||||
<p class="help">{{ctx.Locale.Tr "repo.settings.unit_visibility_releases_help"}}</p>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.update_platform"}}</label>
|
||||
<select name="update_platform" class="ui dropdown">
|
||||
<option value="joomla" {{if or (not .RepoUpdateConfig) (eq .RepoUpdateConfig.Platform "joomla") (eq .RepoUpdateConfig.Platform "")}}selected{{end}}>Joomla (updates.xml)</option>
|
||||
<option value="dolibarr" {{if and .RepoUpdateConfig (eq .RepoUpdateConfig.Platform "dolibarr")}}selected{{end}}>Dolibarr (JSON)</option>
|
||||
<option value="both" {{if and .RepoUpdateConfig (eq .RepoUpdateConfig.Platform "both")}}selected{{end}}>{{ctx.Locale.Tr "repo.settings.update_platform_both"}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="require_update_key" type="checkbox" {{if and .RepoUpdateConfig .RepoUpdateConfig.RequireKey}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.require_update_key"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{$isPackagesEnabled := .Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypePackages}}
|
||||
|
||||
Reference in New Issue
Block a user