Skip to content

Commit

Permalink
feat: added custom payment methods (#173)
Browse files Browse the repository at this point in the history
  • Loading branch information
ellite authored Mar 1, 2024
1 parent cb5ce49 commit e739622
Show file tree
Hide file tree
Showing 21 changed files with 691 additions and 15 deletions.
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

0 comments on commit e739622

Please sign in to comment.