Add named teams and per-user data visibility (own/team/org) with settings UI and org module.
This commit is contained in:
@@ -67,3 +67,8 @@ export class UpdateUserCommissionDto {
|
||||
@Max(100)
|
||||
commissionPercent!: number;
|
||||
}
|
||||
|
||||
export class UpdateUserVisibilityDto {
|
||||
@IsIn(['own', 'team', 'org'])
|
||||
dataVisibility!: 'own' | 'team' | 'org';
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
UpdateUserCommissionDto,
|
||||
UpdateUserRoleDto,
|
||||
UpdateUserStatusDto,
|
||||
UpdateUserVisibilityDto,
|
||||
} from './dto';
|
||||
import { UsersService } from './users.service';
|
||||
|
||||
@@ -79,6 +80,21 @@ export class UsersController {
|
||||
);
|
||||
}
|
||||
|
||||
@Patch(':id/visibility')
|
||||
@Roles('owner', 'admin')
|
||||
updateVisibility(
|
||||
@CurrentUser() user: { organizationId: string; role: UserRole },
|
||||
@Param('id') id: string,
|
||||
@Body() dto: UpdateUserVisibilityDto,
|
||||
) {
|
||||
return this.usersService.updateVisibility(
|
||||
user.organizationId,
|
||||
user.role,
|
||||
id,
|
||||
dto.dataVisibility,
|
||||
);
|
||||
}
|
||||
|
||||
@Patch(':id/role')
|
||||
@Roles('owner', 'admin')
|
||||
updateRole(
|
||||
|
||||
@@ -5,7 +5,13 @@ import {
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import type { InviteUserRequest, OrgUserDto, UserRole } from '@mento/shared';
|
||||
import type {
|
||||
DataVisibility,
|
||||
InviteUserRequest,
|
||||
OrgUserDto,
|
||||
UserRole,
|
||||
} from '@mento/shared';
|
||||
import { DATA_VISIBILITIES } from '@mento/shared';
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { normalizeMobile } from '../auth/auth.service';
|
||||
@@ -32,6 +38,7 @@ type MembershipRow = {
|
||||
orgRoleId: string | null;
|
||||
isActive: boolean;
|
||||
commissionPercent: { toString(): string } | number | null;
|
||||
dataVisibility?: string | null;
|
||||
createdAt: Date;
|
||||
orgRole: { id: string; name: string; color: string } | null;
|
||||
user: {
|
||||
@@ -155,6 +162,34 @@ export class UsersService {
|
||||
return this.dtoOf(organizationId, targetId);
|
||||
}
|
||||
|
||||
async updateVisibility(
|
||||
organizationId: string,
|
||||
actorRole: UserRole,
|
||||
targetId: string,
|
||||
dataVisibility: DataVisibility,
|
||||
): Promise<OrgUserDto> {
|
||||
if (actorRole !== 'owner' && actorRole !== 'admin') {
|
||||
throw new ForbiddenException('اجازه تغییر سطح دید را ندارید');
|
||||
}
|
||||
if (!DATA_VISIBILITIES.includes(dataVisibility)) {
|
||||
throw new BadRequestException('سطح دید نامعتبر است');
|
||||
}
|
||||
const target = await this.memberships.findUserInOrgById(
|
||||
organizationId,
|
||||
targetId,
|
||||
);
|
||||
if (target.role === 'owner' || target.role === 'admin') {
|
||||
throw new BadRequestException(
|
||||
'مالک و مدیر همیشه همه پروندهها را میبینند',
|
||||
);
|
||||
}
|
||||
await this.prisma.membership.update({
|
||||
where: { id: target.id },
|
||||
data: { dataVisibility },
|
||||
});
|
||||
return this.dtoOf(organizationId, targetId);
|
||||
}
|
||||
|
||||
async updateRole(
|
||||
organizationId: string,
|
||||
actor: { userId: string; role: UserRole },
|
||||
@@ -326,6 +361,12 @@ export class UsersService {
|
||||
lastLoginAt: row.user.lastLoginAt ? row.user.lastLoginAt.toISOString() : null,
|
||||
hasAvatar: Boolean(row.user.avatarStorageKey),
|
||||
commissionPercent: Number(row.commissionPercent ?? 0),
|
||||
dataVisibility:
|
||||
row.role === 'owner' || row.role === 'admin'
|
||||
? 'org'
|
||||
: DATA_VISIBILITIES.includes(row.dataVisibility as DataVisibility)
|
||||
? (row.dataVisibility as DataVisibility)
|
||||
: 'own',
|
||||
createdAt: row.createdAt.toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user