Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added custom payment methods #173

Merged
merged 2 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 183 additions & 0 deletions endpoints/payments/add.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
<?php
error_reporting(E_ERROR | E_PARSE);
require_once '../../includes/connect_endpoint.php';
require_once '../../includes/inputvalidation.php';
require_once '../../includes/getsettings.php';

session_start();

function sanitizeFilename($filename) {
$filename = preg_replace("/[^a-zA-Z0-9\s]/", "", $filename);
$filename = str_replace(" ", "-", $filename);
return $filename;
}

function getLogoFromUrl($url, $uploadDir, $name) {

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

$imageData = curl_exec($ch);

if ($imageData !== false) {
$timestamp = time();
$fileName = $timestamp . '-payments-' . sanitizeFilename($name) . '.png';
$uploadDir = '../../images/uploads/logos/';
$uploadFile = $uploadDir . $fileName;

if (saveLogo($imageData, $uploadFile, $name)) {
return $fileName;
} else {
echo translate('error_fetching_image', $i18n) . ": " . curl_error($ch);
return "";
}

curl_close($ch);
} else {
echo translate('error_fetching_image', $i18n) . ": " . curl_error($ch);
return "";
}
}

function saveLogo($imageData, $uploadFile, $name) {
$image = imagecreatefromstring($imageData);
$removeBackground = isset($settings['removeBackground']) && $settings['removeBackground'] === 'true';
if ($image !== false) {
$tempFile = tempnam(sys_get_temp_dir(), 'logo');
imagepng($image, $tempFile);
imagedestroy($image);

$imagick = new Imagick($tempFile);
if ($removeBackground) {
$fuzz = Imagick::getQuantum() * 0.1; // 10%
$imagick->transparentPaintImage("rgb(247, 247, 247)", 0, $fuzz, false);
}
$imagick->setImageFormat('png');
$imagick->writeImage($uploadFile);

$imagick->clear();
$imagick->destroy();
unlink($tempFile);

return true;
} else {
return false;
}
}

function resizeAndUploadLogo($uploadedFile, $uploadDir, $name) { $targetWidth = 70;
$targetHeight = 48;

$timestamp = time();
$originalFileName = $uploadedFile['name'];
$fileExtension = pathinfo($originalFileName, PATHINFO_EXTENSION);
$fileName = $timestamp . '-payments-' . sanitizeFilename($name) . '.' . $fileExtension;
$uploadFile = $uploadDir . $fileName;

if (move_uploaded_file($uploadedFile['tmp_name'], $uploadFile)) {
$fileInfo = getimagesize($uploadFile);

if ($fileInfo !== false) {
$width = $fileInfo[0];
$height = $fileInfo[1];

// Load the image based on its format
if ($fileExtension === 'png') {
$image = imagecreatefrompng($uploadFile);
} elseif ($fileExtension === 'jpg' || $fileExtension === 'jpeg') {
$image = imagecreatefromjpeg($uploadFile);
} else {
// Handle other image formats as needed
return "";
}

// Enable alpha channel (transparency) for PNG images
if ($fileExtension === 'png') {
imagesavealpha($image, true);
}

$newWidth = $width;
$newHeight = $height;

if ($width > $targetWidth) {
$newWidth = $targetWidth;
$newHeight = ($targetWidth / $width) * $height;
}

if ($newHeight > $targetHeight) {
$newWidth = ($targetHeight / $newHeight) * $newWidth;
$newHeight = $targetHeight;
}

$resizedImage = imagecreatetruecolor($newWidth, $newHeight);
imagesavealpha($resizedImage, true);
$transparency = imagecolorallocatealpha($resizedImage, 0, 0, 0, 127);
imagefill($resizedImage, 0, 0, $transparency);
imagecopyresampled($resizedImage, $image, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);

if ($fileExtension === 'png') {
imagepng($resizedImage, $uploadFile);
} elseif ($fileExtension === 'jpg' || $fileExtension === 'jpeg') {
imagejpeg($resizedImage, $uploadFile);
} else {
return "";
}

imagedestroy($image);
imagedestroy($resizedImage);
return $fileName;
}
}

return "";
}

if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$enabled = 1;
$name = validate($_POST["paymentname"]);
$iconUrl = validate($_POST['icon-url']);

if ($name === "" || ($iconUrl === "" && empty($_FILES['paymenticon']['name']))) {
$response = [
"success" => false,
"errorMessage" => translate('fill_all_fields', $i18n)
];
echo json_encode($response);
exit();
}


$icon = "";

if($iconUrl !== "") {
$icon = getLogoFromUrl($iconUrl, '../../images/uploads/logos/', $name);
} else {
if (!empty($_FILES['paymenticon']['name'])) {
$icon = resizeAndUploadLogo($_FILES['paymenticon'], '../../images/uploads/logos/', $name);
}
}

