mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2025-02-19 22:24:23 +01:00
Added theweb nodes from rcpp_framework.
This commit is contained in:
parent
48e8b85f7e
commit
121740f070
12
modules/web/nodes/admin_panel/SCsub
Normal file
12
modules/web/nodes/admin_panel/SCsub
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env_mod")
|
||||
Import("env")
|
||||
|
||||
env_mod.core_sources = []
|
||||
|
||||
env_mod.add_source_files(env_mod.core_sources, "*.cpp")
|
||||
|
||||
# Build it all as a library
|
||||
lib = env_mod.add_library("admin_panel", env_mod.core_sources)
|
||||
env.Prepend(LIBS=[lib])
|
32
modules/web/nodes/admin_panel/admin_node.cpp
Normal file
32
modules/web/nodes/admin_panel/admin_node.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include "admin_node.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"
|
||||
|
||||
void AdminNode::admin_handle_request_main(Request *request) {
|
||||
|
||||
}
|
||||
|
||||
String AdminNode::admin_get_section_name() {
|
||||
return "";
|
||||
}
|
||||
|
||||
void AdminNode::admin_add_section_links(Vector<AdminSectionLinkInfo> *links) {
|
||||
|
||||
}
|
||||
|
||||
bool AdminNode::admin_full_render() {
|
||||
return false;
|
||||
}
|
||||
|
||||
AdminNode::AdminNode() :
|
||||
WebNode() {
|
||||
|
||||
}
|
||||
|
||||
AdminNode::~AdminNode() {
|
||||
}
|
40
modules/web/nodes/admin_panel/admin_node.h
Normal file
40
modules/web/nodes/admin_panel/admin_node.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef ADMIN_NODE_H
|
||||
#define ADMIN_NODE_H
|
||||
|
||||
#include "web/http/web_node.h"
|
||||
|
||||
#include "core/containers/vector.h"
|
||||
#include "core/string.h"
|
||||
|
||||
class Request;
|
||||
class FormValidator;
|
||||
|
||||
struct AdminSectionLinkInfo {
|
||||
String name;
|
||||
String link;
|
||||
|
||||
AdminSectionLinkInfo() {
|
||||
}
|
||||
|
||||
AdminSectionLinkInfo(const String &p_name, const String &p_link) {
|
||||
name = p_name;
|
||||
link = p_link;
|
||||
}
|
||||
};
|
||||
|
||||
class AdminNode : public WebNode {
|
||||
RCPP_OBJECT(AdminNode, WebNode);
|
||||
|
||||
public:
|
||||
virtual void admin_handle_request_main(Request *request);
|
||||
virtual String admin_get_section_name();
|
||||
virtual void admin_add_section_links(Vector<AdminSectionLinkInfo> *links);
|
||||
virtual bool admin_full_render();
|
||||
|
||||
AdminNode();
|
||||
~AdminNode();
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
#endif
|
171
modules/web/nodes/admin_panel/admin_panel.cpp
Normal file
171
modules/web/nodes/admin_panel/admin_panel.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
#include "admin_panel.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 "admin_node.h"
|
||||
|
||||
void AdminPanel::handle_request_main(Request *request) {
|
||||
if (_web_permission.is_valid()) {
|
||||
if (_web_permission->activate(request)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String seg = request->get_current_path_segment();
|
||||
|
||||
if (seg == "") {
|
||||
render_admin_panel_list(request);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _controllers.size(); ++i) {
|
||||
AdminPanelSection &s = _controllers[i];
|
||||
|
||||
if (s.section_url == seg) {
|
||||
AdminNode *c = s.controller;
|
||||
|
||||
request->push_path();
|
||||
|
||||
if (c->admin_full_render()) {
|
||||
c->admin_handle_request_main(request);
|
||||
return;
|
||||
}
|
||||
|
||||
// render_menu(request);
|
||||
render_headers(request);
|
||||
render_segment_body_top(request);
|
||||
render_controller_panel(request, c);
|
||||
render_footer(request);
|
||||
|
||||
// request->pop_path();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
request->send_error(404);
|
||||
}
|
||||
|
||||
void AdminPanel::render_admin_panel_list(Request *request) {
|
||||
render_headers(request);
|
||||
render_main_body_top(request);
|
||||
|
||||
String rootlink = request->get_url_root();
|
||||
|
||||
HTMLBuilder b;
|
||||
|
||||
Vector<AdminSectionLinkInfo> links;
|
||||
|
||||
b.div()->cls("content");
|
||||
|
||||
for (int i = 0; i < _controllers.size(); ++i) {
|
||||
b.div()->cls("section");
|
||||
|
||||
AdminPanelSection &s = _controllers[i];
|
||||
|
||||
b.div()->cls("section_header");
|
||||
b.w(s.controller->admin_get_section_name());
|
||||
b.cdiv();
|
||||
|
||||
s.controller->admin_add_section_links(&links);
|
||||
|
||||
for (int j = 0; j < links.size(); ++j) {
|
||||
AdminSectionLinkInfo &li = links[j];
|
||||
|
||||
b.div()->cls("section_entry");
|
||||
b.a()->href(rootlink + s.section_url + "/" + li.link);
|
||||
b.w(li.name);
|
||||
b.ca();
|
||||
b.cdiv();
|
||||
}
|
||||
|
||||
links.clear();
|
||||
|
||||
b.cdiv();
|
||||
}
|
||||
|
||||
b.cdiv();
|
||||
|
||||
render_footer(request);
|
||||
|
||||
request->body += b.result;
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void AdminPanel::render_controller_panel(Request *request, AdminNode *controller) {
|
||||
// set up headers
|
||||
controller->admin_handle_request_main(request);
|
||||
// set up footers
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void AdminPanel::register_admin_controller(const String §ion, AdminNode *controller) {
|
||||
AdminPanelSection sec;
|
||||
|
||||
sec.section_url = section;
|
||||
sec.controller = controller;
|
||||
|
||||
_controllers.push_back(sec);
|
||||
}
|
||||
|
||||
void AdminPanel::clear() {
|
||||
_controllers.clear();
|
||||
}
|
||||
|
||||
void AdminPanel::render_headers(Request *request) {
|
||||
request->head += _default_headers;
|
||||
}
|
||||
|
||||
void AdminPanel::render_main_body_top(Request *request) {
|
||||
request->body += _default_main_body_top;
|
||||
}
|
||||
|
||||
void AdminPanel::render_segment_body_top(Request *request) {
|
||||
request->body += _default_segment_body_top;
|
||||
}
|
||||
|
||||
void AdminPanel::render_footer(Request *request) {
|
||||
request->body += _default_footer;
|
||||
}
|
||||
|
||||
void AdminPanel::set_default_header(const String &val) {
|
||||
_default_headers = val;
|
||||
}
|
||||
void AdminPanel::set_default_main_body_top(const String &val) {
|
||||
_default_main_body_top = val;
|
||||
}
|
||||
void AdminPanel::set_default_segment_body_top(const String &val) {
|
||||
_default_segment_body_top = val;
|
||||
}
|
||||
|
||||
void AdminPanel::set_default_footer(const String &val) {
|
||||
_default_footer = val;
|
||||
}
|
||||
|
||||
AdminPanel *AdminPanel::get_singleton() {
|
||||
return _self;
|
||||
}
|
||||
|
||||
AdminPanel::AdminPanel() :
|
||||
WebNode() {
|
||||
|
||||
if (_self) {
|
||||
printf("AdminPanel::AdminPanel(): Error! self is not null!/n");
|
||||
}
|
||||
|
||||
_self = this;
|
||||
}
|
||||
|
||||
AdminPanel::~AdminPanel() {
|
||||
if (_self == this) {
|
||||
_self = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
AdminPanel *AdminPanel::_self = nullptr;
|
57
modules/web/nodes/admin_panel/admin_panel.h
Normal file
57
modules/web/nodes/admin_panel/admin_panel.h
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef ADMIN_PANEL_H
|
||||
#define ADMIN_PANEL_H
|
||||
|
||||
#include "web/http/web_node.h"
|
||||
|
||||
#include "core/string.h"
|
||||
#include "core/containers/vector.h"
|
||||
|
||||
class Request;
|
||||
class FormValidator;
|
||||
class AdminNode;
|
||||
|
||||
class AdminPanel : public WebNode {
|
||||
RCPP_OBJECT(AdminPanel, WebNode);
|
||||
|
||||
public:
|
||||
void handle_request_main(Request *request);
|
||||
|
||||
virtual void render_admin_panel_list(Request *request);
|
||||
virtual void render_controller_panel(Request *request, AdminNode *controller);
|
||||
|
||||
void register_admin_controller(const String §ion, AdminNode *controller);
|
||||
void clear();
|
||||
|
||||
virtual void render_headers(Request *request);
|
||||
virtual void render_main_body_top(Request *request);
|
||||
virtual void render_segment_body_top(Request *request);
|
||||
virtual void render_footer(Request *request);
|
||||
|
||||
void set_default_header(const String &val);
|
||||
void set_default_main_body_top(const String &val);
|
||||
void set_default_segment_body_top(const String &val);
|
||||
void set_default_footer(const String &val);
|
||||
|
||||
static AdminPanel *get_singleton();
|
||||
|
||||
AdminPanel();
|
||||
~AdminPanel();
|
||||
|
||||
protected:
|
||||
struct AdminPanelSection {
|
||||
String section_url;
|
||||
String name;
|
||||
AdminNode *controller;
|
||||
};
|
||||
|
||||
static AdminPanel *_self;
|
||||
|
||||
Vector<AdminPanelSection> _controllers;
|
||||
|
||||
String _default_headers;
|
||||
String _default_main_body_top;
|
||||
String _default_segment_body_top;
|
||||
String _default_footer;
|
||||
};
|
||||
|
||||
#endif
|
26
modules/web/nodes/admin_panel/detect.py
Normal file
26
modules/web/nodes/admin_panel/detect.py
Normal file
@ -0,0 +1,26 @@
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
|
||||
def is_active():
|
||||
return True
|
||||
|
||||
|
||||
def get_name():
|
||||
return "users"
|
||||
|
||||
|
||||
def can_build():
|
||||
return True
|
||||
|
||||
|
||||
def get_opts():
|
||||
return []
|
||||
|
||||
def get_flags():
|
||||
|
||||
return []
|
||||
|
||||
def configure(env):
|
||||
pass
|
12
modules/web/nodes/folder_serve_nodes/SCsub
Normal file
12
modules/web/nodes/folder_serve_nodes/SCsub
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env_mod")
|
||||
Import("env")
|
||||
|
||||
env_mod.core_sources = []
|
||||
|
||||
env_mod.add_source_files(env_mod.core_sources, "*.cpp")
|
||||
|
||||
# Build it all as a library
|
||||
lib = env_mod.add_library("paged_list", env_mod.core_sources)
|
||||
env.Prepend(LIBS=[lib])
|
@ -0,0 +1,139 @@
|
||||
#include "browsable_folder_serve_node.h"
|
||||
|
||||
#include "core/os/directory.h"
|
||||
#include "web/file_cache.h"
|
||||
#include "web/html/html_builder.h"
|
||||
#include "web/http/request.h"
|
||||
|
||||
void BrowsableFolderServeNode::_handle_request_main(Request *request) {
|
||||
String file_name = request->get_path(true, false);
|
||||
|
||||
String *s = _folder_indexes[file_name];
|
||||
|
||||
if (!s) {
|
||||
request->send_error(HTTP_STATUS_CODE_404_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
if (should_render_menu) {
|
||||
render_menu(request);
|
||||
}
|
||||
|
||||
request->body += (*s);
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void BrowsableFolderServeNode::render_index(Request *request) {
|
||||
String *s = _folder_indexes["/"];
|
||||
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
|
||||
request->body += (*s);
|
||||
}
|
||||
void BrowsableFolderServeNode::render_preview(Request *request) {
|
||||
}
|
||||
|
||||
void BrowsableFolderServeNode::load() {
|
||||
if (serve_folder == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
FolderServeNode::load();
|
||||
|
||||
evaluate_dir(serve_folder, true);
|
||||
}
|
||||
|
||||
void BrowsableFolderServeNode::evaluate_dir(const String &path, const bool top_level) {
|
||||
Ref<Directory> dir;
|
||||
dir.instance();
|
||||
|
||||
ERR_FAIL_COND_MSG(dir->open_dir(path) != OK, "Error opening folde!r: " + String(path));
|
||||
|
||||
String dir_uri;
|
||||
|
||||
if (!top_level) {
|
||||
dir_uri = path.substr(serve_folder.size(), path.size() - serve_folder.size());
|
||||
} else {
|
||||
dir_uri = "/";
|
||||
}
|
||||
|
||||
Vector<String> folders;
|
||||
Vector<String> files;
|
||||
|
||||
while (dir->next()) {
|
||||
String np = dir->current_get_path();
|
||||
np = np.substr(serve_folder.size(), np.size() - serve_folder.size());
|
||||
|
||||
if (dir->current_is_file()) {
|
||||
files.push_back(np);
|
||||
|
||||
} else {
|
||||
folders.push_back(np);
|
||||
evaluate_dir(dir->current_get_path());
|
||||
}
|
||||
}
|
||||
|
||||
dir->close_dir();
|
||||
|
||||
folders.sort_inc();
|
||||
files.sort_inc();
|
||||
|
||||
render_dir_page(dir_uri, folders, files, top_level);
|
||||
}
|
||||
|
||||
void BrowsableFolderServeNode::render_dir_page(const String &dir_uri, const Vector<String> &folders, const Vector<String> &files, const bool top_level) {
|
||||
HTMLBuilder b;
|
||||
|
||||
String uri = get_full_uri(false);
|
||||
|
||||
b.div("file_list");
|
||||
{
|
||||
if (!top_level) {
|
||||
b.div("file_list_entry");
|
||||
{
|
||||
b.a(uri + dir_uri.path_get_prev_dir())->w("..")->ca();
|
||||
}
|
||||
b.cdiv();
|
||||
}
|
||||
|
||||
for (int i = 0; i < folders.size(); ++i) {
|
||||
b.div("file_list_entry");
|
||||
{
|
||||
b.a(uri + folders[i])->w("(Folder) ")->w(folders[i].path_get_basename())->ca();
|
||||
}
|
||||
b.cdiv();
|
||||
}
|
||||
|
||||
for (int i = 0; i < files.size(); ++i) {
|
||||
b.div("file_list_entry");
|
||||
{
|
||||
b.a(uri + files[i])->w("(File) ")->w(files[i].path_get_basename())->ca();
|
||||
}
|
||||
b.cdiv();
|
||||
}
|
||||
}
|
||||
b.cdiv();
|
||||
|
||||
String *s = new String();
|
||||
s->append_str(b.result);
|
||||
|
||||
_folder_indexes[dir_uri] = s;
|
||||
}
|
||||
|
||||
BrowsableFolderServeNode::BrowsableFolderServeNode() :
|
||||
FolderServeNode() {
|
||||
|
||||
should_render_menu = true;
|
||||
}
|
||||
|
||||
BrowsableFolderServeNode::~BrowsableFolderServeNode() {
|
||||
for (std::map<String, String *>::iterator E = _folder_indexes.begin(); E != _folder_indexes.end(); E++) {
|
||||
if (E->second) {
|
||||
delete E->second;
|
||||
}
|
||||
}
|
||||
|
||||
_folder_indexes.clear();
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
#ifndef BROWSABLE_FOLDER_SERVE_NODE_H
|
||||
#define BROWSABLE_FOLDER_SERVE_NODE_H
|
||||
|
||||
#include "core/string.h"
|
||||
#include <map>
|
||||
|
||||
#include "folder_serve_node.h"
|
||||
|
||||
// On top of serving the files from the folder set to it's serve_folder property,
|
||||
// this class also generates HTML directory lists. (Similar to apache's directory listing)
|
||||
// It caches folder contents on ENTER_TREE, it does not watch for folder changes yet.
|
||||
|
||||
// if (should_render_menu) -> render_menu(request)
|
||||
// <div class="file_list">
|
||||
// <div class="file_list_entry"><a href="/files/">..</a></div>
|
||||
// <div class="file_list_entry"><a href="/files/test_folder/">(Folder) test_folder</a></div>
|
||||
// <div class="file_list_entry"><a href="/files/test_file.md">(File) test_file.md</a></div>
|
||||
// ...
|
||||
// </div>
|
||||
|
||||
class BrowsableFolderServeNode : public FolderServeNode {
|
||||
RCPP_OBJECT(BrowsableFolderServeNode, FolderServeNode);
|
||||
|
||||
public:
|
||||
void _handle_request_main(Request *request);
|
||||
|
||||
void render_index(Request *request);
|
||||
void render_preview(Request *request);
|
||||
|
||||
virtual void load();
|
||||
|
||||
void evaluate_dir(const String &path, const bool top_level = false);
|
||||
virtual void render_dir_page(const String &dir_uri, const Vector<String> &folders, const Vector<String> &files, const bool top_level);
|
||||
|
||||
bool should_render_menu;
|
||||
|
||||
BrowsableFolderServeNode();
|
||||
~BrowsableFolderServeNode();
|
||||
|
||||
protected:
|
||||
std::map<String, String *> _folder_indexes;
|
||||
};
|
||||
|
||||
#endif
|
27
modules/web/nodes/folder_serve_nodes/detect.py
Normal file
27
modules/web/nodes/folder_serve_nodes/detect.py
Normal file
@ -0,0 +1,27 @@
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
|
||||
def is_active():
|
||||
return True
|
||||
|
||||
|
||||
def get_name():
|
||||
return "paged_list"
|
||||
|
||||
|
||||
def can_build():
|
||||
return True
|
||||
|
||||
|
||||
def get_opts():
|
||||
return []
|
||||
|
||||
def get_flags():
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
67
modules/web/nodes/folder_serve_nodes/folder_serve_node.cpp
Normal file
67
modules/web/nodes/folder_serve_nodes/folder_serve_node.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include "folder_serve_node.h"
|
||||
|
||||
#include "web/http/request.h"
|
||||
#include "web/http/web_permission.h"
|
||||
|
||||
void FolderServeNode::handle_request_main(Request *request) {
|
||||
if (_web_permission.is_valid()) {
|
||||
if (_web_permission->activate(request)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const String &rp = request->get_current_path_segment();
|
||||
|
||||
if (rp == "") {
|
||||
if (!try_route_request_to_children(request)) {
|
||||
_handle_request_main(request);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
String file_name = request->get_path(true, false);
|
||||
|
||||
if (file_cache->wwwroot_has_file(file_name)) {
|
||||
String fp = file_cache->wwwroot;
|
||||
fp.append_path(file_name);
|
||||
|
||||
request->send_file(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!try_route_request_to_children(request)) {
|
||||
_handle_request_main(request);
|
||||
}
|
||||
}
|
||||
|
||||
void FolderServeNode::load() {
|
||||
file_cache->clear();
|
||||
|
||||
if (serve_folder == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
serve_folder.path_clean_end_slash();
|
||||
|
||||
file_cache->wwwroot = serve_folder;
|
||||
file_cache->wwwroot_refresh_cache();
|
||||
}
|
||||
|
||||
void FolderServeNode::_notification(const int what) {
|
||||
switch (what) {
|
||||
case NOTIFICATION_ENTER_TREE:
|
||||
load();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FolderServeNode::FolderServeNode() :
|
||||
WebNode() {
|
||||
|
||||
file_cache = new FileCache();
|
||||
}
|
||||
|
||||
FolderServeNode::~FolderServeNode() {
|
||||
}
|
33
modules/web/nodes/folder_serve_nodes/folder_serve_node.h
Normal file
33
modules/web/nodes/folder_serve_nodes/folder_serve_node.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef FOLDER_SERVE_NODE_H
|
||||
#define FOLDER_SERVE_NODE_H
|
||||
|
||||
#include "core/string.h"
|
||||
|
||||
#include "web/file_cache.h"
|
||||
#include "web/http/web_node.h"
|
||||
|
||||
// This class will serve the files from the folder set to it's serve_folder property.
|
||||
// It will cache the folder's contents on ENTER_TREE, and will match against the cached list,
|
||||
// this means directory walking (for example sending http://webapp.com/files/../../../etc/passwd),
|
||||
// and other techniques like it should not be possible.
|
||||
|
||||
class FolderServeNode : public WebNode {
|
||||
RCPP_OBJECT(FolderServeNode, WebNode);
|
||||
|
||||
public:
|
||||
void handle_request_main(Request *request);
|
||||
|
||||
virtual void load();
|
||||
|
||||
void _notification(const int what);
|
||||
|
||||
String serve_folder;
|
||||
|
||||
FolderServeNode();
|
||||
~FolderServeNode();
|
||||
|
||||
protected:
|
||||
FileCache *file_cache;
|
||||
};
|
||||
|
||||
#endif
|
12
modules/web/nodes/list_page/SCsub
Normal file
12
modules/web/nodes/list_page/SCsub
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env_mod")
|
||||
Import("env")
|
||||
|
||||
env_mod.core_sources = []
|
||||
|
||||
env_mod.add_source_files(env_mod.core_sources, "*.cpp")
|
||||
|
||||
# Build it all as a library
|
||||
lib = env_mod.add_library("list_page", env_mod.core_sources)
|
||||
env.Prepend(LIBS=[lib])
|
27
modules/web/nodes/list_page/detect.py
Normal file
27
modules/web/nodes/list_page/detect.py
Normal file
@ -0,0 +1,27 @@
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
|
||||
def is_active():
|
||||
return True
|
||||
|
||||
|
||||
def get_name():
|
||||
return "list_page"
|
||||
|
||||
|
||||
def can_build():
|
||||
return True
|
||||
|
||||
|
||||
def get_opts():
|
||||
return []
|
||||
|
||||
def get_flags():
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
197
modules/web/nodes/list_page/list_page.cpp
Normal file
197
modules/web/nodes/list_page/list_page.cpp
Normal file
@ -0,0 +1,197 @@
|
||||
#include "list_page.h"
|
||||
|
||||
#include "core/math/math.h"
|
||||
#include "web/html/html_builder.h"
|
||||
#include "web/html/utils.h"
|
||||
#include "web/http/web_permission.h"
|
||||
|
||||
#include <tinydir/tinydir.h>
|
||||
#include <iostream>
|
||||
|
||||
void ListPage::handle_request_main(Request *request) {
|
||||
if (_web_permission.is_valid()) {
|
||||
if (_web_permission->activate(request)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_pages.size() == 0) {
|
||||
render_menu(request);
|
||||
request->body += _no_entries_response;
|
||||
request->compile_and_send_body();
|
||||
return;
|
||||
}
|
||||
|
||||
const String &cs = request->get_current_path_segment();
|
||||
|
||||
if (cs == "") {
|
||||
render_menu(request);
|
||||
render_index(request);
|
||||
request->compile_and_send_body();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cs.is_uint()) {
|
||||
request->send_error(HTTP_STATUS_CODE_404_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
int p = cs.to_int();
|
||||
|
||||
p = ((p == 0) ? (0) : (p - 1));
|
||||
|
||||
if (p < 0 || p >= _pages.size()) {
|
||||
request->send_error(HTTP_STATUS_CODE_404_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
render_menu(request);
|
||||
request->body += _pages[p];
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void ListPage::render_index(Request *request) {
|
||||
request->body += _pages[0];
|
||||
}
|
||||
void ListPage::render_preview(Request *request) {
|
||||
}
|
||||
|
||||
void ListPage::load() {
|
||||
if (folder == "") {
|
||||
RLOG_ERR("Error: ListPage::load called, but a folder is not set!");
|
||||
return;
|
||||
}
|
||||
|
||||
Vector<String> files;
|
||||
|
||||
tinydir_dir dir;
|
||||
if (tinydir_open(&dir, folder.c_str()) == -1) {
|
||||
RLOG_ERR("Error opening ListPage::folder! folder: \n" + folder);
|
||||
return;
|
||||
}
|
||||
|
||||
while (dir.has_next) {
|
||||
tinydir_file file;
|
||||
if (tinydir_readfile(&dir, &file) == -1) {
|
||||
tinydir_next(&dir);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!file.is_dir) {
|
||||
String np = file.path;
|
||||
|
||||
files.push_back(np);
|
||||
}
|
||||
|
||||
tinydir_next(&dir);
|
||||
}
|
||||
|
||||
tinydir_close(&dir);
|
||||
|
||||
files.sort_inc();
|
||||
|
||||
Vector<String> list_entries;
|
||||
|
||||
for (uint32_t i = 0; i < files.size(); ++i) {
|
||||
FILE *f = fopen(files[i].c_str(), "r");
|
||||
|
||||
if (!f) {
|
||||
RLOG_ERR("Settings::parse_file: Error opening file!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
long fsize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET); /* same as rewind(f); */
|
||||
|
||||
String fd;
|
||||
fd.resize(fsize);
|
||||
|
||||
fread(&fd[0], 1, fsize, f);
|
||||
fclose(f);
|
||||
|
||||
Utils::markdown_to_html(&fd);
|
||||
|
||||
list_entries.push_back(fd);
|
||||
}
|
||||
|
||||
render_entries(list_entries);
|
||||
render_no_entries_response();
|
||||
}
|
||||
|
||||
void ListPage::render_entries(const Vector<String> &list_entries) {
|
||||
if (list_entries.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int pages = Math::floorf_int(Math::divf(list_entries.size(), entry_per_page));
|
||||
for (int i = 0; i < pages; ++i) {
|
||||
String r = "";
|
||||
|
||||
int efrom = i * entry_per_page;
|
||||
int eto = MIN((i + 1) * entry_per_page, list_entries.size());
|
||||
|
||||
r = render_page(i, pages, list_entries, efrom, eto);
|
||||
_pages.push_back(r);
|
||||
}
|
||||
}
|
||||
|
||||
String ListPage::render_page(const int page_index, const int page_count, const Vector<String> &list_entries, const int efrom, const int eto) {
|
||||
HTMLBuilder b;
|
||||
|
||||
b.div(main_div_class);
|
||||
|
||||
for (int i = efrom; i < eto; ++i) {
|
||||
b.w(render_entry(list_entries[i]));
|
||||
}
|
||||
|
||||
b.w(Utils::get_pagination(get_full_uri(), page_count, page_index, max_visible_navigation_links));
|
||||
b.cdiv();
|
||||
|
||||
return b.result;
|
||||
}
|
||||
|
||||
String ListPage::render_entry(const String &list_entry) {
|
||||
HTMLBuilder b;
|
||||
|
||||
b.div(main_div_class);
|
||||
b.div(empty_div_class)->w(list_entry)->cdiv();
|
||||
b.cdiv();
|
||||
|
||||
return b.result;
|
||||
}
|
||||
|
||||
void ListPage::render_no_entries_response() {
|
||||
HTMLBuilder b;
|
||||
|
||||
b.div(empty_div_class)->w(placeholder_text)->cdiv();
|
||||
|
||||
_no_entries_response = b.result;
|
||||
}
|
||||
|
||||
void ListPage::_notification(const int what) {
|
||||
switch (what) {
|
||||
case NOTIFICATION_ENTER_TREE:
|
||||
load();
|
||||
break;
|
||||
case NOTIFICATION_EXIT_TREE:
|
||||
_pages.clear();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ListPage::ListPage() :
|
||||
WebNode() {
|
||||
|
||||
max_visible_navigation_links = 6;
|
||||
entry_per_page = 4;
|
||||
main_div_class = "list_page";
|
||||
entry_div_class = "list_entry";
|
||||
empty_div_class = "list_entry_empty";
|
||||
placeholder_text = "No content yet!";
|
||||
}
|
||||
|
||||
ListPage::~ListPage() {
|
||||
}
|
66
modules/web/nodes/list_page/list_page.h
Normal file
66
modules/web/nodes/list_page/list_page.h
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef LIST_PAGE_H
|
||||
#define LIST_PAGE_H
|
||||
|
||||
#include "core/containers/vector.h"
|
||||
#include "core/string.h"
|
||||
|
||||
#include "web/http/web_node.h"
|
||||
|
||||
#include "web/http/request.h"
|
||||
|
||||
// This class will load and generate pages from a folder of md files. It supports pagination,
|
||||
// it will put entry_per_page md files per page. It generates html on enter tree, and caches everything.
|
||||
// Each md file gets rendered into a div with a class of "list_entry"
|
||||
|
||||
// HTML (If there are entries):
|
||||
// render_menu()
|
||||
// <div class="list_page"> // Set the class via the main_div_class property
|
||||
// <div class="list_entry">md file 1</div> // Set the class via the entry_div_class property
|
||||
// <div class="list_entry">md file 2</div>
|
||||
// ...
|
||||
// <pagination>
|
||||
// </div>
|
||||
|
||||
// HTML (If there are no entries):
|
||||
// render_menu()
|
||||
// <div class="list_page"> // Set the class via the main_div_class property
|
||||
// <div class="list_entry_empty">No content yet!</div> // Set the class via the empty_div_class property, text via placeholder_text property
|
||||
// </div>
|
||||
|
||||
class ListPage : public WebNode {
|
||||
RCPP_OBJECT(ListPage, WebNode);
|
||||
|
||||
public:
|
||||
void handle_request_main(Request *request);
|
||||
|
||||
void render_index(Request *request);
|
||||
void render_preview(Request *request);
|
||||
|
||||
void load();
|
||||
|
||||
virtual void render_entries(const Vector<String> &list_entries);
|
||||
virtual String render_page(const int page_index, const int page_count, const Vector<String> &list_entries, const int efrom, const int eto);
|
||||
virtual String render_entry(const String &list_entry);
|
||||
virtual void render_no_entries_response();
|
||||
|
||||
void _notification(const int what);
|
||||
|
||||
ListPage();
|
||||
~ListPage();
|
||||
|
||||
bool paginate;
|
||||
int max_visible_navigation_links;
|
||||
int entry_per_page;
|
||||
String folder;
|
||||
|
||||
String main_div_class;
|
||||
String entry_div_class;
|
||||
String empty_div_class;
|
||||
String placeholder_text;
|
||||
|
||||
protected:
|
||||
Vector<String> _pages;
|
||||
String _no_entries_response;
|
||||
};
|
||||
|
||||
#endif
|
12
modules/web/nodes/message_page/SCsub
Normal file
12
modules/web/nodes/message_page/SCsub
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env_mod")
|
||||
Import("env")
|
||||
|
||||
env_mod.core_sources = []
|
||||
|
||||
env_mod.add_source_files(env_mod.core_sources, "*.cpp")
|
||||
|
||||
# Build it all as a library
|
||||
lib = env_mod.add_library("message_page", env_mod.core_sources)
|
||||
env.Prepend(LIBS=[lib])
|
27
modules/web/nodes/message_page/detect.py
Normal file
27
modules/web/nodes/message_page/detect.py
Normal file
@ -0,0 +1,27 @@
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
|
||||
def is_active():
|
||||
return True
|
||||
|
||||
|
||||
def get_name():
|
||||
return "message_page"
|
||||
|
||||
|
||||
def can_build():
|
||||
return True
|
||||
|
||||
|
||||
def get_opts():
|
||||
return []
|
||||
|
||||
def get_flags():
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
85
modules/web/nodes/message_page/message_page.cpp
Normal file
85
modules/web/nodes/message_page/message_page.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include "message_page.h"
|
||||
|
||||
#include "database/database.h"
|
||||
|
||||
#include "database/query_builder.h"
|
||||
#include "database/table_builder.h"
|
||||
#include "database/query_result.h"
|
||||
#include "web/http/web_permission.h"
|
||||
|
||||
void MessagePage::handle_request_main(Request *request) {
|
||||
if (_web_permission.is_valid()) {
|
||||
if (_web_permission->activate(request)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Ref<QueryBuilder> b = db->get_query_builder();
|
||||
|
||||
b->select("text")->from("message_page")->end_command();
|
||||
|
||||
Ref<QueryResult> res = db->query(b->query_result);
|
||||
|
||||
Vector<String> msgs;
|
||||
|
||||
while (res->next_row()) {
|
||||
msgs.push_back(res->get_cell(0));
|
||||
}
|
||||
|
||||
String r = "<html><body>";
|
||||
|
||||
for (uint32_t i = 0; i < messages.size(); ++i) {
|
||||
r += "<p>" + messages[i] + "</p><br>";
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < msgs.size(); ++i) {
|
||||
r += "<p>" + msgs[i] + "</p><br>";
|
||||
}
|
||||
|
||||
r += "</html></body>";
|
||||
|
||||
request->body += r;
|
||||
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void MessagePage::_migrate(const bool clear, const bool seed_db) {
|
||||
Ref<TableBuilder> t = db->get_table_builder();
|
||||
|
||||
t->drop_table("message_page");
|
||||
db->query_run(t->result);
|
||||
|
||||
printf("%s\n", t->result.c_str());
|
||||
|
||||
t->result.clear();
|
||||
|
||||
t->create_table("message_page")->integer("id")->auto_increment()->primary_key()->next_row()->varchar("text", 30)->ccreate_table();
|
||||
|
||||
printf("%s\n", t->result.c_str());
|
||||
|
||||
db->query(t->result);
|
||||
|
||||
Ref<QueryBuilder> b = db->get_query_builder();
|
||||
|
||||
b->insert("message_page")->values("default, 'aaewdwd'");
|
||||
|
||||
printf("%s\n", b->query_result.c_str());
|
||||
|
||||
db->query_run(b->query_result);
|
||||
|
||||
b->query_result.clear();
|
||||
b->insert("message_page")->values("default, 'qqqqq'");
|
||||
|
||||
printf("%s\n", b->query_result.c_str());
|
||||
|
||||
db->query_run(b->query_result);
|
||||
}
|
||||
|
||||
MessagePage::MessagePage() :
|
||||
WebNode() {
|
||||
messages.push_back("T message 1");
|
||||
messages.push_back("T message 2");
|
||||
}
|
||||
|
||||
MessagePage::~MessagePage() {
|
||||
}
|
26
modules/web/nodes/message_page/message_page.h
Normal file
26
modules/web/nodes/message_page/message_page.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef MESSAGE_PAGE_H
|
||||
#define MESSAGE_PAGE_H
|
||||
|
||||
#include "core/containers/vector.h"
|
||||
#include "core/string.h"
|
||||
|
||||
#include "web/http/web_node.h"
|
||||
|
||||
#include "web/http/request.h"
|
||||
|
||||
|
||||
class MessagePage : public WebNode {
|
||||
RCPP_OBJECT(MessagePage, WebNode);
|
||||
|
||||
public:
|
||||
void handle_request_main(Request *request);
|
||||
|
||||
void _migrate(const bool clear, const bool seed_db);
|
||||
|
||||
MessagePage();
|
||||
~MessagePage();
|
||||
|
||||
Vector<String> messages;
|
||||
};
|
||||
|
||||
#endif
|
12
modules/web/nodes/paged_article/SCsub
Normal file
12
modules/web/nodes/paged_article/SCsub
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env_mod")
|
||||
Import("env")
|
||||
|
||||
env_mod.core_sources = []
|
||||
|
||||
env_mod.add_source_files(env_mod.core_sources, "*.cpp")
|
||||
|
||||
# Build it all as a library
|
||||
lib = env_mod.add_library("list_page", env_mod.core_sources)
|
||||
env.Prepend(LIBS=[lib])
|
27
modules/web/nodes/paged_article/detect.py
Normal file
27
modules/web/nodes/paged_article/detect.py
Normal file
@ -0,0 +1,27 @@
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
|
||||
def is_active():
|
||||
return True
|
||||
|
||||
|
||||
def get_name():
|
||||
return "list_page"
|
||||
|
||||
|
||||
def can_build():
|
||||
return True
|
||||
|
||||
|
||||
def get_opts():
|
||||
return []
|
||||
|
||||
def get_flags():
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
173
modules/web/nodes/paged_article/paged_article.cpp
Normal file
173
modules/web/nodes/paged_article/paged_article.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
#include "paged_article.h"
|
||||
|
||||
#include "core/os/directory.h"
|
||||
#include "web/html/utils.h"
|
||||
#include "web/http/web_permission.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void PagedArticle::handle_request_main(Request *request) {
|
||||
if (_web_permission.is_valid()) {
|
||||
if (_web_permission->activate(request)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const String &rp = request->get_current_path_segment();
|
||||
|
||||
if (request->get_remaining_segment_count() > 1 && rp == "files") {
|
||||
String file_name = "/" + request->get_path_segment(request->get_current_segment_index() + 1);
|
||||
|
||||
if (file_cache->wwwroot_has_file(file_name)) {
|
||||
String fp = file_cache->wwwroot + file_name;
|
||||
|
||||
request->send_file(fp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (rp == "") {
|
||||
render_menu(request);
|
||||
|
||||
render_index(request);
|
||||
|
||||
request->compile_and_send_body();
|
||||
return;
|
||||
}
|
||||
|
||||
const String *page = pages[rp];
|
||||
|
||||
if (page == nullptr) {
|
||||
// bad url
|
||||
request->send_error(404);
|
||||
return;
|
||||
}
|
||||
|
||||
render_menu(request);
|
||||
request->body += (*page);
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void PagedArticle::render_index(Request *request) {
|
||||
// summary page
|
||||
request->body += index_page;
|
||||
}
|
||||
|
||||
void PagedArticle::render_preview(Request *request) {
|
||||
}
|
||||
|
||||
void PagedArticle::load() {
|
||||
ERR_FAIL_COND_MSG(articles_folder == "", "Error: PagedArticle::load called, but a articles_folder is not set!");
|
||||
|
||||
Ref<Directory> dir;
|
||||
dir.instance();
|
||||
|
||||
ERR_FAIL_COND_MSG(dir->open_dir(articles_folder.c_str()) != OK, "Error opening PagedArticle::folder! folder: " + articles_folder);
|
||||
|
||||
Vector<String> files;
|
||||
|
||||
while (dir->next()) {
|
||||
if (dir->current_is_file()) {
|
||||
files.push_back(dir->current_get_name());
|
||||
}
|
||||
}
|
||||
|
||||
dir->close_dir();
|
||||
|
||||
if (files.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
files.sort_inc();
|
||||
|
||||
for (uint32_t i = 0; i < files.size(); ++i) {
|
||||
String file_path = articles_folder;
|
||||
file_path.append_path(files[i]);
|
||||
|
||||
String fd;
|
||||
|
||||
ERR_CONTINUE_MSG(dir->read_file_into(file_path, &fd) != OK, "PagedArticle::load_folder: Error opening file! " + file_path);
|
||||
|
||||
Utils::markdown_to_html(&fd);
|
||||
|
||||
if (files[i] == "summary.md") {
|
||||
summary = fd;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
String pagination;
|
||||
|
||||
pagination = Utils::get_pagination_links(get_full_uri(), files, i);
|
||||
|
||||
String *finals = new String();
|
||||
|
||||
(*finals) += pagination;
|
||||
(*finals) += fd;
|
||||
(*finals) += pagination;
|
||||
|
||||
pages[files[i]] = finals;
|
||||
|
||||
if (i == 0) {
|
||||
index_page = (*finals);
|
||||
}
|
||||
}
|
||||
|
||||
file_cache->clear();
|
||||
|
||||
if (serve_folder != "") {
|
||||
if (serve_folder_relative) {
|
||||
file_cache->wwwroot = articles_folder;
|
||||
file_cache->wwwroot.append_path(serve_folder);
|
||||
} else {
|
||||
file_cache->wwwroot = serve_folder;
|
||||
}
|
||||
|
||||
file_cache->wwwroot_refresh_cache();
|
||||
}
|
||||
|
||||
if (summary == "") {
|
||||
generate_summary();
|
||||
}
|
||||
}
|
||||
|
||||
String PagedArticle::get_index_page() {
|
||||
return index_page;
|
||||
}
|
||||
|
||||
String PagedArticle::get_summary() {
|
||||
return summary;
|
||||
}
|
||||
|
||||
void PagedArticle::generate_summary() {
|
||||
summary = get_uri_segment();
|
||||
}
|
||||
|
||||
void PagedArticle::_notification(const int what) {
|
||||
switch (what) {
|
||||
case NOTIFICATION_ENTER_TREE:
|
||||
load();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PagedArticle::PagedArticle() :
|
||||
WebNode() {
|
||||
|
||||
file_cache = new FileCache();
|
||||
|
||||
serve_folder_relative = true;
|
||||
serve_folder = "files";
|
||||
}
|
||||
|
||||
PagedArticle::~PagedArticle() {
|
||||
for (std::map<String, String *>::iterator it = pages.begin(); it != pages.end(); ++it) {
|
||||
delete ((*it).second);
|
||||
}
|
||||
|
||||
pages.clear();
|
||||
|
||||
delete file_cache;
|
||||
}
|
52
modules/web/nodes/paged_article/paged_article.h
Normal file
52
modules/web/nodes/paged_article/paged_article.h
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef PAGED_ARTICLE_H
|
||||
#define PAGED_ARTICLE_H
|
||||
|
||||
#include "core/containers/vector.h"
|
||||
#include "core/string.h"
|
||||
#include <map>
|
||||
|
||||
#include "web/file_cache.h"
|
||||
#include "web/http/web_node.h"
|
||||
|
||||
#include "web/http/request.h"
|
||||
|
||||
// This class will load and process all md files from the folder set to it's articles_folder property,
|
||||
// and serve every file from the directory set to it's serve_folder property.
|
||||
// if it finds a summary.md, it will serve it as the root.
|
||||
// It uses pagination.
|
||||
// THe links is generates currently look like: <url>/01_test.md
|
||||
// files are served under <url>/files/<file>
|
||||
|
||||
class PagedArticle : public WebNode {
|
||||
RCPP_OBJECT(PagedArticle, WebNode);
|
||||
|
||||
public:
|
||||
void handle_request_main(Request *request);
|
||||
|
||||
void render_index(Request *request);
|
||||
void render_preview(Request *request);
|
||||
|
||||
void load();
|
||||
void load_folder(const String &folder, const String &path);
|
||||
String get_index_page();
|
||||
String get_summary();
|
||||
|
||||
virtual void generate_summary();
|
||||
|
||||
void _notification(const int what);
|
||||
|
||||
PagedArticle();
|
||||
~PagedArticle();
|
||||
|
||||
String articles_folder;
|
||||
bool serve_folder_relative;
|
||||
String serve_folder;
|
||||
|
||||
protected:
|
||||
String index_page;
|
||||
String summary;
|
||||
std::map<String, String *> pages;
|
||||
FileCache *file_cache;
|
||||
};
|
||||
|
||||
#endif
|
94
modules/web/nodes/paged_article/paged_articles.cpp
Normal file
94
modules/web/nodes/paged_article/paged_articles.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
#include "paged_articles.h"
|
||||
|
||||
#include "web/html/html_builder.h"
|
||||
|
||||
#include "core/os/directory.h"
|
||||
#include "paged_article.h"
|
||||
#include "web/html/utils.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void PagedArticles::_handle_request_main(Request *request) {
|
||||
render_menu(request);
|
||||
|
||||
render_index(request);
|
||||
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void PagedArticles::render_index(Request *request) {
|
||||
// summary page
|
||||
request->body += index_page;
|
||||
}
|
||||
void PagedArticles::render_preview(Request *request) {
|
||||
}
|
||||
|
||||
void PagedArticles::load() {
|
||||
ERR_FAIL_COND_MSG(folder == "", "Error: PagedArticles::load called, but a folder is not set!");
|
||||
|
||||
if (folder.size() > 0 && folder[folder.size() - 1] == '/') {
|
||||
folder.pop_back();
|
||||
}
|
||||
|
||||
Ref<Directory> dir;
|
||||
dir.instance();
|
||||
|
||||
ERR_FAIL_COND_MSG(dir->open_dir(folder) != OK, "Error opening PagedArticles::folder! folder: " + folder);
|
||||
|
||||
while (dir->next()) {
|
||||
if (dir->current_is_dir()) {
|
||||
String np = dir->current_get_path();
|
||||
String fn = dir->current_get_name();
|
||||
|
||||
String ff = folder;
|
||||
ff.append_path(fn);
|
||||
|
||||
PagedArticle *p = new PagedArticle();
|
||||
String seg = dir->current_get_name();
|
||||
p->articles_folder = ff;
|
||||
p->set_uri_segment(seg);
|
||||
add_child(p);
|
||||
}
|
||||
}
|
||||
|
||||
generate_index_page();
|
||||
}
|
||||
|
||||
void PagedArticles::generate_index_page() {
|
||||
HTMLBuilder b;
|
||||
|
||||
b.div("article_list");
|
||||
|
||||
for (int i = 0; i < get_child_count(); ++i) {
|
||||
PagedArticle *a = Object::cast_to<PagedArticle>(get_child(i));
|
||||
|
||||
if (a) {
|
||||
b.a(a->get_full_uri());
|
||||
b.div("article_list_entry")->w(a->get_summary())->cdiv();
|
||||
b.ca();
|
||||
}
|
||||
}
|
||||
|
||||
b.cdiv();
|
||||
|
||||
index_page = b.result;
|
||||
}
|
||||
|
||||
void PagedArticles::_notification(const int what) {
|
||||
switch (what) {
|
||||
case NOTIFICATION_ENTER_TREE:
|
||||
load();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
WebNode::_notification(what);
|
||||
}
|
||||
|
||||
PagedArticles::PagedArticles() :
|
||||
WebNode() {
|
||||
}
|
||||
|
||||
PagedArticles::~PagedArticles() {
|
||||
}
|
50
modules/web/nodes/paged_article/paged_articles.h
Normal file
50
modules/web/nodes/paged_article/paged_articles.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef PAGED_ARTICLES_H
|
||||
#define PAGED_ARTICLES_H
|
||||
|
||||
#include "core/containers/vector.h"
|
||||
#include "core/string.h"
|
||||
|
||||
#include "web/file_cache.h"
|
||||
#include "web/http/web_node.h"
|
||||
|
||||
#include "web/http/request.h"
|
||||
|
||||
// This class will load and process all md files from the folder set to it's folder property,
|
||||
// and generate one page from them. TThe files are processed in alphabetical order.
|
||||
|
||||
// The generated HTML looks like:
|
||||
|
||||
// render_menu()
|
||||
// <div class="article_list_entry">
|
||||
// Contents of the first md file.
|
||||
// </div>
|
||||
// <div class="article_list_entry">
|
||||
// Contents of the second md file.
|
||||
// </div>
|
||||
// ...
|
||||
// </div>
|
||||
|
||||
class PagedArticles : public WebNode {
|
||||
RCPP_OBJECT(PagedArticles, WebNode);
|
||||
|
||||
public:
|
||||
void _handle_request_main(Request *request);
|
||||
|
||||
void render_index(Request *request);
|
||||
void render_preview(Request *request);
|
||||
|
||||
void load();
|
||||
void generate_index_page();
|
||||
|
||||
void _notification(const int what);
|
||||
|
||||
PagedArticles();
|
||||
~PagedArticles();
|
||||
|
||||
String folder;
|
||||
|
||||
protected:
|
||||
String index_page;
|
||||
};
|
||||
|
||||
#endif
|
51
modules/web/nodes/paged_article/paged_articles_md_index.cpp
Normal file
51
modules/web/nodes/paged_article/paged_articles_md_index.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include "paged_articles_md_index.h"
|
||||
|
||||
#include "web/html/html_builder.h"
|
||||
#include "web/http/request.h"
|
||||
#include "web/http/web_permission.h"
|
||||
|
||||
void PagedArticlesMDIndex::handle_request_main(Request *request) {
|
||||
if (_web_permission.is_valid()) {
|
||||
if (_web_permission->activate(request)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const String path = request->get_current_path_segment();
|
||||
|
||||
if (request->get_remaining_segment_count() == 0) {
|
||||
main_page->handle_request_main(request);
|
||||
return;
|
||||
}
|
||||
|
||||
articles->handle_request_main(request);
|
||||
}
|
||||
|
||||
void PagedArticlesMDIndex::render_index(Request *request) {
|
||||
main_page->render_index(request);
|
||||
}
|
||||
|
||||
void PagedArticlesMDIndex::render_preview(Request *request) {
|
||||
main_page->render_preview(request);
|
||||
}
|
||||
|
||||
void PagedArticlesMDIndex::load() {
|
||||
main_page->folder = folder;
|
||||
main_page->load();
|
||||
|
||||
articles->articles_folder = folder;
|
||||
articles->serve_folder = folder + "/files";
|
||||
articles->load();
|
||||
}
|
||||
|
||||
PagedArticlesMDIndex::PagedArticlesMDIndex() :
|
||||
WebNode() {
|
||||
|
||||
main_page = new ListPage();
|
||||
articles = new PagedArticle();
|
||||
}
|
||||
|
||||
PagedArticlesMDIndex::~PagedArticlesMDIndex() {
|
||||
delete main_page;
|
||||
delete articles;
|
||||
}
|
35
modules/web/nodes/paged_article/paged_articles_md_index.h
Normal file
35
modules/web/nodes/paged_article/paged_articles_md_index.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef PAGED_ARTICLES_MD_INDEX_H
|
||||
#define PAGED_ARTICLES_MD_INDEX_H
|
||||
|
||||
#include "core/string.h"
|
||||
|
||||
#include "web/http/web_node.h"
|
||||
|
||||
#include "web_modules/list_page/list_page.h"
|
||||
#include "web_modules/paged_article/paged_article.h"
|
||||
|
||||
// Inherit from PagedArticles and override generate_index_page -> load and process md files in the set folder
|
||||
// SHould probably be called something else. PagedArticlesMDIndex ?
|
||||
|
||||
class PagedArticlesMDIndex : public WebNode {
|
||||
RCPP_OBJECT(PagedArticlesMDIndex, WebNode);
|
||||
|
||||
public:
|
||||
void handle_request_main(Request *request);
|
||||
|
||||
void render_index(Request *request);
|
||||
void render_preview(Request *request);
|
||||
|
||||
void load();
|
||||
|
||||
PagedArticlesMDIndex();
|
||||
~PagedArticlesMDIndex();
|
||||
|
||||
String folder;
|
||||
String base_path;
|
||||
|
||||
ListPage *main_page;
|
||||
PagedArticle *articles;
|
||||
};
|
||||
|
||||
#endif
|
12
modules/web/nodes/rbac/SCsub
Normal file
12
modules/web/nodes/rbac/SCsub
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env_mod")
|
||||
Import("env")
|
||||
|
||||
env_mod.core_sources = []
|
||||
|
||||
env_mod.add_source_files(env_mod.core_sources, "*.cpp")
|
||||
|
||||
# Build it all as a library
|
||||
lib = env_mod.add_library("rbac", env_mod.core_sources)
|
||||
env.Prepend(LIBS=[lib])
|
31
modules/web/nodes/rbac/detect.py
Normal file
31
modules/web/nodes/rbac/detect.py
Normal file
@ -0,0 +1,31 @@
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
|
||||
def is_active():
|
||||
return True
|
||||
|
||||
|
||||
def get_name():
|
||||
return "users"
|
||||
|
||||
|
||||
def can_build():
|
||||
return True
|
||||
|
||||
|
||||
def get_opts():
|
||||
return []
|
||||
|
||||
def get_flags():
|
||||
|
||||
return []
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
|
||||
def get_module_dependencies():
|
||||
return [
|
||||
"admin_panel",
|
||||
]
|
872
modules/web/nodes/rbac/rbac_controller.cpp
Normal file
872
modules/web/nodes/rbac/rbac_controller.cpp
Normal file
@ -0,0 +1,872 @@
|
||||
#include "rbac_controller.h"
|
||||
|
||||
#include "core/error_macros.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 "rbac_default_permissions.h"
|
||||
#include "web_modules/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"
|
||||
|
||||
void RBACController::handle_request_main(Request *request) {
|
||||
}
|
||||
|
||||
void RBACController::create_validators() {
|
||||
}
|
||||
|
||||
void RBACController::admin_handle_request_main(Request *request) {
|
||||
String seg = request->get_current_path_segment();
|
||||
|
||||
if (seg == "") {
|
||||
admin_render_rank_list(request);
|
||||
return;
|
||||
} else if (seg == "new_rank") {
|
||||
request->push_path();
|
||||
|
||||
admin_handle_new_rank(request);
|
||||
} else if (seg == "edit_rank") {
|
||||
request->push_path();
|
||||
|
||||
admin_handle_edit_rank(request);
|
||||
} else if (seg == "permission_editor") {
|
||||
request->push_path();
|
||||
|
||||
admin_permission_editor(request);
|
||||
}
|
||||
}
|
||||
|
||||
void RBACController::admin_handle_new_rank(Request *request) {
|
||||
|
||||
if (request->get_method() == HTTP_METHOD_POST) {
|
||||
Ref<RBACRank> rank;
|
||||
rank.instance();
|
||||
|
||||
rank->name = request->get_parameter("name");
|
||||
rank->name_internal = request->get_parameter("name_internal");
|
||||
rank->settings = request->get_parameter("settings");
|
||||
|
||||
int base_permissions = 0;
|
||||
|
||||
for (int i = 0; i < _registered_permissions.size(); ++i) {
|
||||
String param = request->get_parameter("perm_check_" + String::num(i));
|
||||
|
||||
if (param != "") {
|
||||
base_permissions |= _registered_permissions[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
rank->base_permissions = base_permissions;
|
||||
|
||||
int rank_permissions = 0;
|
||||
|
||||
for (int i = 0; i < _registered_rank_permissions.size(); ++i) {
|
||||
String param = request->get_parameter("perm_rank_check_" + String::num(i));
|
||||
|
||||
if (param != "") {
|
||||
rank_permissions |= _registered_rank_permissions[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
rank->rank_permissions = rank_permissions;
|
||||
|
||||
db_save_rank(rank);
|
||||
|
||||
_ranks[rank->id] = rank;
|
||||
|
||||
request->send_redirect(request->get_url_root_parent() + "edit_rank/" + String::num(rank->id));
|
||||
return;
|
||||
}
|
||||
|
||||
RBACAdminRankViewData data;
|
||||
render_rank_view(request, &data);
|
||||
}
|
||||
|
||||
void RBACController::admin_handle_edit_rank(Request *request) {
|
||||
String seg = request->get_current_path_segment();
|
||||
|
||||
//check whether it's numeric
|
||||
//if (!seg.is)
|
||||
|
||||
int id = seg.to_int();
|
||||
|
||||
if (id == 0) {
|
||||
RLOG_MSG("RBACController::admin_handle_edit_rank: id == 0!\n");
|
||||
request->send_redirect(request->get_url_root_parent());
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<RBACRank> rank = _ranks[id];
|
||||
|
||||
if (!rank.is_valid()) {
|
||||
RLOG_MSG("RBACController::admin_handle_edit_rank: !rank.is_valid()\n");
|
||||
request->send_redirect(request->get_url_root_parent());
|
||||
return;
|
||||
}
|
||||
|
||||
RBACAdminRankViewData data;
|
||||
data.rank = rank;
|
||||
|
||||
if (request->get_method() == HTTP_METHOD_POST) {
|
||||
rank->name = request->get_parameter("name");
|
||||
rank->name_internal = request->get_parameter("name_internal");
|
||||
rank->settings = request->get_parameter("settings");
|
||||
|
||||
int base_permissions = 0;
|
||||
|
||||
for (int i = 0; i < _registered_permissions.size(); ++i) {
|
||||
String param = request->get_parameter("perm_check_" + String::num(i));
|
||||
|
||||
if (param != "") {
|
||||
base_permissions |= _registered_permissions[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
rank->base_permissions = base_permissions;
|
||||
|
||||
int rank_permissions = 0;
|
||||
|
||||
for (int i = 0; i < _registered_rank_permissions.size(); ++i) {
|
||||
String param = request->get_parameter("perm_rank_check_" + String::num(i));
|
||||
|
||||
if (param != "") {
|
||||
rank_permissions |= _registered_rank_permissions[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
rank->rank_permissions = rank_permissions;
|
||||
|
||||
db_save_rank(rank);
|
||||
|
||||
data.messages.push_back("Save Success!");
|
||||
}
|
||||
|
||||
render_rank_view(request, &data);
|
||||
}
|
||||
|
||||
void RBACController::render_rank_view(Request *request, RBACAdminRankViewData *data) {
|
||||
int id = 0;
|
||||
String name = "";
|
||||
String name_internal = "";
|
||||
String settings = "";
|
||||
int base_permissions = 0;
|
||||
int rank_permissions = 0;
|
||||
|
||||
if (data->rank.is_valid()) {
|
||||
id = data->rank->id;
|
||||
name = data->rank->name;
|
||||
name_internal = data->rank->name_internal;
|
||||
settings = data->rank->settings;
|
||||
base_permissions = data->rank->base_permissions;
|
||||
rank_permissions = data->rank->rank_permissions;
|
||||
}
|
||||
|
||||
HTMLBuilder b;
|
||||
|
||||
b.h4()->f()->a()->href(request->get_url_root_parent())->f()->w("<- Back")->ca()->ch4();
|
||||
b.h4()->f()->w("RBAC Editor")->ch4();
|
||||
|
||||
b.div()->cls("messages");
|
||||
for (int i = 0; i < data->messages.size(); ++i) {
|
||||
b.w(data->messages[i])->br();
|
||||
}
|
||||
b.cdiv();
|
||||
|
||||
b.form()->method("POST")->action(request->get_url_root() + String::num(id));
|
||||
{
|
||||
b.csrf_token(request);
|
||||
|
||||
//b.input()->type("hidden")->name("id")->value(String::num(id))->f()->cinput();
|
||||
b.w("Name:")->br();
|
||||
b.input()->type("text")->name("name")->value(name)->f()->br();
|
||||
b.w("Name (Internal):")->br();
|
||||
b.input()->type("text")->name("name_internal")->value(name_internal)->f()->cinput()->br();
|
||||
b.w("Custom Settings:")->br();
|
||||
b.input()->type("text")->name("settings")->value(settings)->f()->cinput()->br();
|
||||
|
||||
b.w("Base Permissions:")->br();
|
||||
|
||||
for (int i = 0; i < _registered_permissions.size(); ++i) {
|
||||
String checkbox_name = "perm_check_" + String::num(i);
|
||||
|
||||
b.input()->type("checkbox")->name(checkbox_name)->value(checkbox_name)->id(checkbox_name)->checked((base_permissions & _registered_permissions[i].value) != 0);
|
||||
b.label()->fora(checkbox_name)->f()->w(_registered_permissions[i].name)->clabel();
|
||||
}
|
||||
|
||||
b.br();
|
||||
|
||||
b.w("Rank Permissions:")->br();
|
||||
|
||||
for (int i = 0; i < _registered_rank_permissions.size(); ++i) {
|
||||
String checkbox_name = "perm_rank_check_" + String::num(i);
|
||||
|
||||
b.input()->type("checkbox")->name(checkbox_name)->value(checkbox_name)->id(checkbox_name)->checked((rank_permissions & _registered_rank_permissions[i].value) != 0);
|
||||
b.label()->fora(checkbox_name)->f()->w(_registered_rank_permissions[i].name)->clabel();
|
||||
}
|
||||
|
||||
b.br();
|
||||
|
||||
b.input()->type("submit")->value("Save");
|
||||
}
|
||||
b.cform();
|
||||
|
||||
request->body += b.result;
|
||||
}
|
||||
|
||||
void RBACController::admin_permission_editor(Request *request) {
|
||||
|
||||
String seg = request->get_current_path_segment();
|
||||
|
||||
//check whether it's numeric
|
||||
//if (!seg.is)
|
||||
|
||||
int id = seg.to_int();
|
||||
|
||||
if (id == 0) {
|
||||
RLOG_MSG("RBACController::admin_permission_editor: id == 0!\n");
|
||||
request->send_redirect(request->get_url_root_parent());
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<RBACRank> rank = _ranks[id];
|
||||
|
||||
if (!rank.is_valid()) {
|
||||
RLOG_MSG("RBACController::admin_permission_editor: !rank.is_valid()\n");
|
||||
request->send_redirect(request->get_url_root_parent());
|
||||
return;
|
||||
}
|
||||
|
||||
RBACAdminEditPermissionView data;
|
||||
data.rank = rank;
|
||||
|
||||
request->push_path();
|
||||
|
||||
String segn = request->get_current_path_segment();
|
||||
|
||||
if (segn == "") {
|
||||
admin_render_permission_editor_main_view(request, &data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (segn == "new") {
|
||||
request->push_path();
|
||||
|
||||
if (request->get_method() == HTTP_METHOD_POST) {
|
||||
if (admin_process_permission_editor_entry_edit_create_post(request, &data)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
admin_render_permission_editor_entry_edit_create_view(request, &data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (segn.is_uint()) {
|
||||
int perm_index = segn.to_int();
|
||||
|
||||
request->push_path();
|
||||
|
||||
if (perm_index < 0 || perm_index >= rank->permissions.size()) {
|
||||
RLOG_ERR("(perm_index < 0 || perm_index >= rank->permissions.size())!\n");
|
||||
request->send_redirect(request->get_url_root_parent());
|
||||
return;
|
||||
}
|
||||
|
||||
data.permission = rank->permissions[perm_index];
|
||||
|
||||
if (!data.permission.is_valid()) {
|
||||
RLOG_ERR("(!data.permission.is_valid()\n");
|
||||
request->send_error(503);
|
||||
return;
|
||||
}
|
||||
|
||||
if (request->get_method() == HTTP_METHOD_POST) {
|
||||
if (admin_process_permission_editor_entry_edit_create_post(request, &data)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
admin_render_permission_editor_entry_edit_create_view(request, &data);
|
||||
return;
|
||||
}
|
||||
|
||||
request->send_error(404);
|
||||
}
|
||||
|
||||
void RBACController::admin_render_permission_editor_main_view(Request *request, RBACAdminEditPermissionView *data) {
|
||||
HTMLBuilder b;
|
||||
|
||||
Ref<RBACRank> rank = data->rank;
|
||||
|
||||
b.h4()->f()->a()->href(request->get_url_root_parent(2))->f()->w("<- Back")->ca()->ch4();
|
||||
b.h4()->f()->w("RBAC Editor")->ch4();
|
||||
|
||||
b.div()->cls("heading");
|
||||
{
|
||||
b.w("[ Id ]: ")->wn(rank->id)->w(", [ Name ]: ")->w(rank->name)->w(", [ Name Internal ]: ")->w(rank->name_internal);
|
||||
}
|
||||
b.cdiv();
|
||||
|
||||
b.br();
|
||||
|
||||
for (int i = 0; i < rank->permissions.size(); ++i) {
|
||||
Ref<RBACPermission> perm = rank->permissions[i];
|
||||
|
||||
if (!perm.is_valid()) {
|
||||
RLOG_ERR("RBACController::admin_render_permission_editor_main_view: !perm.is_valid()\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
b.div()->cls("row");
|
||||
{
|
||||
b.a()->href(request->get_url_root() + String::num(i));
|
||||
|
||||
b.w("-- Rank: [ Id ]: ")->wn(perm->id)->w(", [ Rank Id ]: ")->wn(perm->rank_id)->w(", [ Name ]: ")->w(perm->name);
|
||||
b.w(" [ URL ]: ")->w(perm->url)->w(", [ Sort Order ]: ")->wn(perm->sort_order);
|
||||
b.w(" [ Permissions ]: ");
|
||||
|
||||
int pcount = 0;
|
||||
int perms = perm->permissions;
|
||||
for (int i = 0; i < _registered_permissions.size(); ++i) {
|
||||
if ((_registered_permissions[i].value & perms) != 0) {
|
||||
if (pcount > 0) {
|
||||
b.w(", ");
|
||||
}
|
||||
|
||||
b.w(_registered_permissions[i].name);
|
||||
|
||||
++pcount;
|
||||
}
|
||||
}
|
||||
|
||||
if (pcount == 0) {
|
||||
b.w("- None -");
|
||||
}
|
||||
|
||||
b.ca();
|
||||
}
|
||||
b.cdiv();
|
||||
}
|
||||
|
||||
b.br();
|
||||
|
||||
b.a()->href(request->get_url_root("new"));
|
||||
b.w("New Permission");
|
||||
b.ca();
|
||||
|
||||
request->body += b.result;
|
||||
}
|
||||
|
||||
void RBACController::admin_render_permission_editor_entry_edit_create_view(Request *request, RBACAdminEditPermissionView *data) {
|
||||
HTMLBuilder b;
|
||||
|
||||
Ref<RBACRank> rank = data->rank;
|
||||
Ref<RBACPermission> perm = data->permission;
|
||||
|
||||
String name;
|
||||
String url;
|
||||
int sort_order = 0;
|
||||
int permissions = 0;
|
||||
|
||||
if (perm.is_valid()) {
|
||||
name = perm->name;
|
||||
url = perm->url;
|
||||
sort_order = perm->sort_order;
|
||||
permissions = perm->permissions;
|
||||
}
|
||||
|
||||
b.h4()->f()->a()->href(request->get_url_root_parent())->f()->w("<- Back")->ca()->ch4();
|
||||
b.h4()->f()->w("RBAC Editor")->ch4();
|
||||
b.br();
|
||||
|
||||
b.div()->cls("messages");
|
||||
for (int i = 0; i < data->messages.size(); ++i) {
|
||||
b.w(data->messages[i])->br();
|
||||
}
|
||||
b.cdiv();
|
||||
b.br();
|
||||
|
||||
b.div()->cls("heading");
|
||||
{
|
||||
b.w("Rank: [ Id ]: ")->wn(rank->id)->w(", [ Name ]: ")->w(rank->name)->w(", [ Name Internal ]: ")->w(rank->name_internal);
|
||||
}
|
||||
b.cdiv();
|
||||
b.br();
|
||||
|
||||
b.form()->method("POST")->action(request->get_url_root());
|
||||
{
|
||||
b.csrf_token(request);
|
||||
|
||||
b.w("Name:")->br();
|
||||
b.input()->type("text")->name("name")->value(name)->f()->br();
|
||||
b.w("URL:")->br();
|
||||
b.input()->type("text")->name("url")->value(url)->f()->cinput()->br();
|
||||
|
||||
b.w("Permissions:")->br();
|
||||
|
||||
for (int i = 0; i < _registered_permissions.size(); ++i) {
|
||||
String checkbox_name = "perm_check_" + String::num(i);
|
||||
|
||||
b.input()->type("checkbox")->name(checkbox_name)->value(checkbox_name)->id(checkbox_name)->checked((permissions & _registered_permissions[i].value) != 0);
|
||||
b.label()->fora(checkbox_name)->f()->w(_registered_permissions[i].name)->clabel();
|
||||
}
|
||||
|
||||
b.br();
|
||||
|
||||
b.input()->type("submit")->value("Save");
|
||||
}
|
||||
b.cform();
|
||||
|
||||
request->body += b.result;
|
||||
}
|
||||
|
||||
bool RBACController::admin_process_permission_editor_entry_edit_create_post(Request *request, RBACAdminEditPermissionView *data) {
|
||||
Ref<RBACRank> rank = data->rank;
|
||||
|
||||
Ref<RBACPermission> perm = data->permission;
|
||||
|
||||
if (!perm.is_valid()) {
|
||||
perm.instance();
|
||||
|
||||
perm->rank_id = rank->id;
|
||||
|
||||
if (rank->permissions.size() > 0) {
|
||||
Ref<RBACPermission> p = rank->permissions[rank->permissions.size() - 1];
|
||||
|
||||
perm->sort_order = p->sort_order + 1;
|
||||
}
|
||||
|
||||
rank->permissions.push_back(perm);
|
||||
}
|
||||
|
||||
perm->name = request->get_parameter("name");
|
||||
perm->url = request->get_parameter("url");
|
||||
|
||||
int permissions = 0;
|
||||
|
||||
for (int i = 0; i < _registered_permissions.size(); ++i) {
|
||||
String param = request->get_parameter("perm_check_" + String::num(i));
|
||||
|
||||
if (param != "") {
|
||||
permissions |= _registered_permissions[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
perm->permissions = permissions;
|
||||
|
||||
//set this up in the form by default
|
||||
//perm->sort_order = request->get_parameter("sort_order").to_int();
|
||||
|
||||
db_save_permission(perm);
|
||||
|
||||
if (perm->id == 0) {
|
||||
RLOG_ERR("RBACController::admin_process_permission_editor_entry_edit_create_post: perm->id == 0!\n");
|
||||
}
|
||||
|
||||
request->send_redirect(request->get_url_root_parent());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RBACController::admin_render_rank_list(Request *request) {
|
||||
HTMLBuilder b;
|
||||
|
||||
b.h4()->f()->a()->href(request->get_url_root_parent())->f()->w("<- Back")->ca()->ch4();
|
||||
b.h4()->f()->w("RBAC Editor")->ch4();
|
||||
|
||||
for (std::map<int, Ref<RBACRank> >::iterator p = _ranks.begin(); p != _ranks.end(); p++) {
|
||||
Ref<RBACRank> r = p->second;
|
||||
|
||||
if (!r.is_valid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
b.div()->cls("row");
|
||||
{
|
||||
b.a()->href(request->get_url_root("permission_editor/") + String::num(r->id));
|
||||
b.w("[ Id ]: ")->wn(r->id)->w(", [ Name ]: ")->w(r->name)->w(", [ Name Internal ]: ")->w(r->name_internal);
|
||||
b.w(", [ Base Permissions ]: ");
|
||||
|
||||
int pcount = 0;
|
||||
int perms = r->base_permissions;
|
||||
for (int i = 0; i < _registered_permissions.size(); ++i) {
|
||||
if ((_registered_permissions[i].value & perms) != 0) {
|
||||
if (pcount > 0) {
|
||||
b.w(", ");
|
||||
}
|
||||
|
||||
b.w(_registered_permissions[i].name);
|
||||
|
||||
++pcount;
|
||||
}
|
||||
}
|
||||
|
||||
if (pcount == 0) {
|
||||
b.w("- None -");
|
||||
}
|
||||
|
||||
b.w(", [ Rank Permissions ]: ");
|
||||
|
||||
pcount = 0;
|
||||
perms = r->rank_permissions;
|
||||
for (int i = 0; i < _registered_rank_permissions.size(); ++i) {
|
||||
if ((_registered_rank_permissions[i].value & perms) != 0) {
|
||||
if (pcount > 0) {
|
||||
b.w(", ");
|
||||
}
|
||||
|
||||
b.w(_registered_rank_permissions[i].name);
|
||||
|
||||
++pcount;
|
||||
}
|
||||
}
|
||||
|
||||
if (pcount == 0) {
|
||||
b.w("- None -");
|
||||
}
|
||||
|
||||
b.ca();
|
||||
|
||||
b.w(" - ");
|
||||
|
||||
b.a()->href(request->get_url_root("edit_rank/") + String::num(r->id));
|
||||
b.w("[ Edit ]");
|
||||
b.ca();
|
||||
}
|
||||
b.cdiv();
|
||||
}
|
||||
|
||||
b.br();
|
||||
|
||||
b.a()->href(request->get_url_root("new_rank"));
|
||||
b.w("New Rank");
|
||||
b.ca();
|
||||
|
||||
request->body += b.result;
|
||||
}
|
||||
|
||||
void RBACController::admin_render_rank_editor(Request *request) {
|
||||
}
|
||||
|
||||
String RBACController::admin_get_section_name() {
|
||||
return "Role Based Access Control";
|
||||
}
|
||||
|
||||
void RBACController::admin_add_section_links(Vector<AdminSectionLinkInfo> *links) {
|
||||
links->push_back(AdminSectionLinkInfo("Editor", ""));
|
||||
}
|
||||
|
||||
void RBACController::register_permission(const String &name, const int val) {
|
||||
_registered_permissions.push_back(PermissionEntry(name, val));
|
||||
}
|
||||
void RBACController::register_rank_permission(const String &name, const int val) {
|
||||
_registered_rank_permissions.push_back(PermissionEntry(name, val));
|
||||
}
|
||||
void RBACController::clear_registered_permissions() {
|
||||
_registered_permissions.clear();
|
||||
_registered_rank_permissions.clear();
|
||||
}
|
||||
|
||||
void RBACController::initialize() {
|
||||
_ranks = db_load_ranks();
|
||||
_default_rank_id = db_get_default_rank();
|
||||
_default_user_rank_id = db_get_default_user_rank();
|
||||
|
||||
register_permissions();
|
||||
}
|
||||
|
||||
void RBACController::register_permissions() {
|
||||
register_permission("Create", User::PERMISSION_CREATE);
|
||||
register_permission("Read", User::PERMISSION_READ);
|
||||
register_permission("Update", User::PERMISSION_UPDATE);
|
||||
register_permission("Delete", User::PERMISSION_DELETE);
|
||||
|
||||
register_rank_permission("Admin Panel", RBAC_RANK_PERMISSION_ADMIN_PANEL);
|
||||
register_rank_permission("Use Redirect", RBAC_RANK_PERMISSION_USE_REDIRECT);
|
||||
}
|
||||
|
||||
Ref<RBACRank> RBACController::get_rank(int rank_id) {
|
||||
return _ranks[rank_id];
|
||||
}
|
||||
|
||||
int RBACController::get_default_user_rank_id() {
|
||||
return _default_user_rank_id;
|
||||
}
|
||||
Ref<RBACRank> RBACController::get_default_user_rank() {
|
||||
return _ranks[get_default_user_rank_id()];
|
||||
}
|
||||
|
||||
int RBACController::get_default_rank_id() {
|
||||
return _default_rank_id;
|
||||
}
|
||||
|
||||
Ref<RBACRank> RBACController::get_default_rank() {
|
||||
return _ranks[get_default_rank_id()];
|
||||
}
|
||||
|
||||
String &RBACController::get_redirect_url() {
|
||||
return _redirect_url;
|
||||
}
|
||||
|
||||
bool RBACController::continue_on_missing_default_rank() {
|
||||
//todo, add setting
|
||||
return false;
|
||||
}
|
||||
|
||||
//DB
|
||||
|
||||
std::map<int, Ref<RBACRank> > RBACController::db_load_ranks() {
|
||||
std::map<int, Ref<RBACRank> > ranks;
|
||||
|
||||
Ref<QueryBuilder> qb = get_query_builder();
|
||||
|
||||
qb->select("id,name,name_internal,settings,base_permissions,rank_permissions")->from(_rbac_ranks_table);
|
||||
Ref<QueryResult> res = qb->run();
|
||||
|
||||
while (res->next_row()) {
|
||||
Ref<RBACRank> r;
|
||||
r.instance();
|
||||
|
||||
r->id = res->get_cell_int(0);
|
||||
r->name = res->get_cell_str(1);
|
||||
r->name_internal = res->get_cell_str(2);
|
||||
r->settings = res->get_cell_str(3);
|
||||
r->base_permissions = res->get_cell_int(4);
|
||||
r->rank_permissions = res->get_cell_int(5);
|
||||
|
||||
ranks[r->id] = r;
|
||||
}
|
||||
|
||||
qb->reset();
|
||||
qb->select("id,rank_id,name,url,sort_order,permissions")->from(_rbac_permissions_table);
|
||||
res = qb->run();
|
||||
|
||||
while (res->next_row()) {
|
||||
Ref<RBACPermission> p;
|
||||
p.instance();
|
||||
|
||||
p->id = res->get_cell_int(0);
|
||||
p->rank_id = res->get_cell_int(1);
|
||||
p->name = res->get_cell_str(2);
|
||||
p->url = res->get_cell_str(3);
|
||||
p->sort_order = res->get_cell_int(4);
|
||||
p->permissions = res->get_cell_int(5);
|
||||
|
||||
Ref<RBACRank> r = ranks[p->rank_id];
|
||||
|
||||
if (!r.is_valid()) {
|
||||
RLOG_ERR("RBACModel::load_permissions: !r.is_valid()!");
|
||||
continue;
|
||||
}
|
||||
|
||||
r->permissions.push_back(p);
|
||||
}
|
||||
|
||||
for (std::map<int, Ref<RBACRank> >::iterator i = ranks.begin(); i != ranks.end(); ++i) {
|
||||
Ref<RBACRank> r = i->second;
|
||||
|
||||
if (r.is_valid()) {
|
||||
r->sort_permissions();
|
||||
}
|
||||
}
|
||||
|
||||
return ranks;
|
||||
}
|
||||
|
||||
void RBACController::db_save(const Ref<RBACRank> &rank) {
|
||||
db_save_rank(rank);
|
||||
|
||||
for (int i = 0; i < rank->permissions.size(); ++i) {
|
||||
Ref<RBACPermission> permission = rank->permissions[i];
|
||||
|
||||
int rid = rank->id;
|
||||
|
||||
if (permission->rank_id != rid) {
|
||||
permission->rank_id = rid;
|
||||
}
|
||||
|
||||
db_save_permission(permission);
|
||||
}
|
||||
}
|
||||
|
||||
void RBACController::db_save_rank(const Ref<RBACRank> &rank) {
|
||||
Ref<QueryBuilder> qb = get_query_builder();
|
||||
|
||||
if (rank->id == 0) {
|
||||
qb->insert(_rbac_ranks_table, "name,name_internal,settings,base_permissions,rank_permissions")->values();
|
||||
qb->val(rank->name)->val(rank->name_internal)->val(rank->settings)->val(rank->base_permissions)->val(rank->rank_permissions);
|
||||
qb->cvalues();
|
||||
qb->select_last_insert_id();
|
||||
Ref<QueryResult> res = qb->run();
|
||||
//qb->print();
|
||||
|
||||
Ref<RBACRank> r = rank;
|
||||
|
||||
r->id = res->get_last_insert_rowid();
|
||||
} else {
|
||||
qb->update(_rbac_ranks_table)->set();
|
||||
qb->setp("name", rank->name);
|
||||
qb->setp("name_internal", rank->name_internal);
|
||||
qb->setp("settings", rank->settings);
|
||||
qb->setp("base_permissions", rank->base_permissions);
|
||||
qb->setp("rank_permissions", rank->rank_permissions);
|
||||
qb->cset();
|
||||
qb->where()->wp("id", rank->id);
|
||||
qb->end_command();
|
||||
qb->run_query();
|
||||
//qb->print();
|
||||
}
|
||||
}
|
||||
|
||||
void RBACController::db_save_permission(const Ref<RBACPermission> &permission) {
|
||||
Ref<QueryBuilder> qb = get_query_builder();
|
||||
|
||||
if (permission->id == 0) {
|
||||
qb->insert(_rbac_permissions_table, "rank_id,name,url,sort_order,permissions")->values();
|
||||
qb->val(permission->rank_id)->val(permission->name)->val(permission->url);
|
||||
qb->val(permission->sort_order)->val(permission->permissions);
|
||||
qb->cvalues();
|
||||
qb->select_last_insert_id();
|
||||
Ref<QueryResult> res = qb->run();
|
||||
//qb->print();
|
||||
|
||||
Ref<RBACPermission> r = permission;
|
||||
|
||||
r->id = res->get_last_insert_rowid();
|
||||
} else {
|
||||
qb->update(_rbac_permissions_table)->set();
|
||||
qb->setp("rank_id", permission->rank_id);
|
||||
qb->setp("name", permission->name);
|
||||
qb->setp("url", permission->url);
|
||||
qb->setp("sort_order", permission->sort_order);
|
||||
qb->setp("permissions", permission->permissions);
|
||||
qb->cset();
|
||||
qb->where()->wp("id", permission->id);
|
||||
qb->end_command();
|
||||
qb->run_query();
|
||||
//qb->print();
|
||||
}
|
||||
}
|
||||
|
||||
int RBACController::db_get_default_rank() {
|
||||
//todo, load this, and save it to a table (probably a new settings class)
|
||||
return 3;
|
||||
}
|
||||
|
||||
int RBACController::db_get_default_user_rank() {
|
||||
//todo, load this, and save it to a table (probably a new settings class)
|
||||
return 2;
|
||||
}
|
||||
|
||||
String RBACController::db_get_redirect_url() {
|
||||
//todo, load this, and save it to a table (probably a new settings class)
|
||||
return String("/user/login");
|
||||
}
|
||||
|
||||
void RBACController::create_table() {
|
||||
Ref<TableBuilder> tb = get_table_builder();
|
||||
|
||||
tb->create_table(_rbac_ranks_table);
|
||||
tb->integer("id")->auto_increment()->next_row();
|
||||
tb->varchar("name", 60)->not_null()->next_row();
|
||||
tb->varchar("name_internal", 100)->not_null()->next_row();
|
||||
tb->varchar("settings", 200)->not_null()->next_row();
|
||||
tb->integer("base_permissions")->not_null()->next_row();
|
||||
tb->integer("rank_permissions")->not_null()->next_row();
|
||||
tb->primary_key("id");
|
||||
tb->ccreate_table();
|
||||
//tb->run_query();
|
||||
//tb->print();
|
||||
|
||||
//tb->result = "";
|
||||
|
||||
tb->create_table(_rbac_permissions_table);
|
||||
tb->integer("id")->auto_increment()->next_row();
|
||||
tb->integer("rank_id")->not_null()->next_row();
|
||||
tb->varchar("name", 60)->not_null()->next_row();
|
||||
tb->varchar("url", 100)->not_null()->next_row();
|
||||
tb->integer("sort_order")->not_null()->next_row();
|
||||
tb->integer("permissions")->not_null()->next_row();
|
||||
|
||||
tb->primary_key("id");
|
||||
tb->foreign_key("rank_id")->references(_rbac_ranks_table, "id");
|
||||
tb->ccreate_table();
|
||||
tb->run_query();
|
||||
//tb->print();
|
||||
}
|
||||
void RBACController::drop_table() {
|
||||
Ref<TableBuilder> tb = get_table_builder();
|
||||
|
||||
tb->drop_table_if_exists(_rbac_permissions_table)->drop_table_if_exists(_rbac_ranks_table)->run_query();
|
||||
//tb->print();
|
||||
}
|
||||
|
||||
void RBACController::create_default_entries() {
|
||||
Ref<RBACRank> admin;
|
||||
admin.instance();
|
||||
|
||||
admin->name = "Admin";
|
||||
admin->base_permissions = User::PERMISSION_ALL;
|
||||
admin->rank_permissions = RBAC_RANK_PERMISSION_ADMIN_PANEL;
|
||||
|
||||
db_save_rank(admin);
|
||||
|
||||
Ref<RBACRank> user;
|
||||
user.instance();
|
||||
|
||||
user->name = "User";
|
||||
//user->base_permissions = User::PERMISSION_READ;
|
||||
//user->rank_permissions = 0;
|
||||
|
||||
//temporary!
|
||||
user->base_permissions = User::PERMISSION_ALL;
|
||||
user->rank_permissions = RBAC_RANK_PERMISSION_ADMIN_PANEL;
|
||||
|
||||
db_save_rank(user);
|
||||
|
||||
Ref<RBACRank> guest;
|
||||
guest.instance();
|
||||
|
||||
guest->name = "Guest";
|
||||
guest->base_permissions = User::PERMISSION_READ;
|
||||
guest->rank_permissions = RBAC_RANK_PERMISSION_USE_REDIRECT;
|
||||
|
||||
db_save_rank(guest);
|
||||
}
|
||||
|
||||
|
||||
RBACController *RBACController::get_singleton() {
|
||||
return _self;
|
||||
}
|
||||
|
||||
RBACController::RBACController() :
|
||||
AdminNode() {
|
||||
|
||||
if (_self) {
|
||||
printf("RBACController::RBACController(): Error! self is not null!/n");
|
||||
}
|
||||
|
||||
_default_rank_id = 0;
|
||||
_default_user_rank_id = 0;
|
||||
|
||||
_rbac_ranks_table = "rbac_ranks";
|
||||
_rbac_permissions_table = "rbac_permissions";
|
||||
|
||||
_self = this;
|
||||
}
|
||||
|
||||
RBACController::~RBACController() {
|
||||
if (_self == this) {
|
||||
_self = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RBACController *RBACController::_self = nullptr;
|
127
modules/web/nodes/rbac/rbac_controller.h
Normal file
127
modules/web/nodes/rbac/rbac_controller.h
Normal file
@ -0,0 +1,127 @@
|
||||
#ifndef RBAC_CONTROLLER_H
|
||||
#define RBAC_CONTROLLER_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "web_modules/admin_panel/admin_node.h"
|
||||
|
||||
#include "core/containers/vector.h"
|
||||
#include "core/string.h"
|
||||
|
||||
#include "rbac_permission.h"
|
||||
#include "rbac_rank.h"
|
||||
|
||||
class Request;
|
||||
class FormValidator;
|
||||
|
||||
class RBACController : public AdminNode {
|
||||
RCPP_OBJECT(RBACController, AdminNode);
|
||||
|
||||
public:
|
||||
void handle_request_main(Request *request);
|
||||
void create_validators();
|
||||
|
||||
void admin_handle_request_main(Request *request);
|
||||
String admin_get_section_name();
|
||||
void admin_add_section_links(Vector<AdminSectionLinkInfo> *links);
|
||||
|
||||
struct RBACAdminRankViewData {
|
||||
Ref<RBACRank> rank;
|
||||
Vector<String> messages;
|
||||
|
||||
int id = 0;
|
||||
String name = "";
|
||||
String name_internal = "";
|
||||
String settings = "";
|
||||
int rank_permissions = 0;
|
||||
};
|
||||
|
||||
void admin_handle_new_rank(Request *request);
|
||||
void admin_handle_edit_rank(Request *request);
|
||||
void render_rank_view(Request *request, RBACAdminRankViewData *data);
|
||||
|
||||
struct RBACAdminEditPermissionView {
|
||||
Ref<RBACRank> rank;
|
||||
Ref<RBACPermission> permission;
|
||||
Vector<String> messages;
|
||||
|
||||
int rank_id = 0;
|
||||
int permission_id = 0;
|
||||
};
|
||||
|
||||
void admin_permission_editor(Request *request);
|
||||
void admin_render_permission_editor_main_view(Request *request, RBACAdminEditPermissionView *data);
|
||||
void admin_render_permission_editor_entry_edit_create_view(Request *request, RBACAdminEditPermissionView *data);
|
||||
bool admin_process_permission_editor_entry_edit_create_post(Request *request, RBACAdminEditPermissionView *data);
|
||||
|
||||
void admin_render_rank_list(Request *request);
|
||||
void admin_render_rank_editor(Request *request);
|
||||
|
||||
void register_permission(const String &name, const int val);
|
||||
void register_rank_permission(const String &name, const int val);
|
||||
void clear_registered_permissions();
|
||||
|
||||
void initialize();
|
||||
virtual void register_permissions();
|
||||
|
||||
Ref<RBACRank> get_rank(int rank_id);
|
||||
|
||||
int get_default_user_rank_id();
|
||||
Ref<RBACRank> get_default_user_rank();
|
||||
|
||||
int get_default_rank_id();
|
||||
Ref<RBACRank> get_default_rank();
|
||||
|
||||
String &get_redirect_url();
|
||||
|
||||
bool continue_on_missing_default_rank();
|
||||
|
||||
// db
|
||||
|
||||
virtual std::map<int, Ref<RBACRank> > db_load_ranks();
|
||||
|
||||
virtual void db_save(const Ref<RBACRank> &rank);
|
||||
virtual void db_save_rank(const Ref<RBACRank> &rank);
|
||||
virtual void db_save_permission(const Ref<RBACPermission> &permission);
|
||||
virtual int db_get_default_rank();
|
||||
virtual int db_get_default_user_rank();
|
||||
virtual String db_get_redirect_url();
|
||||
|
||||
void create_table();
|
||||
void drop_table();
|
||||
void create_default_entries();
|
||||
|
||||
static RBACController *get_singleton();
|
||||
|
||||
RBACController();
|
||||
~RBACController();
|
||||
|
||||
protected:
|
||||
static RBACController *_self;
|
||||
|
||||
int _default_rank_id;
|
||||
int _default_user_rank_id;
|
||||
std::map<int, Ref<RBACRank> > _ranks;
|
||||
String _redirect_url;
|
||||
|
||||
struct PermissionEntry {
|
||||
String name;
|
||||
int value;
|
||||
|
||||
PermissionEntry() {
|
||||
}
|
||||
|
||||
PermissionEntry(const String &p_name, const int p_val) {
|
||||
name = p_name;
|
||||
value = p_val;
|
||||
}
|
||||
};
|
||||
|
||||
String _rbac_ranks_table;
|
||||
String _rbac_permissions_table;
|
||||
|
||||
Vector<PermissionEntry> _registered_permissions;
|
||||
Vector<PermissionEntry> _registered_rank_permissions;
|
||||
};
|
||||
|
||||
#endif
|
9
modules/web/nodes/rbac/rbac_default_permissions.h
Normal file
9
modules/web/nodes/rbac/rbac_default_permissions.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef RBAC_DEFAULT_PERMISSIONS_H
|
||||
#define RBAC_DEFAULT_PERMISSIONS_H
|
||||
|
||||
enum RBACDefaultRankPermissions {
|
||||
RBAC_RANK_PERMISSION_ADMIN_PANEL = 1 << 0,
|
||||
RBAC_RANK_PERMISSION_USE_REDIRECT = 1 << 1,
|
||||
};
|
||||
|
||||
#endif
|
21
modules/web/nodes/rbac/rbac_permission.cpp
Normal file
21
modules/web/nodes/rbac/rbac_permission.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include "rbac_permission.h"
|
||||
|
||||
bool RBACPermission::is_smaller(const Ref<RBACPermission> &b) const {
|
||||
if (!b.is_valid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return sort_order < b->sort_order;
|
||||
}
|
||||
|
||||
RBACPermission::RBACPermission() :
|
||||
Resource() {
|
||||
|
||||
id = 0;
|
||||
rank_id = 0;
|
||||
sort_order = 0;
|
||||
permissions = 0;
|
||||
}
|
||||
|
||||
RBACPermission::~RBACPermission() {
|
||||
}
|
25
modules/web/nodes/rbac/rbac_permission.h
Normal file
25
modules/web/nodes/rbac/rbac_permission.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef RBAC_PERMISSION_H
|
||||
#define RBAC_PERMISSION_H
|
||||
|
||||
#include "core/string.h"
|
||||
|
||||
#include "core/resource.h"
|
||||
|
||||
class RBACPermission : public Resource {
|
||||
RCPP_OBJECT(RBACPermission, Resource);
|
||||
|
||||
public:
|
||||
int id;
|
||||
int rank_id;
|
||||
String name;
|
||||
String url;
|
||||
int sort_order;
|
||||
int permissions;
|
||||
|
||||
bool is_smaller(const Ref<RBACPermission> &b) const;
|
||||
|
||||
RBACPermission();
|
||||
~RBACPermission();
|
||||
};
|
||||
|
||||
#endif
|
77
modules/web/nodes/rbac/rbac_rank.cpp
Normal file
77
modules/web/nodes/rbac/rbac_rank.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
#include "rbac_rank.h"
|
||||
|
||||
#include "web/http/request.h"
|
||||
|
||||
Ref<RBACPermission> RBACRank::match_request(Request *request) {
|
||||
const String &full_path = request->get_path_full();
|
||||
|
||||
Ref<RBACPermission> perm;
|
||||
int current_max = 0;
|
||||
|
||||
for (int i = 0; i < permissions.size(); ++i) {
|
||||
Ref<RBACPermission> p;
|
||||
|
||||
if (!p.is_valid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int c = full_path.first_difference_index(p->url);
|
||||
|
||||
if (c > current_max) {
|
||||
perm = p;
|
||||
current_max = c;
|
||||
}
|
||||
}
|
||||
|
||||
return perm;
|
||||
}
|
||||
|
||||
bool RBACRank::get_permissions(Request *request) {
|
||||
int perm = base_permissions;
|
||||
|
||||
Ref<RBACPermission> match = match_request(request);
|
||||
|
||||
if (match.is_valid()) {
|
||||
perm = match->permissions;
|
||||
}
|
||||
|
||||
return perm;
|
||||
}
|
||||
|
||||
bool RBACRank::has_permission(Request *request, const int permission) {
|
||||
int perm = base_permissions;
|
||||
|
||||
Ref<RBACPermission> match = match_request(request);
|
||||
|
||||
if (match.is_valid()) {
|
||||
perm = match->permissions;
|
||||
}
|
||||
|
||||
return (perm & permission) != 0;
|
||||
}
|
||||
|
||||
bool RBACRank::has_rank_permission(const int permission) {
|
||||
return (rank_permissions & permission) != 0;
|
||||
}
|
||||
|
||||
void RBACRank::sort_permissions() {
|
||||
for (int i = 0; i < permissions.size(); ++i) {
|
||||
for (int j = i + 1; j < permissions.size(); ++j) {
|
||||
if (permissions[j]->is_smaller(permissions[i])) {
|
||||
permissions.swap(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RBACRank::RBACRank() :
|
||||
Resource() {
|
||||
|
||||
id = 0;
|
||||
base_permissions = 0;
|
||||
rank_permissions = 0;
|
||||
}
|
||||
|
||||
RBACRank::~RBACRank() {
|
||||
permissions.clear();
|
||||
}
|
40
modules/web/nodes/rbac/rbac_rank.h
Normal file
40
modules/web/nodes/rbac/rbac_rank.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef RBAC_RANK_H
|
||||
#define RBAC_RANK_H
|
||||
|
||||
#include "core/string.h"
|
||||
#include "core/containers/vector.h"
|
||||
|
||||
#include "core/resource.h"
|
||||
|
||||
#include "rbac_permission.h"
|
||||
|
||||
class Request;
|
||||
|
||||
class RBACRank : public Resource {
|
||||
RCPP_OBJECT(RBACRank, Resource);
|
||||
|
||||
public:
|
||||
int id;
|
||||
|
||||
String name;
|
||||
String name_internal;
|
||||
String settings;
|
||||
|
||||
int base_permissions;
|
||||
int rank_permissions;
|
||||
|
||||
Vector<Ref<RBACPermission> > permissions;
|
||||
|
||||
Ref<RBACPermission> match_request(Request *request);
|
||||
|
||||
bool get_permissions(Request *request);
|
||||
bool has_permission(Request *request, const int permission);
|
||||
bool has_rank_permission(const int permission);
|
||||
|
||||
void sort_permissions();
|
||||
|
||||
RBACRank();
|
||||
~RBACRank();
|
||||
};
|
||||
|
||||
#endif
|
12
modules/web/nodes/rbac_users/SCsub
Normal file
12
modules/web/nodes/rbac_users/SCsub
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env_mod")
|
||||
Import("env")
|
||||
|
||||
env_mod.core_sources = []
|
||||
|
||||
env_mod.add_source_files(env_mod.core_sources, "*.cpp")
|
||||
|
||||
# Build it all as a library
|
||||
lib = env_mod.add_library("users", env_mod.core_sources)
|
||||
env.Prepend(LIBS=[lib])
|
33
modules/web/nodes/rbac_users/detect.py
Normal file
33
modules/web/nodes/rbac_users/detect.py
Normal file
@ -0,0 +1,33 @@
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
|
||||
def is_active():
|
||||
return True
|
||||
|
||||
|
||||
def get_name():
|
||||
return "users"
|
||||
|
||||
|
||||
def can_build():
|
||||
return True
|
||||
|
||||
|
||||
def get_opts():
|
||||
return []
|
||||
|
||||
def get_flags():
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
|
||||
def get_module_dependencies():
|
||||
return [
|
||||
"users",
|
||||
"rbac"
|
||||
]
|
37
modules/web/nodes/rbac_users/rbac_user.cpp
Normal file
37
modules/web/nodes/rbac_users/rbac_user.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include "rbac_user.h"
|
||||
|
||||
int RBACUser::get_permissions(Request *request) {
|
||||
if (!rbac_rank.is_valid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return rbac_rank->get_permissions(request);
|
||||
}
|
||||
bool RBACUser::has_permission(Request *request, const int permission) {
|
||||
if (!rbac_rank.is_valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return rbac_rank->has_permission(request, permission);
|
||||
}
|
||||
int RBACUser::get_additional_permissions(Request *request) {
|
||||
if (!rbac_rank.is_valid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return rbac_rank->rank_permissions;
|
||||
}
|
||||
bool RBACUser::has_additional_permission(Request *request, const int permission) {
|
||||
if (!rbac_rank.is_valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return rbac_rank->rank_permissions & permission;
|
||||
}
|
||||
|
||||
RBACUser::RBACUser() :
|
||||
User() {
|
||||
}
|
||||
|
||||
RBACUser::~RBACUser() {
|
||||
}
|
27
modules/web/nodes/rbac_users/rbac_user.h
Normal file
27
modules/web/nodes/rbac_users/rbac_user.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef RBAC_USER_H
|
||||
#define RBAC_USER_H
|
||||
|
||||
#include "core/string.h"
|
||||
|
||||
#include "web_modules/users/user.h"
|
||||
#include "web_modules/rbac/rbac_rank.h"
|
||||
|
||||
class Request;
|
||||
class FormValidator;
|
||||
|
||||
class RBACUser : public User {
|
||||
RCPP_OBJECT(RBACUser, User);
|
||||
|
||||
public:
|
||||
Ref<RBACRank> rbac_rank;
|
||||
|
||||
int get_permissions(Request *request);
|
||||
bool has_permission(Request *request, const int permission);
|
||||
int get_additional_permissions(Request *request);
|
||||
bool has_additional_permission(Request *request, const int permission);
|
||||
|
||||
RBACUser();
|
||||
~RBACUser();
|
||||
};
|
||||
|
||||
#endif
|
146
modules/web/nodes/rbac_users/rbac_user_controller.cpp
Normal file
146
modules/web/nodes/rbac_users/rbac_user_controller.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
#include "rbac_user_controller.h"
|
||||
|
||||
#include "web/http/http_session.h"
|
||||
#include "web/http/request.h"
|
||||
|
||||
#include "web_modules/rbac/rbac_controller.h"
|
||||
#include "web_modules/rbac/rbac_default_permissions.h"
|
||||
#include "rbac_user.h"
|
||||
|
||||
Ref<User> RBACUserController::db_get_user(const int id) {
|
||||
Ref<RBACUser> u = UserController::db_get_user(id);
|
||||
|
||||
if (u.is_valid()) {
|
||||
u->rbac_rank = RBACController::get_singleton()->get_rank(u->rank);
|
||||
}
|
||||
|
||||
return u;
|
||||
}
|
||||
Ref<User> RBACUserController::db_get_user(const String &user_name_input) {
|
||||
Ref<RBACUser> u = UserController::db_get_user(user_name_input);
|
||||
|
||||
if (u.is_valid()) {
|
||||
u->rbac_rank = RBACController::get_singleton()->get_rank(u->rank);
|
||||
}
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
Vector<Ref<User> > RBACUserController::db_get_all() {
|
||||
Vector<Ref<User> > users = UserController::db_get_all();
|
||||
|
||||
for (int i = 0; i < users.size(); ++i) {
|
||||
Ref<RBACUser> u = users[i];
|
||||
|
||||
if (u.is_valid()) {
|
||||
u->rbac_rank = RBACController::get_singleton()->get_rank(u->rank);
|
||||
}
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
|
||||
Ref<User> RBACUserController::create_user() {
|
||||
Ref<RBACUser> u;
|
||||
u.instance();
|
||||
|
||||
u->rank = RBACController::get_singleton()->get_default_user_rank_id();
|
||||
u->rbac_rank = RBACController::get_singleton()->get_rank(u->rank);
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
RBACUserController::RBACUserController() :
|
||||
UserController() {
|
||||
}
|
||||
|
||||
RBACUserController::~RBACUserController() {
|
||||
}
|
||||
|
||||
// returnring true means handled, false means continue
|
||||
bool RBACUserSessionSetupMiddleware::on_before_handle_request_main(Request *request) {
|
||||
if (request->session.is_valid()) {
|
||||
int user_id = request->session->get_int("user_id");
|
||||
|
||||
if (user_id != 0) {
|
||||
|
||||
Ref<RBACUser> u = UserController::get_singleton()->db_get_user(user_id);
|
||||
|
||||
if (u.is_valid()) {
|
||||
request->reference_data["user"] = u;
|
||||
} else {
|
||||
// log
|
||||
request->session->remove("user_id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
RBACUserSessionSetupMiddleware::RBACUserSessionSetupMiddleware() {
|
||||
}
|
||||
RBACUserSessionSetupMiddleware::~RBACUserSessionSetupMiddleware() {
|
||||
}
|
||||
|
||||
// returnring true means handled, false means continue
|
||||
bool RBACDefaultUserSessionSetupMiddleware::on_before_handle_request_main(Request *request) {
|
||||
// note: add a new file handler middleware func, so basic file handling is easy to set up before this
|
||||
|
||||
Ref<RBACRank> rank;
|
||||
|
||||
if (request->session.is_valid()) {
|
||||
int user_id = request->session->get_int("user_id");
|
||||
|
||||
if (user_id != 0) {
|
||||
|
||||
Ref<RBACUser> u = UserController::get_singleton()->db_get_user(user_id);
|
||||
|
||||
if (u.is_valid()) {
|
||||
rank = u->rbac_rank;
|
||||
|
||||
request->reference_data["user"] = u;
|
||||
} else {
|
||||
// log
|
||||
request->session->remove("user_id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!rank.is_valid()) {
|
||||
rank = RBACController::get_singleton()->get_default_rank();
|
||||
|
||||
if (!rank.is_valid()) {
|
||||
if (RBACController::get_singleton()->continue_on_missing_default_rank()) {
|
||||
RLOG_ERR("get_default_rank() has not been set up properly!!! Continuing!");
|
||||
return false;
|
||||
} else {
|
||||
RLOG_ERR("get_default_rank() has not been set up properly!!! Sending 404!");
|
||||
request->send_error(404);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!rank->has_permission(request, User::PERMISSION_READ)) {
|
||||
if (rank->has_rank_permission(RBAC_RANK_PERMISSION_USE_REDIRECT)) {
|
||||
// Note this can make the webapp prone to enumerations, if not done correctly
|
||||
// e.g. redirect from /admin, but sending 404 on a non existing uri, which does not have
|
||||
// a special rbac entry
|
||||
request->send_redirect(RBACController::get_singleton()->get_redirect_url());
|
||||
return true;
|
||||
}
|
||||
|
||||
request->send_error(404);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
RBACDefaultUserSessionSetupMiddleware::RBACDefaultUserSessionSetupMiddleware() {
|
||||
}
|
||||
RBACDefaultUserSessionSetupMiddleware::~RBACDefaultUserSessionSetupMiddleware() {
|
||||
}
|
54
modules/web/nodes/rbac_users/rbac_user_controller.h
Normal file
54
modules/web/nodes/rbac_users/rbac_user_controller.h
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef RBAC_USER_CONTROLLER_H
|
||||
#define RBAC_USER_CONTROLLER_H
|
||||
|
||||
#include "web_modules/users/user_controller.h"
|
||||
|
||||
#include "web/http/middleware.h"
|
||||
|
||||
class Request;
|
||||
|
||||
class RBACUserController : public UserController {
|
||||
RCPP_OBJECT(RBACUserController, UserController);
|
||||
|
||||
public:
|
||||
// db
|
||||
|
||||
Ref<User> db_get_user(const int id);
|
||||
Ref<User> db_get_user(const String &user_name_input);
|
||||
|
||||
Vector<Ref<User> > db_get_all();
|
||||
|
||||
Ref<User> create_user();
|
||||
|
||||
RBACUserController();
|
||||
~RBACUserController();
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
// just session setup
|
||||
class RBACUserSessionSetupMiddleware : public Middleware {
|
||||
RCPP_OBJECT(RBACUserSessionSetupMiddleware, Middleware);
|
||||
|
||||
public:
|
||||
//returnring true means handled, false means continue
|
||||
bool on_before_handle_request_main(Request *request);
|
||||
|
||||
RBACUserSessionSetupMiddleware();
|
||||
~RBACUserSessionSetupMiddleware();
|
||||
};
|
||||
|
||||
// this one also handles missing read permission / redirect
|
||||
class RBACDefaultUserSessionSetupMiddleware : public Middleware {
|
||||
RCPP_OBJECT(RBACDefaultUserSessionSetupMiddleware, Middleware);
|
||||
|
||||
public:
|
||||
//returnring true means handled, false means continue
|
||||
bool on_before_handle_request_main(Request *request);
|
||||
|
||||
RBACDefaultUserSessionSetupMiddleware();
|
||||
~RBACDefaultUserSessionSetupMiddleware();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
12
modules/web/nodes/static_pages/SCsub
Normal file
12
modules/web/nodes/static_pages/SCsub
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env_mod")
|
||||
Import("env")
|
||||
|
||||
env_mod.core_sources = []
|
||||
|
||||
env_mod.add_source_files(env_mod.core_sources, "*.cpp")
|
||||
|
||||
# Build it all as a library
|
||||
lib = env_mod.add_library("paged_list", env_mod.core_sources)
|
||||
env.Prepend(LIBS=[lib])
|
27
modules/web/nodes/static_pages/detect.py
Normal file
27
modules/web/nodes/static_pages/detect.py
Normal file
@ -0,0 +1,27 @@
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
|
||||
def is_active():
|
||||
return True
|
||||
|
||||
|
||||
def get_name():
|
||||
return "paged_list"
|
||||
|
||||
|
||||
def can_build():
|
||||
return True
|
||||
|
||||
|
||||
def get_opts():
|
||||
return []
|
||||
|
||||
def get_flags():
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
73
modules/web/nodes/static_pages/static_page.cpp
Normal file
73
modules/web/nodes/static_pages/static_page.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
#include "static_page.h"
|
||||
|
||||
#include "core/os/directory.h"
|
||||
#include "web/file_cache.h"
|
||||
#include "web/html/html_builder.h"
|
||||
#include "web/html/utils.h"
|
||||
#include "web/http/request.h"
|
||||
|
||||
void StaticPage::_handle_request_main(Request *request) {
|
||||
if (should_render_menu) {
|
||||
render_menu(request);
|
||||
}
|
||||
|
||||
render_index(request);
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void StaticPage::render_index(Request *request) {
|
||||
request->body += data;
|
||||
}
|
||||
|
||||
void StaticPage::render_preview(Request *request) {
|
||||
request->body += preview_data;
|
||||
}
|
||||
|
||||
void StaticPage::load_file(const String &path) {
|
||||
Ref<Directory> d;
|
||||
d.instance();
|
||||
|
||||
d->read_file_into(path, &data);
|
||||
}
|
||||
|
||||
void StaticPage::load_and_process_file(const String &path) {
|
||||
Ref<Directory> d;
|
||||
d.instance();
|
||||
|
||||
d->read_file_into(path, &data);
|
||||
|
||||
if (path.file_get_extension() == "md") {
|
||||
Utils::markdown_to_html(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void StaticPage::load_md_file(const String &path) {
|
||||
Ref<Directory> d;
|
||||
d.instance();
|
||||
|
||||
d->read_file_into(path, &data);
|
||||
Utils::markdown_to_html(&data);
|
||||
}
|
||||
|
||||
void StaticPage::set_data_md(const String &d) {
|
||||
data.clear();
|
||||
|
||||
Utils::markdown_to_html(&data);
|
||||
}
|
||||
|
||||
void StaticPage::set_data(const String &d) {
|
||||
data = d;
|
||||
}
|
||||
|
||||
void StaticPage::set_preview_data(const String &d) {
|
||||
preview_data = d;
|
||||
}
|
||||
|
||||
StaticPage::StaticPage() :
|
||||
WebNode() {
|
||||
|
||||
should_render_menu = true;
|
||||
}
|
||||
|
||||
StaticPage::~StaticPage() {
|
||||
}
|
33
modules/web/nodes/static_pages/static_page.h
Normal file
33
modules/web/nodes/static_pages/static_page.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef STATIC_PAGE_H
|
||||
#define STATIC_PAGE_H
|
||||
|
||||
#include "core/string.h"
|
||||
|
||||
#include "web/http/web_node.h"
|
||||
|
||||
class StaticPage : public WebNode {
|
||||
RCPP_OBJECT(StaticPage, WebNode);
|
||||
|
||||
public:
|
||||
void _handle_request_main(Request *request);
|
||||
|
||||
void render_index(Request *request);
|
||||
void render_preview(Request *request);
|
||||
|
||||
void load_file(const String &path);
|
||||
void load_and_process_file(const String &path);
|
||||
void load_md_file(const String &path);
|
||||
|
||||
void set_data_md(const String &d);
|
||||
void set_data(const String &d);
|
||||
void set_preview_data(const String &d);
|
||||
|
||||
String data;
|
||||
String preview_data;
|
||||
bool should_render_menu;
|
||||
|
||||
StaticPage();
|
||||
~StaticPage();
|
||||
};
|
||||
|
||||
#endif
|
36
modules/web/nodes/static_pages/static_page_file.cpp
Normal file
36
modules/web/nodes/static_pages/static_page_file.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
#include "static_page_file.h"
|
||||
|
||||
#include "web/file_cache.h"
|
||||
#include "web/html/html_builder.h"
|
||||
#include "web/http/request.h"
|
||||
|
||||
void StaticPageFile::load() {
|
||||
if (file_path == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (process_if_can) {
|
||||
load_and_process_file(file_path);
|
||||
} else {
|
||||
load_file(file_path);
|
||||
}
|
||||
}
|
||||
|
||||
void StaticPageFile::_notification(const int what) {
|
||||
switch (what) {
|
||||
case NOTIFICATION_ENTER_TREE:
|
||||
load();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
StaticPageFile::StaticPageFile() :
|
||||
StaticPage() {
|
||||
|
||||
process_if_can = true;
|
||||
}
|
||||
|
||||
StaticPageFile::~StaticPageFile() {
|
||||
}
|
23
modules/web/nodes/static_pages/static_page_file.h
Normal file
23
modules/web/nodes/static_pages/static_page_file.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef STATIC_PAGE_FILE_H
|
||||
#define STATIC_PAGE_FILE_H
|
||||
|
||||
#include "core/string.h"
|
||||
|
||||
#include "static_page.h"
|
||||
|
||||
class StaticPageFile : public StaticPage {
|
||||
RCPP_OBJECT(StaticPageFile, StaticPage);
|
||||
|
||||
public:
|
||||
void load();
|
||||
|
||||
void _notification(const int what);
|
||||
|
||||
String file_path;
|
||||
bool process_if_can;
|
||||
|
||||
StaticPageFile();
|
||||
~StaticPageFile();
|
||||
};
|
||||
|
||||
#endif
|
57
modules/web/nodes/static_pages/static_page_folder_files.cpp
Normal file
57
modules/web/nodes/static_pages/static_page_folder_files.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include "static_page_folder_files.h"
|
||||
|
||||
#include "core/os/directory.h"
|
||||
#include "web/file_cache.h"
|
||||
#include "web/html/html_builder.h"
|
||||
#include "web/html/utils.h"
|
||||
#include "web/http/request.h"
|
||||
|
||||
void StaticPageFolderFiles::load() {
|
||||
if (dir_path == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<Directory> d;
|
||||
d.instance();
|
||||
|
||||
ERR_FAIL_COND_MSG(!d->open_dir(dir_path), "Dir Path = " + dir_path);
|
||||
|
||||
String str;
|
||||
while (d->has_next()) {
|
||||
if (d->current_is_file()) {
|
||||
String fn = dir_path;
|
||||
fn.append_path(d->current_get_name_cstr());
|
||||
|
||||
d->read_file_into(fn, &str);
|
||||
|
||||
if (process_if_can && d->current_get_extension() == "md") {
|
||||
Utils::markdown_to_html(&str);
|
||||
}
|
||||
|
||||
append_data(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StaticPageFolderFiles::append_data(const String &d) {
|
||||
data += d;
|
||||
}
|
||||
|
||||
void StaticPageFolderFiles::_notification(const int what) {
|
||||
switch (what) {
|
||||
case NOTIFICATION_ENTER_TREE:
|
||||
load();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
StaticPageFolderFiles::StaticPageFolderFiles() :
|
||||
StaticPage() {
|
||||
|
||||
process_if_can = true;
|
||||
}
|
||||
|
||||
StaticPageFolderFiles::~StaticPageFolderFiles() {
|
||||
}
|
24
modules/web/nodes/static_pages/static_page_folder_files.h
Normal file
24
modules/web/nodes/static_pages/static_page_folder_files.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef STATIC_PAGE_FOLDER_FILES_H
|
||||
#define STATIC_PAGE_FOLDER_FILES_H
|
||||
|
||||
#include "core/string.h"
|
||||
|
||||
#include "static_page.h"
|
||||
|
||||
class StaticPageFolderFiles : public StaticPage {
|
||||
RCPP_OBJECT(StaticPageFolderFiles, StaticPage);
|
||||
|
||||
public:
|
||||
void load();
|
||||
virtual void append_data(const String &d);
|
||||
|
||||
void _notification(const int what);
|
||||
|
||||
String dir_path;
|
||||
bool process_if_can;
|
||||
|
||||
StaticPageFolderFiles();
|
||||
~StaticPageFolderFiles();
|
||||
};
|
||||
|
||||
#endif
|
12
modules/web/nodes/users/SCsub
Normal file
12
modules/web/nodes/users/SCsub
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env_mod")
|
||||
Import("env")
|
||||
|
||||
env_mod.core_sources = []
|
||||
|
||||
env_mod.add_source_files(env_mod.core_sources, "*.cpp")
|
||||
|
||||
# Build it all as a library
|
||||
lib = env_mod.add_library("users", env_mod.core_sources)
|
||||
env.Prepend(LIBS=[lib])
|
27
modules/web/nodes/users/detect.py
Normal file
27
modules/web/nodes/users/detect.py
Normal file
@ -0,0 +1,27 @@
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
|
||||
def is_active():
|
||||
return True
|
||||
|
||||
|
||||
def get_name():
|
||||
return "users"
|
||||
|
||||
|
||||
def can_build():
|
||||
return True
|
||||
|
||||
|
||||
def get_opts():
|
||||
return []
|
||||
|
||||
def get_flags():
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
107
modules/web/nodes/users/user.cpp
Normal file
107
modules/web/nodes/users/user.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
#include "user.h"
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/rapidjson.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include <rapidjson/writer.h>
|
||||
#include <tinydir/tinydir.h>
|
||||
#include <cstdio>
|
||||
|
||||
#include "database/database_manager.h"
|
||||
#include "database/query_builder.h"
|
||||
#include "database/query_result.h"
|
||||
#include "database/table_builder.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/html/utils.h"
|
||||
|
||||
String User::to_json(rapidjson::Document *into) {
|
||||
rapidjson::Document *document;
|
||||
|
||||
if (into) {
|
||||
document = into;
|
||||
} else {
|
||||
document = new rapidjson::Document();
|
||||
}
|
||||
|
||||
document->SetObject();
|
||||
|
||||
document->AddMember("id", id, document->GetAllocator());
|
||||
|
||||
document->AddMember("name", rapidjson::Value(name_user_input.c_str(), document->GetAllocator()), document->GetAllocator());
|
||||
document->AddMember("email", rapidjson::Value(email_user_input.c_str(), document->GetAllocator()), document->GetAllocator());
|
||||
document->AddMember("rank", rank, document->GetAllocator());
|
||||
document->AddMember("pre_salt", rapidjson::Value(pre_salt.c_str(), document->GetAllocator()), document->GetAllocator());
|
||||
document->AddMember("post_salt", rapidjson::Value(post_salt.c_str(), document->GetAllocator()), document->GetAllocator());
|
||||
document->AddMember("password_hash", rapidjson::Value(password_hash.c_str(), document->GetAllocator()), document->GetAllocator());
|
||||
document->AddMember("banned", banned, document->GetAllocator());
|
||||
document->AddMember("password_reset_token", rapidjson::Value(password_reset_token.c_str(), document->GetAllocator()), document->GetAllocator());
|
||||
document->AddMember("locked", locked, document->GetAllocator());
|
||||
|
||||
if (into) {
|
||||
return "";
|
||||
}
|
||||
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||
document->Accept(writer);
|
||||
|
||||
String s = buffer.GetString();
|
||||
|
||||
delete document;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void User::from_json(const String &p_data) {
|
||||
|
||||
rapidjson::Document data;
|
||||
data.Parse(p_data.c_str());
|
||||
|
||||
rapidjson::Value uobj = data.GetObject();
|
||||
|
||||
id = uobj["id"].GetInt();
|
||||
name_user_input = uobj["name"].GetString();
|
||||
email_user_input = uobj["email"].GetString();
|
||||
rank = uobj["rank"].GetInt();
|
||||
pre_salt = uobj["pre_salt"].GetString();
|
||||
post_salt = uobj["post_salt"].GetString();
|
||||
password_hash = uobj["password_hash"].GetString();
|
||||
banned = uobj["banned"].GetBool();
|
||||
|
||||
password_reset_token = uobj["password_reset_token"].GetString();
|
||||
locked = uobj["locked"].GetBool();
|
||||
}
|
||||
|
||||
int User::get_permissions(Request *request) {
|
||||
return PERMISSION_ALL;
|
||||
}
|
||||
|
||||
bool User::has_permission(Request *request, const int permission) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int User::get_additional_permissions(Request *request) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool User::has_additional_permission(Request *request, const int permission) {
|
||||
return true;
|
||||
}
|
||||
|
||||
User::User() :
|
||||
Resource() {
|
||||
|
||||
rank = 0;
|
||||
banned = false;
|
||||
locked = false;
|
||||
}
|
||||
|
||||
User::~User() {
|
||||
}
|
49
modules/web/nodes/users/user.h
Normal file
49
modules/web/nodes/users/user.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef USER_H
|
||||
#define USER_H
|
||||
|
||||
#include "core/string.h"
|
||||
|
||||
#include "core/resource.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include <mutex>
|
||||
|
||||
class Request;
|
||||
class FormValidator;
|
||||
|
||||
class User : public Resource {
|
||||
RCPP_OBJECT(User, Resource);
|
||||
|
||||
public:
|
||||
enum Permissions {
|
||||
PERMISSION_CREATE = 1 << 0,
|
||||
PERMISSION_READ = 1 << 1,
|
||||
PERMISSION_UPDATE = 1 << 2,
|
||||
PERMISSION_DELETE = 1 << 3,
|
||||
|
||||
PERMISSION_ALL = PERMISSION_CREATE | PERMISSION_READ | PERMISSION_UPDATE | PERMISSION_DELETE,
|
||||
PERMISSION_NONE = 0
|
||||
};
|
||||
|
||||
String name_user_input;
|
||||
String email_user_input;
|
||||
int rank;
|
||||
String pre_salt;
|
||||
String post_salt;
|
||||
String password_hash;
|
||||
bool banned;
|
||||
String password_reset_token;
|
||||
bool locked;
|
||||
|
||||
String to_json(rapidjson::Document *into = nullptr);
|
||||
void from_json(const String &data);
|
||||
|
||||
virtual int get_permissions(Request *request);
|
||||
virtual bool has_permission(Request *request, const int permission);
|
||||
virtual int get_additional_permissions(Request *request);
|
||||
virtual bool has_additional_permission(Request *request, const int permission);
|
||||
|
||||
User();
|
||||
~User();
|
||||
};
|
||||
|
||||
#endif
|
828
modules/web/nodes/users/user_controller.cpp
Normal file
828
modules/web/nodes/users/user_controller.cpp
Normal file
@ -0,0 +1,828 @@
|
||||
#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 "database/database.h"
|
||||
#include "database/database_manager.h"
|
||||
#include "database/query_builder.h"
|
||||
#include "database/query_result.h"
|
||||
#include "database/table_builder.h"
|
||||
|
||||
#include "crypto/hash/sha256.h"
|
||||
|
||||
void UserController::handle_request_main(Request *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 (u.is_valid()) {
|
||||
handle_request(u, request);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const String &segment = request->get_current_path_segment();
|
||||
|
||||
if (segment == "") {
|
||||
handle_login_request_default(request);
|
||||
|
||||
return;
|
||||
} else if (segment == "login") {
|
||||
handle_login_request_default(request);
|
||||
|
||||
return;
|
||||
} else if (segment == "register") {
|
||||
handle_register_request_default(request);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
handle_login_request_default(request);
|
||||
}
|
||||
|
||||
void UserController::handle_login_request_default(Request *request) {
|
||||
LoginRequestData data;
|
||||
|
||||
if (request->get_method() == 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);
|
||||
for (int i = 0; i < errors.size(); ++i) {
|
||||
data.error_str += errors[i] + "<br>";
|
||||
}
|
||||
// not needed end
|
||||
|
||||
data.uname_val = request->get_parameter("username");
|
||||
data.pass_val = request->get_parameter("password");
|
||||
|
||||
Ref<User> user = db_get_user(data.uname_val);
|
||||
|
||||
if (user.is_valid()) {
|
||||
if (!check_password(user, 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);
|
||||
|
||||
::Cookie c = ::Cookie("session_id", session->session_id);
|
||||
c.path = "/";
|
||||
|
||||
request->add_cookie(c);
|
||||
|
||||
render_login_success(request);
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
data.error_str += "Invalid username or password!";
|
||||
}
|
||||
}
|
||||
|
||||
render_login_request_default(request, &data);
|
||||
}
|
||||
|
||||
void UserController::render_login_request_default(Request *request, LoginRequestData *data) {
|
||||
HTMLBuilder b;
|
||||
|
||||
b.w("Login");
|
||||
b.br();
|
||||
|
||||
{
|
||||
if (data->error_str.size() != 0) {
|
||||
b.div()->cls("error");
|
||||
|
||||
b.w(data->error_str);
|
||||
|
||||
b.cdiv();
|
||||
}
|
||||
}
|
||||
|
||||
b.div()->cls("login");
|
||||
{
|
||||
|
||||
// todo href path helper
|
||||
b.form()->method("POST")->href("/user/login");
|
||||
{
|
||||
b.csrf_token(request);
|
||||
|
||||
b.w("Username");
|
||||
b.br();
|
||||
b.input()->type("text")->name("username")->value(data->uname_val);
|
||||
b.cinput();
|
||||
b.br();
|
||||
|
||||
b.w("Password");
|
||||
b.br();
|
||||
b.input()->type("password")->name("password");
|
||||
b.cinput();
|
||||
b.br();
|
||||
|
||||
b.input()->type("submit")->value("Send");
|
||||
b.cinput();
|
||||
}
|
||||
b.cform();
|
||||
}
|
||||
b.cdiv();
|
||||
|
||||
request->body += b.result;
|
||||
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void UserController::handle_register_request_default(Request *request) {
|
||||
RegisterRequestData data;
|
||||
|
||||
if (request->get_method() == HTTP_METHOD_POST) {
|
||||
|
||||
Vector<String> errors;
|
||||
|
||||
_registration_validator->validate(request, &errors);
|
||||
|
||||
for (int i = 0; i < errors.size(); ++i) {
|
||||
data.error_str += errors[i] + "<br>";
|
||||
}
|
||||
|
||||
data.uname_val = request->get_parameter("username");
|
||||
data.email_val = request->get_parameter("email");
|
||||
data.pass_val = request->get_parameter("password");
|
||||
data.pass_check_val = request->get_parameter("password_check");
|
||||
|
||||
// todo username length etc check
|
||||
// todo pw length etc check
|
||||
|
||||
if (is_username_taken(data.uname_val)) {
|
||||
data.error_str += "Username already taken!<br>";
|
||||
}
|
||||
|
||||
if (is_email_taken(data.email_val)) {
|
||||
data.error_str += "Email already in use!<br>";
|
||||
}
|
||||
|
||||
if (data.pass_val != data.pass_check_val) {
|
||||
data.error_str += "The passwords did not match!<br>";
|
||||
}
|
||||
|
||||
if (data.error_str.size() == 0) {
|
||||
Ref<User> user;
|
||||
user = create_user();
|
||||
|
||||
user->name_user_input = data.uname_val;
|
||||
user->email_user_input = data.email_val;
|
||||
|
||||
create_password(user, data.pass_val);
|
||||
db_save_user(user);
|
||||
|
||||
render_register_success(request);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
render_register_request_default(request, &data);
|
||||
}
|
||||
|
||||
void UserController::render_register_success(Request *request) {
|
||||
HTMLBuilder b;
|
||||
|
||||
b.div()->cls("success");
|
||||
{
|
||||
b.w("Registration successful! You can now log in!");
|
||||
b.br();
|
||||
b.a()->href("/user/login");
|
||||
b.w(">> Login <<");
|
||||
b.ca();
|
||||
}
|
||||
b.cdiv();
|
||||
|
||||
request->body += b.result;
|
||||
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void UserController::render_register_request_default(Request *request, RegisterRequestData *data) {
|
||||
HTMLBuilder b;
|
||||
|
||||
b.w("Registration");
|
||||
b.br();
|
||||
|
||||
{
|
||||
if (data->error_str.size() != 0) {
|
||||
b.div()->cls("error");
|
||||
|
||||
b.w(data->error_str);
|
||||
|
||||
b.cdiv();
|
||||
}
|
||||
}
|
||||
|
||||
b.div()->cls("register");
|
||||
{
|
||||
// todo href path helper
|
||||
b.form()->method("POST")->href("/user/register");
|
||||
{
|
||||
b.csrf_token(request);
|
||||
|
||||
b.w("Username");
|
||||
b.br();
|
||||
b.input()->type("text")->name("username")->value(data->uname_val);
|
||||
b.cinput();
|
||||
b.br();
|
||||
|
||||
b.w("Email");
|
||||
b.br();
|
||||
b.input()->type("email")->name("email")->value(data->email_val);
|
||||
b.cinput();
|
||||
b.br();
|
||||
|
||||
b.w("Password");
|
||||
b.br();
|
||||
b.input()->type("password")->name("password");
|
||||
b.cinput();
|
||||
b.br();
|
||||
|
||||
b.w("Password again");
|
||||
b.br();
|
||||
b.input()->type("password")->name("password_check");
|
||||
b.cinput();
|
||||
b.br();
|
||||
|
||||
b.input()->type("submit")->value("Register");
|
||||
b.cinput();
|
||||
}
|
||||
b.cform();
|
||||
}
|
||||
b.cdiv();
|
||||
|
||||
request->body += b.result;
|
||||
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void UserController::render_already_logged_in_error(Request *request) {
|
||||
request->body += "You are already logged in.";
|
||||
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void UserController::render_login_success(Request *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) {
|
||||
const String &segment = request->get_current_path_segment();
|
||||
|
||||
if (segment == "") {
|
||||
handle_main_page_request(user, request);
|
||||
} else if (segment == "settings") {
|
||||
handle_settings_request(user, request);
|
||||
} else if (segment == "password_reset") {
|
||||
handle_password_reset_request(user, request);
|
||||
} else if (segment == "logout") {
|
||||
handle_logout_request(user, request);
|
||||
} else if (segment == "delete") {
|
||||
handle_delete_request(user, request);
|
||||
} else if (segment == "login") {
|
||||
render_already_logged_in_error(request);
|
||||
} else if (segment == "register") {
|
||||
render_already_logged_in_error(request);
|
||||
} else {
|
||||
request->send_error(404);
|
||||
}
|
||||
}
|
||||
|
||||
void UserController::handle_main_page_request(Ref<User> &user, Request *request) {
|
||||
request->body += "handle_main_page_request";
|
||||
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void UserController::handle_settings_request(Ref<User> &user, Request *request) {
|
||||
|
||||
SettingsRequestData data;
|
||||
|
||||
if (request->get_method() == HTTP_METHOD_POST) {
|
||||
|
||||
data.uname_val = request->get_parameter("username");
|
||||
data.email_val = request->get_parameter("email");
|
||||
data.pass_val = request->get_parameter("password");
|
||||
data.pass_check_val = request->get_parameter("password_check");
|
||||
|
||||
bool changed = false;
|
||||
|
||||
Vector<String> errors;
|
||||
|
||||
bool valid = _profile_validator->validate(request, &errors);
|
||||
|
||||
for (int i = 0; i < errors.size(); ++i) {
|
||||
data.error_str += errors[i] + "<br>";
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
if (data.uname_val == user->name_user_input) {
|
||||
data.uname_val = "";
|
||||
}
|
||||
|
||||
if (data.email_val == user->email_user_input) {
|
||||
data.email_val = "";
|
||||
}
|
||||
|
||||
if (data.uname_val != "") {
|
||||
if (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;
|
||||
changed = true;
|
||||
data.uname_val = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (data.email_val != "") {
|
||||
if (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;
|
||||
changed = true;
|
||||
data.email_val = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (data.pass_val != "") {
|
||||
if (data.pass_val != data.pass_check_val) {
|
||||
data.error_str += "The passwords did not match!<br>";
|
||||
} else {
|
||||
create_password(user, data.pass_val);
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
db_save_user(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render_settings_request(user, request, &data);
|
||||
}
|
||||
|
||||
void UserController::render_settings_request(Ref<User> &user, Request *request, SettingsRequestData *data) {
|
||||
HTMLBuilder b;
|
||||
|
||||
b.w("Settings");
|
||||
b.br();
|
||||
|
||||
{
|
||||
if (data->error_str.size() != 0) {
|
||||
b.div()->cls("error");
|
||||
|
||||
b.w(data->error_str);
|
||||
|
||||
b.cdiv();
|
||||
}
|
||||
}
|
||||
|
||||
b.div()->cls("settings");
|
||||
{
|
||||
// todo href path helper
|
||||
b.form()->method("POST")->href("/user/settings");
|
||||
{
|
||||
b.csrf_token(request);
|
||||
|
||||
b.w("Username");
|
||||
b.br();
|
||||
b.input()->type("text")->name("username")->placeholder(user->name_user_input)->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.cinput();
|
||||
b.br();
|
||||
|
||||
b.w("Password");
|
||||
b.br();
|
||||
b.input()->type("password")->placeholder("*******")->name("password");
|
||||
b.cinput();
|
||||
b.br();
|
||||
|
||||
b.w("Password again");
|
||||
b.br();
|
||||
b.input()->type("password")->placeholder("*******")->name("password_check");
|
||||
b.cinput();
|
||||
b.br();
|
||||
|
||||
b.input()->type("submit")->value("Save");
|
||||
b.cinput();
|
||||
}
|
||||
b.cform();
|
||||
}
|
||||
b.cdiv();
|
||||
|
||||
request->body += b.result;
|
||||
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void UserController::handle_password_reset_request(Ref<User> &user, Request *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");
|
||||
|
||||
db_save_user(user);
|
||||
|
||||
SessionManager::get_singleton()->delete_session(request->session->session_id);
|
||||
request->session = nullptr;
|
||||
|
||||
HTMLBuilder b;
|
||||
b.w("Logout successful!");
|
||||
request->body += b.result;
|
||||
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void UserController::handle_delete_request(Ref<User> &user, Request *request) {
|
||||
request->body += "handle_delete_request";
|
||||
|
||||
request->compile_and_send_body();
|
||||
}
|
||||
|
||||
void UserController::create_validators() {
|
||||
if (!_login_validator) {
|
||||
// Login
|
||||
_login_validator = new FormValidator();
|
||||
|
||||
_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");
|
||||
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->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");
|
||||
pw->need_to_exist();
|
||||
pw->need_to_have_lowercase_character()->need_to_have_uppercase_character();
|
||||
pw->need_minimum_length(5);
|
||||
|
||||
_registration_validator->new_field("password_check", "Password check")->need_to_match("password");
|
||||
|
||||
_registration_validator->new_field("email", "Email")->need_to_exist()->need_to_be_email();
|
||||
}
|
||||
|
||||
if (!_profile_validator) {
|
||||
_profile_validator = new FormValidator();
|
||||
|
||||
_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");
|
||||
pw->ignore_if_not_exists();
|
||||
pw->need_to_have_lowercase_character()->need_to_have_uppercase_character();
|
||||
pw->need_minimum_length(5);
|
||||
|
||||
_profile_validator->new_field("password_check", "Password check")->ignore_if_other_field_not_exists("password")->need_to_match("password");
|
||||
}
|
||||
}
|
||||
|
||||
Ref<User> UserController::db_get_user(const int id) {
|
||||
if (id == 0) {
|
||||
return Ref<User>();
|
||||
}
|
||||
|
||||
Ref<QueryBuilder> b = get_query_builder();
|
||||
|
||||
b->select("username, email, rank, pre_salt, post_salt, password_hash, banned, password_reset_token, locked");
|
||||
b->from(_table_name);
|
||||
|
||||
b->where()->wp("id", id);
|
||||
|
||||
b->end_command();
|
||||
|
||||
Ref<QueryResult> r = b->run();
|
||||
|
||||
if (!r->next_row()) {
|
||||
return Ref<User>();
|
||||
}
|
||||
|
||||
Ref<User> user;
|
||||
user = create_user();
|
||||
|
||||
user->id = id;
|
||||
user->name_user_input = r->get_cell(0);
|
||||
user->email_user_input = r->get_cell(1);
|
||||
user->rank = r->get_cell_int(2);
|
||||
user->pre_salt = r->get_cell(3);
|
||||
user->post_salt = r->get_cell(4);
|
||||
user->password_hash = r->get_cell(5);
|
||||
user->banned = r->get_cell_bool(6);
|
||||
user->password_reset_token = r->get_cell(7);
|
||||
user->locked = r->get_cell_bool(8);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
Ref<User> UserController::db_get_user(const String &user_name_input) {
|
||||
if (user_name_input == "") {
|
||||
return Ref<User>();
|
||||
}
|
||||
|
||||
Ref<QueryBuilder> b = get_query_builder();
|
||||
|
||||
b->select("id, email, rank, pre_salt, post_salt, password_hash, banned, password_reset_token, locked");
|
||||
b->from(_table_name);
|
||||
b->where()->wp("username", user_name_input);
|
||||
b->end_command();
|
||||
|
||||
Ref<QueryResult> r = b->run();
|
||||
|
||||
if (!r->next_row()) {
|
||||
return Ref<User>();
|
||||
}
|
||||
|
||||
Ref<User> user;
|
||||
user = create_user();
|
||||
|
||||
user->id = r->get_cell_int(0);
|
||||
user->name_user_input = user_name_input;
|
||||
user->email_user_input = r->get_cell(1);
|
||||
user->rank = r->get_cell_int(2);
|
||||
user->pre_salt = r->get_cell(3);
|
||||
user->post_salt = r->get_cell(4);
|
||||
user->password_hash = r->get_cell(5);
|
||||
user->banned = r->get_cell_bool(6);
|
||||
user->password_reset_token = r->get_cell(7);
|
||||
user->locked = r->get_cell_bool(8);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
void UserController::db_save_user(Ref<User> &user) {
|
||||
Ref<QueryBuilder> b = get_query_builder();
|
||||
|
||||
if (user->id == 0) {
|
||||
b->insert(_table_name, "username, email, rank, pre_salt, post_salt, password_hash, banned, password_reset_token, locked");
|
||||
|
||||
b->values();
|
||||
b->val(user->name_user_input);
|
||||
b->val(user->email_user_input);
|
||||
b->val(user->rank);
|
||||
b->val(user->pre_salt);
|
||||
b->val(user->post_salt);
|
||||
b->val(user->password_hash);
|
||||
b->val(user->banned);
|
||||
b->val(user->password_reset_token);
|
||||
b->val(user->locked);
|
||||
b->cvalues();
|
||||
|
||||
b->end_command();
|
||||
b->select_last_insert_id();
|
||||
|
||||
Ref<QueryResult> r = b->run();
|
||||
|
||||
user->id = r->get_last_insert_rowid();
|
||||
} else {
|
||||
b->update(_table_name);
|
||||
b->set();
|
||||
b->setp("username", user->name_user_input);
|
||||
b->setp("email", user->email_user_input);
|
||||
b->setp("rank", user->rank);
|
||||
b->setp("pre_salt", user->pre_salt);
|
||||
b->setp("post_salt", user->post_salt);
|
||||
b->setp("password_hash", user->password_hash);
|
||||
b->setp("banned", user->banned);
|
||||
b->setp("password_reset_token", user->password_reset_token);
|
||||
b->setp("locked", user->locked);
|
||||
b->cset();
|
||||
b->where()->wp("id", user->id);
|
||||
|
||||
// b->print();
|
||||
|
||||
b->run_query();
|
||||
}
|
||||
}
|
||||
|
||||
Vector<Ref<User> > UserController::db_get_all() {
|
||||
Ref<QueryBuilder> b = get_query_builder();
|
||||
|
||||
b->select("id, username, email, rank, pre_salt, post_salt, password_hash, banned, password_reset_token, locked");
|
||||
b->from(_table_name);
|
||||
b->end_command();
|
||||
// b->print();
|
||||
|
||||
Vector<Ref<User> > users;
|
||||
|
||||
Ref<QueryResult> r = b->run();
|
||||
|
||||
while (r->next_row()) {
|
||||
Ref<User> user = create_user();
|
||||
|
||||
user->id = r->get_cell_int(0);
|
||||
user->name_user_input = r->get_cell(1);
|
||||
user->email_user_input = r->get_cell(2);
|
||||
user->rank = r->get_cell_int(3);
|
||||
user->pre_salt = r->get_cell(4);
|
||||
user->post_salt = r->get_cell(5);
|
||||
user->password_hash = r->get_cell(6);
|
||||
user->banned = r->get_cell_bool(7);
|
||||
user->password_reset_token = r->get_cell(8);
|
||||
user->locked = r->get_cell_bool(9);
|
||||
|
||||
users.push_back(user);
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
|
||||
Ref<User> UserController::create_user() {
|
||||
Ref<User> u;
|
||||
u.instance();
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
bool UserController::is_username_taken(const String &user_name_input) {
|
||||
Ref<QueryBuilder> b = get_query_builder();
|
||||
|
||||
b->select("id")->from(_table_name)->where("username")->like(user_name_input)->end_command();
|
||||
|
||||
Ref<QueryResult> r = b->run();
|
||||
|
||||
return r->next_row();
|
||||
}
|
||||
bool UserController::is_email_taken(const String &email_input) {
|
||||
Ref<QueryBuilder> b = get_query_builder();
|
||||
|
||||
b->select("id")->from(_table_name)->where("username")->like(email_input)->end_command();
|
||||
|
||||
Ref<QueryResult> r = b->run();
|
||||
|
||||
return r->next_row();
|
||||
}
|
||||
|
||||
bool UserController::check_password(const Ref<User> &user, const String &p_password) {
|
||||
return hash_password(user, p_password) == user->password_hash;
|
||||
}
|
||||
|
||||
void UserController::create_password(Ref<User> &user, const String &p_password) {
|
||||
if (!user.is_valid()) {
|
||||
printf("Error UserController::create_password !user.is_valid()!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// todo improve a bit
|
||||
user->pre_salt = hash_password(user, user->name_user_input + user->email_user_input);
|
||||
user->post_salt = hash_password(user, user->email_user_input + user->name_user_input);
|
||||
|
||||
user->password_hash = hash_password(user, p_password);
|
||||
}
|
||||
|
||||
String UserController::hash_password(const Ref<User> &user, const String &p_password) {
|
||||
if (!user.is_valid()) {
|
||||
printf("Error UserController::hash_password !user.is_valid()!\n");
|
||||
return "";
|
||||
}
|
||||
|
||||
Ref<SHA256> s = SHA256::get();
|
||||
|
||||
String p = user->pre_salt + p_password + user->post_salt;
|
||||
|
||||
String c = s->compute(p);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void UserController::create_table() {
|
||||
Ref<TableBuilder> tb = get_table_builder();
|
||||
|
||||
tb->create_table(_table_name);
|
||||
tb->integer("id")->auto_increment()->next_row();
|
||||
tb->varchar("username", 60)->not_null()->next_row();
|
||||
tb->varchar("email", 100)->not_null()->next_row();
|
||||
tb->integer("rank")->not_null()->next_row();
|
||||
tb->varchar("pre_salt", 100)->next_row();
|
||||
tb->varchar("post_salt", 100)->next_row();
|
||||
tb->varchar("password_hash", 100)->next_row();
|
||||
tb->integer("banned")->next_row();
|
||||
tb->varchar("password_reset_token", 100)->next_row();
|
||||
tb->integer("locked")->next_row();
|
||||
tb->primary_key("id");
|
||||
tb->ccreate_table();
|
||||
tb->run_query();
|
||||
// tb->print();
|
||||
}
|
||||
void UserController::drop_table() {
|
||||
Ref<TableBuilder> tb = get_table_builder();
|
||||
|
||||
tb->drop_table_if_exists(_table_name)->run_query();
|
||||
}
|
||||
|
||||
void UserController::create_default_entries() {
|
||||
Ref<User> user;
|
||||
user = create_user();
|
||||
|
||||
user->rank = 3;
|
||||
user->name_user_input = "admin";
|
||||
user->email_user_input = "admin@admin.com";
|
||||
|
||||
create_password(user, "Password");
|
||||
db_save_user(user);
|
||||
|
||||
user = create_user();
|
||||
|
||||
user->rank = 1;
|
||||
user->name_user_input = "user";
|
||||
user->email_user_input = "user@user.com";
|
||||
|
||||
create_password(user, "Password");
|
||||
db_save_user(user);
|
||||
}
|
||||
|
||||
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";
|
||||
|
||||
|
||||
// returnring true means handled, false means continue
|
||||
bool UserSessionSetupMiddleware::on_before_handle_request_main(Request *request) {
|
||||
if (request->session.is_valid()) {
|
||||
int user_id = request->session->get_int("user_id");
|
||||
|
||||
if (user_id != 0) {
|
||||
|
||||
Ref<User> u = UserController::get_singleton()->db_get_user(user_id);
|
||||
|
||||
if (u.is_valid()) {
|
||||
request->reference_data["user"] = u;
|
||||
} else {
|
||||
// log
|
||||
request->session->remove("user_id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
UserSessionSetupMiddleware::UserSessionSetupMiddleware() {
|
||||
}
|
||||
UserSessionSetupMiddleware::~UserSessionSetupMiddleware() {
|
||||
}
|
118
modules/web/nodes/users/user_controller.h
Normal file
118
modules/web/nodes/users/user_controller.h
Normal file
@ -0,0 +1,118 @@
|
||||
#ifndef USER_CONTROLLER_H
|
||||
#define USER_CONTROLLER_H
|
||||
|
||||
#include "core/containers/vector.h"
|
||||
#include "core/string.h"
|
||||
|
||||
#include "web/http/web_node.h"
|
||||
|
||||
#include "user.h"
|
||||
#include "web/http/middleware.h"
|
||||
|
||||
class Request;
|
||||
class FormValidator;
|
||||
|
||||
class UserController : public WebNode {
|
||||
RCPP_OBJECT(UserController, WebNode);
|
||||
|
||||
public:
|
||||
void handle_request_main(Request *request);
|
||||
|
||||
struct LoginRequestData {
|
||||
String error_str;
|
||||
String uname_val;
|
||||
String pass_val;
|
||||
};
|
||||
|
||||
virtual void handle_login_request_default(Request *request);
|
||||
virtual void render_login_request_default(Request *request, LoginRequestData *data);
|
||||
|
||||
struct RegisterRequestData {
|
||||
String error_str;
|
||||
String uname_val;
|
||||
String email_val;
|
||||
String pass_val;
|
||||
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 render_already_logged_in_error(Request *request);
|
||||
virtual void render_login_success(Request *request);
|
||||
|
||||
virtual void handle_request(Ref<User> &user, Request *request);
|
||||
virtual void handle_main_page_request(Ref<User> &user, Request *request);
|
||||
|
||||
struct SettingsRequestData {
|
||||
String error_str;
|
||||
|
||||
String uname_val;
|
||||
String email_val;
|
||||
String pass_val;
|
||||
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_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();
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
// just session setup
|
||||
class UserSessionSetupMiddleware : public Middleware {
|
||||
RCPP_OBJECT(UserSessionSetupMiddleware, Middleware);
|
||||
|
||||
public:
|
||||
//returnring true means handled, false means continue
|
||||
bool on_before_handle_request_main(Request *request);
|
||||
|
||||
UserSessionSetupMiddleware();
|
||||
~UserSessionSetupMiddleware();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user