mirror of
https://git.meshkee.com/Meshkee/backend.git
synced 2026-08-11 22:30:59 +04:30
Initial commit: Meshkee CMS API
NestJS backend with Prisma, Docker Compose for Postgres/Redis, and deploy docs for the production VM.
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
import {
|
||||
ForbiddenException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { AuthUser } from '../auth/auth.types';
|
||||
import { PermissionsService } from '../auth/permissions.service';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { BusinessSettings } from './business-settings.types';
|
||||
import {
|
||||
mergeBusinessSettings,
|
||||
normalizeBusinessSettings,
|
||||
toPrismaJson,
|
||||
} from './business-settings.util';
|
||||
import { UpdateBusinessSettingsDto } from './dto/update-business-settings.dto';
|
||||
import { normalizeBusinessPrimaryColorId } from './business-primary-colors';
|
||||
|
||||
@Injectable()
|
||||
export class BusinessSettingsService {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly permissions: PermissionsService,
|
||||
) {}
|
||||
|
||||
async get(businessIdRaw: string, actor: AuthUser) {
|
||||
const businessId = BigInt(businessIdRaw);
|
||||
await this.assertPermission(businessId, actor.id, 'business.read');
|
||||
|
||||
const business = await this.prisma.business.findUnique({
|
||||
where: { id: businessId },
|
||||
select: { id: true, settings: true },
|
||||
});
|
||||
|
||||
if (!business) {
|
||||
throw new NotFoundException('Business not found');
|
||||
}
|
||||
|
||||
return {
|
||||
businessId: business.id.toString(),
|
||||
settings: normalizeBusinessSettings(business.settings),
|
||||
};
|
||||
}
|
||||
|
||||
async update(
|
||||
businessIdRaw: string,
|
||||
dto: UpdateBusinessSettingsDto,
|
||||
actor: AuthUser,
|
||||
) {
|
||||
const businessId = BigInt(businessIdRaw);
|
||||
await this.assertPermission(businessId, actor.id, 'business.update');
|
||||
|
||||
const business = await this.prisma.business.findUnique({
|
||||
where: { id: businessId },
|
||||
select: { id: true, settings: true },
|
||||
});
|
||||
|
||||
if (!business) {
|
||||
throw new NotFoundException('Business not found');
|
||||
}
|
||||
|
||||
const current = normalizeBusinessSettings(business.settings);
|
||||
const patch: Partial<BusinessSettings> = {};
|
||||
|
||||
if (dto.branding) {
|
||||
patch.branding = {
|
||||
primaryColor: normalizeBusinessPrimaryColorId(
|
||||
dto.branding.primaryColor ?? current.branding.primaryColor,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
if (dto.dashboard) {
|
||||
patch.dashboard = {
|
||||
comments: {
|
||||
autoApprove:
|
||||
dto.dashboard.comments?.autoApprove ??
|
||||
current.dashboard.comments.autoApprove,
|
||||
},
|
||||
expertReviews: {
|
||||
autoApprove:
|
||||
dto.dashboard.expertReviews?.autoApprove ??
|
||||
current.dashboard.expertReviews.autoApprove,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (dto.store) {
|
||||
patch.store = {
|
||||
onlineSellEnabled:
|
||||
dto.store.onlineSellEnabled ?? current.store.onlineSellEnabled,
|
||||
orderProcessSteps:
|
||||
dto.store.orderProcessSteps ?? current.store.orderProcessSteps,
|
||||
};
|
||||
}
|
||||
|
||||
const next = mergeBusinessSettings(current, patch);
|
||||
|
||||
const updated = await this.prisma.business.update({
|
||||
where: { id: businessId },
|
||||
data: { settings: toPrismaJson(next) },
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
return {
|
||||
businessId: updated.id.toString(),
|
||||
settings: next,
|
||||
};
|
||||
}
|
||||
|
||||
async getNormalizedSettings(businessId: bigint): Promise<BusinessSettings> {
|
||||
const business = await this.prisma.business.findUnique({
|
||||
where: { id: businessId },
|
||||
select: { settings: true },
|
||||
});
|
||||
|
||||
if (!business) {
|
||||
throw new NotFoundException('Business not found');
|
||||
}
|
||||
|
||||
return normalizeBusinessSettings(business.settings);
|
||||
}
|
||||
|
||||
async isCommentsAutoApprove(businessId: bigint) {
|
||||
const settings = await this.getNormalizedSettings(businessId);
|
||||
return settings.dashboard.comments.autoApprove;
|
||||
}
|
||||
|
||||
async isExpertReviewsAutoApprove(businessId: bigint) {
|
||||
const settings = await this.getNormalizedSettings(businessId);
|
||||
return settings.dashboard.expertReviews.autoApprove;
|
||||
}
|
||||
|
||||
async isOnlineSellEnabled(businessId: bigint) {
|
||||
const settings = await this.getNormalizedSettings(businessId);
|
||||
return settings.store.onlineSellEnabled;
|
||||
}
|
||||
|
||||
async getOrderProcessSteps(businessId: bigint) {
|
||||
const settings = await this.getNormalizedSettings(businessId);
|
||||
return settings.store.orderProcessSteps;
|
||||
}
|
||||
|
||||
private async assertPermission(
|
||||
businessId: bigint,
|
||||
userId: bigint,
|
||||
permission: string,
|
||||
) {
|
||||
const allowed = await this.permissions.hasBusinessPermission(
|
||||
userId,
|
||||
businessId,
|
||||
permission,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
throw new ForbiddenException('Insufficient permissions');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user