###############################################################################1#2# CoCalc: Collaborative Calculation in the Cloud3#4# Copyright (C) 2016, Sagemath Inc.5#6# This program is free software: you can redistribute it and/or modify7# it under the terms of the GNU General Public License as published by8# the Free Software Foundation, either version 3 of the License, or9# (at your option) any later version.10#11# This program is distributed in the hope that it will be useful,12# but WITHOUT ANY WARRANTY; without even the implied warranty of13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14# GNU General Public License for more details.15#16# You should have received a copy of the GNU General Public License17# along with this program. If not, see <http://www.gnu.org/licenses/>.18#19###############################################################################2021{PROJECT_UPGRADES} = require('./schema')2223misc = require('./misc')2425# This is used by the frontend in r_account. It's also used by the backend26# to double check the claims of the frontend.27# stripe_subscriptions_data = stripe_customer?.subscriptions?.data28exports.get_total_upgrades = get_total_upgrades = (stripe_subscriptions_data) ->29subs = stripe_subscriptions_data30if not subs?31return {}32total = {}33for sub in subs34for q in [0...sub.quantity]35total = misc.map_sum(total, PROJECT_UPGRADES.membership[sub.plan.id.split('-')[0]].benefits)36return total3738#39# INPUT:40# memberships = {standard:2, premium:1, course:2, ...}41# projects = {project_id:{cores:1, network:1, ...}, ...}42#43# OUTPUT:44# {available:{cores:10, network:3, ...}, excess:{project_id:{cores:2, ...}} }45#46exports.available_upgrades = (stripe_subscriptions_data, projects) ->47available = get_total_upgrades(stripe_subscriptions_data) # start with amount available being your quota48excess = {} # nothing exceeds quota49# sort projects by project_id so that excess will be well defined50v = ({project_id: project_id, upgrades: upgrades} for project_id, upgrades of projects)51v.sort (a,b) -> misc.cmp(a.project_id, b.project_id)52for {project_id, upgrades} in v53for prop, curval of upgrades54available[prop] ?= 0 # ensure that available is defined for this prop55if curval <= available[prop] # if the current value for this project is within what is left, just subtract it off56available[prop] -= curval57else # otherwise, it goes over, so record by how much in excess, then set available to 0.58excess[project_id] ?= {}59excess[project_id][prop] = curval - available[prop]60available[prop] = 061return available:available, excess:excess6263# INPUT: same as above, but also a single project_id64#65# OUTPUT: Returns the maximum amount for each upgrade setting that a control66# (which starts at 0) for configuring that setting for the project should go up to.67#68# {cores:2, network:1, disk_quota:2000, memory:1000}69#70#71exports.upgrade_maxes = (stripe_subscriptions_data, projects, project_id) ->72{available, excess} = available_upgrades(stripe_subscriptions_data, projects)73allocated = projects[project_id]74maxes = {}75for param, avail of available76max = PROJECT_UPGRADES.max_per_project[param] # the maximum allowed for this param for any project77alloc = allocated[param] ? 0 # how much has already been allocated to this project78maxes[param] = Math.min(alloc + avail, max)79return maxes808182