Просмотр исходного кода

移除 ChatGroup 相关的控制器、服务和路由,重构 TgGroup 相关功能以支持群组管理,添加 TgGroup 实体和更新相关 DTO,增强代码一致性和可维护性。

wuyi 3 недель назад
Родитель
Сommit
f76c577f2e

+ 0 - 2
src/app.ts

@@ -19,7 +19,6 @@ import tgMsgSendRoutes from './routes/tg-msg-send.routes'
 import taskRoutes from './routes/task.routes'
 import taskRoutes from './routes/task.routes'
 import testRoutes from './routes/test.routes'
 import testRoutes from './routes/test.routes'
 import tgUserRoutes from './routes/tg-user.routes'
 import tgUserRoutes from './routes/tg-user.routes'
-import chatGroupRoutes from './routes/chat-group.routes'
 import tgGroupRoutes from './routes/tg-group.routes'
 import tgGroupRoutes from './routes/tg-group.routes'
 
 
 const options: FastifyEnvOptions = {
 const options: FastifyEnvOptions = {
@@ -94,7 +93,6 @@ export const createApp = async () => {
   app.register(tgMsgSendRoutes, { prefix: '/api/msg' })
   app.register(tgMsgSendRoutes, { prefix: '/api/msg' })
   app.register(taskRoutes, { prefix: '/api/tasks' })
   app.register(taskRoutes, { prefix: '/api/tasks' })
   app.register(tgUserRoutes, { prefix: '/api/tg-users' })
   app.register(tgUserRoutes, { prefix: '/api/tg-users' })
-  app.register(chatGroupRoutes, { prefix: '/api/chat-groups' })
   app.register(tgGroupRoutes, { prefix: '/api/tg-groups' })
   app.register(tgGroupRoutes, { prefix: '/api/tg-groups' })
   app.register(testRoutes, { prefix: '/api/test' })
   app.register(testRoutes, { prefix: '/api/test' })
   const dataSource = createDataSource(app)
   const dataSource = createDataSource(app)

+ 0 - 81
src/controllers/chat-group.controller.ts

@@ -1,81 +0,0 @@
-import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
-import { ChatGroupService } from '../services/chat-group.service'
-import {
-  CreateChatGroupRecordBody,
-  ListChatGroupQuery,
-  UpdateChatGroupRecordBody
-} from '../dto/chat-group.dto'
-
-export class ChatGroupController {
-  private chatGroupService: ChatGroupService
-
-  constructor(app: FastifyInstance) {
-    this.chatGroupService = new ChatGroupService(app)
-  }
-
-  async createOrUpdate(
-    request: FastifyRequest<{ Body: CreateChatGroupRecordBody }>,
-    reply: FastifyReply
-  ): Promise<FastifyReply> {
-    try {
-      const payload = request.body
-      if (!payload.chatId || !payload.accessHash) {
-        return reply.code(400).send({ message: 'chatId 和 accessHash 为必填项' })
-      }
-      const saved = await this.chatGroupService.upsertGroup(payload)
-      return reply.code(201).send({ message: '保存成功', data: saved })
-    } catch (error) {
-      return reply
-        .code(500)
-        .send({ message: '保存失败', error: error instanceof Error ? error.message : String(error) })
-    }
-  }
-
-  async update(
-    request: FastifyRequest<{ Body: UpdateChatGroupRecordBody }>,
-    reply: FastifyReply
-  ): Promise<FastifyReply> {
-    try {
-      const payload = request.body
-      if (!payload.chatId) {
-        return reply.code(400).send({ message: 'chatId 不能为空' })
-      }
-      const updated = await this.chatGroupService.updateGroup(payload)
-      if (!updated) {
-        return reply.code(404).send({ message: '群组不存在' })
-      }
-      return reply.send({ message: '更新成功', data: updated })
-    } catch (error) {
-      return reply
-        .code(500)
-        .send({ message: '更新失败', error: error instanceof Error ? error.message : String(error) })
-    }
-  }
-
-  async getById(request: FastifyRequest<{ Params: { chatId: string } }>, reply: FastifyReply): Promise<FastifyReply> {
-    try {
-      const { chatId } = request.params
-      const data = await this.chatGroupService.findByChatId(chatId)
-      if (!data) {
-        return reply.code(404).send({ message: '群组不存在' })
-      }
-      return reply.send({ data })
-    } catch (error) {
-      return reply
-        .code(500)
-        .send({ message: '查询失败', error: error instanceof Error ? error.message : String(error) })
-    }
-  }
-
-  async list(request: FastifyRequest<{ Querystring: ListChatGroupQuery }>, reply: FastifyReply): Promise<FastifyReply> {
-    try {
-      const result = await this.chatGroupService.list(request.query)
-      return reply.send(result)
-    } catch (error) {
-      return reply
-        .code(500)
-        .send({ message: '查询失败', error: error instanceof Error ? error.message : String(error) })
-    }
-  }
-}
-

+ 69 - 1
src/controllers/tg-group.controller.ts

@@ -1,6 +1,12 @@
 import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
 import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
 import { TgGroupService } from '../services/tg-group.service'
 import { TgGroupService } from '../services/tg-group.service'
-import { CreateTgGroupBody, InviteMembersBody } from '../dto/tg-group.dto'
+import {
+  CreateTgGroupBody,
+  InviteMembersBody,
+  CreateTgGroupRecordBody,
+  ListTgGroupQuery,
+  UpdateTgGroupRecordBody
+} from '../dto/tg-group.dto'
 
 
 export class TgGroupController {
 export class TgGroupController {
   private readonly tgGroupService: TgGroupService
   private readonly tgGroupService: TgGroupService
@@ -57,4 +63,66 @@ export class TgGroupController {
 
 
     return reply.code(result.success ? 200 : 500).send(result)
     return reply.code(result.success ? 200 : 500).send(result)
   }
   }
+
+  async createOrUpdate(
+    request: FastifyRequest<{ Body: CreateTgGroupRecordBody }>,
+    reply: FastifyReply
+  ): Promise<FastifyReply> {
+    try {
+      const payload = request.body
+      if (!payload.chatId || !payload.accessHash) {
+        return reply.code(400).send({ message: 'chatId 和 accessHash 为必填项' })
+      }
+      const saved = await this.tgGroupService.upsertGroup(payload)
+      return reply.code(201).send({ message: '保存成功', data: saved })
+    } catch (error) {
+      return reply
+        .code(500)
+        .send({ message: '保存失败', error: error instanceof Error ? error.message : String(error) })
+    }
+  }
+
+  async update(request: FastifyRequest<{ Body: UpdateTgGroupRecordBody }>, reply: FastifyReply): Promise<FastifyReply> {
+    try {
+      const payload = request.body
+      if (!payload.chatId) {
+        return reply.code(400).send({ message: 'chatId 不能为空' })
+      }
+      const updated = await this.tgGroupService.updateGroup(payload)
+      if (!updated) {
+        return reply.code(404).send({ message: '群组不存在' })
+      }
+      return reply.send({ message: '更新成功', data: updated })
+    } catch (error) {
+      return reply
+        .code(500)
+        .send({ message: '更新失败', error: error instanceof Error ? error.message : String(error) })
+    }
+  }
+
+  async getById(request: FastifyRequest<{ Params: { chatId: string } }>, reply: FastifyReply): Promise<FastifyReply> {
+    try {
+      const { chatId } = request.params
+      const data = await this.tgGroupService.findByChatId(chatId)
+      if (!data) {
+        return reply.code(404).send({ message: '群组不存在' })
+      }
+      return reply.send({ data })
+    } catch (error) {
+      return reply
+        .code(500)
+        .send({ message: '查询失败', error: error instanceof Error ? error.message : String(error) })
+    }
+  }
+
+  async list(request: FastifyRequest<{ Querystring: ListTgGroupQuery }>, reply: FastifyReply): Promise<FastifyReply> {
+    try {
+      const result = await this.tgGroupService.list(request.query)
+      return reply.send(result)
+    } catch (error) {
+      return reply
+        .code(500)
+        .send({ message: '查询失败', error: error instanceof Error ? error.message : String(error) })
+    }
+  }
 }
 }

+ 0 - 26
src/dto/chat-group.dto.ts

@@ -1,26 +0,0 @@
-import { Pagination } from './common.dto'
-
-export interface CreateChatGroupRecordBody {
-  chatId: string
-  accessHash: string
-  name?: string
-  groupType?: string
-  inviteLink?: string
-  publicLink?: string
-  senderId?: string
-}
-
-export interface UpdateChatGroupRecordBody {
-  chatId: string
-  name?: string
-  groupType?: string
-  inviteLink?: string
-  publicLink?: string
-  delFlag?: boolean
-}
-
-export interface ListChatGroupQuery extends Pagination {
-  senderId?: string
-  delFlag?: boolean
-}
-

+ 26 - 0
src/dto/tg-group.dto.ts

@@ -1,3 +1,5 @@
+import { Pagination } from './common.dto'
+
 export interface CreateTgGroupBody {
 export interface CreateTgGroupBody {
   groupName: string
   groupName: string
   groupDescription?: string
   groupDescription?: string
@@ -11,4 +13,28 @@ export interface InviteMembersBody {
   chatId?: string
   chatId?: string
   accessHash?: string
   accessHash?: string
   members?: string[]
   members?: string[]
+}
+
+export interface CreateTgGroupRecordBody {
+  chatId: string
+  accessHash: string
+  name?: string
+  groupType?: string
+  inviteLink?: string
+  publicLink?: string
+  senderId?: string
+}
+
+export interface UpdateTgGroupRecordBody {
+  chatId: string
+  name?: string
+  groupType?: string
+  inviteLink?: string
+  publicLink?: string
+  delFlag?: boolean
+}
+
+export interface ListTgGroupQuery extends Pagination {
+  senderId?: string
+  delFlag?: boolean
 }
 }

+ 13 - 8
src/entities/chat-group.entity.ts → src/entities/tg-group.entity.ts

@@ -1,30 +1,35 @@
 import { Column, CreateDateColumn, Entity, Index, PrimaryColumn, UpdateDateColumn } from 'typeorm'
 import { Column, CreateDateColumn, Entity, Index, PrimaryColumn, UpdateDateColumn } from 'typeorm'
 
 
+export enum TgGroupType {
+  CHANNEL = 'channel',
+  MEGA_GROUP = 'megagroup'
+}
+
 @Entity()
 @Entity()
-@Index(['senderId', 'delFlag'])
+@Index(['ownerId', 'delFlag'])
 @Index(['delFlag', 'createdAt'])
 @Index(['delFlag', 'createdAt'])
-export class ChatGroup {
+export class TgGroup {
   @PrimaryColumn({ type: 'bigint' })
   @PrimaryColumn({ type: 'bigint' })
   chatId: string
   chatId: string
 
 
   @Column({ type: 'bigint' })
   @Column({ type: 'bigint' })
   accessHash: string
   accessHash: string
 
 
-  @Column({ type: 'bigint', nullable: true })
-  senderId: string
-
   @Column({ nullable: true })
   @Column({ nullable: true })
   name: string
   name: string
 
 
-  @Column({ nullable: true })
-  groupType: string
-
   @Column({ nullable: true })
   @Column({ nullable: true })
   publicLink: string
   publicLink: string
 
 
   @Column({ nullable: true })
   @Column({ nullable: true })
   inviteLink: string
   inviteLink: string
 
 
+  @Column({ type: 'bigint' })
+  ownerId: string
+
+  @Column({ type: 'enum', enum: TgGroupType, default: TgGroupType.MEGA_GROUP })
+  groupType: TgGroupType
+
   @Column({ default: false })
   @Column({ default: false })
   delFlag: boolean
   delFlag: boolean
 
 

+ 0 - 34
src/routes/chat-group.routes.ts

@@ -1,34 +0,0 @@
-import { FastifyInstance } from 'fastify'
-import { ChatGroupController } from '../controllers/chat-group.controller'
-import { hasRole } from '../middlewares/auth.middleware'
-import { UserRole } from '../entities/user.entity'
-import { CreateChatGroupRecordBody, ListChatGroupQuery, UpdateChatGroupRecordBody } from '../dto/chat-group.dto'
-
-export default async function chatGroupRoutes(fastify: FastifyInstance) {
-  const controller = new ChatGroupController(fastify)
-
-  fastify.post<{ Body: CreateChatGroupRecordBody }>(
-    '/',
-    { onRequest: [hasRole(UserRole.ADMIN)] },
-    controller.createOrUpdate.bind(controller)
-  )
-
-  fastify.put<{ Body: UpdateChatGroupRecordBody }>(
-    '/',
-    { onRequest: [hasRole(UserRole.ADMIN)] },
-    controller.update.bind(controller)
-  )
-
-  fastify.get<{ Params: { chatId: string } }>(
-    '/:chatId',
-    { onRequest: [hasRole(UserRole.ADMIN)] },
-    controller.getById.bind(controller)
-  )
-
-  fastify.get<{ Querystring: ListChatGroupQuery }>(
-    '/',
-    { onRequest: [hasRole(UserRole.ADMIN)] },
-    controller.list.bind(controller)
-  )
-}
-

+ 26 - 1
src/routes/tg-group.routes.ts

@@ -1,9 +1,34 @@
 import { FastifyInstance } from 'fastify'
 import { FastifyInstance } from 'fastify'
 import { TgGroupController } from '../controllers/tg-group.controller'
 import { TgGroupController } from '../controllers/tg-group.controller'
-import { CreateTgGroupBody } from '../dto/tg-group.dto'
+import { hasRole } from '../middlewares/auth.middleware'
+import { UserRole } from '../entities/user.entity'
+import {
+  CreateTgGroupBody,
+  CreateTgGroupRecordBody,
+  ListTgGroupQuery,
+  UpdateTgGroupRecordBody
+} from '../dto/tg-group.dto'
 
 
 export default async function tgGroupRoutes(fastify: FastifyInstance) {
 export default async function tgGroupRoutes(fastify: FastifyInstance) {
   const controller = new TgGroupController(fastify)
   const controller = new TgGroupController(fastify)
 
 
   fastify.post<{ Body: CreateTgGroupBody }>('/create', controller.createGroup.bind(controller))
   fastify.post<{ Body: CreateTgGroupBody }>('/create', controller.createGroup.bind(controller))
+
+  fastify.put<{ Body: UpdateTgGroupRecordBody }>(
+    '/',
+    { onRequest: [hasRole(UserRole.ADMIN)] },
+    controller.update.bind(controller)
+  )
+
+  fastify.get<{ Params: { chatId: string } }>(
+    '/:chatId',
+    { onRequest: [hasRole(UserRole.ADMIN)] },
+    controller.getById.bind(controller)
+  )
+
+  fastify.get<{ Querystring: ListTgGroupQuery }>(
+    '/',
+    { onRequest: [hasRole(UserRole.ADMIN)] },
+    controller.list.bind(controller)
+  )
 }
 }

+ 0 - 75
src/services/chat-group.service.ts

@@ -1,75 +0,0 @@
-import { FastifyInstance } from 'fastify'
-import { Repository } from 'typeorm'
-import { ChatGroup } from '../entities/chat-group.entity'
-import { PaginationResponse } from '../dto/common.dto'
-import { CreateChatGroupRecordBody, ListChatGroupQuery, UpdateChatGroupRecordBody } from '../dto/chat-group.dto'
-
-export class ChatGroupService {
-  private chatGroupRepository: Repository<ChatGroup>
-  private app: FastifyInstance
-
-  constructor(app: FastifyInstance) {
-    this.app = app
-    this.chatGroupRepository = app.dataSource.getRepository(ChatGroup)
-  }
-
-  async upsertGroup(payload: CreateChatGroupRecordBody): Promise<ChatGroup> {
-    const existing = await this.chatGroupRepository.findOne({ where: { chatId: payload.chatId } })
-    
-    if (existing) {
-      // 更新现有记录
-      Object.assign(existing, {
-        ...payload,
-        chatId: String(payload.chatId),
-        accessHash: String(payload.accessHash)
-      })
-      return await this.chatGroupRepository.save(existing)
-    } else {
-      // 创建新记录
-      const entity = this.chatGroupRepository.create({
-        ...payload,
-        chatId: String(payload.chatId),
-        accessHash: String(payload.accessHash)
-      })
-      return await this.chatGroupRepository.save(entity)
-    }
-  }
-
-  async updateGroup(payload: UpdateChatGroupRecordBody): Promise<ChatGroup | null> {
-    const existing = await this.chatGroupRepository.findOne({ where: { chatId: payload.chatId } })
-    if (!existing) {
-      return null
-    }
-    const { chatId, ...updateData } = payload
-    await this.chatGroupRepository.update({ chatId }, updateData)
-    return await this.chatGroupRepository.findOne({ where: { chatId: payload.chatId } })
-  }
-
-  async findByChatId(chatId: string): Promise<ChatGroup | null> {
-    return await this.chatGroupRepository.findOne({ where: { chatId, delFlag: false } })
-  }
-
-  async list(query: ListChatGroupQuery): Promise<PaginationResponse<ChatGroup>> {
-    const { page = 0, size = 20, senderId, delFlag } = query
-    const where: any = {}
-    if (senderId !== undefined) where.senderId = senderId
-    if (delFlag !== undefined) where.delFlag = delFlag
-
-    const [content, total] = await this.chatGroupRepository.findAndCount({
-      where,
-      skip: (Number(page) || 0) * (Number(size) || 20),
-      take: Number(size) || 20,
-      order: { createdAt: 'DESC' }
-    })
-
-    return {
-      content,
-      metadata: {
-        total: Number(total),
-        page: Number(page) || 0,
-        size: Number(size) || 20
-      }
-    }
-  }
-}
-

+ 5 - 5
src/services/test.service.ts

@@ -8,7 +8,7 @@ import { TaskItem, TaskItemStatus } from '../entities/task-item.entity'
 import { TgUser } from '../entities/tg-user.entity'
 import { TgUser } from '../entities/tg-user.entity'
 import { TgUserService } from './tg-user.service'
 import { TgUserService } from './tg-user.service'
 import { TgClientService } from './tgClient.service'
 import { TgClientService } from './tgClient.service'
-import { ChatGroupService } from './chat-group.service'
+import { TgGroupService } from './tg-group.service'
 import { buildStringSession, buildStringSessionByDcIdAndAuthKey } from '../utils/tg.util'
 import { buildStringSession, buildStringSessionByDcIdAndAuthKey } from '../utils/tg.util'
 
 
 export class TestService {
 export class TestService {
@@ -18,7 +18,7 @@ export class TestService {
   private readonly senderRepository: Repository<TgUser>
   private readonly senderRepository: Repository<TgUser>
   private readonly senderService: TgUserService
   private readonly senderService: TgUserService
   private readonly tgClientService: TgClientService
   private readonly tgClientService: TgClientService
-  private readonly chatGroupService: ChatGroupService
+  private readonly tgGroupService: TgGroupService
   private senderSendLimit = 5
   private senderSendLimit = 5
   private senderUsageInBatch: Map<string, number> = new Map()
   private senderUsageInBatch: Map<string, number> = new Map()
   private senderCursor = 0
   private senderCursor = 0
@@ -31,7 +31,7 @@ export class TestService {
     this.senderRepository = app.dataSource.getRepository(TgUser)
     this.senderRepository = app.dataSource.getRepository(TgUser)
     this.senderService = new TgUserService(app)
     this.senderService = new TgUserService(app)
     this.tgClientService = new TgClientService()
     this.tgClientService = new TgClientService()
-    this.chatGroupService = new ChatGroupService(app)
+    this.tgGroupService = new TgGroupService(app)
   }
   }
 
 
   async findTaskById(id: number): Promise<Task | null> {
   async findTaskById(id: number): Promise<Task | null> {
@@ -702,7 +702,7 @@ export class TestService {
       }
       }
 
 
       try {
       try {
-        await this.chatGroupService.upsertGroup({
+        await this.tgGroupService.upsertGroup({
           chatId: chatId.toString(),
           chatId: chatId.toString(),
           accessHash: accessHash?.toString() || '',
           accessHash: accessHash?.toString() || '',
           name: createdChat.title || groupName,
           name: createdChat.title || groupName,
@@ -958,7 +958,7 @@ export class TestService {
       }
       }
 
 
       try {
       try {
-        await this.chatGroupService.upsertGroup({
+        await this.tgGroupService.upsertGroup({
           chatId: chatEntity.id.toString(),
           chatId: chatEntity.id.toString(),
           accessHash: (chatEntity.accessHash || '').toString(),
           accessHash: (chatEntity.accessHash || '').toString(),
           name: chatEntity.title || chatEntity.username || chatTarget,
           name: chatEntity.title || chatEntity.username || chatTarget,

+ 69 - 4
src/services/tg-group.service.ts

@@ -1,20 +1,26 @@
 import { FastifyInstance } from 'fastify'
 import { FastifyInstance } from 'fastify'
 import { Repository } from 'typeorm'
 import { Repository } from 'typeorm'
 import { TgUser } from '../entities/tg-user.entity'
 import { TgUser } from '../entities/tg-user.entity'
+import { TgGroup } from '../entities/tg-group.entity'
 import { TgClientService } from './tgClient.service'
 import { TgClientService } from './tgClient.service'
 import { buildStringSessionByDcIdAndAuthKey } from '../utils/tg.util'
 import { buildStringSessionByDcIdAndAuthKey } from '../utils/tg.util'
 import { TelegramClient } from 'telegram'
 import { TelegramClient } from 'telegram'
-import { ChatGroupService } from './chat-group.service'
+import { PaginationResponse } from '../dto/common.dto'
+import {
+  CreateTgGroupRecordBody,
+  ListTgGroupQuery,
+  UpdateTgGroupRecordBody
+} from '../dto/tg-group.dto'
 
 
 export class TgGroupService {
 export class TgGroupService {
   private readonly app: FastifyInstance
   private readonly app: FastifyInstance
   private readonly tgClientService: TgClientService
   private readonly tgClientService: TgClientService
-  private readonly chatGroupService: ChatGroupService
+  private readonly tgGroupRepository: Repository<TgGroup>
   private readonly senderRepository: Repository<TgUser>
   private readonly senderRepository: Repository<TgUser>
   constructor(app: FastifyInstance) {
   constructor(app: FastifyInstance) {
     this.app = app
     this.app = app
     this.tgClientService = new TgClientService()
     this.tgClientService = new TgClientService()
-    this.chatGroupService = new ChatGroupService(app)
+    this.tgGroupRepository = app.dataSource.getRepository(TgGroup)
     this.senderRepository = app.dataSource.getRepository(TgUser)
     this.senderRepository = app.dataSource.getRepository(TgUser)
   }
   }
 
 
@@ -90,7 +96,7 @@ export class TgGroupService {
         await this.tgClientService.sendMessageToChannelGroup(inputChannel, initMsg.trim())
         await this.tgClientService.sendMessageToChannelGroup(inputChannel, initMsg.trim())
       }
       }
 
 
-      await this.chatGroupService.upsertGroup({
+      await this.upsertGroup({
         chatId: groupInfo.chatId,
         chatId: groupInfo.chatId,
         accessHash: groupInfo.accessHash,
         accessHash: groupInfo.accessHash,
         name: groupName,
         name: groupName,
@@ -132,4 +138,63 @@ export class TgGroupService {
   }
   }
 
 
   async inviteMembers(senderId?: string, chatId?: string, accessHash?: string, members?: string[]): Promise<any> {}
   async inviteMembers(senderId?: string, chatId?: string, accessHash?: string, members?: string[]): Promise<any> {}
+
+  async upsertGroup(payload: CreateTgGroupRecordBody): Promise<TgGroup> {
+    const existing = await this.tgGroupRepository.findOne({ where: { chatId: payload.chatId } })
+    
+    if (existing) {
+      // 更新现有记录
+      Object.assign(existing, {
+        ...payload,
+        chatId: String(payload.chatId),
+        accessHash: String(payload.accessHash)
+      })
+      return await this.tgGroupRepository.save(existing)
+    } else {
+      // 创建新记录
+      const entity = this.tgGroupRepository.create({
+        ...payload,
+        chatId: String(payload.chatId),
+        accessHash: String(payload.accessHash)
+      })
+      return await this.tgGroupRepository.save(entity)
+    }
+  }
+
+  async updateGroup(payload: UpdateTgGroupRecordBody): Promise<TgGroup | null> {
+    const existing = await this.tgGroupRepository.findOne({ where: { chatId: payload.chatId } })
+    if (!existing) {
+      return null
+    }
+    const { chatId, ...updateData } = payload
+    await this.tgGroupRepository.update({ chatId }, updateData)
+    return await this.tgGroupRepository.findOne({ where: { chatId: payload.chatId } })
+  }
+
+  async findByChatId(chatId: string): Promise<TgGroup | null> {
+    return await this.tgGroupRepository.findOne({ where: { chatId, delFlag: false } })
+  }
+
+  async list(query: ListTgGroupQuery): Promise<PaginationResponse<TgGroup>> {
+    const { page = 0, size = 20, senderId, delFlag } = query
+    const where: any = {}
+    if (senderId !== undefined) where.senderId = senderId
+    if (delFlag !== undefined) where.delFlag = delFlag
+
+    const [content, total] = await this.tgGroupRepository.findAndCount({
+      where,
+      skip: (Number(page) || 0) * (Number(size) || 20),
+      take: Number(size) || 20,
+      order: { createdAt: 'DESC' }
+    })
+
+    return {
+      content,
+      metadata: {
+        total: Number(total),
+        page: Number(page) || 0,
+        size: Number(size) || 20
+      }
+    }
+  }
 }
 }