feat(authorization): add admin API for community authorization
Add new endpoint POST /api/v1/admin/authorizations/community that allows administrators to directly authorize users as community managers without requiring the user to self-apply first. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
003bef1c76
commit
f8cfb5e597
|
|
@ -1,8 +1,8 @@
|
||||||
import { Controller, Post, Body, UseGuards, HttpCode, HttpStatus } from '@nestjs/common'
|
import { Controller, Post, Body, UseGuards, HttpCode, HttpStatus } from '@nestjs/common'
|
||||||
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger'
|
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger'
|
||||||
import { AuthorizationApplicationService } from '@/application/services'
|
import { AuthorizationApplicationService } from '@/application/services'
|
||||||
import { GrantProvinceCompanyCommand, GrantCityCompanyCommand } from '@/application/commands'
|
import { GrantCommunityCommand, GrantProvinceCompanyCommand, GrantCityCompanyCommand } from '@/application/commands'
|
||||||
import { GrantProvinceCompanyDto, GrantCityCompanyDto } from '@/api/dto/request'
|
import { GrantCommunityDto, GrantProvinceCompanyDto, GrantCityCompanyDto } from '@/api/dto/request'
|
||||||
import { CurrentUser } from '@/shared/decorators'
|
import { CurrentUser } from '@/shared/decorators'
|
||||||
import { JwtAuthGuard } from '@/shared/guards'
|
import { JwtAuthGuard } from '@/shared/guards'
|
||||||
|
|
||||||
|
|
@ -13,6 +13,25 @@ import { JwtAuthGuard } from '@/shared/guards'
|
||||||
export class AdminAuthorizationController {
|
export class AdminAuthorizationController {
|
||||||
constructor(private readonly applicationService: AuthorizationApplicationService) {}
|
constructor(private readonly applicationService: AuthorizationApplicationService) {}
|
||||||
|
|
||||||
|
@Post('community')
|
||||||
|
@HttpCode(HttpStatus.CREATED)
|
||||||
|
@ApiOperation({ summary: '授权社区(管理员)' })
|
||||||
|
@ApiResponse({ status: 201, description: '授权成功' })
|
||||||
|
async grantCommunity(
|
||||||
|
@CurrentUser() user: { userId: string; accountSequence: number },
|
||||||
|
@Body() dto: GrantCommunityDto,
|
||||||
|
): Promise<{ message: string }> {
|
||||||
|
const command = new GrantCommunityCommand(
|
||||||
|
dto.userId,
|
||||||
|
dto.accountSequence,
|
||||||
|
dto.communityName,
|
||||||
|
user.userId,
|
||||||
|
user.accountSequence,
|
||||||
|
)
|
||||||
|
await this.applicationService.grantCommunity(command)
|
||||||
|
return { message: '社区授权成功' }
|
||||||
|
}
|
||||||
|
|
||||||
@Post('province-company')
|
@Post('province-company')
|
||||||
@HttpCode(HttpStatus.CREATED)
|
@HttpCode(HttpStatus.CREATED)
|
||||||
@ApiOperation({ summary: '授权正式省公司(管理员)' })
|
@ApiOperation({ summary: '授权正式省公司(管理员)' })
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { IsString, IsNotEmpty, MaxLength, IsNumber } from 'class-validator'
|
||||||
|
import { ApiProperty } from '@nestjs/swagger'
|
||||||
|
|
||||||
|
export class GrantCommunityDto {
|
||||||
|
@ApiProperty({ description: '用户ID' })
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty({ message: '用户ID不能为空' })
|
||||||
|
userId: string
|
||||||
|
|
||||||
|
@ApiProperty({ description: '账户序列号' })
|
||||||
|
@IsNumber()
|
||||||
|
@IsNotEmpty({ message: '账户序列号不能为空' })
|
||||||
|
accountSequence: number
|
||||||
|
|
||||||
|
@ApiProperty({ description: '社区名称', example: '深圳社区' })
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty({ message: '社区名称不能为空' })
|
||||||
|
@MaxLength(100, { message: '社区名称最大100字符' })
|
||||||
|
communityName: string
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
export * from './apply-community-auth.dto'
|
export * from './apply-community-auth.dto'
|
||||||
export * from './apply-auth-province.dto'
|
export * from './apply-auth-province.dto'
|
||||||
export * from './apply-auth-city.dto'
|
export * from './apply-auth-city.dto'
|
||||||
|
export * from './grant-community.dto'
|
||||||
export * from './grant-province-company.dto'
|
export * from './grant-province-company.dto'
|
||||||
export * from './grant-city-company.dto'
|
export * from './grant-city-company.dto'
|
||||||
export * from './revoke-authorization.dto'
|
export * from './revoke-authorization.dto'
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
export class GrantCommunityCommand {
|
||||||
|
constructor(
|
||||||
|
public readonly userId: string,
|
||||||
|
public readonly accountSequence: number,
|
||||||
|
public readonly communityName: string,
|
||||||
|
public readonly adminId: string,
|
||||||
|
public readonly adminAccountSequence: number,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
export * from './apply-community-auth.command'
|
export * from './apply-community-auth.command'
|
||||||
export * from './apply-auth-province-company.command'
|
export * from './apply-auth-province-company.command'
|
||||||
export * from './apply-auth-city-company.command'
|
export * from './apply-auth-city-company.command'
|
||||||
|
export * from './grant-community.command'
|
||||||
export * from './grant-province-company.command'
|
export * from './grant-province-company.command'
|
||||||
export * from './grant-city-company.command'
|
export * from './grant-city-company.command'
|
||||||
export * from './revoke-authorization.command'
|
export * from './revoke-authorization.command'
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import {
|
||||||
ApplyAuthProvinceCompanyResult,
|
ApplyAuthProvinceCompanyResult,
|
||||||
ApplyAuthCityCompanyCommand,
|
ApplyAuthCityCompanyCommand,
|
||||||
ApplyAuthCityCompanyResult,
|
ApplyAuthCityCompanyResult,
|
||||||
|
GrantCommunityCommand,
|
||||||
GrantProvinceCompanyCommand,
|
GrantProvinceCompanyCommand,
|
||||||
GrantCityCompanyCommand,
|
GrantCityCompanyCommand,
|
||||||
RevokeAuthorizationCommand,
|
RevokeAuthorizationCommand,
|
||||||
|
|
@ -218,6 +219,24 @@ export class AuthorizationApplicationService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理员直接授权社区
|
||||||
|
*/
|
||||||
|
async grantCommunity(command: GrantCommunityCommand): Promise<void> {
|
||||||
|
const userId = UserId.create(command.userId, command.accountSequence)
|
||||||
|
const adminId = AdminUserId.create(command.adminId, command.adminAccountSequence)
|
||||||
|
|
||||||
|
const authorization = AuthorizationRole.createCommunity({
|
||||||
|
userId,
|
||||||
|
communityName: command.communityName,
|
||||||
|
adminId,
|
||||||
|
})
|
||||||
|
|
||||||
|
await this.authorizationRepository.save(authorization)
|
||||||
|
await this.eventPublisher.publishAll(authorization.domainEvents)
|
||||||
|
authorization.clearDomainEvents()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 管理员授权正式省公司
|
* 管理员授权正式省公司
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import {
|
||||||
import { RoleType, AuthorizationStatus, MonthlyTargetType } from '@/domain/enums'
|
import { RoleType, AuthorizationStatus, MonthlyTargetType } from '@/domain/enums'
|
||||||
import { DomainError } from '@/shared/exceptions'
|
import { DomainError } from '@/shared/exceptions'
|
||||||
import {
|
import {
|
||||||
|
CommunityAuthorizedEvent,
|
||||||
CommunityAuthRequestedEvent,
|
CommunityAuthRequestedEvent,
|
||||||
AuthProvinceCompanyRequestedEvent,
|
AuthProvinceCompanyRequestedEvent,
|
||||||
AuthCityCompanyRequestedEvent,
|
AuthCityCompanyRequestedEvent,
|
||||||
|
|
@ -215,6 +216,48 @@ export class AuthorizationRole extends AggregateRoot {
|
||||||
return auth
|
return auth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 工厂方法 - 管理员直接授权社区
|
||||||
|
static createCommunity(params: {
|
||||||
|
userId: UserId
|
||||||
|
communityName: string
|
||||||
|
adminId: AdminUserId
|
||||||
|
}): AuthorizationRole {
|
||||||
|
const auth = new AuthorizationRole({
|
||||||
|
authorizationId: AuthorizationId.generate(),
|
||||||
|
userId: params.userId,
|
||||||
|
roleType: RoleType.COMMUNITY,
|
||||||
|
regionCode: RegionCode.create(params.communityName),
|
||||||
|
regionName: params.communityName,
|
||||||
|
status: AuthorizationStatus.AUTHORIZED,
|
||||||
|
displayTitle: params.communityName,
|
||||||
|
authorizedAt: new Date(),
|
||||||
|
authorizedBy: params.adminId,
|
||||||
|
revokedAt: null,
|
||||||
|
revokedBy: null,
|
||||||
|
revokeReason: null,
|
||||||
|
assessmentConfig: AssessmentConfig.forCommunity(),
|
||||||
|
requireLocalPercentage: 0,
|
||||||
|
exemptFromPercentageCheck: true,
|
||||||
|
benefitActive: true,
|
||||||
|
benefitActivatedAt: new Date(),
|
||||||
|
benefitDeactivatedAt: null,
|
||||||
|
currentMonthIndex: 1,
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
})
|
||||||
|
|
||||||
|
auth.addDomainEvent(
|
||||||
|
new CommunityAuthorizedEvent({
|
||||||
|
authorizationId: auth.authorizationId.value,
|
||||||
|
userId: params.userId.value,
|
||||||
|
communityName: params.communityName,
|
||||||
|
authorizedBy: params.adminId.value,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
return auth
|
||||||
|
}
|
||||||
|
|
||||||
// 工厂方法 - 创建授权省公司
|
// 工厂方法 - 创建授权省公司
|
||||||
static createAuthProvinceCompany(params: {
|
static createAuthProvinceCompany(params: {
|
||||||
userId: UserId
|
userId: UserId
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,29 @@
|
||||||
import { DomainEvent } from './domain-event.base'
|
import { DomainEvent } from './domain-event.base'
|
||||||
import { RoleType } from '@/domain/enums'
|
import { RoleType } from '@/domain/enums'
|
||||||
|
|
||||||
|
// 社区授权事件(管理员直接授权)
|
||||||
|
export class CommunityAuthorizedEvent extends DomainEvent {
|
||||||
|
readonly eventType = 'authorization.community.authorized'
|
||||||
|
readonly aggregateId: string
|
||||||
|
readonly payload: {
|
||||||
|
authorizationId: string
|
||||||
|
userId: string
|
||||||
|
communityName: string
|
||||||
|
authorizedBy: string
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(data: {
|
||||||
|
authorizationId: string
|
||||||
|
userId: string
|
||||||
|
communityName: string
|
||||||
|
authorizedBy: string
|
||||||
|
}) {
|
||||||
|
super()
|
||||||
|
this.aggregateId = data.authorizationId
|
||||||
|
this.payload = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 社区授权申请事件
|
// 社区授权申请事件
|
||||||
export class CommunityAuthRequestedEvent extends DomainEvent {
|
export class CommunityAuthRequestedEvent extends DomainEvent {
|
||||||
readonly eventType = 'authorization.community.requested'
|
readonly eventType = 'authorization.community.requested'
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue