Change credentials in typeorm denpendig of user logged - postgresql

I'm working with nestjs and typeorm to connect to postgres database I want to change the credentials of the connection in runtime depending of the role of the user logged. There is any way to achieve that?
#Module({
imports: [
TypeOrmModule.forRootAsync({
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
type: 'postgres',
host: configService.get<string>('database.host'),
port: configService.get<number>('database.port'),
database: configService.get<string>('database.name'),
autoLoadEntities: true,
//I want these two properties to be dynamic
username: configService.get<string>('database.user'),
password: configService.get<string>('database.password'),
})
}),
]
})
export class AppModule {}

Related

Can't connect to mongodb Atlas with typeorm

I'm trying to connect to a MongoDB Atlas database with typeORM in an express project but I'm getting a 'Unescaped slash in userinfo section' error. My password doesn't have any special characters that need to be encoded so I don't know what's going on.
import { DataSource } from "typeorm"
export const AppDataSource = new DataSource({
type: "mongodb",
host: "mongodb+srv://username:password#database.cluster.mongodb.net/?retryWrites=true&w=majority",
useNewUrlParser: true,
synchronize: true,
useUnifiedTopology: true,
logging: true,
ssl: true,
entities: [
"src/entity/*.ts"
],
subscribers: [],
migrations: [],
})
"use strict";
import express from "express";
import cors from 'cors';
import "reflect-metadata";
import { AppDataSource } from "./data-source";
AppDataSource.initialize().then(() => {
const app = express();
app.use(cors({
origin: ['http://localhost:3000'],
credentials: true // this will allow cookies to be sent accross domains
}));
app.listen(8080, () => {
console.log("Server is running on port 8080");
})
})
the error I'm getting :
return callback(new MongoParseError('Unescaped slash in userinfo section'));
^
MongoParseError: Unescaped slash in userinfo section
at parseConnectionString (D:\Personal\jamboit\backend\node_modules\mongodb\lib\core\uri_parser.js:627:21)
at connect (D:\Personal\jamboit\backend\node_modules\mongodb\lib\operations\connect.js:283:3)
at D:\Personal\jamboit\backend\node_modules\mongodb\lib\mongo_client.js:284:5
at maybePromise (D:\Personal\jamboit\backend\node_modules\mongodb\lib\utils.js:692:3)
at MongoClient.connect (D:\Personal\jamboit\backend\node_modules\mongodb\lib\mongo_client.js:280:10)
at Function.MongoClient.connect (D:\Personal\jamboit\backend\node_modules\mongodb\lib\mongo_client.js:426:22)
at D:\Personal\jamboit\backend\node_modules\typeorm\src\driver\mongodb\MongoDriver.ts:249:38
at new Promise (<anonymous>)
Just replace host params to url in DataSource options
export const AppDataSource = new DataSource({
type: "mongodb",
url: "mongodb+srv://username:password#database.cluster.mongodb.net/?retryWrites=true&w=majority",
useNewUrlParser: true,
synchronize: true,
useUnifiedTopology: true,
logging: true,
ssl: true,
entities: [
"src/entity/*.ts"
],
subscribers: [],
migrations: [],
})

How to Authenticate and Retrive data Google JWT in NestJs

I am working on nestjs backend app.I have google access token from google auth playground and i want to retrieve user data from this token using jwt ex. like curl http://locahost:3000/user/profile -H "Authorization : Bearer jwt".I have used jwt strategy from stackoverflow Authenticate Google JWT in NestJs question but unable to get data getting unauthorized error.
Below is my code and jwt strategy
JWT Stragy:
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private configService: ConfigService){
super({
secretOrKeyProvider: passportJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: 'https://www.googleapis.com/oauth2/v3/certs',
}),
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
issuer: 'https://accounts.google.com',
algorithms: ['RS256'],
});
}
async validate(payload: any): Promise<unknown> {
// const { email } = payload;
console.log('payload t',payload)
return payload;
}
}
App module:
#Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
// JwtModule.register({
// secretOrPrivateKey: 'secretKey',
// signOptions: { expiresIn: '60s' },
// }),
AuthModule
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Auth module:
#Module({
imports: [
ConfigModule.forRoot(),
],
providers: [JwtStrategy],
exports: [JwtStrategy],
})
export class AuthModule {}

Use more than one MongoDb collection in a single app

