feat(ops): add global test whitelist and exclude test accounts from settlement
Unify product/store visibility on HQ whitelist, mark isTest snapshots, and fix SUPER_ADMIN access for the new module.
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Param,
|
||||
Patch,
|
||||
Post,
|
||||
Put,
|
||||
Query,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { IsBoolean, IsIn, IsInt, IsOptional, IsString, Max, MaxLength, Min } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import { HqAuthGuard } from '../../common/guards/hq-auth.guard';
|
||||
import {
|
||||
HqPermissionGuard,
|
||||
RequireHqPermissions,
|
||||
} from '../../common/guards/hq-permission.guard';
|
||||
import { CurrentUser } from '../../common/decorators/current-user.decorator';
|
||||
import type { AuthUser } from '../../common/guards/jwt-auth.guard';
|
||||
import { TestWhitelistService } from '../../common/test-whitelist/test-whitelist.service';
|
||||
import { SystemConfigService } from '../../common/system-config/system-config.service';
|
||||
|
||||
class ListPhonesQueryDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
phone?: string;
|
||||
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
page?: number = 1;
|
||||
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
@Max(100)
|
||||
pageSize?: number = 20;
|
||||
}
|
||||
|
||||
class AddPhoneDto {
|
||||
@IsString()
|
||||
phone!: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(256)
|
||||
note?: string;
|
||||
}
|
||||
|
||||
class UpdatePhoneDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(256)
|
||||
note?: string | null;
|
||||
}
|
||||
|
||||
class ListAccountsQueryDto {
|
||||
@IsIn(['user', 'store_account', 'partner', 'store', 'order'])
|
||||
type!: 'user' | 'store_account' | 'partner' | 'store' | 'order';
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
phone?: string;
|
||||
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
page?: number = 1;
|
||||
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
@Max(100)
|
||||
pageSize?: number = 20;
|
||||
}
|
||||
|
||||
class UpdateMockFlagsDto {
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
mockSms?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
mockWechat?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
mockPay?: boolean;
|
||||
}
|
||||
|
||||
@Controller('admin/test-whitelist')
|
||||
@UseGuards(HqAuthGuard, HqPermissionGuard)
|
||||
@RequireHqPermissions('test_whitelist')
|
||||
export class AdminTestWhitelistController {
|
||||
constructor(
|
||||
private readonly testWhitelist: TestWhitelistService,
|
||||
private readonly systemConfig: SystemConfigService,
|
||||
) {}
|
||||
|
||||
@Get('mock-flags')
|
||||
async getMockFlags() {
|
||||
const form = await this.systemConfig.getForm(['feature']);
|
||||
const v = form.values;
|
||||
return {
|
||||
mockSms: v.MOCK_SMS === 'true' || v.MOCK_SMS === '1',
|
||||
mockWechat: v.MOCK_WECHAT === 'true' || v.MOCK_WECHAT === '1',
|
||||
mockPay: v.MOCK_PAY === 'true' || v.MOCK_PAY === '1',
|
||||
};
|
||||
}
|
||||
|
||||
@Put('mock-flags')
|
||||
async updateMockFlags(@Body() dto: UpdateMockFlagsDto) {
|
||||
const values: Record<string, string> = {};
|
||||
if (dto.mockSms !== undefined) values.MOCK_SMS = String(dto.mockSms);
|
||||
if (dto.mockWechat !== undefined) values.MOCK_WECHAT = String(dto.mockWechat);
|
||||
if (dto.mockPay !== undefined) values.MOCK_PAY = String(dto.mockPay);
|
||||
if (Object.keys(values).length) {
|
||||
await this.systemConfig.update({ values }, ['feature']);
|
||||
}
|
||||
return this.getMockFlags();
|
||||
}
|
||||
|
||||
@Get('phones')
|
||||
listPhones(@Query() query: ListPhonesQueryDto) {
|
||||
return this.testWhitelist.listPhones(query);
|
||||
}
|
||||
|
||||
@Post('phones')
|
||||
addPhone(@Body() dto: AddPhoneDto, @CurrentUser() actor: AuthUser) {
|
||||
return this.testWhitelist.addPhone({
|
||||
phone: dto.phone,
|
||||
note: dto.note,
|
||||
createdByHqId: actor.actorId,
|
||||
});
|
||||
}
|
||||
|
||||
@Patch('phones/:id')
|
||||
updatePhone(@Param('id') id: string, @Body() dto: UpdatePhoneDto) {
|
||||
return this.testWhitelist.updatePhone(BigInt(id), { note: dto.note });
|
||||
}
|
||||
|
||||
@Delete('phones/:id')
|
||||
removePhone(@Param('id') id: string) {
|
||||
return this.testWhitelist.removePhone(BigInt(id));
|
||||
}
|
||||
|
||||
@Get('accounts')
|
||||
listAccounts(@Query() query: ListAccountsQueryDto) {
|
||||
return this.testWhitelist.listAccounts(query);
|
||||
}
|
||||
|
||||
@Get('phones/:id/linked')
|
||||
linked(@Param('id') id: string) {
|
||||
return this.testWhitelist.linkedForPhoneId(BigInt(id));
|
||||
}
|
||||
|
||||
@Post('migrate-visibility')
|
||||
migrate(@CurrentUser() actor: AuthUser) {
|
||||
return this.testWhitelist.migrateVisibilityPhones(actor.actorId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user