77 *
88 */
99
10+ import { RedisService } from '@liaoliaots/nestjs-redis' ;
1011import { Inject , Injectable , Logger , forwardRef } from '@nestjs/common' ;
1112import { ConfigService } from '@nestjs/config' ;
1213import {
@@ -30,6 +31,7 @@ import {
3031import bcrypt from 'bcryptjs' ;
3132import { isEmail } from 'class-validator' ;
3233import { Request } from 'express' ;
34+ import Redis from 'ioredis' ;
3335import assert from 'node:assert' ;
3436import { AnswerService } from '../answer/answer.service' ;
3537import {
@@ -81,9 +83,15 @@ import {
8183 UsernameNotFoundError ,
8284} from './users.error' ;
8385
86+ const USER_PROFILE_UPDATE_CHANNEL = 'cache:user:updated' ;
87+
8488@Injectable ( )
8589export class UsersService {
90+ private readonly logger = new Logger ( UsersService . name ) ;
91+ private readonly redis : Redis ;
92+
8693 constructor (
94+ private readonly redisService : RedisService ,
8795 private readonly emailService : EmailService ,
8896 private readonly emailRuleService : EmailRuleService ,
8997 private readonly authService : AuthService ,
@@ -100,7 +108,9 @@ export class UsersService {
100108 private readonly prismaService : PrismaService ,
101109 private readonly totpService : TOTPService ,
102110 private readonly srpService : SrpService ,
103- ) { }
111+ ) {
112+ this . redis = this . redisService . getOrThrow ( ) ;
113+ }
104114
105115 private readonly passwordResetEmailValidSeconds = 10 * 60 ; // 10 minutes
106116
@@ -1039,23 +1049,70 @@ export class UsersService {
10391049 intro : string ,
10401050 avatarId : number ,
10411051 ) : Promise < void > {
1052+ this . logger . log ( `Attempting to update profile for user ID: ${ userId } ` ) ;
10421053 const [ , profile ] =
10431054 await this . findUserRecordAndProfileRecordOrThrow ( userId ) ;
1044- if ( ( await this . avatarsService . isAvatarExists ( avatarId ) ) == false ) {
1055+
1056+ if ( ( await this . avatarsService . isAvatarExists ( avatarId ) ) === false ) {
1057+ this . logger . warn ( `Avatar not found: ${ avatarId } for user: ${ userId } ` ) ;
10451058 throw new AvatarNotFoundError ( avatarId ) ;
10461059 }
1047- await this . avatarsService . plusUsageCount ( avatarId ) ;
1048- await this . avatarsService . minusUsageCount ( profile . avatarId ) ;
1049- await this . prismaService . userProfile . update ( {
1050- where : {
1051- userId,
1052- } ,
1053- data : {
1054- nickname,
1055- intro,
1056- avatarId,
1057- } ,
1058- } ) ;
1060+
1061+ const oldAvatarId = profile . avatarId ;
1062+
1063+ if (
1064+ profile . nickname !== nickname ||
1065+ profile . intro !== intro ||
1066+ profile . avatarId !== avatarId
1067+ ) {
1068+ await this . prismaService . userProfile . update ( {
1069+ where : {
1070+ userId,
1071+ } ,
1072+ data : {
1073+ nickname,
1074+ intro,
1075+ avatarId,
1076+ } ,
1077+ } ) ;
1078+ this . logger . log ( `Profile successfully updated for user ID: ${ userId } ` ) ;
1079+
1080+ try {
1081+ const publishedCount = await this . redis . publish (
1082+ USER_PROFILE_UPDATE_CHANNEL ,
1083+ userId . toString ( ) ,
1084+ ) ;
1085+ this . logger . log (
1086+ `Published cache invalidation message for user ID: ${ userId } to channel '${ USER_PROFILE_UPDATE_CHANNEL } '. Received by ${ publishedCount } clients.` ,
1087+ ) ;
1088+ } catch ( error ) {
1089+ this . logger . error (
1090+ `Failed to publish cache invalidation message for user ID: ${ userId } to Redis channel '${ USER_PROFILE_UPDATE_CHANNEL } '` ,
1091+ error instanceof Error ? error . stack : error ,
1092+ ) ;
1093+ }
1094+
1095+ if ( oldAvatarId !== avatarId ) {
1096+ try {
1097+ await Promise . all ( [
1098+ this . avatarsService . plusUsageCount ( avatarId ) ,
1099+ this . avatarsService . minusUsageCount ( oldAvatarId ) ,
1100+ ] ) ;
1101+ this . logger . log (
1102+ `Updated avatar usage counts for user ID: ${ userId } . New: ${ avatarId } , Old: ${ oldAvatarId } ` ,
1103+ ) ;
1104+ } catch ( avatarError ) {
1105+ this . logger . error (
1106+ `Error updating avatar usage counts for user ID ${ userId } ` ,
1107+ avatarError instanceof Error ? avatarError . stack : avatarError ,
1108+ ) ;
1109+ }
1110+ }
1111+ } else {
1112+ this . logger . log (
1113+ `Profile data unchanged for user ID: ${ userId } . Skipping update and cache invalidation.` ,
1114+ ) ;
1115+ }
10591116 }
10601117
10611118 async getUniqueFollowRelationship (
0 commit comments