UNPKG

@cocalc/server

Version:

CoCalc server functionality: functions used by either the hub and the next.js server

97 lines (95 loc) 4.5 kB
"use strict"; /* * This file is part of CoCalc: Copyright © 2020 Sagemath, Inc. * License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /* Handle purchasing a licenses by customers. This is the server side of @cocalc/frontend/site-licenses/purchase/ What this does: - stores the request object in a table in the database - if the request is for a quote, sends an email - if the request is to make a purchase, makes that purchase and creates the license */ const database_1 = require("@cocalc/database"); const pool_1 = __importDefault(require("@cocalc/database/pool")); const sanity_checks_1 = require("@cocalc/util/licenses/purchase/sanity-checks"); const charge_1 = require("./charge"); const create_license_1 = __importDefault(require("./create-license")); const client_1 = require("@cocalc/server/stripe/client"); const async_utils_1 = require("@cocalc/util/async-utils"); const awaiting_1 = require("awaiting"); const logger_1 = require("@cocalc/backend/logger"); const logger = (0, logger_1.getLogger)("purchase-license"); // Does what should be done, and returns the license_id of the license that was created // and has user added to as a manager. // We don't allow a user to attempt a purchase more than once every THROTTLE_S seconds. // This is just standard good practice, and avoids "double clicks" and probably some // sort of attacks... const THROTTLE_S = 15; const last_attempt = {}; async function purchaseLicense(account_id, info, noThrottle) { logger.debug("purchase_license: info=", info, ", account_id=", account_id); if (!noThrottle) { const now = Date.now(); if (now - (last_attempt[account_id] ?? 0) <= THROTTLE_S * 1000) { throw Error("You must wait at least " + THROTTLE_S.toString() + " seconds between license purchases."); } last_attempt[account_id] = now; } logger.debug("purchase_license: running sanity checks..."); await (0, sanity_checks_1.sanity_checks)((0, pool_1.default)(), info); logger.debug("purchase_license: charging user for license..."); const stripe = new client_1.StripeClient({ account_id }); const purchase = await (0, charge_1.chargeUserForLicense)(stripe, info); logger.debug("purchase_license: creating the license..."); const database = (0, database_1.db)(); const license_id = await (0, create_license_1.default)(database, account_id, info); logger.debug("purchase_license: set metadata on purchase..."); await (0, charge_1.setPurchaseMetadata)(purchase, { license_id, account_id }); // We have to try a few times, since the metadata sometimes doesn't appear // when querying stripe for the customer, even after it was written in the // above line. Also, this gives the credit card a first chance to work. // This is ONLY for subscriptions. if (info.subscription != "no") { let done = false; let delay_s = 1; for (let i = 0; i < 20; i++) { const customer = await (0, async_utils_1.callback2)(database.stripe_update_customer, { account_id, }); const data = customer?.subscriptions?.data; if (data != null) { for (const sub of data) { if (sub.metadata?.license_id == license_id && sub.status == "active") { // metadata is set and status is active -- yes done = true; break; } } } if (done) { logger.debug("purchase_license: successfully verified metadata properly set and sub is active..."); break; } else { logger.debug("purchase_license: trying again to verify metadata properly set and sub is active..."); } await (0, awaiting_1.delay)(delay_s * 1000); delay_s *= 1.1; } // Sets the license expire date if the subscription is NOT // active at this point (e.g., due to credit card failure). await database.sync_site_license_subscriptions(account_id); } return license_id; } exports.default = purchaseLicense; //# sourceMappingURL=index.js.map