bab29a83fa
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
110 lines
3.3 KiB
Go
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
|
|
}
|