Skip to content

Commit

Permalink
feat: add some leeway for totp codes
Browse files Browse the repository at this point in the history
feat: add start date to subscriptions
feat: add option for manual/automatic renewals
fix: layout issue with subscriptions list during search
  • Loading branch information
ellite authored Nov 17, 2024
1 parent b59540e commit 6e44a26
Show file tree
Hide file tree
Showing 43 changed files with 412 additions and 25 deletions.
4 changes: 4 additions & 0 deletions api/subscriptions/get_subscriptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@
"logo": "example.png",
"price": 10.00,
"currency_id": 1,
"start_date": "2024-09-01",
"next_payment": "2024-09-01",
"cycle": 1,
"frequency": 1,
"auto_renew": 1,
"notes": "Example note",
"payment_method_id": 1,
"payer_user_id": 1,
Expand All @@ -52,9 +54,11 @@
"logo": "another.png",
"price": 15.00,
"currency_id": 2,
"start_date": "2024-09-02",
"next_payment": "2024-09-02",
"cycle": 1,
"frequency": 1,
"auto_renew": 0,
"notes": "",
"payment_method_id": 2,
"payer_user_id": 2,
Expand Down
10 changes: 10 additions & 0 deletions endpoints/admin/deleteuser.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,16 @@
$stmt->bindValue(':id', $userId, SQLITE3_INTEGER);
$result = $stmt->execute();

// Delete totp
$stmt = $db->prepare('DELETE FROM totp WHERE user_id = :id');
$stmt->bindValue(':id', $userId, SQLITE3_INTEGER);
$result = $stmt->execute();

// Delete total yearly cost
$stmt = $db->prepare('DELETE FROM total_yearly_cost WHERE user_id = :id');
$stmt->bindValue(':id', $userId, SQLITE3_INTEGER);
$result = $stmt->execute();

