Integrating Mollie payments in NestJS backend - module

I am trying to integrate Mollie payments into my NestJS backend.
To make a connection with Mollie, I have to use their MollieClient function. However, when I try to use it in a service I get the error:
Nest can't resolve dependencies of the NewUserService (UserService, MailService, ConfigService, JwtService, ?). Please make sure that the argument Object at index [4] is available in the NewUserModule context.
I am pretty sure this means I have to add a Mollie module/service to the NewUserModule, but I think the package doesn't actually come with a module made for NestJS. So if I try to make a Mollie module/service or use the MollieClient in another service, it asks me to provide it whilst I don't have anything to provide.
I'm pretty new to NestJS and backend development in general, so am I mistaken? Or is there a module added in the installed package?
If there isn't a module, should I make one? What exactly should be in such a module? Is there some sort of guide for it?
I realise this might be a rather vague series of questions, but I'm not very sure how to approach this.
Edit:
Rewrote the question for clarification.
Thanks in advance!

The message means, that Nest does not now how to resolve the 5th constructor argument of your NewUserService. I assume this is something like a MollieService?
You need to add MollieService as Provider to your NewUserModule:
#Module({
imports: [...],
controllers: [...],
providers: [
...otherProviders,
MollieService
]
})
export class NewUserModule {}
Or you can create a separate MollieModule and import it in NewUserModule:
#Module({
providers: [ MollieService ],
exports: [ MollieService ] // export MollieService, so that other modules can use it
})
export class MollieModule {}
#Module({
imports: [MollieModule],
controllers: [...],
providers: [...] // no need to provide MollieService here, because it's imported from MollieModule
})
export class NewUserModule {}
Of course you must also implement the MollieService using their SDK.
A recommend to read the Documentation on Modules. They are a little hard to understand at a first sight, but a powerful concept!
EDIT:
I would suggest to wrap the MollySDK in a service. This way you're not dealing with molly at various places in your app and prevent leaking it's api and types into your services.
#Injectable()
export class MollyService {
private readonly mollyClient: WhateverType;
constructor() {
this.mollyClient = createMollieClient({ apiKey: 'test_dHar4XY7LxsDOtmnkVtjNVWXLSlXsM' });
}
createPayment() {
this.mollieClient.payments.create({...});
}
}
This service could be injected as usual.
However if you really want to use the molly-client directly, you have to use a custom provider
#Module({
providers: [{
provides: 'MOLLY_CLIENT',
useFactory: () => createMollieClient({ apiKey: 'test_dHar4XY7LxsDOtmnkVtjNVWXLSlXsM' }) // you could also use useValue instead of useFactory
}],
exports: [ 'MOLLY_CLIENT' ]
})
export class MollieModule {}
Then inject it into NewUsersService like so:
constructor(#Inject('MOLLY_CLIENT')private readonly mollyClient: WhateverType) {}

Related

Spartacus Product Configurator - Authorization Code Flow breaks deep links

I am currently working on implementing the authorization code flow with Auth0 for our Spartacus application. The authentication works fine and I can navigate the page from the root. However when I try to access a deep link, e.g. /configure/vc/product/entityKey/key I get redirected to the Homepage. Same behaviour when I refresh the page.
I observed that the pages request gets canceled and instead the Router routes to "/". I don't see any Fail Actions being fired by ngrx.
Debugging the flow, I believe it has to do with the AuthService.checkOAuthParamsInUrl() method, which throws an exception in line
const result = await this.oAuthLibWrapperService.tryLogin(); (https://github.com/SAP/spartacus/blob/develop/projects/core/src/auth/user-auth/facade/auth.service.ts)
The method seems to check for the code inside the url, which is not available in deep links. I assumed it would take the token from the local storage if available.
Am I on the wrong track, or is the only possiblity to adjust the behaviour of the AuthService? If so, how should I go on with it?
Spartacus Version: 3.4.3.
rxjs Version: 6.6.7
[EDIT] My AuthConfig:
provideConfig(<AuthConfig>{
authentication: {
OAuthLibConfig: {
responseType: 'code',
redirectUri: environment.spartacus.auth.redirectUrl,
customQueryParams: {
connection: 'main-tenant-oidc',
audience: 'my-audience'
}
},
baseUrl: 'https://my-auth.auth0.com',
client_id: 'id',
client_secret: 'secret',
loginUrl: '/authorize',
tokenEndpoint: '/oauth/token',
userinfoEndpoint: '/userinfo',
revokeEndpoint: '/oauth/revoke'
}
})
[EDIT]
The AuthGuard confirms that the user is logged in, i.e. the isUserLoggedIn() function returns true.
[EDIT]
Updated to Spartacus 4 following the reference structure, no change of behaviour. I am configuring authentication via
routing: {protected: true}
My Feature Module looks like this, knowing that I definitly dont need all of the imports:
import {NgModule} from '#angular/core';
import {OrderConfirmationModule, ReplenishmentOrderConfirmationModule} from "#spartacus/checkout/components";
import {CheckoutOccModule} from "#spartacus/checkout/occ";
import {
AuthModule,
CartModule,
CartOccModule,
CostCenterOccModule,
ExternalRoutesModule,
ProductModule,
ProductOccModule,
UserOccModule
} from "#spartacus/core";
// TODO:Spartacus - 'ProductVariantsModule' was removed from #spartacus/storefront. Use #spartacus/product/variants feature-library instead. To benefit from lazy loading it by default, consider removing the module import and running the command 'ng add #spartacus/product --features=Product-Variants'.
// TODO:Spartacus - 'UserComponentModule' - Following module imports 'LoginModule', 'LoginFormModule', 'LoginRegisterModule', 'RegisterComponentModule' were removed. Those modules are now part of #spartacus/user.
import {
AddressBookModule,
BannerCarouselModule,
BannerModule,
BreadcrumbModule,
CartComponentModule,
CartPageEventModule,
CategoryNavigationModule,
CmsParagraphModule,
FooterNavigationModule,
HamburgerMenuModule,
LinkModule,
MyCouponsModule,
MyInterestsModule,
NavigationEventModule,
NavigationModule,
NotificationPreferenceModule,
OrderCancellationModule,
OrderDetailsModule,
OrderHistoryModule,
OrderReturnModule,
PaymentMethodsModule,
ProductCarouselModule,
ProductDetailsPageModule,
ProductFacetNavigationModule,
ProductImagesModule,
ProductIntroModule,
ProductListingPageModule,
ProductListModule,
ProductPageEventModule,
ProductReferencesModule,
ProductSummaryModule,
ProductTabsModule,
ReplenishmentOrderDetailsModule,
ReplenishmentOrderHistoryModule,
ReturnRequestDetailModule,
ReturnRequestListModule,
SearchBoxModule,
SiteContextSelectorModule,
StockNotificationModule,
TabParagraphContainerModule,
WishListModule
} from "#spartacus/storefront";
import {
CloseAccountModule,
ForgotPasswordModule,
RegisterComponentModule,
ResetPasswordModule,
UpdateEmailModule,
UpdatePasswordModule,
UpdateProfileModule
} from "#spartacus/user/profile/components";
import {ProductVariantsFeatureModule} from './features/product/product-variants-feature.module';
import {LoginFormModule, LoginModule, LoginRegisterModule} from "#spartacus/user/account/components";
import { UserFeatureModule } from './features/user/user-feature.module';
#NgModule({
declarations: [],
imports: [
// Migrating the StorefrontModule
ProductDetailsPageModule,
ProductListingPageModule,
ExternalRoutesModule.forRoot(),
// Migrating the CmsLibModule
HamburgerMenuModule,
CmsParagraphModule,
LinkModule,
BannerModule,
CategoryNavigationModule,
NavigationModule,
FooterNavigationModule,
BreadcrumbModule,
SearchBoxModule,
SiteContextSelectorModule,
AddressBookModule,
OrderHistoryModule,
OrderCancellationModule,
OrderReturnModule,
ReturnRequestListModule,
ReturnRequestDetailModule,
ProductListModule,
ProductFacetNavigationModule,
ProductTabsModule,
ProductCarouselModule,
ProductReferencesModule,
OrderDetailsModule,
PaymentMethodsModule,
CartComponentModule,
TabParagraphContainerModule,
OrderConfirmationModule,
ProductImagesModule,
ProductSummaryModule,
ProductIntroModule,
BannerCarouselModule,
MyCouponsModule,
WishListModule,
NotificationPreferenceModule,
MyInterestsModule,
StockNotificationModule,
ReplenishmentOrderHistoryModule,
ReplenishmentOrderConfirmationModule,
ReplenishmentOrderDetailsModule,
CloseAccountModule,
UpdateEmailModule,
UpdatePasswordModule,
UpdateProfileModule,
ForgotPasswordModule,
ResetPasswordModule,
// Migrating the StorefrontFoundationModule
AuthModule.forRoot(),
CartModule.forRoot(),
ProductModule.forRoot(),
// Migrating the OccModule
CartOccModule,
CheckoutOccModule,
ProductOccModule,
UserOccModule,
CostCenterOccModule,
// Migrating the EventsModule
CartPageEventModule,
NavigationEventModule,
ProductPageEventModule,
ProductVariantsFeatureModule,
// UserComponentModule Substitution
LoginModule,
LoginFormModule,
LoginRegisterModule,
RegisterComponentModule,
UserFeatureModule
]
})
export class SpartacusFeaturesModule {
}
[EDIT]
Important to notice: Our tokens are not being validated by SAP Commerce Backend. So it may be an issue with the error responses, that differ from the native error responses.
Thanks for any hints :)
The throw from this method is not unusual and is handled with the try-catch. This confirms even that if this throws we don't invoke this.authRedirectService.redirect(); method.
In my opinion the depth of the url should not make any difference to Auth handling. I would look either into other guards that could cause some redirect or into this code specific to this configurator routes.

