Type 'Observable<boolean>' is not assignable to type error. works in Ang 5 not in v6 - angular5

Upgrading a sample project from Angular 5 to 6.
https://github.com/mmacneil/AngularASPNETCore2WebApiAuth
The error happens on the return statement.
Type 'Observable<boolean>' is not assignable to type 'Observable<UserRegistration>'.
register Function
register(email: string, password: string, firstName: string, lastName: string, location: string, gender: string, birthDate: any): Observable<UserRegistration> {
let body = JSON.stringify({ email, password, firstName, lastName, location, gender, birthDate });
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.post(this.baseUrl + "/accounts", body, options)
.pipe(
map(res => true),
catchError(this.handleError)
);
}
UserRegistration
export interface UserRegistration {
email: string;
password: string;
firstName: string;
lastName: string;
location: string;
birthDate: any;
gender: string;
}
Could it be some new import I'm missing.??
Showing the Imports.
import { Injectable } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { HttpClientModule } from '#angular/common/http';
import { UserRegistration } from '../models/user.registration.interface';
import { ConfigService } from '../utils/config.service';
import { BaseService } from "./base.service";
import { Observable } from 'rxjs/Rx';
import { BehaviorSubject } from 'rxjs/Rx';
import { map, filter, catchError, mergeMap } from 'rxjs/operators';
// Add the RxJS Observable operators we need in this app.
import '../../rxjs-operators';
#Injectable()

Related

NestJS - No metadata for "EmployeeRepository" was found with authentication

I try to do some authentication for my nestjs app but I got stuck with this error and I don't know where to look at
My app.module.ts
#Module({
imports: [
AgenciesModule,
ActionsModule,
AuthModule,
TypeOrmModule.forRoot({
type: 'mysql',
host: '************',
username: '*********',
password: '*********',
database: '*********',
synchronize: true,
autoLoadEntities: true,
}),
EmployeesModule,
],
})
export class AppModule {}
My auth.service.ts
import { EmployeeRepository } from 'src/employees/entities/employee.repository';
#Injectable()
export class AuthService {
constructor(
#InjectRepository(EmployeeRepository)
private employeeRepository: EmployeeRepository,
) {}
async validateUser(email: string, password: string): Promise<any> {
const user = await this.employeeRepository.findOne({
where: { email, password },
});
// this work with postman if I put false data
//const user = {
// email: "email",
// password: "password",
//}
if (user && user.email === email && user.password === password) {
const { password, ...result } = user;
return result;
}
return null;
}
}
My auth.controller.ts
#Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}
#Post('login')
async login(#Body() body) {
return this.authService.login(body.email, body.password);
}
}
My auth.module.ts
imports: [TypeOrmModule.forFeature([EmployeeRepository])],
controllers: [AuthController],
providers: [AuthService, JwtStrategy],
exports: [AuthService],
})
export class AuthModule {}
And my employee.repository.ts
import { EntityRepository, Repository } from 'typeorm';
import { Employee } from './employee.entity';
#EntityRepository(Employee)
export class EmployeeRepository extends Repository<Employee> {}
I didn't put the different import for each file but I can provide them if needed
I checked all the file name and path from the differents import and they are all correct and I also updated my packages just in case.
These posts dosen't help :
NestJS - No metadata for "<Entity>" was found
No metadata for "User" was found using TypeOrm
Try this in auth.module.ts
imports: [TypeOrmModule.forFeature([EmployeeRepository])]
Change like this
imports: [TypeOrmModule.forFeature([Employee])]

nestjsx/crud + TypeORM: patch and post results in empty request

I'm trying to get into nestjs by creating a simple REST Api with TypeORM and the crud library. So far I have created a working role based authentication, but I'm running into a strange problem. I used the crud library to create a simple controller for the User entity. The GET-requests are working without any problems. But I can't POST to create a new user, neither can I use PATCH to update one. I think it might just be a very stupid mistake by me, but as I did not write much code, I can't find any differences to the examples in the doc.
When I try to patch a property, it just responds me with the original user object, no changes made (It's like I send an empty request).
When I try to post a new user, the response is the following error message:
{
"statusCode": 400,
"error": "Bad Request",
"message": "Empty data. Nothing to save."
}
It might have something to do with validation..
This is my user controller:
import { Controller, UseGuards } from '#nestjs/common';
import { UserService } from './user.service';
import { User } from './user.entity';
import { AuthGuard } from '#nestjs/passport';
import { ApiTags, ApiSecurity } from '#nestjs/swagger';
import { RolesGuard } from 'src/auth/role.guard';
import { Roles } from './roles.decorator';
import { Crud, CrudController } from '#nestjsx/crud';
#UseGuards(AuthGuard('jwt'), RolesGuard)
#Crud({
model: {
type: User
},
routes: {
exclude: ['createManyBase', 'replaceOneBase'],
},
//validation: false,
})
#Roles('admin')
#ApiSecurity('bearer')
#ApiTags('user')
#Controller('user')
export class UserController implements CrudController<User> {
constructor(public service: UserService) {}
}
This is my user service:
import { Injectable, Body, NotFoundException } from '#nestjs/common';
import { CreateUserDTO } from './dto/create-user.dto';
import { User } from './user.entity';
import { GetUsersFilterDto } from './dto/get-users-filter.dto';
import { InjectRepository } from '#nestjs/typeorm';
import { UserRepository } from './user.repository';
import { Role } from './role.entity';
import { TypeOrmCrudService } from '#nestjsx/crud-typeorm';
#Injectable()
export class UserService extends TypeOrmCrudService<User> {
constructor(
#InjectRepository(User) user,
private userRepository: UserRepository
) {
super(user);
}
async getUserByName(username: string): Promise<User>{
const found = await this.userRepository.findOne({
where: {
username: username,
},
relations: ["roles"]
});
if (!found){
throw new NotFoundException('User "${username}" not found!');
}
return found;
}
async getUserById(id: number): Promise<User>{
const found = await this.userRepository.findOne(id, {relations: ["roles"] });
if (!found){
throw new NotFoundException('User with "${id}" not found');
}
return found;
}
async matchRoles(roles: string[], userroles: Role[]){
let match = false;
console.log(userroles)
userroles.forEach(r => {
if (roles.indexOf('r.name')){
match = true;
}
})
return match;
}
}
This is the entity:
import { Entity, Column, PrimaryGeneratedColumn, ManyToMany, JoinTable, BeforeInsert, Unique } from 'typeorm';
import { Role } from './role.entity';
import * as bcrypt from 'bcryptjs';
import { Exclude } from 'class-transformer';
import { ApiProperty } from '#nestjs/swagger';
#Entity('auth_user')
#Unique(['username'])
export class User {
#PrimaryGeneratedColumn()
id: number;
#ApiProperty()
#Column({ length: 30 })
username: string;
#ApiProperty()
#Column()
firstName: string;
#ApiProperty()
#Column()
lastName: string;
#ApiProperty()
#Column()
email: string;
#BeforeInsert()
async hashPassword() {
this.password = await bcrypt.hash(this.password, 10);
}
#ApiProperty()
#Column()//({select: false})
#Exclude()
password: string;
#ApiProperty()
#Column({ default: true })
isActive: boolean;
#ManyToMany(
type => Role,
role => role.users,
{ cascade: true },
)
#JoinTable()
roles?: Role[];
}
Any hints are appreciated
As it turned out, it was the validation. Crud already has validation activated and I had this in the main.ts:
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true}));
So it was validated twice, what somehow led to an empty body in the request. I removed this and now I'm able to post/patch/put.

NestJS passport authentication returns 401 when using email for authentication

