Browse Source

feat(auth): update channelId handling in login process and add user/channel retrieval methods

Dave 2 tháng trước cách đây
mục cha
commit
2e66708df9

+ 1 - 1
apps/box-app-api/src/feature/auth/auth.controller.ts

@@ -42,7 +42,7 @@ export class AuthController {
       userAgent,
       appVersion: body.appVersion,
       os: body.os,
-      uChannelId: body.uChannelId,
+      uChannelId: body.channelId,
       machine: body.machine,
       // add any other auth-related fields as needed
     });

+ 59 - 2
apps/box-app-api/src/feature/auth/auth.service.ts

@@ -5,6 +5,8 @@ import { UserLoginEventPayload } from '@box/common/events/user-login-event.dto';
 import { RabbitmqPublisherService } from '../../rabbitmq/rabbitmq-publisher.service';
 import { AdService } from '../ads/ad.service';
 import { AppJwtPayload } from './interfaces/app-jwt-payload';
+import { PrismaMongoStatsService } from '../../prisma/prisma-mongo-stats.service';
+import { PrismaMongoService } from '../../prisma/prisma-mongo.service';
 
 @Injectable()
 export class AuthService {
@@ -13,6 +15,8 @@ export class AuthService {
     private readonly jwtService: JwtService,
     private readonly rabbitmqPublisher: RabbitmqPublisherService,
     private readonly adService: AdService,
+    private readonly prismaMongoStatsService: PrismaMongoStatsService,
+    private readonly prismaMongoService: PrismaMongoService,
   ) {}
 
   async login(params: {
@@ -35,6 +39,18 @@ export class AuthService {
 
     const now = Date.now(); // number (ms since epoch)
 
+    const user = await this.getUserByUid(uid);
+    const firstChannel = await this.getChannelById(uChannelId || '');
+    // if user does not exist, uChannelId = firstChannel.channelId
+    let finalUChannelId = uChannelId;
+    if (!user && firstChannel) {
+      finalUChannelId = firstChannel.channelId;
+    }
+    // if user exists, take firstChannel.channelId
+    else if (user && firstChannel) {
+      finalUChannelId = firstChannel.channelId;
+    }
+
     // Build JWT payload with required and optional tracking fields.
     // Tracking fields (uChannelId, machine, ip, userAgent, appVersion, os) are optional
     // to preserve backward compatibility with older tokens and minimize JWT size for stability.
@@ -42,7 +58,7 @@ export class AuthService {
       sub: uid,
       uid,
       jti: tokenId,
-      uChannelId,
+      uChannelId: finalUChannelId,
       machine,
       ip,
       userAgent,
@@ -60,7 +76,7 @@ export class AuthService {
       userAgent,
       appVersion,
       os,
-      uChannelId,
+      uChannelId: finalUChannelId,
       machine,
       tokenId,
       loginAt: now,
@@ -102,4 +118,45 @@ export class AuthService {
 
     return { accessToken, allAds };
   }
+
+  // add a function to retrieve user record from mongo by uid
+  async getUserByUid(uid: string): Promise<any> {
+    // Implement your MongoDB query here to find the user by uid
+    // For example, if you have a UserModel injected, you might do:
+    // return this.userModel.findOne({ uid }).exec();
+    // Placeholder implementation:
+
+    const user = await this.prismaMongoStatsService.user.findUnique({
+      where: { uid },
+    });
+
+    if (user) {
+      return user;
+    }
+    return null;
+  }
+
+  // retrive the first channel from mongo collection, order by createAt ascending
+  async getFirstChannel(): Promise<any> {
+    const channel = await this.prismaMongoService.channel.findFirst({
+      orderBy: { createAt: 'asc' },
+    });
+
+    if (channel) {
+      return channel;
+    }
+    return null;
+  }
+
+  // find by channelId
+  async getChannelById(channelId: string): Promise<any> {
+    const channel = await this.prismaMongoService.channel.findUnique({
+      where: { channelId },
+    });
+
+    if (channel) {
+      return this.getFirstChannel();
+    }
+    return null;
+  }
 }

+ 4 - 0
apps/box-app-api/src/feature/auth/interfaces/app-jwt-payload.ts

@@ -34,6 +34,10 @@ export interface AppJwtPayload {
   jti: string;
 
   /**
+   * must include
+   */
+
+  /**
    * Optional: Channel/Traffic source identifier.
    * Tracks which channel or promotion campaign drove this login.
    * Used for analytics and conversion tracking.

+ 4 - 4
apps/box-app-api/src/feature/auth/login.dto.ts

@@ -15,18 +15,18 @@ export class LoginDto {
     example: 'channel-123',
     required: true,
   })
-  @IsNotEmpty()
+  @IsOptional()
   @IsString()
-  uChannelId: string;
+  channelId?: string;
 
   @ApiProperty({
     description: '机器型号',
     example: 'iPhone 12 Pro xxxx',
     required: true,
   })
-  @IsNotEmpty()
+  @IsOptional()
   @IsString()
-  machine: string;
+  machine?: string;
 
   @ApiProperty({
     description: '应用版本号',

+ 6 - 0
apps/box-app-api/src/prisma/prisma-mongo-stats.service.ts

@@ -0,0 +1,6 @@
+import { Injectable } from '@nestjs/common';
+// 👇 Reuse the shared Mongo Prisma service from libs/db
+import { MongoStatsPrismaService } from '@box/db/prisma/mongo-stats-prisma.service';
+
+@Injectable()
+export class PrismaMongoStatsService extends MongoStatsPrismaService {}

+ 3 - 2
apps/box-app-api/src/prisma/prisma-mongo.module.ts

@@ -1,9 +1,10 @@
 import { Global, Module } from '@nestjs/common';
 import { PrismaMongoService } from './prisma-mongo.service';
+import { PrismaMongoStatsService } from './prisma-mongo-stats.service';
 
 @Global()
 @Module({
-  providers: [PrismaMongoService],
-  exports: [PrismaMongoService],
+  providers: [PrismaMongoService, PrismaMongoStatsService],
+  exports: [PrismaMongoService, PrismaMongoStatsService],
 })
 export class PrismaMongoModule {}

+ 1 - 1
prisma/mongo/schema/ads.prisma

@@ -7,7 +7,7 @@ model Ads {
   adsCoverImg  String?                       // 广告图片
   adsUrl       String?                       // 广告链接
 
-  imgSource    ImageSource @default(PROVIDER)
+  imgSource    ImageSource @default(LOCAL_ONLY)
 
   // 有效期,使用 BigInt epoch
   startDt      BigInt                        // 开始时间