From f06d7d78fc204276f480e63faa9a7295d631a833 Mon Sep 17 00:00:00 2001 From: Emily Date: Fri, 8 Nov 2024 15:14:09 +0100 Subject: [PATCH] add code redeem --- dashboard/components/settings/Codes.vue | 58 +++++++++++++++++++ dashboard/pages/settings.vue | 4 ++ ...de.post.ts => redeem_appsumo_code.post.ts} | 18 +++--- dashboard/server/api/pay/valid_codes.ts | 14 +++++ dashboard/server/api/pay/webhook.post.ts | 2 +- dashboard/server/services/AppsumoService.ts | 19 +++++- shared/data/PREMIUM.ts | 6 +- .../{AppsumoCode.ts => AppsumoCodeSchema.ts} | 0 shared/schema/AppsumoCodeTrySchema.ts | 15 +++++ 9 files changed, 120 insertions(+), 16 deletions(-) create mode 100644 dashboard/components/settings/Codes.vue rename dashboard/server/api/pay/{redeem_code.post.ts => redeem_appsumo_code.post.ts} (76%) create mode 100644 dashboard/server/api/pay/valid_codes.ts rename shared/schema/{AppsumoCode.ts => AppsumoCodeSchema.ts} (100%) create mode 100644 shared/schema/AppsumoCodeTrySchema.ts diff --git a/dashboard/components/settings/Codes.vue b/dashboard/components/settings/Codes.vue new file mode 100644 index 0000000..22067fa --- /dev/null +++ b/dashboard/components/settings/Codes.vue @@ -0,0 +1,58 @@ + + + + diff --git a/dashboard/pages/settings.vue b/dashboard/pages/settings.vue index e9ed830..a1d40b9 100644 --- a/dashboard/pages/settings.vue +++ b/dashboard/pages/settings.vue @@ -7,6 +7,7 @@ const items = [ { label: 'General', slot: 'general' }, { label: 'Members', slot: 'members' }, { label: 'Billing', slot: 'billing' }, + { label: 'Codes', slot: 'codes' }, { label: 'Account', slot: 'account' } ] @@ -27,6 +28,9 @@ const items = [ + diff --git a/dashboard/server/api/pay/redeem_code.post.ts b/dashboard/server/api/pay/redeem_appsumo_code.post.ts similarity index 76% rename from dashboard/server/api/pay/redeem_code.post.ts rename to dashboard/server/api/pay/redeem_appsumo_code.post.ts index 414ed01..c46a453 100644 --- a/dashboard/server/api/pay/redeem_code.post.ts +++ b/dashboard/server/api/pay/redeem_appsumo_code.post.ts @@ -1,9 +1,7 @@ import { getPlanFromId } from "@data/PREMIUM"; -import StripeService from '~/server/services/StripeService'; import { PREMIUM_PLAN } from "../../../../shared/data/PREMIUM"; -import { checkAppsumoCode, useAppsumoCode } from "~/server/services/AppsumoService"; - - +import { canTryAppsumoCode, checkAppsumoCode, useAppsumoCode, useTryAppsumoCode } from "~/server/services/AppsumoService"; +import StripeService from '~/server/services/StripeService'; function getPlanToActivate(current_plan_id: number) { if (current_plan_id === PREMIUM_PLAN.FREE.ID) { @@ -28,24 +26,26 @@ export default defineEventHandler(async event => { const data = await getRequestData(event, { requireSchema: false, allowGuests: false, allowLitlyx: false }); if (!data) return; - const { project, pid } = data; + const { project, pid, user } = data; const body = await readBody(event); const { code } = body; - const valid = await checkAppsumoCode(code); + const canTry = await canTryAppsumoCode(pid); + if (!canTry) return setResponseStatus(event, 400, 'You tried too much codes. Please contact support.'); + await useTryAppsumoCode(pid, code); - if (!valid) return setResponseStatus(event, 400, 'Current plan not found'); + const valid = await checkAppsumoCode(code); + if (!valid) return setResponseStatus(event, 400, 'Code not valid'); const currentPlan = getPlanFromId(project.premium_type); if (!currentPlan) return setResponseStatus(event, 400, 'Current plan not found'); const planToActivate = getPlanToActivate(currentPlan.ID); if (!planToActivate) return setResponseStatus(event, 400, 'Cannot use code on current plan'); - await StripeService.deleteSubscription(project.subscription_id); await StripeService.createSubscription(project.customer_id, planToActivate.ID); - await useAppsumoCode(code); + await useAppsumoCode(pid, code); }); \ No newline at end of file diff --git a/dashboard/server/api/pay/valid_codes.ts b/dashboard/server/api/pay/valid_codes.ts new file mode 100644 index 0000000..77348b7 --- /dev/null +++ b/dashboard/server/api/pay/valid_codes.ts @@ -0,0 +1,14 @@ +import { AppsumoCodeTryModel } from "@schema/AppsumoCodeTrySchema"; + +export default defineEventHandler(async event => { + + const data = await getRequestData(event, { requireSchema: false, allowGuests: false, allowLitlyx: false }); + if (!data) return; + + const { pid } = data; + + const tryRes = await AppsumoCodeTryModel.findOne({ project_id: pid }, { valid_codes: 1 }); + if (!tryRes) return { count: 0 } + return { count: tryRes.valid_codes.length } + +}); \ No newline at end of file diff --git a/dashboard/server/api/pay/webhook.post.ts b/dashboard/server/api/pay/webhook.post.ts index 3727a3a..426057d 100644 --- a/dashboard/server/api/pay/webhook.post.ts +++ b/dashboard/server/api/pay/webhook.post.ts @@ -133,7 +133,7 @@ async function onPaymentSuccess(event: Event.InvoicePaidEvent) { if (!price) return { error: 'Price not found' } const PLAN = getPlanFromPrice(price, StripeService.testMode || false); - if (!PLAN) return { error: 'Plan not found' } + if (!PLAN) return { error: `Plan not found. Price: ${price}. TestMode: ${StripeService.testMode}` } await addSubscriptionToProject(project._id.toString(), PLAN, subscription_id, currentSubscription.current_period_start, currentSubscription.current_period_end) diff --git a/dashboard/server/services/AppsumoService.ts b/dashboard/server/services/AppsumoService.ts index 4ff0b9f..1e7d686 100644 --- a/dashboard/server/services/AppsumoService.ts +++ b/dashboard/server/services/AppsumoService.ts @@ -1,13 +1,26 @@ -import { AppsumoCodeModel } from '@schema/AppsumoCode' +import { AppsumoCodeModel } from '@schema/AppsumoCodeSchema'; +import { AppsumoCodeTryModel } from '@schema/AppsumoCodeTrySchema'; + + +export async function canTryAppsumoCode(project_id: string) { + const tries = await AppsumoCodeTryModel.findOne({ project_id }); + if (!tries) return true; + if (tries.codes.length >= 30) return false; + return true; +} + +export async function useTryAppsumoCode(project_id: string, code: string) { + await AppsumoCodeTryModel.updateOne({ project_id }, { $push: { codes: code } }, { upsert: true }); +} export async function checkAppsumoCode(code: string) { const target = await AppsumoCodeModel.exists({ code, used_at: { $exists: false } }); return target; } - -export async function useAppsumoCode(code: string) { +export async function useAppsumoCode(project_id: string, code: string) { + await AppsumoCodeTryModel.updateOne({ project_id }, { $push: { valid_codes: code } }, { upsert: true }); await AppsumoCodeModel.updateOne({ code }, { used_at: Date.now() }); } \ No newline at end of file diff --git a/shared/data/PREMIUM.ts b/shared/data/PREMIUM.ts index 00a502e..8914965 100644 --- a/shared/data/PREMIUM.ts +++ b/shared/data/PREMIUM.ts @@ -131,7 +131,7 @@ export const PREMIUM_PLAN: Record = { ID: 6001, COUNT_LIMIT: 50_000, AI_MESSAGE_LIMIT: 30, - PRICE: '', + PRICE: 'price_1QIXwbB2lPUiVs9VKSsoksaU', PRICE_TEST: '', COST: 0 }, @@ -139,7 +139,7 @@ export const PREMIUM_PLAN: Record = { ID: 6002, COUNT_LIMIT: 150_000, AI_MESSAGE_LIMIT: 100, - PRICE: '', + PRICE: 'price_1QIXxRB2lPUiVs9VrjaVRoOl', PRICE_TEST: '', COST: 0 }, @@ -147,7 +147,7 @@ export const PREMIUM_PLAN: Record = { ID: 6003, COUNT_LIMIT: 500_000, AI_MESSAGE_LIMIT: 3_000, - PRICE: '', + PRICE: 'price_1QIXy8B2lPUiVs9VQBOUPAoE', PRICE_TEST: '', COST: 0 }, diff --git a/shared/schema/AppsumoCode.ts b/shared/schema/AppsumoCodeSchema.ts similarity index 100% rename from shared/schema/AppsumoCode.ts rename to shared/schema/AppsumoCodeSchema.ts diff --git a/shared/schema/AppsumoCodeTrySchema.ts b/shared/schema/AppsumoCodeTrySchema.ts new file mode 100644 index 0000000..a5f9db1 --- /dev/null +++ b/shared/schema/AppsumoCodeTrySchema.ts @@ -0,0 +1,15 @@ +import { model, Schema, Types } from 'mongoose'; + +export type TAppsumoCodeTry = { + project_id: Types.ObjectId, + codes: string[], + valid_codes: string[], +} + +const AppsumoCodeTrySchema = new Schema({ + project_id: { type: Schema.Types.ObjectId, required: true, unique: true, index: 1 }, + codes: [{ type: String }], + valid_codes: [{ type: String }] +}); + +export const AppsumoCodeTryModel = model('appsumo_codes_tries', AppsumoCodeTrySchema);