Files
AudioCore/plugins/store/plugin.php

213 lines
9.2 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
use Core\Http\Router;
use Core\Services\Database;
use Core\Services\Settings;
use Core\Services\Shortcodes;
use Plugins\Store\StoreController;
require_once __DIR__ . '/StoreController.php';
require_once __DIR__ . '/gateways/GatewayInterface.php';
require_once __DIR__ . '/gateways/PaypalGateway.php';
require_once __DIR__ . '/gateways/Gateways.php';
Shortcodes::register('sale-chart', static function (array $attrs = []): string {
$defaultLimit = max(1, min(50, (int)Settings::get('store_sales_chart_limit', '10')));
$defaultScope = strtolower(trim((string)Settings::get('store_sales_chart_default_scope', 'tracks')));
if (!in_array($defaultScope, ['tracks', 'releases'], true)) {
$defaultScope = 'tracks';
}
$defaultWindow = strtolower(trim((string)Settings::get('store_sales_chart_default_window', 'latest')));
if (!in_array($defaultWindow, ['latest', 'weekly', 'all_time'], true)) {
$defaultWindow = 'latest';
}
$limit = max(1, min(50, (int)($attrs['limit'] ?? $defaultLimit)));
$scope = strtolower(trim((string)($attrs['type'] ?? $attrs['scope'] ?? $defaultScope)));
if (!in_array($scope, ['tracks', 'releases'], true)) {
$scope = $defaultScope;
}
$window = strtolower(trim((string)($attrs['mode'] ?? $attrs['window'] ?? $defaultWindow)));
if (!in_array($window, ['latest', 'weekly', 'all_time'], true)) {
$window = $defaultWindow;
}
$db = Database::get();
if (!($db instanceof \PDO)) {
return '';
}
$rows = [];
try {
$stmt = $db->prepare("
SELECT item_label AS title, units, revenue
FROM ac_store_sales_chart_cache
WHERE chart_scope = :scope
AND chart_window = :window
ORDER BY rank_no ASC
LIMIT :limit
");
$stmt->bindValue(':scope', $scope, \PDO::PARAM_STR);
$stmt->bindValue(':window', $window, \PDO::PARAM_STR);
$stmt->bindValue(':limit', $limit, \PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll(\PDO::FETCH_ASSOC) ?: [];
} catch (\Throwable $e) {
$rows = [];
}
if (!$rows) {
try {
$controller = new StoreController();
$controller->rebuildSalesChartCache();
$stmt = $db->prepare("
SELECT item_label AS title, units, revenue
FROM ac_store_sales_chart_cache
WHERE chart_scope = :scope
AND chart_window = :window
ORDER BY rank_no ASC
LIMIT :limit
");
$stmt->bindValue(':scope', $scope, \PDO::PARAM_STR);
$stmt->bindValue(':window', $window, \PDO::PARAM_STR);
$stmt->bindValue(':limit', $limit, \PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll(\PDO::FETCH_ASSOC) ?: [];
} catch (\Throwable $e) {
$rows = [];
}
}
if (!$rows) {
return '<div class="ac-shortcode-empty">No sales yet.</div>';
}
$currency = strtoupper(trim((string)Settings::get('store_currency', 'GBP')));
if (!preg_match('/^[A-Z]{3}$/', $currency)) {
$currency = 'GBP';
}
$list = '';
$position = 1;
foreach ($rows as $row) {
$title = htmlspecialchars((string)($row['title'] ?? ''), ENT_QUOTES, 'UTF-8');
$units = (int)($row['units'] ?? 0);
$revenue = number_format((float)($row['revenue'] ?? 0), 2);
$list .= '<li class="ac-shortcode-sale-item">'
. '<span class="ac-shortcode-sale-rank">#' . $position . '</span>'
. '<span class="ac-shortcode-sale-title">' . $title . '</span>'
. '<span class="ac-shortcode-sale-meta">' . $units . ' sold - ' . htmlspecialchars($currency, ENT_QUOTES, 'UTF-8') . ' ' . $revenue . '</span>'
. '</li>';
$position++;
}
return '<section class="ac-shortcode-sale-chart"><ol class="ac-shortcode-sale-list">' . $list . '</ol></section>';
});
Shortcodes::register('top-sellers', static function (array $attrs = []): string {
$type = trim((string)($attrs['type'] ?? 'tracks'));
$window = trim((string)($attrs['window'] ?? 'latest'));
$limit = max(1, min(50, (int)($attrs['limit'] ?? 10)));
return Shortcodes::render('[sale-chart type="' . $type . '" window="' . $window . '" limit="' . $limit . '"]');
});
Shortcodes::register('login-link', static function (array $attrs = []): string {
$label = trim((string)($attrs['label'] ?? 'Login'));
if ($label === '') {
$label = 'Login';
}
return '<a class="ac-shortcode-link ac-shortcode-link-login" href="/account">' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '</a>';
});
Shortcodes::register('account-link', static function (array $attrs = []): string {
$label = trim((string)($attrs['label'] ?? 'My Account'));
if ($label === '') {
$label = 'My Account';
}
return '<a class="ac-shortcode-link ac-shortcode-link-account" href="/account">' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '</a>';
});
Shortcodes::register('checkout-link', static function (array $attrs = []): string {
$label = trim((string)($attrs['label'] ?? 'Checkout'));
if ($label === '') {
$label = 'Checkout';
}
return '<a class="ac-shortcode-link ac-shortcode-link-checkout" href="/checkout">' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '</a>';
});
Shortcodes::register('cart-link', static function (array $attrs = []): string {
$showCount = ((string)($attrs['show_count'] ?? '1')) !== '0';
$showTotal = ((string)($attrs['show_total'] ?? '1')) !== '0';
$label = trim((string)($attrs['label'] ?? 'Cart'));
if ($label === '') {
$label = 'Cart';
}
$count = 0;
$amount = 0.0;
$currency = strtoupper(trim((string)Settings::get('store_currency', 'GBP')));
if (!preg_match('/^[A-Z]{3}$/', $currency)) {
$currency = 'GBP';
}
if (session_status() !== PHP_SESSION_ACTIVE) {
@session_start();
}
$cart = is_array($_SESSION['ac_cart'] ?? null) ? $_SESSION['ac_cart'] : [];
foreach ($cart as $item) {
if (!is_array($item)) {
continue;
}
$qty = max(1, (int)($item['qty'] ?? 1));
$price = (float)($item['price'] ?? 0);
$count += $qty;
$amount += ($price * $qty);
}
$parts = [htmlspecialchars($label, ENT_QUOTES, 'UTF-8')];
if ($showCount) {
$parts[] = '<span class="ac-shortcode-cart-count">' . $count . '</span>';
}
if ($showTotal) {
$parts[] = '<span class="ac-shortcode-cart-total">' . htmlspecialchars($currency, ENT_QUOTES, 'UTF-8') . ' ' . number_format($amount, 2) . '</span>';
}
return '<a class="ac-shortcode-link ac-shortcode-link-cart" href="/cart">' . implode(' ', $parts) . '</a>';
});
return function (Router $router): void {
$controller = new StoreController();
$router->get('/cart', [$controller, 'cartIndex']);
$router->post('/cart/discount/apply', [$controller, 'cartApplyDiscount']);
$router->post('/cart/discount/remove', [$controller, 'cartClearDiscount']);
$router->get('/checkout', [$controller, 'checkoutIndex']);
$router->get('/account', [$controller, 'accountIndex']);
$router->post('/account/request-login', [$controller, 'accountRequestLogin']);
$router->get('/account/login', [$controller, 'accountLogin']);
$router->get('/account/logout', [$controller, 'accountLogout']);
$router->post('/checkout/place', [$controller, 'checkoutPlace']);
$router->get('/checkout/paypal/return', [$controller, 'checkoutPaypalReturn']);
$router->get('/checkout/paypal/cancel', [$controller, 'checkoutPaypalCancel']);
$router->post('/checkout/sandbox', [$controller, 'checkoutSandbox']);
$router->get('/store/download', [$controller, 'download']);
$router->post('/cart/remove', [$controller, 'cartRemove']);
$router->get('/store/sales-chart/rebuild', [$controller, 'salesChartCron']);
$router->get('/admin/store', [$controller, 'adminIndex']);
$router->post('/admin/store/install', [$controller, 'adminInstall']);
$router->get('/admin/store/settings', [$controller, 'adminSettings']);
$router->post('/admin/store/settings', [$controller, 'adminSaveSettings']);
$router->post('/admin/store/settings/rebuild-sales-chart', [$controller, 'adminRebuildSalesChart']);
$router->post('/admin/store/discounts/create', [$controller, 'adminDiscountCreate']);
$router->post('/admin/store/discounts/delete', [$controller, 'adminDiscountDelete']);
$router->post('/admin/store/settings/test-email', [$controller, 'adminSendTestEmail']);
$router->post('/admin/store/settings/test-paypal', [$controller, 'adminTestPaypal']);
$router->get('/admin/store/customers', [$controller, 'adminCustomers']);
$router->get('/admin/store/orders', [$controller, 'adminOrders']);
$router->post('/admin/store/orders/create', [$controller, 'adminOrderCreate']);
$router->post('/admin/store/orders/status', [$controller, 'adminOrderStatus']);
$router->post('/admin/store/orders/refund', [$controller, 'adminOrderRefund']);
$router->post('/admin/store/orders/delete', [$controller, 'adminOrderDelete']);
$router->get('/admin/store/order', [$controller, 'adminOrderView']);
$router->post('/store/cart/add', [$controller, 'cartAdd']);
};