Skip to content
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

fix: match payer email with registered email #1552

Merged
merged 3 commits into from
Jun 27, 2024
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
49 changes: 49 additions & 0 deletions src/controllers/StripeController/StripeController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import express from 'express';
import { getIndexFileContents } from '../IndexController/getIndexFileContents';
import { getDatabase } from '../../data_layer';
import { useDefaultEmailService } from '../../services/EmailService/EmailService';
import UsersRepository from '../../data_layer/UsersRepository';
import UsersService from '../../services/UsersService';
import TokenRepository from '../../data_layer/TokenRepository';
import AuthenticationService from '../../services/AuthenticationService';
import { getStripe } from '../../lib/integrations/stripe';
import { extractTokenFromCookies } from './extractTokenFromCookies';

export class StripeController {
async getSuccessfulCheckout(req: express.Request, res: express.Response) {
const cookies = req.get('cookie');
const token = extractTokenFromCookies(cookies);

if (!token) {
return res.send(getIndexFileContents());
}

const database = getDatabase();
const emailService = useDefaultEmailService();
const userRepository = new UsersRepository(database);
const usersService = new UsersService(userRepository, emailService);
const tokenRepository = new TokenRepository(database);
const authService = new AuthenticationService(
tokenRepository,
userRepository
);

const loggedInUser = await authService.getUserFrom(token);
const sessionId = req.query.session_id as string;

if (loggedInUser && sessionId) {
const stripe = getStripe();
const session = await stripe.checkout.sessions.retrieve(sessionId);
const email = session.customer_email;

if (loggedInUser.email !== email && email) {
await usersService.updateSubScriptionEmailUsingPrimaryEmail(
email.toLowerCase(),
loggedInUser.email.toLowerCase()
);
}
}

res.send(getIndexFileContents());
}
}
13 changes: 13 additions & 0 deletions src/controllers/StripeController/extractTokenFromCookies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export function extractTokenFromCookies(
cookies: string | undefined
): string | null {
if (!cookies) {
return null;
}

const cookiesArray = cookies.split('; ');
const tokenCookie = cookiesArray.find((cookie) =>
cookie.startsWith('token=')
);
return tokenCookie ? tokenCookie.split('=')[1] : null;
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import express from 'express';

import { INotionRepository } from '../data_layer/NotionRespository';
import { IUploadRepository } from '../data_layer/UploadRespository';
import NotionTokens from '../data_layer/public/NotionTokens';
import Uploads from '../data_layer/public/Uploads';
import NotionService from '../services/NotionService';
import UploadService from '../services/UploadService';
import { INotionRepository } from '../../data_layer/NotionRespository';
import { IUploadRepository } from '../../data_layer/UploadRespository';
import NotionTokens from '../../data_layer/public/NotionTokens';
import Uploads from '../../data_layer/public/Uploads';
import NotionService from '../../services/NotionService';
import UploadService from '../../services/UploadService';
import UploadController from './UploadController';

describe('Upload file', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import express from 'express';

import { getOwner } from '../lib/User/getOwner';
import { sendError } from '../lib/error/sendError';
import { getLimitMessage } from '../lib/misc/getLimitMessage';
import NotionService from '../services/NotionService';
import UploadService from '../services/UploadService';
import { getUploadHandler } from '../lib/misc/GetUploadHandler';
import { isLimitError } from '../lib/misc/isLimitError';
import { getOwner } from '../../lib/User/getOwner';
import { sendError } from '../../lib/error/sendError';
import NotionService from '../../services/NotionService';
import UploadService from '../../services/UploadService';
import { getUploadHandler } from '../../lib/misc/GetUploadHandler';
import { isLimitError } from '../../lib/misc/isLimitError';
import { handleUploadLimitError } from './helpers/handleUploadLimitError';

class UploadController {
constructor(
Expand Down Expand Up @@ -51,7 +51,7 @@ class UploadController {

handleUploadEndpoint(req, res, async (error) => {
if (isLimitError(error)) {
return res.status(500).send(getLimitMessage());
return handleUploadLimitError(req, res);
}
await this.service.handleUpload(req, res);
});
Expand Down
29 changes: 29 additions & 0 deletions src/controllers/Upload/helpers/handleUploadLimitError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import express from 'express';
import { useDefaultEmailService } from '../../../services/EmailService/EmailService';
import UsersService from '../../../services/UsersService';
import UsersRepository from '../../../data_layer/UsersRepository';
import { getDatabase } from '../../../data_layer';

export const handleUploadLimitError = async (
req: express.Request,
response: express.Response
) => {
const owner = response.locals.owner;

// If the user is already logged in, redirect to the pricing page
if (owner) {
const database = getDatabase();
const emailService = useDefaultEmailService();
const usersService = new UsersService(
new UsersRepository(database),
emailService
);

const user = await usersService.getUserById(response.locals.owner);
if (user) {
return response.redirect('/pricing?error=upload_limit_exceeded');
}
}

response.redirect('/login?error=upload_limit_exceeded');
};
12 changes: 8 additions & 4 deletions src/data_layer/UsersRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,19 @@ class UsersRepository {
]);
}

async updateSubscriptionLinkedEmail(owner: string, email: string) {
async linkCurrentUserWithEmail(owner: string, email: string) {
const user = await this.database(this.table).where({ id: owner }).first();
if (!user) {
return null;
}

return this.updateSubScriptionEmailUsingPrimaryEmail(user.email, email);
}

updateSubScriptionEmailUsingPrimaryEmail(email: string, newEmail: string) {
return this.database('subscriptions')
.where({ email: user.email })
.update({ linked_email: email.toLowerCase() });
.where({ email: email.toLowerCase() })
.update({ linked_email: newEmail.toLowerCase() });
}

async getSubscriptionLinkedEmail(owner: string) {
Expand All @@ -86,7 +90,7 @@ class UsersRepository {
}

const subscription: Subscriptions = await this.database('subscriptions')
.where({ email: user.email })
.where({ email: user.email.toLowerCase() })
.select('linked_email')
.first();
return subscription?.linked_email;
Expand Down
2 changes: 1 addition & 1 deletion src/routes/UploadRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import express from 'express';

import RequireAllowedOrigin from './middleware/RequireAllowedOrigin';
import RequireAuthentication from './middleware/RequireAuthentication';
import UploadController from '../controllers/UploadController';
import UploadController from '../controllers/Upload/UploadController';
import JobController from '../controllers/JobController';
import JobService from '../services/JobService';
import JobRepository from '../data_layer/JobRepository';
Expand Down
6 changes: 6 additions & 0 deletions src/routes/WebhookRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import {
updateStoreSubscription,
} from '../lib/integrations/stripe';
import { getDatabase } from '../data_layer';
import { StripeController } from '../controllers/StripeController/StripeController';

const WebhooksRouter = () => {
const router = express.Router();
const controller = new StripeController();

router.post(
'/webhook',
Expand Down Expand Up @@ -73,6 +75,10 @@ const WebhooksRouter = () => {
response.send();
}
);

router.get('/successful-checkout', (req, res) =>
controller.getSuccessfulCheckout(req, res)
);
return router;
};

Expand Down
4 changes: 2 additions & 2 deletions src/services/AuthenticationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class AuthenticationService {
async getIsSubscriber(owner: string, db: Knex, email: string) {
const linkedEmail = await db('subscriptions')
.select('active')
.where({ linked_email: email })
.where({ linked_email: email.toLowerCase() })
.first();

if (linkedEmail) {
Expand All @@ -129,7 +129,7 @@ class AuthenticationService {

const result = await db('subscriptions')
.select('active')
.where({ email: email })
.where({ email: email.toLowerCase() })
.first();

return result?.active ?? false;
Expand Down
8 changes: 7 additions & 1 deletion src/services/UploadService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import GeneratePackagesUseCase from '../usecases/uploads/GeneratePackagesUseCase
import { toText } from './NotionService/BlockHandler/helpers/deckNameToText';
import { getSafeFilename } from '../lib/getSafeFilename';
import { isPaying } from '../lib/isPaying';
import { isLimitError } from '../lib/misc/isLimitError';
import { handleUploadLimitError } from '../controllers/Upload/helpers/handleUploadLimitError';

class UploadService {
getUploadsByOwner(owner: number) {
Expand Down Expand Up @@ -76,7 +78,11 @@ class UploadService {
ErrorHandler(res, req, NO_PACKAGE_ERROR);
}
} catch (err) {
ErrorHandler(res, req, err as Error);
if (isLimitError(err as Error)) {
handleUploadLimitError(req, res);
} else {
return ErrorHandler(res, req, err as Error);
}
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion src/services/UsersService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,14 @@ class UsersService {
}

updateSubscriptionLinkedEmail(owner: string, email: string) {
return this.repository.updateSubscriptionLinkedEmail(owner, email);
return this.repository.linkCurrentUserWithEmail(owner, email);
}

updateSubScriptionEmailUsingPrimaryEmail(email: string, newEmail: string) {
return this.repository.updateSubScriptionEmailUsingPrimaryEmail(
email,
newEmail
);
}

getSubscriptionLinkedEmail(owner: string) {
Expand Down
Loading