From 430ee2df5bfa7809e83b66acddfc20c8db3c8ce5 Mon Sep 17 00:00:00 2001 From: yahia008 Date: Sat, 21 Feb 2026 09:44:21 +0100 Subject: [PATCH 1/7] implemented get user profile --- backend/src/users/dto/creator-profile.dto.ts | 10 +++++ backend/src/users/dto/user-profile.dto.ts | 7 ++++ backend/src/users/entities/creator.entity.ts | 30 ++++++++++++++ backend/src/users/users.controller.ts | 6 +-- backend/src/users/users.service.ts | 41 +++++++++++++++++++- 5 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 backend/src/users/dto/creator-profile.dto.ts create mode 100644 backend/src/users/entities/creator.entity.ts diff --git a/backend/src/users/dto/creator-profile.dto.ts b/backend/src/users/dto/creator-profile.dto.ts new file mode 100644 index 0000000..0975b6a --- /dev/null +++ b/backend/src/users/dto/creator-profile.dto.ts @@ -0,0 +1,10 @@ +export class CreatorProfileDto { + bio: string; + subscription_price: number; + total_subscribers: number; + is_active: boolean; + + constructor(partial: Partial) { + Object.assign(this, partial); + } +} \ No newline at end of file diff --git a/backend/src/users/dto/user-profile.dto.ts b/backend/src/users/dto/user-profile.dto.ts index eee070a..01c1e34 100644 --- a/backend/src/users/dto/user-profile.dto.ts +++ b/backend/src/users/dto/user-profile.dto.ts @@ -1,4 +1,5 @@ import { Exclude, Expose } from 'class-transformer'; +import { CreatorProfileDto } from './creator-profile.dto'; @Exclude() export class UserProfileDto { @@ -17,6 +18,12 @@ export class UserProfileDto { @Expose() is_creator: boolean; + email_notifications: boolean; + push_notifications: boolean; + marketing_emails: boolean; + + creator?: CreatorProfileDto; + @Expose() created_at: Date; } diff --git a/backend/src/users/entities/creator.entity.ts b/backend/src/users/entities/creator.entity.ts new file mode 100644 index 0000000..15b9cd8 --- /dev/null +++ b/backend/src/users/entities/creator.entity.ts @@ -0,0 +1,30 @@ +import { Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm'; +import { User } from './user.entity'; + +@Entity() +export class Creator { + @PrimaryGeneratedColumn('uuid') + id: string; + + @OneToOne(() => User, { onDelete: 'CASCADE' }) + @JoinColumn() + user: User; + + @Column({ type: 'text', nullable: true }) + bio: string; + + @Column({ type: 'decimal', default: 0 }) + subscription_price: number; + + @Column({ type: 'int', default: 0 }) + total_subscribers: number; + + @Column({ type: 'boolean', default: true }) + is_active: boolean; + + @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) + created_at: Date; + + @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP', onUpdate: 'CURRENT_TIMESTAMP' }) + updated_at: Date; +} \ No newline at end of file diff --git a/backend/src/users/users.controller.ts b/backend/src/users/users.controller.ts index 9a7f4cb..70db4f6 100644 --- a/backend/src/users/users.controller.ts +++ b/backend/src/users/users.controller.ts @@ -19,9 +19,9 @@ export class UsersController { constructor(private readonly usersService: UsersService) {} @Get('me') - async getMe(): Promise { - // TODO: Get user ID from auth token/session - const userId = 'temp-user-id'; + async getMe(@Req() req): Promise { + + const userId = req.user.id; const user = await this.usersService.findOne(userId); return plainToInstance(UserProfileDto, user); } diff --git a/backend/src/users/users.service.ts b/backend/src/users/users.service.ts index 983d5a6..cd99309 100644 --- a/backend/src/users/users.service.ts +++ b/backend/src/users/users.service.ts @@ -2,14 +2,18 @@ import { Injectable, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { User } from './entities/user.entity'; -import { UpdateUserDto } from './dto'; +import { UpdateUserDto, UserProfileDto } from './dto'; import { UpdateNotificationsDto } from './dto/update-notifications.dto'; +import { Creator } from './entities/creator.entity'; +import { CreatorProfileDto } from './dto/creator-profile.dto'; @Injectable() export class UsersService { constructor( @InjectRepository(User) private usersRepository: Repository, + @InjectRepository(User) + private creatorRepository: Repository ) {} async findOne(id: string): Promise { @@ -56,4 +60,39 @@ export class UsersService { }, }; } + + async getCurrentUserProfile(userId: string): Promise { + const user = await this.usersRepository.findOne({ where: { id: userId } }); + + if (!user) throw new NotFoundException('User not found'); + + const profile: UserProfileDto = { + id: user.id, + username: user.username, + display_name: user.display_name, + avatar_url:user.avatar_url, + is_creator: user.is_creator, + email_notifications: user.email_notifications, + push_notifications: user.push_notifications, + marketing_emails: user.marketing_emails, + created_at: user.created_at, + }; + + if (user.is_creator) { + const creator = await this.creatorRepository.findOne({ + where: { user: { id: userId } }, + }); + + if (creator) { + profile.creator = { + bio: creator.bio, + subscription_price: creator.subscription_price, + total_subscribers: creator.total_subscribers, + is_active: creator.is_active, + } as CreatorProfileDto; + } + } + + return profile; + } } From bd4acdf451a4e1441bcd5b2c7160290aa2d96099 Mon Sep 17 00:00:00 2001 From: yahia008 Date: Sat, 21 Feb 2026 09:49:53 +0100 Subject: [PATCH 2/7] implemented get user profile --- backend/src/users/users.controller.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/src/users/users.controller.ts b/backend/src/users/users.controller.ts index 70db4f6..0a41ad6 100644 --- a/backend/src/users/users.controller.ts +++ b/backend/src/users/users.controller.ts @@ -22,6 +22,9 @@ export class UsersController { async getMe(@Req() req): Promise { const userId = req.user.id; + if(!userId) { + throw new Error('User ID not found in request'); + } const user = await this.usersService.findOne(userId); return plainToInstance(UserProfileDto, user); } From e21688b9ca58c6e6fb8917d1dd0071cc9617f2c6 Mon Sep 17 00:00:00 2001 From: yahia008 Date: Sat, 21 Feb 2026 10:04:39 +0100 Subject: [PATCH 3/7] added jwt for proper authentication --- .env.example | 1 + backend/src/users/users.controller.ts | 3 +++ backend/src/users/users.module.ts | 6 ++++- backend/src/utils/auth.guard.ts | 36 +++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 backend/src/utils/auth.guard.ts diff --git a/.env.example b/.env.example index 14378a3..321da72 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ STELLAR_NETWORK=testnet CONTRACT_ADDRESS= BACKEND_URL=http://localhost:3001 +JWT_SECRET=your_jwt_secret_key diff --git a/backend/src/users/users.controller.ts b/backend/src/users/users.controller.ts index 0a41ad6..149e7da 100644 --- a/backend/src/users/users.controller.ts +++ b/backend/src/users/users.controller.ts @@ -7,17 +7,20 @@ import { UseInterceptors, ClassSerializerInterceptor, Req, + UseGuards, } from '@nestjs/common'; import { UsersService } from './users.service'; import { UpdateUserDto, UserProfileDto } from './dto'; import { plainToInstance } from 'class-transformer'; import { UpdateNotificationsDto } from './dto/update-notifications.dto'; +import { AuthGuard } from 'src/utils/auth.guard'; @Controller('users') @UseInterceptors(ClassSerializerInterceptor) export class UsersController { constructor(private readonly usersService: UsersService) {} + @UseGuards(AuthGuard) @Get('me') async getMe(@Req() req): Promise { diff --git a/backend/src/users/users.module.ts b/backend/src/users/users.module.ts index b6c45ef..e87d624 100644 --- a/backend/src/users/users.module.ts +++ b/backend/src/users/users.module.ts @@ -3,9 +3,13 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { UsersController } from './users.controller'; import { UsersService } from './users.service'; import { User } from './entities/user.entity'; +import { JwtModule } from '@nestjs/jwt'; @Module({ - imports: [TypeOrmModule.forFeature([User])], + imports: [TypeOrmModule.forFeature([User]), JwtModule.register({ + secret: process.env.JWT_SECRET || 'default_secret_key', + signOptions: { expiresIn: '1h' }, + })], controllers: [UsersController], providers: [UsersService], exports: [UsersService], diff --git a/backend/src/utils/auth.guard.ts b/backend/src/utils/auth.guard.ts new file mode 100644 index 0000000..c5cb295 --- /dev/null +++ b/backend/src/utils/auth.guard.ts @@ -0,0 +1,36 @@ + +import { + CanActivate, + ExecutionContext, + Injectable, + UnauthorizedException, +} from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import { Request } from 'express'; + +@Injectable() +export class AuthGuard implements CanActivate { + constructor(private jwtService: JwtService) {} + + async canActivate(context: ExecutionContext): Promise { + const request = context.switchToHttp().getRequest(); + const token = this.extractTokenFromHeader(request); + if (!token) { + throw new UnauthorizedException(); + } + try { + + const payload = await this.jwtService.verifyAsync(token); + + request['user'] = payload; + } catch { + throw new UnauthorizedException(); + } + return true; + } + + private extractTokenFromHeader(request: Request): string | undefined { + const [type, token] = request.headers.authorization?.split(' ') ?? []; + return type === 'Bearer' ? token : undefined; + } +} From 0cf6dc1c28592314a7dc48b325b56a390e129023 Mon Sep 17 00:00:00 2001 From: yahia008 Date: Sat, 21 Feb 2026 13:14:45 +0100 Subject: [PATCH 4/7] ci/cd issue --- backend/package-lock.json | 133 ++++++++++++++++++++++++++++++++- backend/package.json | 1 + backend/src/app-test.module.ts | 4 +- 3 files changed, 133 insertions(+), 5 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index ce713db..0f5f7e1 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@nestjs/common": "^11.0.1", "@nestjs/core": "^11.0.1", + "@nestjs/jwt": "^11.0.2", "@nestjs/mapped-types": "^2.1.0", "@nestjs/platform-express": "^11.0.1", "@nestjs/typeorm": "^11.0.0", @@ -2377,6 +2378,19 @@ } } }, + "node_modules/@nestjs/jwt": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-11.0.2.tgz", + "integrity": "sha512-rK8aE/3/Ma45gAWfCksAXUNbOoSOUudU0Kn3rT39htPF7wsYXtKfjALKeKKJbFrIWbLjsbqfXX5bIJNvgBugGA==", + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "9.0.10", + "jsonwebtoken": "9.0.3" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0" + } + }, "node_modules/@nestjs/mapped-types": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.1.0.tgz", @@ -2886,6 +2900,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, "node_modules/@types/methods": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", @@ -2893,11 +2917,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "22.19.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.11.tgz", "integrity": "sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==", - "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -4270,6 +4299,12 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -4984,6 +5019,15 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "license": "MIT" }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -7357,6 +7401,49 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -7460,6 +7547,42 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -7474,6 +7597,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -8750,7 +8879,6 @@ "version": "7.7.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -10136,7 +10264,6 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "devOptional": true, "license": "MIT" }, "node_modules/universalify": { diff --git a/backend/package.json b/backend/package.json index da198c1..c434715 100644 --- a/backend/package.json +++ b/backend/package.json @@ -22,6 +22,7 @@ "dependencies": { "@nestjs/common": "^11.0.1", "@nestjs/core": "^11.0.1", + "@nestjs/jwt": "^11.0.2", "@nestjs/mapped-types": "^2.1.0", "@nestjs/platform-express": "^11.0.1", "@nestjs/typeorm": "^11.0.0", diff --git a/backend/src/app-test.module.ts b/backend/src/app-test.module.ts index 1ab9fa5..832b073 100644 --- a/backend/src/app-test.module.ts +++ b/backend/src/app-test.module.ts @@ -1,10 +1,10 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; -import { NotificationModule } from './notification/notification.module'; + @Module({ - imports: [NotificationModule], + imports: [], controllers: [AppController], providers: [AppService], }) From a2028445bd3b5b804e08875a5b6e9ee8e69dd2b5 Mon Sep 17 00:00:00 2001 From: yahia008 Date: Sun, 22 Feb 2026 11:28:03 +0100 Subject: [PATCH 5/7] Fixed. The failure was from jest.spyOn(bcrypt, hash) --- backend/package-lock.json | 38 ------------------- .../src/users-module/users.service.spec.ts | 16 +++++--- 2 files changed, 11 insertions(+), 43 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 224395c..4764ac0 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -3050,14 +3050,12 @@ "@types/node": "*" } }, - "node_modules/@types/luxon": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.7.1.tgz", "integrity": "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==", "license": "MIT" }, - "node_modules/@types/methods": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", @@ -7903,42 +7901,6 @@ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", "license": "MIT" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", - "license": "MIT" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", - "license": "MIT" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", - "license": "MIT" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", - "license": "MIT" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "license": "MIT" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", - "license": "MIT" - }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", diff --git a/backend/src/users-module/users.service.spec.ts b/backend/src/users-module/users.service.spec.ts index e3fdcf1..cc0c807 100644 --- a/backend/src/users-module/users.service.spec.ts +++ b/backend/src/users-module/users.service.spec.ts @@ -4,6 +4,11 @@ import { ConflictException, NotFoundException } from '@nestjs/common'; import { DataSource } from 'typeorm'; import * as bcrypt from 'bcrypt'; +jest.mock('bcrypt', () => ({ + hash: jest.fn(), + compare: jest.fn(), +})); + import { UsersService } from './users.service'; import { User } from './user.entity'; import { CreateUserDto } from './create-user.dto'; @@ -35,6 +40,7 @@ const createQb = (result: User | null = null) => ({ describe('UsersService', () => { let service: UsersService; + const bcryptHashMock = bcrypt.hash as jest.MockedFunction; const mockRepo = { findOne: jest.fn(), @@ -79,7 +85,7 @@ describe('UsersService', () => { it('should create and return a user profile without passwordHash', async () => { mockRepo.createQueryBuilder.mockReturnValue(createQb(null)); - jest.spyOn(bcrypt, 'hash').mockResolvedValue('hashed' as never); + bcryptHashMock.mockResolvedValue('hashed' as never); const result = await service.create(dto); @@ -107,11 +113,11 @@ describe('UsersService', () => { it('should hash password with bcrypt', async () => { mockRepo.createQueryBuilder.mockReturnValue(createQb(null)); - const hashSpy = jest.spyOn(bcrypt, 'hash').mockResolvedValue('hashed' as never); + bcryptHashMock.mockResolvedValue('hashed' as never); await service.create(dto); - expect(hashSpy).toHaveBeenCalledWith(dto.password, 12); + expect(bcryptHashMock).toHaveBeenCalledWith(dto.password, 12); }); }); @@ -178,11 +184,11 @@ describe('UsersService', () => { it('should hash password if provided', async () => { mockRepo.findOne.mockResolvedValue(mockUser()); mockRepo.createQueryBuilder.mockReturnValue(createQb(null)); - const hashSpy = jest.spyOn(bcrypt, 'hash').mockResolvedValue('newhashed' as never); + bcryptHashMock.mockResolvedValue('newhashed' as never); await service.update('uuid-1', { password: 'NewPass123!' }); - expect(hashSpy).toHaveBeenCalledWith('NewPass123!', 12); + expect(bcryptHashMock).toHaveBeenCalledWith('NewPass123!', 12); }); it('should throw 404 when user not found', async () => { From ab1cc8181a04b5517cfd771c8d77d045875fb39d Mon Sep 17 00:00:00 2001 From: yahia008 Date: Mon, 23 Feb 2026 16:13:17 +0100 Subject: [PATCH 6/7] jst testing --- backend/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/README.md b/backend/README.md index 8f0f65f..2487046 100644 --- a/backend/README.md +++ b/backend/README.md @@ -96,3 +96,4 @@ Nest is an MIT-licensed open source project. It can grow thanks to the sponsors ## License Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE). +########################################################################### \ No newline at end of file From 913c1843748ec236577a537b7c1cbb4575c25141 Mon Sep 17 00:00:00 2001 From: yahia008 Date: Mon, 23 Feb 2026 16:22:35 +0100 Subject: [PATCH 7/7] ci/cd second time --- backend/src/users/users.controller.ts | 2 ++ backend/src/users/users.service.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/backend/src/users/users.controller.ts b/backend/src/users/users.controller.ts index b7b6d9e..149e7da 100644 --- a/backend/src/users/users.controller.ts +++ b/backend/src/users/users.controller.ts @@ -7,11 +7,13 @@ import { UseInterceptors, ClassSerializerInterceptor, Req, + UseGuards, } from '@nestjs/common'; import { UsersService } from './users.service'; import { UpdateUserDto, UserProfileDto } from './dto'; import { plainToInstance } from 'class-transformer'; import { UpdateNotificationsDto } from './dto/update-notifications.dto'; +import { AuthGuard } from 'src/utils/auth.guard'; @Controller('users') @UseInterceptors(ClassSerializerInterceptor) diff --git a/backend/src/users/users.service.ts b/backend/src/users/users.service.ts index f63b96c..5c66c7d 100644 --- a/backend/src/users/users.service.ts +++ b/backend/src/users/users.service.ts @@ -4,6 +4,7 @@ import { Repository } from 'typeorm'; import { User } from './entities/user.entity'; import { UpdateUserDto } from './dto'; import { UpdateNotificationsDto } from './dto/update-notifications.dto'; +import { Creator } from './entities/creator.entity'; @Injectable() export class UsersService {