This commit is contained in:
count-null 2025-03-06 11:54:23 -05:00
parent 35971fd696
commit 1ed14b5549
7 changed files with 118 additions and 162 deletions

View file

@ -90,7 +90,7 @@ class account
$user_id = $_SESSION['user_id']; $user_id = $_SESSION['user_id'];
$token = magic_links::add($email, $user_id); $token = magic_links::add($email, $user_id);
users::updateReplaceEmailTokenById($user_id, $token); users::updateReplaceEmailTokenById($user_id, $token);
header('Location: /account'); header('Location: /account/verify');
exit; exit;
} }
} }
@ -98,30 +98,6 @@ class account
public static function verify($defaults) 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/pages/index.twig', array_merge($defaults, [ echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
'child_template' => 'account/verify.twig', 'child_template' => 'account/verify.twig',
'page_title' => $_ENV['APP_NAME'], 'page_title' => $_ENV['APP_NAME'],
@ -303,9 +279,8 @@ class account
} }
$existingUser = users::getByEmail($email); $existingUser = users::getByEmail($email);
if ($existingUser) { if ($existingUser) {
$_SESSION['error'] = 'Email already exists. Please choose a different email or log in.'; $token = magic_links::add($email, $user_id);
$_SESSION['last_post'] = $_POST; header("Location: /account/verify");
header('Location: /account/signup');
exit; exit;
} }
$useShipping = $_POST['use_shipping'] ?? false; $useShipping = $_POST['use_shipping'] ?? false;
@ -368,7 +343,8 @@ class account
); );
$_SESSION['user_id'] = $user_id; $_SESSION['user_id'] = $user_id;
if (! $verified) { if (! $verified) {
header("Location: /magic-link?email=$email&signup=1"); $token = magic_links::add($email, $user_id);
header("Location: /account/verify");
exit; exit;
} }
header('Location: /account'); header('Location: /account');

View file

@ -107,7 +107,6 @@ class admin
$user_identifier = $_POST['user_identifier'] ?? null; $user_identifier = $_POST['user_identifier'] ?? null;
if (! $amount || ! $user_identifier) { 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['error'] = ! $amount ? "Please enter an amount for the transaction." : "Please enter a user email or id for the transaction.";
$_SESSION['last_post'] = $_POST;
} else { } else {
if (strpos($user_identifier, '@') !== false && strpos($user_identifier, '.') !== false) { if (strpos($user_identifier, '@') !== false && strpos($user_identifier, '.') !== false) {
$user = users::getByEmail($user_identifier); $user = users::getByEmail($user_identifier);
@ -115,23 +114,14 @@ class admin
$user = users::getById((int) $user_identifier); $user = users::getById((int) $user_identifier);
} else { } 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) { if (! $user) {
$_SESSION['error'] = "User not found. Please enter a valid email or user ID."; $_SESSION['error'] = "User not found. Please enter a valid email or user ID.";
$_SESSION['last_post'] = $_POST;
} else { } else {
if ($_POST['confirm']) {
// create the transaction // create the transaction
$txid = transactions::add($user['id'], $amount > 0 ? 'CREDIT' : 'REVOKE', $currency == 'cents' ? $amount : 0, $currency == 'sats' ? $amount : 0); $txid = transactions::add($user['id'], $amount > 0 ? 'CREDIT' : 'REVOKE', $currency == 'cents' ? $amount : 0, $currency == 'sats' ? $amount : 0);
header('Location: /transaction/' . $txid); header('Location: /transaction/' . $txid);
exit; exit;
} else {
$_SESSION['last_post'] = $_POST;
$_SESSION['last_post']['confirm'] = true;
$_SESSION['last_post']['email'] = $user['email'];
$_SESSION['last_post']['id'] = $user['id'];
}
} }
} }
} }
@ -153,6 +143,7 @@ class admin
], ],
], ],
])); ]));
exit;
} }
public static function emails($defaults) public static function emails($defaults)

View file

