mirror of
https://github.com/Fluffy-Bean/image-gallery.git
synced 2025-05-19 18:04:53 +00:00
Finalised Ban/Log system
This commit is contained in:
parent
6f39ca7759
commit
8d291d0c7d
2 changed files with 177 additions and 145 deletions
|
@ -72,7 +72,7 @@
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<h3>Bans/Timeouts</h3>
|
<h3>Bans</h3>
|
||||||
<div id="bans" class="bans">
|
<div id="bans" class="bans">
|
||||||
<?php
|
<?php
|
||||||
// Reading images from table
|
// Reading images from table
|
||||||
|
@ -88,7 +88,7 @@
|
||||||
<p><?php echo $ban['id']; ?></p>
|
<p><?php echo $ban['id']; ?></p>
|
||||||
<p><?php echo $ban['ipaddress']; ?></p>
|
<p><?php echo $ban['ipaddress']; ?></p>
|
||||||
<p><?php echo $ban['reason']; ?></p>
|
<p><?php echo $ban['reason']; ?></p>
|
||||||
<p><?php echo $ban['length']; ?></p>
|
<p><?php echo $ban['length']; ?> mins</p>
|
||||||
<?php
|
<?php
|
||||||
$log_time = new DateTime($ban['time']);
|
$log_time = new DateTime($ban['time']);
|
||||||
echo "<p>" . $log_time->format('d/m/Y H:i:s T') . "<br>" . $diff->time($ban['time']) . "</p>";
|
echo "<p>" . $log_time->format('d/m/Y H:i:s T') . "<br>" . $diff->time($ban['time']) . "</p>";
|
||||||
|
|
|
@ -19,20 +19,10 @@ $user_ip = $user_info->get_ip();
|
||||||
|-------------------------------------------------------------
|
|-------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
if (isset($_POST['submit_login'])) {
|
if (isset($_POST['submit_login'])) {
|
||||||
/*
|
|
||||||
|-------------------------------------------------------------
|
|
||||||
| Set error status to 0
|
|
||||||
|-------------------------------------------------------------
|
|
||||||
| if there are more than 0 error, then they cannot submit a
|
|
||||||
| request
|
|
||||||
|-------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
$error = 0;
|
$error = 0;
|
||||||
|
$ban_query = mysqli_query($conn, "SELECT * FROM bans WHERE ipaddress = '$user_ip' ORDER BY id DESC LIMIT 1");
|
||||||
|
|
||||||
$sql = "SELECT * FROM bans WHERE ipaddress = '$user_ip' ORDER BY id DESC LIMIT 1";
|
while ($ban_check = mysqli_fetch_assoc($ban_query)) {
|
||||||
$query = mysqli_query($conn, $sql);
|
|
||||||
|
|
||||||
while ($ban_check = mysqli_fetch_assoc($query)) {
|
|
||||||
$ban_time = $ban_check['time'];
|
$ban_time = $ban_check['time'];
|
||||||
$ban_perm = $ban_check['permanent'];
|
$ban_perm = $ban_check['permanent'];
|
||||||
}
|
}
|
||||||
|
@ -45,55 +35,60 @@ if (isset($_POST['submit_login'])) {
|
||||||
sniffleAdd('Bye bye!', 'You have been banned, contact the owner if you feel that this was a mistake', 'var(--red)', 'assets/icons/warning.svg');
|
sniffleAdd('Bye bye!', 'You have been banned, contact the owner if you feel that this was a mistake', 'var(--red)', 'assets/icons/warning.svg');
|
||||||
</script>
|
</script>
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
$error += 1;
|
$error += 1;
|
||||||
} elseif (($ban_diff / 60) <= 60) {
|
} elseif (($ban_diff / 60) <= 60) {
|
||||||
?>
|
?>
|
||||||
<script>
|
<script>
|
||||||
sniffleAdd('Slow down!', 'You have attempted to login too many times in the last 10 minutes. Come back in <?php echo round(60-($ban_diff/60)); ?> minutes', 'var(--red)', 'assets/icons/warning.svg');
|
sniffleAdd('Slow down!', 'You have attempted to login/signup too many times in 10 minutes. Come back in <?php echo round(60-($ban_diff/60)); ?> minutes', 'var(--red)', 'assets/icons/warning.svg');
|
||||||
</script>
|
</script>
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
$error += 1;
|
$error += 1;
|
||||||
} else {
|
} else {
|
||||||
$attemps = 0;
|
$attemps = 0;
|
||||||
|
$log_query = mysqli_query($conn, "SELECT * FROM logs WHERE ipaddress = '$user_ip' ORDER BY id DESC LIMIT 5");
|
||||||
|
|
||||||
$sql = "SELECT * FROM logs WHERE ipaddress = '$user_ip' ORDER BY id DESC LIMIT 5";
|
while ($log_array = mysqli_fetch_assoc($log_query)) {
|
||||||
$query = mysqli_query($conn, $sql);
|
|
||||||
|
|
||||||
while ($log_array = mysqli_fetch_assoc($query)) {
|
|
||||||
$log_diff = time() - strtotime($log_array['time']);
|
$log_diff = time() - strtotime($log_array['time']);
|
||||||
if ($log_array['action'] == 'Failed to enter correct Password' && ($log_diff / 60) <= 10 ) {
|
|
||||||
|
if ($log_array['action'] == 'Failed to enter correct Password' && ($log_diff / 60) <= 10) {
|
||||||
|
$attemps += 1;
|
||||||
|
} elseif ($log_array['action'] == 'Failed to enter correct Invite Code' && ($log_diff / 60) <= 10) {
|
||||||
$attemps += 1;
|
$attemps += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($attemps >= 5) {
|
if ($attemps >= 5) {
|
||||||
mysqli_query($conn,"INSERT INTO bans (ipaddress, reason, length, permanent) VALUES('$user_ip','Attempted password too many times', '60', '0')");
|
mysqli_query($conn,"INSERT INTO bans (ipaddress, reason, length, permanent) VALUES('$user_ip','Attempted password too many times', '60', '0')");
|
||||||
} else {
|
|
||||||
// Checking if Username is empty
|
|
||||||
if (empty(trim($_POST["username"]))) {
|
|
||||||
?>
|
|
||||||
<script>
|
|
||||||
sniffleAdd('Who dis?', 'You must enter a username to login!', 'var(--red)', 'assets/icons/cross.svg');
|
|
||||||
</script>
|
|
||||||
<?php
|
|
||||||
$error += 1;
|
|
||||||
} else {
|
|
||||||
$username = trim($_POST["username"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if Password is empty
|
|
||||||
if (empty(trim($_POST["password"]))) {
|
|
||||||
?>
|
|
||||||
<script>
|
|
||||||
sniffleAdd('Whats the magic word?', 'Pls enter the super duper secrete word(s) to login!', 'var(--red)', 'assets/icons/cross.svg');
|
|
||||||
</script>
|
|
||||||
<?php
|
|
||||||
$error += 1;
|
|
||||||
} else {
|
|
||||||
$password = trim($_POST["password"]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($error <= 0) {
|
||||||
|
// Checking if Username is empty
|
||||||
|
if (empty(trim($_POST["username"]))) {
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
sniffleAdd('Who dis?', 'You must enter a username to login!', 'var(--red)', 'assets/icons/cross.svg');
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
$error += 1;
|
||||||
|
} else {
|
||||||
|
$username = trim($_POST["username"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if Password is empty
|
||||||
|
if (empty(trim($_POST["password"]))) {
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
sniffleAdd('Whats the magic word?', 'Pls enter the super duper secrete word(s) to login!', 'var(--red)', 'assets/icons/cross.svg');
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
$error += 1;
|
||||||
|
} else {
|
||||||
|
$password = trim($_POST["password"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($error <= 0) {
|
if ($error <= 0) {
|
||||||
// Prepare so SQL doesnt get spooked
|
// Prepare so SQL doesnt get spooked
|
||||||
|
@ -174,149 +169,96 @@ if (isset($_POST['submit_login'])) {
|
||||||
|-------------------------------------------------------------
|
|-------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
if (isset($_POST['submit_signup'])) {
|
if (isset($_POST['submit_signup'])) {
|
||||||
/*
|
|
||||||
|-------------------------------------------------------------
|
|
||||||
| Set error status to 0
|
|
||||||
|-------------------------------------------------------------
|
|
||||||
| if there are more than 0 error, then they cannot submit a
|
|
||||||
| request
|
|
||||||
|-------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
$error = 0;
|
$error = 0;
|
||||||
|
$ban_query = mysqli_query($conn, "SELECT * FROM bans WHERE ipaddress = '$user_ip' ORDER BY id DESC LIMIT 1");
|
||||||
|
|
||||||
if (empty(trim($_POST["username"]))) {
|
while ($ban_check = mysqli_fetch_assoc($ban_query)) {
|
||||||
// Username not entered
|
$ban_time = $ban_check['time'];
|
||||||
|
$ban_perm = $ban_check['permanent'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$ban_diff = time() - strtotime($ban_time);
|
||||||
|
|
||||||
|
if ($ban_perm) {
|
||||||
?>
|
?>
|
||||||
<script>
|
<script>
|
||||||
sniffleAdd('Hmmm', 'You must enter a username!', 'var(--red)', 'assets/icons/cross.svg');
|
sniffleAdd('Bye bye!', 'You have been banned, contact the owner if you feel that this was a mistake', 'var(--red)', 'assets/icons/warning.svg');
|
||||||
</script>
|
</script>
|
||||||
<?php
|
<?php
|
||||||
$error = $error + 1;
|
|
||||||
} elseif (!preg_match('/^[a-zA-Z0-9_]+$/', trim($_POST["username"]))) {
|
$error += 1;
|
||||||
// Username entered contains illegal characters
|
} elseif (($ban_diff / 60) <= 60) {
|
||||||
?>
|
?>
|
||||||
<script>
|
<script>
|
||||||
sniffleAdd('Sussy Wussy', 'Very sus. Username can only contain letters, numbers, and underscores', 'var(--red)', 'assets/icons/cross.svg');
|
sniffleAdd('Slow down!', 'You have attempted to login/signup too many times in 10 minutes. Come back in <?php echo round(60-($ban_diff/60)); ?> minutes', 'var(--red)', 'assets/icons/warning.svg');
|
||||||
</script>
|
</script>
|
||||||
<?php
|
<?php
|
||||||
$error = $error + 1;
|
|
||||||
|
$error += 1;
|
||||||
} else {
|
} else {
|
||||||
// Prepare sql for sus
|
$attemps = 0;
|
||||||
$sql = "SELECT id FROM users WHERE username = ?";
|
$log_query = mysqli_query($conn, "SELECT * FROM logs WHERE ipaddress = '$user_ip' ORDER BY id DESC LIMIT 5");
|
||||||
|
|
||||||
if ($stmt = mysqli_prepare($conn, $sql)) {
|
while ($log_array = mysqli_fetch_assoc($log_query)) {
|
||||||
mysqli_stmt_bind_param($stmt, "s", $username_request);
|
$log_diff = time() - strtotime($log_array['time']);
|
||||||
|
|
||||||
$username_request = trim($_POST["username"]);
|
if ($log_array['action'] == 'Failed to enter correct Password' && ($log_diff / 60) <= 10) {
|
||||||
|
$attemps += 1;
|
||||||
if (mysqli_stmt_execute($stmt)) {
|
} elseif ($log_array['action'] == 'Failed to enter correct Invite Code' && ($log_diff / 60) <= 10) {
|
||||||
// Ask sql nicely if other usernames exist and store info
|
$attemps += 1;
|
||||||
mysqli_stmt_store_result($stmt);
|
|
||||||
|
|
||||||
if (mysqli_stmt_num_rows($stmt) == 1) {
|
|
||||||
// Username taken
|
|
||||||
?>
|
|
||||||
<script>
|
|
||||||
sniffleAdd('A clone?', 'Sorry, but username was already taken by someone else', 'var(--red)', 'assets/icons/cross.svg');
|
|
||||||
</script>
|
|
||||||
<?php
|
|
||||||
$error = $error + 1;
|
|
||||||
} else {
|
|
||||||
$username = trim($_POST["username"]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
?>
|
|
||||||
<script>
|
|
||||||
sniffleAdd('Reee', 'We had a problem on our end, sowwy', 'var(--red)', 'assets/icons/cross.svg');
|
|
||||||
</script>
|
|
||||||
<?php
|
|
||||||
$error = $error + 1;
|
|
||||||
}
|
}
|
||||||
// Outa here with this
|
}
|
||||||
mysqli_stmt_close($stmt);
|
|
||||||
|
if ($attemps >= 5) {
|
||||||
|
mysqli_query($conn,"INSERT INTO bans (ipaddress, reason, length, permanent) VALUES('$user_ip','Attempted password too many times', '60', '0')");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate sussness of Password
|
if ($error <= 0) {
|
||||||
if (empty(trim($_POST["password"]))) {
|
if (empty(trim($_POST["username"]))) {
|
||||||
// No password entered
|
// Username not entered
|
||||||
?>
|
|
||||||
<script>
|
|
||||||
sniffleAdd('What', 'You must enter a password, dont want just anyone seeing your stuff uwu', 'var(--red)', 'assets/icons/cross.svg');
|
|
||||||
</script>
|
|
||||||
<?php
|
|
||||||
$error = $error + 1;
|
|
||||||
} elseif(strlen(trim($_POST["password"])) < 6){
|
|
||||||
// Password not long enough 👀
|
|
||||||
?>
|
|
||||||
<script>
|
|
||||||
sniffleAdd('👀', 'Nice (Password) but its not long enough 👀', 'var(--red)', 'assets/icons/cross.svg');
|
|
||||||
</script>
|
|
||||||
<?php
|
|
||||||
$error = $error + 1;
|
|
||||||
} else {
|
|
||||||
$password = trim($_POST["password"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate sussiness of the other Password
|
|
||||||
if (empty(trim($_POST["confirm_password"]))) {
|
|
||||||
// Did not confirm passowrd
|
|
||||||
?>
|
|
||||||
<script>
|
|
||||||
sniffleAdd('Eh?', 'Confirm the password pls, its very important you remember what it issss', 'var(--red)', 'assets/icons/cross.svg');
|
|
||||||
</script>
|
|
||||||
<?php
|
|
||||||
$error = $error + 1;
|
|
||||||
} else {
|
|
||||||
$confirm_password = trim($_POST["confirm_password"]);
|
|
||||||
if (empty($error) && $confirm_password != $password) {
|
|
||||||
// Password and re-entered Password does not match
|
|
||||||
?>
|
?>
|
||||||
<script>
|
<script>
|
||||||
sniffleAdd('Try again', 'Passwords need to be the same, smelly smelly', 'var(--red)', 'assets/icons/cross.svg');
|
sniffleAdd('Hmmm', 'You must enter a username!', 'var(--red)', 'assets/icons/cross.svg');
|
||||||
</script>
|
</script>
|
||||||
<?php
|
<?php
|
||||||
$error = $error + 1;
|
$error = $error + 1;
|
||||||
}
|
} elseif (!preg_match('/^[a-zA-Z0-9_]+$/', trim($_POST["username"]))) {
|
||||||
}
|
// Username entered contains illegal characters
|
||||||
|
|
||||||
// Check for invite code
|
|
||||||
if (isset($_POST['token'])) {
|
|
||||||
// Check if invite code is empty
|
|
||||||
if (empty($_POST['token'])) {
|
|
||||||
?>
|
?>
|
||||||
<script>
|
<script>
|
||||||
sniffleAdd('smelly', 'Enter Invite Code ;3', 'var(--red)', 'assets/icons/cross.svg');
|
sniffleAdd('Sussy Wussy', 'Very sus. Username can only contain letters, numbers, and underscores', 'var(--red)', 'assets/icons/cross.svg');
|
||||||
</script>
|
</script>
|
||||||
<?php
|
<?php
|
||||||
mysqli_query($conn,"INSERT INTO logs (ipaddress, action) VALUES('$user_ip','Failed to enter correct Invite Code')");
|
|
||||||
$error = $error + 1;
|
$error = $error + 1;
|
||||||
} else {
|
} else {
|
||||||
// Prepare sql for sus
|
// Prepare sql for sus
|
||||||
$sql = "SELECT id FROM tokens WHERE code = ? AND used = 0";
|
$sql = "SELECT id FROM users WHERE username = ?";
|
||||||
|
|
||||||
if ($stmt = mysqli_prepare($conn, $sql)) {
|
if ($stmt = mysqli_prepare($conn, $sql)) {
|
||||||
mysqli_stmt_bind_param($stmt, "s", $param_code);
|
mysqli_stmt_bind_param($stmt, "s", $username_request);
|
||||||
|
|
||||||
$param_code = $_POST['token'];
|
$username_request = trim($_POST["username"]);
|
||||||
|
|
||||||
// Ask sql nicely if other usernames exist and store info
|
|
||||||
if (mysqli_stmt_execute($stmt)) {
|
if (mysqli_stmt_execute($stmt)) {
|
||||||
|
// Ask sql nicely if other usernames exist and store info
|
||||||
mysqli_stmt_store_result($stmt);
|
mysqli_stmt_store_result($stmt);
|
||||||
|
|
||||||
if (mysqli_stmt_num_rows($stmt) == 1) {
|
if (mysqli_stmt_num_rows($stmt) == 1) {
|
||||||
$token = trim($_POST["token"]);
|
// Username taken
|
||||||
} else {
|
|
||||||
?>
|
?>
|
||||||
<script>
|
<script>
|
||||||
sniffleAdd('Argh', 'Your invite code/token did not check out, woopsie!', 'var(--red)', 'assets/icons/cross.svg');
|
sniffleAdd('A clone?', 'Sorry, but username was already taken by someone else', 'var(--red)', 'assets/icons/cross.svg');
|
||||||
</script>
|
</script>
|
||||||
<?php
|
<?php
|
||||||
$error = $error + 1;
|
$error = $error + 1;
|
||||||
|
} else {
|
||||||
|
$username = trim($_POST["username"]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
?>
|
?>
|
||||||
<script>
|
<script>
|
||||||
sniffleAdd('Woops', 'The server or website died inside and could not process your information, sowwy!', 'var(--red)', 'assets/icons/cross.svg');
|
sniffleAdd('Reee', 'We had a problem on our end, sowwy', 'var(--red)', 'assets/icons/cross.svg');
|
||||||
</script>
|
</script>
|
||||||
<?php
|
<?php
|
||||||
$error = $error + 1;
|
$error = $error + 1;
|
||||||
|
@ -325,6 +267,96 @@ if (isset($_POST['submit_signup'])) {
|
||||||
mysqli_stmt_close($stmt);
|
mysqli_stmt_close($stmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate sussness of Password
|
||||||
|
if (empty(trim($_POST["password"]))) {
|
||||||
|
// No password entered
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
sniffleAdd('What', 'You must enter a password, dont want just anyone seeing your stuff uwu', 'var(--red)', 'assets/icons/cross.svg');
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
$error = $error + 1;
|
||||||
|
} elseif(strlen(trim($_POST["password"])) < 6){
|
||||||
|
// Password not long enough 👀
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
sniffleAdd('👀', 'Nice (Password) but its not long enough 👀', 'var(--red)', 'assets/icons/cross.svg');
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
$error = $error + 1;
|
||||||
|
} else {
|
||||||
|
$password = trim($_POST["password"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate sussiness of the other Password
|
||||||
|
if (empty(trim($_POST["confirm_password"]))) {
|
||||||
|
// Did not confirm passowrd
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
sniffleAdd('Eh?', 'Confirm the password pls, its very important you remember what it issss', 'var(--red)', 'assets/icons/cross.svg');
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
$error = $error + 1;
|
||||||
|
} else {
|
||||||
|
$confirm_password = trim($_POST["confirm_password"]);
|
||||||
|
if (empty($error) && $confirm_password != $password) {
|
||||||
|
// Password and re-entered Password does not match
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
sniffleAdd('Try again', 'Passwords need to be the same, smelly smelly', 'var(--red)', 'assets/icons/cross.svg');
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
$error = $error + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for invite code
|
||||||
|
if (isset($_POST['token'])) {
|
||||||
|
// Check if invite code is empty
|
||||||
|
if (empty($_POST['token'])) {
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
sniffleAdd('smelly', 'Enter Invite Code ;3', 'var(--red)', 'assets/icons/cross.svg');
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
mysqli_query($conn,"INSERT INTO logs (ipaddress, action) VALUES('$user_ip','Failed to enter correct Invite Code')");
|
||||||
|
$error = $error + 1;
|
||||||
|
} else {
|
||||||
|
// Prepare sql for sus
|
||||||
|
$sql = "SELECT id FROM tokens WHERE code = ? AND used = 0";
|
||||||
|
|
||||||
|
if ($stmt = mysqli_prepare($conn, $sql)) {
|
||||||
|
mysqli_stmt_bind_param($stmt, "s", $param_code);
|
||||||
|
|
||||||
|
$param_code = $_POST['token'];
|
||||||
|
|
||||||
|
// Ask sql nicely if other usernames exist and store info
|
||||||
|
if (mysqli_stmt_execute($stmt)) {
|
||||||
|
mysqli_stmt_store_result($stmt);
|
||||||
|
if (mysqli_stmt_num_rows($stmt) == 1) {
|
||||||
|
$token = trim($_POST["token"]);
|
||||||
|
} else {
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
sniffleAdd('Argh', 'Your invite code/token did not check out, woopsie!', 'var(--red)', 'assets/icons/cross.svg');
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
$error = $error + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
sniffleAdd('Woops', 'The server or website died inside and could not process your information, sowwy!', 'var(--red)', 'assets/icons/cross.svg');
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
$error = $error + 1;
|
||||||
|
}
|
||||||
|
// Outa here with this
|
||||||
|
mysqli_stmt_close($stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checking for errors
|
// Checking for errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue