549e890cd0
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Generic: Project CI / Lint & Validate (push) Successful in 40s
Deploy MokoGitea / deploy (push) Successful in 5m29s
Generic: Project CI / Tests (push) Has been cancelled
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
Rename the licensing/update server model package to better reflect its purpose. All imports updated from licenses_model to updateserver_model. License key management UI files kept (only imports updated).
139 lines
4.0 KiB
Go
139 lines
4.0 KiB
Go
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package updateserver
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
|
|
updateserver_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/updateserver"
|
|
repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
|
|
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
|
|
)
|
|
|
|
// WHMCS module update JSON structures.
|
|
// WHMCS marketplace modules check for updates via a simple JSON endpoint.
|
|
|
|
type WHMCSUpdate struct {
|
|
Name string `json:"name"`
|
|
Version string `json:"version"`
|
|
Description string `json:"description,omitempty"`
|
|
DownloadURL string `json:"download_url,omitempty"`
|
|
Changelog string `json:"changelog,omitempty"`
|
|
ReleaseDate string `json:"release_date"`
|
|
Author string `json:"author,omitempty"`
|
|
AuthorURL string `json:"author_url,omitempty"`
|
|
SHA256 string `json:"sha256,omitempty"`
|
|
}
|
|
|
|
// GenerateWHMCSJSON builds a WHMCS-compatible module update response.
|
|
func GenerateWHMCSJSON(ctx context.Context, repo *repo_model.Repository, licenseKey string) (*WHMCSUpdate, error) {
|
|
releases, err := db.Find[repo_model.Release](ctx, repo_model.FindReleasesOptions{
|
|
RepoID: repo.ID,
|
|
ListOptions: db.ListOptionsAll,
|
|
IncludeDrafts: false,
|
|
IncludeTags: false,
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("FindReleases: %w", err)
|
|
}
|
|
|
|
if err := repo.LoadOwner(ctx); err != nil {
|
|
return nil, fmt.Errorf("LoadOwner: %w", err)
|
|
}
|
|
|
|
baseURL := strings.TrimSuffix(setting.AppURL, "/")
|
|
repoLink := fmt.Sprintf("%s/%s/%s", baseURL, repo.Owner.Name, repo.Name)
|
|
|
|
cfg := updateserver_model.GetEffectiveConfig(ctx, repo.OwnerID, repo.ID)
|
|
meta := resolveExtensionMetadata(ctx, repo, cfg)
|
|
displayName := meta.DisplayName
|
|
description := meta.Description
|
|
maintainer := repo.Owner.Name
|
|
maintainerURL := fmt.Sprintf("%s/%s", baseURL, repo.Owner.Name)
|
|
if cfg != nil {
|
|
if cfg.Maintainer != "" {
|
|
maintainer = cfg.Maintainer
|
|
}
|
|
if cfg.MaintainerURL != "" {
|
|
maintainerURL = cfg.MaintainerURL
|
|
}
|
|
}
|
|
|
|
streams := updateserver_model.GetEffectiveStreams(ctx, repo.OwnerID, repo.ID)
|
|
|
|
// Find latest stable release.
|
|
var latestStable *repo_model.Release
|
|
for _, rel := range releases {
|
|
if rel.IsDraft || rel.IsTag {
|
|
continue
|
|
}
|
|
ch := updateserver_model.ResolveReleaseStream(ctx, rel.ID, rel.TagName, rel.IsPrerelease, streams)
|
|
if ch == "stable" {
|
|
if latestStable == nil || rel.CreatedUnix > latestStable.CreatedUnix {
|
|
latestStable = rel
|
|
}
|
|
}
|
|
}
|
|
|
|
if latestStable == nil {
|
|
return &WHMCSUpdate{
|
|
Name: displayName,
|
|
Version: "0.0.0",
|
|
}, nil
|
|
}
|
|
|
|
if err := latestStable.LoadAttributes(ctx); err != nil {
|
|
return nil, fmt.Errorf("LoadAttributes: %w", err)
|
|
}
|
|
|
|
var downloadURL, sha256Hash string
|
|
for _, att := range latestStable.Attachments {
|
|
if strings.HasSuffix(strings.ToLower(att.Name), ".zip") && !strings.HasSuffix(att.Name, ".sha256") {
|
|
downloadURL = fmt.Sprintf("%s/releases/download/%s/%s", repoLink, latestStable.TagName, att.Name)
|
|
break
|
|
}
|
|
}
|
|
if downloadURL == "" {
|
|
downloadURL = fmt.Sprintf("%s/archive/%s.zip", repoLink, latestStable.TagName)
|
|
}
|
|
if licenseKey != "" {
|
|
downloadURL += "?dlid=" + licenseKey
|
|
}
|
|
for _, att := range latestStable.Attachments {
|
|
if strings.HasSuffix(att.Name, ".sha256") {
|
|
sha256Hash = readSHA256FromSidecar(ctx, att)
|
|
break
|
|
}
|
|
}
|
|
|
|
version := extractVersion(latestStable.TagName)
|
|
if isStreamName(version, streams) || version == "" {
|
|
version = extractVersion(latestStable.Title)
|
|
}
|
|
if version == "" {
|
|
version = latestStable.TagName
|
|
}
|
|
|
|
changelog := ""
|
|
if latestStable.Note != "" {
|
|
changelog = latestStable.Note
|
|
}
|
|
|
|
return &WHMCSUpdate{
|
|
Name: displayName,
|
|
Version: version,
|
|
Description: description,
|
|
DownloadURL: downloadURL,
|
|
Changelog: changelog,
|
|
ReleaseDate: time.Unix(int64(latestStable.CreatedUnix), 0).Format("2006-01-02"),
|
|
Author: maintainer,
|
|
AuthorURL: maintainerURL,
|
|
SHA256: sha256Hash,
|
|
}, nil
|
|
}
|