$sql = "INSERT INTO payment_methods (name, icon, enabled) VALUES (:name, :icon, :enabled)";

$stmt = $db->prepare($sql);

$stmt->bindParam(':name', $name, SQLITE3_TEXT);
$stmt->bindParam(':icon', $icon, SQLITE3_TEXT);
$stmt->bindParam(':enabled', $enabled, SQLITE3_INTEGER);

if ($stmt->execute()) {
$success['success'] = true;
$success['message'] = translate('payment_method_added_successfuly', $i18n);
$json = json_encode($success);
header('Content-Type: application/json');
echo $json;
exit();
} else {
echo translate('error', $i18n) . ": " . $db->lastErrorMsg();
}
}
}
$db->close();

?>
29 changes: 29 additions & 0 deletions endpoints/payments/delete.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

require_once '../../includes/connect_endpoint.php';
session_start();
if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
if ($_SERVER["REQUEST_METHOD"] === "DELETE") {
$paymentMethodId = $_GET["id"];
$deleteQuery = "DELETE FROM payment_methods WHERE id = :paymentMethodId";
$deleteStmt = $db->prepare($deleteQuery);
$deleteStmt->bindParam(':paymentMethodId', $paymentMethodId, SQLITE3_INTEGER);

if ($deleteStmt->execute()) {
$success['success'] = true;
$success['message'] = translate('payment_method_added_successfuly', $i18n);
$json = json_encode($success);
header('Content-Type: application/json');
echo $json;
} else {
http_response_code(500);
echo json_encode(array("message" => translate('error', $i18n)));
}
} else {
http_response_code(405);
echo json_encode(array("message" => translate('invalid_request_method', $i18n)));
}
}
$db->close();

?>
59 changes: 59 additions & 0 deletions endpoints/payments/get.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

require_once '../../includes/connect_endpoint.php';
session_start();

if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
$paymentsInUseQuery = $db->query('SELECT id FROM payment_methods WHERE id IN (SELECT DISTINCT payment_method_id FROM subscriptions)');
$paymentsInUse = [];
while ($row = $paymentsInUseQuery->fetchArray(SQLITE3_ASSOC)) {
$paymentsInUse[] = $row['id'];
}

$sql = "SELECT * FROM payment_methods";

$result = $db->query($sql);
if ($result) {
$payments = array();
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$payments[] = $row;
}
} else {
http_response_code(500);
echo json_encode(array("message" => translate('error', $i18n)));
exit();
}

foreach ($payments as $payment) {
$paymentIconFolder = $payment['id'] <= 31 ? 'images/uploads/icons/' : 'images/uploads/logos/';
$inUse = in_array($payment['id'], $paymentsInUse);
?>
<div class="payments-payment"
data-enabled="<?= $payment['enabled']; ?>"
data-in-use="<?= $inUse ? 'yes' : 'no' ?>"
data-paymentid="<?= $payment['id'] ?>"
title="<?= $inUse ? translate('cant_delete_payment_method_in_use', $i18n) : ($payment['enabled'] ? translate('disable', $i18n) : translate('enable', $i18n)) ?>"
onClick="togglePayment(<?= $payment['id'] ?>)">
<img src="<?= $paymentIconFolder.$payment['icon'] ?>" alt="Logo" />
<span class="payment-name">
<?= $payment['name'] ?>
</span>
<?php
if ($payment['id'] > 31 && !$inUse) {
?>
<div class="delete-payment-method" title="<?= translate('delete', $i18n) ?>" data-paymentid="<?= $payment['id'] ?>" onclick="deletePaymentMethod(<?= $payment['id'] ?>)">
x
</div>
<?php
}
?>
</div>
<?php
}
} else {
http_response_code(401);
echo json_encode(array("message" => translate('error', $i18n)));
exit();
}

?>
81 changes: 81 additions & 0 deletions endpoints/payments/search.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php
if (isset($_GET['search'])) {
$searchTerm = urlencode($_GET['search'] . " logo");

$url = "https://www.google.com/search?q={$searchTerm}&tbm=isch";
$backupUrl = "https://search.brave.com/search?q={$searchTerm}";

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

// Convert all environment variable keys to lowercase
$envVars = array_change_key_case($_SERVER, CASE_LOWER);

// Check for http_proxy or https_proxy environment variables
$httpProxy = isset($envVars['http_proxy']) ? $envVars['http_proxy'] : null;
$httpsProxy = isset($envVars['https_proxy']) ? $envVars['https_proxy'] : null;

if (!empty($httpProxy)) {
curl_setopt($ch, CURLOPT_PROXY, $httpProxy);
} elseif (!empty($httpsProxy)) {
curl_setopt($ch, CURLOPT_PROXY, $httpsProxy);
}

$response = curl_exec($ch);

if ($response === false) {
// If cURL fails to access google images, use brave image search as a backup
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $backupUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$envVars = array_change_key_case($_SERVER, CASE_LOWER);
$httpProxy = isset($envVars['http_proxy']) ? $envVars['http_proxy'] : null;
$httpsProxy = isset($envVars['https_proxy']) ? $envVars['https_proxy'] : null;
if (!empty($httpProxy)) {
curl_setopt($ch, CURLOPT_PROXY, $httpProxy);
} elseif (!empty($httpsProxy)) {
curl_setopt($ch, CURLOPT_PROXY, $httpsProxy);
}
$response = curl_exec($ch);
if ($response === false) {
echo json_encode(['error' => 'Failed to fetch data from Google.']);
} else {
$imageUrls = extractImageUrlsFromPage($response);
header('Content-Type: application/json');
echo json_encode(['imageUrls' => $imageUrls]);
}
} else {
// Parse the HTML response to extract image URLs
$imageUrls = extractImageUrlsFromPage($response);

// Pass the image URLs to the client
header('Content-Type: application/json');
echo json_encode(['imageUrls' => $imageUrls]);
}

curl_close($ch);
} else {
echo json_encode(['error' => 'Invalid request.']);
}

function extractImageUrlsFromPage($html) {
$imageUrls = [];

$doc = new DOMDocument();
@$doc->loadHTML($html);

$imgTags = $doc->getElementsByTagName('img');
foreach ($imgTags as $imgTag) {
$src = $imgTag->getAttribute('src');
if (!strstr($imgTag->getAttribute('class'), "favicon") && !strstr($imgTag->getAttribute('class'), "logo")) {
if (filter_var($src, FILTER_VALIDATE_URL)) {
$imageUrls[] = $src;
}
}
}

return $imageUrls;
}

?>
3 changes: 2 additions & 1 deletion endpoints/subscriptions/get.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
$print[$id]['currency_code'] = $currencies[$subscription['currency_id']]['code'];
$currencyId = $subscription['currency_id'];
$print[$id]['next_payment'] = date('M d, Y', strtotime($subscription['next_payment']));
$print[$id]['payment_method_icon'] = "images/uploads/icons/" . $payment_methods[$paymentMethodId]['icon'];
$paymentIconFolder = $paymentMethodId <= 31 ? 'images/uploads/icons/' : 'images/uploads/logos/';
$print[$id]['payment_method_icon'] = $paymentIconFolder . $payment_methods[$paymentMethodId]['icon'];
$print[$id]['payment_method_name'] = $payment_methods[$paymentMethodId]['name'];
$print[$id]['payment_method_id'] = $paymentMethodId;
$print[$id]['category_id'] = $subscription['category_id'];
Expand Down
3 changes: 3 additions & 0 deletions includes/i18n/de.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@
"payment_methods" => "Zahlungsmethoden",
"payment_methods_info" => "Zahlungsmethode zum (de-)aktivieren anklicken.",
"cant_delete_payment_method_in_use" => "Genutzte Zahlungsmethoden können nicht deaktiviert werden",
"add_custom_payment" => "Eigene Zahlungsmethode hinzufügen",
"payment_method_name" => "Name der Zahlungsmethode",
"payment_method_added_successfuly" => "Zahlungsmethode erfolgreich hinzugefügt",
"disable" => "Deaktivieren",
"enable" => "Aktivieren",
"test" => "Test",
Expand Down
3 changes: 3 additions & 0 deletions includes/i18n/el.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@
"payment_methods" => "Τρόποι πληρωμής",
"payment_methods_info" => "Κάνε κλικ σε μια μέθοδο πληρωμής για να την απενεργοποιήσεις/ενεργοποιήσεις.",
"cant_delete_payment_method_in_use" => "Δεν είναι εφικτό να απενεργοποιηθεί η χρησιμοποιούμενη μέθοδο πληρωμής",
"add_custom_payment" => "Προσθήκη προσαρμοσμένης μεθόδου πληρωμής",
"payment_method_name" => "Όνομα μεθόδου πληρωμής",
"payment_method_added_successfuly" => "Η μέθοδος πληρωμής προστέθηκε με επιτυχία",
"disable" => "Ανενεργό",
"enable" => "Ενεργό",
"test" => "Δοκιμή",
Expand Down
3 changes: 3 additions & 0 deletions includes/i18n/en.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@
"payment_methods" => "Payment Methods",
"payment_methods_info" => "Click a payment method to disable / enable it.",
"cant_delete_payment_method_in_use" => "Can't disable used payment method",
"add_custom_payment" => "Add Custom Payment Method",
"payment_method_name" => "Payment Method Name",
"payment_method_added_successfuly" => "Payment method added successfully",
"disable" => "Disable",
"enable" => "Enable",
"test" => "Test",
Expand Down
Loading