pushy

Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
This commit is contained in:
2026-06-28 11:29:07 +08:00
parent 463a8d3978
commit 89acdfc239
67 changed files with 2736 additions and 306 deletions
@@ -0,0 +1,136 @@
'use strict';
const mdl_TierCategories = require('../../models/tiers/tier_categories.mdl');
const mdl_TierPlans = require('../../models/tiers/tier_plans.mdl');
const Asset = require('../../models/assets/assets.mdl');
const R = require('../../utils/response.util');
const logActivity = require('../../utils/logActivity.util');
require('../../models/tiers/tier.associations');
const ASSET_ATTRS = ['asset_id', 'file_url', 'display_name', 'mime_type'];
const withBadge = [{ model: Asset, as: 'badgeAsset', attributes: ASSET_ATTRS, required: false }];
// ─── GET /admin/tiers/categories ─────────────────────────────────────────────
exports.getCategories = async (req, res) => {
try {
const categories = await mdl_TierCategories.findAll({
include: withBadge,
order: [['rank', 'ASC']],
});
return R.success(res, 'Tier categories retrieved.', categories);
} catch (err) {
console.error('[ADMIN][GET TIER CATEGORIES]', err);
return R.error(res, 'Could not retrieve tier categories.', 500);
}
};
// ─── GET /admin/tiers/categories/:id ─────────────────────────────────────────
exports.getCategory = async (req, res) => {
try {
const cat = await mdl_TierCategories.findByPk(req.params.id, { include: withBadge });
if (!cat) return R.error(res, 'Tier category not found.', 404);
return R.success(res, 'Tier category retrieved.', cat);
} catch (err) {
console.error('[ADMIN][GET TIER CATEGORY]', err);
return R.error(res, 'Could not retrieve tier category.', 500);
}
};
// ─── POST /admin/tiers/categories ────────────────────────────────────────────
exports.createCategory = async (req, res) => {
try {
const { slug, name, description, rank, color, badge_asset_id, badge_icon, badge_label } = req.body;
if (!slug || !name) return R.error(res, 'slug and name are required.', 400);
const parsedRank = Number(rank ?? 1);
if (parsedRank <= 0) return R.error(res, 'Non-default tier categories must have rank greater than 0.', 400);
const exists = await mdl_TierCategories.findOne({ where: { slug } });
if (exists) return R.error(res, `A tier category with slug "${slug}" already exists.`, 409);
const cat = await mdl_TierCategories.create({
slug, name,
description: description ?? null,
rank: parsedRank,
color: color || 'purple',
badge_asset_id: badge_asset_id || null,
badge_icon: badge_icon || null,
badge_label: badge_label ?? null,
is_default: false,
is_active: true,
});
logActivity(req.user?.user_id, 'create_tier_category', { entityType: 'tier_category', details: { slug, name } });
const result = await mdl_TierCategories.findByPk(cat.tier_category_id, { include: withBadge });
return R.success(res, 'Tier category created.', result, 201);
} catch (err) {
console.error('[ADMIN][CREATE TIER CATEGORY]', err);
return R.error(res, 'Could not create tier category.', 500);
}
};
// ─── PUT /admin/tiers/categories/:id ─────────────────────────────────────────
exports.updateCategory = async (req, res) => {
try {
const cat = await mdl_TierCategories.findByPk(req.params.id);
if (!cat) return R.error(res, 'Tier category not found.', 404);
const { name, description, rank, color, badge_asset_id, badge_icon, badge_label, is_active } = req.body;
if (!cat.is_default && rank !== undefined) {
const parsedRank = Number(rank);
if (parsedRank <= 0) return R.error(res, 'Non-default tier categories must have rank greater than 0.', 400);
}
await cat.update({
name: name ?? cat.name,
description: description !== undefined ? (description || null) : cat.description,
rank: rank !== undefined ? Number(rank) : cat.rank,
color: color !== undefined ? (color || cat.color) : cat.color,
badge_asset_id: badge_asset_id !== undefined ? (badge_asset_id || null) : cat.badge_asset_id,
badge_icon: badge_icon !== undefined ? (badge_icon || null) : cat.badge_icon,
badge_label: badge_label !== undefined ? (badge_label || null) : cat.badge_label,
// Default category (free) cannot be deactivated
is_active: (!cat.is_default && is_active !== undefined) ? is_active : cat.is_active,
});
logActivity(req.user?.user_id, 'update_tier_category', { entityType: 'tier_category', details: { id: cat.tier_category_id, slug: cat.slug } });
const result = await mdl_TierCategories.findByPk(cat.tier_category_id, { include: withBadge });
return R.success(res, 'Tier category updated.', result);
} catch (err) {
console.error('[ADMIN][UPDATE TIER CATEGORY]', err);
return R.error(res, 'Could not update tier category.', 500);
}
};
// ─── DELETE /admin/tiers/categories/:id ──────────────────────────────────────
exports.deleteCategory = async (req, res) => {
try {
const cat = await mdl_TierCategories.findByPk(req.params.id);
if (!cat) return R.error(res, 'Tier category not found.', 404);
if (cat.is_default) return R.error(res, 'The default (Free) tier category cannot be deleted.', 400);
// Block deletion if active plans still reference this category
const activePlans = await mdl_TierPlans.count({
where: { tier_category_id: cat.tier_category_id, is_active: true },
});
if (activePlans > 0)
return R.error(res, `Cannot delete — ${activePlans} active plan(s) belong to this category. Archive or reassign them first.`, 409);
await cat.destroy();
logActivity(req.user?.user_id, 'delete_tier_category', { entityType: 'tier_category', details: { slug: cat.slug } });
return R.success(res, 'Tier category deleted.');
} catch (err) {
console.error('[ADMIN][DELETE TIER CATEGORY]', err);
return R.error(res, 'Could not delete tier category.', 500);
}
};