Files
jmiller bab29a83fa refactor: rename Go module path MokoConsulting/MokoGitea -> MokoConsulting/MokoGIT
Sweep all .go imports + go.mod, plus module-path refs in .golangci.yml,
Dockerfile, swagger templates, locale example, and repo/wiki URLs
(MokoGitea-Fork -> MokoGIT). Part of the MokoGIT rebrand.

Claude-Session: https://claude.ai/code/session_01Bqe7fAuHQeiLueYfeHFrHw
2026-07-14 15:31:19 -05:00

110 lines
3.3 KiB
Go

// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
// SPDX-License-Identifier: GPL-3.0-or-later
package licensing
import (
"context"
"code.mokoconsulting.tech/MokoConsulting/MokoGIT/models/db"
"code.mokoconsulting.tech/MokoConsulting/MokoGIT/modules/json"
"code.mokoconsulting.tech/MokoConsulting/MokoGIT/modules/timeutil"
)
func init() {
db.RegisterModel(new(LicenseEntitlement))
}
// LicenseEntitlement maps a license to an individual product (repo) it can access.
type LicenseEntitlement struct {
ID int64 `xorm:"pk autoincr"`
LicenseID int64 `xorm:"INDEX NOT NULL"`
ProductCode string `xorm:"VARCHAR(30) NOT NULL"`
RepoOwner string `xorm:"VARCHAR(100) NOT NULL DEFAULT 'MokoConsulting'"`
RepoName string `xorm:"VARCHAR(100) NOT NULL"`
IsCustom bool `xorm:"NOT NULL DEFAULT false"` // true = manually added, survives tier changes
CreatedAt timeutil.TimeStamp `xorm:"CREATED"`
}
func (LicenseEntitlement) TableName() string {
return "license_entitlement"
}
// GetEntitlementsByLicense returns all entitlements for a license.
func GetEntitlementsByLicense(ctx context.Context, licenseID int64) ([]*LicenseEntitlement, error) {
var ents []*LicenseEntitlement
return ents, db.GetEngine(ctx).Where("license_id = ?", licenseID).Find(&ents)
}
// HasEntitlement checks if a license has access to a specific product code.
func HasEntitlement(ctx context.Context, licenseID int64, productCode string) (bool, error) {
return db.GetEngine(ctx).
Where("license_id = ? AND product_code = ?", licenseID, productCode).
Exist(new(LicenseEntitlement))
}
// AddCustomEntitlement adds a manual entitlement that survives tier changes.
func AddCustomEntitlement(ctx context.Context, licenseID int64, productCode, repoName string) error {
ent := &LicenseEntitlement{
LicenseID: licenseID,
ProductCode: productCode,
RepoOwner: "MokoConsulting",
RepoName: repoName,
IsCustom: true,
}
_, err := db.GetEngine(ctx).Insert(ent)
return err
}
// RebuildEntitlements deletes non-custom entitlements and rebuilds from the product tier.
// Custom entitlements (manually added) are preserved.
func RebuildEntitlements(ctx context.Context, licenseID int64, tierKey string) error {
// Delete non-custom entitlements
_, err := db.GetEngine(ctx).
Where("license_id = ? AND is_custom = ?", licenseID, false).
Delete(new(LicenseEntitlement))
if err != nil {
return err
}
// Look up tier
tier, err := GetProductTierByKey(ctx, tierKey)
if err != nil || tier == nil {
return err
}
// Parse repos JSON
var repos []string
if err := json.Unmarshal([]byte(tier.Repos), &repos); err != nil {
return err
}
// Build product code from repo name (lowercase, stripped)
for _, repoName := range repos {
productCode := repoName
// Check if this entitlement already exists (custom)
exists, err := db.GetEngine(ctx).
Where("license_id = ? AND product_code = ?", licenseID, productCode).
Exist(new(LicenseEntitlement))
if err != nil {
return err
}
if exists {
continue
}
ent := &LicenseEntitlement{
LicenseID: licenseID,
ProductCode: productCode,
RepoOwner: "MokoConsulting",
RepoName: repoName,
IsCustom: false,
}
if _, err := db.GetEngine(ctx).Insert(ent); err != nil {
return err
}
}
return nil
}