From e435d32588c3932a87f4f84d3e610a5dc3d7f90f Mon Sep 17 00:00:00 2001 From: count-null <70529195+count-null@users.noreply.github.com> Date: Thu, 27 Feb 2025 16:38:19 -0500 Subject: [PATCH] save --- .env.example | 3 + composer.json | 3 +- composer.lock | 60 +++- public/index.php | 60 ++-- src/app.php | 4 +- src/colors.php | 114 +++--- src/controllers/account.php | 325 ++++++++---------- src/controllers/admin.php | 156 ++++----- src/controllers/cart.php | 15 +- src/controllers/category.php | 8 +- src/controllers/checkout.php | 15 +- src/controllers/home.php | 7 +- src/controllers/lnurlp.php | 47 ++- src/controllers/lost.php | 7 +- src/controllers/magic_link.php | 15 +- src/controllers/support.php | 33 +- src/controllers/transaction.php | 145 ++++---- src/models/addresses.php | 171 ++++++--- src/models/cart_items.php | 8 +- src/models/carts.php | 6 +- src/models/emails.php | 30 +- src/models/invoices.php | 12 +- src/models/magic_links.php | 44 +-- src/models/order_items.php | 8 +- src/models/orders.php | 16 +- src/models/products.php | 36 +- src/models/quote_items.php | 12 +- src/models/quotes.php | 12 +- src/models/subscriptions.php | 30 +- src/models/transactions.php | 20 +- src/models/user_addresses.php | 61 ---- src/models/users.php | 34 +- src/scripts/check_all_invoices.php | 7 +- src/scripts/check_subscriptions.php | 2 +- src/scripts/init_db.php | 51 +-- src/views/404.twig | 4 +- src/views/account/address/confirm.twig | 1 + src/views/account/address/edit.twig | 1 + src/views/account/billing.twig | 53 ++- src/views/account/index.twig | 137 +++++--- src/views/account/login.twig | 8 +- src/views/account/orders.twig | 6 +- src/views/account/returns.twig | 6 +- src/views/account/shipping.twig | 47 ++- src/views/account/signup.twig | 63 ++-- src/views/account/verify.twig | 21 +- src/views/admin/emails.twig | 50 ++- src/views/admin/index.twig | 26 +- src/views/admin/orders.twig | 2 +- src/views/admin/returns.twig | 2 +- src/views/admin/transactions/add.twig | 58 ++-- src/views/admin/transactions/index.twig | 162 ++++++--- src/views/admin/users.twig | 2 +- src/views/cart.twig | 6 +- src/views/checkout/confirmed.twig | 2 +- src/views/checkout/review_pay.twig | 2 +- src/views/checkout/shipping_billing.twig | 2 +- src/views/footer.twig | 42 ++- src/views/head.twig | 18 +- src/views/header.twig | 313 +++++++++-------- src/views/home.twig | 2 +- src/views/lib/address.twig | 42 +++ src/views/lib/alert.twig | 78 +++-- src/views/lib/button.twig | 77 +++-- src/views/lib/emails/verify.twig | 64 ++-- src/views/lib/empty.twig | 12 +- src/views/lib/{form => forms}/address.twig | 18 +- src/views/lib/{form => forms}/profile.twig | 12 +- src/views/lib/input.twig | 48 --- src/views/lib/inputs/number.twig | 11 + src/views/lib/{ => inputs}/select.twig | 0 src/views/lib/inputs/text.twig | 37 ++ src/views/lib/{ => inputs}/toggle.twig | 0 src/views/lib/modal.twig | 9 +- .../lib/modals/confirm_delete_address.twig | 3 + src/views/lib/modals/credit.twig | 24 ++ src/views/lib/modals/sats.twig | 30 ++ src/views/lib/number_input.twig | 17 - src/views/lib/{page => pages}/category.twig | 0 src/views/lib/{page => pages}/flow.twig | 0 src/views/lib/{page => pages}/index.twig | 0 src/views/lib/policy/credit.twig | 12 - src/views/lib/policy/sats.twig | 13 - src/views/lib/rule.twig | 18 +- src/views/policies.twig | 2 +- src/views/support/ask.twig | 2 +- src/views/support/bitcoin.twig | 2 +- src/views/transaction.twig | 20 +- 88 files changed, 1781 insertions(+), 1383 deletions(-) delete mode 100644 src/models/user_addresses.php create mode 100644 src/views/account/address/confirm.twig create mode 100644 src/views/account/address/edit.twig create mode 100644 src/views/lib/address.twig rename src/views/lib/{form => forms}/address.twig (72%) rename src/views/lib/{form => forms}/profile.twig (70%) delete mode 100644 src/views/lib/input.twig create mode 100644 src/views/lib/inputs/number.twig rename src/views/lib/{ => inputs}/select.twig (100%) create mode 100644 src/views/lib/inputs/text.twig rename src/views/lib/{ => inputs}/toggle.twig (100%) create mode 100644 src/views/lib/modals/confirm_delete_address.twig create mode 100644 src/views/lib/modals/credit.twig create mode 100644 src/views/lib/modals/sats.twig delete mode 100644 src/views/lib/number_input.twig rename src/views/lib/{page => pages}/category.twig (100%) rename src/views/lib/{page => pages}/flow.twig (100%) rename src/views/lib/{page => pages}/index.twig (100%) delete mode 100644 src/views/lib/policy/credit.twig delete mode 100644 src/views/lib/policy/sats.twig diff --git a/.env.example b/.env.example index 99b8d90..877a1a2 100644 --- a/.env.example +++ b/.env.example @@ -11,3 +11,6 @@ SMTP_FROM="noreply@example.com" # !! Choose your LN_SERVICE carefully!! # NOTE: The LN_SERVICE must support LUD-21 Payment Verification LN_ADDRESS="your@node.win" +# Shippo API for address validation and getting live shipping rates +# buying and printing labels +SHIPPO_API_KEY="your-shippo.com-API-key" diff --git a/composer.json b/composer.json index cb34158..1d85678 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ "web-auth/webauthn-lib": "^5.0", "twig/twig": "^3.0", "swentel/nostr-php": "^1.5", - "jorijn/bitcoin-bolt11": "^1.0" + "jorijn/bitcoin-bolt11": "^1.0", + "shippo/shippo-php": "^2.0" } } diff --git a/composer.lock b/composer.lock index 1baf487..9f0b41d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3f3a1571b095d2550e901def5ae562ca", + "content-hash": "d534de83ea2acfea5f56dd6efb27959e", "packages": [ { "name": "bitwasp/bech32", @@ -1709,6 +1709,64 @@ }, "time": "2023-03-08T19:51:13+00:00" }, + { + "name": "shippo/shippo-php", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/goshippo/shippo-php-client.git", + "reference": "7422af5b97c8b36718593dbaf5cfb757771fb907" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/goshippo/shippo-php-client/zipball/7422af5b97c8b36718593dbaf5cfb757771fb907", + "reference": "7422af5b97c8b36718593dbaf5cfb757771fb907", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "9.5.*" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/Shippo/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Shippo & Contributors", + "homepage": "https://goshippo.com/" + } + ], + "description": "A PHP library for connecting with multiple carriers (FedEx, UPS, USPS) using Shippo.", + "homepage": "https://goshippo.com/", + "keywords": [ + "FedEx", + "Uber", + "address", + "dhl", + "shipping", + "shyp", + "tracking", + "ups", + "usps" + ], + "support": { + "issues": "https://github.com/goshippo/shippo-php-client/issues", + "source": "https://github.com/goshippo/shippo-php-client/tree/v2.0.0" + }, + "time": "2022-01-19T22:36:48+00:00" + }, { "name": "simplito/bigint-wrapper-php", "version": "1.0.0", diff --git a/public/index.php b/public/index.php index cf73f45..8134ead 100644 --- a/public/index.php +++ b/public/index.php @@ -1,12 +1,12 @@ date('Y'), - 'session' => $_SESSION, - 'http_host' => $_SERVER['HTTP_HOST'], - 'env' => $_ENV, - 'is_admin' => isset($_SESSION['user_id']) && $_SESSION['user_id'] == 1, + 'session' => $_SESSION, + 'http_host' => $_SERVER['HTTP_HOST'], + 'env' => $_ENV, + 'is_user' => isset($_SESSION['user_id']), + 'is_admin' => isset($_SESSION['user_id']) && $_SESSION['user_id'] == 1, // uses cookie-js to get the client's preferred theme - // used to conditionally deliver image assets + // used to conditionally deliver image assets // or styles based on theme - 'theme' => isset($_COOKIE["theme"]) ? $_COOKIE["theme"] : 'light', + 'theme' => isset($_COOKIE["theme"]) ? $_COOKIE["theme"] : 'light', // set your tailwind colors here for app themeing // the idea is to avoid using colors in your templates - 'colors' => require dirname(__DIR__) . '/src/colors.php', + 'colors' => require dirname(__DIR__) . '/src/colors.php', ]; // Setup a twig -$loader = new \Twig\Loader\FilesystemLoader(paths: dirname(__DIR__) . '/src/views'); +$loader = new \Twig\Loader\FilesystemLoader(paths: dirname(__DIR__) . '/src/views'); $GLOBALS['twig'] = new \Twig\Environment($loader, [ //'cache' => dirname(__DIR__) . '/cache', 'cache' => false, @@ -66,33 +67,35 @@ if (str_starts_with(haystack: $route, needle: '/.well-known/lnurlp/')) { // Combined regex to match multiple dynamic routes in one go if (preg_match('/^\/(transaction|user|order|product)\/([\w-]+)$/', $route, $matches)) { [$full, $type, $id] = $matches; - $controllers = [ - 'transaction' => fn($id) => transaction::view($defaults, $id), - 'user' => fn($id) => users::view($id), - 'order' => fn($id) => orders::view($id), - 'quote' => fn($id) => quotes::view($id), - 'product' => fn($id) => products::view($id), + $controllers = [ + 'transaction' => fn($id) => transaction::view($defaults, $id), + 'user' => fn($id) => users::view($id), + 'order' => fn($id) => orders::view($id), + 'quote' => fn($id) => quotes::view($id), + 'product' => fn($id) => products::view($id), 'subscription' => fn($id) => subscriptions::view($id), - 'cart' => fn($id) => cart::index($id), + 'cart' => fn($id) => cart::index($id), ]; - + if (isset($controllers[$type])) { $controller = $controllers[$type]($id); } } else { $controller = match ($route) { '/' => home::index($defaults), - '/account' => account::index($defaults), - '/account/profile' => account::profile(), '/account/login' => account::login($defaults), - '/account/email' => account::email(), - '/account/logout' => account::logout(), - '/account/returns' => account::returns($defaults), '/account/signup' => account::signup($defaults), - '/account/billing' => account::billing($defaults), - '/account/orders' => account::orders($defaults), - '/account/shipping' => account::shipping($defaults), '/account/verify' => account::verify($defaults), + '/account' => $defaults['is_user'] ? account::index($defaults) : header('Location: /account/login'), + '/account/profile' => $defaults['is_user'] ? account::profile() : header('Location: /account/login'), + '/account/email' => $defaults['is_user'] ? account::email() : header('Location: /account/login'), + '/account/logout' => $defaults['is_user'] ? account::logout() : header('Location: /account/login'), + '/account/returns' => $defaults['is_user'] ? account::returns($defaults) : header('Location: /account/login'), + '/account/billing' => $defaults['is_user'] ? account::billing($defaults) : header('Location: /account/login'), + '/account/orders' => $defaults['is_user'] ? account::orders($defaults) : header('Location: /account/login'), + '/account/shipping' => $defaults['is_user'] ? account::shipping($defaults) : header('Location: /account/login'), + '/account/address/edit' => $defaults['is_user'] ? account::address_edit($defaults) : header('Location: /account/login'), + '/account/address/confirm' => $defaults['is_user'] ? account::address_confirm($defaults) : header('Location: /account/login'), '/admin' => $defaults['is_admin'] ? admin::index($defaults) : lost::index($defaults), '/admin/users' => $defaults['is_admin'] ? admin::users($defaults) : lost::index($defaults), '/admin/orders' => $defaults['is_admin'] ? admin::orders($defaults) : lost::index($defaults), @@ -113,7 +116,8 @@ if (preg_match('/^\/(transaction|user|order|product)\/([\w-]+)$/', $route, $matc '/power-meters' => category::power_meters($defaults), default => lost::index($defaults) }; -}; +} +; // Clear alerts after rendering foreach (['error', 'warning', 'info', 'success'] as $alert) { diff --git a/src/app.php b/src/app.php index 899ff8a..ef8a6c3 100644 --- a/src/app.php +++ b/src/app.php @@ -1,7 +1,7 @@ getMessage()); } } - + public static function sendJson($data, $status = 200) { http_response_code($status); diff --git a/src/colors.php b/src/colors.php index e51a152..bf5d426 100644 --- a/src/colors.php +++ b/src/colors.php @@ -1,58 +1,58 @@ - [ - 'banner' => 'bg-gray-100 dark:bg-gray-600 text-gray-200 dark:text-gray-200', - ], - 'anchor' => [ - 'primary' => 'text-blue-400 dark:text-blue-200' - ], - 'body' => 'bg-white dark:bg-gray-800 text-gray-600 dark:text-gray-300', - 'button' => [ - 'primary' => 'border-blue-400 dark:border-blue-600 dark:hover:border-blue-800 bg-blue-400 dark:bg-blue-600 hover:bg-blue-600 hover:dark:bg-blue-800 text-white dark:text-white', - 'default' => 'hover:bg-gray-50 dark:hover:bg-gray-900' - ], - 'breadcrumb' => [ - 'parent' => 'text-gray-300 dark:text-gray-400 hover:text-gray-400 dark:hover:text-gray-500', - 'seperator' => 'text-gray-200 dark:text-gray-200', - 'child' => 'text-gray-200 dark:text-gray-300' - ], - 'dropdown' => [ - 'list' => 'bg-white dark:bg-blue-900 border-gray-600 dark:border-gray-300', - 'item' => 'hover:bg-gray-200 dark:hover:bg-gray-900' - ], - 'input' => 'text-gray-800 dark:text-gray-300 bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-500 focus:ring-blue-500', - 'error' => [ - 'text' => 'text-red-600', - 'alert' => 'bg-red-100 text-gray-800 border-red-600' - ], - 'warning' => [ - 'text' => 'text-yellow-400', - 'alert' => 'bg-yellow-100 text-gray-800 border-yellow-400' - ], - 'success' => [ - 'text' => 'text-green-600', - 'alert' => 'bg-green-100 text-gray-800 border-green-600' - ], - 'info' => [ - 'text' => 'text-blue-400', - 'alert' => 'bg-blue-200 text-gray-800 border-blue-400' - ], - 'modal' => [ - 'content' => 'bg-white dark:bg-blue-900 border-gray-600 dark:border-gray-300', - 'shadow' => 'bg-black/70' - ], - 'nav' => [ - 'bar' => 'bg-blue-400 dark:bg-blue-600 text-gray-200 dark:text-gray-200', - 'item' => 'hover:bg-blue-600 dark:hover:bg-blue-800 hover:text-gray-200 dark:hover:text-gray-300 text-white border-blue-400 dark:border-blue-600', - 'hovercontent' => 'bg-white dark:bg-slate-700 text-gray-800 dark:text-gray-300' - ], - 'rule' => 'border-gray-400 dark:border-gray-400', - 'text' => [ - 'muted' => 'text-gray-400 dark:text-gray-300' - ], - 'toggle' => "bg-gray-300 peer-checked:bg-green-400 after:bg-white", - 'footer' => [ - "primary" => "bg-gray-200 dark:bg-slate-600 text-gray-500 dark:text-gray-300", - "policy" => "bg-slate-400 dark:bg-slate-800 text-gray-200 dark:text-gray-400" - ], - ]; \ No newline at end of file + 'header' => [ + 'banner' => 'bg-gray-100 dark:bg-gray-600 text-gray-200 dark:text-gray-200', + ], + 'anchor' => [ + 'primary' => 'text-blue-400 dark:text-blue-200', + ], + 'body' => 'bg-white dark:bg-gray-800 text-gray-600 dark:text-gray-300', + 'button' => [ + 'primary' => 'border-blue-400 dark:border-blue-600 dark:hover:border-blue-800 bg-blue-400 dark:bg-blue-600 hover:bg-blue-600 hover:dark:bg-blue-800 text-white dark:text-white', + 'default' => 'hover:bg-gray-50 dark:hover:bg-gray-900', + ], + 'breadcrumb' => [ + 'parent' => 'text-gray-300 dark:text-gray-400 hover:text-gray-400 dark:hover:text-gray-500', + 'seperator' => 'text-gray-200 dark:text-gray-200', + 'child' => 'text-gray-200 dark:text-gray-300', + ], + 'dropdown' => [ + 'list' => 'bg-white dark:bg-blue-900 border-gray-600 dark:border-gray-300', + 'item' => 'hover:bg-gray-200 dark:hover:bg-gray-900', + ], + 'input' => 'text-gray-800 dark:text-gray-300 bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-500 focus:ring-blue-500', + 'error' => [ + 'text' => 'text-red-600', + 'alert' => 'bg-red-100 text-gray-800 border-red-600', + ], + 'warning' => [ + 'text' => 'text-yellow-400', + 'alert' => 'bg-yellow-100 text-gray-800 border-yellow-400', + ], + 'success' => [ + 'text' => 'text-green-600', + 'alert' => 'bg-green-100 text-gray-800 border-green-600', + ], + 'info' => [ + 'text' => 'text-blue-400', + 'alert' => 'bg-blue-200 text-gray-800 border-blue-400', + ], + 'modal' => [ + 'content' => 'bg-white dark:bg-blue-900 border-gray-600 dark:border-gray-300', + 'shadow' => 'bg-black/70', + ], + 'nav' => [ + 'bar' => 'bg-blue-400 dark:bg-blue-600 text-gray-200 dark:text-gray-200', + 'item' => 'hover:bg-blue-600 dark:hover:bg-blue-800 hover:text-gray-200 dark:hover:text-gray-300 text-white border-blue-400 dark:border-blue-600', + 'hovercontent' => 'bg-white dark:bg-slate-700 text-gray-800 dark:text-gray-300', + ], + 'rule' => 'border-gray-400 dark:border-gray-400', + 'text' => [ + 'muted' => 'text-gray-400 dark:text-gray-300', + ], + 'toggle' => "bg-gray-300 peer-checked:bg-green-400 after:bg-white", + 'footer' => [ + "primary" => "bg-gray-200 dark:bg-slate-600 text-gray-500 dark:text-gray-300", + "policy" => "bg-slate-400 dark:bg-slate-800 text-gray-200 dark:text-gray-400", + ], +]; diff --git a/src/controllers/account.php b/src/controllers/account.php index 443229b..331891e 100644 --- a/src/controllers/account.php +++ b/src/controllers/account.php @@ -2,64 +2,40 @@ namespace app\controllers; use app\models\addresses; -use app\models\users; use app\models\emails; -use app\models\user_addresses; use app\models\magic_links; +use app\models\users; class account { public static function index($defaults): void { - if (!isset($_SESSION['user_id'])) { - header('Location: /account/login'); - } - $user_id = $_SESSION['user_id']; - $user = users::getById($user_id); - $default_shipping = null; - $default_billing = null; - $ship_addrs = []; - $bill_addrs = []; - $addresses = user_addresses::getShippingByUserId($user['id']); - foreach ($addresses as $address) { - if ($address['id'] == $user['shipping_address_id']){ - $default_shipping = $address; - } else { - $ship_addrs[] = $address; - } - } - $bill_addresses = user_addresses::getBillingByUserId($_SESSION['user_id']); - foreach ($bill_addresses as $addr) { - if ($addr['id'] == $user['billing_address_id']){ - $default_billing = $addr; - } else { - $bill_addrs[] = $addr; - } - } - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + $user = users::getById($_SESSION['user_id']); + $addresses = addresses::getByUserId($_SESSION['user_id']); + + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'account/index.twig', - 'page_title' => 'Manage Account - ' . $_ENV['APP_NAME'], - 'user' => $user, - 'shipping' => $ship_addrs, - 'billing' => $bill_addrs, - 'default_shipping' => $default_shipping, - 'default_billing' => $default_billing, - 'breadcrumbs' => [ + 'page_title' => 'Manage Account - ' . $_ENV['APP_NAME'], + 'user' => $user, + 'addresses' => $addresses, + 'breadcrumbs' => [ [ - 'url' => null, + 'url' => null, 'title' => 'My Account', - ] - ] + ], + ], ])); } + public static function billing($defaults) { if ($_SERVER['REQUEST_METHOD'] == 'POST') { - if (!$_SESSION['user_id']) { - http_response_code(403); + $bill = addresses::validatePost("billing_"); + if (isset($bill['error'])) { + header('Location: /account/billing'); } - $bill = addresses::validatePost("billing"); $bill_id = addresses::add( + $_SESSION['user_id'], $bill['name'], $bill['company'], $bill['addressLine1'], @@ -68,51 +44,34 @@ class account $bill['state'], $bill['zip'], $bill['phone'], - 1, - 0 - ); - user_addresses::add( - $_SESSION['user_id'], - $bill_id + $bill['hash'] ); $_SESSION['success'] = "Billing address saved!"; header('Location: /account/billing'); } - $user_id = $_SESSION['user_id']; - $user = users::getById($user_id); - $default_billing = null; - $bill_addrs = []; - $bill_addresses = user_addresses::getBillingByUserId($_SESSION['user_id']); - foreach ($bill_addresses as $addr) { - if ($addr['id'] == $user['billing_address_id']){ - $default_billing = $addr; - } else { - $bill_addrs[] = $addr; - } - } - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + $user = users::getById($_SESSION['user_id']); + $addresses = addresses::getByUserId($_SESSION['user_id']); + + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'account/billing.twig', - 'page_title' => 'Billing Information - ' . $_ENV['APP_NAME'], - 'billing' => $bill_addrs, - 'default_billing' => $default_billing, - 'breadcrumbs' => [ + 'page_title' => 'Billing Information - ' . $_ENV['APP_NAME'], + 'user' => $user, + 'addresses' => $addresses, + 'breadcrumbs' => [ [ - 'url' => '/account', - 'title' => 'My Account' + 'url' => '/account', + 'title' => 'My Account', ], [ - 'url' => null, - 'title' => 'Billing' - ] - ] + 'url' => null, + 'title' => 'Billing', + ], + ], ])); } public static function profile() { if ($_SERVER['REQUEST_METHOD'] == 'POST') { - if (!$_SESSION['user_id']) { - http_response_code(403); - } users::updateProfileById($_SESSION['user_id'], $_POST); header('Location: /account'); } @@ -120,18 +79,15 @@ class account public static function email() { - $user_id = $_SESSION['user_id'] ?? null; - if (empty($user_id)){ - header('Location: /account/login'); - } - if ($_SERVER['REQUEST_METHOD'] == 'POST') { + if ($_SERVER['REQUEST_METHOD'] == 'POST') { $email = $_POST['email'] ?? null; if (empty($email)) { $_SESSION['error'] = "Enter your email to get a login link"; header('Location: /account'); exit; } else { - $token = magic_links::add($email, $user_id); + $user_id = $_SESSION['user_id']; + $token = magic_links::add($email, $user_id); users::updateReplaceEmailTokenById($user_id, $token); header('Location: /account'); exit; @@ -148,8 +104,8 @@ class account $user = $link['user_id'] ? users::getById($link['user_id']) : users::getByEmail($link['email']); if ($user) { $_SESSION['user_email'] = $link['email']; - $_SESSION['user_id'] = $user['id']; - if (!$user['verified']) { + $_SESSION['user_id'] = $user['id']; + if (! $user['verified']) { users::verify($link['email']); } header('Location: /account'); @@ -166,19 +122,55 @@ class account } } - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'account/verify.twig', - 'page_title' => $_ENV['APP_NAME'], - 'breadcrumbs' => [ + 'page_title' => $_ENV['APP_NAME'], + 'breadcrumbs' => [ [ - 'url' => '/account', - 'title' => 'My Account' + 'url' => '/account', + 'title' => 'My Account', ], [ - 'url' => null, - 'title' => 'Verify' - ] - ] + 'url' => null, + 'title' => 'Verify', + ], + ], + ])); + } + + public static function address_edit($defaults) + { + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ + 'child_template' => 'account/address/edit.twig', + 'page_title' => 'Edit Address - ' . $_ENV['APP_NAME'], + 'breadcrumbs' => [ + [ + 'url' => '/account', + 'title' => 'My Account', + ], + [ + 'url' => null, + 'title' => 'Edit Address', + ], + ], + ])); + } + + public static function address_confirm($defaults) + { + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ + 'child_template' => 'account/address/confirm.twig', + 'page_title' => 'Confirm Address - ' . $_ENV['APP_NAME'], + 'breadcrumbs' => [ + [ + 'url' => '/account', + 'title' => 'My Account', + ], + [ + 'url' => null, + 'title' => 'Confirm Address', + ], + ], ])); } @@ -199,15 +191,15 @@ class account if (isset($_SESSION['user_id'])) { header('Location: /account'); } - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'account/login.twig', - 'page_title' => 'Sign In or Create an Account!', - 'breadcrumbs' => [ + 'page_title' => 'Sign In or Create an Account!', + 'breadcrumbs' => [ [ - 'url' => null, - 'title' => 'My Account' + 'url' => null, + 'title' => 'My Account', ], - ] + ], ])); } @@ -220,50 +212,48 @@ class account public static function orders($defaults) { - if (!isset($_SESSION['user_id'])) { - header('Location: /account/login'); - } - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'account/orders.twig', - 'page_title' => 'View ' . $_ENV['APP_NAME'] . ' Orders', - 'breadcrumbs' => [ + 'page_title' => 'View ' . $_ENV['APP_NAME'] . ' Orders', + 'breadcrumbs' => [ [ - 'url' => '/account', - 'title' => 'My Account' + 'url' => '/account', + 'title' => 'My Account', ], [ - 'url' => null, - 'title' => 'Orders' - ] - ] + 'url' => null, + 'title' => 'Orders', + ], + ], ])); } public static function returns($defaults) { - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'account/returns.twig', - 'page_title' => 'View ' . $_ENV['APP_NAME'] . ' Returns', - 'breadcrumbs' => [ + 'page_title' => 'View ' . $_ENV['APP_NAME'] . ' Returns', + 'breadcrumbs' => [ [ - 'url' => '/account', - 'title' => 'My Account' + 'url' => '/account', + 'title' => 'My Account', ], [ - 'url' => null, - 'title' => 'Returns' - ] - ] + 'url' => null, + 'title' => 'Returns', + ], + ], ])); } public static function shipping($defaults) { if ($_SERVER['REQUEST_METHOD'] == 'POST') { - if (!$_SESSION['user_id']) { - http_response_code(403); + $ship = addresses::validatePost("shipping_"); + if (isset($ship['error'])) { + header('Location: /account/shipping'); } - $ship = addresses::validatePost("shipping"); $ship_id = addresses::add( + $_SESSION['user_id'], $ship['name'], $ship['company'], $ship['addressLine1'], @@ -272,43 +262,28 @@ class account $ship['state'], $ship['zip'], $ship['phone'], - 0, - 1 - ); - user_addresses::add( - $_SESSION['user_id'], - $ship_id + $ship['hash'] ); $_SESSION['success'] = "Shipping address saved!"; header('Location: /account/shipping'); } - $user_id = $_SESSION['user_id']; - $user = users::getById($user_id); - $addresses = user_addresses::getShippingByUserId($user['id']); - $default_shipping = null; - $ship_addrs = []; - foreach ($addresses as $addr) { - if ($addr['id'] == $user['shipping_address_id']){ - $default_shipping = $addr; - } else { - $ship_addrs[] = $addr; - } - } - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + $user = users::getById($_SESSION['user_id']); + $addresses = addresses::getByUserId($_SESSION['user_id']); + + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'account/shipping.twig', - 'page_title' => $_ENV['APP_NAME'] . ' Shipping', - 'shipping' => $ship_addrs, - 'default_shipping' => $default_shipping, - 'breadcrumbs' => [ + 'page_title' => $_ENV['APP_NAME'] . ' Shipping', + 'addresses' => $addresses, + 'breadcrumbs' => [ [ - 'url' => '/account', - 'title' => 'My Account' + 'url' => '/account', + 'title' => 'My Account', ], [ - 'url' => null, - 'title' => 'Shipping' - ] - ] + 'url' => null, + 'title' => 'Shipping', + ], + ], ])); } @@ -321,22 +296,22 @@ class account } $existingUser = users::getByEmail($email); if ($existingUser) { - $_SESSION['error'] = 'Email already exists. Please choose a different email or log in.'; + $_SESSION['error'] = 'Email already exists. Please choose a different email or log in.'; $_SESSION['last_post'] = $_POST; header('Location: /account/signup'); exit; } $useShipping = $_POST['use_shipping'] ?? false; - $ship = addresses::validatePost("shipping"); - if (!isset($ship['name'])){ - $_SESSION['error'] = "Shipping address verification failed. Check your entry for errors."; + $ship = addresses::validatePost("shipping_"); + if (isset($ship['error'])) { + $_SESSION['error'] = "Shipping address verification failed. " . $_SESSION['error']; $_SESSION['last_post'] = $_POST; header('Location: /account/signup'); } - if (!$useShipping) { - $bill = addresses::validatePost("billing"); - if (!isset($bill['name'])){ - $_SESSION['error'] = "Billing address verification failed. Check your entry for errors."; + if (! $useShipping) { + $bill = addresses::validatePost("billing_"); + if (isset($bill['error'])) { + $_SESSION['error'] = "Billing address verification failed. " . $_SESSION['error']; $_SESSION['last_post'] = $_POST; header('Location: /account/signup'); } @@ -346,6 +321,7 @@ class account header('Location: /account/signup'); } $ship_id = addresses::add( + null, $ship['name'], $ship['company'], $ship['addressLine1'], @@ -354,12 +330,12 @@ class account $ship['state'], $ship['zip'], $ship['phone'], - $useShipping == 'on', - 1 + $ship['hash'] ); $bill_id = $ship_id; - if (!$useShipping) { + if (! $useShipping) { $bill_id = addresses::add( + null, $bill['name'], $bill['company'], $bill['addressLine1'], @@ -368,14 +344,13 @@ class account $bill['state'], $bill['zip'], $bill['phone'], - 1, - 0 + $bill['hash'] ); } $opt_in_promotional = $_POST['opt_in_promotional'] ?? false; - $verified = isset($_SESSION['user_email']); - $dark_theme = $defaults['theme'] == 'dark'; - $user_id = users::add( + $verified = isset($_SESSION['user_email']); + $dark_theme = $defaults['theme'] == 'dark'; + $user_id = users::add( $email, $ship_id, $bill_id, @@ -384,21 +359,11 @@ class account $dark_theme ); emails::updateUserIdByEmail($email, $user_id); - user_addresses::add( - user_id: $user_id, - address_id: $ship_id - ); - if (!$useShipping) { - user_addresses::add( - user_id: $user_id, - address_id: $bill_id - ); - } $_SESSION['user_id'] = $user_id; - if (!$verified) { + if (! $verified) { header("Location: /magic-link?email=$email&signup=1"); exit; - } + } header('Location: /account'); exit; } // endif request === POST @@ -408,9 +373,9 @@ class account exit; } - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'account/signup.twig', - 'page_title' => 'Create an Account - ' . $_ENV['APP_NAME'] + 'page_title' => 'Create an Account - ' . $_ENV['APP_NAME'], ])); } -} \ No newline at end of file +} diff --git a/src/controllers/admin.php b/src/controllers/admin.php index 290fbd6..3bd2d54 100644 --- a/src/controllers/admin.php +++ b/src/controllers/admin.php @@ -1,100 +1,100 @@ render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'admin/index.twig', - 'page_title' => 'Dashboard', - 'breadcrumbs' => [ + 'page_title' => 'Dashboard', + 'breadcrumbs' => [ [ - 'url' => '/admin', - 'title' => 'Admin' - ] + 'url' => '/admin', + 'title' => 'Admin', + ], ], ])); } public static function users($defaults) { - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'admin/users.twig', - 'page_title' => 'Users', - 'breadcrumbs' => [ + 'page_title' => 'Users', + 'breadcrumbs' => [ [ - 'url' => '/admin', - 'title' => 'Admin' + 'url' => '/admin', + 'title' => 'Admin', ], [ - 'url' => '/admin/users', - 'title' => 'Users' - ] + 'url' => '/admin/users', + 'title' => 'Users', + ], ], ])); } public static function orders($defaults) { - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'admin/orders.twig', - 'page_title' => 'Orders', - 'breadcrumbs' => [ + 'page_title' => 'Orders', + 'breadcrumbs' => [ [ - 'url' => '/admin', - 'title' => 'Admin' + 'url' => '/admin', + 'title' => 'Admin', ], [ - 'url' => '/admin/orders', - 'title' => 'Orders' - ] + 'url' => '/admin/orders', + 'title' => 'Orders', + ], ], ])); } public static function returns($defaults) { - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'admin/returns.twig', - 'page_title' => 'Returns', - 'breadcrumbs' => [ + 'page_title' => 'Returns', + 'breadcrumbs' => [ [ - 'url' => '/admin', - 'title' => 'Admin' + 'url' => '/admin', + 'title' => 'Admin', ], [ - 'url' => '/admin/returns', - 'title' => 'Returns' - ] + 'url' => '/admin/returns', + 'title' => 'Returns', + ], ], ])); } public static function transactions($defaults) { - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ - 'child_template' => 'admin/transactions/index.twig', - 'page_title' => 'Transactions', - 'recent_sats' => transactions::getRecent(10, 'sats'), - 'recent_cents' => transactions::getRecent(10, 'cents'), - 'whales_sats' => transactions::getWhales(10, 'sats'), - 'whales_cents' => transactions::getWhales(10, 'cents'), - 'sats_liability' => transactions::getLiabilities('sats'), + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ + 'child_template' => 'admin/transactions/index.twig', + 'page_title' => 'Transactions', + 'recent_sats' => transactions::getRecent(10, 'sats'), + 'recent_cents' => transactions::getRecent(10, 'cents'), + 'whales_sats' => transactions::getWhales(10, 'sats'), + 'whales_cents' => transactions::getWhales(10, 'cents'), + 'sats_liability' => transactions::getLiabilities('sats'), 'cents_liability' => transactions::getLiabilities('cents'), - 'breadcrumbs' => [ + 'breadcrumbs' => [ [ - 'url' => '/admin', - 'title' => 'Admin' + 'url' => '/admin', + 'title' => 'Admin', ], [ - 'url' => '/admin/transactions', - 'title' => 'Transactions' - ] + 'url' => '/admin/transactions', + 'title' => 'Transactions', + ], ], ])); } @@ -102,55 +102,55 @@ class admin public static function transactions_add($defaults) { if ($_SERVER['REQUEST_METHOD'] == 'POST') { - $amount = $_POST['amount'] ?? null; - $currency = $_POST['currency']; + $amount = $_POST['amount'] ?? null; + $currency = $_POST['currency']; $user_identifier = $_POST['user_identifier'] ?? null; - if (!$amount || !$user_identifier) { - $_SESSION['error'] = !$amount ? "Please enter an amount for the transaction." : "Please enter a user email or id for the transaction."; + if (! $amount || ! $user_identifier) { + $_SESSION['error'] = ! $amount ? "Please enter an amount for the transaction." : "Please enter a user email or id for the transaction."; $_SESSION['last_post'] = $_POST; } else { if (strpos($user_identifier, '@') !== false && strpos($user_identifier, '.') !== false) { $user = users::getByEmail($user_identifier); } elseif (is_numeric($user_identifier)) { - $user = users::getById((int)$user_identifier); + $user = users::getById((int) $user_identifier); } else { - $_SESSION['error'] = "Invalid user identifier. Please enter a valid email or user ID."; + $_SESSION['error'] = "Invalid user identifier. Please enter a valid email or user ID."; $_SESSION['last_post'] = $_POST; } - if (!$user) { - $_SESSION['error'] = "User not found. Please enter a valid email or user ID."; + if (! $user) { + $_SESSION['error'] = "User not found. Please enter a valid email or user ID."; $_SESSION['last_post'] = $_POST; } else { - if($_POST['confirm']){ + if ($_POST['confirm']) { // create the transaction $txid = transactions::add($user['id'], $amount > 0 ? 'CREDIT' : 'REVOKE', $currency == 'cents' ? $amount : 0, $currency == 'sats' ? $amount : 0); header('Location: /transaction/' . $txid); exit; } else { - $_SESSION['last_post'] = $_POST; + $_SESSION['last_post'] = $_POST; $_SESSION['last_post']['confirm'] = true; - $_SESSION['last_post']['email'] = $user['email']; - $_SESSION['last_post']['id'] = $user['id']; + $_SESSION['last_post']['email'] = $user['email']; + $_SESSION['last_post']['id'] = $user['id']; } } } } - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'admin/transactions/add.twig', - 'page_title' => 'Add a Transaction', - 'breadcrumbs' => [ + 'page_title' => 'Add a Transaction', + 'breadcrumbs' => [ [ - 'url' => '/admin', - 'title' => 'Admin' + 'url' => '/admin', + 'title' => 'Admin', ], [ - 'url' => '/admin/transactions', - 'title' => 'Transactions' + 'url' => '/admin/transactions', + 'title' => 'Transactions', ], [ - 'url' => '/admin/transactions/add', - 'title' => 'Add' - ] + 'url' => '/admin/transactions/add', + 'title' => 'Add', + ], ], ])); } @@ -158,19 +158,19 @@ class admin public static function emails($defaults) { $recent_emails = emails::getRecent(20); - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'admin/emails.twig', - 'page_title' => 'Emails', - 'recent_emails' => $recent_emails, - 'breadcrumbs' => [ + 'page_title' => 'Emails', + 'recent_emails' => $recent_emails, + 'breadcrumbs' => [ [ - 'url' => '/admin', - 'title' => 'Admin' + 'url' => '/admin', + 'title' => 'Admin', ], [ - 'url' => '/admin/emails', - 'title' => 'Emails' - ] + 'url' => '/admin/emails', + 'title' => 'Emails', + ], ], ])); } @@ -179,6 +179,6 @@ class admin { $_SESSION['last_post'] = null; header('Location: /admin/transactions/add'); - exit; + exit; } -} \ No newline at end of file +} diff --git a/src/controllers/cart.php b/src/controllers/cart.php index ba43a70..0bd017b 100644 --- a/src/controllers/cart.php +++ b/src/controllers/cart.php @@ -1,18 +1,19 @@ render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'cart.twig', - 'page_title' => $_ENV['APP_NAME'] . ' Cart', - 'breadcrumbs' => [ + 'page_title' => $_ENV['APP_NAME'] . ' Cart', + 'breadcrumbs' => [ [ - 'url' => null, - 'title' => 'Cart' - ] + 'url' => null, + 'title' => 'Cart', + ], ], ])); } -} \ No newline at end of file +} diff --git a/src/controllers/category.php b/src/controllers/category.php index 31094dd..137978a 100644 --- a/src/controllers/category.php +++ b/src/controllers/category.php @@ -1,14 +1,14 @@ render('lib/page/index.twig', context: array_merge($defaults, [ - 'child_template' => 'lib/page/category.twig', - 'page_title' => 'Power Meters - ' . $_ENV['APP_NAME'], + echo $GLOBALS['twig']->render('lib/pages/index.twig', context: array_merge($defaults, [ + 'child_template' => 'lib/pages/category.twig', + 'page_title' => 'Power Meters - ' . $_ENV['APP_NAME'], 'product_category' => 'power_meters', ])); } } - diff --git a/src/controllers/checkout.php b/src/controllers/checkout.php index 7f64b94..ac09114 100644 --- a/src/controllers/checkout.php +++ b/src/controllers/checkout.php @@ -1,26 +1,27 @@ render('lib/page/flow.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/flow.twig', array_merge($defaults, [ 'child_template' => 'checkout/shipping_billing.twig', - 'page_title' => 'Checkout with ' . $_ENV['APP_NAME'], + 'page_title' => 'Checkout with ' . $_ENV['APP_NAME'], ])); } public static function review_pay($defaults) { - echo $GLOBALS['twig']->render('lib/page/flow.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/flow.twig', array_merge($defaults, [ 'child_template' => 'checkout/review_pay.twig', - 'page_title' => 'Review & Payment | ' . $_ENV['APP_NAME'] + 'page_title' => 'Review & Payment | ' . $_ENV['APP_NAME'], ])); } public static function confirmed($defaults) { - echo $GLOBALS['twig']->render('lib/page/flow.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/flow.twig', array_merge($defaults, [ 'child_template' => 'checkout/confirmed.twig', - 'page_title' => 'Order Recieved! - Thank You' + 'page_title' => 'Order Recieved! - Thank You', ])); } -} \ No newline at end of file +} diff --git a/src/controllers/home.php b/src/controllers/home.php index b36f828..01719bb 100644 --- a/src/controllers/home.php +++ b/src/controllers/home.php @@ -1,12 +1,13 @@ render(name: 'lib/page/index.twig', context: array_merge($defaults, [ + echo $GLOBALS['twig']->render(name: 'lib/pages/index.twig', context: array_merge($defaults, [ 'child_template' => 'home.twig', - 'page_title' => $_ENV['APP_NAME'] . ": Specialty Hardware" + 'page_title' => $_ENV['APP_NAME'] . ": Specialty Hardware", ])); } -} \ No newline at end of file +} diff --git a/src/controllers/lnurlp.php b/src/controllers/lnurlp.php index d3e0b65..362684e 100644 --- a/src/controllers/lnurlp.php +++ b/src/controllers/lnurlp.php @@ -1,11 +1,10 @@ 'ERROR', - 'reason' => "@$username is not registered" + 'reason' => "@$username is not registered", ]); } // for when the client makes it's first call (querying the lightning address) list($proxy_user, $proxy_host) = explode("@", $_ENV['LN_ADDRESS']); - $metadata = "[[\"text/plain\",\"Funding @$username on $host\"],[\"text/identifier\",\"$username@$host\"]]"; + $metadata = "[[\"text/plain\",\"Funding @$username on $host\"],[\"text/identifier\",\"$username@$host\"]]"; if ($paymentRequest == false && $verify == false) { $res = json_decode(file_get_contents("https://$proxy_host/.well-known/lnurlp/$proxy_user"), true); returnJson( [ - 'callback' => "https://$host/lnurlp?pay=1&username=$username", - 'maxSendable' => $res['maxSendable'], - 'minSendable' => $res['minSendable'], - 'metadata' => $metadata, + 'callback' => "https://$host/lnurlp?pay=1&username=$username", + 'maxSendable' => $res['maxSendable'], + 'minSendable' => $res['minSendable'], + 'metadata' => $metadata, 'commentAllowed' => $res['commentAllowed'], - 'payerData' => $res['payerData'], - 'tag' => "payRequest", + 'payerData' => $res['payerData'], + 'tag' => "payRequest", ] ); } // for when the client makes it's second call (callback) to get an invoice if ($paymentRequest == "1") { - $res = json_decode(file_get_contents("https://$proxy_host/.well-known/lnurlp/$proxy_user"), true); + $res = json_decode(file_get_contents("https://$proxy_host/.well-known/lnurlp/$proxy_user"), true); $proxy_url = $res['callback']; if (isset($_GET["amount"])) { $proxy_url .= "&amount=" . urlencode($_GET["amount"]); } $res = json_decode(file_get_contents($proxy_url), true); - if ($res['status'] === 'OK'){ + if ($res['status'] === 'OK') { // subscribe to this invoice by adding to our db - $invoice = $res['pr']; - $decoder = new PaymentRequestDecoder(); - $denormalizer = new PaymentRequestDenormalizer(); + $invoice = $res['pr']; + $decoder = new PaymentRequestDecoder(); + $denormalizer = new PaymentRequestDenormalizer(); $paymentRequest = $denormalizer->denormalize($decoder->decode($invoice)); invoices::add( $user['id'], @@ -86,13 +85,13 @@ class lnurlp $paymentRequest->getMilliSatoshis(), $paymentRequest->getExpiryDateTime()['date'] ); - $boom = explode("=", $res['verify']); + $boom = explode("=", $res['verify']); $proxy_verify = end($boom); returnJson([ 'status' => 'OK', - 'pr' => $invoice, + 'pr' => $invoice, 'routes' => $res['routes'], - 'verify' => "https://$host/lnurlp?verify=$proxy_verify" + 'verify' => "https://$host/lnurlp?verify=$proxy_verify", ]); } else { returnJson($res); @@ -101,9 +100,9 @@ class lnurlp // for when they want to verify the payment succeeded if ($verify) { - $res = json_decode(file_get_contents("https://$proxy_host/.well-known/lnurlp/$proxy_user"), true); + $res = json_decode(file_get_contents("https://$proxy_host/.well-known/lnurlp/$proxy_user"), true); $proxy_url = $res['verify']; - $prox_res = json_decode(file_get_contents($proxy_url), true); + $prox_res = json_decode(file_get_contents($proxy_url), true); returnJson($prox_res); } @@ -113,4 +112,4 @@ class lnurlp 'reason' => 'unhandled error (how did you get here?)', ]); } -} \ No newline at end of file +} diff --git a/src/controllers/lost.php b/src/controllers/lost.php index 39ecf0b..6aa12be 100644 --- a/src/controllers/lost.php +++ b/src/controllers/lost.php @@ -1,12 +1,13 @@ render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => '404.twig', - 'page_title' => 'Not Found - ' . $_ENV['APP_NAME'], + 'page_title' => 'Not Found - ' . $_ENV['APP_NAME'], ])); } -} \ No newline at end of file +} diff --git a/src/controllers/magic_link.php b/src/controllers/magic_link.php index 8b38d84..56a2272 100644 --- a/src/controllers/magic_link.php +++ b/src/controllers/magic_link.php @@ -1,21 +1,22 @@ render('lib/page/index.twig', array_merge($defaults, [ + $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'support/ask.twig', - 'page_title' => $_ENV['APP_NAME'] . ': Frequently Asked Questions', - 'breadcrumbs' => [ + 'page_title' => $_ENV['APP_NAME'] . ': Frequently Asked Questions', + 'breadcrumbs' => [ [ - 'url' => null, - 'title' => 'Support' - ] - ] + 'url' => null, + 'title' => 'Support', + ], + ], ])); } public static function bitcoin($defaults) { - $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'support/bitcoin.twig', - 'page_title' => $_ENV['APP_NAME'] . ' Bitcoin Accepted', - 'breadcrumbs' => [ + 'page_title' => $_ENV['APP_NAME'] . ' Bitcoin Accepted', + 'breadcrumbs' => [ [ - 'url' => '/support/ask', - 'title' => 'Support' + 'url' => '/support/ask', + 'title' => 'Support', ], [ - 'url' => null, - 'title' => 'Bitcoin' - ] + 'url' => null, + 'title' => 'Bitcoin', + ], ], ])); } -} \ No newline at end of file +} diff --git a/src/controllers/transaction.php b/src/controllers/transaction.php index 213e5ca..e220153 100644 --- a/src/controllers/transaction.php +++ b/src/controllers/transaction.php @@ -1,108 +1,107 @@ render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'transaction.twig', - 'page_title' => 'Transaction Reciept #' . $txid, - 'tx' => $tx, - 'user' => $user, - 'breadcrumbs' => [ + 'page_title' => 'Transaction Reciept #' . $txid, + 'tx' => $tx, + 'user' => $user, + 'breadcrumbs' => [ [ - 'url' => "/transaction/" . $txid, - 'title' => 'Transaction Reciept' - ] + 'url' => "/transaction/" . $txid, + 'title' => 'Transaction Reciept', + ], ], ])); } public static function users($defaults) { - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'admin/users.twig', - 'page_title' => $_ENV['APP_NAME'] . ' Users', - 'breadcrumbs' => [ + 'page_title' => $_ENV['APP_NAME'] . ' Users', + 'breadcrumbs' => [ [ - 'url' => '/admin', - 'title' => 'Admin' + 'url' => '/admin', + 'title' => 'Admin', ], [ - 'url' => '/admin/users', - 'title' => 'Users' - ] + 'url' => '/admin/users', + 'title' => 'Users', + ], ], ])); } public static function orders($defaults) { - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'admin/orders.twig', - 'page_title' => $_ENV['APP_NAME'] . ' Orders', - 'breadcrumbs' => [ + 'page_title' => $_ENV['APP_NAME'] . ' Orders', + 'breadcrumbs' => [ [ - 'url' => '/admin', - 'title' => 'Admin' + 'url' => '/admin', + 'title' => 'Admin', ], [ - 'url' => '/admin/orders', - 'title' => 'Orders' - ] + 'url' => '/admin/orders', + 'title' => 'Orders', + ], ], ])); } public static function returns($defaults) { - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'admin/returns.twig', - 'page_title' => $_ENV['APP_NAME'] . ' Returns', - 'breadcrumbs' => [ + 'page_title' => $_ENV['APP_NAME'] . ' Returns', + 'breadcrumbs' => [ [ - 'url' => '/admin', - 'title' => 'Admin' + 'url' => '/admin', + 'title' => 'Admin', ], [ - 'url' => '/admin/returns', - 'title' => 'Returns' - ] + 'url' => '/admin/returns', + 'title' => 'Returns', + ], ], ])); } public static function transactions($defaults) { - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ - 'child_template' => 'admin/transactions/index.twig', - 'page_title' => $_ENV['APP_NAME'] . ' Transactions', - 'recent_sats' => transactions::getRecent(10, 'sats'), - 'recent_cents' => transactions::getRecent(10, 'cents'), - 'whales_sats' => transactions::getWhales(10, 'sats'), - 'whales_cents' => transactions::getWhales(10, 'cents'), - 'sats_liability' => transactions::getLiabilities('sats'), + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ + 'child_template' => 'admin/transactions/index.twig', + 'page_title' => $_ENV['APP_NAME'] . ' Transactions', + 'recent_sats' => transactions::getRecent(10, 'sats'), + 'recent_cents' => transactions::getRecent(10, 'cents'), + 'whales_sats' => transactions::getWhales(10, 'sats'), + 'whales_cents' => transactions::getWhales(10, 'cents'), + 'sats_liability' => transactions::getLiabilities('sats'), 'cents_liability' => transactions::getLiabilities('cents'), - 'breadcrumbs' => [ + 'breadcrumbs' => [ [ - 'url' => '/admin', - 'title' => 'Admin' + 'url' => '/admin', + 'title' => 'Admin', ], [ - 'url' => '/admin/transactions', - 'title' => 'Transactions' - ] + 'url' => '/admin/transactions', + 'title' => 'Transactions', + ], ], ])); } @@ -110,55 +109,55 @@ class transaction public static function transactions_add($defaults) { if ($_SERVER['REQUEST_METHOD'] == 'POST') { - $amount = $_POST['amount'] ?? null; - $currency = $_POST['currency']; + $amount = $_POST['amount'] ?? null; + $currency = $_POST['currency']; $user_identifier = $_POST['user_identifier'] ?? null; - if (!$amount || !$user_identifier) { - $_SESSION['error'] = !$amount ? "Please enter an amount for the transaction." : "Please enter a user email or id for the transaction."; + if (! $amount || ! $user_identifier) { + $_SESSION['error'] = ! $amount ? "Please enter an amount for the transaction." : "Please enter a user email or id for the transaction."; $_SESSION['last_post'] = $_POST; } else { if (strpos($user_identifier, '@') !== false && strpos($user_identifier, '.') !== false) { $user = users::getByEmail($user_identifier); } elseif (is_numeric($user_identifier)) { - $user = users::getById((int)$user_identifier); + $user = users::getById((int) $user_identifier); } else { - $_SESSION['error'] = "Invalid user identifier. Please enter a valid email or user ID."; + $_SESSION['error'] = "Invalid user identifier. Please enter a valid email or user ID."; $_SESSION['last_post'] = $_POST; } - if (!$user) { - $_SESSION['error'] = "User not found. Please enter a valid email or user ID."; + if (! $user) { + $_SESSION['error'] = "User not found. Please enter a valid email or user ID."; $_SESSION['last_post'] = $_POST; } else { - if($_POST['confirm']){ + if ($_POST['confirm']) { // create the transaction $txid = transactions::add($user['id'], 'CREDIT', $currency == 'cents' ? $amount : 0, $currency == 'sats' ? $amount : 0); header('Location: /transaction/' . $txid); exit; } else { - $_SESSION['last_post'] = $_POST; + $_SESSION['last_post'] = $_POST; $_SESSION['last_post']['confirm'] = true; - $_SESSION['last_post']['email'] = $user['email']; - $_SESSION['last_post']['id'] = $user['id']; + $_SESSION['last_post']['email'] = $user['email']; + $_SESSION['last_post']['id'] = $user['id']; } } } } - echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [ + echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [ 'child_template' => 'admin/transactions/add.twig', - 'page_title' => 'Add a Transaction', - 'breadcrumbs' => [ + 'page_title' => 'Add a Transaction', + 'breadcrumbs' => [ [ - 'url' => '/admin', - 'title' => 'Admin' + 'url' => '/admin', + 'title' => 'Admin', ], [ - 'url' => '/admin/transactions', - 'title' => 'Transactions' + 'url' => '/admin/transactions', + 'title' => 'Transactions', ], [ - 'url' => '/admin/transactions/add', - 'title' => 'Add' - ] + 'url' => '/admin/transactions/add', + 'title' => 'Add', + ], ], ])); } @@ -167,6 +166,6 @@ class transaction { $_SESSION['last_post'] = null; header('Location: /admin/transactions/add'); - exit; + exit; } -} \ No newline at end of file +} diff --git a/src/models/addresses.php b/src/models/addresses.php index ecbfb81..3f524a5 100644 --- a/src/models/addresses.php +++ b/src/models/addresses.php @@ -2,12 +2,14 @@ namespace app\models; use app\app; + class addresses { public static function init() { app::$db->exec("CREATE TABLE IF NOT EXISTS addresses ( id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER, name TEXT NOT NULL, company TEXT, addressLine1 TEXT NOT NULL, @@ -16,80 +18,154 @@ class addresses state TEXT NOT NULL, zip TEXT NOT NULL, phone TEXT, - billing BOOLEAN NOT NULL, - shipping BOOLEAN NOT NULL + hash TEXT NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) )"); } - public static function validatePost($type) + public static function validatePost($type = "") { - $name = $_POST["{$type}_name"]; - $company = $_POST["{$type}_company"] ?? null; - $addressLine2 = $_POST["{$type}_addressLine2"] ?? null; - $addressLine1 = $_POST["{$type}_addressLine1"]; - $city = $_POST["{$type}_city"]; - $state = $_POST["{$type}_state"]; - $zip = $_POST["{$type}_zip"]; - $phone = $_POST["{$type}_phone"]; + $name = $_POST["{$type}name"]; + $company = $_POST["{$type}company"] ?? null; + $addressLine2 = $_POST["{$type}addressLine2"] ?? null; + $addressLine1 = $_POST["{$type}addressLine1"]; + $city = $_POST["{$type}city"]; + $state = $_POST["{$type}state"]; + $zip = $_POST["{$type}zip"]; + $phone = $_POST["{$type}phone"]; + $email = $_POST["{$type}email"] ?? null; // Assuming email is part of the form + // check all required fields are set if (empty($name) || empty($addressLine1) || empty($city) || empty($state) || empty($zip) || empty($phone)) { $_SESSION['error'] = "Missing required {$type} information."; + return ["error" => "Missing required {$type} information."]; } - $url = "https://nominatim.openstreetmap.org/search?" . http_build_query([ - "q" => implode(" ", array_filter([$addressLine1, $addressLine2, $city, $state, $zip])), - "format" => "json", - "addressdetails" => 1, - "limit" => 1 - ]); + + // Set up the cURL request $ch = curl_init(); + + // Set the Shippo API endpoint for address validation + $url = sprintf( + 'https://api.goshippo.com/v2/addresses/validate?address_line_1=%s&city_locality=%s&state_province=%s&postal_code=%s&country_code=US&organization=%s', + urlencode($addressLine1), + urlencode($city), + urlencode($state), + urlencode($zip), + urlencode($company) + ); + + // Set the cURL options curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_USERAGENT, "AddressValidator/1.0"); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Authorization: ShippoToken ' . $_ENV['SHIPPO_API_KEY'], + ]); + + // Execute the cURL request $response = curl_exec($ch); curl_close($ch); - $data = json_decode($response, true); - if (empty($data)) { - return ["error" => "Address not found"]; + $validated_address = json_decode($response, true); + // print_r($response); + // Check the status of the validation + if (isset($validated_address['analysis']['validation_result']['value']) && $validated_address['analysis']['validation_result']['value'] === 'valid') { + $result = [ + 'name' => $name, + 'company' => $company, + "addressLine1" => $addressLine1, + "addressLine2" => $addressLine2, + "city" => $city, + "state" => $state, + "zip" => $zip, + 'phone' => $phone, + ]; + } elseif (isset($validated_address['recommended_address']['confidence_result']['score']) && $validated_address['recommended_address']['confidence_result']['score'] === 'high') { + $recommended = $validated_address['recommended_address']; + $result = [ + 'name' => $name, + 'company' => $company, + "addressLine1" => $recommended['address_line_1'], + "addressLine2" => $addressLine2, + "city" => $recommended['city_locality'], + "state" => $recommended['state_province'], + "zip" => $recommended['postal_code'], + 'phone' => $phone, + ]; + } else { + $error_message = "Address is invalid."; + if (isset($validated_address['analysis']['validation_result']['reasons'])) { + foreach ($validated_address['analysis']['validation_result']['reasons'] as $reason) { + if ($reason['type'] === 'error') { + $error_message = $reason['description']; + break; + } + } + } + $_SESSION['error'] = $error_message; + return ["error" => $error_message]; } - $addressDetails = $data[0]['address']; - return [ - 'name' => $name, - 'company' => $company, - "addressLine1" => ($addressDetails['house_number'] ?? '') . ' ' . ($addressDetails['building'] ?? '') . ' ' . ($addressDetails['road'] ?? ''), - "addressLine2" => $addressLine2, - "city" => $addressDetails['city'] ?? $addressDetails['town'] ?? $addressDetails['village'] ?? '', - "state" => $addressDetails['state_code'] ?? ($addressDetails['state'] ?? ''), - "zip" => $addressDetails['postcode'] ?? '', - 'phone' => $phone - ]; + $result['hash'] = hash("sha256", json_encode($result)); + $existing = self::getByHash($result['hash']); + if ($existing) { + $_SESSION['error'] = "The address already exists."; + return ["error" => $_SESSION['error']]; + } + return $result; } - public static function add($name, $company, $addressLine1, $addressLine2, $city, $state, $zip, $phone, $billing, $shipping) + public static function updateUserIdById($bill_id, $user_id) + { + $query = "UPDATE addresses SET user_id = :user_id WHERE id = :bill_id"; + $stmt = app::$db->prepare($query); + $stmt->bindParam(':user_id', $user_id); + $stmt->bindParam(':bill_id', $bill_id); + $stmt->execute(); + } + + public static function getByHash($hash) + { + $query = "SELECT * FROM addresses WHERE hash = :hash"; + $stmt = app::$db->prepare($query); + $stmt->bindParam(':hash', $hash); + $stmt->execute(); + return $stmt->fetch(\PDO::FETCH_ASSOC); + } + + public static function getByUserId($user_id) + { + $query = "SELECT * FROM addresses WHERE user_id = :user_id"; + $stmt = app::$db->prepare($query); + $stmt->bindParam(':user_id', $user_id); + $stmt->execute(); + return $stmt->fetchAll(\PDO::FETCH_ASSOC); + } + + public static function add($user_id, $name, $company, $addressLine1, $addressLine2, $city, $state, $zip, $phone, $hash) { $query = "INSERT INTO addresses ( - name, - company, + user_id, + name, + company, addressLine1, - addressLine2, - city, - state, + addressLine2, + city, + state, zip, phone, - billing, - shipping + hash ) VALUES ( - :name, - :company, + :user_id, + :name, + :company, :addressLine1, :addressLine2, - :city, - :state, + :city, + :state, :zip, :phone, - :billing, - :shipping + :hash )"; $stmt = app::$db->prepare($query); + $stmt->bindParam(':user_id', $user_id); $stmt->bindParam(':name', $name); $stmt->bindParam(':company', $company); $stmt->bindParam(':addressLine1', $addressLine1); @@ -98,8 +174,7 @@ class addresses $stmt->bindParam(':state', $state); $stmt->bindParam(':zip', $zip); $stmt->bindParam(':phone', $phone); - $stmt->bindParam(':billing', $billing); - $stmt->bindParam(':shipping', $shipping); + $stmt->bindParam(':hash', $hash); $stmt->execute(); return app::$db->lastInsertId(); } diff --git a/src/models/cart_items.php b/src/models/cart_items.php index d12b485..edbaef1 100644 --- a/src/models/cart_items.php +++ b/src/models/cart_items.php @@ -20,12 +20,12 @@ class cart_items public static function addItem(int $cartId, int $productId, int $quantity) { - $stmt = app::$db->prepare("INSERT INTO cart_items (cart_id, product_id, quantity) + $stmt = app::$db->prepare("INSERT INTO cart_items (cart_id, product_id, quantity) VALUES (:cart_id, :product_id, :quantity)"); $stmt->execute([ - 'cart_id' => $cartId, + 'cart_id' => $cartId, 'product_id' => $productId, - 'quantity' => $quantity + 'quantity' => $quantity, ]); } @@ -34,7 +34,7 @@ class cart_items $stmt = app::$db->prepare("UPDATE cart_items SET quantity = :quantity WHERE cart_item_id = :cart_item_id"); $stmt->execute([ 'cart_item_id' => $cartItemId, - 'quantity' => $quantity + 'quantity' => $quantity, ]); } diff --git a/src/models/carts.php b/src/models/carts.php index 73b4813..7bf304d 100644 --- a/src/models/carts.php +++ b/src/models/carts.php @@ -8,8 +8,8 @@ class carts public static function init() { app::$db->exec("CREATE TABLE IF NOT EXISTS carts ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id INTEGER NOT NULL, + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL, short_id TEXT UNIQUE NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) @@ -29,7 +29,7 @@ class carts private static function createCart(int $userId, string $column): string { $characters = '123456789ABCDEFGHJKLMNPQRSTUVWXYZ'; - $shortId = ''; + $shortId = ''; for ($i = 0; $i < 6; $i++) { $shortId .= $characters[random_int(0, strlen($characters) - 1)]; diff --git a/src/models/emails.php b/src/models/emails.php index b1afc7e..b39f3ed 100644 --- a/src/models/emails.php +++ b/src/models/emails.php @@ -2,18 +2,16 @@ namespace app\models; use app\app; - use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\SMTP; -use PHPMailer\PHPMailer\Exception; class emails { public static function init() { app::$db->exec("CREATE TABLE IF NOT EXISTS emails ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id INTEGER, + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER, from_email TEXT NOT NULL, from_name TEXT NOT NULL, to_email TEXT NOT NULL, @@ -28,7 +26,7 @@ class emails public static function getRecentByUserId($user_id, $n) { $query = "SELECT * FROM emails WHERE user_id = :user_id ORDER BY created_at DESC LIMIT :n"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':user_id', $user_id, \PDO::PARAM_INT); $stmt->bindParam(':n', $n, \PDO::PARAM_INT); $stmt->execute(); @@ -38,7 +36,7 @@ class emails public static function getRecent($n) { $query = "SELECT * FROM emails ORDER BY created_at DESC LIMIT :n"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':n', $n, \PDO::PARAM_INT); $stmt->execute(); return $stmt->fetchAll(\PDO::FETCH_ASSOC); @@ -47,7 +45,7 @@ class emails public static function updateUserIdByEmail($email, $user_id) { $query = "UPDATE emails SET user_id = :user_id WHERE to_email = :email AND user_id IS NULL"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':user_id', $user_id, \PDO::PARAM_INT); $stmt->bindParam(':email', $email); $stmt->execute(); @@ -55,11 +53,11 @@ class emails public static function send($subject, $from_email, $from_name, $to_email, $message, $template, $template_vars) { - $user = users::getByEmail($to_email); + $user = users::getByEmail($to_email); $user_id = $user ? $user['id'] : null; - + $HTML_message = $GLOBALS['twig']->render("lib/emails/$template", $template_vars); - $query = "INSERT INTO emails (user_id, from_email, from_name, to_email, subject, message, html_message) + $query = "INSERT INTO emails (user_id, from_email, from_name, to_email, subject, message, html_message) VALUES (:user_id, :from_email, :from_name, :to_email, :subject, :message, :html_message)"; $stmt = app::$db->prepare($query); $stmt->bindParam(':user_id', $user_id); @@ -74,17 +72,17 @@ class emails // Mail Server settings $mail->SMTPDebug = SMTP::DEBUG_SERVER; $mail->isSMTP(); - $mail->Host = $_ENV['SMTP_HOST']; - $mail->SMTPAuth = true; - $mail->Username = $_ENV['SMTP_USER']; - $mail->Password = $_ENV['SMTP_PASS']; + $mail->Host = $_ENV['SMTP_HOST']; + $mail->SMTPAuth = true; + $mail->Username = $_ENV['SMTP_USER']; + $mail->Password = $_ENV['SMTP_PASS']; $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; - $mail->Port = 587; + $mail->Port = 587; $mail->isHTML(true); $mail->setFrom($from_email, $from_name); $mail->addAddress($to_email); $mail->Subject = $subject; - $mail->Body = $HTML_message; + $mail->Body = $HTML_message; $mail->AltBody = $message; // Buffer the output ob_start(); diff --git a/src/models/invoices.php b/src/models/invoices.php index 4aafbd3..3d98880 100644 --- a/src/models/invoices.php +++ b/src/models/invoices.php @@ -1,7 +1,8 @@ prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':user_id', $user_id, \PDO::PARAM_INT); $stmt->bindParam(':order_id', $order_id, \PDO::PARAM_INT); $stmt->bindParam(':invoice', $invoice); @@ -33,7 +34,7 @@ class invoices $stmt->bindParam(':amount_msats', $amount_milisats); $stmt->bindParam(':expiry_date', $expiry_date); $stmt->execute(); - + return app::$db->lastInsertId(); } @@ -84,13 +85,12 @@ class invoices } } else { // Check if more than 24 hours past expiry - $expiryDate = new \DateTime($invoice['expiry_date']); + $expiryDate = new \DateTime($invoice['expiry_date']); $currentDate = new \DateTime(); - $interval = $expiryDate->diff($currentDate); + $interval = $expiryDate->diff($currentDate); if ($interval->days >= 1) { self::delete($invoice_id); } } } } - diff --git a/src/models/magic_links.php b/src/models/magic_links.php index 66b4a27..885169f 100644 --- a/src/models/magic_links.php +++ b/src/models/magic_links.php @@ -23,12 +23,12 @@ class magic_links public static function add($email, $user_id) { $token = bin2hex(random_bytes(32)); - $seed = hexdec(substr($token, 0, 8)); // Use the first 8 characters of the token as a seed + $seed = hexdec(substr($token, 0, 8)); // Use the first 8 characters of the token as a seed mt_srand($seed); - $code = str_pad(strval(mt_rand(0, 999999)), 6, "0", STR_PAD_LEFT); + $code = str_pad(strval(mt_rand(0, 999999)), 6, "0", STR_PAD_LEFT); $expires_at = date('Y-m-d H:i:s', time() + 60 * 15); - $ipv4 = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; // Get client's IPv4 address - $query = "INSERT INTO magic_links ( + $ipv4 = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; // Get client's IPv4 address + $query = "INSERT INTO magic_links ( email, user_id, token, @@ -38,7 +38,7 @@ class magic_links ) VALUES ( :email, :user_id, - :token, + :token, :code, :expires_at, :ipv4 @@ -51,17 +51,17 @@ class magic_links $stmt->bindParam(':expires_at', $expires_at); $stmt->bindParam(':ipv4', $ipv4); $stmt->execute(); - $link = $_ENV['APP_HOST'] . "/magic-link?token=" . urlencode($token); - $subject = "Your Magic Sign-In Link"; - $message = "Enter this code into the sign-in form\n$code\n or copy-paste this link into your browser to sign in:\n$link"; + $link = $_ENV['APP_HOST'] . "/magic-link?token=" . urlencode($token); + $subject = "Your Magic Sign-In Link"; + $message = "Enter this code into the sign-in form\n$code\n or copy-paste this link into your browser to sign in:\n$link"; $template_vars = ['code' => $code, 'link' => $link]; emails::send( - $subject, - $_ENV['SMTP_FROM'], - $_ENV['APP_NAME'], - $email, - $message, - 'verify.twig', + $subject, + $_ENV['SMTP_FROM'], + $_ENV['APP_NAME'], + $email, + $message, + 'verify.twig', $template_vars ); $_SESSION['success'] = 'Link sent to your email!'; @@ -70,9 +70,9 @@ class magic_links public static function validateToken($token) { - $query = "SELECT * FROM magic_links - WHERE token = :token - AND used = FALSE + $query = "SELECT * FROM magic_links + WHERE token = :token + AND used = FALSE AND expires_at > datetime('now')"; $stmt = app::$db->prepare($query); $stmt->bindParam(':token', $token); @@ -80,7 +80,7 @@ class magic_links $link = $stmt->fetch(\PDO::FETCH_ASSOC); $updateQuery = "UPDATE magic_links SET used = TRUE WHERE token = :token"; - $updateStmt = app::$db->prepare($updateQuery); + $updateStmt = app::$db->prepare($updateQuery); $updateStmt->bindParam(':token', $token); $updateStmt->execute(); @@ -89,9 +89,9 @@ class magic_links public static function validateCode($code) { - $query = "SELECT * FROM magic_links - WHERE code = :code - AND used = FALSE + $query = "SELECT * FROM magic_links + WHERE code = :code + AND used = FALSE AND expires_at > datetime('now')"; $stmt = app::$db->prepare($query); $stmt->bindParam(':code', $code); @@ -99,7 +99,7 @@ class magic_links $link = $stmt->fetch(\PDO::FETCH_ASSOC); $updateQuery = "UPDATE magic_links SET used = TRUE WHERE code = :code"; - $updateStmt = app::$db->prepare($updateQuery); + $updateStmt = app::$db->prepare($updateQuery); $updateStmt->bindParam(':code', $code); $updateStmt->execute(); diff --git a/src/models/order_items.php b/src/models/order_items.php index 1d03b3e..3b71a78 100644 --- a/src/models/order_items.php +++ b/src/models/order_items.php @@ -24,12 +24,12 @@ class order_items throw new \InvalidArgumentException('Quantity must be greater than zero.'); } - $stmt = app::$db->prepare("INSERT INTO order_items (order_id, product_id, quantity) + $stmt = app::$db->prepare("INSERT INTO order_items (order_id, product_id, quantity) VALUES (:order_id, :product_id, :quantity)"); $stmt->execute([ - 'order_id' => $orderId, + 'order_id' => $orderId, 'product_id' => $productId, - 'quantity' => $quantity + 'quantity' => $quantity, ]); } @@ -42,7 +42,7 @@ class order_items $stmt = app::$db->prepare("UPDATE order_items SET quantity = :quantity WHERE order_item_id = :order_item_id"); $stmt->execute([ 'order_item_id' => $orderItemId, - 'quantity' => $quantity + 'quantity' => $quantity, ]); } diff --git a/src/models/orders.php b/src/models/orders.php index 0df971d..931ba7e 100644 --- a/src/models/orders.php +++ b/src/models/orders.php @@ -6,8 +6,8 @@ use app\app; class orders { const STATUSES = [ - 'SHIPPED', 'PENDING', 'HOLD', 'PARTIAL', - 'BACKORDER', 'FAILED', 'CANCELED', 'PROCESSING' + 'SHIPPED', 'PENDING', 'HOLD', 'PARTIAL', + 'BACKORDER', 'FAILED', 'CANCELED', 'PROCESSING', ]; public static function init() @@ -27,13 +27,13 @@ class orders { self::validateStatus($status); - $stmt = app::$db->prepare("INSERT INTO orders (user_id, value_sats, value_cents, status) + $stmt = app::$db->prepare("INSERT INTO orders (user_id, value_sats, value_cents, status) VALUES (:user_id, :value_sats, :value_cents, :status)"); $stmt->execute([ - 'user_id' => $userId, - 'value_sats' => $valueSats, + 'user_id' => $userId, + 'value_sats' => $valueSats, 'value_cents' => $valueCents, - 'status' => $status + 'status' => $status, ]); return app::$db->lastInsertId(); @@ -46,7 +46,7 @@ class orders $stmt = app::$db->prepare("UPDATE orders SET status = :status WHERE order_id = :order_id"); $stmt->execute([ 'order_id' => $orderId, - 'status' => $status + 'status' => $status, ]); } @@ -66,7 +66,7 @@ class orders private static function validateStatus(string $status) { - if (!in_array($status, self::STATUSES, true)) { + if (! in_array($status, self::STATUSES, true)) { throw new \InvalidArgumentException("Invalid order status: $status"); } } diff --git a/src/models/products.php b/src/models/products.php index 985c19b..6bcdb23 100644 --- a/src/models/products.php +++ b/src/models/products.php @@ -45,26 +45,26 @@ class products )"); $stmt->execute([ - ':title' => $title, - ':desc' => $desc, - ':stock_qty' => $stock_qty, - ':specs_json' => $specs_json, - ':sats_price' => $sats_price, - ':cents_price' => $cents_price, - ':digital' => (int) $digital, + ':title' => $title, + ':desc' => $desc, + ':stock_qty' => $stock_qty, + ':specs_json' => $specs_json, + ':sats_price' => $sats_price, + ':cents_price' => $cents_price, + ':digital' => (int) $digital, ':subscription' => (int) $subscription, - ':image_url_0' => $images[0] ?? null, - ':image_url_1' => $images[1] ?? null, - ':image_url_2' => $images[2] ?? null, - ':image_url_3' => $images[3] ?? null, - ':image_url_4' => $images[4] ?? null, - ':image_url_5' => $images[5] ?? null, - ':image_url_6' => $images[6] ?? null, - ':image_url_7' => $images[7] ?? null, - ':image_url_8' => $images[8] ?? null, - ':image_url_9' => $images[9] ?? null, + ':image_url_0' => $images[0] ?? null, + ':image_url_1' => $images[1] ?? null, + ':image_url_2' => $images[2] ?? null, + ':image_url_3' => $images[3] ?? null, + ':image_url_4' => $images[4] ?? null, + ':image_url_5' => $images[5] ?? null, + ':image_url_6' => $images[6] ?? null, + ':image_url_7' => $images[7] ?? null, + ':image_url_8' => $images[8] ?? null, + ':image_url_9' => $images[9] ?? null, ':image_url_10' => $images[10] ?? null, - ':image_url_11' => $images[11] ?? null + ':image_url_11' => $images[11] ?? null, ]); } } diff --git a/src/models/quote_items.php b/src/models/quote_items.php index 9df3cf3..af78494 100644 --- a/src/models/quote_items.php +++ b/src/models/quote_items.php @@ -28,13 +28,13 @@ class quote_items throw new \InvalidArgumentException('Price must be non-negative.'); } - $stmt = app::$db->prepare("INSERT INTO quote_items (quote_id, product_id, quantity, price) + $stmt = app::$db->prepare("INSERT INTO quote_items (quote_id, product_id, quantity, price) VALUES (:quote_id, :product_id, :quantity, :price)"); $stmt->execute([ - 'quote_id' => $quoteId, + 'quote_id' => $quoteId, 'product_id' => $productId, - 'quantity' => $quantity, - 'price' => $price + 'quantity' => $quantity, + 'price' => $price, ]); } @@ -50,8 +50,8 @@ class quote_items $stmt = app::$db->prepare("UPDATE quote_items SET quantity = :quantity, price = :price WHERE quote_item_id = :quote_item_id"); $stmt->execute([ 'quote_item_id' => $quoteItemId, - 'quantity' => $quantity, - 'price' => $price + 'quantity' => $quantity, + 'price' => $price, ]); } diff --git a/src/models/quotes.php b/src/models/quotes.php index 3d8e286..8ee2dac 100644 --- a/src/models/quotes.php +++ b/src/models/quotes.php @@ -6,8 +6,8 @@ use app\app; class quotes { private const STATUSES = [ - 'DRAFT', 'PUBLISHED', 'SENT', 'PURCHASED', - 'EXPIRED', 'CANCELED' + 'DRAFT', 'PUBLISHED', 'SENT', 'PURCHASED', + 'EXPIRED', 'CANCELED', ]; public static function init() @@ -25,11 +25,11 @@ class quotes { self::validateStatus($status); - $stmt = app::$db->prepare("INSERT INTO quotes (user_id, status) + $stmt = app::$db->prepare("INSERT INTO quotes (user_id, status) VALUES (:user_id, :status)"); $stmt->execute([ 'user_id' => $userId, - 'status' => $status + 'status' => $status, ]); return app::$db->lastInsertId(); @@ -42,7 +42,7 @@ class quotes $stmt = app::$db->prepare("UPDATE quotes SET status = :status WHERE quote_id = :quote_id"); $stmt->execute([ 'quote_id' => $quoteId, - 'status' => $status + 'status' => $status, ]); } @@ -62,7 +62,7 @@ class quotes private static function validateStatus(string $status) { - if (!in_array($status, self::STATUSES, true)) { + if (! in_array($status, self::STATUSES, true)) { throw new \InvalidArgumentException("Invalid quote status: $status"); } } diff --git a/src/models/subscriptions.php b/src/models/subscriptions.php index 8189de7..236779f 100644 --- a/src/models/subscriptions.php +++ b/src/models/subscriptions.php @@ -6,11 +6,11 @@ use app\app; class subscriptions { const STATES = [ - 'TRIAL', 'START', 'RENEWAL' + 'TRIAL', 'START', 'RENEWAL', ]; const STATUS = [ - 'COMPLETED', 'CANCELED' + 'COMPLETED', 'CANCELED', ]; public static function init() @@ -29,21 +29,21 @@ class subscriptions );"); } - public static function createSubscription( $userId, $productId, $state, $startDate, $renewAt, $invoiceDate) + public static function createSubscription($userId, $productId, $state, $startDate, $renewAt, $invoiceDate) { self::validateState($state); self::validateStatus($status); - $stmt = app::$db->prepare("INSERT INTO subscriptions (user_id, product_id, state, status, start_date, renews_at, invoice_date) + $stmt = app::$db->prepare("INSERT INTO subscriptions (user_id, product_id, state, status, start_date, renews_at, invoice_date) VALUES (:user_id, :product_id, :state, :status, :start_date, :renews_at, :invoice_date)"); $stmt->execute([ - 'user_id' => $userId, - 'product_id' => $productId, - 'state' => $state, - 'status' => $status, - 'start_date' => $startDate, - 'renews_at' => $renewAt, - 'invoice_date' => $invoiceDate + 'user_id' => $userId, + 'product_id' => $productId, + 'state' => $state, + 'status' => $status, + 'start_date' => $startDate, + 'renews_at' => $renewAt, + 'invoice_date' => $invoiceDate, ]); return app::$db->lastInsertId(); @@ -56,7 +56,7 @@ class subscriptions $stmt = app::$db->prepare("UPDATE subscriptions SET state = :state WHERE subscription_id = :subscription_id"); $stmt->execute([ 'subscription_id' => $subscriptionId, - 'state' => $state + 'state' => $state, ]); } @@ -67,7 +67,7 @@ class subscriptions $stmt = app::$db->prepare("UPDATE subscriptions SET status = :status WHERE subscription_id = :subscription_id"); $stmt->execute([ 'subscription_id' => $subscriptionId, - 'status' => $status + 'status' => $status, ]); } @@ -87,14 +87,14 @@ class subscriptions private static function validateState(string $state) { - if (!in_array($state, self::STATES, true)) { + if (! in_array($state, self::STATES, true)) { throw new \InvalidArgumentException("Invalid subscription state: $state"); } } private static function validateStatus(string $status) { - if (!in_array($status, self::STATUS, true)) { + if (! in_array($status, self::STATUS, true)) { throw new \InvalidArgumentException("Invalid subscription status: $status"); } } diff --git a/src/models/transactions.php b/src/models/transactions.php index 6e54e53..f32f25e 100644 --- a/src/models/transactions.php +++ b/src/models/transactions.php @@ -20,11 +20,11 @@ class transactions FOREIGN KEY (user_id) REFERENCES users(id) )"); } - + public static function getById($id) { $query = "SELECT * FROM transactions WHERE id = :id"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':id', $id, \PDO::PARAM_INT); $stmt->execute(); return $stmt->fetch(); @@ -32,7 +32,7 @@ class transactions public static function add($user_id, $transaction_type, $cents, $sats) { - if (!in_array($transaction_type, self::TYPES)) { + if (! in_array($transaction_type, self::TYPES)) { throw new \Exception("Invalid transaction type."); } if ($cents < 0 || $sats < 0) { @@ -43,7 +43,7 @@ class transactions throw new \Exception("Insufficient funds."); } $query = "INSERT INTO transactions (user_id, type, cents, sats) VALUES (:user_id, :transaction_type, :cents, :sats)"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':user_id', $user_id); $stmt->bindParam(':transaction_type', $transaction_type); $stmt->bindParam(':cents', $cents); @@ -55,7 +55,7 @@ class transactions public static function getUserBalance($user_id) { $query = "SELECT COALESCE(SUM(cents), 0) AS total_cents, COALESCE(SUM(sats), 0) AS total_sats FROM transactions WHERE user_id = :user_id"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':user_id', $user_id); $stmt->execute(); return $stmt->fetch(); @@ -64,7 +64,7 @@ class transactions public static function getRecent($n, $currency) { $query = "SELECT * FROM transactions WHERE $currency > 0 ORDER BY date DESC LIMIT :n"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':n', $n, \PDO::PARAM_INT); $stmt->execute(); return $stmt->fetchAll(); @@ -72,11 +72,11 @@ class transactions public static function getWhales($n, $currency) { - if (!in_array($currency, ['cents', 'sats'])) { + if (! in_array($currency, ['cents', 'sats'])) { throw new \Exception("Invalid currency type."); } $query = "SELECT user_id, COALESCE(SUM($currency), 0) AS total FROM transactions GROUP BY user_id ORDER BY total DESC LIMIT :n"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':n', $n, \PDO::PARAM_INT); $stmt->execute(); return $stmt->fetchAll(); @@ -84,11 +84,11 @@ class transactions public static function getLiabilities($currency) { - if (!in_array($currency, ['cents', 'sats'])) { + if (! in_array($currency, ['cents', 'sats'])) { throw new \Exception("Invalid currency type."); } $query = "SELECT COALESCE(SUM($currency), 0) AS total FROM transactions"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->execute(); return $stmt->fetchColumn(); } diff --git a/src/models/user_addresses.php b/src/models/user_addresses.php deleted file mode 100644 index 4de093d..0000000 --- a/src/models/user_addresses.php +++ /dev/null @@ -1,61 +0,0 @@ -exec("CREATE TABLE IF NOT EXISTS user_addresses ( - user_id INTEGER NOT NULL, - address_id INTEGER NOT NULL, - PRIMARY KEY (user_id, address_id), - FOREIGN KEY (address_id) REFERENCES addresses(id) - )"); - } - - public static function getShippingByUserId($id) - { - $query = "SELECT a.* FROM users u - JOIN user_addresses ua ON u.id = ua.user_id - JOIN addresses a ON ua.address_id = a.id - WHERE u.id = :id AND a.shipping = 1"; - $stmt = app::$db->prepare($query); - $stmt->bindParam(':id', $id); - $stmt->execute(); - $addrs = $stmt->fetch(\PDO::FETCH_ASSOC); - return [$addrs]; - } - - public static function getBillingByUserId($id) - { - $query = "SELECT a.* FROM users u - JOIN user_addresses ua ON u.id = ua.user_id - JOIN addresses a ON ua.address_id = a.id - WHERE u.id = :id AND a.billing = 1"; - $stmt = app::$db->prepare($query); - $stmt->bindParam(':id', $id); - $stmt->execute(); - $addrs = $stmt->fetch(\PDO::FETCH_ASSOC); - return [$addrs]; - } - - public static function add($user_id, $address_id) - { - $query = "INSERT INTO user_addresses ( - user_id, - address_id - ) VALUES ( - :user_id, - :address_id - )"; - $stmt = app::$db->prepare($query); - $stmt->bindParam(':user_id', $user_id); - $stmt->bindParam(':address_id', $address_id); - $stmt->execute(); - return app::$db->lastInsertId(); - } - -} diff --git a/src/models/users.php b/src/models/users.php index cafe0af..0ecc71f 100644 --- a/src/models/users.php +++ b/src/models/users.php @@ -2,6 +2,7 @@ namespace app\models; use app\app; +use app\models\addresses; use swentel\nostr\Key\Key; class users @@ -35,7 +36,7 @@ class users public static function updateReplaceEmailTokenById($user_id, $replace_token) { $query = "UPDATE users SET replace_email_token = :replace_token WHERE id = :user_id"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':replace_token', $replace_token); $stmt->bindParam(':user_id', $user_id); $stmt->execute(); @@ -44,7 +45,7 @@ class users public static function updateEmailById($user_id, $email) { $query = "UPDATE users SET email = :email WHERE id = :user_id"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':email', $email); $stmt->bindParam(':user_id', $user_id); $stmt->execute(); @@ -54,7 +55,7 @@ class users public static function getByReplaceEmailToken($token) { $query = "SELECT * FROM users WHERE replace_email_token = :token"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':token', $token); $stmt->execute(); return $stmt->fetch(\PDO::FETCH_ASSOC); @@ -62,7 +63,7 @@ class users public static function updateProfileById($user_id, $post) { - $query = "UPDATE users SET + $query = "UPDATE users SET name = :name, company_name = :company_name, company_type = :company_type, @@ -79,13 +80,13 @@ class users public static function add($email, $ship_id, $bill_id, $opt_in_promotional, $verified, $dark_theme) { - $key = new Key(); + $key = new Key(); $private_key = $key->generatePrivateKey(); $public_key = $key->getPublicKey($private_key); - $npub = $key->convertPublicKeyToBech32($public_key); - $nsec = $key->convertPrivateKeyToBech32($private_key); - $query = "INSERT INTO users ( - email, + $npub = $key->convertPublicKeyToBech32($public_key); + $nsec = $key->convertPrivateKeyToBech32($private_key); + $query = "INSERT INTO users ( + email, shipping_address_id, billing_address_id, opt_in_promotional, @@ -113,13 +114,18 @@ class users $stmt->bindParam(':nsec', $nsec); $stmt->bindParam(':npub', $npub); $stmt->execute(); - return app::$db->lastInsertId(); + $user_id = app::$db->lastInsertId(); + addresses::updateUserIdById($ship_id, $user_id); + if ($ship_id != $bill_id) { + addresses::updateUserIdById($bill_id, $user_id); + } + return $user_id; } public static function verify($email) { $query = "UPDATE users SET verified = 1 WHERE email = :email"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':email', $email); $stmt->execute(); } @@ -127,7 +133,7 @@ class users public static function getById($id) { $query = "SELECT * FROM users WHERE id = :id"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':id', $id); $stmt->execute(); return $stmt->fetch(\PDO::FETCH_ASSOC); @@ -136,7 +142,7 @@ class users public static function getByNpub($npub) { $query = "SELECT * FROM users WHERE npub = :npub"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':npub', $npub); $stmt->execute(); return $stmt->fetch(\PDO::FETCH_ASSOC); @@ -145,7 +151,7 @@ class users public static function getByEmail($email) { $query = "SELECT * FROM users WHERE email = :email"; - $stmt = app::$db->prepare($query); + $stmt = app::$db->prepare($query); $stmt->bindParam(':email', $email); $stmt->execute(); return $stmt->fetch(\PDO::FETCH_ASSOC); diff --git a/src/scripts/check_all_invoices.php b/src/scripts/check_all_invoices.php index 433a8dd..f291dd6 100644 --- a/src/scripts/check_all_invoices.php +++ b/src/scripts/check_all_invoices.php @@ -4,12 +4,12 @@ // It will apply store_credit if the invoice was paid and associated with a deposit // It will make adjustments to quotes or orders if the invoice was paid and associated with a quote or order payment // It will mark invoices as expired if they are expired -// +// // Run this every 10 seconds with cron like this... // * * * * * bash -c 'start=$(date +%s); for i in {1..6}; do php /path/to/scripts/check_all_invoices.php; sleep $((10 - ($(date +%s) - start) % 10)); done' // -// Cron only lets you run every minute, using this we can run every 10 seconds. -// It accounts for the execution time of this script +// Cron only lets you run every minute, using this we can run every 10 seconds. +// It accounts for the execution time of this script // so there will be minimal 'drift' over time. // require_once __DIR__ . '/../../vendor/autoload.php'; @@ -22,4 +22,3 @@ use app\models\invoices; app::init_db(); invoices::checkAll(); - diff --git a/src/scripts/check_subscriptions.php b/src/scripts/check_subscriptions.php index d3259ae..37554b7 100644 --- a/src/scripts/check_subscriptions.php +++ b/src/scripts/check_subscriptions.php @@ -18,4 +18,4 @@ require_once __DIR__ . '/../../vendor/autoload.php'; // Load environment variables from the .env file at project root -Dotenv\Dotenv::createImmutable(__DIR__ . '/../../')->load(); \ No newline at end of file +Dotenv\Dotenv::createImmutable(__DIR__ . '/../../')->load(); diff --git a/src/scripts/init_db.php b/src/scripts/init_db.php index 4031b97..6dea255 100644 --- a/src/scripts/init_db.php +++ b/src/scripts/init_db.php @@ -13,48 +13,33 @@ Dotenv\Dotenv::createImmutable(__DIR__ . '/../../')->load(); use app\app; app::init_db(); -// db models go brrr... use app\models\addresses; -addresses::init(); - -use app\models\cart_items; -cart_items::init(); - use app\models\carts; -carts::init(); - +use app\models\cart_items; use app\models\emails; -emails::init(); - use app\models\invoices; -invoices::init(); - use app\models\magic_links; -magic_links::init(); - -use app\models\order_items; -order_items::init(); - use app\models\orders; -orders::init(); - +use app\models\order_items; use app\models\products; -products::init(); - -use app\models\quote_items; -quote_items::init(); - use app\models\quotes; -quotes::init(); - +use app\models\quote_items; use app\models\subscriptions; -subscriptions::init(); - use app\models\transactions; -transactions::init(); - -use app\models\user_addresses; -user_addresses::init(); - use app\models\users; + +// db models go brrr... +addresses::init(); +carts::init(); +cart_items::init(); +emails::init(); +invoices::init(); +magic_links::init(); +order_items::init(); +orders::init(); +products::init(); +quote_items::init(); +quotes::init(); +subscriptions::init(); +transactions::init(); users::init(); diff --git a/src/views/404.twig b/src/views/404.twig index 8598f2d..0b79319 100644 --- a/src/views/404.twig +++ b/src/views/404.twig @@ -1,7 +1,7 @@
- {% include 'lib/empty.twig' with { + {% include 'lib/empty.twig' with { type: '404', title: 'Page not found.', subtitle: 'Shop our latest products!' } %} -
\ No newline at end of file + diff --git a/src/views/account/address/confirm.twig b/src/views/account/address/confirm.twig new file mode 100644 index 0000000..763ec59 --- /dev/null +++ b/src/views/account/address/confirm.twig @@ -0,0 +1 @@ +confirm the address \ No newline at end of file diff --git a/src/views/account/address/edit.twig b/src/views/account/address/edit.twig new file mode 100644 index 0000000..08d43f1 --- /dev/null +++ b/src/views/account/address/edit.twig @@ -0,0 +1 @@ +edit the address \ No newline at end of file diff --git a/src/views/account/billing.twig b/src/views/account/billing.twig index 75c9c6b..e7c63d2 100644 --- a/src/views/account/billing.twig +++ b/src/views/account/billing.twig @@ -1,8 +1,10 @@
- +
-
-

Payment Methods

+
+

+ Payment Methods +

{% include 'lib/rule.twig' %}
{% include 'lib/empty.twig' with { @@ -11,20 +13,25 @@ subtitle: 'Add a payment method' } %}
-

Billing Address

+

+ Billing Address +

{% include 'lib/rule.twig' %} -

Your billing information must match the information associatied with the credit card making the purchase.

-
- {{ default_billing.name }} - {{ default_billing.company }} - {{ default_billing.addressLine1 }} - {{ default_billing.addressLine2 }} - {{ default_billing.city }}, {{ default_billing.state }} {{ default_billing.zip }} - {{ default_billing.phone }} -
+

+ Your billing information must match the information associatied with the credit card making the purchase. +

+ {% for address in addresses %} + {% if address.id == user.billing_address_id %} + {% include 'lib/address.twig' with { + address: address, + edit_url: '/account/billing/edit/' ~ address.id, + delete_url: '/account/billing/delete/' ~ address.id + } %} + {% endif %} + {% endfor %}
- {% include 'lib/form/address.twig' with { + {% include 'lib/forms/address.twig' with { action: 'billing' } %} {% include 'lib/button.twig' with { @@ -32,9 +39,17 @@ onclick: 'this.parentNode.submit()', } %}
- {% include 'lib/rule.twig' with { - text: 'OR' - } %} - Use saved address + {% if addresses|length > 1 %} + {% include 'lib/rule.twig' with { + text: 'OR' + } %} + {% for address in addresses %} + {% include 'lib/address.twig' with { + address: address, + edit_url: '/account/billing/edit/' ~ address.id, + delete_url: '/account/billing/delete/' ~ address.id + } %} + {% endfor %} + {% endif %}
-
\ No newline at end of file + diff --git a/src/views/account/index.twig b/src/views/account/index.twig index 0c601cb..b46ff3c 100644 --- a/src/views/account/index.twig +++ b/src/views/account/index.twig @@ -1,10 +1,12 @@
{% include 'lib/alert.twig' %} -

Profile

+

+ Profile +

{% include 'lib/rule.twig' %}
- {% include 'lib/form/profile.twig' with { + {% include 'lib/forms/profile.twig' with { name: user.name, company_name: user.company_name, company_type: user.company_type, @@ -17,14 +19,19 @@
-

Email

+

+ Email +

- {% include 'lib/input.twig' with { + {% include 'lib/inputs/text.twig' with { type: 'text', name: 'email', value: user.email } %} -

Verified: {{ user.verified ? 'Yes' : 'No' }}

+

+ Verified: + {{ user.verified ? 'Yes' : 'No' }} +

{% include 'lib/button.twig' with { label: 'Save Email', onclick: 'this.parentNode.submit()', @@ -33,66 +40,102 @@
-

Shipping

- Edit +

+ Shipping +

+ + Edit +
{% include 'lib/rule.twig' %} -
-

{{ default_shipping.name }}

-

{{ default_shipping.company }}

-

{{ default_shipping.addressLine1 }}

-

{{ default_billing.addressLine2 }}

-

{{ default_shipping.city }}, {{ default_shipping.state }}, {{ default_shipping.zip }}

-

{{ default_shipping.phone }}

-
-
-
-
-

Billing

- Edit -
- {% include 'lib/rule.twig' %} -
-

{{ default_billing.name }}

-

{{ default_billing.company }}

-

{{ default_billing.addressLine1 }}

-

{{ default_billing.addressLine2 }}

-

{{ default_billing.city }}, {{ default_billing.state }}, {{ default_billing.zip }}

-

{{ default_billing.phone }}

-
+ {% for address in addresses %} + {% if address.id == user.shipping_address_id %} + {% include 'lib/address.twig' with { + address: address, + edit_url: '/account/shipping/edit/' ~ address.id, + delete_url: '/account/shipping/delete/' ~ address.id + } %} + {% endif %} + {% endfor %}
-

Credit Card

- Edit -
+

+ Billing +

+ + Edit + +
+ {% include 'lib/rule.twig' %} + {% for address in addresses %} + {% if address.id == user.billing_address_id %} + {% include 'lib/address.twig' with { + address: address, + edit_url: '/account/billing/edit/' ~ address.id, + delete_url: '/account/billing/delete/' ~ address.id + } %} + {% endif %} + {% endfor %} + +
+
+

+ Credit Card +

+ + Edit + +
{% include 'lib/rule.twig' %}
-

Store Credit

- +

+ Store Credit +

+ + + + + + +
- $0.00 -
+ + $0.00 + +
{% include 'lib/rule.twig' %}
-
-

Sats

- +
+

+ Sats +

+ + + + + + +
- 0 -
+ + 0 + +
{% include 'lib/rule.twig' %}
-

Marketing

+

+ Marketing +

{% include 'lib/rule.twig' %} - {% include 'lib/toggle.twig' with { + {% include 'lib/inputs/toggle.twig' with { label: 'Recieve coupons & more', name: 'opt_in_promotional', on: user.opt_in_promotional @@ -106,9 +149,9 @@
{% include 'lib/modal.twig' with { id: 'store-credit', - content: 'lib/policy/credit.twig' + content: 'lib/modals/credit.twig' } %} {% include 'lib/modal.twig' with { id: 'sats', - content: 'lib/policy/sats.twig' -} %} \ No newline at end of file + content: 'lib/modals/sats.twig' +} %} diff --git a/src/views/account/login.twig b/src/views/account/login.twig index 3ecca86..90ec368 100644 --- a/src/views/account/login.twig +++ b/src/views/account/login.twig @@ -1,12 +1,14 @@
-

Login

+

+ Login +

{% include 'lib/rule.twig' %}
{% include 'lib/alert.twig' %} - {% include 'lib/input.twig' with { + {% include 'lib/inputs/text.twig' with { type: 'email', name: 'email', label: 'Email link', @@ -20,4 +22,4 @@ } %}
-
\ No newline at end of file + diff --git a/src/views/account/orders.twig b/src/views/account/orders.twig index 63001c0..d3a2f1d 100644 --- a/src/views/account/orders.twig +++ b/src/views/account/orders.twig @@ -1,6 +1,8 @@
-

Order History

+

+ Order History +

{% include 'lib/rule.twig' %}
{% include 'lib/empty.twig' with { @@ -8,4 +10,4 @@ title: 'No Orders Yet', subtitle: 'Your orders will show here.' } %} -
\ No newline at end of file + diff --git a/src/views/account/returns.twig b/src/views/account/returns.twig index 1eacd43..b42bc38 100644 --- a/src/views/account/returns.twig +++ b/src/views/account/returns.twig @@ -1,6 +1,8 @@
-

Returns

+

+ Returns +

{% include 'lib/rule.twig' %}
{% include 'lib/empty.twig' with { @@ -8,4 +10,4 @@ title: "No returns started", subtitle: 'Click here to start a return' } %} -
\ No newline at end of file + diff --git a/src/views/account/shipping.twig b/src/views/account/shipping.twig index 00ba5cb..e163a41 100644 --- a/src/views/account/shipping.twig +++ b/src/views/account/shipping.twig @@ -1,21 +1,26 @@
-
+
-

Saved Shipping Address

+

+ Saved Shipping Address +

{% include 'lib/rule.twig' %} -

This is your default shipping address for orders at checkout.

-
-
- {{ default_shipping.name }} - {{ default_shipping.company }} - {{ default_shipping.addressLine1 }} - {{ default_shipping.addressLine2 }} - {{ default_shipping.city }}, {{ default_shipping.state }} {{ default_shipping.zip }} - {{ default_shipping.phone }} +

+ This is your default shipping address for orders at checkout. +

+ {% for address in addresses %} + {% if address.id == user.shipping_address_id %} + {% include 'lib/address.twig' with { + address: address, + edit_url: '/account/shipping/edit/' ~ address.id, + delete_url: '/account/shipping/delete/' ~ address.id + } %} + {% endif %} + {% endfor %}
- {% include 'lib/form/address.twig' with { + {% include 'lib/forms/address.twig' with { action: 'shipping' } %} {% include 'lib/button.twig' with { @@ -23,9 +28,17 @@ onclick: 'this.parentNode.submit()' } %}
- {% include 'lib/rule.twig' with { - text: 'OR' - } %} - Use a saved address + {% if addresses|length > 1 %} + {% include 'lib/rule.twig' with { + text: 'OR' + } %} + {% for address in addresses %} + {% include 'lib/address.twig' with { + address: address, + edit_url: '/account/billing/edit/' ~ address.id, + delete_url: '/account/billing/delete/' ~ address.id + } %} + {% endfor %} + {% endif %} -
\ No newline at end of file + diff --git a/src/views/account/signup.twig b/src/views/account/signup.twig index 10c6615..a0d73ac 100644 --- a/src/views/account/signup.twig +++ b/src/views/account/signup.twig @@ -1,26 +1,34 @@
-

Create an Account

- You can manage all your orders, addresses, and payment cards in one place! +

+ Create an Account +

+ + You can manage all your orders, addresses, and payment cards in one place! +
{% include 'lib/alert.twig' %}
{% include 'lib/rule.twig' with { text: 'STEP 1' } %}
-

Email Address

- Recieve login link to verify. Order and account updates will be sent here. +

+ Email Address +

+ + Recieve login link to verify. Order and account updates will be sent here. +
- {% include 'lib/input.twig' with { + {% include 'lib/inputs/text.twig' with { type: 'text', name: 'email', value: session.user_email is defined ? session.user_email : null, readonly: session.user_email is defined ? true : null } %}
- {% include 'lib/toggle.twig' with { + {% include 'lib/inputs/toggle.twig' with { label: 'Recieve coupons & more', name: 'opt_in_promotional', on: true @@ -28,10 +36,14 @@
{% include 'lib/rule.twig' with { text: 'STEP 2' } %}
-

Shipping Address

- Your orders will ship to this address (USA only). +

+ Shipping Address +

+ + Your orders will ship to this address (USA only). +
- {% include 'lib/form/address.twig' with { + {% include 'lib/forms/address.twig' with { action: 'shipping', name: session.last_post.shipping_name, addressLine1: session.last_post.shipping_addressLine1, @@ -45,18 +57,22 @@ {% include 'lib/rule.twig' with { text: 'STEP 3' } %}
-

Billing Address

- Info must match the credit card making the purchase. +

+ Billing Address +

+ + Info must match the credit card making the purchase. +
- - {% include 'lib/toggle.twig' with { + + {% include 'lib/inputs/toggle.twig' with { label: 'Same as shipping', name: 'use_shipping', on: true } %} -
- + - {% include 'lib/rule.twig' with { text: 'ALL DONE!' } %} - {% include 'lib/button.twig' with { +
+ {% include 'lib/rule.twig' with { text: 'ALL DONE!' } %} + {% include 'lib/button.twig' with { label: 'Register', onclick: 'this.parentNode.submit()', captcha: true } %} - - - -
\ No newline at end of file + \ No newline at end of file diff --git a/src/views/account/verify.twig b/src/views/account/verify.twig index c692deb..d6bcc07 100644 --- a/src/views/account/verify.twig +++ b/src/views/account/verify.twig @@ -1,12 +1,16 @@
-

Check Your Email

-

We have sent a verification code to your email.

+

+ Check Your Email +

+

+ We have sent a verification code to your email. +

{% include 'lib/rule.twig' %}
{% include 'lib/alert.twig' %} -