save
This commit is contained in:
parent
27df1a73b5
commit
a0cb5fb6b0
36 changed files with 1886 additions and 187 deletions
|
@ -3,6 +3,7 @@ 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;
|
||||
|
||||
|
@ -138,6 +139,49 @@ class account
|
|||
}
|
||||
}
|
||||
|
||||
public static function verify($defaults)
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$code = $_POST['code'];
|
||||
$link = magic_links::validateCode($code);
|
||||
if ($link) {
|
||||
$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']) {
|
||||
users::verify($link['email']);
|
||||
}
|
||||
header('Location: /account');
|
||||
exit;
|
||||
} else {
|
||||
$_SESSION['user_email'] = $link['email'];
|
||||
header('Location: /account/signup');
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
$_SESSION['error'] = "Invalid or expired verification code.";
|
||||
header('Location: /account/verify');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'account/verify.twig',
|
||||
'page_title' => $_ENV['APP_NAME'],
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/account',
|
||||
'title' => 'My Account'
|
||||
],
|
||||
[
|
||||
'url' => null,
|
||||
'title' => 'Verify'
|
||||
]
|
||||
]
|
||||
]));
|
||||
}
|
||||
|
||||
public static function login($defaults)
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
|
@ -148,7 +192,7 @@ class account
|
|||
exit;
|
||||
} else {
|
||||
$token = magic_links::add($email, null);
|
||||
header('Location: /account/login');
|
||||
header('Location: /account/verify');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
@ -339,6 +383,7 @@ class account
|
|||
$verified,
|
||||
$dark_theme
|
||||
);
|
||||
emails::updateUserIdByEmail($email, $user_id);
|
||||
user_addresses::add(
|
||||
user_id: $user_id,
|
||||
address_id: $ship_id
|
||||
|
|
184
src/controllers/admin.php
Normal file
184
src/controllers/admin.php
Normal file
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
namespace app\controllers;
|
||||
|
||||
use app\models\transactions;
|
||||
use app\models\emails;
|
||||
use app\models\users;
|
||||
|
||||
class admin
|
||||
{
|
||||
public static function index($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/index.twig',
|
||||
'page_title' => 'Dashboard',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
]
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function users($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/users.twig',
|
||||
'page_title' => 'Users',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
],
|
||||
[
|
||||
'url' => '/admin/users',
|
||||
'title' => 'Users'
|
||||
]
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function orders($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/orders.twig',
|
||||
'page_title' => 'Orders',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
],
|
||||
[
|
||||
'url' => '/admin/orders',
|
||||
'title' => 'Orders'
|
||||
]
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function returns($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/returns.twig',
|
||||
'page_title' => 'Returns',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
],
|
||||
[
|
||||
'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'),
|
||||
'cents_liability' => transactions::getLiabilities('cents'),
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
],
|
||||
[
|
||||
'url' => '/admin/transactions',
|
||||
'title' => 'Transactions'
|
||||
]
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function transactions_add($defaults)
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$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.";
|
||||
$_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);
|
||||
} else {
|
||||
$_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.";
|
||||
$_SESSION['last_post'] = $_POST;
|
||||
} else {
|
||||
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']['confirm'] = true;
|
||||
$_SESSION['last_post']['email'] = $user['email'];
|
||||
$_SESSION['last_post']['id'] = $user['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/transactions/add.twig',
|
||||
'page_title' => 'Add a Transaction',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
],
|
||||
[
|
||||
'url' => '/admin/transactions',
|
||||
'title' => 'Transactions'
|
||||
],
|
||||
[
|
||||
'url' => '/admin/transactions/add',
|
||||
'title' => 'Add'
|
||||
]
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function emails($defaults)
|
||||
{
|
||||
$recent_emails = emails::getRecent(20);
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/emails.twig',
|
||||
'page_title' => 'Emails',
|
||||
'recent_emails' => $recent_emails,
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
],
|
||||
[
|
||||
'url' => '/admin/emails',
|
||||
'title' => 'Emails'
|
||||
]
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function transactions_reset($defaults)
|
||||
{
|
||||
$_SESSION['last_post'] = null;
|
||||
header('Location: /admin/transactions/add');
|
||||
exit;
|
||||
}
|
||||
}
|
|
@ -2,13 +2,18 @@
|
|||
|
||||
namespace app\controllers;
|
||||
use app\app;
|
||||
use app\models\invoices;
|
||||
$invoice = 'lnbc234340n1pnm5uh2pp5pwekmjzj3hgadahfeprtc6f2ppmhnqjzh556q4fvve8z953v3t0sdqqcqzysxqrrsssp5uq25yjnmvdpnglmv42nf64wk0pugrynq549f3wgghgtkfapwdfhq9qxpqysgqyjq2ewqkm6s2dlhuruuc4k9md22wraz829tlhfeuxrsnwmephfkjz8e9g7j6373989mfccajy3cxexac8xu6yen4qfs4947fkrg9ynsq7x72ze';
|
||||
use Jorijn\Bitcoin\Bolt11\Encoder\PaymentRequestDecoder;
|
||||
use Jorijn\Bitcoin\Bolt11\Model\Tag;
|
||||
use Jorijn\Bitcoin\Bolt11\Normalizer\PaymentRequestDenormalizer;
|
||||
|
||||
class lnurlp
|
||||
{
|
||||
public static function index()
|
||||
public static function index($defaults)
|
||||
{
|
||||
header(header: 'Content-Type: application/json');
|
||||
$host = $_SERVER['HTTP_HOST'];
|
||||
$user = $_GET["username"] ?? false;
|
||||
$username = $_GET["username"] ?? false;
|
||||
$paymentRequest = $_GET["pay"] ?? false;
|
||||
$verify = $_GET["verify"] ?? false;
|
||||
|
||||
|
@ -25,25 +30,29 @@ class lnurlp
|
|||
'reason' => 'invalid value for `pay` param (set `pay=1` or exclude `pay` from the url)',
|
||||
]);
|
||||
}
|
||||
// for when the user is missing
|
||||
if ($user == false && $verify == false) {
|
||||
// for when the user is not specified
|
||||
if ($username == false && $verify == false) {
|
||||
returnJson([
|
||||
'status' => 'ERROR',
|
||||
'reason' => 'no user specified (set `username=<name>` in the url)',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
list($proxy_user, $proxy_host) = explode("@", $_ENV['LN_ADDRESS']);
|
||||
|
||||
|
||||
// for when the user is not registered
|
||||
$user = users::getByNpub($username);
|
||||
if (!$user){
|
||||
returnJson([
|
||||
'status' => 'ERROR',
|
||||
'reason' => "@$username is not registered"
|
||||
]);
|
||||
}
|
||||
// for when the client makes it's first call (querying the lightning address)
|
||||
$metadata = "[[\"text/plain\",\"Funding @$user on $host\"],[\"text/identifier\",\"$user@$host\"]]";
|
||||
list($proxy_user, $proxy_host) = explode("@", $_ENV['LN_ADDRESS']);
|
||||
$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=$user",
|
||||
'callback' => "https://$host/lnurlp?pay=1&username=$username",
|
||||
'maxSendable' => $res['maxSendable'],
|
||||
'minSendable' => $res['minSendable'],
|
||||
'metadata' => $metadata,
|
||||
|
@ -54,19 +63,34 @@ class lnurlp
|
|||
);
|
||||
}
|
||||
|
||||
// for when the client makes it's second call (callback)
|
||||
// for when the client makes it's second call (callback) to get an invoice
|
||||
if ($paymentRequest == "1") {
|
||||
$proxy_url = "https://$proxy_host/lnurlp?pay=1&username=$proxy_user";
|
||||
$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'){
|
||||
// subscribe to this invoice by adding to our db
|
||||
$invoice = $res['pr'];
|
||||
$decoder = new PaymentRequestDecoder();
|
||||
$denormalizer = new PaymentRequestDenormalizer();
|
||||
$paymentRequest = $denormalizer->denormalize($decoder->decode($invoice));
|
||||
invoices::add(
|
||||
$user['id'],
|
||||
null,
|
||||
$invoice,
|
||||
$res['verify'],
|
||||
$paymentRequest->getMilliSatoshis(),
|
||||
$paymentRequest->getExpiryDateTime()['date']
|
||||
);
|
||||
$boom = explode("=", $res['verify']);
|
||||
$proxy_verify = end($boom);
|
||||
returnJson([
|
||||
'status' => 'OK',
|
||||
'pr' => $res['pr'],
|
||||
'pr' => $invoice,
|
||||
'routes' => $res['routes'],
|
||||
'verify' => "https://$host/lnurlp?verify=$proxy_verify"
|
||||
]);
|
||||
|
@ -77,8 +101,10 @@ class lnurlp
|
|||
|
||||
// for when they want to verify the payment succeeded
|
||||
if ($verify) {
|
||||
$res = json_decode(file_get_contents("https://$proxy_host/lnurlp?verify=$verify"), true);
|
||||
returnJson($res);
|
||||
$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);
|
||||
returnJson($prox_res);
|
||||
}
|
||||
|
||||
// for when none of the above conditions are met
|
||||
|
|
172
src/controllers/transaction.php
Normal file
172
src/controllers/transaction.php
Normal file
|
@ -0,0 +1,172 @@
|
|||
<?php
|
||||
namespace app\controllers;
|
||||
|
||||
use app\models\transactions;
|
||||
use app\models\users;
|
||||
|
||||
use app\controllers\lost;
|
||||
|
||||
class transaction
|
||||
{
|
||||
public static function view($defaults, $txid)
|
||||
{
|
||||
$tx = transactions::getById($txid);
|
||||
if (!$tx) {
|
||||
lost::index($defaults);
|
||||
}
|
||||
$user = users::getById($tx['user_id']);
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'transaction.twig',
|
||||
'page_title' => 'Transaction Reciept #' . $txid,
|
||||
'tx' => $tx,
|
||||
'user' => $user,
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => "/transaction/" . $txid,
|
||||
'title' => 'Transaction Reciept'
|
||||
]
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function users($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/users.twig',
|
||||
'page_title' => $_ENV['APP_NAME'] . ' Users',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
],
|
||||
[
|
||||
'url' => '/admin/users',
|
||||
'title' => 'Users'
|
||||
]
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function orders($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/orders.twig',
|
||||
'page_title' => $_ENV['APP_NAME'] . ' Orders',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
],
|
||||
[
|
||||
'url' => '/admin/orders',
|
||||
'title' => 'Orders'
|
||||
]
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function returns($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/returns.twig',
|
||||
'page_title' => $_ENV['APP_NAME'] . ' Returns',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
],
|
||||
[
|
||||
'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'),
|
||||
'cents_liability' => transactions::getLiabilities('cents'),
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
],
|
||||
[
|
||||
'url' => '/admin/transactions',
|
||||
'title' => 'Transactions'
|
||||
]
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function transactions_add($defaults)
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$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.";
|
||||
$_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);
|
||||
} else {
|
||||
$_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.";
|
||||
$_SESSION['last_post'] = $_POST;
|
||||
} else {
|
||||
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']['confirm'] = true;
|
||||
$_SESSION['last_post']['email'] = $user['email'];
|
||||
$_SESSION['last_post']['id'] = $user['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/transactions/add.twig',
|
||||
'page_title' => 'Add a Transaction',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
],
|
||||
[
|
||||
'url' => '/admin/transactions',
|
||||
'title' => 'Transactions'
|
||||
],
|
||||
[
|
||||
'url' => '/admin/transactions/add',
|
||||
'title' => 'Add'
|
||||
]
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function transactions_reset($defaults)
|
||||
{
|
||||
$_SESSION['last_post'] = null;
|
||||
header('Location: /admin/transactions/add');
|
||||
exit;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue