User is undefined on the context.switchToHttp().getRequest() nestjs - javascript

I'm new to nestJs and I needed to add role based access to the application so I followed the documentation but in the execution context user doesn't exist. I can't seems to find the problem here's the github repo if you need to seem more code: https://github.com/anjula-sack/slinc-backend
roles.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '#nestjs/common';
import { Reflector } from '#nestjs/core';
import { ROLES_KEY } from 'src/decorators/roles.decorator';
import Role from 'src/util/enums/role.enum';
#Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) {
return true;
}
const { user } = context.switchToHttp().getRequest();
console.log(context.switchToHttp().getRequest().req);
return requiredRoles.some((role) => user.type === role);
}
}
app.controller.ts
#UseGuards(JwtAuthGuard, RolesGuard)
#Get('me/business')
#Roles(Role.ADMIN)
getBusiness(#Request() req) {
return this.usersService.getUserBusiness(req.user.id);
}

From the code, I think you are mixing global and local guard
In app.module.ts, the below code is for registering global guard.
and app.useGlobalGuard() should be used together if you want to apply guard globally.
// Remove the following code in app.module.ts
{
provide: APP_GUARD,
useClass: RolesGuard,
}
But your intention should be building a local role guard, so please remove the above code and the request user will work.

Related

Angular 4: Cannot instantiate cyclic dependency! InjectionToken_HTTP_INTERCEPTORS

I know, this question may sound duplicate and I have tried everything found on stackover flow unable to resolve this problem, so please bear with me
To make you able to reproduce the error I am providing you the whole code thought this
Github Repo
Problem
I am getting the following error:
Provider parse errors:↵Cannot instantiate cyclic dependency!
InjectionToken_HTTP_INTERCEPTORS ("[ERROR ->]"): in NgModule AppModule
in ./AppModule#-1:-1
Information about the scenario (Notes)
Note 1
File: response-interceptor.service.ts
Path: ./src/app/shared/interceptors/response-interceptor/
I am intercepting the HTTPClient responses to check the 401 error and when the error comes I need to ask user to re-login.
To show the re-login prompt to user I have made a global-functions-services that has a function 'relogin'
Note 2
File: global-function.service.ts
Path: ./src/app/shared/services/helper-services/global-function/
Here is the place where this all started to happen...
As soon as I am injecting the PersonService
constructor(
public dialog: MatDialog,
private _personService: PersonService
) { }
I am getting this error and in PersonService I cannot find any import that can cause the issue.
PersonService:
./src/app/shared/services/api-services/person/person.service.ts
import { IRequest } from './../../../interfaces/I-request';
import { environment } from 'environments/environment';
import { Injectable } from '#angular/core';
// for service
import 'rxjs/add/operator/map'
import 'rxjs/add/operator/toPromise';
// models
import { Person } from 'app/shared/models/person';
import { RequestFactoryService, REQUEST_TYPES } from 'app/shared/factories/request-factory/request-factory.service';
#Injectable()
export class PersonService {
private _requestService: IRequest;
constructor(
_requestFactoryService: RequestFactoryService
) {
this._requestService = _requestFactoryService.getStorage(REQUEST_TYPES.HTTP);
}
public signup(record): Promise<Person> {
let url = environment.api + 'person/public/signup';
return this._requestService.post(url, record) as Promise<Person>;;
}
public authenticate(code: string, password: string): Promise<Person> {
let url = environment.api + 'auth/signin';
let postData = {
code: code,
password: password
}
return this._requestService.post(url, postData) as Promise<Person>;
}
}
Request
Please suggest a solution for this, I have already wasted 2 days to figure out the issue but no luck.
Many thanks!! in advance
Cyclic dependency, means circling around endless, like planets orbiting sun..
Solution: Break the dependency chain, Re-factor code.
You have GlobalFunctionService -> PersonService -> so on... -> ResponseInterceptorService -> and back to -> GlobalFunctionService.
Cycle complete.
REMOVE the PersonService dependency from GlobalFunctionService. (its not used anyway, if you need it then find different way to get around.)
import { PersonService } from 'app/shared/services/api-services/person/person.service';
import { Injectable } from '#angular/core';
import { InputModalComponent } from 'app/shared/components/input-modal/input-modal.component';
import { MatDialog } from '#angular/material';
#Injectable()
export class GlobalFunctionService {
constructor(
public dialog: MatDialog
) { }
relogin(): void {
let dialogRef = this.dialog.open(InputModalComponent, {
width: '250px',
data: { title: "Please provide your password to re-login." }
});
dialogRef.afterClosed().subscribe(result => {
debugger
console.log('The dialog was closed');
let password = result;
});
}
}
Use setTimeout() function in constructor to assign service.
constructor(private injector: Injector) {
setTimeout(() => {
this.loginService = this.injector.get(LoginService);
})
}
Try this and revert back if you face any issue.
You have to modify your response-interceptor.service.ts
import { Injectable,Inject, Injector } from '#angular/core';
constructor( inj: Injector) {
this._globalFunctionService=inj.get(GlobalFunctionService)
}
You can get more info From this link