I have an app which uses MongoDb and I am connecting to MongoDb by calling MongooseModule.forRoot in replies.module.ts, now I have another module called replies.module.ts and I want to connect to another collection but in the same database, should I use the same method in the new module and just change the collection name? does it won't create a duplicate connection to mongo? what is the best practice for that?
Reviews module: reviews.module.ts
#Module({
imports: [
MongooseModule.forRoot('mongodb+srv://user:password#url/reviews?retryWrites=true&w=majority',),
MongooseModule.forFeature([{name: 'Review', schema: ReviewSchema}
])],
controllers: [ReviewsController],
providers: [ReviewsService]
})
Replies module: replies.module.ts
#Module({
imports: [
MongooseModule.forRoot('mongodb+srv://user:password#url/replies?retryWrites=true&w=majority',),
MongooseModule.forFeature([{name: 'Replies', schema: RepliesSchema}
])],
controllers: [RepliesController],
providers: [RepliesService]
})
I think you can do what you want by naming your connections:
app.module.ts:
#Module({
imports: [
MongooseModule.forRoot('mongodb+srv://user:password#url/reviews?retryWrites=true&w=majority', { connectionName: 'ReviewsDB' }),
MongooseModule.forRoot('mongodb+srv://user:password#url/replies?retryWrites=true&w=majority', { connectionName: 'RepliesDB' })
]})
export class AppModule implements NestModule {}
Then you can use your models, for examples in dedicatied modules:
review.module.ts :
#Module({
imports: [
MongooseModule.forFeature([{ name: Review.name, schema: ReviewSchema }], 'ReviewsDB')
],
providers: [ReviewService],
exports: [ReviewService],
})
export class ReviewModule {}
And the for replies:
reply.module.ts :
#Module({
imports: [
MongooseModule.forFeature([{ name: Reply.name, schema: ReplySchema }], 'RepliesDB')
],
providers: [ReplyService],
exports: [ReplyService],
})
export class ReplyModule {}
Do not forget to set the connection name of the wanted database in your forFeature declaration

NestJs: Query multiple entities from multiple database

