Skip to content

Commit 5135742

Browse files
committed
fix #7570 -- normalize date range of non-subscription license to be valid whenever the cart is touched
- start can't be in past - end must be at least an hour after start This is done on the backend whenever anything touches the shopping cart, which should greatly increase chances of it always working. It's automatic. You do see it the second you view your cart (on the way to checkout).
1 parent af1fee3 commit 5135742

File tree

2 files changed

+39
-2
lines changed

2 files changed

+39
-2
lines changed

src/packages/server/shopping/cart/get.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { assertValidAccountID } from "@cocalc/util/misc";
88
import getPool from "@cocalc/database/pool";
99
import { Item } from "@cocalc/util/db-schema/shopping-cart-items";
1010
export type { Item };
11+
import { ensureValidLicenseIntervals } from "./validate";
1112

1213
interface Options {
1314
account_id: string;
@@ -26,8 +27,9 @@ export default async function getCart({
2627
`SELECT * FROM shopping_cart_items WHERE account_id=$1 AND purchased IS ${
2728
purchased ? " NOT " : ""
2829
} NULL AND removed IS ${removed ? " NOT " : ""} NULL ORDER BY id DESC`,
29-
[account_id]
30+
[account_id],
3031
);
32+
await ensureValidLicenseIntervals(rows, pool);
3133
return rows;
3234
}
3335

@@ -42,7 +44,7 @@ export async function getItem({
4244
const pool = getPool();
4345
const { rows } = await pool.query(
4446
"SELECT * FROM shopping_cart_items WHERE account_id=$1 AND id=$2",
45-
[account_id, id]
47+
[account_id, id],
4648
);
4749
if (rows.length == 0) {
4850
throw Error(`no item with id ${id}`);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// This ensures the date ranges in the rows are valid in the
2+
// database, and also mutates the rows themselves to be valid.
3+
export async function ensureValidLicenseIntervals(rows: any[], pool) {
4+
for (const row of rows) {
5+
const { description } = row;
6+
const range = description?.range;
7+
if (range == null) {
8+
// subscriptions, etc.
9+
continue;
10+
}
11+
// "range": ["2024-09-30T07:00:00.000Z", "2024-10-16T06:58:59.999Z"] is two UTC strings. We
12+
// ensure that the start endpoint is >= now and the end endpoint is >= start + 1 hour.
13+
let start = new Date(range[0]);
14+
let end = new Date(range[1]);
15+
const now = new Date();
16+
let changed = false;
17+
if (start < now) {
18+
changed = true;
19+
start = now;
20+
}
21+
// 1 hour in milliseconds
22+
const oneHourLater = new Date(start.getTime() + 3600 * 1000);
23+
if (end < oneHourLater) {
24+
changed = true;
25+
end = oneHourLater;
26+
}
27+
if (changed) {
28+
description.range = [start.toISOString(), end.toISOString()];
29+
await pool.query(
30+
"UPDATE shopping_cart_items SET description=$1 WHERE id=$2",
31+
[description, row.id],
32+
);
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)