dfssdfsfdsf
This commit is contained in:
2026-04-09 21:00:04 +02:00
parent 983b67e6fc
commit 89bc86b615
27 changed files with 2921 additions and 408 deletions

View File

@@ -11,10 +11,11 @@ import { validate, rules } from '../middleware/validate.mjs'
import { limiters } from '../middleware/rateLimit.mjs'
import { respond } from '../utils/response.mjs'
import { subscriptions, submissions } from '../services/database.mjs'
import { config } from '../config/index.mjs'
import { config, isAdmin } from '../config/index.mjs'
import { log } from '../middleware/logger.mjs'
import { requireAuth } from '../middleware/auth.mjs'
import { loadEmailTemplate, renderTemplate, sendPlainEmail } from '../utils/mailer.mjs'
import { isAppwriteCollectionMissing } from '../utils/appwriteErrors.mjs'
const router = express.Router()
@@ -165,30 +166,91 @@ router.post('/checkout',
/**
* GET /api/subscription/status
* Get user's subscription status
* (Also registered on app in index.mjs before router mount.)
*/
router.get('/status', asyncHandler(async (req, res) => {
export async function handleGetSubscriptionStatus(req, res) {
const userId = req.appwriteUser.id
const sub = await subscriptions.getByUser(userId, req.appwriteUser?.email)
const topKey = config.topSubscriptionPlan
const plan = sub.plan || topKey
const features =
PLANS[plan]?.features ||
PLANS[topKey]?.features ||
PLANS.business.features
if (isAdmin(req.appwriteUser.email)) {
return respond.success(res, {
status: 'active',
plan: 'business',
planDisplayName: 'Business (Admin)',
isFreeTier: false,
emailsUsedThisMonth: 0,
emailsLimit: 999999,
features: {
emailAccounts: 999,
emailsPerDay: 999999,
historicalSync: true,
customRules: true,
prioritySupport: true,
},
})
}
respond.success(res, {
status: sub.status || 'active',
plan,
planDisplayName: PLAN_DISPLAY_NAMES[plan] || PLAN_DISPLAY_NAMES[topKey] || 'Business',
isFreeTier: Boolean(sub.isFreeTier),
emailsUsedThisMonth: sub.emailsUsedThisMonth ?? 0,
emailsLimit: sub.emailsLimit ?? -1,
features,
currentPeriodEnd: sub.currentPeriodEnd,
cancelAtPeriodEnd: Boolean(sub.cancelAtPeriodEnd),
})
}))
try {
const sub = await subscriptions.getByUser(userId, req.appwriteUser?.email)
// No subscription document yet (synthetic free tier from DB layer) — safe defaults, not 404
if (!sub?.$id && sub?.plan === 'free') {
return respond.success(res, {
status: 'free',
plan: 'free',
planDisplayName: PLAN_DISPLAY_NAMES.free,
isFreeTier: true,
emailsUsedThisMonth: sub.emailsUsedThisMonth ?? 0,
emailsLimit: sub.emailsLimit ?? 500,
features: {
emailAccounts: 1,
emailsPerDay: 50,
historicalSync: false,
customRules: false,
prioritySupport: false,
},
})
}
const topKey = config.topSubscriptionPlan
const plan = sub.plan || topKey
const features =
PLANS[plan]?.features ||
PLANS[topKey]?.features ||
PLANS.business.features
return respond.success(res, {
status: sub.status || 'active',
plan,
planDisplayName: PLAN_DISPLAY_NAMES[plan] || PLAN_DISPLAY_NAMES[topKey] || 'Business',
isFreeTier: Boolean(sub.isFreeTier),
emailsUsedThisMonth: sub.emailsUsedThisMonth ?? 0,
emailsLimit: sub.emailsLimit ?? -1,
features,
currentPeriodEnd: sub.currentPeriodEnd,
cancelAtPeriodEnd: Boolean(sub.cancelAtPeriodEnd),
})
} catch (err) {
if (isAppwriteCollectionMissing(err)) {
return respond.success(res, {
status: 'free',
plan: 'free',
isFreeTier: true,
emailsUsedThisMonth: 0,
emailsLimit: 50,
features: {
emailAccounts: 1,
emailsPerDay: 50,
historicalSync: false,
customRules: false,
prioritySupport: false,
},
})
}
throw err
}
}
router.get('/status', asyncHandler(handleGetSubscriptionStatus))
/**
* POST /api/subscription/portal