@ -9,6 +9,48 @@ class magic_link
{ {
public static function index() public static function index()
{ {
if ($_SERVER['REQUEST_METHOD'] == 'POST') { // using a 6-digit code
$code = $_POST['code'] ?? null;
if (! $code) {
$_SESSION['error'] = "Invalid or expired code.";
header('Location: /account/verify');
exit;
} else {
$link = magic_links::validateCode($code);
if ($link) { // the code is valid
$user = $link['user_id'] ? users::getById($link['user_id']) : users::getByEmail($link['email']);
if ($user) { // this email is registered or associated with a user
$user_replacing = users::getByReplaceEmailToken($link['token']);
if ($user_replacing) { // user is replacing their email
users::updateEmailById($user_replacing['id'], $link['email']);
$_SESSION['user_email'] = $link['email'];
$_SESSION['user_id'] = $user_replacing['id'];
if (! $user_replacing['verified']) {
users::verify($link['email']);
}
header('Location: /account');
exit;
} else { // user is logging in
$_SESSION['user_email'] = $link['email'];
$_SESSION['user_id'] = $user['id'];
if (! $user['verified']) {
users::verify($link['email']);
}
header('Location: /account');
exit;
}
} else { // new user signup
$_SESSION['user_email'] = $link['email'];
header('Location: /account/signup');
exit;
}
} else { // the code is not valid
$_SESSION['error'] = "Invalid or expired verification code.";
header('Location: /account/verify');
exit;
}
}
} else { // using a link with a token
$token = $_GET['token'] ?? null; $token = $_GET['token'] ?? null;
if (! $token) { if (! $token) {
$_SESSION['error'] = "Invalid or expired link."; $_SESSION['error'] = "Invalid or expired link.";
@ -22,7 +64,18 @@ class magic_link
exit; exit;
} }
$user = $link['user_id'] ? users::getById($link['user_id']) : users::getByEmail($link['email']); $user = $link['user_id'] ? users::getById($link['user_id']) : users::getByEmail($link['email']);
if ($user) { // user with this email exists, log them in if ($user) { // this email is registered or is associated with a user
$user_replacing = users::getByReplaceEmailToken($token);
if ($user_replacing) { // user is replacing their email
users::updateEmailById($user_replacing['id'], $link['email']);
$_SESSION['user_email'] = $link['email'];
$_SESSION['user_id'] = $user_replacing['id'];
if (! $user_replacing['verified']) {
users::verify($link['email']);
}
header('Location: /account');
exit;
} else { // user is logging in
$_SESSION['user_email'] = $link['email']; $_SESSION['user_email'] = $link['email'];
$_SESSION['user_id'] = $user['id']; $_SESSION['user_id'] = $user['id'];
if (! $user['verified']) { if (! $user['verified']) {
@ -30,18 +83,7 @@ class magic_link
} }
header('Location: /account'); header('Location: /account');
exit; exit;
} else { // no users with this email
$user_replacing_email = users::getByReplaceEmailToken($token);
if ($user_replacing_email) { // user is replacing their email
$user_id = $user_replacing_email['id'];
users::updateEmailById($user_id, $link['email']);
$_SESSION['user_email'] = $link['email'];
$_SESSION['user_id'] = $user_id;
if (! $user['verified']) {
users::verify($link['email']);
} }
header('Location: /account');
exit;
} else { // new user signup } else { // new user signup
$_SESSION['user_email'] = $link['email']; $_SESSION['user_email'] = $link['email'];
header('Location: /account/signup'); header('Location: /account/signup');

View file

@ -72,12 +72,11 @@ class users
public static function updateEmailById($user_id, $email) public static function updateEmailById($user_id, $email)
{ {
$query = "UPDATE users SET email = :email WHERE id = :user_id"; $query = "UPDATE users SET email = :email, replace_email_token = NULL WHERE id = :user_id";
$stmt = app::$db->prepare($query); $stmt = app::$db->prepare($query);
$stmt->bindParam(':email', $email); $stmt->bindParam(':email', $email);
$stmt->bindParam(':user_id', $user_id); $stmt->bindParam(':user_id', $user_id);
$stmt->execute(); $stmt->execute();
users::updateReplaceEmailTokenById($user_id, null);
} }
public static function getByReplaceEmailToken($token) public static function getByReplaceEmailToken($token)

View file

@ -11,7 +11,7 @@
</div> </div>
{% include 'lib/alert.twig' %} {% include 'lib/alert.twig' %}
<form action="/account/verify" method="post" class="flex flex-col items-center gap-4"> <form action="/magic-link" method="post" class="flex flex-col items-center gap-4">
{% include 'lib/inputs/text.twig' with { {% include 'lib/inputs/text.twig' with {
type: 'tel', type: 'tel',
name: 'code', name: 'code',

View file

@ -1,67 +1,32 @@
<section class="flex flex-col gap-4"> <section class="flex flex-col gap-4">
{% include 'lib/alert.twig' %} {% include 'lib/alert.twig' %}
<form action="/admin/transactions/add" method="post" class="flex flex-col gap-4"> <form action="/admin/transactions/add" method="post" class="flex flex-col gap-4">
{% if session.last_post.confirm %}
Confirm
<input type="hidden" name="confirm" id="confirm" value="{{ session.last_post.confirm }}">
{% endif %}
{% if session.last_post.amount is defined %}
{{ session.last_post.amount }}
{{ session.last_post.currency }}
<input
type="hidden" name="amount" id="amount" value="{{ session.last_post.amount }}" />
{% else %}
{% include 'lib/inputs/number.twig' with { {% include 'lib/inputs/number.twig' with {
id: 'amount', id: 'amount',
name: 'amount', name: 'amount',
label: 'Amount', label: 'Amount',
placeholder: 'Enter the amount', placeholder: 'Enter the amount',
value: session.last_post.amount,
required: true required: true
} %} } %}
{% endif %}
{% if session.last_post.currency %}
<input
type="hidden" name="currency" id="currency" value="{{ session.last_post.currency }}" />
{% else %}
{% include 'lib/inputs/select.twig' with { {% include 'lib/inputs/select.twig' with {
id: 'currency', id: 'currency',
name: 'currency', name: 'currency',
label: 'Currency', label: 'Currency',
value: session.last_post.currency,
options: [ options: [
{ 'value': 'sats', 'text': 'Sats' }, { 'value': 'sats', 'text': 'Sats' },
{ 'value': 'cents', 'text': 'Cents' } { 'value': 'cents', 'text': 'Cents' }
], ],
required: true required: true
} %} } %}
{% endif %}
{% if session.last_post.user_identifier is defined %}
{% if session.last_post.email is defined %}
{{ session.last_post.id }}
{{ session.last_post.email }}
{% endif %}
<input
type="hidden" name="user_identifier" id="user_identifier" value="{{ session.last_post.user_identifier }}" />
{% else %}
{% include 'lib/inputs/text.twig' with { {% include 'lib/inputs/text.twig' with {
type: 'text', type: 'text',
name: 'user_identifier', name: 'user_identifier',
label: 'User Identifier', label: 'User Identifier',
placeholder: 'Enter email or user index', placeholder: 'Enter email or user index',
value: session.last_post.user_identifier
} %} } %}
{% endif %}
{% include 'lib/buttons/submit.twig' with { {% include 'lib/buttons/submit.twig' with {
label: 'Submit', label: 'Submit',
} %} } %}
</form> </form>
{% if session.last_post %}
<a href="/admin/transactions/reset">
{% include 'lib/buttons/default.twig' with {
label: 'Cancel'
} %}
</a>
{% endif %}
</section>
</section>

View file

@ -1,27 +1,10 @@
<section class="flex flex-col gap-4"> <section class="flex flex-col gap-4">
{% include 'lib/alert.twig' %} {% include 'lib/alert.twig' %}
<form action="/admin/transactions/add" method="post" class="flex flex-col gap-4"> <a href="/admin/transactions/add">
{% include 'lib/inputs/number.twig' with {
id: 'amount',
name: 'amount',
label: 'Amount',
required: true
} %}
{% include 'lib/inputs/select.twig' with {
id: 'currency',
name: 'currency',
label: 'Currency',
options: [
{ value: 'cents', text: 'Cents' },
{ value: 'sats', text: 'Sats' }
],
required: true
} %}
{% include 'lib/buttons/submit.twig' with { {% include 'lib/buttons/submit.twig' with {
label: 'Submit', label: 'Create a New Transaction',
} %} } %}
</form> </a>
<h3 class="text-2xl font-semibold"> <h3 class="text-2xl font-semibold">
Liabilities Liabilities
</h3> </h3>