Skip to content

PM-1100 - endpoint for fetching trolley portal url #29

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 18, 2025

Conversation

vas3a
Copy link
Collaborator

@vas3a vas3a commented Apr 17, 2025

https://topcoder.atlassian.net/browse/PM-1100 - Implement GET /trolley/portal-link

Handles the implementation of the /trolley/portal-link endpoint as per ticket specifications.

@vas3a vas3a requested a review from kkartunov April 17, 2025 10:50
import { Roles, User } from 'src/core/auth/decorators';
import { UserInfo } from 'src/dto/user.dto';
import { Role } from 'src/core/auth/auth.constants';
import { ResponseDto } from 'src/dto/adminWinning.dto';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ResponseDto type seems to be imported from adminWinning.dto, which might not be the most appropriate place for a DTO related to payment providers. Consider creating a new DTO file or moving it to a more relevant location.

*/
private async getTrolleyPaymentMethod() {
const method = await this.prisma.payment_method.findUnique({
where: { payment_method_type: 'Trolley' },

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using a more specific error type instead of a generic Error to provide better error handling and debugging.


return this.prisma.$transaction(async (tx) => {
let userPaymentMethod = await tx.user_payment_methods.findFirst({
where: {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The findFirst method might return null if no record is found. Ensure that subsequent operations handle this case appropriately.

});
}

const updatedUserPaymentMethod = await tx.user_payment_methods.update({

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding error handling for the update method to manage potential update failures.

* @returns Trolley recipient DB model
*/
async getPayeeRecipient(user: UserInfo) {
const dbRecipient = await this.prisma.trolley_recipient.findUnique({

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding error handling for the findUnique method to manage cases where the recipient cannot be retrieved.

* @returns A URL string to the Trolley user portal.
*/
async getPortalUrlForUser(user: UserInfo) {
const recipient = await this.getPayeeRecipient(user);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding error handling for the getPayeeRecipient method to manage cases where the recipient cannot be retrieved or created.

@@ -49,6 +49,7 @@ export class RolesGuard implements CanActivate {
request.user = {
id: userId,
handle: userHandle,
email: request.email,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The request.email property is being used here, but it is not clear from the context if request.email is a valid property of the request object. Ensure that request.email is correctly set and available before this line to avoid potential runtime errors.

@@ -49,7 +51,7 @@ async function bootstrap() {
})
.build();
const document = SwaggerModule.createDocument(app, config, {
include: [ApiModule],
include: [ApiModule, PaymentProvidersModule, WebhooksModule],

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Including PaymentProvidersModule and WebhooksModule in the Swagger document might not be necessary for the /trolley/portal-link endpoint unless these modules are directly related to the endpoint's functionality. Please ensure that these modules are required for the new endpoint and remove them if they are not relevant.

import trolley from 'trolleyhq';
import { Injectable } from '@nestjs/common';

const { TORLLEY_ACCESS_KEY, TORLLEY_SECRET_KEY, TROLLEY_WIDGET_BASE_URL } =

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in environment variable name: TORLLEY_ACCESS_KEY should be TROLLEY_ACCESS_KEY.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vas3a please check.

import { Injectable } from '@nestjs/common';

const { TORLLEY_ACCESS_KEY, TORLLEY_SECRET_KEY, TROLLEY_WIDGET_BASE_URL } =
process.env;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in environment variable name: TORLLEY_SECRET_KEY should be TROLLEY_SECRET_KEY.

const widgetBaseUrl = new url.URL(TROLLEY_WIDGET_BASE_URL as string);
const querystring = new url.URLSearchParams({
ts: `${Math.floor(new Date().getTime() / 1000)}`,
key: TORLLEY_ACCESS_KEY,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in environment variable usage: TORLLEY_ACCESS_KEY should be TROLLEY_ACCESS_KEY.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vas3a please check

* - `AUTH0_M2M_GRANT_TYPE`: The grant type for the M2M token request.
*/
async getToken(): Promise<string | undefined> {
const tokenURL = `${process.env.AUTH0_TC_PROXY_URL}/token`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider checking if process.env.AUTH0_TC_PROXY_URL is defined before using it to construct tokenURL to prevent potential runtime errors.

return m2mToken;
} catch (error) {
// eslint-disable-next-line no-console
console.log('Failed fetching TC M2M Token!', error);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using console.log for error handling is not recommended in production code. Consider using a logging library or throwing an error to handle this more gracefully.

Copy link
Contributor

@kkartunov kkartunov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Let's fix typos and merge it...

import trolley from 'trolleyhq';
import { Injectable } from '@nestjs/common';

const { TORLLEY_ACCESS_KEY, TORLLEY_SECRET_KEY, TROLLEY_WIDGET_BASE_URL } =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vas3a please check.

const widgetBaseUrl = new url.URL(TROLLEY_WIDGET_BASE_URL as string);
const querystring = new url.URLSearchParams({
ts: `${Math.floor(new Date().getTime() / 1000)}`,
key: TORLLEY_ACCESS_KEY,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vas3a please check

import trolley from 'trolleyhq';
import { Injectable } from '@nestjs/common';

const { TROLLEY_ACCESS_KEY, TROLLEY_SECRET_KEY, TROLLEY_WIDGET_BASE_URL } =

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo fix: Corrected TORLLEY_ACCESS_KEY to TROLLEY_ACCESS_KEY. Ensure all instances of the typo are corrected.

import trolley from 'trolleyhq';
import { Injectable } from '@nestjs/common';

const { TROLLEY_ACCESS_KEY, TROLLEY_SECRET_KEY, TROLLEY_WIDGET_BASE_URL } =

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo fix: Corrected TORLLEY_SECRET_KEY to TROLLEY_SECRET_KEY. Ensure all instances of the typo are corrected.

process.env;

const client = trolley({
key: TROLLEY_ACCESS_KEY as string,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo fix: Corrected TORLLEY_ACCESS_KEY to TROLLEY_ACCESS_KEY. Ensure all instances of the typo are corrected.


const client = trolley({
key: TROLLEY_ACCESS_KEY as string,
secret: TROLLEY_SECRET_KEY as string,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo fix: Corrected TORLLEY_SECRET_KEY to TROLLEY_SECRET_KEY. Ensure all instances of the typo are corrected.

* @param recipient - recipient's details
* @returns A string representing the fully constructed and signed URL for the Trolley widget.
*
* @throws This function assumes that `TROLLEY_WIDGET_BASE_URL`, `TROLLEY_ACCESS_KEY`,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo correction needed: TORLLEY_ACCESS_KEY should be TROLLEY_ACCESS_KEY.

const widgetBaseUrl = new url.URL(TROLLEY_WIDGET_BASE_URL as string);
const querystring = new url.URLSearchParams({
ts: `${Math.floor(new Date().getTime() / 1000)}`,
key: TROLLEY_ACCESS_KEY,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo correction needed: TORLLEY_ACCESS_KEY should be TROLLEY_ACCESS_KEY.

.toString()
.replace(/\+/g, '%20');

const hmac = crypto.createHmac('sha256', TROLLEY_SECRET_KEY as string);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a typo in the variable name TORLLEY_SECRET_KEY. It has been corrected to TROLLEY_SECRET_KEY. Ensure that the corrected variable name is defined and used consistently throughout the codebase.

@@ -1,9 +1,11 @@
import axios from 'axios';
import { chunk } from 'lodash';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import statement for axios has been removed. If axios is no longer needed in this file, ensure that all references to it have been removed as well. If it is still needed, consider re-adding the import statement.

return axios
.get(requestUrl)
.then(({ data }) => data as { handle: string; userId: string });
return fetch(requestUrl).then(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding error handling for the fetch request to manage potential network errors or unsuccessful responses. This can help ensure that the application handles such scenarios gracefully.

) {
const { fields } = options;

let m2mToken: string | undefined;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider initializing m2mToken with a default value or handling the case where it remains undefined after the try-catch block. This will prevent potential runtime errors when m2mToken is used in the request headers.

const requestUrl = `${process.env.TOPCODER_API_BASE_URL}/members/${handle}${fields ? `?fields=${fields.join(',')}` : ''}`;

try {
const response: { [key: string]: string } = await fetch(requestUrl, {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fetch API returns a Response object, which requires checking response.ok to ensure the request was successful before calling response.json(). Consider adding error handling for non-2xx status codes.

Base automatically changed from PM-1073_trolley-webhooks to dev April 18, 2025 09:29
@vas3a vas3a merged commit 6290075 into dev Apr 18, 2025
1 check passed
@vas3a vas3a deleted the PM-1100_trolley-portal branch April 18, 2025 09:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants