summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcflip <36554078+cflip@users.noreply.github.com>2021-08-11 16:29:51 -0600
committercflip <36554078+cflip@users.noreply.github.com>2021-08-11 16:29:51 -0600
commit946fd6a6c2f402bc8e663c2c9d41bbac25b49971 (patch)
tree1565fd3230dad24f6df90dc4e3e3d5101d1127b7
parent2458ca6964401c0bd2cd809d303dfbcaea3ead90 (diff)
Implement invite codes for user registration
-rw-r--r--includes/form/RegisterForm.php16
-rwxr-xr-xincludes/model/User.php60
-rw-r--r--meta/setup.sql2
-rwxr-xr-xregister.php12
-rwxr-xr-xviewuser.php113
5 files changed, 141 insertions, 62 deletions
diff --git a/includes/form/RegisterForm.php b/includes/form/RegisterForm.php
index 4967048..c1c1966 100644
--- a/includes/form/RegisterForm.php
+++ b/includes/form/RegisterForm.php
@@ -53,4 +53,20 @@ class RegisterForm extends Form
return $result;
}
+
+ public function validate_invite_code($invite_code): ?string
+ {
+ $result = null;
+
+ if (empty($invite_code)) {
+ $this->report_error("You need an invite code to register an account.");
+ } else {
+ $result = filter_var($invite_code, FILTER_SANITIZE_STRING);
+
+ if (!User::invite_code_exists($result)) {
+ $this->report_error("Your invite code is invalid.");
+ }
+ }
+ return $result;
+ }
}
diff --git a/includes/model/User.php b/includes/model/User.php
index e489edf..e497fc6 100755
--- a/includes/model/User.php
+++ b/includes/model/User.php
@@ -3,6 +3,18 @@ include_once './includes/Database.php';
const USER_LEVEL_MODERATOR = 'moderator';
+function generate_invite_code(): string
+{
+ $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+ $result = '';
+
+ for ($i = 0; $i < 8; $i++) {
+ $result .= $characters[rand(0, strlen($characters) - 1)];
+ }
+
+ return $result;
+}
+
class User
{
public $id;
@@ -10,14 +22,15 @@ class User
public $password;
public $date_registered;
public $level = 'user';
+ public $invite_code;
private $has_value = false;
// Can't use a constructor here because we have two possible ways to get the user from the database
- // and PHP does not allow function overloading.
+ // and PHP does not allow function overloading.
public function get_by_id($id)
{
- $sql = "SELECT user_name, user_date_registered, user_level, user_password FROM users WHERE user_id = ?;";
+ $sql = "SELECT user_name, user_password, user_date_registered, user_level, user_invite_code FROM users WHERE user_id = ?;";
$result = Database::get()->query($sql, "i", $id);
if (empty($result)) {
@@ -29,13 +42,15 @@ class User
$this->password = $result[0]['user_password'];
$this->date_registered = $result[0]['user_date_registered'];
$this->level = $result[0]['user_level'];
+ $this->invite_code = $result[0]['user_invite_code'];
$this->has_value = true;
}
+ // TODO: Duplicated code, there should be a common database read function for all models
public function get_by_name($name)
{
- $sql = "SELECT user_id, user_date_registered, user_level, user_password FROM users WHERE user_name = ?";
+ $sql = "SELECT user_id, user_password, user_date_registered, user_level, user_invite_code FROM users WHERE user_name = ?;";
$result = Database::get()->query($sql, "s", $name);
if (empty($result)) {
@@ -47,6 +62,26 @@ class User
$this->password = $result[0]['user_password'];
$this->date_registered = $result[0]['user_date_registered'];
$this->level = $result[0]['user_level'];
+ $this->invite_code = $result[0]['user_invite_code'];
+
+ $this->has_value = true;
+ }
+
+ public function get_by_invite_code($invite_code)
+ {
+ $sql = "SELECT user_id, user_name, user_password, user_date_registered, user_level FROM users WHERE user_invite_code = ?;";
+ $result = Database::get()->query($sql, "s", $invite_code);
+
+ if (empty($result)) {
+ return;
+ }
+
+ $this->id = $result[0]['user_id'];
+ $this->name = $result[0]['user_name'];
+ $this->password = $result[0]['user_password'];
+ $this->date_registered = $result[0]['user_date_registered'];
+ $this->level = $result[0]['user_level'];
+ $this->invite_code = $invite_code;
$this->has_value = true;
}
@@ -58,9 +93,16 @@ class User
public static function register(string $username, string $password)
{
- $sql = "INSERT INTO users(user_name, user_password, user_date_registered) VALUES(?, ?, NOW());";
+ $sql = "INSERT INTO users(user_name, user_password, user_date_registered, user_invite_code) VALUES(?, ?, NOW(), ?);";
$pass_hash = password_hash($password, PASSWORD_DEFAULT);
- Database::get()->query($sql, "ss", $username, $pass_hash);
+ $invite_code = generate_invite_code();
+ Database::get()->query($sql, "sss", $username, $pass_hash, $invite_code);
+ }
+
+ public function update_invite_code()
+ {
+ $sql = "UPDATE users SET user_invite_code = ? WHERE user_id = ?";
+ Database::get()->query($sql, "si", generate_invite_code(), $this->id);
}
public function change_password(string $pass_hash)
@@ -101,4 +143,12 @@ class User
return !empty($result);
}
+
+ public static function invite_code_exists($invite_code): bool
+ {
+ $sql = "SELECT * FROM users WHERE user_invite_code = ?;";
+ $result = Database::get()->query($sql, "s", $invite_code);
+
+ return !empty($result);
+ }
}
diff --git a/meta/setup.sql b/meta/setup.sql
index cb7df23..5d63ff7 100644
--- a/meta/setup.sql
+++ b/meta/setup.sql
@@ -4,7 +4,9 @@ CREATE TABLE users (
user_password VARCHAR(255) NOT NULL,
user_level ENUM('user', 'moderator', 'administrator') NOT NULL DEFAULT 'user',
user_date_registered DATETIME NOT NULL,
+ user_invite_code VARCHAR(8) NOT NULL,
UNIQUE INDEX user_name_unique (user_name),
+ UNIQUE INDEX user_invite_unique (user_invite_code),
PRIMARY KEY (user_id)
);
diff --git a/register.php b/register.php
index d7f5fed..44ab879 100755
--- a/register.php
+++ b/register.php
@@ -10,7 +10,9 @@
<h2>Register an account</h2>
<form action="register.php" method="post">
<label for="user_name">Username: </label><br>
- <input type="text" name="user_name"><br>
+ <input type="text" name="user_name" id="user_name"><br>
+ <label for="invite_code">Invite Code: </label><br>
+ <input type="text" name="invite_code" id="invite_code"><br>
<label for="user_pass">Password: </label><br>
<input type="password" name="user_pass"><br>
<label for="user_pass_check">Re-enter password: </label><br>
@@ -27,9 +29,15 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$form = new RegisterForm();
$username = $form->validate_username($_POST['user_pass']);
$password = $form->validate_password($_POST['user_pass'], $_POST['user_pass_check']);
+ $invite_code = $form->validate_invite_code($_POST['invite_code']);
- $form->on_success(function () use ($username, $password) {
+ $form->on_success(function () use ($username, $password, $invite_code) {
User::register($username, $password);
+
+ $inviter = new User();
+ $inviter->get_by_invite_code($invite_code);
+ $inviter->update_invite_code();
+
echo '<p class="success">Account successfully registered! You can now <a href="signin.php">sign in</a></p>';
});
}
diff --git a/viewuser.php b/viewuser.php
index 8d9c9c1..9a42467 100755
--- a/viewuser.php
+++ b/viewuser.php
@@ -1,55 +1,58 @@
-<?php
-include_once './includes/model/User.php';
-include_once './includes/model/Thread.php';
-
-if (!isset($_GET['id']) or !filter_var($_GET['id'], FILTER_VALIDATE_INT)) {
- http_response_code(404);
- include('includes/templates/404.php');
- die();
-}
-
-$current = new User();
-$current->get_by_id($_GET['id']);
-if (!$current->has_value()) {
- http_response_code(404);
- include('includes/templates/404.php');
- die();
-}
-?>
-<!DOCTYPE html>
-<html lang="en">
-<head>
- <title><?= $current->name; ?>'s Profile - cflip.net forum</title>
-<?php include_once 'includes/templates/head.php'; ?>
-</head>
-<body>
-<?php include_once "includes/templates/header.php" ?>
- <h1><?= $current->name; ?></h1>
- member since <?= date('M d, Y', strtotime($current->date_registered)); ?>
- <h2><?= $current->name; ?>'s Threads</h2>
- <table>
- <tr>
- <th>Thread</th>
- <th>Category</th>
- <th>Latest Post</th>
- </tr>
-<?php foreach ($current->get_threads() as $thread): ?>
- <tr>
- <td>
- <b><a href="viewthread.php?id=<?= $thread->id ?>"><?= $thread->subject ?></a></b>
- <small>on <?= date('M d, Y', strtotime($thread->date_created)); ?></small>
- </td>
- <td><a href="viewcategory.php?id=<?= $thread->category_id ?>"><?= $thread->get_parent_category()->name ?></a></td>
-<?php $latest_post = $thread->get_latest_post(); if ($latest_post->has_value()): ?>
- <td>
- <small>by <b><a href="viewuser.php?id=<?= $latest_post->author_id ?>"><?= $latest_post->get_author()->name ?></a></b>
- on <?= $latest_post->date_created ?></small>
- </td>
-<?php else: ?>
- <td>No posts yet!</td>
-<?php endif ?>
- </tr>
-<?php endforeach ?>
- </table>
-</body>
-</html>
+<?php
+include_once './includes/model/User.php';
+include_once './includes/model/Thread.php';
+
+if (!isset($_GET['id']) or !filter_var($_GET['id'], FILTER_VALIDATE_INT)) {
+ http_response_code(404);
+ include('includes/templates/404.php');
+ die();
+}
+
+$current = new User();
+$current->get_by_id($_GET['id']);
+if (!$current->has_value()) {
+ http_response_code(404);
+ include('includes/templates/404.php');
+ die();
+}
+?>
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <title><?= $current->name; ?>'s Profile - cflip.net forum</title>
+<?php include_once 'includes/templates/head.php'; ?>
+</head>
+<body>
+<?php include_once "includes/templates/header.php" ?>
+ <h1><?= $current->name; ?></h1>
+ member since <?= date('M d, Y', strtotime($current->date_registered)); ?>
+<?php if (Session::get()->is_signed_in() && Session::get()->get_current_user()->id == $current->id): ?>
+ <p>Your invite code is <em><?= $current->invite_code ?></em></p>
+<?php endif ?>
+ <h2><?= $current->name; ?>'s Threads</h2>
+ <table>
+ <tr>
+ <th>Thread</th>
+ <th>Category</th>
+ <th>Latest Post</th>
+ </tr>
+<?php foreach ($current->get_threads() as $thread): ?>
+ <tr>
+ <td>
+ <b><a href="viewthread.php?id=<?= $thread->id ?>"><?= $thread->subject ?></a></b>
+ <small>on <?= date('M d, Y', strtotime($thread->date_created)); ?></small>
+ </td>
+ <td><a href="viewcategory.php?id=<?= $thread->category_id ?>"><?= $thread->get_parent_category()->name ?></a></td>
+<?php $latest_post = $thread->get_latest_post(); if ($latest_post->has_value()): ?>
+ <td>
+ <small>by <b><a href="viewuser.php?id=<?= $latest_post->author_id ?>"><?= $latest_post->get_author()->name ?></a></b>
+ on <?= $latest_post->date_created ?></small>
+ </td>
+<?php else: ?>
+ <td>No posts yet!</td>
+<?php endif ?>
+ </tr>
+<?php endforeach ?>
+ </table>
+</body>
+</html>