admin user and ui panel

This commit is contained in:
s.esmaeili
2026-09-21 08:32:31 +03:30
parent 79226c9f13
commit ef1d4638cc
341 changed files with 2270 additions and 657 deletions
@@ -1,4 +1,14 @@
import { Body, Controller, Delete, Get, HttpCode, Param, Post, Put } from '@nestjs/common';
import {
Body,
Controller,
Delete,
ForbiddenException,
Get,
HttpCode,
Param,
Post,
Put,
} from '@nestjs/common';
import { AdminMiscService } from './admin-misc.service';
import { TableQueryDto } from '../admin-table/table-query.dto';
import { CurrentAdmin, RequirePermission } from '../auth/guards';
@@ -162,15 +172,44 @@ export class AdminMiscController {
return this.misc.removeBrand(id);
}
// The mobile home slider ("اسلایدر موبایل") is stored under the same
// `Setting` table as every other `const/:key` entry (key: mobile_main_slider),
// but it gets its own permission (`custom.config.statics.slider`, per
// acl.constants.ts / permissionConst.ts) rather than the broad `config.statics`
// that guards the rest of the "مدیریت ثابت ها" screen — uploading/replacing the
// public site banner is more sensitive than editing brand/tag lists, so it
// should not be reachable by everyone who can merely open that screen.
// Routes declared ahead of `const/:key` so Nest doesn't match `const/slider`
// (the legacy REST shape) to the generic key handler instead.
@Get('const/slider')
@RequirePermission('custom.config.statics.slider')
getSlider() {
return this.misc.getConst('mobile_main_slider');
}
@Put('const/slider')
@RequirePermission('custom.config.statics.slider')
setSlider(@Body() body: Record<string, unknown>) {
return this.misc.setConst('mobile_main_slider', body.val !== undefined ? body.val : body);
}
@Delete('const/slider')
@RequirePermission('custom.config.statics.slider')
removeSlider() {
return this.misc.removeConst('mobile_main_slider');
}
@Get('const/:key')
@RequirePermission('config.statics')
getConst(@Param('key') key: string) {
this.assertNotSliderKey(key);
return this.misc.getConst(key);
}
@Put('const/:key')
@RequirePermission('config.statics')
setConst(@Param('key') key: string, @Body() body: Record<string, unknown>) {
this.assertNotSliderKey(key);
// Legacy posts either a bare value under `val` or a whole object.
return this.misc.setConst(key, body.val !== undefined ? body.val : body);
}
@@ -178,6 +217,18 @@ export class AdminMiscController {
@Delete('const/:key')
@RequirePermission('config.statics')
removeConst(@Param('key') key: string) {
this.assertNotSliderKey(key);
return this.misc.removeConst(key);
}
// Blocks the generic `config.statics`-gated routes from reaching the slider
// setting by its raw key — otherwise anyone with `config.statics` could
// bypass the dedicated `const/slider` routes (guarded by the stricter
// `custom.config.statics.slider`) simply by calling `const/mobile_main_slider`
// directly, since the underlying Setting row is keyed the same either way.
private assertNotSliderKey(key: string) {
if (key === 'mobile_main_slider') {
throw new ForbiddenException('این تنظیم فقط از مسیر اختصاصی خود قابل دسترسی است');
}
}
}