From 745544547450dce7a85786134566e03bdcc3c16f Mon Sep 17 00:00:00 2001 From: bc-chaz Date: Fri, 23 Sep 2022 13:06:42 -0700 Subject: [PATCH 1/2] feat(common): adds sql support --- lib/dbs/mysql.ts | 54 ++++++++++++++++++++++++++++++++++++++++++++++-- scripts/db.js | 24 ++++++++++++++++++++- types/db.ts | 1 + 3 files changed, 76 insertions(+), 3 deletions(-) diff --git a/lib/dbs/mysql.ts b/lib/dbs/mysql.ts index 62f48d77..320ddbcc 100644 --- a/lib/dbs/mysql.ts +++ b/lib/dbs/mysql.ts @@ -1,6 +1,7 @@ import * as mysql from 'mysql'; import { promisify } from 'util'; import { SessionProps, StoreData } from '../../types'; +import { trialDays } from '../checkout'; const MYSQL_CONFIG = { host: process.env.MYSQL_HOST, @@ -26,12 +27,17 @@ export async function setUser({ user }: SessionProps) { } export async function setStore(session: SessionProps) { - const { access_token: accessToken, context, scope } = session; + const { + access_token: accessToken, + context, + scope, + user: { id }, + } = session; // Only set on app install or update if (!accessToken || !scope) return null; const storeHash = context?.split('/')[1] || ''; - const storeData: StoreData = { accessToken, scope, storeHash }; + const storeData: StoreData = { accessToken, adminId: id, scope, storeHash }; await query('REPLACE INTO stores SET ?', storeData); } @@ -91,3 +97,47 @@ export async function getStoreToken(storeHash: string) { export async function deleteStore({ store_hash: storeHash }: SessionProps) { await query('DELETE FROM stores WHERE storeHash = ?', storeHash); } + +// CHECKOUT Functions +export async function setStorePlan(session: SessionProps) { + const { access_token: accessToken, context, plan, sub } = session; + // Only set on app install or subscription verification (load) + if ((!accessToken && !plan?.pid) || (plan && !plan.isPaidApp)) return null; + + const contextString = context ?? sub; + const storeHash = contextString?.split('/')[1] || ''; + const defaultEnd = Date.now() + (trialDays * 24 * 60 * 60 * 1000); + const data = { pid: '', isPaidApp: false, showPaidWelcome: false, storeHash, trialEndDate: defaultEnd, ...plan }; + + await query('REPLACE INTO plan SET ?', data); +} + +export async function getStorePlan(storeHash: string) { + if (!storeHash) return null; + + const results = await query('SELECT * FROM plan WHERE storeHash = ? LIMIT 1', storeHash); + + return results.length ? results[0] : null; +} + +export async function setStoreWelcome(storeHash: string, show: boolean) { + if (!storeHash) return null; + + const values = [show, storeHash]; + + await query('UPDATE plan SET showPaidWelcome = ? WHERE storeHash = ?', values); +} + +export async function setCheckoutId(pid: string, checkoutId: string) { + if (!pid || !checkoutId) return null; + + await query('REPLACE INTO checkout SET ?', { pid, checkoutId }); +} + +export async function getCheckoutId(pid: string) { + if (!pid) return null; + + const results = await query('SELECT checkoutId FROM checkout WHERE pid = ?', pid); + + return results.length ? results[0].checkoutId : null; +} diff --git a/scripts/db.js b/scripts/db.js index c2abe9c2..68a00f70 100644 --- a/scripts/db.js +++ b/scripts/db.js @@ -26,6 +26,7 @@ const storesCreate = query('CREATE TABLE `stores` (\n' + ' `id` int(11) unsigned NOT NULL AUTO_INCREMENT,\n' + ' `storeHash` varchar(10) NOT NULL,\n' + ' `accessToken` text,\n' + + ' `adminId` int(11) NOT NULL,\n' + ' `scope` text,\n' + ' PRIMARY KEY (`id`),\n' + ' UNIQUE KEY `storeHash` (`storeHash`)\n' + @@ -42,6 +43,27 @@ const storeUsersCreate = query('CREATE TABLE `storeUsers` (\n' + ') ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;\n' ); -Promise.all([usersCreate, storesCreate]).then(() => { +const planCreate = query('CREATE TABLE `plan` (\n' + + ' `id` int(11) unsigned NOT NULL AUTO_INCREMENT,\n' + + ' `storeHash` varchar(10) NOT NULL,\n' + + ' `pid` varchar(20) NOT NULL,\n' + + ' `isPaidApp` boolean,\n' + + ' `showPaidWelcome` boolean,\n' + + ' `trialEndDate` bigint(20),\n' + + ' PRIMARY KEY (`id`),\n' + + ' UNIQUE KEY `storeHash` (`storeHash`)\n' + + ') ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;' +); + +const checkoutCreate = query('CREATE TABLE `checkout` (\n' + + ' `id` int(11) unsigned NOT NULL AUTO_INCREMENT,\n' + + ' `pid` varchar(20) NOT NULL,\n' + + ' `checkoutId` varchar(40) NOT NULL,\n' + + ' PRIMARY KEY (`id`),\n' + + ' UNIQUE KEY `pid` (`pid`)\n' + + ') ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;\n' +); + +Promise.all([usersCreate, storesCreate, storeUsersCreate, planCreate, checkoutCreate]).then(() => { connection.end(); }); diff --git a/types/db.ts b/types/db.ts index 784c3133..5880983e 100644 --- a/types/db.ts +++ b/types/db.ts @@ -4,6 +4,7 @@ import { SessionProps } from './index'; export interface StoreData { accessToken?: string; + adminId: number; scope?: string; storeHash: string; } From 68391da15b3e38c99ce000d1bc79484846033bbb Mon Sep 17 00:00:00 2001 From: bc-chaz Date: Tue, 27 Sep 2022 14:08:39 -0700 Subject: [PATCH 2/2] feat(common): fetch merchant uuid --- .env-sample | 1 - lib/checkout.ts | 3 +-- lib/dbs/mysql.ts | 11 +++++++++-- pages/api/checkout/[pid].ts | 14 +++++++++----- scripts/db.js | 2 +- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/.env-sample b/.env-sample index b1b60183..c7d34fad 100644 --- a/.env-sample +++ b/.env-sample @@ -36,7 +36,6 @@ CHECKOUT_APP_ID={Application ID} CHECKOUT_CLIENT={Partner Client ID} CHECKOUT_TOKEN={Partner Access Token} CHECKOUT_PARTNER={Partner Account UUID} -CHECKOUT_MERCHANT={Merchant Account UUID} CHECKOUT_URL=https://${API_URL}/accounts/${CHECKOUT_PARTNER}/graphql # Dev Enironment Vars diff --git a/lib/checkout.ts b/lib/checkout.ts index 6703d8aa..2e26ec95 100644 --- a/lib/checkout.ts +++ b/lib/checkout.ts @@ -1,6 +1,5 @@ const checkoutAppId = process.env.CHECKOUT_APP_ID; const appId = process.env.CURRENT_APP_ID ?? checkoutAppId; -const merchantUuid = process.env.CHECKOUT_MERCHANT; const environment = process.env.ENVIRONMENT; const isProd = environment === 'bigcommerce.com'; const hostName = isProd ? environment : `-${environment}`; @@ -99,7 +98,7 @@ const checkoutGraphQuery = ` } `; -export function getCheckoutBody(productId: string, storeHash: string) { +export function getCheckoutBody(productId: string, storeHash: string, merchantUuid: string) { return { query: checkoutGraphQuery, variables: { diff --git a/lib/dbs/mysql.ts b/lib/dbs/mysql.ts index 320ddbcc..068cd2ee 100644 --- a/lib/dbs/mysql.ts +++ b/lib/dbs/mysql.ts @@ -106,8 +106,15 @@ export async function setStorePlan(session: SessionProps) { const contextString = context ?? sub; const storeHash = contextString?.split('/')[1] || ''; - const defaultEnd = Date.now() + (trialDays * 24 * 60 * 60 * 1000); - const data = { pid: '', isPaidApp: false, showPaidWelcome: false, storeHash, trialEndDate: defaultEnd, ...plan }; + const defaultEnd = new Date(Date.now() + (trialDays * 24 * 60 * 60 * 1000)); + const data = { + pid: '', + isPaidApp: false, + showPaidWelcome: false, + storeHash, + trialEndDate: defaultEnd, + ...plan, + }; await query('REPLACE INTO plan SET ?', data); } diff --git a/pages/api/checkout/[pid].ts b/pages/api/checkout/[pid].ts index 6f198844..081b0b46 100644 --- a/pages/api/checkout/[pid].ts +++ b/pages/api/checkout/[pid].ts @@ -1,13 +1,16 @@ import { NextApiRequest, NextApiResponse } from 'next'; -import { getSession, setCheckout } from '../../../lib/auth'; +import { bigcommerceClient, getSession, setCheckout } from '../../../lib/auth'; import { getCheckoutBody } from '../../../lib/checkout'; export default async function checkout(req: NextApiRequest, res: NextApiResponse) { const { query: { pid } } = req; try { - const { storeHash } = await getSession(req); - const checkoutBody = getCheckoutBody(String(pid), storeHash); + const { accessToken, storeHash } = await getSession(req); + const bigcommerce = bigcommerceClient(accessToken, storeHash, 'v2'); + const { account_uuid: merchantUuid } = await bigcommerce.get(`/store`); + + const checkoutBody = getCheckoutBody(String(pid), storeHash, merchantUuid); const response = await fetch(process.env.CHECKOUT_URL, { method: 'POST', headers: { @@ -24,10 +27,11 @@ export default async function checkout(req: NextApiRequest, res: NextApiResponse throw new Error(errors[0]?.message); } - const checkoutId = data?.checkout?.createCheckout?.checkout?.id.split('/')[3] ?? ''; + const checkout = data?.checkout?.createCheckout?.checkout || {}; + const checkoutId = checkout.id?.split('/')[3] ?? ''; if (checkoutId) setCheckout(String(pid), checkoutId); - res.status(200).json(data?.checkout?.createCheckout?.checkout); + res.status(200).json(checkout); } catch (error) { const { message, response } = error; res.status(response?.status || 500).json({ message }); diff --git a/scripts/db.js b/scripts/db.js index 68a00f70..57b0db48 100644 --- a/scripts/db.js +++ b/scripts/db.js @@ -49,7 +49,7 @@ const planCreate = query('CREATE TABLE `plan` (\n' + ' `pid` varchar(20) NOT NULL,\n' + ' `isPaidApp` boolean,\n' + ' `showPaidWelcome` boolean,\n' + - ' `trialEndDate` bigint(20),\n' + + ' `trialEndDate` datetime,\n' + ' PRIMARY KEY (`id`),\n' + ' UNIQUE KEY `storeHash` (`storeHash`)\n' + ') ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;'