I have a problem that seems to be not that uncommon, but the solutions that I found did not work in my project.
What I want to do is a simple authentication using passport as this tutorial suggests: https://docs.nestjs.com/techniques/authentication
I followed this tutorial all along and at first it worked. Later I decided to use the users E-Mail and password as authentication instead of a username. So I changed my variable names and parameters in the authentication process to email and that was the point where everything broke apart. Am I missing something here?
auth.module.ts
import {Module} from '#nestjs/common';
import {UsersModule} from "../users/users.module";
import {AuthService} from "./services/auth.service";
import {PassportModule} from "#nestjs/passport";
import {LocalStrategy} from "./strategies/local.strategy";
import {AuthController} from "./controllers/auth.controller";
import {JwtModule} from "#nestjs/jwt";
import {jwtConstants} from "./constants";
import {JwtStrategy} from "./strategies/jwt.strategy";
import {EncryptionModule} from "../encryption/encryption.module";
#Module({
imports: [
UsersModule,
EncryptionModule,
PassportModule.register({defaultStrategy: 'jwt'}),
JwtModule.register({
secret: jwtConstants.secret,
signOptions: {
expiresIn: '30s'
}
})
],
providers: [
AuthService,
LocalStrategy,
JwtStrategy
],
controllers: [
AuthController
]
})
export class AuthModule {
}
controllers/auth.controller.ts
import {Controller, Get, Post, Request, UseGuards} from '#nestjs/common';
import {AuthService} from "../services/auth.service";
import {JwtAuthGuard} from "../guards/jwt-auth.guard";
import {LocalAuthGuard} from "../guards/local-auth.guard";
#Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {
}
#UseGuards(LocalAuthGuard)
#Post('login')
login(#Request() req) {
return this.authService.login(req.user);
}
#UseGuards(JwtAuthGuard)
#Get('profile')
getProfile(#Request() req) {
return req.user;
}
}
services/auth.service.ts
import {Injectable} from '#nestjs/common';
import {UsersService} from "../../users/services/users.service";
import {User} from "../../users/interfaces/user.interface";
import {JwtService} from "#nestjs/jwt";
import {JwtPayloadDto} from "../models/jwt-payload.dto";
import {EncryptionService} from "../../encryption/services/encryption.service";
#Injectable()
export class AuthService {
constructor(private usersService: UsersService,
private jwtService: JwtService,
private encryptionService: EncryptionService) {
}
async validateUser(email: string, pass: string): Promise<User | undefined> {
/**
* The findOne-method sends a database query
* to my mongodb via mongoose.
* I don't think it's necessary to post the UserService here, is it?
*/
const user: User = await this.usersService.findOne(email);
return this.encryptionService.compare(pass, user.password).then((result) => {
if (result) {
return user;
}
return undefined;
});
}
async login(user: User) {
const payload: JwtPayloadDto = {
email: user.email,
sub: user.id
}
return {
accessToken: this.jwtService.sign(payload)
};
}
}
strategies/local.strategy.ts
import {Injectable, UnauthorizedException} from "#nestjs/common";
import {PassportStrategy} from "#nestjs/passport";
import {Strategy} from "passport-local";
import {AuthService} from "../services/auth.service";
#Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super();
}
async validate(email: string, password: string): Promise<any> {
const user = await this.authService.validateUser(email, password);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
guards/local-auth.guard.ts
import {Injectable} from "#nestjs/common";
import {AuthGuard} from "#nestjs/passport";
#Injectable()
export class LocalAuthGuard extends AuthGuard('local') {
}
According to this question I found out that the validate-methods signature has to have the same parameter names as the request payloads keys.
For debugging purposes I have put a console.log()-call on the first line of my validate-method in the strategies/local.strategy.ts but it seems as it does not get called at all.
Thanks for any answer in advance.
Have a good one!
for me, when create LocalStrategy, I passed {usernameField: 'email'} to ParentClass.
If you want to check user authenticate with custom column like 'email', try pass it.
my user.entity.ts:
#Entity()
export class User {
#PrimaryGeneratedColumn()
id: number;
#Column({ unique: true })
email: string;
#Column()
name: string;
}
my local.strategy.ts:
#Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({ usernameField: 'email' });
}
async validate(email: string, password: string): Promise<User> {
console.log(email, password); // it works
}
}
Well, I solved it myself. 5 hours of debugging wasted!
Turned out that somehow my Postman did not send the Content-Type header with the request. Restarting Postman fixed it.

Angular 5: Solving unresolved dependency in constructor

