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 "web/html/form_validator.h"
#include "web/html/html_builder.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 "../../singleton/user_db.h"
#include "../../users/user.h"
#include "database/database.h"
#include "database/database_manager.h"
#include "database/query_builder.h"
#include "database/query_result.h"
#include "database/table_builder.h"
#include "core/variant.h"
#include "modules/web/html/form_validator.h"
#include "modules/web/html/html_builder.h"
#include "modules/web/http/http_server_enums.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(Request *request) {
void UserController::_handle_request_main(Ref<WebServerRequest> request) {
if (_web_permission.is_valid()) {
if (_web_permission->activate(request)) {
return;
}
}
if (request->session.is_valid()) {
Ref<User> u = request->reference_data["user"];
if (request->get_session().is_valid()) {
Ref<User> u = request->get_meta("user");
if (u.is_valid()) {
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 == "") {
handle_login_request_default(request);
@ -52,14 +50,13 @@ void UserController::handle_request_main(Request *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;
if (request->get_method() == HTTP_METHOD_POST) {
if (request->get_method() == HTTPServerEnums::HTTP_METHOD_POST) {
// this is probbaly not needed
// it's ok for now as I need to test the validators more
Vector<String> errors;
_login_validator->validate(request, &errors);
PoolStringArray errors = _login_validator->validate(request);
for (int i = 0; i < errors.size(); ++i) {
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.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 (!check_password(user, data.pass_val)) {
if (!user->check_password(data.pass_val)) {
data.error_str += "Invalid username or password!";
} else {
Ref<HTTPSession> session = request->get_or_create_session();
session->add("user_id", user->id);
SessionManager::get_singleton()->save_session(session);
session->add("user_id", user->get_user_id());
::Cookie c = ::Cookie("session_id", session->session_id);
c.path = "/";
request->add_cookie(c);
Ref<WebServerCookie> c;
c.instance();
c->set_data("session_id", session->session_id);
//c.path = "/";
request->response_add_cookie(c);
render_login_success(request);
@ -96,7 +93,7 @@ void UserController::handle_login_request_default(Request *request) {
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;
b.w("Login");
@ -117,7 +114,7 @@ void UserController::render_login_request_default(Request *request, LoginRequest
// todo href path helper
b.form()->method("POST")->href("/user/login");
{
b.csrf_token(request);
b.csrf_tokenr(request);
b.w("Username");
b.br();
@ -143,13 +140,11 @@ void UserController::render_login_request_default(Request *request, LoginRequest
request->compile_and_send_body();
}
void UserController::handle_register_request_default(Request *request) {
void UserController::handle_register_request_default(Ref<WebServerRequest> request) {
RegisterRequestData data;
if (request->get_method() == HTTP_METHOD_POST) {
Vector<String> errors;
_registration_validator->validate(request, &errors);
if (request->get_method() == HTTPServerEnums::HTTP_METHOD_POST) {
PoolStringArray errors = _registration_validator->validate(request);
for (int i = 0; i < errors.size(); ++i) {
data.error_str += errors[i] + "<br>";
@ -163,11 +158,11 @@ void UserController::handle_register_request_default(Request *request) {
// todo username 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>";
}
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>";
}
@ -177,13 +172,13 @@ void UserController::handle_register_request_default(Request *request) {
if (data.error_str.size() == 0) {
Ref<User> user;
user = create_user();
user = UserDB::get_singleton()->create_user();
user->name_user_input = data.uname_val;
user->email_user_input = data.email_val;
user->set_user_name(data.uname_val);
user->set_email(data.email_val);
create_password(user, data.pass_val);
db_save_user(user);
user->create_password(data.pass_val);
user->save();
render_register_success(request);
return;
@ -193,7 +188,7 @@ void UserController::handle_register_request_default(Request *request) {
render_register_request_default(request, &data);
}
void UserController::render_register_success(Request *request) {
void UserController::render_register_success(Ref<WebServerRequest> request) {
HTMLBuilder b;
b.div()->cls("success");
@ -211,7 +206,7 @@ void UserController::render_register_success(Request *request) {
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;
b.w("Registration");
@ -232,7 +227,7 @@ void UserController::render_register_request_default(Request *request, RegisterR
// todo href path helper
b.form()->method("POST")->href("/user/register");
{
b.csrf_token(request);
b.csrf_tokenr(request);
b.w("Username");
b.br();
@ -270,20 +265,20 @@ void UserController::render_register_request_default(Request *request, RegisterR
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->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->compile_and_send_body();
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();
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->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;
if (request->get_method() == HTTP_METHOD_POST) {
if (request->get_method() == HTTPServerEnums::HTTP_METHOD_POST) {
data.uname_val = request->get_parameter("username");
data.email_val = request->get_parameter("email");
data.pass_val = request->get_parameter("password");
@ -322,41 +317,39 @@ void UserController::handle_settings_request(Ref<User> &user, Request *request)
bool changed = false;
Vector<String> errors;
bool valid = _profile_validator->validate(request, &errors);
PoolStringArray errors = _profile_validator->validate(request);
for (int i = 0; i < errors.size(); ++i) {
data.error_str += errors[i] + "<br>";
}
if (valid) {
if (data.uname_val == user->name_user_input) {
if (errors.size() == 0) {
if (data.uname_val == user->get_user_name()) {
data.uname_val = "";
}
if (data.email_val == user->email_user_input) {
if (data.email_val == user->get_email()) {
data.email_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>";
} else {
// todo sanitize for html special chars!
user->name_user_input = data.uname_val;
user->set_user_name(data.uname_val);
changed = true;
data.uname_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>";
} else {
// todo sanitize for html special chars!
// also send email
user->email_user_input = data.email_val;
user->set_email(data.email_val);
changed = true;
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) {
data.error_str += "The passwords did not match!<br>";
} else {
create_password(user, data.pass_val);
user->create_password(data.pass_val);
changed = true;
}
}
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);
}
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;
b.w("Settings");
@ -402,17 +395,17 @@ void UserController::render_settings_request(Ref<User> &user, Request *request,
// todo href path helper
b.form()->method("POST")->href("/user/settings");
{
b.csrf_token(request);
b.csrf_tokenr(request);
b.w("Username");
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.br();
b.w("Email");
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.br();
@ -440,19 +433,20 @@ void UserController::render_settings_request(Ref<User> &user, Request *request,
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->compile_and_send_body();
}
void UserController::handle_logout_request(Ref<User> &user, Request *request) {
request->remove_cookie("session_id");
void UserController::handle_logout_request(Ref<User> &user, Ref<WebServerRequest> request) {
request->response_remove_cookie_simple("session_id");
db_save_user(user);
user->save();
SessionManager::get_singleton()->delete_session(request->session->session_id);
request->session = nullptr;
HTTPSessionManager *sess_man = request->get_server()->get_session_manager();
sess_man->delete_session(request->get_session()->get_session_id());
request->set_session(Ref<HTTPSession>());
HTMLBuilder b;
b.w("Logout successful!");
@ -461,32 +455,32 @@ void UserController::handle_logout_request(Ref<User> &user, Request *request) {
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->compile_and_send_body();
}
void UserController::create_validators() {
if (!_login_validator) {
UserController::UserController() {
{
// 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);
FormField *pw = _login_validator->new_field("password", "Password");
Ref<FormField> pw = _login_validator->new_field("password", "Password");
pw->need_to_exist();
pw->need_to_have_lowercase_character()->need_to_have_uppercase_character();
pw->need_minimum_length(5);
}
if (!_registration_validator) {
{
// 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("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_have_lowercase_character()->need_to_have_uppercase_character();
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();
}
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("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->need_to_have_lowercase_character()->need_to_have_uppercase_character();
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() {
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
#define USER_CONTROLLER_H
#include "core/containers/vector.h"
#include "core/string.h"
#include "core/reference.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"
#include "web/http/middleware.h"
class Request;
class WebServerRequest;
class FormValidator;
//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 User;
class UserController : public WebNode {
RCPP_OBJECT(UserController, WebNode);
GDCLASS(UserController, WebNode);
public:
void handle_request_main(Request *request);
void _handle_request_main(Ref<WebServerRequest> request);
struct LoginRequestData {
String error_str;
@ -44,8 +23,8 @@ public:
String pass_val;
};
virtual void handle_login_request_default(Request *request);
virtual void render_login_request_default(Request *request, LoginRequestData *data);
virtual void handle_login_request_default(Ref<WebServerRequest> request);
virtual void render_login_request_default(Ref<WebServerRequest> request, LoginRequestData *data);
struct RegisterRequestData {
String error_str;
@ -55,15 +34,15 @@ public:
String pass_check_val;
};
virtual void handle_register_request_default(Request *request);
virtual void render_register_request_default(Request *request, RegisterRequestData *data);
virtual void render_register_success(Request *request);
virtual void handle_register_request_default(Ref<WebServerRequest> request);
virtual void render_register_request_default(Ref<WebServerRequest> request, RegisterRequestData *data);
virtual void render_register_success(Ref<WebServerRequest> request);
virtual void render_already_logged_in_error(Request *request);
virtual void render_login_success(Request *request);
virtual void render_already_logged_in_error(Ref<WebServerRequest> request);
virtual void render_login_success(Ref<WebServerRequest> request);
virtual void handle_request(Ref<User> &user, Request *request);
virtual void handle_main_page_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, Ref<WebServerRequest> request);
struct SettingsRequestData {
String error_str;
@ -74,52 +53,20 @@ public:
String pass_check_val;
};
virtual void handle_settings_request(Ref<User> &user, Request *request);
virtual void render_settings_request(Ref<User> &user, Request *request, SettingsRequestData *data);
virtual void handle_settings_request(Ref<User> &user, Ref<WebServerRequest> request);
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_logout_request(Ref<User> &user, Request *request);
virtual void handle_delete_request(Ref<User> &user, Request *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();
virtual void handle_password_reset_request(Ref<User> &user, Ref<WebServerRequest> request);
virtual void handle_logout_request(Ref<User> &user, Ref<WebServerRequest> request);
virtual void handle_delete_request(Ref<User> &user, Ref<WebServerRequest> request);
UserController();
~UserController();
protected:
static UserController *_self;
static FormValidator *_login_validator;
static FormValidator *_registration_validator;
static FormValidator *_profile_validator;
String _file_path;
static String _path;
static String _table_name;
Ref<FormValidator> _login_validator;
Ref<FormValidator> _registration_validator;
Ref<FormValidator> _profile_validator;
};
#endif