I have mysql_server_1.database1.users
And mysql_server_2.database3.users_revenue
How can I query rows from users
How can I query rows from users_revenue
First, I've already setup the connections:
const mysql1__database1 = TypeOrmModule.forRootAsync({
imports: [ConfigModule],
// #ts-ignore
useFactory: (configService: ConfigService) => ({
type: configService.get("DASHBOARD_DB_TYPE"),
host: configService.get("DASHBOARD_DB_HOST"),
port: configService.get("DASHBOARD_DB_PORT"),
username: configService.get("DASHBOARD_DB_USER"),
password: configService.get("DASHBOARD_DB_PASSWORD"),
database: configService.get("DASHBOARD_DB_NAME"),
entities: [__dirname + '/**/*.entity{.ts,.js}'],
// entities: [User],
autoLoadEntities: true,
synchronize: true,
}),
inject: [ConfigService],
});
const mysql2__database3 = TypeOrmModule.forRootAsync({
imports: [ConfigModule],
// #ts-ignore
useFactory: (configService: ConfigService) => ({
name: 'mysql2__database3',
type: configService.get("DASHBOARD2_DB_TYPE"),
host: configService.get("DASHBOARD2_DB_HOST"),
port: configService.get("DASHBOARD2_DB_PORT"),
username: configService.get("DASHBOARD2_DB_USER"),
password: configService.get("DASHBOARD2_DB_PASSWORD"),
database: configService.get("DASHBOARD2_DB_NAME"),
entities: [__dirname + '/**/*.entity{.ts,.js}'],
// entities: [User],
autoLoadEntities: true,
synchronize: true,
}),
inject: [ConfigService],
});
#Module({
imports: [
mysql1__database1,
mysql2__database3,
StatsModule,
],
controllers: [AppController],
providers: [AppService, StatsService],
})
export class AppModule {}
user.service.ts
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
#Injectable()
export class UserService {
constructor(#InjectRepository(User) private usersRepository: Repository<User>) {}
async findAll(): Promise<User[]> {
return await this.usersRepository.find();
}
}
Then this code return an empty array instead of so many rows exists in my database;
const items = await this.userService.findAll();
--- update ---
I've take a look at the typeorm source code:
https://github.com/nestjs/typeorm/blob/8af34889fa7bf14d7dc5541beef1d5c2b50c2609/lib/common/typeorm.decorators.ts#L13
Then https://docs.nestjs.com/techniques/database#multiple-databases
At this point, you have User and Album entities registered with their own connection. With this setup, you have to tell the TypeOrmModule.forFeature() method and the #InjectRepository() decorator which connection should be used. If you do not pass any connection name, the default connection is used.
So I think it should work?
#InjectRepository(User, 'mysql2_database3')
#Module({
imports: [
TypeOrmModule.forFeature([User], "mysql2_database3"),
],
providers: [UserService],
controllers: [StatsController],
})
export class StatsModule {}
Still got the error:
Please make sure that the argument mysql2_database3Connection at index [0] is available in the TypeOrmModule context.
Thank to #jmc29 on discord, his guide helped
The solution is:
const mysql2__database3 = TypeOrmModule.forRootAsync({
imports: [ConfigModule],
// #ts-ignore
useFactory: (configService: ConfigService) => ({
name: 'mysql2__database3',
type: configService.get("DASHBOARD2_DB_TYPE"),
host: configService.get("DASHBOARD2_DB_HOST"),
port: configService.get("DASHBOARD2_DB_PORT"),
username: configService.get("DASHBOARD2_DB_USER"),
password: configService.get("DASHBOARD2_DB_PASSWORD"),
database: configService.get("DASHBOARD2_DB_NAME"),
entities: [__dirname + '/**/*.entity{.ts,.js}'],
autoLoadEntities: true,
synchronize: true,
}),
inject: [ConfigService],
});
add one more line:
const mysql2__database3 = TypeOrmModule.forRootAsync({
name: 'mysql2__database3', // -----> Add this line, it's is required
imports: [ConfigModule],
// #ts-ignore
useFactory: (configService: ConfigService) => ({
name: 'mysql2__database3',
type: configService.get("DASHBOARD2_DB_TYPE"),
host: configService.get("DASHBOARD2_DB_HOST"),
port: configService.get("DASHBOARD2_DB_PORT"),
username: configService.get("DASHBOARD2_DB_USER"),
password: configService.get("DASHBOARD2_DB_PASSWORD"),
database: configService.get("DASHBOARD2_DB_NAME"),
entities: [__dirname + '/**/*.entity{.ts,.js}'],
autoLoadEntities: true,
synchronize: true,
}),
inject: [ConfigService],
});
for those who face this problem , this is my solution
AppModule
#Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
load: [
database,
databaseAllo
]
}),
TypeOrmModule.forRootAsync({
useFactory: (configs: ConfigService) => configs.get("db_config"),
inject: [ConfigService],
}),
TypeOrmModule.forRootAsync({
name:"db_allo", <= create connection to my second db
useFactory: (configs: ConfigService) => configs.get("db_config_allo"),
inject: [ConfigService],
}),
AuthModule,
JwtAuthModule
],
controllers: []
})
export class AppModule {}
my project module ( contain table from second db )
#Module({
imports: [
TypeOrmModule.forFeature([AlloMpcTable], "db_allo" <= call connection again),
],
providers: [
AlloRepository
],
exports: [AlloRepository],
controllers: [],
})
export class AlloModule {}
my project repository
#Injectable()
export class AlloRepository extends BaseRepository<AlloMpcTable> {
constructor(
#InjectRepository(AlloMpcTable, "db_allo") <= you need to call connection again
private readonly allo: Repository<AlloMpcTable>,
) {
super(allo)
}
public async Find(id: number): Promise<AlloMpcTable> {
return await this.allo.findOne(id)
}
}
so in your case, you need to call "mysql2_database3" again in your providers: [UserService]

Sails.js more database connection

Blockquote
i will planing use more database on same models on sails.Just wanna change db on progress.How can i do it on sails configure
Just change your connection config in config/connections.js to the db you will be using, then, in the model set the connection, example:
Connection
mysql: {
adapter: 'sails-mysql',
host: 'your-host',
user: 'user',
password: 'pass',
database: 'your-db'
port: 3306
}
Model
module.exports = {
schema: true,
connection: 'mysql',
tableName: 'users',
attributes: {
user:{
type:"string",
primaryKey: true,
unique: true
},
password:{
type:"string",
unique: true
}
}
};