Why is the service called twice in this angular 2 component?

I have here the component code, when I am subscribing to the observable the service is called twice, however if I subscribe to the Behaviorsubject it is only triggered once,
I can see on my logs that those are the result, please see my code below for my component
the method subscribeToMap() method is called on ngOninit.
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
// Observable class extensions
import 'rxjs/add/observable/of';
// Observable operators
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import { HeroSearchService } from './hero-search-service';
import { Hero } from './../hero';
#Component({
selector: 'hero-search',
templateUrl: './hero-search.component.html',
styleUrls: [ './hero-search.component.css' ],
providers: [HeroSearchService]
})
export class HeroSearchComponent implements OnInit {
heroes: Observable<Hero[]>;
private searchTerms = new Subject<string>();
constructor(
private heroSearchService: HeroSearchService,
private router: Router) {}
// Push a search term into the observable stream.
search(term: string): void {
this.searchTerms.next(term);
console.log("new " + term);
}
ngOnInit(): void {
this.heroes = this.searchTerms
.debounceTime(300) // wait 300ms after each keystroke before considering the term
.distinctUntilChanged() // ignore if next search term is same as previous
.switchMap(term => {
return term // switch to new observable each time the term changes
// return the http search observable
? this.heroSearchService.search(term)
// or the observable of empty heroes if there was no search term
: Observable.of<Hero[]>([])})
.catch(error => {
// TODO: add real error handling
console.log(error);
return Observable.of<Hero[]>([]);
});
this.subscribeToMap();
}
subscribeToMap(): void{
this.heroes.subscribe(() => console.log("called twice"));
this.searchTerms.subscribe(() => console.log("called once"));
}
gotoDetail(hero: Hero): void {
let link = ['/detail', hero.id];
this.router.navigate(link);
}
}
Here is the code for my service
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { Hero } from './../hero';
#Injectable()
export class HeroSearchService {
constructor(private http: Http) {}
search(term: string): Observable<Hero[]> {
console.log("service is called");
return this.http
.get(`api/heroes/?name=${term}`)
.map(response => response.json().data as Hero[]);
}
}
thank you ver much!!!
When subscription is implemented properly it has nothing to do with "unsubscribe" method, Observable, etc. This behavior is by design of Angular itself.
https://www.reddit.com/r/Angular2/comments/59532r/function_being_called_multiple_times/d95vjlz/
If you're running in development mode, it will run the function
at least twice. since in development mode it does a check, changes,
then rechecks to verify, where production mode only does the first
check, assuming you've done your quality assurance and resolved any
values the get changed post checking.
P.S. This is probably the next issue you will face to in Dev Mode :)
Angular2 change detection "Expression has changed after it was checked"
Try replacing this line:
this.heroes = this.searchTerms
With this one:
this.heroes = this.searchTerms.asObservable()
to ensure that heroes is an observable and your code can't accidentally invoke next() on it.
Your code casts hero to a Subject so you can still do next() on it.

Angular2 custom ErrorHandler, why can I log to console but not to template?