How Passport strategy knows to pick the right jwt strategy in nestJS?

I m following this https://www.codemag.com/Article/2001081/Nest.js-Step-by-Step-Part-3-Users-and-Authentication for implementing jwt using passport in nestJS, everything is working as expected, but I have one question in this approach, if we use UseGuards(#AuthGurads()), the app knows to use passportstrategy to verify the token and call the validate method to proceed further, but how come passport strategy knows the right jwt strategy class to pick for calling the validate method, it is not explicitly mentioned that we are asking passport strategy to use jwtStrategy class and it is not a default export, but still how passportstrategy after validating the token calls the right JwtStrategy class for validate method ?
The important thing for the answer is in this code block: (pulled from the linked article)
#Module({
imports: [ ...,
PassportModule.register({
defaultStrategy: 'jwt',
property: 'user',
session: false,
}), ...
],
controllers: [AuthController],
providers: [AuthService, JwtStrategy],
exports: [PassportModule],
})
export class AuthModule {}
The defaultStrategy tells Nest "when I use AuthGuard(), take this strategy as the one to use". In this case, 'jwt'. Each passport strategy has a default name for passport to know what strategy is being used. In the case of passport-jwt it's (surprise, surprise) 'jwt'

How to init several root provided services on app initialization in Angular 8?

