feat: add admin route guard for the authentication
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { UseGuards, applyDecorators } from "@nestjs/common";
|
||||
import { ApiBearerAuth } from "@nestjs/swagger";
|
||||
|
||||
import { AdminRouteGuard } from "../../modules/auth/guards/admin.guard";
|
||||
import { JwtAuthGuard } from "../../modules/auth/guards/auth.guard";
|
||||
|
||||
export function AuthGuards() {
|
||||
return applyDecorators(UseGuards(JwtAuthGuard), ApiBearerAuth("authorization"));
|
||||
return applyDecorators(UseGuards(JwtAuthGuard, AdminRouteGuard), ApiBearerAuth("authorization"));
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { FastifyRequest } from "fastify";
|
||||
|
||||
import { ADMIN_ROUTE } from "../../../common/decorators/admin.decorator";
|
||||
import { AuthMessage } from "../../../common/enums/message.enum";
|
||||
import { RoleEnum } from "../../users/enums/role.enum";
|
||||
|
||||
@Injectable()
|
||||
export class AdminRouteGuard implements CanActivate {
|
||||
@@ -18,7 +19,7 @@ export class AdminRouteGuard implements CanActivate {
|
||||
|
||||
if (!user) throw new ForbiddenException(AuthMessage.UNAUTHORIZED_ACCESS);
|
||||
|
||||
if (!user.role) throw new ForbiddenException(AuthMessage.UNAUTHORIZED_ACCESS);
|
||||
if (user.isAdmin === undefined || user.role === RoleEnum.USER) throw new ForbiddenException(AuthMessage.UNAUTHORIZED_ACCESS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export class JwtAuthGuard extends AuthGuard([CONSOLE_JWT_STRATEGY_NAME, LOCAL_JW
|
||||
return super.canActivate(context);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
handleRequest(err: unknown, user: any, _info: unknown) {
|
||||
if (err || !user) throw new UnauthorizedException(AuthMessage.TOKEN_EXPIRED_OR_INVALID);
|
||||
return user;
|
||||
|
||||
@@ -6,6 +6,7 @@ import { BusinessSlugParamDto } from "./DTO/business-slug-param.dto";
|
||||
import { PurchaseQuotaDto } from "./DTO/purchase-quota.dto";
|
||||
import { UpdateBusinessSettingsDto } from "./DTO/update-business-settings.dto";
|
||||
import { BusinessesService } from "./services/businesses.service";
|
||||
import { AdminRoute } from "../../common/decorators/admin.decorator";
|
||||
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
|
||||
import { BusinessDec } from "../../common/decorators/business.decorator";
|
||||
import { BusinessInterceptor } from "../../core/interceptors/business.interceptor";
|
||||
@@ -22,6 +23,7 @@ export class BusinessesController {
|
||||
}
|
||||
|
||||
@Patch("settings")
|
||||
@AdminRoute()
|
||||
@UseInterceptors(BusinessInterceptor)
|
||||
@ApiOperation({ summary: "Update business settings" })
|
||||
@AuthGuards()
|
||||
@@ -30,6 +32,7 @@ export class BusinessesController {
|
||||
}
|
||||
|
||||
@Get("settings")
|
||||
@AdminRoute()
|
||||
@UseInterceptors(BusinessInterceptor)
|
||||
@ApiOperation({ summary: "Get business settings" })
|
||||
@AuthGuards()
|
||||
@@ -38,6 +41,7 @@ export class BusinessesController {
|
||||
}
|
||||
|
||||
@Get("quota")
|
||||
@AdminRoute()
|
||||
@UseInterceptors(BusinessInterceptor)
|
||||
@ApiOperation({ summary: "Get business quota information" })
|
||||
@ApiResponse({ status: 200, description: "Business quota information retrieved successfully", type: BusinessQuotaResponseDto })
|
||||
@@ -47,6 +51,7 @@ export class BusinessesController {
|
||||
}
|
||||
|
||||
@Post("quota/purchase")
|
||||
@AdminRoute()
|
||||
@UseInterceptors(BusinessInterceptor)
|
||||
@ApiOperation({ summary: "Purchase additional quota for business" })
|
||||
@ApiResponse({ status: 201, description: "Quota purchase initiated successfully" })
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ApiHeader, ApiOperation, ApiResponse } from "@nestjs/swagger";
|
||||
import { CreateDomainDto } from "./DTO/create-domain.dto";
|
||||
import { UpdateDomainDto } from "./DTO/update-domain.dto";
|
||||
import { DomainsService } from "./services/domains.service";
|
||||
import { AdminRoute } from "../../common/decorators/admin.decorator";
|
||||
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
|
||||
import { BusinessDec } from "../../common/decorators/business.decorator";
|
||||
import { PaginationDto } from "../../common/DTO/pagination.dto";
|
||||
@@ -18,6 +19,7 @@ export class DomainsController {
|
||||
constructor(private readonly domainsService: DomainsService) {}
|
||||
|
||||
@Post()
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Create a new domain and get setup instructions" })
|
||||
@ApiResponse({ status: 201, description: "Domain created with setup instructions" })
|
||||
createDomain(@Body() createDomainDto: CreateDomainDto, @BusinessDec("id") businessId: string) {
|
||||
@@ -25,6 +27,7 @@ export class DomainsController {
|
||||
}
|
||||
|
||||
@Get()
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Get domain for business" })
|
||||
@ApiResponse({ status: 200, description: "Domains retrieved successfully" })
|
||||
getBusinessDomain(@BusinessDec("id") businessId: string, @Query() _query: PaginationDto) {
|
||||
@@ -32,6 +35,7 @@ export class DomainsController {
|
||||
}
|
||||
|
||||
@Patch(":id")
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Update domain" })
|
||||
@ApiResponse({ status: 200, description: "Domain updated successfully" })
|
||||
updateDomain(@Param() paramDto: ParamDto, @Body() updateDomainDto: UpdateDomainDto, @BusinessDec("id") businessId: string) {
|
||||
@@ -39,6 +43,7 @@ export class DomainsController {
|
||||
}
|
||||
|
||||
@Delete(":id")
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Delete domain" })
|
||||
@ApiResponse({ status: 200, description: "Domain deleted successfully" })
|
||||
deleteDomain(@Param() paramDto: ParamDto, @BusinessDec("id") businessId: string) {
|
||||
@@ -46,6 +51,7 @@ export class DomainsController {
|
||||
}
|
||||
|
||||
@Get("setup")
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Get domain setup instructions" })
|
||||
@ApiResponse({ status: 200, description: "Domain setup instructions retrieved" })
|
||||
getDomainSetupInstructions(@BusinessDec("id") businessId: string) {
|
||||
@@ -53,6 +59,7 @@ export class DomainsController {
|
||||
}
|
||||
|
||||
@Get("dns-records")
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Get DNS records for domain" })
|
||||
@ApiResponse({ status: 200, description: "DNS records retrieved successfully" })
|
||||
getDomainDnsRecords(@BusinessDec("id") businessId: string) {
|
||||
@@ -60,6 +67,7 @@ export class DomainsController {
|
||||
}
|
||||
|
||||
@Get("verify-dns")
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Check DNS records, verify domain configuration and return verification status" })
|
||||
@ApiResponse({ status: 200, description: "DNS records verified and status returned" })
|
||||
verifyDnsRecords(@BusinessDec("id") businessId: string) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ApiOperation, ApiParam, ApiQuery, ApiResponse } from "@nestjs/swagger";
|
||||
|
||||
import { MailboxQueryDto } from "./DTO/mailbox.dto";
|
||||
import { MailboxService } from "./services/mailbox.service";
|
||||
import { AdminRoute } from "../../common/decorators/admin.decorator";
|
||||
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
|
||||
import { UserDec } from "../../common/decorators/user.decorator";
|
||||
import { CreateMailboxDto, UpdateMailboxDto } from "../mail-server/DTO";
|
||||
@@ -21,6 +22,7 @@ export class MailboxController {
|
||||
}
|
||||
|
||||
@Get("mailboxes")
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "List mailboxes for a user" })
|
||||
@ApiParam({ name: "userId", description: "User ID" })
|
||||
@ApiQuery({ name: "counters", required: false, description: "Include message counters" })
|
||||
@@ -31,6 +33,7 @@ export class MailboxController {
|
||||
}
|
||||
|
||||
@Get("mailboxes/:mailboxId")
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Get mailbox details" })
|
||||
@ApiParam({ name: "userId", description: "User ID" })
|
||||
@ApiParam({ name: "mailboxId", description: "Mailbox ID" })
|
||||
@@ -41,6 +44,7 @@ export class MailboxController {
|
||||
}
|
||||
|
||||
@Post("mailboxes")
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Create a new mailbox" })
|
||||
@ApiParam({ name: "userId", description: "User ID" })
|
||||
@ApiResponse({ status: 201, description: "Mailbox created successfully" })
|
||||
@@ -50,6 +54,7 @@ export class MailboxController {
|
||||
}
|
||||
|
||||
@Patch("mailboxes/:mailboxId")
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Update mailbox" })
|
||||
@ApiParam({ name: "userId", description: "User ID" })
|
||||
@ApiParam({ name: "mailboxId", description: "Mailbox ID" })
|
||||
@@ -60,6 +65,7 @@ export class MailboxController {
|
||||
}
|
||||
|
||||
@Delete("mailboxes/:mailboxId")
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Delete a mailbox" })
|
||||
@ApiParam({ name: "userId", description: "User ID" })
|
||||
@ApiParam({ name: "mailboxId", description: "Mailbox ID" })
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ApiOperation, ApiResponse } from "@nestjs/swagger";
|
||||
import { CreateEmailSignatureDto } from "./DTO/create-email-signature.dto";
|
||||
import { UpdateEmailSignatureDto } from "./DTO/update-email-signature.dto";
|
||||
import { EmailSignaturesService } from "./services/email-signatures.service";
|
||||
import { AdminRoute } from "../../common/decorators/admin.decorator";
|
||||
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
|
||||
import { BusinessDec } from "../../common/decorators/business.decorator";
|
||||
import { BusinessInterceptor } from "../../core/interceptors/business.interceptor";
|
||||
@@ -17,6 +18,7 @@ export class EmailSignaturesController {
|
||||
constructor(private readonly emailSignaturesService: EmailSignaturesService) {}
|
||||
|
||||
@Post()
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Create a new email signature" })
|
||||
@ApiResponse({ status: 201, description: "Email signature created successfully" })
|
||||
@ApiResponse({ status: 400, description: "Bad request" })
|
||||
@@ -25,6 +27,7 @@ export class EmailSignaturesController {
|
||||
}
|
||||
|
||||
@Get()
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Get a specific email signature" })
|
||||
@ApiResponse({ status: 200, description: "Email signature retrieved successfully" })
|
||||
@ApiResponse({ status: 404, description: "Email signature not found" })
|
||||
@@ -33,6 +36,7 @@ export class EmailSignaturesController {
|
||||
}
|
||||
|
||||
@Patch()
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Update an email signature" })
|
||||
@ApiResponse({ status: 200, description: "Email signature updated successfully" })
|
||||
@ApiResponse({ status: 404, description: "Email signature not found" })
|
||||
@@ -41,6 +45,7 @@ export class EmailSignaturesController {
|
||||
}
|
||||
|
||||
@Delete(":id")
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Delete an email signature" })
|
||||
@ApiResponse({ status: 200, description: "Email signature deleted successfully" })
|
||||
@ApiResponse({ status: 404, description: "Email signature not found" })
|
||||
|
||||
@@ -28,5 +28,20 @@ export class TemplateRepository extends EntityRepository<Template> {
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
async findTemplateByIdWithoutRawHtmlAndStructure(id: string, businessId: string) {
|
||||
const template = await this.findOne(
|
||||
{ id, business: { id: businessId }, deletedAt: null },
|
||||
{ exclude: ["rawHtml", "structure"], populate: ["business"] },
|
||||
);
|
||||
return template;
|
||||
}
|
||||
//**************************************************** */
|
||||
|
||||
async findTemplateByIdWithoutRawHtml(id: string, businessId: string) {
|
||||
const template = await this.findOne({ id, business: { id: businessId }, deletedAt: null }, { exclude: ["rawHtml"], populate: ["business"] });
|
||||
return template;
|
||||
}
|
||||
|
||||
//**************************************************** */
|
||||
}
|
||||
|
||||
@@ -53,11 +53,10 @@ export class TemplatesService {
|
||||
}
|
||||
|
||||
//**************************************************** */
|
||||
async findTemplateById(id: string, businessId: string) {
|
||||
const template = await this.templateRepository.findTemplateById(id, businessId);
|
||||
|
||||
async findTemplateByIdForAdmin(id: string, businessId: string) {
|
||||
const template = await this.templateRepository.findTemplateByIdWithoutRawHtml(id, businessId);
|
||||
if (!template) throw new BadRequestException(TemplateMessage.TEMPLATE_NOT_FOUND);
|
||||
|
||||
return {
|
||||
template,
|
||||
};
|
||||
@@ -85,7 +84,7 @@ export class TemplatesService {
|
||||
|
||||
//**************************************************** */
|
||||
async deleteTemplate(id: string, businessId: string) {
|
||||
const template = await this.templateRepository.findTemplateById(id, businessId);
|
||||
const template = await this.templateRepository.findTemplateByIdWithoutRawHtmlAndStructure(id, businessId);
|
||||
|
||||
if (!template) throw new BadRequestException(TemplateMessage.TEMPLATE_NOT_FOUND);
|
||||
|
||||
@@ -99,20 +98,12 @@ export class TemplatesService {
|
||||
|
||||
//**************************************************** */
|
||||
async getTemplatesByBusinessId(businessId: string) {
|
||||
return this.templateRepository.find(
|
||||
{
|
||||
business: { id: businessId },
|
||||
deletedAt: null,
|
||||
},
|
||||
{
|
||||
populate: ["business"],
|
||||
},
|
||||
);
|
||||
return this.templateRepository.find({ business: { id: businessId }, deletedAt: null }, { populate: ["business"] });
|
||||
}
|
||||
|
||||
//**************************************************** */
|
||||
async setSelectedTemplate(id: string, businessId: string) {
|
||||
const template = await this.templateRepository.findTemplateById(id, businessId);
|
||||
const template = await this.templateRepository.findTemplateByIdWithoutRawHtmlAndStructure(id, businessId);
|
||||
|
||||
if (!template) throw new BadRequestException(TemplateMessage.TEMPLATE_NOT_FOUND);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { TemplateParamDto } from "./DTO/template-param.dto";
|
||||
import { TemplateQueryDto } from "./DTO/template-query.dto";
|
||||
import { UpdateTemplateDto } from "./DTO/update-template.dto";
|
||||
import { TemplatesService } from "./services/templates.service";
|
||||
import { AdminRoute } from "../../common/decorators/admin.decorator";
|
||||
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
|
||||
import { BusinessDec } from "../../common/decorators/business.decorator";
|
||||
import { BusinessInterceptor } from "../../core/interceptors/business.interceptor";
|
||||
@@ -18,6 +19,7 @@ export class TemplatesController {
|
||||
constructor(private readonly templatesService: TemplatesService) {}
|
||||
|
||||
@Post()
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Create a new template" })
|
||||
@ApiResponse({ status: 201, description: "Template created successfully" })
|
||||
@ApiResponse({ status: 400, description: "Bad request - invalid data" })
|
||||
@@ -27,6 +29,7 @@ export class TemplatesController {
|
||||
}
|
||||
|
||||
@Get()
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Get all templates for business" })
|
||||
@ApiResponse({ status: 200, description: "Templates retrieved successfully" })
|
||||
findAllTemplates(@Query() queryDto: TemplateQueryDto, @BusinessDec("id") businessId: string) {
|
||||
@@ -34,14 +37,16 @@ export class TemplatesController {
|
||||
}
|
||||
|
||||
@Get(":id")
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Get template by ID" })
|
||||
@ApiResponse({ status: 200, description: "Template retrieved successfully" })
|
||||
@ApiResponse({ status: 404, description: "Template not found" })
|
||||
findTemplateById(@Param() params: TemplateParamDto, @BusinessDec("id") businessId: string) {
|
||||
return this.templatesService.findTemplateById(params.id, businessId);
|
||||
return this.templatesService.findTemplateByIdForAdmin(params.id, businessId);
|
||||
}
|
||||
|
||||
@Patch(":id")
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Update template by ID" })
|
||||
@ApiResponse({ status: 200, description: "Template updated successfully" })
|
||||
@ApiResponse({ status: 404, description: "Template not found" })
|
||||
@@ -50,6 +55,7 @@ export class TemplatesController {
|
||||
}
|
||||
|
||||
@Delete(":id")
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Delete template by ID" })
|
||||
@ApiResponse({ status: 200, description: "Template deleted successfully" })
|
||||
@ApiResponse({ status: 404, description: "Template not found" })
|
||||
@@ -58,6 +64,7 @@ export class TemplatesController {
|
||||
}
|
||||
|
||||
@Patch(":id/set-selected")
|
||||
@AdminRoute()
|
||||
@ApiOperation({ summary: "Set template as selected (unselects all other templates for the business)" })
|
||||
@ApiResponse({ status: 200, description: "Template set as selected successfully" })
|
||||
@ApiResponse({ status: 404, description: "Template not found" })
|
||||
|
||||
Reference in New Issue
Block a user