feat: migrate from lemonsqueezy to polar (#535)
* feat: move from lemonsqueezy to polar * update lock * add migration files * test with demo product id
This commit is contained in:
@@ -21,6 +21,8 @@ interface LoadOutput {
|
||||
serverLang: string;
|
||||
}
|
||||
|
||||
const APP_SUBDOMAINS = env.PRIVATE_APP_SUBDOMAINS.split(',');
|
||||
|
||||
export const load = async ({ url, cookies, request }): Promise<LoadOutput> => {
|
||||
const response: LoadOutput = {
|
||||
orgSiteName: '',
|
||||
@@ -31,6 +33,8 @@ export const load = async ({ url, cookies, request }): Promise<LoadOutput> => {
|
||||
serverLang: request.headers?.get('accept-language') || ''
|
||||
};
|
||||
|
||||
console.log('IS_SELFHOSTED', IS_SELFHOSTED);
|
||||
|
||||
// Selfhosted usecase would be here
|
||||
if (IS_SELFHOSTED === 'true') {
|
||||
const subdomain = getSubdomain(url);
|
||||
@@ -72,7 +76,7 @@ export const load = async ({ url, cookies, request }): Promise<LoadOutput> => {
|
||||
|
||||
const isDev = dev || isLocalHost;
|
||||
|
||||
if (!url.host.includes('.classroomio.com') && !isLocalHost) {
|
||||
if (isURLCustomDomain(url)) {
|
||||
// Custom domain
|
||||
response.org = (await getCurrentOrg(url.host, true, true)) || null;
|
||||
|
||||
@@ -86,8 +90,15 @@ export const load = async ({ url, cookies, request }): Promise<LoadOutput> => {
|
||||
response.orgSiteName = response.org?.siteName || '';
|
||||
return response;
|
||||
} else if (!blockedSubdomain.includes(subdomain)) {
|
||||
if (APP_SUBDOMAINS.includes(subdomain)) {
|
||||
// This is an app domain specified in the .env file
|
||||
return response;
|
||||
}
|
||||
|
||||
const answer = !!subdomain;
|
||||
|
||||
console.log('subdomain', subdomain);
|
||||
|
||||
response.isOrgSite = debugMode || answer;
|
||||
response.orgSiteName = debugMode ? _orgSiteName : subdomain;
|
||||
response.org = (await getCurrentOrg(response.orgSiteName, true)) || null;
|
||||
@@ -99,7 +110,7 @@ export const load = async ({ url, cookies, request }): Promise<LoadOutput> => {
|
||||
}
|
||||
} else if (subdomain === 'play' || debugPlay === 'true') {
|
||||
response.skipAuth = true;
|
||||
} else if (!env.PRIVATE_APP_SUBDOMAINS.split(',').includes(subdomain) && !isDev) {
|
||||
} else if (!APP_SUBDOMAINS.includes(subdomain) && !isDev) {
|
||||
// This case is for anything in our blockedSubdomains
|
||||
throw redirect(307, 'https://app.classroomio.com');
|
||||
}
|
||||
@@ -107,6 +118,18 @@ export const load = async ({ url, cookies, request }): Promise<LoadOutput> => {
|
||||
return response;
|
||||
};
|
||||
|
||||
function isURLCustomDomain(url: URL) {
|
||||
if (url.host.includes('localhost')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const notCustomDomainHosts = [env.PRIVATE_APP_HOST || '', 'classroomio.com', 'vercel.app'].filter(
|
||||
Boolean
|
||||
);
|
||||
|
||||
return !notCustomDomainHosts.some((host) => url.host.endsWith(host));
|
||||
}
|
||||
|
||||
function getBaseMetaTags(url: URL) {
|
||||
return Object.freeze({
|
||||
title: 'ClassroomIO | The Open Source Learning Management System for Companies',
|
||||
@@ -145,8 +168,6 @@ function getBaseMetaTags(url: URL) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getSubdomain(url: URL) {
|
||||
const host = url.host.replace('www.', '');
|
||||
const parts = host.split('.');
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { env } from '$env/dynamic/private';
|
||||
import { getServerSupabase } from '$lib/utils/functions/supabase.server';
|
||||
import { cancelOrgPlan, createOrgPlan } from '$lib/utils/services/org';
|
||||
import { json } from '@sveltejs/kit';
|
||||
import crypto from 'crypto';
|
||||
import { env } from '$env/dynamic/private';
|
||||
import { createOrgPlan, cancelOrgPlan } from '$lib/utils/services/org';
|
||||
import { PLAN } from 'shared/src/plans/constants';
|
||||
import { getServerSupabase } from '$lib/utils/functions/supabase.server';
|
||||
|
||||
export async function POST({ request }) {
|
||||
try {
|
||||
@@ -30,10 +30,11 @@ export async function POST({ request }) {
|
||||
if (eventType === 'subscription_created' || eventType === 'subscription_resumed') {
|
||||
const orgId = body.meta.custom_data.org_id;
|
||||
const triggeredBy = body.meta.custom_data.triggered_by;
|
||||
const subscriptionId = body.data.id;
|
||||
const isSuccessful = body.data.attributes.status === 'active';
|
||||
|
||||
console.log({
|
||||
orgId,
|
||||
subscriptionId,
|
||||
triggeredBy,
|
||||
isSuccessful
|
||||
});
|
||||
@@ -41,6 +42,7 @@ export async function POST({ request }) {
|
||||
if (isSuccessful && orgId) {
|
||||
const { data, error } = await createOrgPlan({
|
||||
supabase,
|
||||
subscriptionId,
|
||||
orgId,
|
||||
triggeredBy: parseInt(triggeredBy),
|
||||
planName: PLAN.EARLY_ADOPTER,
|
||||
@@ -57,10 +59,10 @@ export async function POST({ request }) {
|
||||
`${eventType}`
|
||||
)
|
||||
) {
|
||||
const orgId = body.meta.custom_data.org_id;
|
||||
const subscriptionId = body.data.id;
|
||||
const { data, error } = await cancelOrgPlan({
|
||||
orgId,
|
||||
planName: PLAN.EARLY_ADOPTER
|
||||
subscriptionId,
|
||||
data: body.data
|
||||
});
|
||||
|
||||
if (error) console.error('Error canceling org plan', error);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { env } from '$env/dynamic/private';
|
||||
import { Checkout } from 'polar-sveltekit';
|
||||
|
||||
export const GET = ({ ...params }) => {
|
||||
const metadata = JSON.parse(params.url.searchParams.get('metadata') ?? '{}');
|
||||
const successUrl = `/org/${metadata.orgSlug}?upgrade=true&confirmation=true`;
|
||||
|
||||
const request = Checkout({
|
||||
accessToken: env.POLAR_ACCESS_TOKEN,
|
||||
successUrl
|
||||
});
|
||||
|
||||
return request(params);
|
||||
};
|
||||
@@ -0,0 +1,86 @@
|
||||
import { env } from '$env/dynamic/private';
|
||||
import { getServerSupabase } from '$lib/utils/functions/supabase.server';
|
||||
import { cancelOrgPlan, createOrgPlan, updateOrgPlan } from '$lib/utils/services/org';
|
||||
import type { PolarWebhookPayload } from '$lib/utils/types/polar';
|
||||
import { Webhooks } from 'polar-sveltekit';
|
||||
import { PLAN } from 'shared/src/plans/constants';
|
||||
|
||||
export const POST = Webhooks({
|
||||
webhookSecret: env.POLAR_WEBHOOK_SECRET!,
|
||||
onPayload
|
||||
});
|
||||
|
||||
async function onPayload(payload: PolarWebhookPayload) {
|
||||
const supabase = getServerSupabase();
|
||||
|
||||
const metadata = payload.data.metadata;
|
||||
const orgId = metadata.orgId;
|
||||
const triggeredBy = metadata.triggeredBy;
|
||||
const subscriptionId = payload.data.id;
|
||||
const isSubscriptionActive = payload.data.status === 'active';
|
||||
|
||||
console.log({
|
||||
orgId,
|
||||
triggeredBy,
|
||||
isSubscriptionActive,
|
||||
subscriptionId
|
||||
});
|
||||
|
||||
if (!orgId) {
|
||||
console.error('Org ID is required');
|
||||
throw new Error('Org ID is required');
|
||||
}
|
||||
|
||||
switch (payload.type) {
|
||||
case 'checkout.created':
|
||||
break;
|
||||
case 'checkout.updated':
|
||||
break;
|
||||
case 'subscription.created':
|
||||
if (isSubscriptionActive) {
|
||||
const { data, error } = await createOrgPlan({
|
||||
supabase,
|
||||
subscriptionId,
|
||||
orgId,
|
||||
triggeredBy: parseInt(triggeredBy),
|
||||
planName: PLAN.EARLY_ADOPTER,
|
||||
data: payload.data
|
||||
});
|
||||
|
||||
if (error) throw new Error('Error creating org plan');
|
||||
console.log('Subscription created', data);
|
||||
}
|
||||
break;
|
||||
case 'subscription.updated':
|
||||
if (!isSubscriptionActive) {
|
||||
// Handle Cancel Subscription
|
||||
const { data, error } = await cancelOrgPlan({
|
||||
subscriptionId,
|
||||
data: payload.data
|
||||
});
|
||||
|
||||
if (error) throw new Error('Error canceling org plan');
|
||||
console.log('Subscription canceled', data);
|
||||
} else {
|
||||
// Handle Update Subscription
|
||||
const { data, error } = await updateOrgPlan({
|
||||
supabase,
|
||||
subscriptionId,
|
||||
data: payload.data
|
||||
});
|
||||
|
||||
if (error) throw new Error('Error updating org plan');
|
||||
console.log('Subscription updated', data);
|
||||
}
|
||||
break;
|
||||
case 'subscription.active':
|
||||
break;
|
||||
case 'subscription.revoked':
|
||||
break;
|
||||
case 'subscription.canceled':
|
||||
break;
|
||||
default:
|
||||
console.log('Unknown event', payload.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user