NestJS, TypeORM, can't fetch data - javascript

I am trying to get started with NestJS which uses TypeORM.
I have connected to a database. At least I think I have, because I was getting a lot of errors and after enough tuning of the config, the errors went away and the connection seems to be successful.
So now I want to fetch any bit of data just to get started.
There is a table in the database called RESULT_PAGE, so I just want to fetch any record from that. This is what I have tried:
result-page.entity.ts
import { Entity, PrimaryColumn, Column } from "typeorm";
#Entity()
export class ResultPage {
#PrimaryColumn()
result_page_id: number;
#Column({ length: 1 })
approval: string;
#Column({ length: 1})
manually_uploaded: string;
}
result-page.controller.ts
import { Controller, Get, Request } from '#nestjs/common';
import { ResultPageService } from './result-page.service';
#Controller('result-page')
export class ResultPageController {
constructor(
private resultPageService: ResultPageService
) { }
#Get('get-all')
getProfile() {
return this.resultPageService.findAll();
}
}
result-page.service.ts
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { ResultPage } from './result-page.entity';
#Injectable()
export class ResultPageService {
constructor(
#InjectRepository(ResultPage)
private readonly resultPageRepository: Repository<ResultPage>,
) {}
findAll(): Promise<ResultPage[]> {
return this.resultPageRepository.find();
}
}
If I edit the service to look like this:
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { ResultPage } from './result-page.entity';
#Injectable()
export class ResultPageService {
constructor(
#InjectRepository(ResultPage)
private readonly resultPageRepository: Repository<ResultPage>,
) {}
findAll(): Promise<string> {
return new Promise((resolve, reject) => { resolve('hello world') })
// return this.resultPageRepository.find();
}
}
then I get 'hello world', so it is definitely that the RESULT_PAGE table isn't connected
In the AppModule I am loading the entities like this
const typeOrmModuleOptions: TypeOrmModuleOptions = {
...
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true
}
I am sure that I am making some absolute noob mistake so if someone could help me out here it would be greatly appreciated. I am quite new to databases and api's so any info would help a lot. TIA
SOLVED
Solved by adding a connectString https://github.com/typeorm/typeorm/issues/3484#issuecomment-472315370

A little bit confusing the question. I miss the error and the database config.
result_page vs RESULT_PAGE: tablename
on linux/unix the tablenames are case sensitive, so you should set it in the annotation
#Entity({name: 'RESULT_PAGE'})
Please give some details to find the root cause if it was not that.

Related

Nest can't resolve dependencies of the ClientsService (?)