die(json_encode([
"success" => true,
"message" => translate('success', $i18n)
Expand Down
2 changes: 1 addition & 1 deletion endpoints/cronjobs/updatenextpayment.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
$cycles[$cycleId] = $row;
}

$query = "SELECT id, next_payment, frequency, cycle FROM subscriptions WHERE next_payment < :currentDate";
$query = "SELECT id, next_payment, frequency, cycle FROM subscriptions WHERE next_payment < :currentDate AND auto_renew = 1";
$stmt = $db->prepare($query);
$stmt->bindValue(':currentDate', $currentDate->format('Y-m-d'));
$result = $stmt->execute();
Expand Down
10 changes: 10 additions & 0 deletions endpoints/settings/deleteaccount.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,16 @@
$stmt->bindValue(':id', $userIdToDelete, SQLITE3_INTEGER);
$result = $stmt->execute();

// Delete totp
$stmt = $db->prepare('DELETE FROM totp WHERE user_id = :id');
$stmt->bindValue(':id', $userIdToDelete, SQLITE3_INTEGER);
$result = $stmt->execute();

// Delete total yearly cost
$stmt = $db->prepare('DELETE FROM total_yearly_cost WHERE user_id = :id');
$stmt->bindValue(':id', $userIdToDelete, SQLITE3_INTEGER);
$result = $stmt->execute();

die(json_encode([
"success" => true,
"message" => translate('success', $i18n)
Expand Down
12 changes: 10 additions & 2 deletions endpoints/subscription/add.php
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ function resizeAndUploadLogo($uploadedFile, $uploadDir, $name, $settings)
$frequency = $_POST["frequency"];
$cycle = $_POST["cycle"];
$nextPayment = $_POST["next_payment"];
$autoRenew = isset($_POST['auto_renew']) ? true : false;
$startDate = $_POST["start_date"];
$paymentMethodId = $_POST["payment_method_id"];
$payerUserId = $_POST["payer_user_id"];
$categoryId = $_POST['category_id'];
Expand Down Expand Up @@ -201,11 +203,13 @@ function resizeAndUploadLogo($uploadedFile, $uploadDir, $name, $settings)
$sql = "INSERT INTO subscriptions (
name, logo, price, currency_id, next_payment, cycle, frequency, notes,
payment_method_id, payer_user_id, category_id, notify, inactive, url,
notify_days_before, user_id, cancellation_date, replacement_subscription_id
notify_days_before, user_id, cancellation_date, replacement_subscription_id,
auto_renew, start_date
) VALUES (
:name, :logo, :price, :currencyId, :nextPayment, :cycle, :frequency, :notes,
:paymentMethodId, :payerUserId, :categoryId, :notify, :inactive, :url,
:notifyDaysBefore, :userId, :cancellationDate, :replacement_subscription_id
:notifyDaysBefore, :userId, :cancellationDate, :replacement_subscription_id,
:autoRenew, :startDate
)";
} else {
$id = $_POST['id'];
Expand All @@ -214,6 +218,8 @@ function resizeAndUploadLogo($uploadedFile, $uploadDir, $name, $settings)
price = :price,
currency_id = :currencyId,
next_payment = :nextPayment,
auto_renew = :autoRenew,
start_date = :startDate,
cycle = :cycle,
frequency = :frequency,
notes = :notes,
Expand Down Expand Up @@ -242,6 +248,8 @@ function resizeAndUploadLogo($uploadedFile, $uploadDir, $name, $settings)
$stmt->bindParam(':price', $price, SQLITE3_FLOAT);
$stmt->bindParam(':currencyId', $currencyId, SQLITE3_INTEGER);
$stmt->bindParam(':nextPayment', $nextPayment, SQLITE3_TEXT);
$stmt->bindParam(':autoRenew', $autoRenew, SQLITE3_INTEGER);
$stmt->bindParam(':startDate', $startDate, SQLITE3_TEXT);
$stmt->bindParam(':cycle', $cycle, SQLITE3_INTEGER);
$stmt->bindParam(':frequency', $frequency, SQLITE3_INTEGER);
$stmt->bindParam(':notes', $notes, SQLITE3_TEXT);
Expand Down
2 changes: 2 additions & 0 deletions endpoints/subscription/clone.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
$cloneStmt->bindValue(':price', $subscriptionToClone['price'], SQLITE3_TEXT);
$cloneStmt->bindValue(':currency_id', $subscriptionToClone['currency_id'], SQLITE3_INTEGER);
$cloneStmt->bindValue(':next_payment', $subscriptionToClone['next_payment'], SQLITE3_TEXT);
$cloneStmt->bindValue(':auto_renew', $subscriptionToClone['auto_renew'], SQLITE3_INTEGER);
$cloneStmt->bindValue(':start_date', $subscriptionToClone['start_date'], SQLITE3_TEXT);
$cloneStmt->bindValue(':cycle', $subscriptionToClone['cycle'], SQLITE3_TEXT);
$cloneStmt->bindValue(':frequency', $subscriptionToClone['frequency'], SQLITE3_INTEGER);
$cloneStmt->bindValue(':notes', $subscriptionToClone['notes'], SQLITE3_TEXT);
Expand Down
2 changes: 2 additions & 0 deletions endpoints/subscription/get.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
$subscriptionData['logo'] = $row['logo'];
$subscriptionData['price'] = $row['price'];
$subscriptionData['currency_id'] = $row['currency_id'];
$subscriptionData['auto_renew'] = $row['auto_renew'];
$subscriptionData['start_date'] = $row['start_date'];
$subscriptionData['next_payment'] = $row['next_payment'];
$subscriptionData['frequency'] = $row['frequency'];
$subscriptionData['cycle'] = $row['cycle'];
Expand Down
89 changes: 89 additions & 0 deletions endpoints/subscription/renew.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php
require_once '../../includes/connect_endpoint.php';

if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
if ($_SERVER["REQUEST_METHOD"] === "GET") {
$currentDate = new DateTime();
$currentDateString = $currentDate->format('Y-m-d');

$cycles = array();
$query = "SELECT * FROM cycles";
$result = $db->query($query);
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$cycleId = $row['id'];
$cycles[$cycleId] = $row;
}

$subscriptionId = $_GET["id"];
$query = "SELECT * FROM subscriptions WHERE id = :id AND user_id = :user_id AND auto_renew = 0";
$stmt = $db->prepare($query);
$stmt->bindValue(':id', $subscriptionId, SQLITE3_INTEGER);
$stmt->bindValue(':user_id', $userId, SQLITE3_INTEGER);
$result = $stmt->execute();
$subscriptionToRenew = $result->fetchArray(SQLITE3_ASSOC);
if ($subscriptionToRenew === false) {
die(json_encode([
"success" => false,
"message" => translate("error", $i18n)
]));
}

$nextPaymentDate = new DateTime($subscriptionToRenew['next_payment']);
$frequency = $subscriptionToRenew['frequency'];
$cycle = $cycles[$subscriptionToRenew['cycle']]['name'];

// Calculate the interval to add based on the cycle
$intervalSpec = "P";
if ($cycle == 'Daily') {
$intervalSpec .= "{$frequency}D";
} elseif ($cycle === 'Weekly') {
$intervalSpec .= "{$frequency}W";
} elseif ($cycle === 'Monthly') {
$intervalSpec .= "{$frequency}M";
} elseif ($cycle === 'Yearly') {
$intervalSpec .= "{$frequency}Y";
}

$interval = new DateInterval($intervalSpec);

// Add intervals until the next payment date is in the future and after current next payment date
while ($nextPaymentDate < $currentDate || $nextPaymentDate == new DateTime($subscriptionToRenew['next_payment'])) {
$nextPaymentDate->add($interval);
}

// Update the subscription's next_payment date
$updateQuery = "UPDATE subscriptions SET next_payment = :nextPaymentDate WHERE id = :subscriptionId";
$updateStmt = $db->prepare($updateQuery);
$updateStmt->bindValue(':nextPaymentDate', $nextPaymentDate->format('Y-m-d'));
$updateStmt->bindValue(':subscriptionId', $subscriptionId);
$updateStmt->execute();

if ($updateStmt->execute()) {
$response = [
"success" => true,
"message" => translate('success', $i18n),
"id" => $subscriptionId
];
echo json_encode($response);
} else {
die(json_encode([
"success" => false,
"message" => translate("error", $i18n)
]));
}
} else {
$db->close();
die(json_encode([
"success" => false,
"message" => translate('invalid_request_method', $i18n)
]));
}
} else {
$db->close();
die(json_encode([
"success" => false,
"message" => translate('session_expired', $i18n)
]));
}

?>
1 change: 1 addition & 0 deletions endpoints/subscriptions/export.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
$subscriptionDetails = array(
'Name' => str_replace(',', ' ', $row['name']),
'Next Payment' => $row['next_payment'],
'Renewal' => $row['auto_renew'] ? 'Automatic' : 'Manual',
'Category' => str_replace(',', ' ', $categories[$row['category_id']]['name']),
'Payment Method' => str_replace(',', ' ', $payment_methods[$row['payment_method_id']]['name']),
'Paid By' => str_replace(',', ' ', $members[$row['payer_user_id']]['name']),
Expand Down
1 change: 1 addition & 0 deletions endpoints/subscriptions/get.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@
$next_payment_timestamp = strtotime($subscription['next_payment']);
$formatted_date = $formatter->format($next_payment_timestamp);
$print[$id]['next_payment'] = $formatted_date;
$print[$id]['auto_renew'] = $subscription['auto_renew'];
$paymentIconFolder = (strpos($payment_methods[$paymentMethodId]['icon'], 'images/uploads/icons/') !== false) ? "" : "images/uploads/logos/";
$print[$id]['payment_method_icon'] = $paymentIconFolder . $payment_methods[$paymentMethodId]['icon'];
$print[$id]['payment_method_name'] = $payment_methods[$paymentMethodId]['name'];
Expand Down
3 changes: 2 additions & 1 deletion endpoints/user/disable_totp.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ function trigger_deprecation($package, $version, $message, ...$args)

$clock = new OTPHP\InternalClock();
$totp = OTPHP\TOTP::createFromSecret($secret, $clock);
$totp->setPeriod(30);

if ($totp->verify($totp_code)) {
if ($totp->verify($totp_code, null, 15)) {
$statement = $db->prepare('UPDATE user SET totp_enabled = 0 WHERE id = :id');
$statement->bindValue(':id', $userId, SQLITE3_INTEGER);
$statement->execute();
Expand Down
4 changes: 3 additions & 1 deletion endpoints/user/enable_totp.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,11 @@ function base32_encode($hex)
}

$clock = new OTPHP\InternalClock();

$totp = OTPHP\TOTP::createFromSecret($secret, $clock);
$totp->setPeriod(30);

if ($totp->verify($totp_code)) {
if ($totp->verify($totp_code, null, 15)) {
// Generate 10 backup codes
$backupCodes = [];
for ($i = 0; $i < 10; $i++) {
Expand Down
3 changes: 3 additions & 0 deletions images/siteicons/svg/automatic.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="100" height="100" viewBox="0 0 50 50">
<path fill="currentColor" d="M 25 5 C 13.964844 5 5 13.964844 5 25 C 4.996094 25.359375 5.183594 25.695313 5.496094 25.878906 C 5.808594 26.058594 6.191406 26.058594 6.503906 25.878906 C 6.816406 25.695313 7.003906 25.359375 7 25 C 7 15.046875 15.046875 7 25 7 C 31.246094 7 36.726563 10.179688 39.957031 15 L 33 15 C 32.640625 14.996094 32.304688 15.183594 32.121094 15.496094 C 31.941406 15.808594 31.941406 16.191406 32.121094 16.503906 C 32.304688 16.816406 32.640625 17.003906 33 17 L 43 17 L 43 7 C 43.003906 6.730469 42.898438 6.46875 42.707031 6.277344 C 42.515625 6.085938 42.253906 5.980469 41.984375 5.984375 C 41.433594 5.996094 40.992188 6.449219 41 7 L 41 13.011719 C 37.347656 8.148438 31.539063 5 25 5 Z M 43.984375 23.984375 C 43.433594 23.996094 42.992188 24.449219 43 25 C 43 34.953125 34.953125 43 25 43 C 18.753906 43 13.269531 39.820313 10.042969 35 L 17 35 C 17.359375 35.007813 17.695313 34.816406 17.878906 34.507813 C 18.058594 34.195313 18.058594 33.808594 17.878906 33.496094 C 17.695313 33.1875 17.359375 32.996094 17 33 L 8.445313 33 C 8.316406 32.976563 8.1875 32.976563 8.058594 33 L 7 33 L 7 43 C 6.996094 43.359375 7.183594 43.695313 7.496094 43.878906 C 7.808594 44.058594 8.191406 44.058594 8.503906 43.878906 C 8.816406 43.695313 9.003906 43.359375 9 43 L 9 36.984375 C 12.648438 41.847656 18.460938 45 25 45 C 36.035156 45 45 36.035156 45 25 C 45.003906 24.730469 44.898438 24.46875 44.707031 24.277344 C 44.515625 24.085938 44.253906 23.980469 43.984375 23.984375 Z"></path>
</svg>
3 changes: 3 additions & 0 deletions images/siteicons/svg/manual.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="100" height="100" viewBox="0 0 50 50">
<path fill="currentColor" d="M 32 1 C 31.0625 1 30.085938 1.324219 29.3125 2 C 28.539063 2.675781 28 3.734375 28 5 L 28 5.40625 C 27.519531 5.1875 27.0625 5 26.5 5 C 24.578125 5 23 6.578125 23 8.5 C 23 10.421875 24.578125 12 26.5 12 C 27.089844 12 27.625 11.824219 28.25 11.625 C 28.875 11.425781 29.539063 11.195313 30.15625 10.9375 C 31 10.585938 31.605469 10.28125 32 10.09375 C 32.394531 10.28125 33 10.585938 33.84375 10.9375 C 34.460938 11.195313 35.125 11.425781 35.75 11.625 C 36.375 11.824219 36.910156 12 37.5 12 C 39.421875 12 41 10.421875 41 8.5 C 41 6.578125 39.421875 5 37.5 5 C 36.9375 5 36.480469 5.1875 36 5.40625 L 36 4.90625 C 36 3.675781 35.429688 2.625 34.65625 1.96875 C 33.882813 1.3125 32.9375 1 32 1 Z M 32 3 C 32.460938 3 33 3.179688 33.375 3.5 C 33.75 3.820313 34 4.238281 34 4.90625 L 34 6.46875 C 33.894531 6.53125 33.789063 6.59375 33.6875 6.65625 C 32.984375 7.09375 32.421875 7.488281 32 7.78125 C 31.578125 7.488281 31.015625 7.09375 30.3125 6.65625 C 30.210938 6.59375 30.105469 6.53125 30 6.46875 L 30 5 C 30 4.265625 30.25 3.824219 30.625 3.5 C 31 3.175781 31.539063 3 32 3 Z M 26.5 7 C 26.492188 7 26.972656 7.121094 27.5 7.375 C 28.027344 7.628906 28.667969 7.980469 29.25 8.34375 C 29.621094 8.574219 29.625 8.605469 29.9375 8.8125 C 29.671875 8.929688 29.675781 8.9375 29.375 9.0625 C 28.789063 9.304688 28.195313 9.574219 27.65625 9.75 C 27.117188 9.925781 26.613281 10 26.5 10 C 25.625 10 25 9.375 25 8.5 C 25 7.625 25.625 7 26.5 7 Z M 37.5 7 C 38.375 7 39 7.625 39 8.5 C 39 9.375 38.375 10 37.5 10 C 37.386719 10 36.882813 9.925781 36.34375 9.75 C 35.804688 9.574219 35.210938 9.304688 34.625 9.0625 C 34.324219 8.9375 34.328125 8.929688 34.0625 8.8125 C 34.375 8.605469 34.378906 8.574219 34.75 8.34375 C 35.332031 7.980469 35.972656 7.628906 36.5 7.375 C 37.027344 7.121094 37.507813 7 37.5 7 Z M 30 12.1875 L 28 13 L 28 15.5 C 27.398438 15.199219 26.800781 15 26 15 C 24.398438 15 23.292969 15.710938 22.59375 16.8125 C 21.992188 16.3125 21.101563 16 20 16 C 18.601563 16 17.011719 16.488281 16.3125 18.6875 C 15.511719 18.085938 14.699219 18 14 18 C 12.5 18 10 18.601563 10 23 L 10 41 C 10 46 14 50 19 50 L 28.09375 50 C 31.492188 50 34.59375 48.101563 36.09375 45 L 39 39.5 C 39.101563 39.199219 40.09375 37.207031 40.09375 34.90625 C 40.09375 31.007813 37.792969 29.011719 36.09375 28.3125 L 36.09375 13 L 34.09375 12.1875 L 34.09375 28.90625 C 34.09375 29.40625 34.507813 29.804688 34.90625 29.90625 C 35.007813 29.90625 38.09375 30.8125 38.09375 34.8125 C 38.09375 36.3125 37.488281 37.898438 37.1875 38.5 L 34.40625 44.09375 C 33.207031 46.492188 30.792969 48 28.09375 48 L 19 48 C 15.101563 48 12 44.898438 12 41 L 12 23 C 12 20.398438 13 20 14 20 C 15 20 16 20.398438 16 23 C 16 23.601563 16.398438 24 17 24 C 17.601563 24 18 23.601563 18 23 L 18 21 C 18 18.199219 19 18 20 18 C 21.699219 18 22 19.101563 22 20 L 22 22 C 22 22.601563 22.398438 23 23 23 C 23.601563 23 24 22.601563 24 22 L 24 19 C 24 18.199219 24.5 17 26 17 C 27.5 17 28 18.199219 28 19 L 28 23 C 28 23.601563 28.398438 24 29 24 C 29.601563 24 30 23.601563 30 23 Z"></path>
</svg>
3 changes: 3 additions & 0 deletions images/siteicons/svg/mobile-menu/renew.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="100" height="100" viewBox="0 0 50 50">
<path fill="currentColor" d="M 8.8125 2 C 8.335938 2.089844 7.992188 2.511719 8 3 L 8 11 C 8 11.03125 8 11.0625 8 11.09375 L 8 36 C 8 37.65625 6.65625 39 5 39 C 4.96875 39 4.9375 39 4.90625 39 C 3.296875 38.949219 2 37.621094 2 36 L 2 14 L 6 14 L 6 12 L 1 12 C 0.449219 12 0 12.449219 0 13 L 0 36 C 0 38.628906 2.074219 40.785156 4.65625 40.96875 C 4.667969 40.96875 4.675781 40.96875 4.6875 40.96875 C 4.707031 40.980469 4.730469 40.992188 4.75 41 C 4.835938 41.003906 4.914063 41 5 41 L 25 41 C 25.359375 41.003906 25.695313 40.816406 25.878906 40.503906 C 26.058594 40.191406 26.058594 39.808594 25.878906 39.496094 C 25.695313 39.183594 25.359375 38.996094 25 39 L 8.96875 39 C 9.609375 38.160156 10 37.128906 10 36 L 10 11.15625 C 10.003906 11.105469 10.003906 11.050781 10 11 L 10 4 L 44 4 L 44 25 C 43.996094 25.359375 44.183594 25.695313 44.496094 25.878906 C 44.808594 26.058594 45.191406 26.058594 45.503906 25.878906 C 45.816406 25.695313 46.003906 25.359375 46 25 L 46 3 C 46 2.449219 45.550781 2 45 2 L 9 2 C 8.96875 2 8.9375 2 8.90625 2 C 8.875 2 8.84375 2 8.8125 2 Z M 16 10 L 16 12 L 38 12 L 38 10 Z M 16 14 L 16 16 L 38 16 L 38 14 Z M 16 22 L 16 24 L 26 24 L 26 22 Z M 28 22 L 28 24 L 38 24 L 38 22 Z M 16 26 L 16 28 L 26 28 L 26 26 Z M 28 26 L 28 28 L 30 28 L 33 26 Z M 39 27 C 32.953125 27 28 31.953125 28 38 C 28 44.046875 32.953125 49 39 49 L 39 47 C 34.046875 47 30 42.953125 30 38 C 30 33.046875 34.046875 29 39 29 C 43.953125 29 48 33.046875 48 38 C 48 40.660156 46.851563 43 45 44.625 L 45 41 L 43 41 L 43 48 L 50 48 L 50 46 L 46.4375 46 C 48.621094 44.011719 50 41.171875 50 38 C 50 31.953125 45.046875 27 39 27 Z M 16 30 L 16 32 L 26 32 L 26 30 Z M 16 34 L 16 36 L 26 36 L 26 34 Z"></path>
</svg>
Loading

0 comments on commit 6e44a26

Please sign in to comment.