I'm trying to create a generic HttpService for my Angular 5 project.
The error I am getting:
Uncaught Error: Can't resolve all parameters for HttpService: ([object Object], [object Object], [object Object], ?)
app/util/constants.ts
import { Injectable } from "#angular/core";
#Injectable()
export class SERVER {
readonly ROOT:string = 'http://localhost:8888/';
readonly API_PATH:string = 'api/v1/';
}
#Injectable()
export class API_URLS {
readonly USER:string = 'user/';
}
app/serializers/serializer.ts
import { Resource } from 'app/models/resource';
export interface Serializer {
fromJson(json: any): Resource;
toJson(resource: Resource): any;
}
app/models/resource.ts
export class Resource {
id: number;
}
app/models/user.model.ts
import { Resource } from 'app/models/resource';
export class User extends Resource{
id: number;
name: string;
email: string;
gender: string;
address: string;
landmark: string;
client_id: number;
dealer_id: number;
phone_number: string;
alternate_phone_number: string;
status: string;
is_active: boolean;
date_created: string;
date_updated: string;
}
app/serializers/user.serializer.ts
import { User } from 'app/models/user.model';
import { Serializer } from 'app/serializers/serializer';
export class UserSerializer implements Serializer {
fromJson(json: any): User {
const user = new User();
user.id = json.id;
user.client_id = json.client_id;
user.dealer_id = json.dealer_id;
user.status = json.status;
user.is_active = json.is_active;
user.date_created = json.date_created;
user.date_updated = json.date_updated;
return user;
}
toJson(user: User): any {
return {
id: user.id,
client_id: user.client_id,
dealer_id: user.dealer_id,
status: user.status,
is_active: user.is_active,
date_created: user.date_created,
date_updated: user.date_updated,
};
}
}
app/services/user.service.ts
import { Injectable } from '#angular/core';
import { SERVER } from 'app/util/constants';
import { API_URLS } from 'app/util/constants';
import { User } from 'app/models/user.model';
import { HttpClient } from '#angular/common/http';
import { HttpService } from 'app/services/http.service';
import { UserSerializer } from 'app/serializers/user.serializer';
#Injectable()
export class UserService extends HttpService<User> {
constructor(
server: SERVER,
API_URLS: API_URLS,
httpClient: HttpClient
) {
super(
server,
httpClient,
API_URLS.USER,
new UserSerializer());
}
}
app/app.module.ts
import { Observable } from 'rxjs/Rx';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { CommonModule } from '#angular/common';
import { RouterModule } from '#angular/router';
import { AppRoutingModule } from './app-routing.module';
import { HttpClientModule } from '#angular/common/http';
import { BrowserModule } from '#angular/platform-browser';
/************** Services *****************/
import { UserService } from './services/user.service';
/************** Components *****************/
import { UserComponent } from './components/user/user.component';
/************** Constant *****************/
import { SERVER } from './util/constants';
import { API_URLS } from './util/constants';
import { OPERATION_TYPES } from './util/constants';
import { REQUEST_METHODS } from './util/constants';
import { Resource } from './models/resource';
#NgModule({
declarations: [
AppComponent,
UserComponent,
],
imports: [
CommonModule,
BrowserModule,
AppRoutingModule,
HttpClientModule
],
providers: [
SERVER,
API_URLS,
OPERATION_TYPES,
REQUEST_METHODS,
Resource,
UserService,
],
bootstrap: [AppComponent]
})
export class AppModule { }
Edit: Added missing code
app/services/http.service.ts
import { Observable } from 'rxjs/Rx';
import { Resource } from 'app/models/resource';
import { Serializer } from 'app/serializers/serializer';
import { SERVER } from 'app/util/constants';
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class HttpService<T extends Resource> {
constructor(
private SERVER: SERVER,
private httpClient: HttpClient,
private API_URL: string,
private serializer: Serializer) { }
/*
* Get single record by id
*/
read(id: number): Observable<T> {
return this.httpClient.get<T>(`${this.SERVER.ROOT}/${this.SERVER.API_PATH}/${this.API_URL}/${id}`).map(data => this.serializer.fromJson(data) as T);
}
/*
* Get all records by page
*/
readRecords(): Observable<T[]>{
return this.httpClient.get<T[]>(`${this.SERVER.ROOT}/${this.SERVER.API_PATH}/${this.API_URL}`).map((data: any) => this.convertData(data.items) as T[]);
}
/*
* Create new record
*/
create(record: T): Observable<T>{
return this.httpClient.post<T>(`${this.SERVER.ROOT}/${this.SERVER.API_PATH}/${this.API_URL}`, record).map(data => this.serializer.fromJson(data) as T);
}
/*
* Update record
*/
update(record: T): Observable<T>{
return this.httpClient.put<T>(`${this.SERVER.ROOT}/${this.SERVER.API_PATH}/${this.API_URL}/${record.id}`, record).map(data => this.serializer.fromJson(data) as T);
}
/*
* Remove record
*/
remove(id: number) {
return this.httpClient.delete(`${this.SERVER.ROOT}/${this.SERVER.API_PATH}/${this.API_URL}/${id}`);
}
private convertData(data: any): T[] {
return data.map(item => this.serializer.fromJson(item));
}
}
What am I missing?
I solved this by making the Serializer abstract class and making serializers injectable.
import { Injectable } from '#angular/core';
import { Resource } from 'app/models/resource';
#Injectable()
export abstract class Serializer {
abstract fromJson(json: any): Resource;
abstract toJson(resource: Resource): any;
}
And
import { Injectable } from '#angular/core';
import { User } from 'app/models/user.model';
import { Serializer } from 'app/serializers/serializer';
#Injectable()
export class UserSerializer implements Serializer {
fromJson(json: any): User {
const user = new User();
user.id = json.id;
user.client_id = json.client_id;
user.dealer_id = json.dealer_id;
user.status = json.status;
user.is_active = json.is_active;
user.date_created = json.date_created;
user.date_updated = json.date_updated;
return user;
}
toJson(user: User): any {
return {
id: user.id,
client_id: user.client_id,
dealer_id: user.dealer_id,
status: user.status,
is_active: user.is_active,
date_created: user.date_created,
date_updated: user.date_updated,
};
}
}

