mirror of
https://github.com/ellite/Wallos.git
synced 2025-12-23 23:18:07 -05:00
feat: add cancelation reminders (#425)
This commit is contained in:
@@ -80,6 +80,7 @@ See instructions to run Wallos below.
|
||||
```bash
|
||||
0 1 * * * php /var/www/html/endpoints/cronjobs/updatenextpayment.php >> /var/log/cron/updatenextpayment.log 2>&1
|
||||
0 2 * * * php /var/www/html/endpoints/cronjobs/updateexchange.php >> /var/log/cron/updateexchange.log 2>&1
|
||||
0 8 * * * php /var/www/html/endpoints/cronjobs/sendcancellationnotifications.php >> /var/log/cron/sendcancellationnotifications.log 2>&1
|
||||
0 9 * * * php /var/www/html/endpoints/cronjobs/sendnotifications.php >> /var/log/cron/sendnotifications.log 2>&1
|
||||
*/2 * * * * php /var/www/html/endpoints/cronjobs/sendverificationemails.php >> /var/log/cron/sendverificationemail.log 2>&1
|
||||
*/2 * * * * php /var/www/html/endpoints/cronjobs/sendresetpasswordemails.php >> /var/log/cron/sendresetpasswordemails.log 2>&1
|
||||
@@ -138,6 +139,8 @@ If you want to trigger an Update of the exchange rates, change your main currenc
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
 
|
||||
|
||||
1
cronjobs
1
cronjobs
@@ -1,6 +1,7 @@
|
||||
# Run the scripts every day
|
||||
0 1 * * * /usr/local/bin/php /var/www/html/endpoints/cronjobs/updatenextpayment.php >> /var/log/cron/updatenextpayment.log 2>&1
|
||||
0 2 * * * /usr/local/bin/php /var/www/html/endpoints/cronjobs/updateexchange.php >> /var/log/cron/updateexchange.log 2>&1
|
||||
0 8 * * * /usr/local/bin/php /var/www/html/endpoints/cronjobs/sendcancellationnotifications.php >> /var/log/cron/sendcancellationnotifications.log 2>&1
|
||||
0 9 * * * /usr/local/bin/php /var/www/html/endpoints/cronjobs/sendnotifications.php >> /var/log/cron/sendnotifications.log 2>&1
|
||||
*/2 * * * * /usr/local/bin/php /var/www/html/endpoints/cronjobs/sendverificationemails.php >> /var/log/cron/sendverificationemails.log 2>&1
|
||||
*/2 * * * * /usr/local/bin/php /var/www/html/endpoints/cronjobs/sendresetpasswordemails.php >> /var/log/cron/sendresetpasswordemails.log 2>&1
|
||||
|
||||
470
endpoints/cronjobs/sendcancellationnotifications.php
Normal file
470
endpoints/cronjobs/sendcancellationnotifications.php
Normal file
@@ -0,0 +1,470 @@
|
||||
<?php
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\SMTP;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
|
||||
require_once __DIR__ . '/../../includes/connect_endpoint_crontabs.php';
|
||||
|
||||
require __DIR__ . '/../../libs/PHPMailer/PHPMailer.php';
|
||||
require __DIR__ . '/../../libs/PHPMailer/SMTP.php';
|
||||
require __DIR__ . '/../../libs/PHPMailer/Exception.php';
|
||||
|
||||
// Get all user ids
|
||||
$query = "SELECT id, username FROM user";
|
||||
$stmt = $db->prepare($query);
|
||||
$usersToNotify = $stmt->execute();
|
||||
|
||||
while ($userToNotify = $usersToNotify->fetchArray(SQLITE3_ASSOC)) {
|
||||
$userId = $userToNotify['id'];
|
||||
echo "For user: " . $userToNotify['username'] . "<br />";
|
||||
|
||||
$emailNotificationsEnabled = false;
|
||||
$gotifyNotificationsEnabled = false;
|
||||
$telegramNotificationsEnabled = false;
|
||||
$pushoverNotificationsEnabled = false;
|
||||
$discordNotificationsEnabled = false;
|
||||
$ntfyNotificationsEnabled = false;
|
||||
|
||||
// Check if email notifications are enabled and get the settings
|
||||
$query = "SELECT * FROM email_notifications WHERE user_id = :userId";
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
|
||||
if ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
$emailNotificationsEnabled = $row['enabled'];
|
||||
$email['smtpAddress'] = $row["smtp_address"];
|
||||
$email['smtpPort'] = $row["smtp_port"];
|
||||
$email['encryption'] = $row["encryption"];
|
||||
$email['smtpUsername'] = $row["smtp_username"];
|
||||
$email['smtpPassword'] = $row["smtp_password"];
|
||||
$email['fromEmail'] = $row["from_email"] ? $row["from_email"] : "wallos@wallosapp.com";
|
||||
}
|
||||
|
||||
// Check if Discord notifications are enabled and get the settings
|
||||
$query = "SELECT * FROM discord_notifications WHERE user_id = :userId";
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
|
||||
if ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
$discordNotificationsEnabled = $row['enabled'];
|
||||
$discord['webhook_url'] = $row["webhook_url"];
|
||||
$discord['bot_username'] = $row["bot_username"];
|
||||
$discord['bot_avatar_url'] = $row["bot_avatar_url"];
|
||||
}
|
||||
|
||||
// Check if Gotify notifications are enabled and get the settings
|
||||
$query = "SELECT * FROM gotify_notifications WHERE user_id = :userId";
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
|
||||
$gotify = [];
|
||||
|
||||
if ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
$gotifyNotificationsEnabled = $row['enabled'];
|
||||
$gotify['serverUrl'] = $row["url"];
|
||||
$gotify['appToken'] = $row["token"];
|
||||
}
|
||||
|
||||
// Check if Telegram notifications are enabled and get the settings
|
||||
$query = "SELECT * FROM telegram_notifications WHERE user_id = :userId";
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
|
||||
if ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
$telegramNotificationsEnabled = $row['enabled'];
|
||||
$telegram['botToken'] = $row["bot_token"];
|
||||
$telegram['chatId'] = $row["chat_id"];
|
||||
}
|
||||
|
||||
// Check if Pushover notifications are enabled and get the settings
|
||||
$query = "SELECT * FROM pushover_notifications WHERE user_id = :userId";
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
|
||||
if ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
$pushoverNotificationsEnabled = $row['enabled'];
|
||||
$pushover['user_key'] = $row["user_key"];
|
||||
$pushover['token'] = $row["token"];
|
||||
}
|
||||
|
||||
// Check if Ntfy notifications are enabled and get the settings
|
||||
$query = "SELECT * FROM ntfy_notifications WHERE user_id = :userId";
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
|
||||
if ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
$ntfyNotificationsEnabled = $row['enabled'];
|
||||
$ntfy['host'] = $row["host"];
|
||||
$ntfy['topic'] = $row["topic"];
|
||||
$ntfy['headers'] = $row["headers"];
|
||||
}
|
||||
|
||||
$notificationsEnabled = $emailNotificationsEnabled || $gotifyNotificationsEnabled || $telegramNotificationsEnabled ||
|
||||
$pushoverNotificationsEnabled || $discordNotificationsEnabled ||$ntfyNotificationsEnabled;
|
||||
|
||||
// If no notifications are enabled, no need to run
|
||||
if (!$notificationsEnabled) {
|
||||
echo "Notifications are disabled. No need to run.<br />";
|
||||
continue;
|
||||
} else {
|
||||
// Get all currencies
|
||||
$currencies = array();
|
||||
$query = "SELECT * FROM currencies WHERE user_id = :userId";
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
|
||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
$currencies[$row['id']] = $row;
|
||||
}
|
||||
|
||||
// Get all household members
|
||||
$query = "SELECT * FROM household WHERE user_id = :userId";
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
$resultHousehold = $stmt->execute();
|
||||
|
||||
$household = [];
|
||||
while ($rowHousehold = $resultHousehold->fetchArray(SQLITE3_ASSOC)) {
|
||||
$household[$rowHousehold['id']] = $rowHousehold;
|
||||
}
|
||||
|
||||
// Get all categories
|
||||
$query = "SELECT * FROM categories WHERE user_id = :userId";
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
$resultCategories = $stmt->execute();
|
||||
|
||||
$categories = [];
|
||||
while ($rowCategory = $resultCategories->fetchArray(SQLITE3_ASSOC)) {
|
||||
$categories[$rowCategory['id']] = $rowCategory;
|
||||
}
|
||||
|
||||
// Get current date to check which subscriptions are set to notify for cancellation
|
||||
$currentDate = new DateTime('now');
|
||||
$currentDate = $currentDate->format('Y-m-d');
|
||||
|
||||
$query = "SELECT * FROM subscriptions WHERE user_id = :user_id AND inactive = :inactive AND cancellation_date = :cancellationDate ORDER BY payer_user_id ASC";
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->bindValue(':user_id', $userId, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':inactive', 0, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':cancellationDate', $currentDate, SQLITE3_TEXT);
|
||||
$resultSubscriptions = $stmt->execute();
|
||||
|
||||
$notify = [];
|
||||
$i = 0;
|
||||
$currentDate = new DateTime('now');
|
||||
while ($rowSubscription = $resultSubscriptions->fetchArray(SQLITE3_ASSOC)) {
|
||||
$notify[$rowSubscription['payer_user_id']][$i]['name'] = $rowSubscription['name'];
|
||||
$notify[$rowSubscription['payer_user_id']][$i]['price'] = $rowSubscription['price'] . $currencies[$rowSubscription['currency_id']]['symbol'];
|
||||
$notify[$rowSubscription['payer_user_id']][$i]['currency'] = $currencies[$rowSubscription['currency_id']]['name'];
|
||||
$notify[$rowSubscription['payer_user_id']][$i]['category'] = $categories[$rowSubscription['category_id']]['name'];
|
||||
$notify[$rowSubscription['payer_user_id']][$i]['payer'] = $household[$rowSubscription['payer_user_id']]['name'];
|
||||
$notify[$rowSubscription['payer_user_id']][$i]['date'] = $rowSubscription['next_payment'];
|
||||
$i++;
|
||||
}
|
||||
|
||||
if (!empty($notify)) {
|
||||
|
||||
// Email notifications if enabled
|
||||
if ($emailNotificationsEnabled) {
|
||||
|
||||
$stmt = $db->prepare('SELECT * FROM user WHERE id = :user_id');
|
||||
$stmt->bindValue(':user_id', $userId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
$defaultUser = $result->fetchArray(SQLITE3_ASSOC);
|
||||
$defaultEmail = $defaultUser['email'];
|
||||
$defaultName = $defaultUser['username'];
|
||||
|
||||
foreach ($notify as $userId => $perUser) {
|
||||
$message = "The following subscriptions are up for cancellation:\n";
|
||||
|
||||
foreach ($perUser as $subscription) {
|
||||
$message .= $subscription['name'] . " for " . $subscription['price'] ."\n";
|
||||
}
|
||||
|
||||
$mail = new PHPMailer(true);
|
||||
$mail->CharSet = "UTF-8";
|
||||
$mail->isSMTP();
|
||||
|
||||
$mail->Host = $email['smtpAddress'];
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = $email['smtpUsername'];
|
||||
$mail->Password = $email['smtpPassword'];
|
||||
$mail->SMTPSecure = $email['encryption'];
|
||||
$mail->Port = $email['smtpPort'];
|
||||
|
||||
$stmt = $db->prepare('SELECT * FROM household WHERE id = :userId');
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
$user = $result->fetchArray(SQLITE3_ASSOC);
|
||||
|
||||
$emailaddress = !empty($user['email']) ? $user['email'] : $defaultEmail;
|
||||
$name = !empty($user['name']) ? $user['name'] : $defaultName;
|
||||
|
||||
$mail->setFrom($email['fromEmail'], 'Wallos App');
|
||||
$mail->addAddress($emailaddress, $name);
|
||||
|
||||
$mail->Subject = 'Wallos Cancellation Notification';
|
||||
$mail->Body = $message;
|
||||
|
||||
if ($mail->send()) {
|
||||
echo "Email Notifications sent<br />";
|
||||
} else {
|
||||
echo "Error sending notifications: " . $mail->ErrorInfo . "<br />";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Discord notifications if enabled
|
||||
if ($discordNotificationsEnabled) {
|
||||
foreach ($notify as $userId => $perUser) {
|
||||
// Get name of user from household table
|
||||
$stmt = $db->prepare('SELECT * FROM household WHERE id = :userId');
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
$user = $result->fetchArray(SQLITE3_ASSOC);
|
||||
|
||||
$title = translate('wallos_notification', $i18n);
|
||||
|
||||
if ($user['name']) {
|
||||
$message = $user['name'] . ", the following subscriptions are up for cancellation:\n";
|
||||
} else {
|
||||
$message = "The following subscriptions are up for cancellation:\n";
|
||||
}
|
||||
|
||||
foreach ($perUser as $subscription) {
|
||||
$message .= $subscription['name'] . " for " . $subscription['price'] . "\n";
|
||||
}
|
||||
|
||||
$postfields = [
|
||||
'content' => $message
|
||||
];
|
||||
|
||||
if (!empty($discord['bot_username'])) {
|
||||
$postfields['username'] = $discord['bot_username'];
|
||||
}
|
||||
|
||||
if (!empty($discord['bot_avatar_url'])) {
|
||||
$postfields['avatar_url'] = $discord['bot_avatar_url'];
|
||||
}
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, $discord['webhook_url']);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postfields));
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/json'
|
||||
]);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($result === false) {
|
||||
echo "Error sending notifications: " . curl_error($ch) . "<br />";
|
||||
} else {
|
||||
echo "Discord Notifications sent<br />";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gotify notifications if enabled
|
||||
if ($gotifyNotificationsEnabled) {
|
||||
foreach ($notify as $userId => $perUser) {
|
||||
// Get name of user from household table
|
||||
$stmt = $db->prepare('SELECT * FROM household WHERE id = :userId');
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
$user = $result->fetchArray(SQLITE3_ASSOC);
|
||||
|
||||
if ($user['name']) {
|
||||
$message = $user['name'] . ", the following subscriptions are up for cancellation:\n";
|
||||
} else {
|
||||
$message = "The following subscriptions are up for cancellation:\n";
|
||||
}
|
||||
|
||||
foreach ($perUser as $subscription) {
|
||||
$message .= $subscription['name'] . " for " . $subscription['price'] . "\n";
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'message' => $message,
|
||||
'priority' => 5
|
||||
);
|
||||
|
||||
$data_string = json_encode($data);
|
||||
|
||||
$ch = curl_init($gotify['serverUrl'] . '/message?token=' . $gotify['appToken']);
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt(
|
||||
$ch,
|
||||
CURLOPT_HTTPHEADER,
|
||||
array(
|
||||
'Content-Type: application/json',
|
||||
'Content-Length: ' . strlen($data_string)
|
||||
)
|
||||
);
|
||||
|
||||
$result = curl_exec($ch);
|
||||
if ($result === false) {
|
||||
echo "Error sending notifications: " . curl_error($ch) . "<br />";
|
||||
} else {
|
||||
echo "Gotify Notifications sent<br />";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Telegram notifications if enabled
|
||||
if ($telegramNotificationsEnabled) {
|
||||
foreach ($notify as $userId => $perUser) {
|
||||
// Get name of user from household table
|
||||
$stmt = $db->prepare('SELECT * FROM household WHERE id = :userId');
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
$user = $result->fetchArray(SQLITE3_ASSOC);
|
||||
|
||||
if ($user['name']) {
|
||||
$message = $user['name'] . ", the following subscriptions are up for cancellation:\n";
|
||||
} else {
|
||||
$message = "The following subscriptions are up for cancellation:\n";
|
||||
}
|
||||
|
||||
foreach ($perUser as $subscription) {
|
||||
$message .= $subscription['name'] . " for " . $subscription['price'] . "\n";
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'chat_id' => $telegram['chatId'],
|
||||
'text' => $message
|
||||
);
|
||||
|
||||
$data_string = json_encode($data);
|
||||
|
||||
$ch = curl_init('https://api.telegram.org/bot' . $telegram['botToken'] . '/sendMessage');
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt(
|
||||
$ch,
|
||||
CURLOPT_HTTPHEADER,
|
||||
array(
|
||||
'Content-Type: application/json',
|
||||
'Content-Length: ' . strlen($data_string)
|
||||
)
|
||||
);
|
||||
|
||||
$result = curl_exec($ch);
|
||||
if ($result === false) {
|
||||
echo "Error sending notifications: " . curl_error($ch) . "<br />";
|
||||
} else {
|
||||
echo "Telegram Notifications sent<br />";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pushover notifications if enabled
|
||||
if ($pushoverNotificationsEnabled) {
|
||||
foreach ($notify as $userId => $perUser) {
|
||||
// Get name of user from household table
|
||||
$stmt = $db->prepare('SELECT * FROM household WHERE id = :userId');
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
$user = $result->fetchArray(SQLITE3_ASSOC);
|
||||
|
||||
if ($user['name']) {
|
||||
$message = $user['name'] . ", the following subscriptions are up for cancellation:\n";
|
||||
} else {
|
||||
$message = "The following subscriptions are up for cancellation:\n";
|
||||
}
|
||||
|
||||
foreach ($perUser as $subscription) {
|
||||
$message .= $subscription['name'] . " for " . $subscription['price'] . "\n";
|
||||
}
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, "https://api.pushover.net/1/messages.json");
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
|
||||
'token' => $pushover['token'],
|
||||
'user' => $pushover['user_key'],
|
||||
'message' => $message,
|
||||
]));
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
$result = curl_exec($ch);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
if ($result === false) {
|
||||
echo "Error sending notifications: " . curl_error($ch) . "<br />";
|
||||
} else {
|
||||
echo "Pushover Notifications sent<br />";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ntfy notifications if enabled
|
||||
if ($ntfyNotificationsEnabled) {
|
||||
foreach ($notify as $userId => $perUser) {
|
||||
// Get name of user from household table
|
||||
$stmt = $db->prepare('SELECT * FROM household WHERE id = :userId');
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
$user = $result->fetchArray(SQLITE3_ASSOC);
|
||||
|
||||
if ($user['name']) {
|
||||
$message = $user['name'] . ", the following subscriptions are up for cancellation:\n";
|
||||
} else {
|
||||
$message = "The following subscriptions are up for cancellation:\n";
|
||||
}
|
||||
|
||||
foreach ($perUser as $subscription) {
|
||||
$message .= $subscription['name'] . " for " . $subscription['price'] . "\n";
|
||||
}
|
||||
|
||||
$headers = json_decode($ntfy["headers"], true);
|
||||
$customheaders = array_map(function ($key, $value) {
|
||||
return "$key: $value";
|
||||
}, array_keys($headers), $headers);
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
$ntfyHost = rtrim($ntfy["host"], '/');
|
||||
$ntfyTopic = $ntfy['topic'];
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, $ntfyHost . '/' . $ntfyTopic);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $message);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $customheaders);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($response === false) {
|
||||
echo "Error sending notifications: " . curl_error($ch) . "<br />";
|
||||
} else {
|
||||
echo "Ntfy Notifications sent<br />";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
echo "Nothing to notify.<br />";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -105,7 +105,7 @@ while ($userToNotify = $usersToNotify->fetchArray(SQLITE3_ASSOC)) {
|
||||
$pushover['token'] = $row["token"];
|
||||
}
|
||||
|
||||
// Check if Nrfy notifications are enabled and get the settings
|
||||
// Check if Ntfy notifications are enabled and get the settings
|
||||
$query = "SELECT * FROM ntfy_notifications WHERE user_id = :userId";
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->bindValue(':userId', $userId, SQLITE3_INTEGER);
|
||||
|
||||
@@ -172,6 +172,7 @@ if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
|
||||
$notify = isset($_POST['notifications']) ? true : false;
|
||||
$notifyDaysBefore = $_POST['notify_days_before'];
|
||||
$inactive = isset($_POST['inactive']) ? true : false;
|
||||
$cancellationDate = $_POST['cancellation_date'] ?? null;
|
||||
|
||||
if ($logoUrl !== "") {
|
||||
$logo = getLogoFromUrl($logoUrl, '../../images/uploads/logos/', $name, $settings, $i18n);
|
||||
@@ -188,21 +189,21 @@ if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
|
||||
|
||||
if (!$isEdit) {
|
||||
$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)
|
||||
payment_method_id, payer_user_id, category_id, notify, inactive, url, notify_days_before, user_id, cancellation_date)
|
||||
VALUES (:name, :logo, :price, :currencyId, :nextPayment, :cycle, :frequency, :notes,
|
||||
:paymentMethodId, :payerUserId, :categoryId, :notify, :inactive, :url, :notifyDaysBefore, :userId)";
|
||||
:paymentMethodId, :payerUserId, :categoryId, :notify, :inactive, :url, :notifyDaysBefore, :userId, :cancellationDate)";
|
||||
} else {
|
||||
$id = $_POST['id'];
|
||||
if ($logo != "") {
|
||||
$sql = "UPDATE subscriptions SET name = :name, logo = :logo, price = :price, currency_id = :currencyId,
|
||||
next_payment = :nextPayment, cycle = :cycle, frequency = :frequency, notes = :notes, payment_method_id = :paymentMethodId,
|
||||
payer_user_id = :payerUserId, category_id = :categoryId, notify = :notify, inactive = :inactive,
|
||||
url = :url, notify_days_before = :notifyDaysBefore WHERE id = :id AND user_id = :userId";
|
||||
url = :url, notify_days_before = :notifyDaysBefore, camcelation_date = :cancellationDate WHERE id = :id AND user_id = :userId";
|
||||
} else {
|
||||
$sql = "UPDATE subscriptions SET name = :name, price = :price, currency_id = :currencyId, next_payment = :nextPayment,
|
||||
cycle = :cycle, frequency = :frequency, notes = :notes, payment_method_id = :paymentMethodId, payer_user_id = :payerUserId,
|
||||
category_id = :categoryId, notify = :notify, inactive = :inactive, url = :url,notify_days_before = :notifyDaysBefore
|
||||
WHERE id = :id AND user_id = :userId";
|
||||
category_id = :categoryId, notify = :notify, inactive = :inactive, url = :url, notify_days_before = :notifyDaysBefore,
|
||||
cancellation_date = :cancellationDate WHERE id = :id AND user_id = :userId";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,6 +229,7 @@ if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
|
||||
$stmt->bindParam(':url', $url, SQLITE3_TEXT);
|
||||
$stmt->bindParam(':notifyDaysBefore', $notifyDaysBefore, SQLITE3_INTEGER);
|
||||
$stmt->bindParam(':userId', $userId, SQLITE3_INTEGER);
|
||||
$stmt->bindParam(':cancellationDate', $cancellationDate, SQLITE3_TEXT);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
$success['status'] = "Success";
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
]));
|
||||
}
|
||||
|
||||
$query = "INSERT INTO subscriptions (name, logo, price, currency_id, next_payment, cycle, frequency, notes, payment_method_id, payer_user_id, category_id, notify, url, inactive, notify_days_before, user_id) VALUES (:name, :logo, :price, :currency_id, :next_payment, :cycle, :frequency, :notes, :payment_method_id, :payer_user_id, :category_id, :notify, :url, :inactive, :notify_days_before, :user_id)";
|
||||
$query = "INSERT INTO subscriptions (name, logo, price, currency_id, next_payment, cycle, frequency, notes, payment_method_id, payer_user_id, category_id, notify, url, inactive, notify_days_before, user_id, cancellation_date) VALUES (:name, :logo, :price, :currency_id, :next_payment, :cycle, :frequency, :notes, :payment_method_id, :payer_user_id, :category_id, :notify, :url, :inactive, :notify_days_before, :user_id, :cancellation_date)";
|
||||
$cloneStmt = $db->prepare($query);
|
||||
$cloneStmt->bindValue(':name', $subscriptionToClone['name'], SQLITE3_TEXT);
|
||||
$cloneStmt->bindValue(':logo', $subscriptionToClone['logo'], SQLITE3_TEXT);
|
||||
@@ -35,6 +35,7 @@
|
||||
$cloneStmt->bindValue(':inactive', $subscriptionToClone['inactive'], SQLITE3_INTEGER);
|
||||
$cloneStmt->bindValue(':notify_days_before', $subscriptionToClone['notify_days_before'], SQLITE3_INTEGER);
|
||||
$cloneStmt->bindValue(':user_id', $userId, SQLITE3_INTEGER);
|
||||
$cloneStmt->bindValue(':cancellation_date', $subscriptionToClone['cancellation_date'], SQLITE3_TEXT);
|
||||
|
||||
if ($cloneStmt->execute()) {
|
||||
$response = [
|
||||
|
||||
@@ -29,6 +29,7 @@ if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
|
||||
$subscriptionData['inactive'] = $row['inactive'];
|
||||
$subscriptionData['url'] = htmlspecialchars_decode($row['url'] ?? "");
|
||||
$subscriptionData['notify_days_before'] = $row['notify_days_before'];
|
||||
$subscriptionData['cancellation_date'] = $row['cancellation_date'];
|
||||
|
||||
$subscriptionJson = json_encode($subscriptionData);
|
||||
header('Content-Type: application/json');
|
||||
|
||||
@@ -83,6 +83,7 @@ $i18n = [
|
||||
"notes" => "Notizen",
|
||||
"enable_notifications" => "Benachrichtigungen für dieses Abonnement aktivieren",
|
||||
"default_value_from_settings" => "Standardwert aus den Einstellungen",
|
||||
"cancellation_notification" => "Benachrichtigung bei Kündigung",
|
||||
"delete" => "Löschen",
|
||||
"cancel" => "Abbrechen",
|
||||
"upload_logo" => "Logo hochladen",
|
||||
|
||||
@@ -83,6 +83,7 @@ $i18n = [
|
||||
"notes" => "Σημειώσεις",
|
||||
"enable_notifications" => "Ενεργοποίηση ειδοποιήσεων για αυτή τη συνδρομή",
|
||||
"default_value_from_settings" => "Προεπιλεγμένη τιμή από τις ρυθμίσεις",
|
||||
"cancellation_notification" => "Ειδοποίηση ακύρωσης",
|
||||
"delete" => "Διαγραφή",
|
||||
"cancel" => "Ακύρωση",
|
||||
"upload_logo" => "Φόρτωση λογότυπου",
|
||||
|
||||
@@ -83,6 +83,7 @@ $i18n = [
|
||||
"notes" => "Notes",
|
||||
"enable_notifications" => "Enable Notifications for this subscription",
|
||||
"default_value_from_settings" => "Default value from settings",
|
||||
"cancellation_notification" => "cancellation Notification",
|
||||
"delete" => "Delete",
|
||||
"cancel" => "Cancel",
|
||||
"upload_logo" => "Upload Logo",
|
||||
|
||||
@@ -83,6 +83,7 @@ $i18n = [
|
||||
"notes" => "Notas",
|
||||
"enable_notifications" => "Habilitar notificaciones para esta suscripción",
|
||||
"default_value_from_settings" => "Valor predeterminado de la configuración",
|
||||
"cancellation_notification" => "Notificación de cancelación",
|
||||
"delete" => "Eliminar",
|
||||
"cancel" => "Cancelar",
|
||||
"upload_logo" => "Cargar Logotipo",
|
||||
|
||||
@@ -83,6 +83,7 @@ $i18n = [
|
||||
"notes" => "Notes",
|
||||
"enable_notifications" => "Activer les notifications pour cet abonnement",
|
||||
"default_value_from_settings" => "Valeur par défaut des paramètres",
|
||||
"cancellation_notification" => "Notification d'annulation",
|
||||
"delete" => "Supprimer",
|
||||
"cancel" => "Annuler",
|
||||
"upload_logo" => "Télécharger le logo",
|
||||
|
||||
@@ -88,6 +88,7 @@ $i18n = [
|
||||
'notes' => 'Note',
|
||||
'enable_notifications' => 'Abilita notifiche per questo abbonamento',
|
||||
'default_value_from_settings' => 'Valore predefinito dalle impostazioni',
|
||||
"cancellation_notification" => "Notifica di cancellazione",
|
||||
'delete' => 'Cancella',
|
||||
'cancel' => 'Annulla',
|
||||
'upload_logo' => 'Carica logo',
|
||||
|
||||
@@ -83,6 +83,7 @@ $i18n = [
|
||||
"notes" => "注釈",
|
||||
"enable_notifications" => "この定期購入の通知を有効にする",
|
||||
"default_value_from_settings" => "設定からデフォルト値を使用",
|
||||
"cancellation_notification" => "キャンセル通知",
|
||||
"delete" => "削除",
|
||||
"cancel" => "キャンセル",
|
||||
"upload_logo" => "ロゴのアップロード",
|
||||
|
||||
@@ -83,6 +83,7 @@ $i18n = [
|
||||
"notes" => "메모",
|
||||
"enable_notifications" => "이 구독에 대한 알림을 활성화합니다.",
|
||||
"default_value_from_settings" => "설정에서 기본값 사용",
|
||||
"cancellation_notification" => "구독 취소 알림",
|
||||
"delete" => "삭제",
|
||||
"cancel" => "취소",
|
||||
"upload_logo" => "로고 업로드",
|
||||
|
||||
@@ -83,6 +83,7 @@ $i18n = [
|
||||
"notes" => "Notatki",
|
||||
"enable_notifications" => "Włącz powiadomienia dla tej subskrypcji",
|
||||
"default_value_from_settings" => "Wartość domyślna z ustawień",
|
||||
"cancellation_notification" => "Powiadomienie o anulowaniu",
|
||||
"delete" => "Usuń",
|
||||
"cancel" => "Anuluj",
|
||||
"upload_logo" => "Prześlij logo",
|
||||
|
||||
@@ -83,6 +83,7 @@ $i18n = [
|
||||
"notes" => "Notas",
|
||||
"enable_notifications" => "Activar notificações para esta subscrição",
|
||||
"default_value_from_settings" => "Valor por defeito das definições",
|
||||
"cancellation_notification" => "Notificação de cancelamento",
|
||||
"delete" => "Remover",
|
||||
"cancel" => "Cancelar",
|
||||
"upload_logo" => "Enviar Logo",
|
||||
|
||||
@@ -83,6 +83,7 @@ $i18n = [
|
||||
"notes" => "Anotações",
|
||||
"enable_notifications" => "Ativar notificações para essa assinatura",
|
||||
"default_value_from_settings" => "Valor padrão das configurações",
|
||||
"cancellation_notification" => "Notificação de cancelamento",
|
||||
"delete" => "Excluir",
|
||||
"cancel" => "Cancelar",
|
||||
"upload_logo" => "Enviar Logo",
|
||||
|
||||
@@ -83,6 +83,7 @@ $i18n = [
|
||||
"notes" => "Примечания",
|
||||
"enable_notifications" => "Включить уведомления для этой подписки",
|
||||
"default_value_from_settings" => "Значение по умолчанию из настроек",
|
||||
"cancellation_notification" => "Уведомление об отмене",
|
||||
"delete" => "Удалить",
|
||||
"cancel" => "Отмена",
|
||||
"upload_logo" => "Загрузить логотип",
|
||||
|
||||
@@ -83,6 +83,7 @@ $i18n = [
|
||||
"notes" => "Opombe",
|
||||
"enable_notifications" => "Omogoči obvestila za to naročnino",
|
||||
"default_value_from_settings" => "Privzeta vrednost iz nastavitev",
|
||||
"cancellation_notification" => "Obvestilo o preklicu",
|
||||
"delete" => "Izbriši",
|
||||
"cancel" => "Prekliči",
|
||||
"upload_logo" => "Naloži logotip",
|
||||
|
||||
@@ -82,6 +82,8 @@ $i18n = [
|
||||
"url" => "URL",
|
||||
"notes" => "Напомене",
|
||||
"enable_notifications" => "Омогући обавештења за ову претплату",
|
||||
"default_value_from_settings" => "Подразумевана вредност из подешавања",
|
||||
"cancellation_notification" => "Обавештење о отказивању",
|
||||
"delete" => "Обриши",
|
||||
"cancel" => "Откажи",
|
||||
"upload_logo" => "Постави логотип",
|
||||
|
||||
@@ -83,6 +83,7 @@ $i18n = [
|
||||
"notes" => "Beleške",
|
||||
"enable_notifications" => "Omogući obaveštenja za ovu pretplatu",
|
||||
"default_value_from_settings" => "Podrazumevana vrednost iz podešavanja",
|
||||
"cancellation_notification" => "Obaveštenje o otkazivanju",
|
||||
"delete" => "Izbriši",
|
||||
"cancel" => "Otkaži",
|
||||
"upload_logo" => "Učitaj logo",
|
||||
|
||||
@@ -83,6 +83,7 @@ $i18n = [
|
||||
"notes" => "Notlar",
|
||||
"enable_notifications" => "Bu abonelik için bildirimleri etkinleştir",
|
||||
"default_value_from_settings" => "Ayarlar'dan varsayılan değeri al",
|
||||
"cancellation_notification" => "İptal Bildirimi",
|
||||
"delete" => "Sil",
|
||||
"cancel" => "İptal",
|
||||
"upload_logo" => "Logo Yükle",
|
||||
|
||||
@@ -88,6 +88,7 @@ $i18n = [
|
||||
"notes" => "备注",
|
||||
"enable_notifications" => "为此订阅启用通知",
|
||||
"default_value_from_settings" => "默认值从设置中获取",
|
||||
"cancellation_notification" => "取消通知",
|
||||
"delete" => "删除",
|
||||
"cancel" => "取消",
|
||||
"upload_logo" => "上传 Logo",
|
||||
|
||||
@@ -83,6 +83,7 @@ $i18n = [
|
||||
"notes" => "備註",
|
||||
"enable_notifications" => "為該訂閱開啟通知",
|
||||
"default_value_from_settings" => "從設定中取得預設值",
|
||||
"cancellation_notification" => "取消通知",
|
||||
"delete" => "刪除",
|
||||
"cancel" => "取消",
|
||||
"upload_logo" => "上傳圖示",
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<?php
|
||||
$version = "v2.13.0";
|
||||
$version = "v2.14.0";
|
||||
?>
|
||||
112
index.php
112
index.php
@@ -93,7 +93,8 @@ $headerClass = count($subscriptions) > 0 ? "main-actions" : "main-actions hidden
|
||||
}
|
||||
?>
|
||||
<div class="filter-item <?= $selectedClass ?>" data-categoryid="<?= $category['id'] ?>">
|
||||
<?= $category['name'] ?></div>
|
||||
<?= $category['name'] ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
@@ -116,7 +117,8 @@ $headerClass = count($subscriptions) > 0 ? "main-actions" : "main-actions hidden
|
||||
}
|
||||
?>
|
||||
<div class="filter-item <?= $selectedClass ?>" data-paymentid="<?= $payment['id'] ?>">
|
||||
<?= $payment['name'] ?></div>
|
||||
<?= $payment['name'] ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
@@ -141,11 +143,14 @@ $headerClass = count($subscriptions) > 0 ? "main-actions" : "main-actions hidden
|
||||
<div class="sort-options" id="sort-options">
|
||||
<ul>
|
||||
<li <?= $sort == "name" ? 'class="selected"' : "" ?> onClick="setSortOption('name')" id="sort-name">
|
||||
<?= translate('name', $i18n) ?></li>
|
||||
<?= translate('name', $i18n) ?>
|
||||
</li>
|
||||
<li <?= $sort == "id" ? 'class="selected"' : "" ?> onClick="setSortOption('id')" id="sort-id">
|
||||
<?= translate('last_added', $i18n) ?></li>
|
||||
<?= translate('last_added', $i18n) ?>
|
||||
</li>
|
||||
<li <?= $sort == "price" ? 'class="selected"' : "" ?> onClick="setSortOption('price')" id="sort-price">
|
||||
<?= translate('price', $i18n) ?></li>
|
||||
<?= translate('price', $i18n) ?>
|
||||
</li>
|
||||
<li <?= $sort == "next_payment" ? 'class="selected"' : "" ?> onClick="setSortOption('next_payment')"
|
||||
id="sort-next_payment"><?= translate('next_payment', $i18n) ?></li>
|
||||
<li <?= $sort == "payer_user_id" ? 'class="selected"' : "" ?> onClick="setSortOption('payer_user_id')"
|
||||
@@ -283,7 +288,8 @@ $headerClass = count($subscriptions) > 0 ? "main-actions" : "main-actions hidden
|
||||
foreach ($cycles as $cycle) {
|
||||
?>
|
||||
<option value="<?= $cycle['id'] ?>" <?= $cycle['id'] == 3 ? "selected" : "" ?>>
|
||||
<?= translate(strtolower($cycle['name']), $i18n) ?></option>
|
||||
<?= translate(strtolower($cycle['name']), $i18n) ?>
|
||||
</option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
@@ -297,39 +303,35 @@ $headerClass = count($subscriptions) > 0 ? "main-actions" : "main-actions hidden
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group-inline">
|
||||
<input type="checkbox" id="notifications" name="notifications" onchange="toggleNotificationDays()">
|
||||
<label for="notifications"><?= translate('enable_notifications', $i18n) ?></label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="notify_days_before"><?= translate('notify_me', $i18n) ?></label>
|
||||
<select id="notify_days_before" name="notify_days_before" disabled>
|
||||
<option value="0"><?= translate('default_value_from_settings', $i18n) ?></option>
|
||||
<option value="1">1 <?= translate('day_before', $i18n) ?></option>
|
||||
<?php
|
||||
for ($i = 2; $i <= 90; $i++) {
|
||||
?>
|
||||
<option value="<?= $i ?>"><?= $i ?> <?= translate('days_before', $i18n) ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="payment_method"><?= translate('payment_method', $i18n) ?></label>
|
||||
<select id="payment_method" name="payment_method_id">
|
||||
<?php
|
||||
foreach ($payment_methods as $payment) {
|
||||
?>
|
||||
<option value="<?= $payment['id'] ?>">
|
||||
<?= $payment['name'] ?>
|
||||
</option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<div class="inline">
|
||||
<div class="split50">
|
||||
<label for="payment_method"><?= translate('payment_method', $i18n) ?></label>
|
||||
<select id="payment_method" name="payment_method_id">
|
||||
<?php
|
||||
foreach ($payment_methods as $payment) {
|
||||
?>
|
||||
<option value="<?= $payment['id'] ?>">
|
||||
<?= $payment['name'] ?>
|
||||
</option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="split50">
|
||||
<label for="payer_user"><?= translate('paid_by', $i18n) ?></label>
|
||||
<select id="payer_user" name="payer_user_id">
|
||||
<?php
|
||||
foreach ($members as $member) {
|
||||
?>
|
||||
<option value="<?= $member['id'] ?>"><?= $member['name'] ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@@ -347,18 +349,32 @@ $headerClass = count($subscriptions) > 0 ? "main-actions" : "main-actions hidden
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group-inline">
|
||||
<input type="checkbox" id="notifications" name="notifications" onchange="toggleNotificationDays()">
|
||||
<label for="notifications"><?= translate('enable_notifications', $i18n) ?></label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="payer_user"><?= translate('paid_by', $i18n) ?></label>
|
||||
<select id="payer_user" name="payer_user_id">
|
||||
<?php
|
||||
foreach ($members as $member) {
|
||||
?>
|
||||
<option value="<?= $member['id'] ?>"><?= $member['name'] ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<div class="inline">
|
||||
<div class="split66 mobile-split-50">
|
||||
<label for="notify_days_before"><?= translate('notify_me', $i18n) ?></label>
|
||||
<select id="notify_days_before" name="notify_days_before" disabled>
|
||||
<option value="0"><?= translate('default_value_from_settings', $i18n) ?></option>
|
||||
<option value="1">1 <?= translate('day_before', $i18n) ?></option>
|
||||
<?php
|
||||
for ($i = 2; $i <= 90; $i++) {
|
||||
?>
|
||||
<option value="<?= $i ?>"><?= $i ?> <?= translate('days_before', $i18n) ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="split33 mobile-split-50">
|
||||
<label for="cancellation_date"><?= translate('cancellation_notification', $i18n) ?></label>
|
||||
<input type="date" id="cancellation_date" name="cancellation_date">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
|
||||
10
migrations/000024.php
Normal file
10
migrations/000024.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
// This migration adds a "cancellation_date" column to the subscriptions table.
|
||||
|
||||
/** @noinspection PhpUndefinedVariableInspection */
|
||||
$columnQuery = $db->query("SELECT * FROM pragma_table_info('subscriptions') where name='cancellation_date'");
|
||||
$columnRequired = $columnQuery->fetchArray(SQLITE3_ASSOC) === false;
|
||||
|
||||
if ($columnRequired) {
|
||||
$db->exec('ALTER TABLE subscriptions ADD COLUMN cancellation_date DATE;');
|
||||
}
|
||||
BIN
screenshots/wallos-calendar.png
Normal file
BIN
screenshots/wallos-calendar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
@@ -74,6 +74,9 @@ function fillEditFormFields(subscription) {
|
||||
|
||||
const nextPament = document.querySelector("#next_payment");
|
||||
nextPament.value = subscription.next_payment;
|
||||
const cancellationDate = document.querySelector("#cancellation_date");
|
||||
cancellationDate.value = subscription.cancellation_date;
|
||||
|
||||
const notes = document.querySelector("#notes");
|
||||
notes.value = subscription.notes;
|
||||
const inactive = document.querySelector("#inactive");
|
||||
|
||||
@@ -228,4 +228,8 @@ input[type="radio"]:disabled + label::before {
|
||||
background-color: #333;
|
||||
border-color: #222;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
input {
|
||||
color-scheme: dark;
|
||||
}
|
||||
@@ -1006,6 +1006,20 @@ header #avatar {
|
||||
flex-basis: 66.66%;
|
||||
}
|
||||
|
||||
.form-group .inline .split50 {
|
||||
flex-basis: 50%;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.form-group .inline .mobile-split-50 {
|
||||
flex-basis: 50%;
|
||||
}
|
||||
|
||||
select#frequency {
|
||||
width: 100px;
|
||||
padding: 0px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
|
||||
Reference in New Issue
Block a user