So I have a sample app im building in nest js and I hit an error on npm start
Nest can't resolve dependencies of the ClientsService (?). Please make sure that the argument ClientModel at index [0] is available in the ClientsModule context.
So I have checked it over but cant seem to find why the error is happening
My client.service.ts
import { Injectable } from '#nestjs/common';
import { Model } from 'mongoose';
import { InjectModel } from '#nestjs/mongoose';
import { Client } from 'clients/interfaces/client.interface';
import { CreateClientDTO } from 'clients/dto/create-client.dto';
#Injectable()
export class ClientsService {
constructor(#InjectModel('Client') private readonly clientModel: Model<Client>) { }
// Get all clients
async getClients(): Promise<Client[]> {
const clients = await this.clientModel.find().exec();
return clients
}
//Get single client
async getClient(clientID: Promise<Client>) {
const client = await this.clientModel
.findById(clientID)
.exec();
return client;
}
//Add client
async addClient(createClientDTO: CreateClientDTO): Promise<Client> {
const newClient = await new this.clientModel(createClientDTO);
return newClient.save()
}
}
and my client.module.ts
import { Module } from '#nestjs/common';
import { ClientsService } from './clients.service';
import { ClientsController } from './clients.controller';
import { MongooseModule } from '#nestjs/mongoose';
import { ClientSchema } from 'clients/schemas/clients.schema';
#Module({
imports: [
MongooseModule.forFeature([{name: 'Clients', schema: ClientSchema}])
],
providers: [ClientsService],
controllers: [ClientsController]
})
export class ClientsModule {}
The InjectModel decorator expects to take the schema name of your entity.
So you tell the mongoose in ClientsModule that the schema name is Clients, but in ClientsService you try to inject the model with the schema name Client, which is different from the contract in the module.
MongooseModule.forFeature([{name: 'Clients', schema: ClientSchema}])
constructor(#InjectModel('Client') private readonly clientModel: Model<Client>) { }

Firebase angularfire2 - How to return data from the current user only?

I'm trying to figure out how to limit a collection to returning just the user's data, not everyone's data.
In the example I'm working from the FirebaseService only shows CRUD examples where the data that's returned is everything.
import { Injectable } from "#angular/core";
import { Platform } from 'ionic-angular';
import 'rxjs/add/operator/toPromise';
import { AngularFirestore } from 'angularfire2/firestore';
import * as firebase from 'firebase/app';
import 'firebase/storage';
#Injectable()
export class FirebaseService {
constructor(
public afs: AngularFirestore,
public platform: Platform
){}
getEvents(){
return new Promise<any>((resolve, reject) => {
this.afs.collection('/events').snapshotChanges() // add +auth.uid ... or something?
.subscribe(snapshots => {
resolve(snapshots)
})
})
}
...
In order to only get the user's events back, I think I need to add:
import { AngularFireAuth } from 'angularfire2/auth';
... and, do something from there. But, I'm at a loss. Any help would be greatly appreciated. Thanks in advance!
You can limit this by adding rules. For example, you are using /users/ node to store user information. You can restrict only for the logged in user matching with userId can access /users/
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
function isOwner(userId) {
return request.auth.uid == userId
}
match /users/{userId} {
allow get: if isSignedIn()
&& isOwner(userId);
....
}
}
To get User Id
constructor(
private afAuth: AngularFireAuth )
// then
ngOnInit() {
this.afAuth.authState;
this.afAuth.authState.subscribe(
user => {
this.userInfo = user; <-- You can store user Id information to user variable
},
err => {
console.log(err);
}
}
you can use this.userInfo.uid to make further calls.

Getting User Data by using Guards (Roles, JWT)

The documentation is kinda thin here so I ran into a problem. I try to use Guards to secure Controller or it's Actions, so I gonna ask for the role of authenticated requests (by JWT). In my auth.guard.ts I ask for "request.user" but it's empty, so I can't check the users role. I don't know how to define "request.user". Here is my auth module and it's imports.
auth.controller.ts
import { Controller, Get, UseGuards } from '#nestjs/common';
import { AuthGuard } from '#nestjs/passport';
import { AuthService } from './auth.service';
import { RolesGuard } from './auth.guard';
#Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
#Get('token')
async createToken(): Promise<any> {
return await this.authService.signIn();
}
#Get('data')
#UseGuards(RolesGuard)
findAll() {
return { message: 'authed!' };
}
}
roles.guard.ts
Here user.request is empty, because I never define it. The documentation doesn't show how or where.
import { Injectable, CanActivate, ExecutionContext } from '#nestjs/common';
import { Reflector } from '#nestjs/core';
#Injectable()
export class RolesGuard implements CanActivate {
constructor(private readonly reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const roles = this.reflector.get<string[]>('roles', context.getHandler());
if (!roles) {
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user; // it's undefined
const hasRole = () =>
user.roles.some(role => !!roles.find(item => item === role));
return user && user.roles && hasRole();
}
}
auth.module.ts
import { Module } from '#nestjs/common';
import { AuthService } from './auth.service';
import { HttpStrategy } from './http.strategy';
import { UserModule } from './../user/user.module';
import { AuthController } from './auth.controller';
import { JwtStrategy } from './jwt.strategy';
import { PassportModule } from '#nestjs/passport';
import { JwtModule } from '#nestjs/jwt';
#Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secretOrPrivateKey: 'secretKey',
signOptions: {
expiresIn: 3600,
},
}),
UserModule,
],
providers: [AuthService, HttpStrategy],
controllers: [AuthController],
})
export class AuthModule {}
auth.service.ts
import { Injectable } from '#nestjs/common';
import { UserService } from '../user/user.service';
import { JwtService } from '#nestjs/jwt';
#Injectable()
export class AuthService {
constructor(
private readonly userService: UserService,
private readonly jwtService: JwtService,
) {}
async signIn(): Promise<object> {
// In the real-world app you shouldn't expose this method publicly
// instead, return a token once you verify user credentials
const user: any = { email: 'user#email.com' };
const token: string = this.jwtService.sign(user);
return { token };
}
async validateUser(payload: any): Promise<any> {
// Validate if token passed along with HTTP request
// is associated with any registered account in the database
return await this.userService.findOneByEmail(payload.email);
}
}
jwt.strategy.ts
import { ExtractJwt, Strategy } from 'passport-jwt';
import { AuthService } from './auth.service';
import { PassportStrategy } from '#nestjs/passport';
import { Injectable, UnauthorizedException } from '#nestjs/common';
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'secretKey',
});
}
async validate(payload: any) {
const user = await this.authService.validateUser(payload);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
Documentation: https://docs.nestjs.com/guards
Thanks for any help.
Additionally to your RolesGuard you need to use an AuthGuard.
Standard
You can use the standard AuthGuard implementation which attaches the user object to the request. It throws a 401 error, when the user is unauthenticated.
#UseGuards(AuthGuard('jwt'))
Extension
If you need to write your own guard because you need different behavior, extend the original AuthGuard and override the methods you need to change (handleRequest in the example):
#Injectable()
export class MyAuthGuard extends AuthGuard('jwt') {
handleRequest(err, user, info: Error) {
// don't throw 401 error when unauthenticated
return user;
}
}
Why do this?
If you look at the source code of the AuthGuard you can see that it attaches the user to the request as a callback to the passport method. If you don't want to use/extend the AuthGuard, you will have to implement/copy the relevant parts.
const user = await passportFn(
type || this.options.defaultStrategy,
options,
// This is the callback passed to passport. handleRequest returns the user.
(err, info, user) => this.handleRequest(err, info, user)
);
// Then the user object is attached to the request
// under the default property 'user' which you can change by configuration.
request[options.property || defaultOptions.property] = user;
You can attach multiple guards together (#UseGuards(AuthGuard('jwt'), RolesGuard)) to pass the context between them. Then you will have access 'req.user' object inside 'RolesGuard'.
After I got the selected answer working (thank you), I found this option as well that you can add to the constructor that essentially does the same thing.
http://www.passportjs.org/docs/authorize/
Association in Verify Callback
One downside to the approach described above is that it requires two
instances of the same strategy and supporting routes.
To avoid this, set the strategy's passReqToCallback option to true.
With this option enabled, req will be passed as the first argument to
the verify callback.
#Injectable()
export class LocalStrategy extends PassportStrategy(Strategy, 'local') {
constructor(private authService: AuthService) {
super({
passReqToCallback: true
})
}
// rest of the strategy (validate)
}
Does it work if you use req.authInfo?
As long as you don't provide a custom callback to passport.authenticate method, the user data should be attached to the request object like this.
req.authInfo should be the object you returned in your validate method

AngularFire2 return 'undefined' [object Object] with Angular 6

I try to get details from the firebase database but keep getting undefined
here is my code for getting the Object from the data base:
import { AppUser } from './models/app-user';
import { Injectable } from '#angular/core';
import { AngularFireDatabase, AngularFireObject } from 'angularfire2/database';
import * as firebase from 'firebase';
#Injectable({
providedIn: 'root'
})
export class UserService {
constructor(private db: AngularFireDatabase ) { }
get(uid: string): AngularFireObject<AppUser> {
console.log(this.db.object('/users/' + uid));
return this.db.object('/users/' + uid);
}
}
the console log from this get method is: [object Object]
I can't find how to get the username or other information of this user.
Here is my AppUser:
export interface AppUser {
email: string;
isAdmin: boolean;
name: string;
}
I found some answers, but it is related to older version of Angular, and is didn't help my issue.
I also saw some answer related to async pipe, but this is in the HTML, and I need the data to be available in a service.ts file.
I need to get the result in my component (not in the html).
I tried to extract the data of the user like that:
get appUser$(): Observable<AppUser> {
return this.user$
.pipe<AppUser>(map(user => {
if ( user ) {
this.userService.get(user.uid);
}
}));
}
but again the log say I got [object Object]...
In my final method that need to use this information:
canActivate() {
return this.auth.appUser$
.pipe(map(user => {
console.log(user);
return user.isAdmin;
}));
}
The console log give undefined
Use JSON.stringify
Console.log(JSON.stringify(this.db.object('/users/' + uid)));
You are returning a AngularFireDatabase.
You want to subscribe to AngularFireObject. so, you have to call :
get(uid: string): AngularFireObject<any> { // <----
console.log(this.db.object('/users/' + uid));
return this.db.object('/users/' + uid).valueChanges(); // <---
}
and than, you can subscribe and reveal the object in your component.
--Updated--
The current object type is AngularFireObject for single object and AngularFireList for a list of objects.
You still have to call .valueChanges() to get the observable.
I've managed to solve it with help from you, and other blogs. Thanks a lot!
Here is the full solution:
The user service.ts file:
import { AppUser } from './models/app-user';
import { Injectable } from '#angular/core';
import { AngularFireDatabase, AngularFireObject } from 'angularfire2/database';
import * as firebase from 'firebase';
#Injectable({
providedIn: 'root'
})
export class UserService {
constructor(private db: AngularFireDatabase ) { }
get(uid: string): AngularFireObject<AppUser> {
return this.db.object('/users/' + uid);
}
}
Here is the Authentication service.ts file:
import { AppUser } from './models/app-user';
import { pipe } from 'rxjs';
import { CanActivate } from '#angular/router';
import { Injectable } from '#angular/core';
import { UserService } from './user.service';
import { map } from 'rxjs/operators';
import * as firebase from 'firebase';
#Injectable({
providedIn: 'root'
})
export class AdminAuthGuard implements CanActivate {
fireBuser: firebase.User;
constructor(private userService: UserService) { }
canActivate() {
this.fireBuser = firebase.auth().currentUser;
return this.userService.get(this.fireBuser.uid)
.valueChanges()
.pipe(map((appUser: AppUser) => {
console.log(appUser.isAdmin);
return appUser.isAdmin;
}));
}
}
console.log(appUser.isAdmin) - give the correct property saved in the database.

How to access module info inside another module in TypeScript?

I'm working on a NativeScript app by using AngularJS2 & TypeScript. I've created one file config.ts for storing my API URL.
code for config.ts
export class Config {
apiUrl = "https://incandescent-fire-8397.firebaseio.com/";
}
Then from an another file called user.service.ts I'm trying to access apiUrl value. But, don't know how to do it. Tried couple of permutation & combination but till now no luck.
Code for user.service.ts
import {Injectable} from "#angular/core";
import {User} from "./user";
import Config = require("../config");
#Injectable()
export class UserService {
config: any;
constructor() {
this.config = new Config();
}
register(user: User) {
alert("API url going to use is : "+this.config.apiUrl);
}
}
Need some guidance.
Regards
------Issue Fixed-------
Updated the user.service.ts file
import {Injectable} from "#angular/core";
import {User} from "./user";
import {ConfigService} from "../config";
#Injectable()
export class UserService {
apiUrl = "https://incandescent-fire-8397.firebaseio.com/";
register(user: User,config:ConfigService) {
//alert("About to register: " + user.email);
alert("API url going to use is : "+config.apiUrl);
}
}
Then, the module(app.componets.ts) from where I'm accessing the register method updated like this -
import {Component} from "#angular/core";
import {User} from "./shared/user/user";
import {UserService} from "./shared/user/user.service";
import {ConfigService} from "./shared/config";
import {HTTP_PROVIDERS} from "#angular/http";
import firebase = require("nativescript-plugin-firebase");
#Component({
selector: "my-app",
providers: [UserService, HTTP_PROVIDERS,ConfigService],
templateUrl: "pages/login/login.html",
styleUrls: ["pages/login/login-common.css", "pages/login/login.css"]
})
export class AppComponent {
user: User;
isLoggingIn = true;
config:any;
constructor(private _userService: UserService, private _configSerice:ConfigService) {
this.user = new User();
this.config = new ConfigService();
}
submit() {
if (this.isLoggingIn) {
this.login();
} else {
this.signUp();
}
}
login() {
// TODO: Define
console.log('Clicked on Login button');
firebase.init(<any>{
persist: true // Allow disk persistence. Default false.
}).then(
function (instance) {
console.log("firebase.init done");
},
function (error) {
console.log("firebase.init error: " + error);
}
);
}
signUp() {
this._userService.register(this.user,this.config);
}
toggleDisplay() {
this.isLoggingIn = !this.isLoggingIn;
}
}
Don't know how much it's a right way to do. But, it's fixed the problem. Will appriciate a lot if someone know any better way to do this.
I thing you're initiating the Config module instead of the Config class inside it.
You can try adding the 'default' keyword to the "export class Config" line, or try initiating the config instance with "new Config.Config()".

Categories

Resources