add launcher user app permission api
This commit is contained in:
+20
-1
@@ -1,4 +1,5 @@
|
|||||||
import { IsBoolean, IsIn, IsInt, IsOptional, IsString, IsUUID } from 'class-validator';
|
import { Type } from 'class-transformer';
|
||||||
|
import { IsArray, IsBoolean, IsIn, IsInt, IsOptional, IsString, IsUUID, ValidateNested } from 'class-validator';
|
||||||
|
|
||||||
export class CreateLauncherVersionDto {
|
export class CreateLauncherVersionDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
@@ -203,6 +204,24 @@ export class MoveLauncherAppLinkDto {
|
|||||||
direction!: 'up' | 'down';
|
direction!: 'up' | 'down';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class UpdateLauncherUserAppPermissionDto {
|
||||||
|
@IsString()
|
||||||
|
appKey!: string;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
canView!: boolean;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
canLaunch!: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdateLauncherUserAppPermissionsDto {
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => UpdateLauncherUserAppPermissionDto)
|
||||||
|
permissions!: UpdateLauncherUserAppPermissionDto[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export class CreateLauncherCommonSettingDto {
|
export class CreateLauncherCommonSettingDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Body, Controller, Delete, Get, Param, Patch, Post } from '@nestjs/common';
|
import { Body, Controller, Delete, Get, Param, Patch, Post, Put } from '@nestjs/common';
|
||||||
|
|
||||||
import { CreateLauncherAppLinkDto, CreateLauncherBuildJobDto, CreateLauncherCommonSettingDto, CreateLauncherVersionDto, UpdateLauncherSourceDto, LinkLauncherVersionSourceDto, MoveLauncherAppLinkDto, UpdateLauncherAppLinkDto, UpdateLauncherCommonSettingDto } from './dto';
|
import { CreateLauncherAppLinkDto, CreateLauncherBuildJobDto, CreateLauncherCommonSettingDto, CreateLauncherVersionDto, UpdateLauncherSourceDto, LinkLauncherVersionSourceDto, MoveLauncherAppLinkDto, UpdateLauncherAppLinkDto, UpdateLauncherCommonSettingDto, UpdateLauncherUserAppPermissionsDto } from './dto';
|
||||||
import { LauncherService } from './launcher.service';
|
import { LauncherService } from './launcher.service';
|
||||||
|
|
||||||
@Controller('launcher')
|
@Controller('launcher')
|
||||||
@@ -67,6 +67,19 @@ export class LauncherController {
|
|||||||
return this.launcherService.listAppLinks();
|
return this.launcherService.listAppLinks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get('users/:userId/app-permissions')
|
||||||
|
listUserAppPermissions(@Param('userId') userId: string) {
|
||||||
|
return this.launcherService.listUserAppPermissions(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Put('users/:userId/app-permissions')
|
||||||
|
updateUserAppPermissions(
|
||||||
|
@Param('userId') userId: string,
|
||||||
|
@Body() body: UpdateLauncherUserAppPermissionsDto,
|
||||||
|
) {
|
||||||
|
return this.launcherService.updateUserAppPermissions(userId, body);
|
||||||
|
}
|
||||||
|
|
||||||
@Post('app-links')
|
@Post('app-links')
|
||||||
createAppLink(@Body() body: CreateLauncherAppLinkDto) {
|
createAppLink(@Body() body: CreateLauncherAppLinkDto) {
|
||||||
return this.launcherService.createAppLink(body);
|
return this.launcherService.createAppLink(body);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
LinkLauncherVersionSourceDto,
|
LinkLauncherVersionSourceDto,
|
||||||
UpdateLauncherAppLinkDto,
|
UpdateLauncherAppLinkDto,
|
||||||
UpdateLauncherCommonSettingDto,
|
UpdateLauncherCommonSettingDto,
|
||||||
|
UpdateLauncherUserAppPermissionsDto,
|
||||||
} from './dto';
|
} from './dto';
|
||||||
|
|
||||||
const execAsync = promisify(exec);
|
const execAsync = promisify(exec);
|
||||||
@@ -233,6 +234,86 @@ export class LauncherService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async listUserAppPermissions(userId: string) {
|
||||||
|
const rows = await this.launcherPrisma.$queryRawUnsafe<LauncherUserAppPermissionRow[]>(
|
||||||
|
`SELECT app.id AS app_id, app.app_key, app.display_name, app.description, app.sort_order, app.is_enabled,
|
||||||
|
permission.id AS permission_id, permission.can_view, permission.can_launch, permission.assigned_at
|
||||||
|
FROM launcher_apps app
|
||||||
|
LEFT JOIN launcher_user_apps permission
|
||||||
|
ON permission.app_id = app.id
|
||||||
|
AND permission.auth_user_id = $1::uuid
|
||||||
|
WHERE app.is_enabled = true
|
||||||
|
ORDER BY app.sort_order ASC, app.display_name ASC`,
|
||||||
|
userId,
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
permissions: rows.map((row) => ({
|
||||||
|
appId: row.app_id,
|
||||||
|
appKey: row.app_key,
|
||||||
|
displayName: row.display_name,
|
||||||
|
description: row.description,
|
||||||
|
sortOrder: row.sort_order,
|
||||||
|
isEnabled: row.is_enabled,
|
||||||
|
permissionId: row.permission_id,
|
||||||
|
canView: row.can_view ?? false,
|
||||||
|
canLaunch: row.can_launch ?? false,
|
||||||
|
assignedAt: row.assigned_at,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateUserAppPermissions(userId: string, body: UpdateLauncherUserAppPermissionsDto) {
|
||||||
|
const inputByAppKey = new Map(
|
||||||
|
body.permissions.map((permission) => [
|
||||||
|
permission.appKey,
|
||||||
|
{
|
||||||
|
canView: permission.canView,
|
||||||
|
canLaunch: permission.canView && permission.canLaunch,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
const apps = await this.launcherPrisma.$queryRawUnsafe<Array<{ id: string; app_key: string }>>(
|
||||||
|
`SELECT id, app_key FROM launcher_apps WHERE is_enabled = true`,
|
||||||
|
);
|
||||||
|
const appKeys = new Set(apps.map((app) => app.app_key));
|
||||||
|
const invalidKeys = [...inputByAppKey.keys()].filter((appKey) => !appKeys.has(appKey));
|
||||||
|
if (invalidKeys.length) {
|
||||||
|
throw new BadRequestException(`알 수 없는 앱 권한입니다: ${invalidKeys.join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const app of apps) {
|
||||||
|
const input = inputByAppKey.get(app.app_key);
|
||||||
|
if (!input || !input.canView) {
|
||||||
|
await this.launcherPrisma.$executeRawUnsafe(
|
||||||
|
`DELETE FROM launcher_user_apps WHERE auth_user_id = $1::uuid AND app_id = $2::uuid`,
|
||||||
|
userId,
|
||||||
|
app.id,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.launcherPrisma.$executeRawUnsafe(
|
||||||
|
`INSERT INTO launcher_user_apps (
|
||||||
|
auth_user_id, app_id, can_view, can_launch, assigned_at, created_at, updated_at
|
||||||
|
) VALUES (
|
||||||
|
$1::uuid, $2::uuid, $3, $4, now(), now(), now()
|
||||||
|
)
|
||||||
|
ON CONFLICT (auth_user_id, app_id) DO UPDATE SET
|
||||||
|
can_view = EXCLUDED.can_view,
|
||||||
|
can_launch = EXCLUDED.can_launch,
|
||||||
|
assigned_at = now(),
|
||||||
|
updated_at = now()`,
|
||||||
|
userId,
|
||||||
|
app.id,
|
||||||
|
input.canView,
|
||||||
|
input.canLaunch,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.listUserAppPermissions(userId);
|
||||||
|
}
|
||||||
|
|
||||||
async syncAdminAppsFromLauncher() {
|
async syncAdminAppsFromLauncher() {
|
||||||
const launcherRows = await this.launcherPrisma.$queryRawUnsafe<LauncherAppRow[]>(`
|
const launcherRows = await this.launcherPrisma.$queryRawUnsafe<LauncherAppRow[]>(`
|
||||||
SELECT app.id, app.app_key, app.display_name, app.description, app.subtitle, app.detail_url, app.video_path,
|
SELECT app.id, app.app_key, app.display_name, app.description, app.subtitle, app.detail_url, app.video_path,
|
||||||
@@ -1037,6 +1118,19 @@ type LauncherAppRow = {
|
|||||||
download_url: string | null;
|
download_url: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type LauncherUserAppPermissionRow = {
|
||||||
|
app_id: string;
|
||||||
|
app_key: string;
|
||||||
|
display_name: string;
|
||||||
|
description: string | null;
|
||||||
|
sort_order: number;
|
||||||
|
is_enabled: boolean;
|
||||||
|
permission_id: string | null;
|
||||||
|
can_view: boolean | null;
|
||||||
|
can_launch: boolean | null;
|
||||||
|
assigned_at: Date | null;
|
||||||
|
};
|
||||||
|
|
||||||
function mapLauncherVersionRow(row: LauncherVersionRow) {
|
function mapLauncherVersionRow(row: LauncherVersionRow) {
|
||||||
return {
|
return {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
|
|||||||
Reference in New Issue
Block a user