feat(plugins): sell khanegi plugins as priced subscriptions

Catalog prices, purchase requests, and setting-key activation live on SuperAdmin so module admins can buy add-ons. Also rewrite legacy nerkh logo hosts to the SuperAdmin upload origin.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-07 16:56:51 +03:30
co-authored by Cursor
parent ccf7e90922
commit 1f776cf6e2
16 changed files with 1386 additions and 14 deletions
+9 -3
View File
@@ -2,6 +2,8 @@ import { Injectable, NotFoundException } from '@nestjs/common';
import { iranDaysUntil } from '../common/iran-time.util';
import { PrismaService } from '../prisma/prisma.service';
import { applyKhanegiNavSample } from './khanegi-nav-sample';
import { rewriteLegacyUploadUrl } from '../uploads/uploads.util';
import { RuntimeSettingsService } from '../notifications/runtime-settings.service';
type UiSetting = { key: string; value: string };
@@ -23,7 +25,10 @@ type SubscriptionAlerts = {
@Injectable()
export class GetUserService {
constructor(private readonly prisma: PrismaService) {}
constructor(
private readonly prisma: PrismaService,
private readonly runtime: RuntimeSettingsService,
) {}
async resolveByHost(hostHeader?: string, domainQuery?: string) {
const host = this.normalizeHost(domainQuery || hostHeader || '');
@@ -88,7 +93,7 @@ export class GetUserService {
name: tenant.nameEn || tenant.slug,
name_fa: tenant.nameFa,
name_en: tenant.nameEn,
avatar: tenant.avatarUrl,
avatar: rewriteLegacyUploadUrl(tenant.avatarUrl),
color,
secondary_color: secondary,
background_color: background,
@@ -111,6 +116,7 @@ export class GetUserService {
ui_settings: uiSettings.length ? uiSettings : undefined,
/** Admin expiry modals — near/expired server, plugin, support */
subscription_alerts,
plugin_store_enabled: isKhanegi ? this.runtime.getPluginStoreEnabled() : false,
};
return {
@@ -265,7 +271,7 @@ export class GetUserService {
}
private toAbsoluteIconUrl(raw: unknown): string {
const value = String(raw || '').trim();
const value = rewriteLegacyUploadUrl(raw);
if (!value) return '';
if (/^(https?:\/\/|data:)/i.test(value)) return value;
if (value.startsWith('//')) return `https:${value}`;