angular 5 async validator not working

I am validating if mobile number exist on server in angular 5.Si i have created a custom async validator for this.But it is not working nor giving any error and it gives pending status to form field.Any help will be appreciated.here is code of service.ts
import { Injectable } from '#angular/core';
import {HttpClient} from "#angular/common/http";
import { Observable } from "rxjs/Observable";
#Injectable()
export class SignupService {
constructor(private _http:HttpClient) {}
mobileExists(mobile:number):Observable<{}>{
return this._http.get("http://localhost/truck/api/web/user/verify- exist?mobile="+mobile,{responseType:'json'});
}
}
and here is code of my component.ts
import { Component, OnInit } from '#angular/core';
import {FormsModule, ReactiveFormsModule,AbstractControl, ValidationErrors,FormControl,Validators,FormGroup,AsyncValidatorFn} from "#angular/forms";
import {SignupService} from "./signup.service";
import {Observable} from "rxjs/Observable";
import {map,take,debounceTime} from "rxjs/operators";
#Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.css'],
providers: [SignupService]
})
export class RegisterComponent implements OnInit {
signupForm: FormGroup;
mobile: number;
password: string;
otp: number;
public exist;
constructor(public service:SignupService) {
}
ngOnInit() {
this.signupForm = new FormGroup({
mobile: new FormControl('',
[Validators.required, Validators.minLength(10), Validators.maxLength(10)],this.mobileValidator.bind(this)),
password: new FormControl('',
[Validators.required, Validators.minLength(6), Validators.maxLength(15)]),
otp: new FormControl('',
[Validators.required, Validators.minLength(6), Validators.maxLength(6)]),
});
}
mobileValidator(control: AbstractControl):any {
return new Observable(resolve => {
this.service.mobileExists(control.value).subscribe(
data=>{
if (data['status'] == 'ok'){
return null;
}else if(this.exist.status == 'exist'){
return {mobileTaken:true};
}
},
error=>{
return console.log(error)
},
);
}
);
}
}
In FormControl use mobile: new FormControl('',
[Validators.required, Validators.minLength(10), Validators.maxLength(10)],[this.mobileValidator()]), so AsyncValidator as third parameter and no need to call bind.
Use map and no need to wrap to new Observable call: mobileValidator() { return (control: AbstractControl): any => { return this.service.mobileExists(control.value).map(data => return (data['status'] == 'ok') ? null : { mobileTaken: true } )); } }
good article is here http://fiyazhasan.me/asynchronous-validation-in-angulars-reactive-forms-control/