Cleaned up UserController.

This commit is contained in:
Relintai 2022-07-22 12:09:00 +02:00
parent cf3c24381d
commit a94e95ce06
2 changed files with 105 additions and 191 deletions

View File

@ -1,30 +1,28 @@
#include "user_controller.h" #include "user_controller.h"
#include "web/html/form_validator.h" #include "../../singleton/user_db.h"
#include "web/html/html_builder.h" #include "../../users/user.h"
#include "web/http/cookie.h"
#include "web/http/http_session.h"
#include "web/http/request.h"
#include "web/http/session_manager.h"
#include "web/http/web_permission.h"
#include "database/database.h" #include "core/variant.h"
#include "database/database_manager.h" #include "modules/web/html/form_validator.h"
#include "database/query_builder.h" #include "modules/web/html/html_builder.h"
#include "database/query_result.h" #include "modules/web/http/http_server_enums.h"
#include "database/table_builder.h" #include "modules/web/http/http_session.h"
#include "modules/web/http/http_session_manager.h"
#include "modules/web/http/web_permission.h"
#include "modules/web/http/web_server.h"
#include "modules/web/http/web_server_cookie.h"
#include "modules/web/http/web_server_request.h"
#include "crypto/hash/sha256.h" void UserController::_handle_request_main(Ref<WebServerRequest> request) {
void UserController::handle_request_main(Request *request) {
if (_web_permission.is_valid()) { if (_web_permission.is_valid()) {
if (_web_permission->activate(request)) { if (_web_permission->activate(request)) {
return; return;
} }
} }
if (request->session.is_valid()) { if (request->get_session().is_valid()) {
Ref<User> u = request->reference_data["user"]; Ref<User> u = request->get_meta("user");
if (u.is_valid()) { if (u.is_valid()) {
handle_request(u, request); handle_request(u, request);
@ -33,7 +31,7 @@ void UserController::handle_request_main(Request *request) {
} }
} }
const String &segment = request->get_current_path_segment(); String segment = request->get_current_path_segment();
if (segment == "") { if (segment == "") {
handle_login_request_default(request); handle_login_request_default(request);
@ -52,14 +50,13 @@ void UserController::handle_request_main(Request *request) {
handle_login_request_default(request); handle_login_request_default(request);
} }
void UserController::handle_login_request_default(Request *request) { void UserController::handle_login_request_default(Ref<WebServerRequest> request) {
LoginRequestData data; LoginRequestData data;
if (request->get_method() == HTTP_METHOD_POST) { if (request->get_method() == HTTPServerEnums::HTTP_METHOD_POST) {
// this is probbaly not needed // this is probbaly not needed
// it's ok for now as I need to test the validators more // it's ok for now as I need to test the validators more
Vector<String> errors; PoolStringArray errors = _login_validator->validate(request);
_login_validator->validate(request, &errors);
for (int i = 0; i < errors.size(); ++i) { for (int i = 0; i < errors.size(); ++i) {
data.error_str += errors[i] + "<br>"; data.error_str += errors[i] + "<br>";
} }
@ -68,21 +65,21 @@ void UserController::handle_login_request_default(Request *request) {
data.uname_val = request->get_parameter("username"); data.uname_val = request->get_parameter("username");
data.pass_val = request->get_parameter("password"); data.pass_val = request->get_parameter("password");
Ref<User> user = db_get_user(data.uname_val); Ref<User> user = UserDB::get_singleton()->get_user_name(data.uname_val);
if (user.is_valid()) { if (user.is_valid()) {
if (!check_password(user, data.pass_val)) { if (!user->check_password(data.pass_val)) {
data.error_str += "Invalid username or password!"; data.error_str += "Invalid username or password!";
} else { } else {
Ref<HTTPSession> session = request->get_or_create_session(); Ref<HTTPSession> session = request->get_or_create_session();
session->add("user_id", user->id); session->add("user_id", user->get_user_id());
SessionManager::get_singleton()->save_session(session);
::Cookie c = ::Cookie("session_id", session->session_id); Ref<WebServerCookie> c;
c.path = "/"; c.instance();
c->set_data("session_id", session->session_id);
request->add_cookie(c); //c.path = "/";
request->response_add_cookie(c);
render_login_success(request); render_login_success(request);
@ -96,7 +93,7 @@ void UserController::handle_login_request_default(Request *request) {
render_login_request_default(request, &data); render_login_request_default(request, &data);
} }
void UserController::render_login_request_default(Request *request, LoginRequestData *data) { void UserController::render_login_request_default(Ref<WebServerRequest> request, LoginRequestData *data) {
HTMLBuilder b; HTMLBuilder b;
b.w("Login"); b.w("Login");
@ -117,7 +114,7 @@ void UserController::render_login_request_default(Request *request, LoginRequest
// todo href path helper // todo href path helper
b.form()->method("POST")->href("/user/login"); b.form()->method("POST")->href("/user/login");
{ {
b.csrf_token(request); b.csrf_tokenr(request);
b.w("Username"); b.w("Username");
b.br(); b.br();
@ -143,13 +140,11 @@ void UserController::render_login_request_default(Request *request, LoginRequest
request->compile_and_send_body(); request->compile_and_send_body();
} }
void UserController::handle_register_request_default(Request *request) { void UserController::handle_register_request_default(Ref<WebServerRequest> request) {
RegisterRequestData data; RegisterRequestData data;
if (request->get_method() == HTTP_METHOD_POST) { if (request->get_method() == HTTPServerEnums::HTTP_METHOD_POST) {
Vector<String> errors; PoolStringArray errors = _registration_validator->validate(request);
_registration_validator->validate(request, &errors);
for (int i = 0; i < errors.size(); ++i) { for (int i = 0; i < errors.size(); ++i) {
data.error_str += errors[i] + "<br>"; data.error_str += errors[i] + "<br>";
@ -163,11 +158,11 @@ void UserController::handle_register_request_default(Request *request) {
// todo username length etc check // todo username length etc check
// todo pw length etc check // todo pw length etc check
if (is_username_taken(data.uname_val)) { if (UserDB::get_singleton()->is_username_taken(data.uname_val)) {
data.error_str += "Username already taken!<br>"; data.error_str += "Username already taken!<br>";
} }
if (is_email_taken(data.email_val)) { if (UserDB::get_singleton()->is_email_taken(data.email_val)) {
data.error_str += "Email already in use!<br>"; data.error_str += "Email already in use!<br>";
} }
@ -177,13 +172,13 @@ void UserController::handle_register_request_default(Request *request) {
if (data.error_str.size() == 0) { if (data.error_str.size() == 0) {
Ref<User> user; Ref<User> user;
user = create_user(); user = UserDB::get_singleton()->create_user();
user->name_user_input = data.uname_val; user->set_user_name(data.uname_val);
user->email_user_input = data.email_val; user->set_email(data.email_val);
create_password(user, data.pass_val); user->create_password(data.pass_val);
db_save_user(user); user->save();
render_register_success(request); render_register_success(request);
return; return;
@ -193,7 +188,7 @@ void UserController::handle_register_request_default(Request *request) {
render_register_request_default(request, &data); render_register_request_default(request, &data);
} }
void UserController::render_register_success(Request *request) { void UserController::render_register_success(Ref<WebServerRequest> request) {
HTMLBuilder b; HTMLBuilder b;
b.div()->cls("success"); b.div()->cls("success");
@ -211,7 +206,7 @@ void UserController::render_register_success(Request *request) {
request->compile_and_send_body(); request->compile_and_send_body();
} }
void UserController::render_register_request_default(Request *request, RegisterRequestData *data) { void UserController::render_register_request_default(Ref<WebServerRequest> request, RegisterRequestData *data) {
HTMLBuilder b; HTMLBuilder b;
b.w("Registration"); b.w("Registration");
@ -232,7 +227,7 @@ void UserController::render_register_request_default(Request *request, RegisterR
// todo href path helper // todo href path helper
b.form()->method("POST")->href("/user/register"); b.form()->method("POST")->href("/user/register");
{ {
b.csrf_token(request); b.csrf_tokenr(request);
b.w("Username"); b.w("Username");
b.br(); b.br();
@ -270,20 +265,20 @@ void UserController::render_register_request_default(Request *request, RegisterR
request->compile_and_send_body(); request->compile_and_send_body();
} }
void UserController::render_already_logged_in_error(Request *request) { void UserController::render_already_logged_in_error(Ref<WebServerRequest> request) {
request->body += "You are already logged in."; request->body += "You are already logged in.";
request->compile_and_send_body(); request->compile_and_send_body();
} }
void UserController::render_login_success(Request *request) { void UserController::render_login_success(Ref<WebServerRequest> request) {
request->body = "Login Success!<br>"; request->body = "Login Success!<br>";
// request->compile_and_send_body(); // request->compile_and_send_body();
request->send_redirect("/user/settings"); request->send_redirect("/user/settings");
} }
void UserController::handle_request(Ref<User> &user, Request *request) { void UserController::handle_request(Ref<User> &user, Ref<WebServerRequest> request) {
const String &segment = request->get_current_path_segment(); const String &segment = request->get_current_path_segment();
if (segment == "") { if (segment == "") {
@ -305,16 +300,16 @@ void UserController::handle_request(Ref<User> &user, Request *request) {
} }
} }
void UserController::handle_main_page_request(Ref<User> &user, Request *request) { void UserController::handle_main_page_request(Ref<User> &user, Ref<WebServerRequest> request) {
request->body += "handle_main_page_request"; request->body += "handle_main_page_request";
request->compile_and_send_body(); request->compile_and_send_body();
} }
void UserController::handle_settings_request(Ref<User> &user, Request *request) { void UserController::handle_settings_request(Ref<User> &user, Ref<WebServerRequest> request) {
SettingsRequestData data; SettingsRequestData data;
if (request->get_method() == HTTP_METHOD_POST) { if (request->get_method() == HTTPServerEnums::HTTP_METHOD_POST) {
data.uname_val = request->get_parameter("username"); data.uname_val = request->get_parameter("username");
data.email_val = request->get_parameter("email"); data.email_val = request->get_parameter("email");
data.pass_val = request->get_parameter("password"); data.pass_val = request->get_parameter("password");
@ -322,41 +317,39 @@ void UserController::handle_settings_request(Ref<User> &user, Request *request)
bool changed = false; bool changed = false;
Vector<String> errors; PoolStringArray errors = _profile_validator->validate(request);
bool valid = _profile_validator->validate(request, &errors);
for (int i = 0; i < errors.size(); ++i) { for (int i = 0; i < errors.size(); ++i) {
data.error_str += errors[i] + "<br>"; data.error_str += errors[i] + "<br>";
} }
if (valid) { if (errors.size() == 0) {
if (data.uname_val == user->name_user_input) { if (data.uname_val == user->get_user_name()) {
data.uname_val = ""; data.uname_val = "";
} }
if (data.email_val == user->email_user_input) { if (data.email_val == user->get_email()) {
data.email_val = ""; data.email_val = "";
} }
if (data.uname_val != "") { if (data.uname_val != "") {
if (is_username_taken(data.uname_val)) { if (UserDB::get_singleton()->is_username_taken(data.uname_val)) {
data.error_str += "Username already taken!<br>"; data.error_str += "Username already taken!<br>";
} else { } else {
// todo sanitize for html special chars! // todo sanitize for html special chars!
user->name_user_input = data.uname_val; user->set_user_name(data.uname_val);
changed = true; changed = true;
data.uname_val = ""; data.uname_val = "";
} }
} }
if (data.email_val != "") { if (data.email_val != "") {
if (is_email_taken(data.email_val)) { if (UserDB::get_singleton()->is_email_taken(data.email_val)) {
data.error_str += "Email already in use!<br>"; data.error_str += "Email already in use!<br>";
} else { } else {
// todo sanitize for html special chars! // todo sanitize for html special chars!
// also send email // also send email
user->email_user_input = data.email_val; user->set_email(data.email_val);
changed = true; changed = true;
data.email_val = ""; data.email_val = "";
} }
@ -366,14 +359,14 @@ void UserController::handle_settings_request(Ref<User> &user, Request *request)
if (data.pass_val != data.pass_check_val) { if (data.pass_val != data.pass_check_val) {
data.error_str += "The passwords did not match!<br>"; data.error_str += "The passwords did not match!<br>";
} else { } else {
create_password(user, data.pass_val); user->create_password(data.pass_val);
changed = true; changed = true;
} }
} }
if (changed) { if (changed) {
db_save_user(user); user->save();
} }
} }
} }
@ -381,7 +374,7 @@ void UserController::handle_settings_request(Ref<User> &user, Request *request)
render_settings_request(user, request, &data); render_settings_request(user, request, &data);
} }
void UserController::render_settings_request(Ref<User> &user, Request *request, SettingsRequestData *data) { void UserController::render_settings_request(Ref<User> &user, Ref<WebServerRequest> request, SettingsRequestData *data) {
HTMLBuilder b; HTMLBuilder b;
b.w("Settings"); b.w("Settings");
@ -402,17 +395,17 @@ void UserController::render_settings_request(Ref<User> &user, Request *request,
// todo href path helper // todo href path helper
b.form()->method("POST")->href("/user/settings"); b.form()->method("POST")->href("/user/settings");
{ {
b.csrf_token(request); b.csrf_tokenr(request);
b.w("Username"); b.w("Username");
b.br(); b.br();
b.input()->type("text")->name("username")->placeholder(user->name_user_input)->value(data->uname_val); b.input()->type("text")->name("username")->placeholder(user->get_user_name())->value(data->uname_val);
b.cinput(); b.cinput();
b.br(); b.br();
b.w("Email"); b.w("Email");
b.br(); b.br();
b.input()->type("email")->name("email")->placeholder(user->email_user_input)->value(data->email_val); b.input()->type("email")->name("email")->placeholder(user->get_email())->value(data->email_val);
b.cinput(); b.cinput();
b.br(); b.br();
@ -440,19 +433,20 @@ void UserController::render_settings_request(Ref<User> &user, Request *request,
request->compile_and_send_body(); request->compile_and_send_body();
} }
void UserController::handle_password_reset_request(Ref<User> &user, Request *request) { void UserController::handle_password_reset_request(Ref<User> &user, Ref<WebServerRequest> request) {
request->body += "handle_password_reset_request"; request->body += "handle_password_reset_request";
request->compile_and_send_body(); request->compile_and_send_body();
} }
void UserController::handle_logout_request(Ref<User> &user, Request *request) { void UserController::handle_logout_request(Ref<User> &user, Ref<WebServerRequest> request) {
request->remove_cookie("session_id"); request->response_remove_cookie_simple("session_id");
db_save_user(user); user->save();
SessionManager::get_singleton()->delete_session(request->session->session_id); HTTPSessionManager *sess_man = request->get_server()->get_session_manager();
request->session = nullptr; sess_man->delete_session(request->get_session()->get_session_id());
request->set_session(Ref<HTTPSession>());
HTMLBuilder b; HTMLBuilder b;
b.w("Logout successful!"); b.w("Logout successful!");
@ -461,32 +455,32 @@ void UserController::handle_logout_request(Ref<User> &user, Request *request) {
request->compile_and_send_body(); request->compile_and_send_body();
} }
void UserController::handle_delete_request(Ref<User> &user, Request *request) { void UserController::handle_delete_request(Ref<User> &user, Ref<WebServerRequest> request) {
request->body += "handle_delete_request"; request->body += "handle_delete_request";
request->compile_and_send_body(); request->compile_and_send_body();
} }
void UserController::create_validators() { UserController::UserController() {
if (!_login_validator) { {
// Login // Login
_login_validator = new FormValidator(); _login_validator.instance();
_login_validator->new_field("username", "Username")->need_to_exist()->need_to_be_alpha_numeric()->need_minimum_length(5)->need_maximum_length(20); _login_validator->new_field("username", "Username")->need_to_exist()->need_to_be_alpha_numeric()->need_minimum_length(5)->need_maximum_length(20);
FormField *pw = _login_validator->new_field("password", "Password"); Ref<FormField> pw = _login_validator->new_field("password", "Password");
pw->need_to_exist(); pw->need_to_exist();
pw->need_to_have_lowercase_character()->need_to_have_uppercase_character(); pw->need_to_have_lowercase_character()->need_to_have_uppercase_character();
pw->need_minimum_length(5); pw->need_minimum_length(5);
} }
if (!_registration_validator) { {
// Registration // Registration
_registration_validator = new FormValidator(); _registration_validator.instance();
_registration_validator->new_field("username", "Username")->need_to_exist()->need_to_be_alpha_numeric()->need_minimum_length(5)->need_maximum_length(20); _registration_validator->new_field("username", "Username")->need_to_exist()->need_to_be_alpha_numeric()->need_minimum_length(5)->need_maximum_length(20);
_registration_validator->new_field("email", "Email")->need_to_exist()->need_to_be_email(); _registration_validator->new_field("email", "Email")->need_to_exist()->need_to_be_email();
FormField *pw = _registration_validator->new_field("password", "Password"); Ref<FormField> pw = _registration_validator->new_field("password", "Password");
pw->need_to_exist(); pw->need_to_exist();
pw->need_to_have_lowercase_character()->need_to_have_uppercase_character(); pw->need_to_have_lowercase_character()->need_to_have_uppercase_character();
pw->need_minimum_length(5); pw->need_minimum_length(5);
@ -496,13 +490,13 @@ void UserController::create_validators() {
_registration_validator->new_field("email", "Email")->need_to_exist()->need_to_be_email(); _registration_validator->new_field("email", "Email")->need_to_exist()->need_to_be_email();
} }
if (!_profile_validator) { {
_profile_validator = new FormValidator(); _profile_validator.instance();
_profile_validator->new_field("username", "Username")->ignore_if_not_exists()->need_to_be_alpha_numeric()->need_minimum_length(5)->need_maximum_length(20); _profile_validator->new_field("username", "Username")->ignore_if_not_exists()->need_to_be_alpha_numeric()->need_minimum_length(5)->need_maximum_length(20);
_profile_validator->new_field("email", "Email")->ignore_if_not_exists()->need_to_be_email(); _profile_validator->new_field("email", "Email")->ignore_if_not_exists()->need_to_be_email();
FormField *pw = _profile_validator->new_field("password", "Password"); Ref<FormField> pw = _profile_validator->new_field("password", "Password");
pw->ignore_if_not_exists(); pw->ignore_if_not_exists();
pw->need_to_have_lowercase_character()->need_to_have_uppercase_character(); pw->need_to_have_lowercase_character()->need_to_have_uppercase_character();
pw->need_minimum_length(5); pw->need_minimum_length(5);
@ -511,32 +505,5 @@ void UserController::create_validators() {
} }
} }
UserController *UserController::get_singleton() {
return _self;
}
UserController::UserController() :
WebNode() {
if (_self) {
printf("UserController::UserController(): Error! self is not null!/n");
}
_self = this;
create_validators();
}
UserController::~UserController() { UserController::~UserController() {
if (_self == this) {
_self = nullptr;
}
} }
UserController *UserController::_self = nullptr;
FormValidator *UserController::_login_validator = nullptr;
FormValidator *UserController::_registration_validator = nullptr;
FormValidator *UserController::_profile_validator = nullptr;
String UserController::_path = "./";
String UserController::_table_name = "users";

View File

@ -1,42 +1,21 @@
#ifndef USER_CONTROLLER_H #ifndef USER_CONTROLLER_H
#define USER_CONTROLLER_H #define USER_CONTROLLER_H
#include "core/containers/vector.h" #include "core/reference.h"
#include "core/string.h" #include "core/ustring.h"
#include "core/vector.h"
#include "web/http/web_node.h" #include "modules/web/http/web_node.h"
#include "user.h" class WebServerRequest;
#include "web/http/middleware.h"
class Request;
class FormValidator; class FormValidator;
class User;
//TODO
// Break this up into multiple small webnodes (per page)
// that would make this a lot more customizable
// Only User management, save, load etc should be kept here
// and this node should be expected to be autoloaded.
// It should keep get_singleton() and c++ stuff that deal with users should expect it's presence
// they should use err macros to not crash the app though
// Rename this UserManager
// Also users are useful for not just web stuff, so don't rename them
// Make this inherit from Node instead, only inherit the web user handling from webnodes.
// Also for other webnodes that have admin functionality, break those into separate nodes. It's a lot safer,
// and I think they will work better in this setting like this.
//Add a UserLevelWebPermission WebPermission. It should read a new projectsettings entry, and use it as an enum, that
// can be manipulated form the inspector.
// The RBAC system can probably be removed, as WebPermissions + the editor is a lot more powerful.
//Note move this with the user controller to it's own module.
class UserController : public WebNode { class UserController : public WebNode {
RCPP_OBJECT(UserController, WebNode); GDCLASS(UserController, WebNode);
public: public:
void handle_request_main(Request *request); void _handle_request_main(Ref<WebServerRequest> request);
struct LoginRequestData { struct LoginRequestData {
String error_str; String error_str;
@ -44,8 +23,8 @@ public:
String pass_val; String pass_val;
}; };
virtual void handle_login_request_default(Request *request); virtual void handle_login_request_default(Ref<WebServerRequest> request);
virtual void render_login_request_default(Request *request, LoginRequestData *data); virtual void render_login_request_default(Ref<WebServerRequest> request, LoginRequestData *data);
struct RegisterRequestData { struct RegisterRequestData {
String error_str; String error_str;
@ -55,15 +34,15 @@ public:
String pass_check_val; String pass_check_val;
}; };
virtual void handle_register_request_default(Request *request); virtual void handle_register_request_default(Ref<WebServerRequest> request);
virtual void render_register_request_default(Request *request, RegisterRequestData *data); virtual void render_register_request_default(Ref<WebServerRequest> request, RegisterRequestData *data);
virtual void render_register_success(Request *request); virtual void render_register_success(Ref<WebServerRequest> request);
virtual void render_already_logged_in_error(Request *request); virtual void render_already_logged_in_error(Ref<WebServerRequest> request);
virtual void render_login_success(Request *request); virtual void render_login_success(Ref<WebServerRequest> request);
virtual void handle_request(Ref<User> &user, Request *request); virtual void handle_request(Ref<User> &user, Ref<WebServerRequest> request);
virtual void handle_main_page_request(Ref<User> &user, Request *request); virtual void handle_main_page_request(Ref<User> &user, Ref<WebServerRequest> request);
struct SettingsRequestData { struct SettingsRequestData {
String error_str; String error_str;
@ -74,52 +53,20 @@ public:
String pass_check_val; String pass_check_val;
}; };
virtual void handle_settings_request(Ref<User> &user, Request *request); virtual void handle_settings_request(Ref<User> &user, Ref<WebServerRequest> request);
virtual void render_settings_request(Ref<User> &user, Request *request, SettingsRequestData *data); virtual void render_settings_request(Ref<User> &user, Ref<WebServerRequest> request, SettingsRequestData *data);
virtual void handle_password_reset_request(Ref<User> &user, Request *request); virtual void handle_password_reset_request(Ref<User> &user, Ref<WebServerRequest> request);
virtual void handle_logout_request(Ref<User> &user, Request *request); virtual void handle_logout_request(Ref<User> &user, Ref<WebServerRequest> request);
virtual void handle_delete_request(Ref<User> &user, Request *request); virtual void handle_delete_request(Ref<User> &user, Ref<WebServerRequest> request);
virtual void create_validators();
// db
virtual Ref<User> db_get_user(const int id);
virtual Ref<User> db_get_user(const String &user_name_input);
virtual void db_save_user(Ref<User> &user);
virtual Vector<Ref<User>> db_get_all();
virtual Ref<User> create_user();
bool is_username_taken(const String &user_name_input);
bool is_email_taken(const String &email_input);
virtual bool check_password(const Ref<User> &user, const String &p_password);
virtual void create_password(Ref<User> &user, const String &p_password);
virtual String hash_password(const Ref<User> &user, const String &p_password);
virtual void create_table();
virtual void drop_table();
virtual void create_default_entries();
static UserController *get_singleton();
UserController(); UserController();
~UserController(); ~UserController();
protected: protected:
static UserController *_self; Ref<FormValidator> _login_validator;
Ref<FormValidator> _registration_validator;
static FormValidator *_login_validator; Ref<FormValidator> _profile_validator;
static FormValidator *_registration_validator;
static FormValidator *_profile_validator;
String _file_path;
static String _path;
static String _table_name;
}; };
#endif #endif