Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/services/tiers.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import axios from 'axios';
import { FastifyBaseLogger } from 'fastify';
import { TiersRepository } from '../core/users/MongoDBTiersRepository';
import { UsersTiersRepository } from '../core/users/MongoDBUsersTiersRepository';
import { Service, Tier } from '../core/users/Tier';
Expand All @@ -8,6 +7,7 @@ import { BadRequestError } from '../errors/Errors';
import { MailService } from './mail.service';
import { StorageService } from './storage.service';
import { UsersService } from './users.service';
import Logger from '../Logger';

export class TierNotFoundError extends Error {
constructor(message: string) {
Expand Down Expand Up @@ -100,7 +100,7 @@ export class TiersService {
return tier;
}

async removeTier(userWithEmail: User & { email: string }, productId: string, log: FastifyBaseLogger): Promise<void> {
async removeTier(userWithEmail: User & { email: string }, productId: string): Promise<void> {
const tier = await this.tiersRepository.findByProductId({ productId });
const { uuid: userUuid } = userWithEmail;

Expand All @@ -117,7 +117,7 @@ export class TiersService {

switch (s) {
case Service.Drive:
await this.removeDriveFeatures(userUuid, tier, log);
await this.removeDriveFeatures(userUuid, tier);
break;
case Service.Vpn:
await this.removeVPNFeatures(userUuid, tier.featuresPerService['vpn']);
Expand Down Expand Up @@ -152,7 +152,7 @@ export class TiersService {
);
}

async removeDriveFeatures(userUuid: User['uuid'], tier: Tier, log: FastifyBaseLogger): Promise<void> {
async removeDriveFeatures(userUuid: User['uuid'], tier: Tier): Promise<void> {
const freeTier = await this.getTierProductsByProductsId('free');
const features = tier.featuresPerService[Service.Drive];

Expand All @@ -163,12 +163,12 @@ export class TiersService {
} catch (error) {
if (axios.isAxiosError(error) && error.response) {
const { status, data } = error.response;
log.error(
Logger.error(
`Failed to delete workspace for user ${userUuid}. Status: ${status}, Response: ${JSON.stringify(data)}`,
);
throw data;
} else {
log.error(`Unexpected error deleting workspace for user ${userUuid}: ${error}`);
Logger.error(`Unexpected error deleting workspace for user ${userUuid}: ${error}`);
throw error;
}
}
Expand Down
4 changes: 0 additions & 4 deletions src/webhooks/handleDisputeResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { StorageService } from '../services/storage.service';
import CacheService from '../services/cache.service';
import handleLifetimeRefunded from './handleLifetimeRefunded';
import { PaymentService } from '../services/payment.service';
import { FastifyBaseLogger } from 'fastify';
import { TiersService } from '../services/tiers.service';
import { PreCreatedUserService } from '../services/preCreatedUser.service';

Expand All @@ -16,7 +15,6 @@ interface HandleDisputeResultProps {
storageService: StorageService;
cacheService: CacheService;
tiersService: TiersService;
log: FastifyBaseLogger;
preCreatedUserService: PreCreatedUserService;
}

Expand All @@ -28,7 +26,6 @@ export async function handleDisputeResult({
storageService,
cacheService,
tiersService,
log,
preCreatedUserService,
}: HandleDisputeResultProps) {
if (dispute.status !== 'lost') {
Expand All @@ -51,7 +48,6 @@ export async function handleDisputeResult({
charge,
cacheService,
paymentService,
log,
tiersService,
preCreatedUserService,
);
Expand Down
17 changes: 8 additions & 9 deletions src/webhooks/handleFundsCaptured.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Stripe from 'stripe';
import { FastifyBaseLogger } from 'fastify';

import { PaymentService } from '../services/payment.service';
import { ObjectStorageService } from '../services/objectStorage.service';
Expand All @@ -8,13 +7,13 @@ import { UserType } from '../core/users/User';
import axios from 'axios';
import { VERIFICATION_CHARGE } from '../constants';
import { stripePaymentsAdapter } from '../infrastructure/adapters/stripe.adapter';
import Logger from '../Logger';

export default async function handleFundsCaptured(
paymentIntent: Stripe.PaymentIntent,
paymentsService: PaymentService,
objectStorageService: ObjectStorageService,
stripe: Stripe,
logger: FastifyBaseLogger,
): Promise<void> {
const isMissingType = !paymentIntent.metadata.type;
const isNotObjectStorage = paymentIntent.metadata.type !== 'object-storage';
Expand All @@ -28,13 +27,13 @@ export default async function handleFundsCaptured(
return;
}

logger.info(
Logger.info(
`Received successful payment intent ${paymentIntent.id} from customer ${paymentIntent.customer as string}`,
);

const customer = await stripePaymentsAdapter.getCustomer(paymentIntent.customer as string);

logger.info(`Object Storage for user ${customer.email} (customer ${customer.id}) is being initialized...`);
Logger.info(`Object Storage for user ${customer.email} (customer ${customer.id}) is being initialized...`);

const isPaymentIntentCanceled = paymentIntent.status === 'canceled';

Expand All @@ -44,7 +43,7 @@ export default async function handleFundsCaptured(
}
} catch (error) {
const err = error as Error;
logger.error(
Logger.error(
`[OBJECT STORAGE] Unexpected error while attempting to cancel the verification payment intent for user ${customer.id}. Error: ${err.message}`,
);

Expand All @@ -71,7 +70,7 @@ export default async function handleFundsCaptured(
}
} catch (error) {
const err = error as Error;
logger.error(
Logger.error(
`[OBJECT STORAGE] Unexpected error while attempting to create a user subscription for user ${customer.id}. Error: ${err.message}`,
);

Expand All @@ -88,15 +87,15 @@ export default async function handleFundsCaptured(
const { status, data } = error.response;

if (status === 409) {
logger.error('The user already has an Object Storage account activated');
Logger.error('The user already has an Object Storage account activated');
throw new ConflictError(error.message);
}

logger.error(`Unexpected error from Object Storage service [status=${status}]: ${JSON.stringify(data)}`);
Logger.error(`Unexpected error from Object Storage service [status=${status}]: ${JSON.stringify(data)}`);
}

throw error;
}

logger.info(`Object Storage for user ${customer.email} (customer ${customer.id}) has been initialized!`);
Logger.info(`Object Storage for user ${customer.email} (customer ${customer.id}) has been initialized!`);
}
15 changes: 7 additions & 8 deletions src/webhooks/handleInvoicePaymentFailed.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import Stripe from 'stripe';
import { FastifyLoggerInstance } from 'fastify';
import { PaymentService } from '../services/payment.service';
import { ObjectStorageService } from '../services/objectStorage.service';
import { UsersService } from '../services/users.service';
import { stripePaymentsAdapter } from '../infrastructure/adapters/stripe.adapter';
import Logger from '../Logger';

function isProduct(product: Stripe.Product | Stripe.DeletedProduct): product is Stripe.Product {
return (
Expand Down Expand Up @@ -45,7 +45,6 @@ export default async function handleInvoicePaymentFailed(
objectStorageService: ObjectStorageService,
paymentService: PaymentService,
usersService: UsersService,
logger: FastifyLoggerInstance,
): Promise<void> {
if (!invoice.customer) {
throw new Error('No customer found for this payment');
Expand All @@ -60,27 +59,27 @@ export default async function handleInvoicePaymentFailed(
const user = await usersService.findUserByCustomerID(customer.id);
if (user) {
await usersService.notifyFailedPayment(user.uuid);
logger.info(`Drive payment failure notification sent for customer ${customer.id} (user UUID: ${user.uuid})`);
Logger.info(`Drive payment failure notification sent for customer ${customer.id} (user UUID: ${user.uuid})`);
} else {
logger.warn(`User not found for customer ${customer.id}. Skipping failed payment notification.`);
Logger.warn(`User not found for customer ${customer.id}. Skipping failed payment notification.`);
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.error(`Failed to send payment notification for customer ${customer.id}. Error: ${errorMessage}`);
Logger.error(`Failed to send payment notification for customer ${customer.id}. Error: ${errorMessage}`);
}
logger.info(
Logger.info(
`Invoice ${invoice.id} does not contain an object storage product. Skipping object storage suspension...`,
);
return;
}

logger.info(
Logger.info(
`Handling invoice not paid ${invoice.id} for customer ${customer.id} > Suspending object storage account..`,
);

await objectStorageService.suspendAccount({ customerId: customer.id });

logger.info(
Logger.info(
`Handling invoice not paid ${invoice.id} for customer ${customer.id} > Object storage account suspended..`,
);
}
10 changes: 4 additions & 6 deletions src/webhooks/handleLifetimeRefunded.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { FastifyLoggerInstance } from 'fastify';
import CacheService from '../services/cache.service';
import { StorageService } from '../services/storage.service';
import { UsersService } from '../services/users.service';
Expand All @@ -8,14 +7,14 @@ import Stripe from 'stripe';
import { PaymentService } from '../services/payment.service';
import { Service } from '../core/users/Tier';
import { PreCreatedUserService } from '../services/preCreatedUser.service';
import Logger from '../Logger';

export default async function handleLifetimeRefunded(
storageService: StorageService,
usersService: UsersService,
charge: Stripe.Charge,
cacheService: CacheService,
paymentsService: PaymentService,
log: FastifyLoggerInstance,
tiersService: TiersService,
preCreatedUserService: PreCreatedUserService,
): Promise<void> {
Expand All @@ -35,7 +34,7 @@ export default async function handleLifetimeRefunded(
productId = product.id;
}

log.info(
Logger.info(
`[LIFETIME REFUNDED]: User with customerId ${customerId} found. The uuid of the user is: ${uuid} and productId: ${productId}`,
);

Expand All @@ -44,7 +43,7 @@ export default async function handleLifetimeRefunded(
await cacheService.clearUsedUserPromoCodes(customerId);
await cacheService.clearUserTier(uuid);
} catch (err) {
log.error(`Error in handleLifetimeRefunded after trying to clear ${customerId} subscription`);
Logger.error(`Error in handleLifetimeRefunded after trying to clear ${customerId} subscription`);
}

try {
Expand All @@ -55,12 +54,11 @@ export default async function handleLifetimeRefunded(
productId,
usersService,
tiersService,
log,
preCreatedUserService,
});
} catch (error) {
const err = error as Error;
log.error(`[LIFETIME REFUNDED/ERROR]: Error canceling tier product. ERROR: ${err.stack ?? err.message}`);
Logger.error(`[LIFETIME REFUNDED/ERROR]: Error canceling tier product. ERROR: ${err.stack ?? err.message}`);
if (!(error instanceof TierNotFoundError)) {
throw error;
}
Expand Down
20 changes: 8 additions & 12 deletions src/webhooks/handleSubscriptionCanceled.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { UserType } from './../core/users/User';
import { FastifyBaseLogger } from 'fastify';
import CacheService from '../services/cache.service';
import { StorageService } from '../services/storage.service';
import { UsersService } from '../services/users.service';
Expand All @@ -24,27 +23,26 @@ async function handleObjectStorageSubscriptionCancelled(
subscription: Stripe.Subscription,
objectStorageService: ObjectStorageService,
paymentService: PaymentService,
logger: FastifyBaseLogger,
): Promise<void> {
const activeSubscriptions = await paymentService.getActiveSubscriptions(customer.id);
const objectStorageActiveSubscriptions = activeSubscriptions.filter(
(s) => s.product?.metadata.type === 'object-storage',
);

if (objectStorageActiveSubscriptions.length > 0) {
logger.info(
Logger.info(
`Preventing removal of an object storage customer ${customer.id} with sub ${subscription.id} due to the existence of another active subscription`,
);
return;
}

logger.info(`Deleting object storage customer ${customer.id} with sub ${subscription.id}`);
Logger.info(`Deleting object storage customer ${customer.id} with sub ${subscription.id}`);

await objectStorageService.suspendAccount({
customerId: customer.id,
});

logger.info(`Object storage customer ${customer.id} with sub ${subscription.id} deleted successfully`);
Logger.info(`Object storage customer ${customer.id} with sub ${subscription.id} deleted successfully`);
}

export default async function handleSubscriptionCanceled(
Expand All @@ -55,7 +53,6 @@ export default async function handleSubscriptionCanceled(
cacheService: CacheService,
objectStorageService: ObjectStorageService,
tiersService: TiersService,
log: FastifyBaseLogger,
preCreatedUserService: PreCreatedUserService,
): Promise<void> {
const customerId = subscription.customer as string;
Expand All @@ -64,15 +61,15 @@ export default async function handleSubscriptionCanceled(
const customer = await stripePaymentsAdapter.getCustomer(customerId);

if (isObjectStorageProduct(productMetadata)) {
await handleObjectStorageSubscriptionCancelled(customer, subscription, objectStorageService, paymentService, log);
await handleObjectStorageSubscriptionCancelled(customer, subscription, objectStorageService, paymentService);
return;
}

const { uuid, lifetime: hasBoughtALifetime } = await usersService.findUserByCustomerID(customerId);

const productType = productMetadata?.type === UserType.Business ? UserType.Business : UserType.Individual;

log.info(
Logger.info(
`[SUB CANCEL]: User with customerId ${customerId} found. The uuid of the user is: ${uuid} and productId: ${productId}`,
);

Expand All @@ -81,11 +78,11 @@ export default async function handleSubscriptionCanceled(
await cacheService.clearUsedUserPromoCodes(customerId);
await cacheService.clearUserTier(uuid);
} catch (err) {
log.error(`Error in handleSubscriptionCanceled after trying to clear ${customerId} subscription`);
Logger.error(`Error in handleSubscriptionCanceled after trying to clear ${customerId} subscription`);
}

if (hasBoughtALifetime && productType === UserType.Individual) {
log.info(`User with uuid ${uuid} has a lifetime subscription. No need to downgrade the user.`);
Logger.info(`User with uuid ${uuid} has a lifetime subscription. No need to downgrade the user.`);
// This user has switched from a subscription to a lifetime, therefore we do not want to downgrade his space
// The space should not be set to Free plan.
return;
Expand All @@ -98,12 +95,11 @@ export default async function handleSubscriptionCanceled(
productId,
usersService,
tiersService,
log,
preCreatedUserService,
});
} catch (error) {
const err = error as Error;
log.error(`[SUB CANCEL/ERROR]: Error canceling tier product. ERROR: ${err.stack ?? err.message}`);
Logger.error(`[SUB CANCEL/ERROR]: Error canceling tier product. ERROR: ${err.stack ?? err.message}`);

if (!(error instanceof TierNotFoundError)) {
throw error;
Expand Down
Loading
Loading