I have several initializable services that implement this simple interface:
interface InitializableService {
init(): void;
}
Those services make some global subscriptions (local and external) that I need during all the live of my app. What I do now is inject those services into my app.component.ts and call them one for one. I want to automate this process.
I have found some info about ways to do this and I just found ways to do it when providing the services into an module. I provide that services in root and I do not want to change this, besides the initial arrangement take the same time to just injecting them into app.components.ts.
I tried creating a base class and extend it so each class service that implement it would become "automatic initialized" on app load but I wasn't able to get the list of services that extend that class to call init on them.
I have no idea where to start to achieve this, or if this is even possible with provideIn: 'root' services.
Have you tried to use Modules with providers ?
solution is , to create a module , something like core.module.ts
then import the module into app.module.ts.
The key is , inside of core module , using module with providers , you can initial the those useful services.
Using provide in root , I just don't like it
core.module.ts Will be something like this
import { ModuleWithProviders, NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { UsersData } from './data/users';
import { UsersService } from './mock/users.service';
const DATA_SERVICES = [
{ provide: UsersData, useClass: UsersService },
];
#NgModule({
imports: [
CommonModule,
],
providers: []
})
export class CoreModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: CoreModule,
providers: [
...DATA_SERVICES,
]
} as ModuleWithProviders;
}
}

Nest.js: Circular dependencies in dynamic modules

What is the correct way to import dynamic modules when there's a circular dependency between them? I simply changed forwardRef(() => MyModule) to forwardRef(() => MyModule.forRoot()), and I'm getting Nest can't resolve dependencies error.
The best way to deal with nest module dependency is to import dependencies always through modules and never through services. If you run into a circular dependency, nest will show you an error and you can easily fix it with forwardRef().
let say your application has 3 tightly coupled modules.
#moduleA()
#moduleB()
#moduleC()
And two supporting modules
#moduleX()
#moduleY()
#moduleZ()
Also, all modules are exporting services with the same name.
Consider a situation where
#moduleA() imports [serviceB, serviceX]
And
#moduleB() imports [serviceA, serviceY, serviceZ]
Now in #moduleC() if you want to use serivceA() then you will have to
#moduleC() imports [serviceA, serviceB, serviceX, serviceY, serviceZ]
In most cases, nest throws the correct error saying which dependency is missing where. But some times, nest only says dependency at [index] is missing, nest doesn't says where it is missing. This will lead to great level of confusion.
A neat approach is to always import modules
#moduleA() imports [moduleB, moduleX]
#moduleB() imports [moduleA, moduleY, moduleZ]
#moduleC() imports [moduleA]
If nest is complaining again about dependency issue then import modules using forwardRef
#module({
imports: [
forwardRef(() => ModuleA)
ModuleB
],
controllers: [],
providers: []
})
Sometimes even after doing all these, you may again run into dependency not available error. Then you can use ModuleRef. Let's take the same example where you want to use ServiceA() in ModuleC()
You will then be adding serviceA() to providers[] in ModuleC() and in the serviceC() class you need to add the following.
import { Injectable, OnModuleInit } from '#nestjs/common'; \\need OnModuleInit
import { ServiceA} from '../FolderA/serviceA.service';
export class ServiceC implements OnModuleInit {
private serviceA: ServiceA;
constructor(private readonly moduleRef: ModuleRef) {}
onModuleInit() {
this.serviceA= this.moduleRef.get(ServiceA);
}
foo(){
console.log(this.serviceA.someFunction())
}
}
Please check more at Official documentation.

Global configuration of ngx-bootstrap datepicker format

Is it possible to globally configure a date format for the ngx-bootstrap datepicker?
The documentation mentions the BsDatepickerConfig class and how to pass it to each individual datepicker, but im a bit surprised that there seems to be no possibility to configure this globally (at least not documented)
https://valor-software.com/ngx-bootstrap/#/datepicker#bs-datepicker-config
This is not yet documented, but it can be achieved pretty easy. We have several demos of that for different components (tooltips, popovers, etc) and the code for datepicker will be almost the same. If you want to configure datepickers globally, replace basic BsDatepickerConfig with your one in providers section of your component or module.
export function getDatepickerConfig(): BsDatepickerConfig {
return Object.assign(new BsDatepickerConfig(), {
dateInputFormat: 'YYYY-MM-DD'
});
}
#NgModule({
...
providers: [{ provide: BsDatepickerConfig, useFactory: getDatepickerConfig }]
})
Example - https://stackblitz.com/edit/angular-tvahsw?file=app%2Fapp.module.ts