add unpaid14 to the premium unlock api

This commit is contained in:
Jonas Lochmann
2026-06-15 02:00:00 +02:00
parent b2bcc3715f
commit 235115168f
4 changed files with 42 additions and 11 deletions
+1
View File
@@ -101,6 +101,7 @@ request properties: ``purchaseToken``, ``purchaseId`` and ``dryRun``
- ``purchasetoken`` is a string which the client shows at the purchase screen - ``purchasetoken`` is a string which the client shows at the purchase screen
- ``purchaseId`` is the ID that is used at the bill - ``purchaseId`` is the ID that is used at the bill
- ``dryRun`` is a boolean; setting true will skip the actual unlocking - ``dryRun`` is a boolean; setting true will skip the actual unlocking
- ``type`` is a string and must be ``year``, ``month`` or ``unpaid14``
### response ### response
+8 -2
View File
@@ -141,7 +141,8 @@ export const createAdminRouter = ({ database, websocket, eventHandler }: {
typeof req.body !== 'object' || typeof req.body !== 'object' ||
typeof req.body.purchaseToken !== 'string' || typeof req.body.purchaseToken !== 'string' ||
typeof req.body.purchaseId !== 'string' || typeof req.body.purchaseId !== 'string' ||
typeof req.body.dryRun !== 'boolean' typeof req.body.dryRun !== 'boolean' ||
typeof req.body.type !== 'string'
) { ) {
throw new BadRequest() throw new BadRequest()
} }
@@ -149,6 +150,11 @@ export const createAdminRouter = ({ database, websocket, eventHandler }: {
const purchaseToken: string = req.body.purchaseToken const purchaseToken: string = req.body.purchaseToken
const purchaseId: string = req.body.purchaseId const purchaseId: string = req.body.purchaseId
const dryRun: boolean = req.body.dryRun const dryRun: boolean = req.body.dryRun
const type: string = req.body.type
if (type !== 'month' && type !== 'year' && type !== 'unpaid14') {
throw new BadRequest()
}
const tokenContent = await verifyIdentitifyToken(purchaseToken) const tokenContent = await verifyIdentitifyToken(purchaseToken)
@@ -259,7 +265,7 @@ export const createAdminRouter = ({ database, websocket, eventHandler }: {
await addPurchase({ await addPurchase({
database, database,
familyId: tokenContent.familyId, familyId: tokenContent.familyId,
type: 'year', type,
service: 'directpurchase', service: 'directpurchase',
transactionId: purchaseId, transactionId: purchaseId,
websocket, websocket,
+3 -3
View File
@@ -1,6 +1,6 @@
/* /*
* server component for the TimeLimit App * server component for the TimeLimit App
* Copyright (C) 2019 - 2022 Jonas Lochmann * Copyright (C) 2019 - 2026 Jonas Lochmann
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as * it under the terms of the GNU Affero General Public License as
@@ -23,7 +23,7 @@ export interface PurchaseAttributes {
familyId: string familyId: string
service: 'googleplay' | 'directpurchase' service: 'googleplay' | 'directpurchase'
transactionId: string transactionId: string
type: 'month' | 'year' type: 'month' | 'year' | 'unpaid14'
loggedAt: string loggedAt: string
previousFullVersionEndTime: string previousFullVersionEndTime: string
newFullVersionEndTime: string newFullVersionEndTime: string
@@ -44,7 +44,7 @@ export const attributes: SequelizeAttributes<PurchaseAttributes> = {
type: Sequelize.STRING, type: Sequelize.STRING,
primaryKey: true primaryKey: true
}, },
type: createEnumColumn(['month', 'year']), type: createEnumColumn(['month', 'year', 'unpaid14']),
loggedAt: { ...timestampColumn }, loggedAt: { ...timestampColumn },
previousFullVersionEndTime: { ...timestampColumn }, previousFullVersionEndTime: { ...timestampColumn },
newFullVersionEndTime: { ...timestampColumn } newFullVersionEndTime: { ...timestampColumn }
+30 -6
View File
@@ -21,13 +21,14 @@ import { notifyClientsAboutChangesDelayed } from '../../function/websocket'
import { WebsocketApi } from '../../websocket' import { WebsocketApi } from '../../websocket'
const day = 1000 * 60 * 60 * 24 const day = 1000 * 60 * 60 * 24
const week = day * 7
const month = day * 31 const month = day * 31
const year = day * 366 const year = day * 366
export const addPurchase = async ({ database, familyId, type, service, transactionId, websocket, transaction }: { export const addPurchase = async ({ database, familyId, type, service, transactionId, websocket, transaction }: {
database: Database database: Database
familyId: string familyId: string
type: 'month' | 'year' type: 'month' | 'year' | 'unpaid14'
service: 'googleplay' | 'directpurchase' service: 'googleplay' | 'directpurchase'
transactionId: string transactionId: string
websocket: WebsocketApi websocket: WebsocketApi
@@ -59,16 +60,39 @@ export const addPurchase = async ({ database, familyId, type, service, transacti
const previousFullVersionEndTime = familyEntry.fullVersionUntil const previousFullVersionEndTime = familyEntry.fullVersionUntil
const previousFullVersionDebts = parseInt(familyEntry.fullVersionDebts, 10) const previousFullVersionDebts = parseInt(familyEntry.fullVersionDebts, 10)
const typeDuration = type === 'year' ? year : month if (type === 'month' || type === 'year') {
const typeDuration = type === 'year' ? year : month
if (typeDuration > previousFullVersionDebts) { if (typeDuration > previousFullVersionDebts) {
const newFullVersionUntil = Math.max(parseInt(familyEntry.fullVersionUntil, 10), Date.now()) + typeDuration - previousFullVersionDebts const newFullVersionUntil = Math.max(parseInt(familyEntry.fullVersionUntil, 10), Date.now()) + typeDuration - previousFullVersionDebts
familyEntry.fullVersionUntil = newFullVersionUntil.toString(10)
familyEntry.fullVersionDebts = '0'
familyEntry.hasFullVersion = true
} else {
familyEntry.fullVersionDebts = (previousFullVersionDebts - typeDuration).toString(10)
}
} else if (type === 'unpaid14') {
const debtsAdd = 2 * week
const debtsMax = 3 * week
const newDebts = Math.min(debtsMax, previousFullVersionDebts + debtsAdd)
if (newDebts <= previousFullVersionDebts) {
// do not save anything
return
}
const durationToAdd = newDebts - previousFullVersionDebts
const newFullVersionUntil = Math.max(parseInt(familyEntry.fullVersionUntil, 10), Date.now()) + durationToAdd
familyEntry.fullVersionUntil = newFullVersionUntil.toString(10) familyEntry.fullVersionUntil = newFullVersionUntil.toString(10)
familyEntry.fullVersionDebts = '0' familyEntry.fullVersionDebts = newDebts.toString(10)
familyEntry.hasFullVersion = true familyEntry.hasFullVersion = true
} else { } else {
familyEntry.fullVersionDebts = (previousFullVersionDebts - typeDuration).toString(10) throw new Error()
} }
await familyEntry.save({ transaction }) await familyEntry.save({ transaction })