main
Peace 1 week ago
parent a3f591ab3a
commit 3864eaa965
  1. 2
      backend/dist/app.module.js
  2. 2
      backend/dist/app.module.js.map
  3. 4
      backend/dist/auth/auth.controller.d.ts
  4. 6
      backend/dist/auth/auth.controller.js
  5. 2
      backend/dist/auth/auth.controller.js.map
  6. 7
      backend/dist/common/dto/sucees-response.dto.d.ts
  7. 27
      backend/dist/common/dto/sucees-response.dto.js
  8. 1
      backend/dist/common/dto/sucees-response.dto.js.map
  9. 2
      backend/dist/tsconfig.build.tsbuildinfo
  10. 7
      backend/dist/users/dto/user-info-response.dto.d.ts
  11. 29
      backend/dist/users/dto/user-info-response.dto.js
  12. 2
      backend/dist/users/dto/user-info-response.dto.js.map
  13. 2
      backend/dist/users/user.entity.d.ts
  14. 9
      backend/dist/users/user.entity.js
  15. 2
      backend/dist/users/user.entity.js.map
  16. 3
      backend/dist/users/users.service.d.ts
  17. 14
      backend/dist/users/users.service.js
  18. 2
      backend/dist/users/users.service.js.map
  19. 62
      backend/package-lock.json
  20. 5
      backend/package.json
  21. 2
      backend/src/app.module.ts
  22. 8
      backend/src/auth/auth.controller.ts
  23. 18
      backend/src/profiles/profile.entity.ts
  24. 4
      backend/src/profiles/profiles.module.ts
  25. 0
      backend/src/scripts/api-seed.ts
  26. 19
      backend/src/scripts/data/sample-user.ts
  27. 26
      backend/src/scripts/seed-users.ts
  28. 13
      backend/src/users/dto/user-info-response.dto.ts
  29. 7
      backend/src/users/user.entity.ts
  30. 17
      backend/src/users/users.service.ts

@ -16,6 +16,7 @@ const path_1 = require("path");
const auth_module_1 = require("./auth/auth.module"); const auth_module_1 = require("./auth/auth.module");
const users_module_1 = require("./users/users.module"); const users_module_1 = require("./users/users.module");
const jwt_1 = require("@nestjs/jwt"); const jwt_1 = require("@nestjs/jwt");
const profiles_module_1 = require("./profiles/profiles.module");
let AppModule = class AppModule { let AppModule = class AppModule {
}; };
exports.AppModule = AppModule; exports.AppModule = AppModule;
@ -41,6 +42,7 @@ exports.AppModule = AppModule = __decorate([
}), }),
auth_module_1.AuthModule, auth_module_1.AuthModule,
users_module_1.UsersModule, users_module_1.UsersModule,
profiles_module_1.ProfilesModule,
], ],
controllers: [app_controller_1.AppController], controllers: [app_controller_1.AppController],
providers: [app_service_1.AppService, jwt_1.JwtService], providers: [app_service_1.AppService, jwt_1.JwtService],

@ -1 +1 @@
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,qDAAiD;AACjD,+CAA2C;AAC3C,2CAA6D;AAC7D,6CAAgD;AAChD,+BAA4B;AAC5B,oDAAgD;AAChD,uDAAmD;AACnD,qCAAyC;AA2BlC,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IAzBrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,qBAAY,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACxC,uBAAa,CAAC,YAAY,CAAC;gBACzB,OAAO,EAAE,CAAC,qBAAY,CAAC;gBACvB,MAAM,EAAE,CAAC,sBAAa,CAAC;gBACvB,UAAU,EAAE,CAAC,MAAqB,EAAE,EAAE,CAAC,CAAC;oBACtC,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,MAAM,CAAC,GAAG,CAAS,SAAS,CAAC;oBACnC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAS,SAAS,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;oBACzD,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAS,aAAa,CAAC;oBAC3C,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAS,aAAa,CAAC;oBAC3C,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAS,aAAa,CAAC;oBAC3C,QAAQ,EAAE,CAAC,IAAA,WAAI,EAAC,SAAS,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAC;oBACrD,WAAW,EAAE,MAAM,CAAC,GAAG,CAAS,UAAU,CAAC,KAAK,YAAY;oBAC5D,gBAAgB,EAAE,IAAI;oBACtB,OAAO,EAAE,IAAI;iBACd,CAAC;aACH,CAAC;YACF,wBAAU;YACV,0BAAW;SACZ;QACD,WAAW,EAAE,CAAC,8BAAa,CAAC;QAC5B,SAAS,EAAE,CAAC,wBAAU,EAAE,gBAAU,CAAC;KACpC,CAAC;GACW,SAAS,CAAG"} {"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,qDAAiD;AACjD,+CAA2C;AAC3C,2CAA6D;AAC7D,6CAAgD;AAChD,+BAA4B;AAC5B,oDAAgD;AAChD,uDAAmD;AACnD,qCAAyC;AACzC,gEAA4D;AA4BrD,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IA1BrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,qBAAY,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACxC,uBAAa,CAAC,YAAY,CAAC;gBACzB,OAAO,EAAE,CAAC,qBAAY,CAAC;gBACvB,MAAM,EAAE,CAAC,sBAAa,CAAC;gBACvB,UAAU,EAAE,CAAC,MAAqB,EAAE,EAAE,CAAC,CAAC;oBACtC,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,MAAM,CAAC,GAAG,CAAS,SAAS,CAAC;oBACnC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAS,SAAS,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;oBACzD,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAS,aAAa,CAAC;oBAC3C,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAS,aAAa,CAAC;oBAC3C,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAS,aAAa,CAAC;oBAC3C,QAAQ,EAAE,CAAC,IAAA,WAAI,EAAC,SAAS,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAC;oBACrD,WAAW,EAAE,MAAM,CAAC,GAAG,CAAS,UAAU,CAAC,KAAK,YAAY;oBAC5D,gBAAgB,EAAE,IAAI;oBACtB,OAAO,EAAE,IAAI;iBACd,CAAC;aACH,CAAC;YACF,wBAAU;YACV,0BAAW;YACX,gCAAc;SACf;QACD,WAAW,EAAE,CAAC,8BAAa,CAAC;QAC5B,SAAS,EAAE,CAAC,wBAAU,EAAE,gBAAU,CAAC;KACpC,CAAC;GACW,SAAS,CAAG"}

