I'm getting: TypeError: Cannot read property 'list' of undefined (my custom repository BeneficiosRepository)
The problem is for the same instance of this service (BeneficiosService), the create and update function works, but pageAll, findOne and delete do not.
I can't understand the reason
I did a test forcing the create function to call the pageAll and it worked.
My Module:
#Module({
imports: [TypeOrmModule.forFeature([Beneficio,]), forwardRef(() => UsersModule)],
controllers: [BeneficiosController],
providers: [BeneficiosService, BeneficiosRepository, IsUniqueNomeConstraint],
exports: [BeneficiosService, BeneficiosRepository],
})
export class BeneficiosModule { }
My Service:
#Injectable({ scope: Scope.REQUEST })
export class BeneficiosService {
constructor(
#Inject(REQUEST)
private readonly request: Request,
private beneficiosRepository: BeneficiosRepository,
#Inject(forwardRef(() => UsersService))
private readonly usersService: UsersService,
) {
}
#UseInterceptors(ClassSerializerInterceptor)
async pageAll(pageOptionsDto: PageOptionsDto, filterDto: FilterBeneficioDto) {
const [beneficios, total] = await this.beneficiosRepository.list(pageOptionsDto, filterDto);
const pageMetaDto = new PageMetaDto({ itemCount: total, pageOptionsDto });
return new PageDto(beneficios, pageMetaDto);
}
#UseInterceptors(ClassSerializerInterceptor)
async create(dto: CreateBeneficioDto) {
const validatedDto = this.validationDesconto(dto);
const user_id = getUserIdService(this.request);
const user = await this.usersService.findOne(user_id);
const beneficio = this.beneficiosRepository.create(validatedDto);
beneficio.user_registrou = user;
const createdBeneficio = await this.beneficiosRepository.save(beneficio);
return plainToClass(Beneficio, createdBeneficio);
}
#UseInterceptors(ClassSerializerInterceptor)
async findOne(id: string) {
const beneficioExists = await this.checkIfBeneficioExists(id);
return instanceToPlain(beneficioExists, { groups: ['find'] }) as Beneficio;
}
#UseInterceptors(ClassSerializerInterceptor)
async update(id: string, dto: UpdateBeneficioDto) {
const validatedDto = this.validationDesconto(dto);
await this.checkIfBeneficioExists(id);
const updatedBeneficio = await this.beneficiosRepository.save(validatedDto);
return plainToClass(Beneficio, updatedBeneficio);
}
#UseInterceptors(ClassSerializerInterceptor)
async remove(id: string) {
await this.checkIfBeneficioExists(id);
await this.beneficiosRepository.softDelete({ id });
}
async findByIds(ids: string[]) {
return await this.beneficiosRepository.findBy({ id: In(ids) });
}
private async checkIfBeneficioExists(id: string): Promise<Beneficio> {
const beneficioExists = await this.beneficiosRepository.findById(id);
if (!beneficioExists) {
throw new AppError(`Benefício ${id} não encontrado!`, 404);
}
return beneficioExists;
}
private validationDesconto(beneficio: Beneficio | UpdateBeneficioDto | CreateBeneficioDto): Beneficio | UpdateBeneficioDto | CreateBeneficioDto {
const { is_descontado, tipo_desconto, valor_desconto } = beneficio;
if (!is_descontado) {
delete beneficio.tipo_desconto;
delete beneficio.valor_desconto;
return beneficio;
}
if (tipo_desconto && valor_desconto && valor_desconto.valueOf()) {
return beneficio;
}
throw new AppError(`Se o benefício é descontado, os campos "tipo_desconto" e "valor_desconto" devem obrigatóriamente serem preenchidos!`);
}
}
My Controller:
#ApiBearerAuth()
#ApiTags('beneficios')
#Controller('beneficios')
export class BeneficiosController {
constructor(private readonly beneficiosService: BeneficiosService) { }
#Post()
#ApiOperation({ summary: 'Cria um novo benefício' })
#ApiResponse({ status: 200, isArray: false, type: Beneficio })
#ApiResponse({ status: 403, description: 'Proibido.' })
async create(#Body() dto: CreateBeneficioDto) {
return await this.beneficiosService.create(dto);
}
#Get()
#ApiOperation({ summary: 'Lista todos os benefícios ativos' })
#ApiResponse({ status: 200, isArray: true, type: Beneficio })
#ApiResponse({ status: 403, description: 'Proibido.' })
async pageAll(#Query() dto: PageOptionsDto, #Query() filter: FilterBeneficioDto) {
return await this.beneficiosService.pageAll(dto, filter);
}
#Get(':id')
#ApiOperation({ summary: 'Recupera um benefício com base no ID passado' })
#ApiResponse({ status: 200, isArray: false, type: Beneficio })
#ApiResponse({ status: 403, description: 'Proibido.' })
findOne(#Param('id') id: string) {
return this.beneficiosService.findOne(id);
}
#Put(':id')
#ApiOperation({ summary: 'Atualiza um benefício' })
#ApiResponse({ status: 200, isArray: false, type: Beneficio })
#ApiResponse({ status: 403, description: 'Proibido.' })
update(#Param('id',) id: string, #Body() dto: UpdateBeneficioDto) {
return this.beneficiosService.update(id, dto);
}
#Delete(':id')
#ApiOperation({ summary: 'Deleta um benefício' })
#ApiResponse({ status: 204, })
#ApiResponse({ status: 403, description: 'Proibido.' })
remove(#Param('id') id: string) {
return this.beneficiosService.remove(id);
}
}
My Repo:
#Injectable()
export class BeneficiosRepository extends Repository<Beneficio> implements IBeneficiosRepository {
constructor(private dataSource: DataSource) {
super(Beneficio, dataSource.createEntityManager());
}
async findById(id: string): Promise<Beneficio> {
const beneficio = await this
.createQueryBuilder("beneficio")
.leftJoinAndSelect("beneficio.user_registrou", "users")
.where("beneficio.id = :id", { id })
.getOne();
return beneficio;
}
async findByNome(nome: string): Promise<Beneficio> {
const beneficio = await this
.createQueryBuilder("beneficio")
.leftJoinAndSelect("beneficio.user_registrou", "users")
.where("beneficio.nome ILIKE :nome", { nome })
.getOne();
return beneficio;
}
async list({ skip, take, order }: PageOptionsDto,
{ tipo_desconto, is_descontado, descricao, nome }: FilterBeneficioDto): Promise<[Beneficio[], number]> {
const query = this
.createQueryBuilder("beneficio")
.orderBy("beneficio.created_at", order)
.skip(skip)
.take(take)
.where("1=1");
if (nome) {
query.andWhere("beneficio.nome ILIKE :nome", { nome: '%${nome}%'});
}
if (descricao) {
query.andWhere("beneficio.descricao ILIKE :descricao", { descricao: '%${descricao}%' });
}
if (is_descontado && is_descontado === 'true' || is_descontado === 'false') {
query.andWhere("beneficio.is_descontado = :is_descontado", { is_descontado });
}
if (tipo_desconto) {
query.andWhere("beneficio.tipo_desconto = :tipo_desconto", { tipo_desconto });
}
const beneficios = await query.getManyAndCount();
return beneficios;
}
}
Resource http://localhost:3000/beneficios - Method POST = Work
Print success
Resource http://localhost:3000/beneficios - Method GET = Repository is undefined
Print error
Testing via Insomnia
Work:
#UseInterceptors(ClassSerializerInterceptor)
async create(dto: CreateBeneficioDto) {
return await this.pageAll({skip: 0}, {});
}
Undefined Error:
#UseInterceptors(ClassSerializerInterceptor)
async pageAll(pageOptionsDto: PageOptionsDto, filterDto: FilterBeneficioDto) {
const [beneficios, total] = await this.beneficiosRepository.list(pageOptionsDto, filterDto);
const pageMetaDto = new PageMetaDto({ itemCount: total, pageOptionsDto });
return new PageDto(beneficios, pageMetaDto);
}
Related
I am using Node with websocket and I have this function:
const validatedCep = async () => {
const data = await axios
.get(`https://viacep.com.br/ws/${message}/json/`)
.then((res) => {
return res.data;
})
.catch((err) => {
return err.response;
});
console.log(1, data);
return data;
};
if (this.props.dataType === "CEP") {
validatedCep();
}
How can I get the value returned in response and access that value outside the validatedCep function?
I need this value to be able to check if it will return the value of the answer or an error, so that I can proceed with the logic of the function.
Full function:
import { MessageSender } from "./message-sender";
import { WappMessage } from "./wapp-message";
import axios from "axios";
export type FormProps = {
error?: string;
text: string;
dataType: string;
typingDuration: number;
};
export class WappFormMessage extends WappMessage<FormProps> {
constructor(
readonly props: FormProps,
private next: WappMessage<any> | undefined,
protected messageSender: MessageSender<FormProps>
) {
super(props, "response", true, messageSender);
}
getNext(message: string): WappMessage<any> | undefined {
const regexs = [
{ type: "email", regex: "^[a-z0-9]+#[a-z0-9]+\\.[a-z]+\\.?([a-z]+)?$" },
{ type: "CPF", regex: "^\\d{3}\\.?\\d{3}\\.?\\d{3}\\-?\\d{2}$" },
{ type: "CNPJ", regex: "^d{2}.?d{3}.?d{3}/?d{4}-?d{2}$" },
{
type: "cellPhone",
regex: "(^\\(?\\d{2}\\)?\\s?)(\\d{4,5}\\-?\\d{4}$)",
},
{ type: "phone", regex: "(^\\(?\\d{2}\\)?\\s?)(\\d{4}\\-?\\d{4}$)" },
{ type: "birthDate", regex: "(^\\d{2})\\/(\\d{2})\\/(\\d{4}$)" },
];
const dataTypes = [
"email",
"birthDate",
"CPF",
"CNPJ",
"cellPhone",
"phone",
];
const validateData = (element: string) => {
if (this.props.dataType === element) {
const getRegex = regexs.find((regexs) => regexs.type === element);
const regexCreate = new RegExp(getRegex!.regex, "i");
const validate = regexCreate.test(message);
return validate;
}
return true;
};
const isValid = dataTypes.find(validateData);
if (!isValid) {
return new WappFormMessage(
{
error: "Invalid data!",
...this.props,
},
this.next,
this.messageSender
);
}
const validatedCep = async () => {
const data = await axios
.get(`https://viacep.com.br/ws/${message}/json/`)
.then((res) => {
return res.data;
})
.catch((err) => {
return err.response;
});
console.log(1, data);
return data;
};
if (this.props.dataType === "CEP") {
validatedCep();
}
return this.next;
}
async send(remoteJid: string): Promise<void> {
await this.messageSender.send(
remoteJid,
this.props,
this.props.typingDuration
);
}
}
I'm coding on NestJS and I'm trying to call my database info by enumeration.
Example: I want all of motherboard (motherboard is an enum). I'm having many options for this.
I would like your opinion and for you, what is the best option?
This is my Entity :
#Entity('component')
export class Component {
static idComponent(idComponent: any): Component[] | PromiseLike<Component[]> {
throw new Error('Method not implemented.');
}
#PrimaryGeneratedColumn()
idComponent: number;
#Column()
name: string;
#Column()
brand: string;
#Column()
availability: string;
#Column()
price: string;
#Column('enum', { enum: ComponentType })
type: ComponentType;
service_type: ComponentType;
#Column('datetime', { default: () => 'CURRENT_TIMESTAMP' })
date: string;
#ApiProperty({ enum: () => Configurateur })
#OneToMany(() => Configurateur, configurateur => configurateur.component)
ComponentType: Configurateur[];
}
My Controller :
#ApiTags('component')
#Controller('component')
export class ComponentController {
constructor(private componentService: ComponentService) { }
#Get('all')
async findAll(#Res() res) {
const lists = await this.componentService.findAll();
return res.status(HttpStatus.OK).json(lists);
}
#Get('id')
async findById(#Res() res, #Query('id') id: string) {
const lists = await this.componentService.findById(id);
if (!lists) throw new NotFoundException('Id does not exist!');
return res.status(HttpStatus.OK).json(lists);
}
#Get('type')
async findByType(#Res() res, #Query('type') ComponentType: string) {
const listsType = await this.componentService.findByType(ComponentType);
if (!listsType) throw new NotFoundException('Id does not exist!');
return res.status(HttpStatus.OK).json(listsType);
}
}
And my Service :
#Injectable()
export class ComponentService {
constructor(
#InjectRepository(Component)
private readonly componentRepository: Repository<Component>,
) { }
async findAll(): Promise<Component[]> {
return await this.componentRepository.find();
}
async findById(id): Promise<Component[]> {
const customer = await this.componentRepository.findByIds(id);
return customer;
}
async findByType(ComponentType): Promise<any> {
const customerType = await this.componentRepository.find(ComponentType);
return customerType;
}
// Have Error and is a test
getType(ByType): Promise<any> {
let Type = String(ByType);
return new Promise(resolve => {
const type = this.componentRepository.find(type => type.Type === Type);
if (!type) {
throw new HttpException('Course does not exist', 404)
}
resolve(Type)
});
}
}
Edit : CompentType is my Enums file.
Thank you for your time.
Im trying to generate rest-api for Odoo - ERP whith Nestjs and odoo-xmlrpc. I can connect to odoo but i cant respose the values than odoo response to my service.
This is the odoo service that response a value or an error:
import { Injectable, OnModuleInit } from '#nestjs/common';
#Injectable()
export class OdooService {
private Odoo = require('odoo-xmlrpc');
public odoo;
constructor () {
this.odoo = new this.Odoo({
url: 'https:/www.xxxxxxxxx.xxx',
db: 'xxxx',
username: 'username',
password: 'password'
});
}
execute(model: string, funtion: string , params: any[], callback) {
const odoo = new this.Odoo({
url: 'https:/www.xxxxxxxxx.xxx',
db: 'xxxx',
username: 'username',
password: 'password'
});
odoo.connect(async function (error: any): Promise<any> {
if (error) {
console.log(error);
return [{}];
}
odoo.execute_kw(model, funtion, params, function (error: any, values: []) {
if (error) {
console.log('error :>> ', error);
return [{}];
}
callback(values);
})
})
}
}
this is the service that use the odooServive
import { Injectable } from '#nestjs/common';
import { OdooService } from '../odoo/odoo.service';
import { CreateCountryDto } from './dto/create-country.dto';
import { UpdateCountryDto } from './dto/update-country.dto';
#Injectable()
export class CountriesService {
constructor(
private odooService: OdooService
) {}
async findAll() {
return await this.odooService.execute('res.country', 'search_read', [[[]], { fields: ['name'] }], async function (response: []) {
// console.log(response);
return await response;
});
}
}
odoo documentation: https://www.odoo.com/documentation/14.0/webservices/odoo.html
library documentation: https://www.npmjs.com/package/odoo-xmlrpc
Elaborating #charlietfl's comment into an answer, you can use one of these codes, either using callback, or using async await
No Promise, no callback
findAll() {
return this.odooService.execute('res.country', 'search_read', [[[]], { fields: ['name'] }]);
}
Using callback, no need for Promise
findAll() {
this.odooService.execute('res.country', 'search_read', [[[]], { fields: ['name'] }], function (response: []) {
return response;
});
}
Using Promise
async findAll() {
const response = await this.odooService.execute('res.country', 'search_read', [[[]], { fields: ['name'] }]);
return response;
}
I am getting an error everytime I submit my post without an image, submission of the image is optional because I run an if condition before appending the imagePath. working on a MEAN stack up to which I am new in.
mime-type-validator
import { AbstractControl } from "#angular/forms";
import { Observable, Observer, of } from "rxjs";
export const mimeType = (
control: AbstractControl
): Promise<{ [key: string]: any }> | Observable<{ [key: string]: any }> => {
if (typeof(control.value) === 'string') {
return of(null);
}
const file = control.value as File;
const fileReader = new FileReader();
const frObs = Observable.create(
(observer: Observer<{ [key: string]: any }>) => {
fileReader.addEventListener("loadend", () => {
const arr = new Uint8Array(fileReader.result as ArrayBuffer).subarray(0, 4);
let header = "";
let isValid = false;
for (let i = 0; i < arr.length; i++) {
header += arr[i].toString(16);
}
switch (header) {
case "89504e47":
isValid = true;
break;
case "ffd8ffe0":
case "ffd8ffe1":
case "ffd8ffe2":
case "ffd8ffe3":
case "ffd8ffe8":
isValid = true;
break;
default:
isValid = false; // Or you can use the blob.type as fallback
break;
}
if (isValid) {
observer.next(null);
} else {
observer.next({ invalidMimeType: true });
}
observer.complete();
});
fileReader.readAsArrayBuffer(file);
}
);
return frObs;
};
create-post-component
import { Component, Inject, Input, OnInit} from '#angular/core';
import { ActivatedRoute, ParamMap } from '#angular/router';
import { FormControl, FormGroup, Validators } from '#angular/forms'
import { PostModel } from 'src/app/Models/post.model';
import { PostsService } from 'src/app/Services/posts.service';
import { Router } from '#angular/router'
import { mimeType } from 'src/app/auth/Validators/mime-type.validator'
import Swal from 'sweetalert2';
#Component({
selector: 'app-create-post',
templateUrl: './create-post.component.html',
styleUrls: ['./create-post.component.css']
})
export class CreatePostComponent {
public mode = 'user';
private postId : string;
public post: PostModel;
isLoading : boolean = false;
imagePreview: string;
PostForm = new FormGroup({
title: new FormControl('', [Validators.required, Validators.minLength(1), Validators.maxLength(30)]),
content: new FormControl('', [Validators.required, Validators.minLength(1)]),
image: new FormControl(null, {validators:[], asyncValidators: [mimeType] })
})
constructor(public postsService: PostsService, public route: ActivatedRoute, private router: Router){
}
ngOnInit(){
this.route.paramMap.subscribe((paramMap: ParamMap)=>{
if(paramMap.has('postId')){
this.mode = 'edit';
this.postId = paramMap.get('postId');
this.isLoading = true;
this.postsService.getPost(this.postId).subscribe(postdata =>{
this.isLoading = false;
this.post = {id: postdata._id, title: postdata.title, content: postdata.content , imagePath: postdata.imagePath};
this.PostForm.setValue({ title: this.post.title, content: this.post.content, image: this.post.imagePath });
});
}
else{
this.mode = 'user';
this.postId = null;
}
})
}
onAddPost()
{
if(this.PostForm.invalid){
return;
}
this.isLoading = true;
if (this.mode === 'user'){
this.postsService.addPosts(this.PostForm.value.title, this.PostForm.value.content, this.PostForm.value.image)
this.isLoading = false;
Swal.fire({
position: 'center',
icon: 'success',
title: 'Post added!',
showConfirmButton: false,
timer: 2000
})
}
else{
this.postsService.updatePosts(
this.postId,
this.PostForm.value.title,
this.PostForm.value.content,
this.PostForm.value.image
);
this.router.navigateByUrl('/user');
}
this.PostForm.reset();
}
onImagePicked(event: Event){
const file = (event.target as HTMLInputElement).files[0];
this.PostForm.patchValue({image: file});
this.PostForm.get('image').updateValueAndValidity();
const reader = new FileReader();
reader.onload = () => {
this.imagePreview = reader.result as string;
};
reader.readAsDataURL(file);
}
}
posts-service.ts
import { Injectable } from '#angular/core';
import { PostModel } from '../Models/post.model';
import { HttpClient } from '#angular/common/http'
import { Subject } from 'rxjs';
import { map } from 'rxjs/operators'
#Injectable(
{ providedIn: 'root' }
)
export class PostsService {
constructor(private http: HttpClient) { }
private posts: PostModel[] = [];
private postsUpdated = new Subject<PostModel[]>()
getPosts() {
this.http.get<{ message: string, posts: any }>('http://localhost:3300/api/posts')
.pipe(
map((postData) => {
return postData.posts.map(post => {
return {
title: post.title,
content: post.content,
id: post._id,
imagePath: post.imagePath
}
})
}))
.subscribe(transformedPosts => {
this.posts = transformedPosts;
this.postsUpdated.next([...this.posts]) //updating the posts so that it is available to the rest of the app
})
}
getUpdatedPostsListener() {
return this.postsUpdated.asObservable()
}
getPost(id: string) {
// return {...this.posts.find( p => p.id === id)} //p implies each post, and p.id implies that post's id
return this.http.get<{ _id: string; title: string; content: string, imagePath: string }>("http://localhost:3300/api/posts/" + id);
}
addPosts(title: string, content: string, image: File) {
const postData = new FormData();
postData.append('title', title);
postData.append('content', content);
if(image != undefined){
postData.append('image', image, title);
}
this.http.post<{ message: string, post: PostModel }>('http://localhost:3300/api/posts', postData).subscribe((responseData) => {
const post: PostModel = { id: responseData.post.id, title: title, content: content, imagePath: responseData.post.imagePath }
this.posts.push(post);
this.postsUpdated.next([...this.posts]);
})
}
updatePosts(id: string, title: string, content: string, image: File | string) {
let postData: PostModel | FormData;
if (typeof image === "object") {
postData = new FormData();
postData.append("id", id);
postData.append("title", title);
postData.append("content", content);
if(image != undefined){
postData.append("image", image, title);
}
} else {
postData = {
id: id,
title: title,
content: content,
imagePath: image
};
}
this.http
.put("http://localhost:3300/api/posts/" + id, postData)
.subscribe(response => {
const updatedPosts = [...this.posts];
const oldPostIndex = updatedPosts.findIndex(p => p.id === id);
const post: PostModel = {
id: id,
title: title,
content: content,
imagePath: ""
};
updatedPosts[oldPostIndex] = post;
this.posts = updatedPosts;
this.postsUpdated.next([...this.posts]);
// this.router.navigate(["/"]);
});
}
deletePosts(postId: string) {
this.http.delete('http://localhost:3300/api/posts/' + postId)
.subscribe(() => {
const updatedPosts = this.posts.filter(post => post.id !== postId);
this.posts = updatedPosts;
this.postsUpdated.next([...this.posts]);
})
}
}
it's my first time making questions on stackoverflow :).
So I'm developing a test / learning application to learn how to use NestJS and Vue.
I am was currently trying to implement several server-side unit tests (using Jest). When trying to create a testingmodule from my UsersService I get the error below on running "npm test users.service.spec"
Nest can't resolve dependencies of the UsersService (?,
ConfigService). Please make sure that the argument at index [0] is
available in the _RootTestModule context.
at Injector.lookupComponentInExports (../node_modules/#nestjs/core/injector/injector.js:183:19)
I am not sure if I am incorrectly instantiating the test model, or misconceived the injection of config.service, the code itself works, but may be implemented incorrectly.
Does anyone have any ideas how to solve this problem?
Git link: https://github.com/Lindul/FuelTracker_NestJs_MySql_Vue.git
users.service.spec.ts
import { Test } from '#nestjs/testing';
import { UsersService } from './users.service';
import { UserDto } from './dto/user.dto';
import { UserLoginRegRequestDto } from './dto/user-login-reg-request.dto';
import { ConfigService } from '../shared/config/config.service';
describe('User Service Tests', () => {
let loginTeste: UserLoginRegRequestDto = {
login: 'LoginJestTeste',
password: 'PassJestTeste',
}
const userMock: UserDto = {
id: 1,
login: 'hugombsantos',
password: 'wefewkfnwekfnwekjnf',
isActive: true,
needChangePass: false,
userType: 0,
};
const dataFindAllMock: UserDto[] = [{
id: 1,
login: 'hugombsantos',
password: 'wefewkfnwekfnwekjnf',
isActive: true,
needChangePass: false,
userType: 0,
}, {
id: 2,
login: 'user2',
password: 'sdgsdgdsgsdgsgsdg',
isActive: true,
needChangePass: false,
userType: 0,
}];
let service: UsersService;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [
ConfigService,
UsersService,
],
}).compile();
service = module.get<UsersService>(UsersService);
});
it('UsersService está defenido', () => {
expect(service).toBeDefined();
});
});
user.service.ts
import { Injectable, Inject, HttpException, HttpStatus } from '#nestjs/common';
import { Users } from '../models/users.schema';
import { UserDto } from './dto/user.dto';
import { UserLoginRegRequestDto } from './dto/user-login-reg-request.dto';
import { UserLoginResponseDto } from './dto/user-login-response.dto';
import { sign } from 'jsonwebtoken';
import { ConfigService } from '../shared/config/config.service';
import { JwtPayload } from './auth/jwt-payload.model';
import { ErroMessageDto } from '../shared/config/dto/erro-message.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import bcrypt = require('bcrypt-nodejs');
const SALT_FACTOR = 8;
#Injectable()
export class UsersService {
constructor(
#Inject('UsersRepository') private usersRepository: typeof Users,
private readonly configService: ConfigService,
) { }
/* istanbul ignore next */
async findAll(): Promise<UserDto[]> {
const users = await this.usersRepository.findAll<Users>();
return users.map(user => {
return new UserDto(user);
});
}
/* istanbul ignore next */
async findUser(id: number): Promise<Users> {
const user = await this.usersRepository.findOne<Users>({
where: { id },
});
return user;
}
/* istanbul ignore next */
async findUserformLogin(login: string): Promise<UserDto> {
return await this.usersRepository.findOne<Users>({
where: { login },
});
}
/* istanbul ignore next */
async findUserforLogin(id: number, login: string): Promise<Users> {
return await this.usersRepository.findOne<Users>({
where: { id, login },
});
}
/* istanbul ignore next */
async creatUserOnDb(createUser: UserLoginRegRequestDto): Promise<Users> {
try {
const user = new Users();
user.login = createUser.login;
user.password = await this.hashPass(createUser.password);
return await user.save();
} catch (err) {
if (err.original.code === 'ER_DUP_ENTRY') {
throw new HttpException(
new ErroMessageDto(
HttpStatus.CONFLICT,
`Login '${err.errors[0].value}' already exists`),
HttpStatus.CONFLICT,
);
}
throw new HttpException(
new ErroMessageDto(
HttpStatus.INTERNAL_SERVER_ERROR,
err),
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
/* istanbul ignore next */
async updateUserOnDb(user: Users): Promise<Users> {
try {
return await user.save();
} catch (err) {
if (err.original.code === 'ER_DUP_ENTRY') {
throw new HttpException(
new ErroMessageDto(
HttpStatus.CONFLICT,
`Login '${err.errors[0].value}' already exists`),
HttpStatus.CONFLICT,
);
}
throw new HttpException(
new ErroMessageDto(
HttpStatus.INTERNAL_SERVER_ERROR,
err),
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
/* istanbul ignore next */
async delete(id: number): Promise<UserDto> {
const user = await this.findUser(+id);
await user.destroy();
return new UserDto(user);
}
async login(
userLoginRequestDto: UserLoginRegRequestDto,
): Promise<UserLoginResponseDto> {
const login = userLoginRequestDto.login;
const password = userLoginRequestDto.password;
const user = await this.findUserformLogin(login);
if (!user) {
throw new HttpException(
new ErroMessageDto(
HttpStatus.UNAUTHORIZED,
'Invalid login or password.'),
HttpStatus.UNAUTHORIZED,
);
}
const isMatch = await this.comparePass(password, user.password);
if (!isMatch) {
throw new HttpException(
new ErroMessageDto(
HttpStatus.UNAUTHORIZED,
'Invalid login or password.'),
HttpStatus.UNAUTHORIZED,
);
}
const token = await this.signToken(user);
return new UserLoginResponseDto(token);
}
async create(createUser: UserLoginRegRequestDto): Promise<UserLoginResponseDto> {
const userData = await this.creatUserOnDb(createUser);
// when registering then log user in automatically by returning a token
const token = await this.signToken(userData);
return new UserLoginResponseDto(token);
}
async updateUser(id: number | string, updateUserDto: UpdateUserDto): Promise<UserLoginResponseDto> {
const user = await this.findUser(+id);
if (!user) {
throw new HttpException(
new ErroMessageDto(
HttpStatus.NOT_FOUND,
'User not found.'),
HttpStatus.NOT_FOUND,
);
}
user.login = updateUserDto.login || user.login;
user.userType = updateUserDto.userType || user.userType;
user.needChangePass = false;
const isMatch = await this.comparePass(updateUserDto.password, user.password);
if (updateUserDto.password && !isMatch) {
user.password = await this.hashPass(updateUserDto.password);
} else {
user.password = user.password;
}
const userData = await this.updateUserOnDb(user);
const token = await this.signToken(userData);
return new UserLoginResponseDto(token);
}
async signToken(user: UserDto): Promise<string> {
const payload: JwtPayload = {
id: user.id,
login: user.login,
};
const token = sign(payload, this.configService.jwtConfig.jwtPrivateKey,
{
expiresIn: this.configService.jwtConfig.valideTime,
});
return token;
}
async hashPass(passToHash: string): Promise<string> {
const saltValue = await bcrypt.genSaltSync(SALT_FACTOR);
return await bcrypt.hashSync(passToHash, saltValue);
}
async comparePass(passToCheck: string, correntPass: string) {
return await bcrypt.compareSync(passToCheck, correntPass);
}
}
users.modules.ts
import { Module } from '#nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import {userProviders} from './users.providers';
import { DatabaseModule } from '../database/database.module';
import { JwtStrategy } from './auth/jwt-strategy';
import { ConfigService } from '../shared/config/config.service';
#Module({
imports: [DatabaseModule, ConfigService],
controllers: [UsersController],
providers: [UsersService,
...userProviders, JwtStrategy],
exports: [UsersService],
})
export class UsersModule {}
config.service.ts
import { Injectable } from '#nestjs/common';
import { JwtConfig } from './interfaces/jwt-config.interface';
import { config } from '../../../config/config.JwT';
import { config as dbConfigData } from '../../../config/config.db';
import { SequelizeOrmConfig } from './interfaces/sequelize-orm-config.interface';
#Injectable()
export class ConfigService {
get sequelizeOrmConfig(): SequelizeOrmConfig {
return dbConfigData.databaseOpt;
}
get jwtConfig(): JwtConfig {
return {
jwtPrivateKey: config.jwtPrivateKey,
valideTime: config.valideTime,
};
}
}
You need to provide some value for Nest to inject for your UserRepository. It looks like you are using the TypeORM #InjectRepository() decorator, so in your testing module you'll need to add something like this under your providers
{
provide: getRepositoryToken('UsersRepository'),
useValue: MyMockUserRepo,
}
So that Nest can know what value to inject for that string. MyMockUserRepo would be your mock repository functionality, so that you aren't making actual database calls to your backend