I would like to have custom errors in my Angular2 app. Thus I have extended ErrorHandler in my component:
import { Component, ErrorHandler, OnInit } from '#angular/core';
import { GenericError } from './generic-error.component';
#Component({
selector: 'custom-error-handler',
templateUrl: 'app/error-handler/custom-error-handler.component.html?' + +new Date()
})
export class CustomErrorHandler extends ErrorHandler {
errorText: string;
constructor() {
super(false);
}
ngOnInit() {
this.errorText = 'Initial text!';
}
public handleError(error: any): void {
if (error.originalError instanceof GenericError) {
console.info('This is printed to console!');
this.errorText = "I want it to print this in the template!";
}
else {
super.handleError(error);
}
}
}
My template simply contains:
<span style="color:red">{{errorText}}</span>
First I see "Initial text!" in the template as set in ngOnInit. That's as expected.
I can then throw a new exception like this from a different component:
throw new GenericError();
and it hits the code with handleError and prints to console but it doesn't update my template errorText with:
"I want it to print this in the template!"
It's like it ignores my template, when inside the handleError function.
What could be the problem here?
* ADDED MORE INFORMATION *
I thought I should add some more information. So here is the module I made for CustomErrorHandler (maybe the problem is with the providers?):
import { NgModule, ErrorHandler } from '#angular/core';
import { CommonModule } from '#angular/common';
import { CustomErrorHandler } from './custom-error-handler.component';
#NgModule({
declarations: [
CustomErrorHandler
],
imports: [
CommonModule
],
exports: [
CustomErrorHandler
],
providers: [
{ provide: ErrorHandler, useClass: CustomErrorHandler }
]
})
export class CustomErrorModule { }
There is indeed only one instance of the CustomErrorHandler (I checked with the Augury Chrome plugin).
For completeness, here is is the GenericError component:
export class GenericError {
toString() {
return "Here is a generic error message";
}
}
The solution was to add a service as suggested in the question's comment track. This way I can set the property in the component and eventually show it in the template.
I created the service, so that it has a function which takes one parameter. Injected the service, call the service's function from the handleError in the component function, and send the text I want in the template as the parameter. Then I use an observable, to get the text back to the component.
In the constructor of the component, I added this observer.
let whatever = this.cs.nameChange.subscribe((value) => {
setTimeout(() => this.errorText = value);
});
I needed to add the setTimeout, or else it would not update the template before the second time the observable was changed.
Phew! The Angular team should make this global exception handling easier in future releases.

Cannot read property 'version' of undefined angular2

I am having a hard time using a async object in a html composition.
Here is my model:
export class Version {
isGood: boolean;
constructor(isGood: boolean) {
this.isGood= isGood;
}
}
This model is called by a component as follows:
#Injectable()
export class MyComponent {
public version: Version;
constructor(private _myService: VersionService) {}
getVersion(): void {
// async service that gets the versions
this._myService.getVersion().subscribe(
data => this.version= data,
error=> console.log(error),
() => console.log("getting all items complete")
);
}
}
My template references to the version variable as follows:
<button (click)="getVersion()">Get Version</button>
<hr>
<p style="color:red">{{error}}</p>
<h1>Version</h1>
<p>{{version.isGood}}</p>
However, I get an exception:
Cannot read property 'isGood' of undefined
From scavenging the internet, I see that my problem is because the version object is null. If I do something like:
<p>{{version | json}}</p>
I can see the correct version
If I do something like
<p>{{version.isGood | async}}</p>
I see nothing
If I edit MyComponent, and set
public version: Version = new Version();
I can execute the .isGood property fetch, but it is always empty.
Is there a different way I am supposed to load a property if I am using it in an asynchronous manner?
Use the ? operator or use an *ngIf.
<p>{{version?.isGood}}</p>
<p *ngIf="version">{{version.isGood}}</p>
Try this:
<p>{{version?.isGood}}</p>
This tells Angular to protect against version.isGood being undefined or null until you click and fetch the data for version through your service.
First me correct you. #Injectable() makes a normal typescript class as injectable service where you can share data.
To make a component you need to use #Component decoratore.
The process of data sharing between component and within the application is to create a service and add that as provides in module. And then its singleton object will available everyshere.
//module
import {NgModule} from '#angular/core';
import {YourService} from "./services/your-service";
#NgModule({
imports: [
BrowserModule
],
declarations: [
AppComponent
],
providers: [
YouService
],
bootstrap: [AppComponent]
})
export class AppModule {
}
//this is your component
import {Component} from '#angular/core';
import {YourService} from "../../services/your-service";
#Component({
selector: 'component-app',
templateUrl: '../../views/app.component.html',
})
export class HeaderComponent {
constructor(public yourService: YourService) {
}
}
//your service
import {Injectable} from "#angular/core";
#Injectable()
export class YourService {
private _message: string = 'initial message';
private _style: string = 'success';
get message(): string {
return this._message;
}
set message(value: string) {
this._message += value;
}
get style(): string {
return this._style;
}
set style(value: string) {
this._style = value;
}
}
//finally your view
<div class="row">
<div [class]=""><h1>{{swapService.message}}</h1></div>
</div>
Observable Data services.
#Injectable()
export class MyComponent {
public version = new ReplaySubject<Version>();
constructor(private _myService: VersionService) {}
init(): void {
// async service that gets the versions
this._myService.getVersion().subscribe(
data => this.version.next(data),
error=> console.log(error),
() => console.log("getting all items complete")
);
}
getVersion(): void {
this.version.asObservable();
}
}
In the template
<button (click)="init()">Get Version</button>
<hr>
<p style="color:red">{{error}}</p>
<h1>Version</h1>
<p>{{(version |async)?.isGood}}</p>

