From 946fd6a6c2f402bc8e663c2c9d41bbac25b49971 Mon Sep 17 00:00:00 2001 From: cflip <36554078+cflip@users.noreply.github.com> Date: Wed, 11 Aug 2021 16:29:51 -0600 Subject: Implement invite codes for user registration --- includes/form/RegisterForm.php | 16 ++++++ includes/model/User.php | 60 ++++++++++++++++++++-- meta/setup.sql | 2 + register.php | 12 ++++- viewuser.php | 113 +++++++++++++++++++++-------------------- 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 @@

Register an account


-
+
+
+



@@ -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 '

Account successfully registered! You can now sign in

'; }); } diff --git a/viewuser.php b/viewuser.php index 8d9c9c1..9a42467 100755 --- a/viewuser.php +++ b/viewuser.php @@ -1,55 +1,58 @@ -get_by_id($_GET['id']); -if (!$current->has_value()) { - http_response_code(404); - include('includes/templates/404.php'); - die(); -} -?> - - - - <?= $current->name; ?>'s Profile - cflip.net forum - - - - -

name; ?>

- member since date_registered)); ?> -

name; ?>'s Threads

- - - - - - -get_threads() as $thread): ?> - - - -get_latest_post(); if ($latest_post->has_value()): ?> - - - - - - -
ThreadCategoryLatest Post
- subject ?> - on date_created)); ?> - get_parent_category()->name ?> - by get_author()->name ?> - on date_created ?> - No posts yet!
- - +get_by_id($_GET['id']); +if (!$current->has_value()) { + http_response_code(404); + include('includes/templates/404.php'); + die(); +} +?> + + + + <?= $current->name; ?>'s Profile - cflip.net forum + + + + +

name; ?>

+ member since date_registered)); ?> +is_signed_in() && Session::get()->get_current_user()->id == $current->id): ?> +

Your invite code is invite_code ?>

+ +

name; ?>'s Threads

+ + + + + + +get_threads() as $thread): ?> + + + +get_latest_post(); if ($latest_post->has_value()): ?> + + + + + + +
ThreadCategoryLatest Post
+ subject ?> + on date_created)); ?> + get_parent_category()->name ?> + by get_author()->name ?> + on date_created ?> + No posts yet!
+ + -- cgit v1.2.3