返回 AiToEarn
relay-callback.controller.ts
根目录 / project / aitoearn-backend / apps / aitoearn-server / src / core / channels / relay / relay-callback.controller.ts
1 import { Body, Controller, Post, Query, Render } from '@nestjs/common'
2 import { ApiTags } from '@nestjs/swagger'
3 import { Public } from '@yikart/aitoearn-auth'
4 import { AccountType, ApiDoc, AppException, ChannelAuthTaskStatus, ParseObjectIdPipe, ResponseCode } from '@yikart/common'
5 import { ServerRedisService } from '../../../common/redis'
6 import { AccountService } from '../accounts/account.service'
7 import { RelayCallbackDto } from './relay-callback.dto'
8
9 interface RelayCallbackAccount {
10 relayAccountRef: string
11 nickname: string
12 avatar?: string
13 platformUid: string
14 platform: AccountType
15 }
16
17 @ApiTags('Channels/Relay')
18 @Controller({ path: '/channels/relay', version: '2' })
19 export class RelayCallbackController {
20 constructor(
21 private readonly accountService: AccountService,
22 private readonly redisService: ServerRedisService,
23 ) {}
24
25 @Public()
26 @ApiDoc({
27 summary: 'Relay OAuth 回调',
28 description: '接收官方服务器 OAuth 完成后浏览器 form POST 过来的账号信息,在本地创建 relay 账号',
29 body: RelayCallbackDto.schema,
30 })
31 @Post('/callback')
32 @Render('channels/auth/callback')
33 async handleRelayCallback(
34 @Body() body: RelayCallbackDto,
35 @Query('userId', ParseObjectIdPipe) userId: string,
36 @Query('groupId') groupId: string | undefined,
37 ) {
38 if (!userId) {
39 throw new AppException(ResponseCode.UserNotFound)
40 }
41
42 const relayAccounts = this.getRelayCallbackAccounts(body)
43 const accounts: Array<{ id: string }> = []
44 for (const relayAccount of relayAccounts) {
45 const account = await this.accountService.createRelayAccount(userId, {
46 type: relayAccount.platform,
47 uid: relayAccount.platformUid,
48 nickname: relayAccount.nickname,
49 avatar: relayAccount.avatar,
50 relayAccountRef: relayAccount.relayAccountRef,
51 groupId,
52 })
53 if (account) {
54 accounts.push(account)
55 }
56 }
57 const accountIds = accounts.map(account => account.id)
58
59 if (body.taskId && accountIds.length > 0) {
60 const authTaskPlatform = this.getAuthTaskPlatform(relayAccounts[0].platform)
61 await this.redisService.saveLegacyRelayAuthTask(authTaskPlatform, body.taskId, {
62 status: ChannelAuthTaskStatus.Completed,
63 accountId: accountIds[0],
64 accountIds,
65 })
66 }
67
68 return {
69 status: 1,
70 message: '授权成功',
71 accountId: accountIds[0],
72 accountIds,
73 redirectUri: body.redirectUri,
74 }
75 }
76
77 private getRelayCallbackAccounts(body: RelayCallbackDto): RelayCallbackAccount[] {
78 if (body.accounts) {
79 try {
80 const accounts = JSON.parse(body.accounts) as RelayCallbackAccount[]
81 if (Array.isArray(accounts) && accounts.length > 0) {
82 const validAccounts = accounts.filter(account => (
83 account.relayAccountRef
84 && account.platformUid
85 && account.platform
86 && account.nickname
87 ))
88 if (validAccounts.length > 0) {
89 return validAccounts
90 }
91 }
92 }
93 catch {
94 // Fall back to legacy single-account fields below.
95 }
96 }
97
98 return [{
99 relayAccountRef: body.relayAccountRef,
100 nickname: body.nickname,
101 avatar: body.avatar,
102 platformUid: body.platformUid,
103 platform: body.platform,
104 }]
105 }
106
107 private getAuthTaskPlatform(platform: string): string {
108 const META_PLATFORMS = ['facebook', 'instagram', 'threads', 'linkedin']
109 if (META_PLATFORMS.includes(platform)) {
110 return 'meta'
111 }
112 return platform
113 }
114 }
115
115 lines TYPESCRIPT