Global function available through all app Angular2

I have a PermissionService, which provide user roles. At the server-side data will not be uploaded if the user is not corresponds on role. The back-end is written with asp.net web api, which will use attributes to secure data. On upload page will be static upload user roles, the idea is just to show or hide elements on page which depending from user role.
The PermissionsService check avaiable role in its array. There are methods like isSeller(), isManager(). And all what i want is to provide accessibility from each view. For now i have this implementation.
permission.service
import { Injectable } from "#angular/core";
export enum Roles {
Admin,
Manager,
Moderator,
Seller
}
interface IPermissionDictionary {
[key: string]: boolean;
}
#Injectable()
export class PermissionService {
private permissions: IPermissionDictionary = {};
public constructor() {
this.emitPermissions();
}
private emitPermissions(): void {
let selector = document.querySelectorAll("#roles > span");
let availableRoles = Array.from(selector).map(element => element.textContent);
for (let role in Roles) {
if (!/^\d+$/.test(role)) { // for strings types in Roles
this.permissions[role] = availableRoles.indexOf(role) > -1;
}
}
}
public isInRole(role: string): boolean {
return this.permissions[role];
}
public isAdmin() {
return this.isInRole(Roles[Roles.Admin]);
}
public isSeller() {
return this.isInRole(Roles[Roles.Seller]);
}
public isManager() {
return this.isInRole(Roles[Roles.Manager]);
}
public isModerator() {
return this.isInRole(Roles[Roles.Moderator]);
}
}
app.component
import { Component } from "#angular/core";
import { ROUTER_DIRECTIVES } from "#angular/router";
import { PermissionService } from "./share/permission.service";
import { HomeComponent } from "./home/home.component";
import { OrderComponent } from "./order/order.component";
#Component({
selector: "admin-panel",
templateUrl: "../app/app.template.html",
directives: [ROUTER_DIRECTIVES],
precompile: [HomeComponent, OrderComponent]
})
export class AppComponent {
constructor(private permissionService: PermissionService) {
}
}
main.ts
import { bootstrap } from "#angular/platform-browser-dynamic";
import { AppComponent } from "./app.component";
import { APP_ROUTES_PROVIDER } from "./app.routes";
import { HTTP_PROVIDERS } from '#angular/http';
import { PermissionService } from "./share/permission.service";
bootstrap(AppComponent, [APP_ROUTES_PROVIDER, HTTP_PROVIDERS, PermissionService]);
For now to access the method of PermissionService need to inject it in component constructor. And in template is is use like
<div *ngIf="permissionService.isAdmin()">will show if you are admin</div>
But every time to inject my service in each component where i want to use it seems for me strange. And i just want to get access it from every part of my app like:
<div *ngIf="isAdmin()">will show if you are admin</div>
I think the person who asked this question has another version of Angular2 (perhaps a pre-release?), but in the latest version if you need to export a service for all the app you do it in the following way.
First, in your main.ts you must have a class that you bootstrap, like this:
platformBrowserDynamic().bootstrapModule(AppModule);
In this class "AppModule" (or whatever it is in your case), you should be able to add a global service provider in this way:
...
import {GlobalService} from './global-service.service'
#NgModule({
...
providers: [MyGlobalService],
...
})
export class AppModule{ ...}
In this way MyGlobalService is available for all other components.
Hopefully this will be useful to someone :).
Some option could be to create top level super class with the permission methods and then just subclass in view .ts. Not sure if this suits you as you still need to import super class into your components and extend it. It can also violate the "is-a".

Categories