@ -3,7 +3,7 @@ import { CreateUserDto } from 'src/users/dto/create-user.dto';
import { LoginUserDto } from 'src/auth/dto/login-user.dto'; import { LoginUserDto } from 'src/auth/dto/login-user.dto';
import { LoginResponseDto } from './dto/login-response.dto'; import { LoginResponseDto } from './dto/login-response.dto';
import { UsersService } from 'src/users/users.service'; import { UsersService } from 'src/users/users.service';
import { UserInfoResponseDto } from 'src/users/dto/user-info-response.dto'; import { UserWithProfileResponseDto } from 'src/users/dto/user-info-response.dto';
import { AuthRequest } from 'src/common/interfaces/auth-request.interface'; import { AuthRequest } from 'src/common/interfaces/auth-request.interface';
import { CreateUserResponse } from 'src/users/dto/create-user-response.dto'; import { CreateUserResponse } from 'src/users/dto/create-user-response.dto';
export declare class AuthController { export declare class AuthController {
@ -12,5 +12,5 @@ export declare class AuthController {
constructor(authService: AuthService, userService: UsersService); constructor(authService: AuthService, userService: UsersService);
signup(dto: CreateUserDto): Promise<CreateUserResponse>; signup(dto: CreateUserDto): Promise<CreateUserResponse>;
login(dto: LoginUserDto): Promise<LoginResponseDto>; login(dto: LoginUserDto): Promise<LoginResponseDto>;
getMe(req: AuthRequest): Promise<UserInfoResponseDto>; getMe(req: AuthRequest): Promise<UserWithProfileResponseDto>;
} }

@ -42,7 +42,7 @@ let AuthController = class AuthController {
return await this.authService.login(dto); return await this.authService.login(dto);
} }
async getMe(req) { async getMe(req) {
return await this.userService.findUserInfoByIdOrFail(req.user.userId); return await this.userService.findUserWithProfileByIdOrFail(req.user.userId);
} }
}; };
exports.AuthController = AuthController; exports.AuthController = AuthController;
@ -70,8 +70,8 @@ __decorate([
(0, common_1.Get)('me'), (0, common_1.Get)('me'),
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard), (0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
(0, swagger_1.ApiBearerAuth)(), (0, swagger_1.ApiBearerAuth)(),
(0, swagger_1.ApiOkResponse)({ description: '성공', type: user_info_response_dto_1.UserInfoResponseDto }), (0, swagger_1.ApiOkResponse)({ description: '성공', type: user_info_response_dto_1.UserWithProfileResponseDto }),
openapi.ApiResponse({ status: 200, type: require("../users/dto/user-info-response.dto").UserInfoResponseDto }), openapi.ApiResponse({ status: 200, type: require("../users/dto/user-info-response.dto").UserWithProfileResponseDto }),
__param(0, (0, common_1.Request)()), __param(0, (0, common_1.Request)()),
__metadata("design:type", Function), __metadata("design:type", Function),
__metadata("design:paramtypes", [Object]), __metadata("design:paramtypes", [Object]),

@ -1 +1 @@
{"version":3,"file":"auth.controller.js","sourceRoot":"","sources":["../../src/auth/auth.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAiF;AACjF,iDAA6C;AAC7C,kEAA8D;AAC9D,yDAA2D;AAC3D,iEAA4D;AAC5D,0DAAuD;AACvD,qDAAgD;AAChD,gFAA2E;AAE3E,6CAAsF;AACtF,oFAA4E;AAIrE,IAAM,cAAc,GAApB,MAAM,cAAc;IAEN;IACT;IAFV,YACmB,WAAwB,EACjC,WAAyB;QADhB,gBAAW,GAAX,WAAW,CAAa;QACjC,gBAAW,GAAX,WAAW,CAAc;IAChC,CAAC;IAKE,AAAN,KAAK,CAAC,MAAM,CAAS,GAAkB;QACrC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChD,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC;IACJ,CAAC;IAKK,AAAN,KAAK,CAAC,KAAK,CAAS,GAAiB;QACnC,OAAO,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IAMK,AAAN,KAAK,CAAC,KAAK,CAAY,GAAgB;QACrC,OAAO,MAAM,IAAI,CAAC,WAAW,CAAC,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxE,CAAC;CACF,CAAA;AA/BY,wCAAc;AASnB;IAHL,IAAA,aAAI,EAAC,QAAQ,CAAC;IACd,IAAA,sBAAY,EAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IACjC,IAAA,uBAAa,EAAC,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,6CAAkB,EAAE,CAAC;;IACjD,WAAA,IAAA,aAAI,GAAE,CAAA;;qCAAM,+BAAa;;4CAMtC;AAKK;IAHL,IAAA,aAAI,EAAC,OAAO,CAAC;IACb,IAAA,sBAAY,EAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAChC,IAAA,uBAAa,EAAC,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,qCAAgB,EAAE,CAAC;;IAChD,WAAA,IAAA,aAAI,GAAE,CAAA;;qCAAM,6BAAY;;2CAEpC;AAMK;IAJL,IAAA,YAAG,EAAC,IAAI,CAAC;IACT,IAAA,kBAAS,EAAC,6BAAY,CAAC;IACvB,IAAA,uBAAa,GAAE;IACf,IAAA,uBAAa,EAAC,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,4CAAmB,EAAE,CAAC;;IACnD,WAAA,IAAA,gBAAO,GAAE,CAAA;;;;2CAErB;yBA9BU,cAAc;IAF1B,IAAA,iBAAO,EAAC,IAAI,CAAC;IACb,IAAA,mBAAU,EAAC,MAAM,CAAC;qCAGe,0BAAW;QACpB,4BAAY;GAHxB,cAAc,CA+B1B"} {"version":3,"file":"auth.controller.js","sourceRoot":"","sources":["../../src/auth/auth.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAiF;AACjF,iDAA6C;AAC7C,kEAA8D;AAC9D,yDAA2D;AAC3D,iEAA4D;AAC5D,0DAAuD;AACvD,qDAAgD;AAChD,gFAAkF;AAElF,6CAAsF;AACtF,oFAA4E;AAIrE,IAAM,cAAc,GAApB,MAAM,cAAc;IAEN;IACT;IAFV,YACmB,WAAwB,EACjC,WAAyB;QADhB,gBAAW,GAAX,WAAW,CAAa;QACjC,gBAAW,GAAX,WAAW,CAAc;IAChC,CAAC;IAKE,AAAN,KAAK,CAAC,MAAM,CAAS,GAAkB;QACrC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChD,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC;IACJ,CAAC;IAKK,AAAN,KAAK,CAAC,KAAK,CAAS,GAAiB;QACnC,OAAO,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IAMK,AAAN,KAAK,CAAC,KAAK,CAAY,GAAgB;QACrC,OAAO,MAAM,IAAI,CAAC,WAAW,CAAC,6BAA6B,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/E,CAAC;CACF,CAAA;AA/BY,wCAAc;AASnB;IAHL,IAAA,aAAI,EAAC,QAAQ,CAAC;IACd,IAAA,sBAAY,EAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IACjC,IAAA,uBAAa,EAAC,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,6CAAkB,EAAE,CAAC;;IACjD,WAAA,IAAA,aAAI,GAAE,CAAA;;qCAAM,+BAAa;;4CAMtC;AAKK;IAHL,IAAA,aAAI,EAAC,OAAO,CAAC;IACb,IAAA,sBAAY,EAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAChC,IAAA,uBAAa,EAAC,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,qCAAgB,EAAE,CAAC;;IAChD,WAAA,IAAA,aAAI,GAAE,CAAA;;qCAAM,6BAAY;;2CAEpC;AAMK;IAJL,IAAA,YAAG,EAAC,IAAI,CAAC;IACT,IAAA,kBAAS,EAAC,6BAAY,CAAC;IACvB,IAAA,uBAAa,GAAE;IACf,IAAA,uBAAa,EAAC,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,mDAA0B,EAAE,CAAC;;IAC1D,WAAA,IAAA,gBAAO,GAAE,CAAA;;;;2CAErB;yBA9BU,cAAc;IAF1B,IAAA,iBAAO,EAAC,IAAI,CAAC;IACb,IAAA,mBAAU,EAAC,MAAM,CAAC;qCAGe,0BAAW;QACpB,4BAAY;GAHxB,cAAc,CA+B1B"}

@ -1,7 +0,0 @@
export declare class SuccessResponseDto<T = any> {
success: boolean;
message?: string;
data?: T;
static of<T>(data: T, message?: string): SuccessResponseDto<T>;
static ok(message?: string): SuccessResponseDto<null>;
}

@ -1,27 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SuccessResponseDto = void 0;
const openapi = require("@nestjs/swagger");
class SuccessResponseDto {
success;
message;
data;
static of(data, message) {
return {
success: true,
data,
message,
};
}
static ok(message) {
return {
success: true,
message,
};
}
static _OPENAPI_METADATA_FACTORY() {
return { success: { required: true, type: () => Boolean }, message: { required: false, type: () => String }, data: { required: false } };
}
}
exports.SuccessResponseDto = SuccessResponseDto;
//# sourceMappingURL=sucees-response.dto.js.map

@ -1 +0,0 @@
{"version":3,"file":"sucees-response.dto.js","sourceRoot":"","sources":["../../../src/common/dto/sucees-response.dto.ts"],"names":[],"mappings":";;;;AAAA,MAAa,kBAAkB;IAC7B,OAAO,CAAU;IACjB,OAAO,CAAU;IACjB,IAAI,CAAK;IAET,MAAM,CAAC,EAAE,CAAI,IAAO,EAAE,OAAgB;QACpC,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI;YACJ,OAAO;SACR,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,EAAE,CAAC,OAAgB;QACxB,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO;SACR,CAAC;IACJ,CAAC;;;;CACF;AAnBD,gDAmBC"}

File diff suppressed because one or more lines are too long

@ -3,3 +3,10 @@ export declare class UserInfoResponseDto {
name: string; name: string;
email?: string; email?: string;
} }
export declare class ProfileResponseDto {
bio?: string;
avatarUrl?: string;
}
export declare class UserWithProfileResponseDto extends UserInfoResponseDto {
profile?: ProfileResponseDto;
}

@ -9,7 +9,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.UserInfoResponseDto = void 0; exports.UserWithProfileResponseDto = exports.ProfileResponseDto = exports.UserInfoResponseDto = void 0;
const openapi = require("@nestjs/swagger"); const openapi = require("@nestjs/swagger");
const swagger_1 = require("@nestjs/swagger"); const swagger_1 = require("@nestjs/swagger");
class UserInfoResponseDto { class UserInfoResponseDto {
@ -33,4 +33,31 @@ __decorate([
(0, swagger_1.ApiProperty)({ description: '사용자 이메일', example: 'user@email.com' }), (0, swagger_1.ApiProperty)({ description: '사용자 이메일', example: 'user@email.com' }),
__metadata("design:type", String) __metadata("design:type", String)
], UserInfoResponseDto.prototype, "email", void 0); ], UserInfoResponseDto.prototype, "email", void 0);
class ProfileResponseDto {
bio;
avatarUrl;
static _OPENAPI_METADATA_FACTORY() {
return { bio: { required: false, type: () => String }, avatarUrl: { required: false, type: () => String } };
}
}
exports.ProfileResponseDto = ProfileResponseDto;
__decorate([
(0, swagger_1.ApiProperty)({ description: '프로필 내용', example: 'bio...' }),
__metadata("design:type", String)
], ProfileResponseDto.prototype, "bio", void 0);
__decorate([
(0, swagger_1.ApiProperty)({ description: '프로필 아바타 주소', example: 'http://...' }),
__metadata("design:type", String)
], ProfileResponseDto.prototype, "avatarUrl", void 0);
class UserWithProfileResponseDto extends UserInfoResponseDto {
profile;
static _OPENAPI_METADATA_FACTORY() {
return { profile: { required: false, type: () => require("./user-info-response.dto").ProfileResponseDto } };
}
}
exports.UserWithProfileResponseDto = UserWithProfileResponseDto;
__decorate([
(0, swagger_1.ApiProperty)({ description: '프로필', type: ProfileResponseDto }),
__metadata("design:type", ProfileResponseDto)
], UserWithProfileResponseDto.prototype, "profile", void 0);
//# sourceMappingURL=user-info-response.dto.js.map //# sourceMappingURL=user-info-response.dto.js.map

@ -1 +1 @@
{"version":3,"file":"user-info-response.dto.js","sourceRoot":"","sources":["../../../src/users/dto/user-info-response.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,6CAA8C;AAE9C,MAAa,mBAAmB;IAE9B,EAAE,CAAS;IAGX,IAAI,CAAS;IAGb,KAAK,CAAU;;;;CAChB;AATD,kDASC;AAPC;IADC,IAAA,qBAAW,EAAC,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;+CACzC;AAGX;IADC,IAAA,qBAAW,EAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;;iDAC/C;AAGb;IADC,IAAA,qBAAW,EAAC,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;;kDACpD"} {"version":3,"file":"user-info-response.dto.js","sourceRoot":"","sources":["../../../src/users/dto/user-info-response.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,6CAA8C;AAE9C,MAAa,mBAAmB;IAE9B,EAAE,CAAS;IAGX,IAAI,CAAS;IAGb,KAAK,CAAU;;;;CAChB;AATD,kDASC;AAPC;IADC,IAAA,qBAAW,EAAC,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;+CACzC;AAGX;IADC,IAAA,qBAAW,EAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;;iDAC/C;AAGb;IADC,IAAA,qBAAW,EAAC,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;;kDACpD;AAGjB,MAAa,kBAAkB;IAE7B,GAAG,CAAU;IAGb,SAAS,CAAU;;;;CACpB;AAND,gDAMC;AAJC;IADC,IAAA,qBAAW,EAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;;+CAC7C;AAGb;IADC,IAAA,qBAAW,EAAC,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;;qDAC/C;AAGrB,MAAa,0BAA2B,SAAQ,mBAAmB;IAEjE,OAAO,CAAsB;;;;CAC9B;AAHD,gEAGC;AADC;IADC,IAAA,qBAAW,EAAC,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;8BACpD,kBAAkB;2DAAC"}

@ -1,7 +1,9 @@
import { TimestampedEntity } from 'src/common/entities/timestamped.entity'; import { TimestampedEntity } from 'src/common/entities/timestamped.entity';
import { Profile } from 'src/profiles/profile.entity';
export declare class User extends TimestampedEntity { export declare class User extends TimestampedEntity {
id: number; id: number;
name: string; name: string;
email?: string; email?: string;
password: string; password: string;
profile: Profile;
} }

@ -12,14 +12,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.User = void 0; exports.User = void 0;
const openapi = require("@nestjs/swagger"); const openapi = require("@nestjs/swagger");
const timestamped_entity_1 = require("../common/entities/timestamped.entity"); const timestamped_entity_1 = require("../common/entities/timestamped.entity");
const profile_entity_1 = require("../profiles/profile.entity");
const typeorm_1 = require("typeorm"); const typeorm_1 = require("typeorm");
let User = class User extends timestamped_entity_1.TimestampedEntity { let User = class User extends timestamped_entity_1.TimestampedEntity {
id; id;
name; name;
email; email;
password; password;
profile;
static _OPENAPI_METADATA_FACTORY() { static _OPENAPI_METADATA_FACTORY() {
return { id: { required: true, type: () => Number }, name: { required: true, type: () => String }, email: { required: false, type: () => String }, password: { required: true, type: () => String } }; return { id: { required: true, type: () => Number }, name: { required: true, type: () => String }, email: { required: false, type: () => String }, password: { required: true, type: () => String }, profile: { required: true, type: () => require("../profiles/profile.entity").Profile } };
} }
}; };
exports.User = User; exports.User = User;
@ -39,6 +41,11 @@ __decorate([
(0, typeorm_1.Column)(), (0, typeorm_1.Column)(),
__metadata("design:type", String) __metadata("design:type", String)
], User.prototype, "password", void 0); ], User.prototype, "password", void 0);
__decorate([
(0, typeorm_1.OneToOne)(() => profile_entity_1.Profile, (profile) => profile.user, { cascade: true }),
(0, typeorm_1.JoinColumn)(),
__metadata("design:type", profile_entity_1.Profile)
], User.prototype, "profile", void 0);
exports.User = User = __decorate([ exports.User = User = __decorate([
(0, typeorm_1.Entity)() (0, typeorm_1.Entity)()
], User); ], User);

@ -1 +1 @@
{"version":3,"file":"user.entity.js","sourceRoot":"","sources":["../../src/users/user.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,8EAA2E;AAC3E,qCAAiE;AAG1D,IAAM,IAAI,GAAV,MAAM,IAAK,SAAQ,sCAAiB;IAEzC,EAAE,CAAS;IAGX,IAAI,CAAS;IAGb,KAAK,CAAU;IAGf,QAAQ,CAAS;;;;CAClB,CAAA;AAZY,oBAAI;AAEf;IADC,IAAA,gCAAsB,GAAE;;gCACd;AAGX;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;;kCACZ;AAGb;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;mCAC1B;AAGf;IADC,IAAA,gBAAM,GAAE;;sCACQ;eAXN,IAAI;IADhB,IAAA,gBAAM,GAAE;GACI,IAAI,CAYhB"} {"version":3,"file":"user.entity.js","sourceRoot":"","sources":["../../src/users/user.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,8EAA2E;AAC3E,+DAAsD;AACtD,qCAAuF;AAGhF,IAAM,IAAI,GAAV,MAAM,IAAK,SAAQ,sCAAiB;IAEzC,EAAE,CAAS;IAGX,IAAI,CAAS;IAGb,KAAK,CAAU;IAGf,QAAQ,CAAS;IAIjB,OAAO,CAAU;;;;CAClB,CAAA;AAhBY,oBAAI;AAEf;IADC,IAAA,gCAAsB,GAAE;;gCACd;AAGX;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;;kCACZ;AAGb;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;mCAC1B;AAGf;IADC,IAAA,gBAAM,GAAE;;sCACQ;AAIjB;IAFC,IAAA,kBAAQ,EAAC,GAAG,EAAE,CAAC,wBAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACrE,IAAA,oBAAU,GAAE;8BACJ,wBAAO;qCAAC;eAfN,IAAI;IADhB,IAAA,gBAAM,GAAE;GACI,IAAI,CAgBhB"}

@ -2,7 +2,7 @@ import { User } from './user.entity';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import { CreateUserDto } from './dto/create-user.dto'; import { CreateUserDto } from './dto/create-user.dto';
import { ChangePasswordDto } from './dto/change-password.dto'; import { ChangePasswordDto } from './dto/change-password.dto';
import { UserInfoResponseDto } from './dto/user-info-response.dto'; import { UserInfoResponseDto, UserWithProfileResponseDto } from './dto/user-info-response.dto';
export declare class UsersService { export declare class UsersService {
private repo; private repo;
constructor(repo: Repository<User>); constructor(repo: Repository<User>);
@ -12,4 +12,5 @@ export declare class UsersService {
create(dto: CreateUserDto): Promise<User>; create(dto: CreateUserDto): Promise<User>;
changePassword(userId: number, dto: ChangePasswordDto): Promise<void>; changePassword(userId: number, dto: ChangePasswordDto): Promise<void>;
findUserInfoByIdOrFail(id: number): Promise<UserInfoResponseDto>; findUserInfoByIdOrFail(id: number): Promise<UserInfoResponseDto>;
findUserWithProfileByIdOrFail(id: number): Promise<UserWithProfileResponseDto>;
} }

@ -60,6 +60,20 @@ let UsersService = class UsersService {
email: user.email, email: user.email,
}; };
} }
async findUserWithProfileByIdOrFail(id) {
const user = await this.repo.findOne({ where: { id }, relations: ['profile'] });
if (!user)
throw new common_1.NotFoundException('User not found');
return {
id: user.id,
name: user.name,
email: user.email,
profile: {
bio: user.profile?.bio,
avatarUrl: user.profile?.avatarUrl,
},
};
}
}; };
exports.UsersService = UsersService; exports.UsersService = UsersService;
exports.UsersService = UsersService = __decorate([ exports.UsersService = UsersService = __decorate([

@ -1 +1 @@
{"version":3,"file":"users.service.js","sourceRoot":"","sources":["../../src/users/users.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAKwB;AACxB,6CAAmD;AACnD,+CAAqC;AACrC,qCAAqC;AAGrC,mCAAmC;AAI5B,IAAM,YAAY,GAAlB,MAAM,YAAY;IACqB;IAA5C,YAA4C,IAAsB;QAAtB,SAAI,GAAJ,IAAI,CAAkB;IAAG,CAAC;IAEtE,KAAK,CAAC,QAAQ,CAAC,EAAU;QACvB,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAY;QAC3B,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAa;QAC7B,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAkB;QAC7B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,QAAQ;YAAE,MAAM,IAAI,4BAAmB,CAAC,sBAAsB,CAAC,CAAC;QAEpE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,MAAc,EAAE,GAAsB;QACzD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,0BAAiB,CAAC,gBAAgB,CAAC,CAAC;QAEzD,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/E,IAAI,CAAC,aAAa;YAAE,MAAM,IAAI,8BAAqB,CAAC,sBAAsB,CAAC,CAAC;QAE5E,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC;QAEvB,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,sBAAsB,CAAC,EAAU;QACrC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,0BAAiB,CAAC,gBAAgB,CAAC,CAAC;QAEzD,OAAO;YACL,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC;IACJ,CAAC;CACF,CAAA;AA9CY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;IAEE,WAAA,IAAA,0BAAgB,EAAC,kBAAI,CAAC,CAAA;qCAAe,oBAAU;GADjD,YAAY,CA8CxB"} {"version":3,"file":"users.service.js","sourceRoot":"","sources":["../../src/users/users.service.ts"],"names":[],"mappings":"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"}

@ -9,6 +9,7 @@
"version": "0.0.1", "version": "0.0.1",
"license": "UNLICENSED", "license": "UNLICENSED",
"dependencies": { "dependencies": {
"@faker-js/faker": "^9.9.0",
"@nestjs/common": "^11.0.1", "@nestjs/common": "^11.0.1",
"@nestjs/config": "^4.0.2", "@nestjs/config": "^4.0.2",
"@nestjs/core": "^11.0.1", "@nestjs/core": "^11.0.1",
@ -17,6 +18,7 @@
"@nestjs/platform-express": "^11.0.1", "@nestjs/platform-express": "^11.0.1",
"@nestjs/swagger": "^11.2.0", "@nestjs/swagger": "^11.2.0",
"@nestjs/typeorm": "^11.0.0", "@nestjs/typeorm": "^11.0.0",
"axios": "^1.11.0",
"bcrypt": "^6.0.0", "bcrypt": "^6.0.0",
"bcryptjs": "^3.0.2", "bcryptjs": "^3.0.2",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
@ -923,6 +925,22 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
} }
}, },
"node_modules/@faker-js/faker": {
"version": "9.9.0",
"resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.9.0.tgz",
"integrity": "sha512-OEl393iCOoo/z8bMezRlJu+GlRGlsKbUAN7jKB6LhnKoqKve5DXRpalbItIIcwnCjs1k/FOPjFzcA6Qn+H+YbA==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/fakerjs"
}
],
"license": "MIT",
"engines": {
"node": ">=18.0.0",
"npm": ">=9.0.0"
}
},
"node_modules/@humanfs/core": { "node_modules/@humanfs/core": {
"version": "0.19.1", "version": "0.19.1",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
@ -4945,7 +4963,6 @@
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/available-typed-arrays": { "node_modules/available-typed-arrays": {
@ -4972,6 +4989,17 @@
"node": ">= 6.0.0" "node": ">= 6.0.0"
} }
}, },
"node_modules/axios": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz",
"integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/b4a": { "node_modules/b4a": {
"version": "1.6.7", "version": "1.6.7",
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz",
@ -5878,7 +5906,6 @@
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"delayed-stream": "~1.0.0" "delayed-stream": "~1.0.0"
@ -6239,7 +6266,6 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=0.4.0" "node": ">=0.4.0"
@ -6482,7 +6508,6 @@
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
@ -7215,6 +7240,26 @@
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/follow-redirects": {
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/for-each": { "node_modules/for-each": {
"version": "0.3.5", "version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
@ -7278,7 +7323,6 @@
"version": "4.0.4", "version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
@ -7305,7 +7349,6 @@
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@ -7315,7 +7358,6 @@
"version": "2.1.35", "version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"mime-db": "1.52.0" "mime-db": "1.52.0"
@ -10294,6 +10336,12 @@
"node": ">= 0.10" "node": ">= 0.10"
} }
}, },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
},
"node_modules/punycode": { "node_modules/punycode": {
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",

@ -17,9 +17,11 @@
"test:watch": "jest --watch", "test:watch": "jest --watch",
"test:cov": "jest --coverage", "test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json" "test:e2e": "jest --config ./test/jest-e2e.json",
"seed:users": "ts-node -r tsconfig-paths/register src/scripts/seed-users.ts"
}, },
"dependencies": { "dependencies": {
"@faker-js/faker": "^9.9.0",
"@nestjs/common": "^11.0.1", "@nestjs/common": "^11.0.1",
"@nestjs/config": "^4.0.2", "@nestjs/config": "^4.0.2",
"@nestjs/core": "^11.0.1", "@nestjs/core": "^11.0.1",
@ -28,6 +30,7 @@
"@nestjs/platform-express": "^11.0.1", "@nestjs/platform-express": "^11.0.1",
"@nestjs/swagger": "^11.2.0", "@nestjs/swagger": "^11.2.0",
"@nestjs/typeorm": "^11.0.0", "@nestjs/typeorm": "^11.0.0",
"axios": "^1.11.0",
"bcrypt": "^6.0.0", "bcrypt": "^6.0.0",
"bcryptjs": "^3.0.2", "bcryptjs": "^3.0.2",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",

@ -7,6 +7,7 @@ import { join } from 'path';
import { AuthModule } from './auth/auth.module'; import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module'; import { UsersModule } from './users/users.module';
import { JwtService } from '@nestjs/jwt'; import { JwtService } from '@nestjs/jwt';
import { ProfilesModule } from './profiles/profiles.module';
@Module({ @Module({
imports: [ imports: [
@ -29,6 +30,7 @@ import { JwtService } from '@nestjs/jwt';
}), }),
AuthModule, AuthModule,
UsersModule, UsersModule,
ProfilesModule,
], ],
controllers: [AppController], controllers: [AppController],
providers: [AppService, JwtService], providers: [AppService, JwtService],

@ -5,7 +5,7 @@ import { LoginUserDto } from 'src/auth/dto/login-user.dto';
import { LoginResponseDto } from './dto/login-response.dto'; import { LoginResponseDto } from './dto/login-response.dto';
import { UsersService } from 'src/users/users.service'; import { UsersService } from 'src/users/users.service';
import { JwtAuthGuard } from './jwt-auth.guard'; import { JwtAuthGuard } from './jwt-auth.guard';
import { UserInfoResponseDto } from 'src/users/dto/user-info-response.dto'; import { UserWithProfileResponseDto } from 'src/users/dto/user-info-response.dto';
import { AuthRequest } from 'src/common/interfaces/auth-request.interface'; import { AuthRequest } from 'src/common/interfaces/auth-request.interface';
import { ApiBearerAuth, ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiBearerAuth, ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
import { CreateUserResponse } from 'src/users/dto/create-user-response.dto'; import { CreateUserResponse } from 'src/users/dto/create-user-response.dto';
@ -39,8 +39,8 @@ export class AuthController {
@Get('me') @Get('me')
@UseGuards(JwtAuthGuard) @UseGuards(JwtAuthGuard)
@ApiBearerAuth() @ApiBearerAuth()
@ApiOkResponse({ description: '성공', type: UserInfoResponseDto }) @ApiOkResponse({ description: '성공', type: UserWithProfileResponseDto })
async getMe(@Request() req: AuthRequest): Promise<UserInfoResponseDto> { async getMe(@Request() req: AuthRequest): Promise<UserWithProfileResponseDto> {
return await this.userService.findUserInfoByIdOrFail(req.user.userId); return await this.userService.findUserWithProfileByIdOrFail(req.user.userId);
} }
} }

@ -0,0 +1,18 @@
import { TimestampedEntity } from 'src/common/entities/timestamped.entity';
import { User } from 'src/users/user.entity';
import { Column, Entity, OneToOne, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Profile extends TimestampedEntity {
@PrimaryGeneratedColumn()
id: number;
@Column({ nullable: true })
bio?: string;
@Column({ nullable: true })
avatarUrl?: string;
@OneToOne(() => User, (user) => user.profile)
user: User;
}

@ -0,0 +1,4 @@
import { Module } from '@nestjs/common';
@Module({})
export class ProfilesModule {}

@ -0,0 +1,19 @@
import { CreateUserDto } from 'src/users/dto/create-user.dto';
export const testUsers: CreateUserDto[] = [
{
name: 'testuser1',
email: 'testuser1@email.com',
password: 'password123',
},
{
name: 'testuser2',
email: 'testuser2@email.com',
password: 'password456',
},
{
name: 'testuser3',
email: 'testuser3@email.com',
password: 'password789',
},
];

@ -0,0 +1,26 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from 'src/app.module';
import { AuthService } from 'src/auth/auth.service';
import { testUsers } from './data/sample-user';
async function bootstrap() {
const app = await NestFactory.createApplicationContext(AppModule);
const authService = app.get(AuthService);
for (const user of testUsers) {
try {
await authService.signup(user);
console.log(`✅ Create user: ${user.name}`);
} catch (err: unknown) {
if (err instanceof Error) {
console.error(`❌ Fail to create user: ${user.name}`, err.message);
} else {
console.error(`❌ Fail to create user: ${user.name}`, err);
}
}
}
await app.close();
}
bootstrap();

@ -10,3 +10,16 @@ export class UserInfoResponseDto {
@ApiProperty({ description: '사용자 이메일', example: 'user@email.com' }) @ApiProperty({ description: '사용자 이메일', example: 'user@email.com' })
email?: string; email?: string;
} }
export class ProfileResponseDto {
@ApiProperty({ description: '프로필 내용', example: 'bio...' })
bio?: string;
@ApiProperty({ description: '프로필 아바타 주소', example: 'http://...' })
avatarUrl?: string;
}
export class UserWithProfileResponseDto extends UserInfoResponseDto {
@ApiProperty({ description: '프로필', type: ProfileResponseDto })
profile?: ProfileResponseDto;
}

@ -1,5 +1,6 @@
import { TimestampedEntity } from 'src/common/entities/timestamped.entity'; import { TimestampedEntity } from 'src/common/entities/timestamped.entity';
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; import { Profile } from 'src/profiles/profile.entity';
import { Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from 'typeorm';
@Entity() @Entity()
export class User extends TimestampedEntity { export class User extends TimestampedEntity {
@ -14,4 +15,8 @@ export class User extends TimestampedEntity {
@Column() @Column()
password: string; password: string;
@OneToOne(() => Profile, (profile) => profile.user, { cascade: true })
@JoinColumn() // FK Owner
profile: Profile;
} }

@ -10,7 +10,7 @@ import { Repository } from 'typeorm';
import { CreateUserDto } from './dto/create-user.dto'; import { CreateUserDto } from './dto/create-user.dto';
import { ChangePasswordDto } from './dto/change-password.dto'; import { ChangePasswordDto } from './dto/change-password.dto';
import * as bcrypt from 'bcryptjs'; import * as bcrypt from 'bcryptjs';
import { UserInfoResponseDto } from './dto/user-info-response.dto'; import { UserInfoResponseDto, UserWithProfileResponseDto } from './dto/user-info-response.dto';
@Injectable() @Injectable()
export class UsersService { export class UsersService {
@ -59,4 +59,19 @@ export class UsersService {
email: user.email, email: user.email,
}; };
} }
async findUserWithProfileByIdOrFail(id: number): Promise<UserWithProfileResponseDto> {
const user = await this.repo.findOne({ where: { id }, relations: ['profile'] });
if (!user) throw new NotFoundException('User not found');
return {
id: user.id,
name: user.name,
email: user.email,
profile: {
bio: user.profile?.bio,
avatarUrl: user.profile?.avatarUrl,
},
};
}
} }

Loading…
Cancel
Save