|
@@ -126,9 +126,6 @@ export class WorkService {
|
|
|
logger.info(`[SyncWorks] Starting sync for userId: ${userId}, accountId: ${accountId || 'all'}, platform: ${platform || 'all'}`);
|
|
logger.info(`[SyncWorks] Starting sync for userId: ${userId}, accountId: ${accountId || 'all'}, platform: ${platform || 'all'}`);
|
|
|
|
|
|
|
|
// 先查看所有账号(调试用)
|
|
// 先查看所有账号(调试用)
|
|
|
- const allAccounts = await this.accountRepository.find({ where: { userId } });
|
|
|
|
|
- logger.info(`[SyncWorks] All accounts for user ${userId}: ${allAccounts.map(a => `id=${a.id},status=${a.status},platform=${a.platform}`).join('; ')}`);
|
|
|
|
|
-
|
|
|
|
|
// 同时查询 active 和 expired 状态的账号(expired 的账号 cookie 可能实际上还有效)
|
|
// 同时查询 active 和 expired 状态的账号(expired 的账号 cookie 可能实际上还有效)
|
|
|
const queryBuilder = this.accountRepository
|
|
const queryBuilder = this.accountRepository
|
|
|
.createQueryBuilder('account')
|
|
.createQueryBuilder('account')
|
|
@@ -181,7 +178,7 @@ export class WorkService {
|
|
|
|
|
|
|
|
// 如果同步成功且账号状态是 expired,则恢复为 active
|
|
// 如果同步成功且账号状态是 expired,则恢复为 active
|
|
|
if (result.syncedCount > 0 && account.status === 'expired') {
|
|
if (result.syncedCount > 0 && account.status === 'expired') {
|
|
|
- await this.accountRepository.update(account.id, { status: 'active' });
|
|
|
|
|
|
|
+ await this.accountRepository.update({ id: account.id, userId }, { status: 'active' });
|
|
|
logger.info(`[SyncWorks] Account ${account.id} status restored to active`);
|
|
logger.info(`[SyncWorks] Account ${account.id} status restored to active`);
|
|
|
}
|
|
}
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
@@ -271,7 +268,7 @@ export class WorkService {
|
|
|
accountUpdate.avatarUrl = accountInfo.avatarUrl;
|
|
accountUpdate.avatarUrl = accountInfo.avatarUrl;
|
|
|
}
|
|
}
|
|
|
if (Object.keys(accountUpdate).length > 0) {
|
|
if (Object.keys(accountUpdate).length > 0) {
|
|
|
- await this.accountRepository.update(account.id, accountUpdate as any);
|
|
|
|
|
|
|
+ await this.accountRepository.update({ id: account.id, userId }, accountUpdate as any);
|
|
|
logger.info(`[SyncAccountWorks] Updated account info: ${Object.keys(accountUpdate).join(', ')}`);
|
|
logger.info(`[SyncAccountWorks] Updated account info: ${Object.keys(accountUpdate).join(', ')}`);
|
|
|
// Bug #6075: 改用前端监听的 ACCOUNT_DATA_CHANGED 事件,确保前端能刷新账号数据(头像、昵称等)
|
|
// Bug #6075: 改用前端监听的 ACCOUNT_DATA_CHANGED 事件,确保前端能刷新账号数据(头像、昵称等)
|
|
|
wsManager.sendToUser(userId, WS_EVENTS.ACCOUNT_DATA_CHANGED, {
|
|
wsManager.sendToUser(userId, WS_EVENTS.ACCOUNT_DATA_CHANGED, {
|
|
@@ -339,11 +336,11 @@ export class WorkService {
|
|
|
});
|
|
});
|
|
|
if (legacyWork && legacyWork.id !== work.id) {
|
|
if (legacyWork && legacyWork.id !== work.id) {
|
|
|
await AppDataSource.getRepository(Comment).update(
|
|
await AppDataSource.getRepository(Comment).update(
|
|
|
- { workId: legacyWork.id },
|
|
|
|
|
|
|
+ { workId: legacyWork.id, userId },
|
|
|
{ workId: work.id }
|
|
{ workId: work.id }
|
|
|
);
|
|
);
|
|
|
await this.workDayStatisticsService.deleteByWorkId(legacyWork.id);
|
|
await this.workDayStatisticsService.deleteByWorkId(legacyWork.id);
|
|
|
- await this.workRepository.delete(legacyWork.id);
|
|
|
|
|
|
|
+ await this.workRepository.delete({ id: legacyWork.id, userId });
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -359,14 +356,14 @@ export class WorkService {
|
|
|
|
|
|
|
|
if (canonicalWork) {
|
|
if (canonicalWork) {
|
|
|
await AppDataSource.getRepository(Comment).update(
|
|
await AppDataSource.getRepository(Comment).update(
|
|
|
- { workId: legacyWork.id },
|
|
|
|
|
|
|
+ { workId: legacyWork.id, userId },
|
|
|
{ workId: canonicalWork.id }
|
|
{ workId: canonicalWork.id }
|
|
|
);
|
|
);
|
|
|
await this.workDayStatisticsService.deleteByWorkId(legacyWork.id);
|
|
await this.workDayStatisticsService.deleteByWorkId(legacyWork.id);
|
|
|
- await this.workRepository.delete(legacyWork.id);
|
|
|
|
|
|
|
+ await this.workRepository.delete({ id: legacyWork.id, userId });
|
|
|
work = canonicalWork;
|
|
work = canonicalWork;
|
|
|
} else {
|
|
} else {
|
|
|
- await this.workRepository.update(legacyWork.id, {
|
|
|
|
|
|
|
+ await this.workRepository.update({ id: legacyWork.id, userId }, {
|
|
|
platformVideoId: canonicalVideoId,
|
|
platformVideoId: canonicalVideoId,
|
|
|
});
|
|
});
|
|
|
work = { ...legacyWork, platformVideoId: canonicalVideoId };
|
|
work = { ...legacyWork, platformVideoId: canonicalVideoId };
|
|
@@ -431,7 +428,7 @@ export class WorkService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (platform === 'weixin_video') {
|
|
if (platform === 'weixin_video') {
|
|
|
- await this.dedupeWeixinVideoWorks(account.id);
|
|
|
|
|
|
|
+ await this.dedupeWeixinVideoWorks(account.id, userId);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 删除本地存在但远程已删除的作品
|
|
// 删除本地存在但远程已删除的作品
|
|
@@ -455,7 +452,8 @@ export class WorkService {
|
|
|
skipLocalDeletions = true;
|
|
skipLocalDeletions = true;
|
|
|
} else {
|
|
} else {
|
|
|
const localWorks = await this.workRepository.find({
|
|
const localWorks = await this.workRepository.find({
|
|
|
- where: { accountId: account.id },
|
|
|
|
|
|
|
+ where: { accountId: account.id, userId },
|
|
|
|
|
+ select: ['id', 'title', 'platformVideoId'],
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
if (platform === 'weixin_video') {
|
|
if (platform === 'weixin_video') {
|
|
@@ -483,9 +481,9 @@ export class WorkService {
|
|
|
let deletedCount = 0;
|
|
let deletedCount = 0;
|
|
|
for (const localWork of localWorks) {
|
|
for (const localWork of localWorks) {
|
|
|
if (!remotePlatformVideoIds.has(localWork.platformVideoId)) {
|
|
if (!remotePlatformVideoIds.has(localWork.platformVideoId)) {
|
|
|
- await AppDataSource.getRepository(Comment).delete({ workId: localWork.id });
|
|
|
|
|
|
|
+ await AppDataSource.getRepository(Comment).delete({ workId: localWork.id, userId });
|
|
|
await this.workDayStatisticsService.deleteByWorkId(localWork.id);
|
|
await this.workDayStatisticsService.deleteByWorkId(localWork.id);
|
|
|
- await this.workRepository.delete(localWork.id);
|
|
|
|
|
|
|
+ await this.workRepository.delete({ id: localWork.id, userId });
|
|
|
deletedCount++;
|
|
deletedCount++;
|
|
|
logger.info(`Deleted work ${localWork.id} (${localWork.title}) - no longer exists on platform`);
|
|
logger.info(`Deleted work ${localWork.id} (${localWork.title}) - no longer exists on platform`);
|
|
|
}
|
|
}
|
|
@@ -505,165 +503,7 @@ export class WorkService {
|
|
|
// }
|
|
// }
|
|
|
|
|
|
|
|
// 小红书:如果是新作品且 work_day_statistics 中尚无任何记录,则补首批日统计 & works.yesterday_*(不受14天限制)
|
|
// 小红书:如果是新作品且 work_day_statistics 中尚无任何记录,则补首批日统计 & works.yesterday_*(不受14天限制)
|
|
|
- if (platform === 'xiaohongshu') {
|
|
|
|
|
- try {
|
|
|
|
|
- const works = await this.workRepository.find({
|
|
|
|
|
- where: { accountId: account.id, platform },
|
|
|
|
|
- select: ['id'],
|
|
|
|
|
- });
|
|
|
|
|
- const workIds = works.map((w) => w.id);
|
|
|
|
|
- if (workIds.length > 0) {
|
|
|
|
|
- const rows = await AppDataSource.getRepository(WorkDayStatistics)
|
|
|
|
|
- .createQueryBuilder('wds')
|
|
|
|
|
- .select('DISTINCT wds.work_id', 'workId')
|
|
|
|
|
- .where('wds.work_id IN (:...ids)', { ids: workIds })
|
|
|
|
|
- .getRawMany();
|
|
|
|
|
- const hasStats = new Set<number>(rows.map((r: any) => Number(r.workId)));
|
|
|
|
|
- const needInitIds = workIds.filter((id) => !hasStats.has(id));
|
|
|
|
|
-
|
|
|
|
|
- if (needInitIds.length > 0) {
|
|
|
|
|
- logger.info(
|
|
|
|
|
- `[SyncAccountWorks] XHS account ${account.id} has ${needInitIds.length} works without statistics, running initial note/base import.`
|
|
|
|
|
- );
|
|
|
|
|
- // 放入任务队列异步执行,避免阻塞同步作品流程
|
|
|
|
|
- taskQueueService.createTask(account.userId, {
|
|
|
|
|
- type: 'xhs_work_stats_backfill',
|
|
|
|
|
- title: `小红书作品补数(${needInitIds.length})`,
|
|
|
|
|
- accountId: account.id,
|
|
|
|
|
- platform: 'xiaohongshu',
|
|
|
|
|
- data: {
|
|
|
|
|
- workIds: needInitIds,
|
|
|
|
|
- },
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } catch (err) {
|
|
|
|
|
- logger.error(
|
|
|
|
|
- `[SyncAccountWorks] Failed to backfill XHS work_day_statistics for account ${account.id}:`,
|
|
|
|
|
- err
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 抖音:如果是新作品且 work_day_statistics 中尚无任何记录,则异步补齐历史日统计 & works.yesterday_*(使用 DouyinWorkStatisticsImportService)
|
|
|
|
|
- if (platform === 'douyin') {
|
|
|
|
|
- try {
|
|
|
|
|
- const works = await this.workRepository.find({
|
|
|
|
|
- where: { accountId: account.id, platform },
|
|
|
|
|
- select: ['id'],
|
|
|
|
|
- });
|
|
|
|
|
- const workIds = works.map((w) => w.id);
|
|
|
|
|
- if (workIds.length > 0) {
|
|
|
|
|
- const rows = await AppDataSource.getRepository(WorkDayStatistics)
|
|
|
|
|
- .createQueryBuilder('wds')
|
|
|
|
|
- .select('DISTINCT wds.work_id', 'workId')
|
|
|
|
|
- .where('wds.work_id IN (:...ids)', { ids: workIds })
|
|
|
|
|
- .getRawMany();
|
|
|
|
|
- const hasStats = new Set<number>(rows.map((r: any) => Number(r.workId)));
|
|
|
|
|
- const needInitIds = workIds.filter((id) => !hasStats.has(id));
|
|
|
|
|
-
|
|
|
|
|
- if (needInitIds.length > 0) {
|
|
|
|
|
- logger.info(
|
|
|
|
|
- `[SyncAccountWorks] DY account ${account.id} has ${needInitIds.length} works without statistics, enqueue dy_work_stats_backfill task.`
|
|
|
|
|
- );
|
|
|
|
|
- taskQueueService.createTask(account.userId, {
|
|
|
|
|
- type: 'dy_work_stats_backfill',
|
|
|
|
|
- title: `抖音作品补数(${needInitIds.length})`,
|
|
|
|
|
- accountId: account.id,
|
|
|
|
|
- platform: 'douyin',
|
|
|
|
|
- data: {
|
|
|
|
|
- workIds: needInitIds,
|
|
|
|
|
- },
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } catch (err) {
|
|
|
|
|
- logger.error(
|
|
|
|
|
- `[SyncAccountWorks] Failed to enqueue DY work_day_statistics backfill for account ${account.id}:`,
|
|
|
|
|
- err
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 百家号:如果是新作品且 work_day_statistics 中尚无任何记录,则异步补齐历史日统计 & works.yesterday_*(使用 BaijiahaoWorkDailyStatisticsImportService)
|
|
|
|
|
- if (platform === 'baijiahao') {
|
|
|
|
|
- try {
|
|
|
|
|
- const works = await this.workRepository.find({
|
|
|
|
|
- where: { accountId: account.id, platform },
|
|
|
|
|
- select: ['id'],
|
|
|
|
|
- });
|
|
|
|
|
- const workIds = works.map((w) => w.id);
|
|
|
|
|
- if (workIds.length > 0) {
|
|
|
|
|
- const rows = await AppDataSource.getRepository(WorkDayStatistics)
|
|
|
|
|
- .createQueryBuilder('wds')
|
|
|
|
|
- .select('DISTINCT wds.work_id', 'workId')
|
|
|
|
|
- .where('wds.work_id IN (:...ids)', { ids: workIds })
|
|
|
|
|
- .getRawMany();
|
|
|
|
|
- const hasStats = new Set<number>(rows.map((r: any) => Number(r.workId)));
|
|
|
|
|
- const needInitIds = workIds.filter((id) => !hasStats.has(id));
|
|
|
|
|
-
|
|
|
|
|
- if (needInitIds.length > 0) {
|
|
|
|
|
- logger.info(
|
|
|
|
|
- `[SyncAccountWorks] BJ account ${account.id} has ${needInitIds.length} works without statistics, enqueue bj_work_stats_backfill task.`
|
|
|
|
|
- );
|
|
|
|
|
- taskQueueService.createTask(account.userId, {
|
|
|
|
|
- type: 'bj_work_stats_backfill',
|
|
|
|
|
- title: `百家号作品补数(${needInitIds.length})`,
|
|
|
|
|
- accountId: account.id,
|
|
|
|
|
- platform: 'baijiahao',
|
|
|
|
|
- data: {
|
|
|
|
|
- workIds: needInitIds,
|
|
|
|
|
- },
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } catch (err) {
|
|
|
|
|
- logger.error(
|
|
|
|
|
- `[SyncAccountWorks] Failed to enqueue BJ work_day_statistics backfill for account ${account.id}:`,
|
|
|
|
|
- err
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 视频号:如果是新作品且 work_day_statistics 中尚无任何记录,则异步补齐日统计 & works.yesterday_*(使用 WeixinVideoWorkStatisticsImportService)
|
|
|
|
|
- if (platform === 'weixin_video') {
|
|
|
|
|
- try {
|
|
|
|
|
- const works = await this.workRepository.find({
|
|
|
|
|
- where: { accountId: account.id, platform },
|
|
|
|
|
- select: ['id'],
|
|
|
|
|
- });
|
|
|
|
|
- const workIds = works.map((w) => w.id);
|
|
|
|
|
- if (workIds.length > 0) {
|
|
|
|
|
- const rows = await AppDataSource.getRepository(WorkDayStatistics)
|
|
|
|
|
- .createQueryBuilder('wds')
|
|
|
|
|
- .select('DISTINCT wds.work_id', 'workId')
|
|
|
|
|
- .where('wds.work_id IN (:...ids)', { ids: workIds })
|
|
|
|
|
- .getRawMany();
|
|
|
|
|
- const hasStats = new Set<number>(rows.map((r: any) => Number(r.workId)));
|
|
|
|
|
- const needInitIds = workIds.filter((id) => !hasStats.has(id));
|
|
|
|
|
-
|
|
|
|
|
- if (needInitIds.length > 0) {
|
|
|
|
|
- logger.info(
|
|
|
|
|
- `[SyncAccountWorks] WX account ${account.id} has ${needInitIds.length} works without statistics, enqueue wx_work_stats_backfill task.`
|
|
|
|
|
- );
|
|
|
|
|
- taskQueueService.createTask(account.userId, {
|
|
|
|
|
- type: 'wx_work_stats_backfill',
|
|
|
|
|
- title: `视频号作品补数(${needInitIds.length})`,
|
|
|
|
|
- accountId: account.id,
|
|
|
|
|
- platform: 'weixin_video',
|
|
|
|
|
- data: {
|
|
|
|
|
- workIds: needInitIds,
|
|
|
|
|
- },
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } catch (err) {
|
|
|
|
|
- logger.error(
|
|
|
|
|
- `[SyncAccountWorks] Failed to enqueue WX work_day_statistics backfill for account ${account.id}:`,
|
|
|
|
|
- err
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ await this.enqueueInitialWorkStatsBackfill(account, platform);
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
syncedCount,
|
|
syncedCount,
|
|
@@ -674,6 +514,84 @@ export class WorkService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
|
|
+ * Find works without day statistics once and enqueue the matching backfill task.
|
|
|
|
|
+ */
|
|
|
|
|
+ private async enqueueInitialWorkStatsBackfill(
|
|
|
|
|
+ account: PlatformAccount,
|
|
|
|
|
+ platform: PlatformType
|
|
|
|
|
+ ): Promise<void> {
|
|
|
|
|
+ const configByPlatform = {
|
|
|
|
|
+ xiaohongshu: {
|
|
|
|
|
+ type: 'xhs_work_stats_backfill',
|
|
|
|
|
+ label: 'XHS',
|
|
|
|
|
+ },
|
|
|
|
|
+ douyin: {
|
|
|
|
|
+ type: 'dy_work_stats_backfill',
|
|
|
|
|
+ label: 'DY',
|
|
|
|
|
+ },
|
|
|
|
|
+ baijiahao: {
|
|
|
|
|
+ type: 'bj_work_stats_backfill',
|
|
|
|
|
+ label: 'BJ',
|
|
|
|
|
+ },
|
|
|
|
|
+ weixin_video: {
|
|
|
|
|
+ type: 'wx_work_stats_backfill',
|
|
|
|
|
+ label: 'WX',
|
|
|
|
|
+ },
|
|
|
|
|
+ } as const;
|
|
|
|
|
+
|
|
|
|
|
+ const backfillConfig = configByPlatform[platform as keyof typeof configByPlatform];
|
|
|
|
|
+ if (!backfillConfig) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const rows = await this.workRepository
|
|
|
|
|
+ .createQueryBuilder('work')
|
|
|
|
|
+ .select('work.id', 'id')
|
|
|
|
|
+ .leftJoin(WorkDayStatistics, 'wds', 'wds.workId = work.id')
|
|
|
|
|
+ .where('work.accountId = :accountId', { accountId: account.id })
|
|
|
|
|
+ .andWhere('work.userId = :userId', { userId: account.userId })
|
|
|
|
|
+ .andWhere('work.platform = :platform', { platform })
|
|
|
|
|
+ .andWhere('wds.id IS NULL')
|
|
|
|
|
+ .getRawMany<{ id: number | string }>();
|
|
|
|
|
+
|
|
|
|
|
+ const workIds = rows
|
|
|
|
|
+ .map((row) => Number(row.id))
|
|
|
|
|
+ .filter((id) => Number.isFinite(id) && id > 0);
|
|
|
|
|
+
|
|
|
|
|
+ if (workIds.length === 0) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ logger.info(
|
|
|
|
|
+ `[SyncAccountWorks] ${backfillConfig.label} account ${account.id} has ${workIds.length} works without statistics, enqueue backfill task.`
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ const activeBackfillExists = taskQueueService
|
|
|
|
|
+ .getActiveTasks(account.userId)
|
|
|
|
|
+ .some((task) => task.type === backfillConfig.type && task.accountId === account.id);
|
|
|
|
|
+
|
|
|
|
|
+ if (activeBackfillExists) {
|
|
|
|
|
+ logger.info(`[SyncAccountWorks] ${backfillConfig.label} backfill for account ${account.id} is already active, skip enqueue.`);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ await taskQueueService.createTask(account.userId, {
|
|
|
|
|
+ type: backfillConfig.type,
|
|
|
|
|
+ title: `${platform} work stats backfill (${workIds.length})`,
|
|
|
|
|
+ accountId: account.id,
|
|
|
|
|
+ platform,
|
|
|
|
|
+ data: { workIds },
|
|
|
|
|
+ });
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ logger.error(
|
|
|
|
|
+ `[SyncAccountWorks] Failed to enqueue work_day_statistics backfill for account ${account.id}:`,
|
|
|
|
|
+ err
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
* 保存作品每日统计数据
|
|
* 保存作品每日统计数据
|
|
|
*/
|
|
*/
|
|
|
private async saveWorkDayStatistics(account: PlatformAccount): Promise<void> {
|
|
private async saveWorkDayStatistics(account: PlatformAccount): Promise<void> {
|
|
@@ -737,11 +655,11 @@ export class WorkService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 先删除关联的评论和作品每日统计
|
|
// 先删除关联的评论和作品每日统计
|
|
|
- await AppDataSource.getRepository(Comment).delete({ workId });
|
|
|
|
|
|
|
+ await AppDataSource.getRepository(Comment).delete({ workId, userId });
|
|
|
await this.workDayStatisticsService.deleteByWorkId(workId);
|
|
await this.workDayStatisticsService.deleteByWorkId(workId);
|
|
|
|
|
|
|
|
// 删除作品
|
|
// 删除作品
|
|
|
- await this.workRepository.delete(workId);
|
|
|
|
|
|
|
+ await this.workRepository.delete({ id: workId, userId });
|
|
|
|
|
|
|
|
logger.info(`Deleted work ${workId} for user ${userId}`);
|
|
logger.info(`Deleted work ${workId} for user ${userId}`);
|
|
|
}
|
|
}
|
|
@@ -765,7 +683,7 @@ export class WorkService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const account = await this.accountRepository.findOne({
|
|
const account = await this.accountRepository.findOne({
|
|
|
- where: { id: work.accountId },
|
|
|
|
|
|
|
+ where: { id: work.accountId, userId },
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
if (!account || !account.cookieData) {
|
|
if (!account || !account.cookieData) {
|
|
@@ -789,7 +707,7 @@ export class WorkService {
|
|
|
|
|
|
|
|
if (result.success) {
|
|
if (result.success) {
|
|
|
// 更新作品状态为已删除
|
|
// 更新作品状态为已删除
|
|
|
- await this.workRepository.update(workId, { status: 'deleted' });
|
|
|
|
|
|
|
+ await this.workRepository.update({ id: workId, userId }, { status: 'deleted' });
|
|
|
logger.info(`Platform work ${workId} deleted successfully`);
|
|
logger.info(`Platform work ${workId} deleted successfully`);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -804,7 +722,7 @@ export class WorkService {
|
|
|
|
|
|
|
|
if (result.success) {
|
|
if (result.success) {
|
|
|
// 更新作品状态为已删除
|
|
// 更新作品状态为已删除
|
|
|
- await this.workRepository.update(workId, { status: 'deleted' });
|
|
|
|
|
|
|
+ await this.workRepository.update({ id: workId, userId }, { status: 'deleted' });
|
|
|
logger.info(`Platform work ${workId} (xiaohongshu) deleted successfully`);
|
|
logger.info(`Platform work ${workId} (xiaohongshu) deleted successfully`);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -854,8 +772,11 @@ export class WorkService {
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private async dedupeWeixinVideoWorks(accountId: number): Promise<void> {
|
|
|
|
|
- const works = await this.workRepository.find({ where: { accountId } });
|
|
|
|
|
|
|
+ private async dedupeWeixinVideoWorks(accountId: number, userId: number): Promise<void> {
|
|
|
|
|
+ const works = await this.workRepository.find({
|
|
|
|
|
+ where: { accountId, userId },
|
|
|
|
|
+ select: ['id', 'title', 'publishTime', 'platformVideoId', 'updatedAt'],
|
|
|
|
|
+ });
|
|
|
const groups = new Map<string, Work[]>();
|
|
const groups = new Map<string, Work[]>();
|
|
|
|
|
|
|
|
for (const w of works) {
|
|
for (const w of works) {
|
|
@@ -879,8 +800,8 @@ export class WorkService {
|
|
|
const keep = list[0];
|
|
const keep = list[0];
|
|
|
for (const dup of list.slice(1)) {
|
|
for (const dup of list.slice(1)) {
|
|
|
if (dup.id === keep.id) continue;
|
|
if (dup.id === keep.id) continue;
|
|
|
- await this.commentRepository.update({ workId: dup.id }, { workId: keep.id });
|
|
|
|
|
- await this.workRepository.delete(dup.id);
|
|
|
|
|
|
|
+ await this.commentRepository.update({ workId: dup.id, userId }, { workId: keep.id });
|
|
|
|
|
+ await this.workRepository.delete({ id: dup.id, userId });
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|