Multi-environment and multi-user construction
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { MembershipsService } from './memberships.service';
|
||||
|
||||
@Module({
|
||||
providers: [MembershipsService],
|
||||
exports: [MembershipsService],
|
||||
})
|
||||
export class MembershipsModule {}
|
||||
@@ -0,0 +1,161 @@
|
||||
import {
|
||||
ForbiddenException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import type { OrganizationMembershipDto, UserRole } from '@mento/shared';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
|
||||
export type MembershipActor = {
|
||||
userId: string;
|
||||
organizationId: string;
|
||||
role: UserRole;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class MembershipsService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
async listActive(userId: string) {
|
||||
return this.prisma.membership.findMany({
|
||||
where: { userId, isActive: true },
|
||||
include: {
|
||||
organization: { select: { id: true, name: true } },
|
||||
orgRole: { select: { name: true } },
|
||||
},
|
||||
orderBy: { createdAt: 'asc' },
|
||||
});
|
||||
}
|
||||
|
||||
async requireActive(
|
||||
userId: string,
|
||||
organizationId: string,
|
||||
): Promise<MembershipActor> {
|
||||
const row = await this.prisma.membership.findFirst({
|
||||
where: { userId, organizationId, isActive: true },
|
||||
select: { userId: true, organizationId: true, role: true },
|
||||
});
|
||||
if (!row) {
|
||||
throw new ForbiddenException('به این محیط دسترسی ندارید');
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
toChoices(
|
||||
rows: Array<{
|
||||
organization: { id: string; name: string };
|
||||
role: UserRole;
|
||||
orgRole: { name: string } | null;
|
||||
}>,
|
||||
): OrganizationMembershipDto[] {
|
||||
return rows.map((row) => ({
|
||||
id: row.organization.id,
|
||||
name: row.organization.name,
|
||||
role: row.role,
|
||||
orgRoleName: row.orgRole?.name,
|
||||
}));
|
||||
}
|
||||
|
||||
async createMembership(data: {
|
||||
userId: string;
|
||||
organizationId: string;
|
||||
role: UserRole;
|
||||
orgRoleId?: string | null;
|
||||
commissionPercent?: number;
|
||||
isActive?: boolean;
|
||||
}) {
|
||||
return this.prisma.membership.create({
|
||||
data: {
|
||||
userId: data.userId,
|
||||
organizationId: data.organizationId,
|
||||
role: data.role,
|
||||
orgRoleId: data.orgRoleId ?? null,
|
||||
isActive: data.isActive ?? true,
|
||||
commissionPercent:
|
||||
data.commissionPercent == null
|
||||
? undefined
|
||||
: new Prisma.Decimal(data.commissionPercent),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async findInOrg(organizationId: string, userId: string) {
|
||||
return this.prisma.membership.findFirst({
|
||||
where: { organizationId, userId },
|
||||
include: {
|
||||
user: true,
|
||||
orgRole: { select: { id: true, name: true, color: true } },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async listInOrg(organizationId: string) {
|
||||
return this.prisma.membership.findMany({
|
||||
where: { organizationId },
|
||||
include: {
|
||||
user: true,
|
||||
orgRole: { select: { id: true, name: true, color: true } },
|
||||
},
|
||||
orderBy: [{ user: { lastLoginAt: 'desc' } }, { user: { fullName: 'asc' } }],
|
||||
});
|
||||
}
|
||||
|
||||
async countActiveOwners(organizationId: string, exceptUserId?: string) {
|
||||
return this.prisma.membership.count({
|
||||
where: {
|
||||
organizationId,
|
||||
role: 'owner',
|
||||
isActive: true,
|
||||
...(exceptUserId ? { userId: { not: exceptUserId } } : {}),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async syncUserLastOrg(
|
||||
userId: string,
|
||||
organizationId: string,
|
||||
role: UserRole,
|
||||
orgRoleId?: string | null,
|
||||
) {
|
||||
await this.prisma.user.update({
|
||||
where: { id: userId },
|
||||
data: {
|
||||
organizationId,
|
||||
role,
|
||||
...(orgRoleId !== undefined ? { orgRoleId } : {}),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async findUserInOrgById(organizationId: string, userId: string) {
|
||||
const row = await this.findInOrg(organizationId, userId);
|
||||
if (!row) throw new NotFoundException('کاربر پیدا نشد');
|
||||
return row;
|
||||
}
|
||||
|
||||
async findUserInOrgByIdentity(
|
||||
organizationId: string,
|
||||
where: { id?: string; email?: string; mobile?: string },
|
||||
) {
|
||||
const user = await this.prisma.user.findFirst({
|
||||
where: {
|
||||
...(where.id ? { id: where.id } : {}),
|
||||
...(where.email ? { email: where.email } : {}),
|
||||
...(where.mobile ? { mobile: where.mobile } : {}),
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
if (!user) return null;
|
||||
return this.prisma.membership.findFirst({
|
||||
where: { organizationId, userId: user.id },
|
||||
include: { user: true },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function unauthorizedIfMissing<T>(value: T | null | undefined): T {
|
||||
if (!value) throw new UnauthorizedException();
|
||||
return value;
|
||||
}
|
||||
Reference in New Issue
Block a user