fix(server): store null instead of empty string for user profileImagePath

This commit is contained in:
Devesh Kolte 2026-07-22 22:11:27 +05:30
parent f2b0b696f6
commit 42b90368eb
9 changed files with 25 additions and 10 deletions

View file

@ -128,7 +128,7 @@ export type User = {
name: string;
email: string;
avatarColor: UserAvatarColor | null;
profileImagePath: string;
profileImagePath: string | null;
profileChangedAt: Date;
};

View file

@ -32,7 +32,7 @@ const LoginResponseSchema = z
userId: z.uuidv4().describe('User ID'),
userEmail: toEmail.describe('User email'),
name: z.string().describe('User name'),
profileImagePath: z.string().describe('Profile image path'),
profileImagePath: z.string().nullable().describe('Profile image path'),
isAdmin: z.boolean().describe('Is admin user'),
shouldChangePassword: z.boolean().describe('Should change password'),
isOnboarded: z.boolean().describe('Is onboarded'),

View file

@ -27,7 +27,7 @@ export const UserResponseSchema = z
id: z.uuidv4().describe('User ID'),
name: z.string().describe('User name'),
email: toEmail.describe('User email'),
profileImagePath: z.string().describe('Profile image path'),
profileImagePath: z.string().nullable().describe('Profile image path'),
avatarColor: UserAvatarColorSchema,
// TODO: use `isoDatetimeToDate` when using `ZodSerializerDto` on the controllers.
profileChangedAt: z.string().meta({ format: 'date-time' }).describe('Profile change date'),

View file

@ -123,7 +123,7 @@ type UserEvent = {
deletedAt: Date | null;
status: UserStatus;
email: string;
profileImagePath: string;
profileImagePath: string | null;
isAdmin: boolean;
shouldChangePassword: boolean;
avatarColor: UserAvatarColor | null;

View file

@ -81,7 +81,7 @@ export class UserRepository {
return this.db
.selectFrom('user')
.select(['id', 'profileImagePath'])
.where('profileImagePath', '!=', sql.lit(''))
.where('profileImagePath', 'is not', null)
.limit(sql.lit(3))
.execute();
}

View file

@ -0,0 +1,13 @@
import { Kysely, sql } from 'kysely';
export async function up(db: Kysely<any>): Promise<void> {
await sql`ALTER TABLE "user" ALTER COLUMN "profileImagePath" DROP NOT NULL;`.execute(db);
await sql`ALTER TABLE "user" ALTER COLUMN "profileImagePath" SET DEFAULT NULL;`.execute(db);
await sql`UPDATE "user" SET "profileImagePath" = NULL WHERE "profileImagePath" = '';`.execute(db);
}
export async function down(db: Kysely<any>): Promise<void> {
await sql`UPDATE "user" SET "profileImagePath" = '' WHERE "profileImagePath" IS NULL;`.execute(db);
await sql`ALTER TABLE "user" ALTER COLUMN "profileImagePath" SET DEFAULT '';`.execute(db);
await sql`ALTER TABLE "user" ALTER COLUMN "profileImagePath" SET NOT NULL;`.execute(db);
}

View file

@ -40,8 +40,8 @@ export class UserTable {
@CreateDateColumn()
createdAt!: Generated<Timestamp>;
@Column({ default: '' })
profileImagePath!: Generated<string>;
@Column({ nullable: true, default: null })
profileImagePath!: string | null;
@Column({ type: 'boolean', default: false })
isAdmin!: Generated<boolean>;

View file

@ -189,7 +189,9 @@ export class CliService extends BaseService {
}
for (const user of users) {
paths.push(user.profileImagePath);
if (user.profileImagePath) {
paths.push(user.profileImagePath);
}
}
for (const asset of assets) {

View file

@ -134,10 +134,10 @@ export class UserService extends BaseService {
async deleteProfileImage(auth: AuthDto): Promise<void> {
const user = await this.findOrFail(auth.user.id, { withDeleted: false });
if (user.profileImagePath === '') {
if (user.profileImagePath == null) {
throw new BadRequestException("Can't delete a missing profile Image");
}
await this.userRepository.update(auth.user.id, { profileImagePath: '', profileChangedAt: new Date() });
await this.userRepository.update(auth.user.id, { profileImagePath: null, profileChangedAt: new Date() });
await this.jobRepository.queue({ name: JobName.FileDelete, data: { files: [user.profileImagePath] } });
}