added shadowrun database
This commit is contained in:
parent
71f771b428
commit
69f7f625f8
88
.vscode/settings.json
vendored
88
.vscode/settings.json
vendored
@ -1,92 +1,6 @@
|
|||||||
{
|
{
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"any": "cpp",
|
|
||||||
"array": "cpp",
|
|
||||||
"atomic": "cpp",
|
|
||||||
"hash_map": "cpp",
|
|
||||||
"bit": "cpp",
|
|
||||||
"*.tcc": "cpp",
|
|
||||||
"bitset": "cpp",
|
|
||||||
"cctype": "cpp",
|
|
||||||
"charconv": "cpp",
|
|
||||||
"chrono": "cpp",
|
|
||||||
"clocale": "cpp",
|
|
||||||
"cmath": "cpp",
|
|
||||||
"codecvt": "cpp",
|
|
||||||
"compare": "cpp",
|
|
||||||
"concepts": "cpp",
|
|
||||||
"condition_variable": "cpp",
|
|
||||||
"coroutine": "cpp",
|
|
||||||
"csignal": "cpp",
|
|
||||||
"cstdarg": "cpp",
|
|
||||||
"cstddef": "cpp",
|
|
||||||
"cstdint": "cpp",
|
|
||||||
"cstdio": "cpp",
|
|
||||||
"cstdlib": "cpp",
|
|
||||||
"cstring": "cpp",
|
|
||||||
"ctime": "cpp",
|
|
||||||
"cwchar": "cpp",
|
|
||||||
"cwctype": "cpp",
|
|
||||||
"deque": "cpp",
|
|
||||||
"forward_list": "cpp",
|
|
||||||
"list": "cpp",
|
|
||||||
"map": "cpp",
|
|
||||||
"set": "cpp",
|
|
||||||
"string": "cpp",
|
|
||||||
"unordered_map": "cpp",
|
|
||||||
"unordered_set": "cpp",
|
|
||||||
"vector": "cpp",
|
|
||||||
"exception": "cpp",
|
|
||||||
"algorithm": "cpp",
|
|
||||||
"functional": "cpp",
|
|
||||||
"iterator": "cpp",
|
|
||||||
"memory": "cpp",
|
|
||||||
"memory_resource": "cpp",
|
|
||||||
"numeric": "cpp",
|
|
||||||
"optional": "cpp",
|
|
||||||
"random": "cpp",
|
|
||||||
"ratio": "cpp",
|
|
||||||
"source_location": "cpp",
|
|
||||||
"string_view": "cpp",
|
|
||||||
"system_error": "cpp",
|
|
||||||
"tuple": "cpp",
|
|
||||||
"type_traits": "cpp",
|
|
||||||
"utility": "cpp",
|
|
||||||
"format": "cpp",
|
|
||||||
"fstream": "cpp",
|
|
||||||
"future": "cpp",
|
|
||||||
"initializer_list": "cpp",
|
|
||||||
"iomanip": "cpp",
|
|
||||||
"iosfwd": "cpp",
|
|
||||||
"iostream": "cpp",
|
|
||||||
"istream": "cpp",
|
|
||||||
"limits": "cpp",
|
|
||||||
"mutex": "cpp",
|
|
||||||
"new": "cpp",
|
|
||||||
"numbers": "cpp",
|
|
||||||
"ostream": "cpp",
|
|
||||||
"ranges": "cpp",
|
|
||||||
"semaphore": "cpp",
|
|
||||||
"shared_mutex": "cpp",
|
|
||||||
"span": "cpp",
|
|
||||||
"sstream": "cpp",
|
|
||||||
"stdexcept": "cpp",
|
|
||||||
"stdfloat": "cpp",
|
|
||||||
"stop_token": "cpp",
|
|
||||||
"streambuf": "cpp",
|
|
||||||
"text_encoding": "cpp",
|
"text_encoding": "cpp",
|
||||||
"thread": "cpp",
|
"thread": "cpp"
|
||||||
"cfenv": "cpp",
|
|
||||||
"cinttypes": "cpp",
|
|
||||||
"typeinfo": "cpp",
|
|
||||||
"valarray": "cpp",
|
|
||||||
"variant": "cpp",
|
|
||||||
"*.ipp": "cpp",
|
|
||||||
"expected": "cpp",
|
|
||||||
"queue": "cpp",
|
|
||||||
"stack": "cpp",
|
|
||||||
"strstream": "cpp",
|
|
||||||
"complex": "cpp",
|
|
||||||
"typeindex": "cpp"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,8 @@
|
|||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(CrowHTMX)
|
project(CrowHTMX)
|
||||||
|
|
||||||
|
set(TARGET_NAME lf-server-admin-panel )
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
@ -30,9 +32,12 @@ foreach(file IN LISTS TEMPLATE_FILES)
|
|||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# Use Crow from system include (installed via yay -S crow + asio)
|
# Use Crow from system include (installed via yay -S crow + asio)
|
||||||
include_directories(/usr/include)
|
include_directories(/usr/include src src/htmx src/shadowrun src/database)
|
||||||
|
|
||||||
add_executable(lf-server-admin-panel src/main.cpp
|
add_executable(${TARGET_NAME}
|
||||||
|
src/main.cpp
|
||||||
|
src/utils.hpp
|
||||||
|
src/utils.cpp
|
||||||
src/htmx/HtmxTable.cpp
|
src/htmx/HtmxTable.cpp
|
||||||
src/htmx/HtmxTable.h
|
src/htmx/HtmxTable.h
|
||||||
src/systemd.cpp
|
src/systemd.cpp
|
||||||
@ -46,9 +51,29 @@ add_executable(lf-server-admin-panel src/main.cpp
|
|||||||
src/htmx_helper.h
|
src/htmx_helper.h
|
||||||
src/json_settings.cpp
|
src/json_settings.cpp
|
||||||
src/json_settings.h
|
src/json_settings.h
|
||||||
src/json.hpp)
|
src/json.hpp
|
||||||
|
|
||||||
target_link_libraries(lf-server-admin-panel pthread)
|
src/database/database.cpp
|
||||||
|
src/database/database.hpp
|
||||||
|
|
||||||
|
# Shadowrun
|
||||||
|
src/shadowrun/HtmxShItemList.cpp
|
||||||
|
src/shadowrun/HtmxShItemList.hpp
|
||||||
|
src/shadowrun/HtmxShAttributeList.cpp
|
||||||
|
src/shadowrun/HtmxShAttributeList.hpp
|
||||||
|
src/shadowrun/HtmxShCondition.cpp
|
||||||
|
src/shadowrun/HtmxShCondition.hpp
|
||||||
|
src/shadowrun/ShadowrunCharacterForm.hpp
|
||||||
|
src/shadowrun/ShadowrunCharacterForm.cpp
|
||||||
|
src/shadowrun/ShadowrunApi.cpp
|
||||||
|
src/shadowrun/ShadowrunApi.hpp
|
||||||
|
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(${TARGET_NAME} PRIVATE APPLICATION_NAME="${TARGET_NAME}")
|
||||||
|
|
||||||
|
target_link_libraries(${TARGET_NAME} pthread sqlite3)
|
||||||
|
|
||||||
# Optional: Print build type at configuration time
|
# Optional: Print build type at configuration time
|
||||||
message(STATUS "Configuring build type: ${CMAKE_BUILD_TYPE}")
|
message(STATUS "Configuring build type: ${CMAKE_BUILD_TYPE}")
|
||||||
@ -1,6 +1,6 @@
|
|||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
pacman -S crow asio gdb gcc cmake make
|
pacman -S crow asio gdb gcc cmake make sqlite3
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
|
|||||||
35
src/database/database.cpp
Normal file
35
src/database/database.cpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include "crow.h"
|
||||||
|
#include "database.hpp"
|
||||||
|
|
||||||
|
Database::Database() :
|
||||||
|
m_db(nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Database::~Database() {
|
||||||
|
sqlite3_close(m_db);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Database::exec(const char* sqlQuery) {
|
||||||
|
char* errmsg = nullptr;
|
||||||
|
int rc = sqlite3_exec(m_db, sqlQuery, nullptr, nullptr, &errmsg);
|
||||||
|
if (rc != SQLITE_OK) {
|
||||||
|
CROW_LOG_ERROR << "SQL error: " << errmsg;
|
||||||
|
sqlite3_free(errmsg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Database::exec(const std::string& sqlQuery)
|
||||||
|
{
|
||||||
|
exec(sqlQuery.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Database::open(){
|
||||||
|
int rc = sqlite3_open("example.db", &m_db);
|
||||||
|
if (rc) {
|
||||||
|
CROW_LOG_ERROR << "Can't open database: " << sqlite3_errmsg(m_db);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
21
src/database/database.hpp
Normal file
21
src/database/database.hpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef __DATABASE_H__
|
||||||
|
#define __DATABASE_H__
|
||||||
|
|
||||||
|
#include "sqlite3.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Database {
|
||||||
|
|
||||||
|
public:
|
||||||
|
Database();
|
||||||
|
~Database();
|
||||||
|
|
||||||
|
bool open();
|
||||||
|
bool exec(const char* sqlQuery);
|
||||||
|
bool exec(const std::string& sqlQuery);
|
||||||
|
|
||||||
|
private:
|
||||||
|
sqlite3* m_db;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __DATABASE_H__
|
||||||
@ -5,6 +5,7 @@
|
|||||||
#include "systemd.h"
|
#include "systemd.h"
|
||||||
#include "htmx_helper.h"
|
#include "htmx_helper.h"
|
||||||
#include "json_settings.h"
|
#include "json_settings.h"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|||||||
31
src/main.cpp
31
src/main.cpp
@ -1,6 +1,4 @@
|
|||||||
#include <crow.h>
|
#include <crow.h>
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <print>
|
#include <print>
|
||||||
@ -8,16 +6,11 @@
|
|||||||
#include "json_settings.h"
|
#include "json_settings.h"
|
||||||
#include "htmx_helper.h"
|
#include "htmx_helper.h"
|
||||||
#include "systemd.h"
|
#include "systemd.h"
|
||||||
|
#include "utils.hpp"
|
||||||
|
#include "ShadowrunApi.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
string load_file(const string& path) {
|
|
||||||
ifstream f(path);
|
|
||||||
stringstream buffer;
|
|
||||||
buffer << f.rdbuf();
|
|
||||||
return buffer.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
optional<string> get_body_name(const string& body) {
|
optional<string> get_body_name(const string& body) {
|
||||||
const auto pos = body.find('=');
|
const auto pos = body.find('=');
|
||||||
if (pos == std::string::npos) return {};
|
if (pos == std::string::npos) return {};
|
||||||
@ -34,11 +27,15 @@ int main() {
|
|||||||
crow::SimpleApp app;
|
crow::SimpleApp app;
|
||||||
|
|
||||||
CROW_ROUTE(app, "/")([] {
|
CROW_ROUTE(app, "/")([] {
|
||||||
return crow::response(load_file("templates/index.html"));
|
return crow::response(utils::loadFile("templates/index.html"));
|
||||||
});
|
});
|
||||||
|
|
||||||
CROW_ROUTE(app, "/static/<string>")([](const std::string& file) {
|
CROW_ROUTE(app, "/static/<string>")([](const std::string& file) {
|
||||||
return crow::response(load_file("static/" + file));
|
return crow::response(utils::loadFile("static/" + file));
|
||||||
|
});
|
||||||
|
|
||||||
|
CROW_ROUTE(app, "/templates/<string>")([](const std::string& file) {
|
||||||
|
return crow::response(utils::loadFile("templates/" + file));
|
||||||
});
|
});
|
||||||
|
|
||||||
CROW_ROUTE(app, "/status")([] {
|
CROW_ROUTE(app, "/status")([] {
|
||||||
@ -80,7 +77,19 @@ int main() {
|
|||||||
} else {
|
} else {
|
||||||
CROW_LOG_ERROR << "failed to load settings : " << opt_settings.error();
|
CROW_LOG_ERROR << "failed to load settings : " << opt_settings.error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto opt_isPortOpen = utils::isLocalPortOpen(httpPort);
|
||||||
|
if (opt_isPortOpen.has_value()){
|
||||||
|
if (opt_isPortOpen.value()){
|
||||||
|
CROW_LOG_ERROR << "Local port : " << httpPort << " is already open";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CROW_LOG_ERROR << "failed to check if local port is open : " << opt_isPortOpen.error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowrun::initApi(app);
|
||||||
|
|
||||||
app.loglevel(crow::LogLevel::INFO);
|
app.loglevel(crow::LogLevel::INFO);
|
||||||
app.port(httpPort).multithreaded().run();
|
app.port(httpPort).multithreaded().run();
|
||||||
|
|||||||
26
src/shadowrun/HtmxShAttributeList.cpp
Normal file
26
src/shadowrun/HtmxShAttributeList.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include <format>
|
||||||
|
#include "HtmxShAttributeList.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
HtmxShAttributeList::HtmxShAttributeList(const std::string& id, const vector<string>& itemList){
|
||||||
|
html += format("<h2>{}</h2>", id);
|
||||||
|
html += "<div class='grid'>";
|
||||||
|
for (auto& item : itemList){
|
||||||
|
string item_id = utils::to_id_format(id + "_" + item);
|
||||||
|
|
||||||
|
html += format("<label>{}:<input type='text' name='{}'></label>", item, item_id);
|
||||||
|
}
|
||||||
|
html += "</div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
HtmxShAttributeList::HtmxShAttributeList(const std::string& id, const std::vector<std::pair<std::string, std::string>>& itemValueList){
|
||||||
|
html += format("<h2>{}</h2>", id);
|
||||||
|
html += "<div class='grid'>";
|
||||||
|
for (auto& item : itemValueList){
|
||||||
|
string item_id = utils::to_id_format(id + "_" + item.first);
|
||||||
|
html += format("<label>{}:<input type='text' name='{}' value='{}'></label>", item, item_id, item.second);
|
||||||
|
}
|
||||||
|
html += "</div>";
|
||||||
|
}
|
||||||
18
src/shadowrun/HtmxShAttributeList.hpp
Normal file
18
src/shadowrun/HtmxShAttributeList.hpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef HTMXSHATTRIBUTELIST_H
|
||||||
|
#define HTMXSHATTRIBUTELIST_H
|
||||||
|
|
||||||
|
#include "HtmxObject.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class HtmxShAttributeList : public HtmxObject {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// create new item list
|
||||||
|
HtmxShAttributeList(const std::string& id, const std::vector<std::string>& itemList);
|
||||||
|
|
||||||
|
// create new item list where each item as a value
|
||||||
|
HtmxShAttributeList(const std::string& id, const std::vector<std::pair<std::string, std::string>>& itemValueList);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HTMXSHATTRIBUTELIST_H
|
||||||
28
src/shadowrun/HtmxShCondition.cpp
Normal file
28
src/shadowrun/HtmxShCondition.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include "HtmxShCondition.hpp"
|
||||||
|
#include "../utils.hpp"
|
||||||
|
#include <format>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
HtmxShCondition::HtmxShCondition(std::string id, size_t nbrOfBoxes)
|
||||||
|
{
|
||||||
|
html += "<div class='section'>";
|
||||||
|
html += format("<h2>{}</h2>", id);
|
||||||
|
html += "<div class='monitor-track'>";
|
||||||
|
|
||||||
|
int con_value = -1;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < nbrOfBoxes; i++)
|
||||||
|
{
|
||||||
|
string item_id = utils::to_id_format(format("{}_{}",id, i));
|
||||||
|
html += format("<label class='monitor-box'><input type='checkbox' name='{}'></label>", item_id);
|
||||||
|
|
||||||
|
if ( ((i + 1) % 3 == 0) && (i != 0) )
|
||||||
|
{
|
||||||
|
html += format("<div class='monitor-number'>{}</div>", con_value);
|
||||||
|
con_value--;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
html += "</div></div>";
|
||||||
|
}
|
||||||
13
src/shadowrun/HtmxShCondition.hpp
Normal file
13
src/shadowrun/HtmxShCondition.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef __HTMXSHCONDITION_H__
|
||||||
|
#define __HTMXSHCONDITION_H__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "HtmxObject.h"
|
||||||
|
|
||||||
|
class HtmxShCondition : public HtmxObject {
|
||||||
|
|
||||||
|
public:
|
||||||
|
HtmxShCondition(std::string id, size_t nbrOfBoxes);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __HTMXSHCONDITION_H__
|
||||||
43
src/shadowrun/HtmxShItemList.cpp
Normal file
43
src/shadowrun/HtmxShItemList.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include <format>
|
||||||
|
#include "HtmxShItemList.hpp"
|
||||||
|
#include "../utils.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
HtmxShItemList::HtmxShItemList(const std::string& id, const std::vector<std::string>& columns, size_t size){
|
||||||
|
html += "<div class='section'>";
|
||||||
|
html += format("<h2>{}</h2>", id);
|
||||||
|
html += format("<div class='grid grid-{}'>", columns.size());
|
||||||
|
for (size_t i = 0; i < size; i++){
|
||||||
|
for (auto& col : columns){
|
||||||
|
string item_id = utils::to_id_format(format("{}_{}_{}", id, i, col));
|
||||||
|
html += format("<input type='text' name='{}' placeholder='{}'>", item_id, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html += "</div></div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
HtmxShItemList::HtmxShItemList(const std::string& id, const std::vector<std::pair<std::string, std::string>>& itemValueList){
|
||||||
|
html += format("<h2>{}</h2>", id);
|
||||||
|
html += "<div class='grid'>";
|
||||||
|
for (auto& item : itemValueList){
|
||||||
|
string item_id = utils::to_id_format(id + "_" + item.first);
|
||||||
|
html += format("<label>{}:<input type='text' name='{}' value='{}'></label>", item, item_id, item.second);
|
||||||
|
}
|
||||||
|
html += "</div>";
|
||||||
|
|
||||||
|
html += "<div class='section'>";
|
||||||
|
html += format("<h2>{}</h2>", id);
|
||||||
|
html += format("<div class='grid grid-{}'>", columns.size());
|
||||||
|
for (size_t i = 0; i < size; i++){
|
||||||
|
for (auto& col : columns){
|
||||||
|
string item_id = utils::to_id_format(format("{}_{}_{}", id, i, col));
|
||||||
|
html += format("<input type='text' name='{}' placeholder='{}' value='{}'>", item_id, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html += "</div></div>";
|
||||||
|
}
|
||||||
|
*/
|
||||||
18
src/shadowrun/HtmxShItemList.hpp
Normal file
18
src/shadowrun/HtmxShItemList.hpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef HTMXSHITEMLIST_H
|
||||||
|
#define HTMXSHITEMLIST_H
|
||||||
|
|
||||||
|
#include "HtmxObject.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class HtmxShItemList : public HtmxObject {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// create new item list,
|
||||||
|
HtmxShItemList(const std::string& id, const std::vector<std::string>& columns, size_t size);
|
||||||
|
|
||||||
|
// create new item list where each item as a value
|
||||||
|
HtmxShItemList(const std::string& id, const std::vector<std::pair<std::string, std::string>>& itemValueList);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HTMXSHITEMLIST_H
|
||||||
106
src/shadowrun/ShadowrunApi.cpp
Normal file
106
src/shadowrun/ShadowrunApi.cpp
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include "ShadowrunApi.hpp"
|
||||||
|
#include "ShadowrunCharacterForm.hpp"
|
||||||
|
#include "database.hpp"
|
||||||
|
|
||||||
|
namespace shadowrun
|
||||||
|
{
|
||||||
|
|
||||||
|
bool initDb() {
|
||||||
|
auto db = Database();
|
||||||
|
|
||||||
|
if (!db.open()){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a tables
|
||||||
|
const char* create_sql_chars = "CREATE TABLE IF NOT EXISTS shadowrun_characters ("
|
||||||
|
"id INTEGER PRIMARY KEY,"
|
||||||
|
"name TEXT,"
|
||||||
|
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP);";
|
||||||
|
|
||||||
|
if (!db.exec(create_sql_chars)){
|
||||||
|
CROW_LOG_ERROR << "Failed to create shadowrun_characters table";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* create_sql_data = "CREATE TABLE IF NOT EXISTS shadowrun_data ("
|
||||||
|
"id INTEGER PRIMARY KEY,"
|
||||||
|
"character_id INTEGER NOT NULL,"
|
||||||
|
"name TEXT NOT NULL,"
|
||||||
|
"value TEXT,"
|
||||||
|
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
|
||||||
|
"updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
|
||||||
|
"FOREIGN KEY (character_id) REFERENCES characters(id) ON DELETE CASCADE);";
|
||||||
|
|
||||||
|
if (!db.exec(create_sql_data)){
|
||||||
|
CROW_LOG_ERROR << "Failed to create shadowrun_data table";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void initApi(crow::SimpleApp& app)
|
||||||
|
{
|
||||||
|
CROW_ROUTE(app, "/api/shadowrun/submit-character").methods("POST"_method)(
|
||||||
|
[](const crow::request& req) {
|
||||||
|
auto params = crow::query_string(req.body);
|
||||||
|
|
||||||
|
std::string name = params.get("name") ? params.get("name") : "";
|
||||||
|
std::string metatype = params.get("metatype") ? params.get("metatype") : "";
|
||||||
|
std::string age = params.get("age") ? params.get("age") : "";
|
||||||
|
// ... extract more fields as needed
|
||||||
|
|
||||||
|
// Optionally save to a DB or do logic here
|
||||||
|
|
||||||
|
// Return response HTML
|
||||||
|
std::ostringstream out;
|
||||||
|
out << "<div class='alert alert-success'>"
|
||||||
|
<< "Character " << name << " submitted successfully!"
|
||||||
|
<< "</div>";
|
||||||
|
|
||||||
|
return crow::response{out.str()};
|
||||||
|
});
|
||||||
|
|
||||||
|
CROW_ROUTE(app, "/api/shadowrun/character-form")
|
||||||
|
([](const crow::request& req) {
|
||||||
|
auto query = crow::query_string(req.url_params);
|
||||||
|
std::string name = query.get("name") ? query.get("name") : "";
|
||||||
|
|
||||||
|
// TODO: Load data from file or DB using `name`
|
||||||
|
std::string metatype = "Troll";
|
||||||
|
int age = 28;
|
||||||
|
|
||||||
|
return crow::response{ShadowrunCharacterForm().htmx()};
|
||||||
|
});
|
||||||
|
|
||||||
|
CROW_ROUTE(app, "/api/shadowrun/character-list")
|
||||||
|
([] {
|
||||||
|
std::ostringstream html;
|
||||||
|
|
||||||
|
// Simulated character database
|
||||||
|
std::vector<std::string> characters = { "Trogdor", "Alice", "Zigzag" };
|
||||||
|
|
||||||
|
html << "<form hx-get='/api/shadowrun/character-form' hx-target='#form-container' hx-params='*'>"
|
||||||
|
<< "<label>Character Name: "
|
||||||
|
<< "<select name='name'>";
|
||||||
|
|
||||||
|
for (const auto& name : characters) {
|
||||||
|
html << "<option value='" << name << "'>" << name << "</option>";
|
||||||
|
}
|
||||||
|
|
||||||
|
html << "</select></label>"
|
||||||
|
<< "<button type='submit'>Load Character</button>"
|
||||||
|
<< "</form>";
|
||||||
|
|
||||||
|
return crow::response{html.str()};
|
||||||
|
});
|
||||||
|
|
||||||
|
if(initDb()){
|
||||||
|
CROW_LOG_ERROR << "Failed to Init shadowrun database";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
11
src/shadowrun/ShadowrunApi.hpp
Normal file
11
src/shadowrun/ShadowrunApi.hpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef __SHADOWRUNAPI_H__
|
||||||
|
#define __SHADOWRUNAPI_H__
|
||||||
|
|
||||||
|
#include <crow.h>
|
||||||
|
|
||||||
|
namespace shadowrun {
|
||||||
|
|
||||||
|
void initApi(crow::SimpleApp& app);
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // __SHADOWRUNAPI_H__
|
||||||
122
src/shadowrun/ShadowrunCharacterForm.cpp
Normal file
122
src/shadowrun/ShadowrunCharacterForm.cpp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "HtmxShItemList.hpp"
|
||||||
|
#include "HtmxShAttributeList.hpp"
|
||||||
|
#include "HtmxShCondition.hpp"
|
||||||
|
#include "ShadowrunCharacterForm.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
static const vector<string> cCharacterInfo = {
|
||||||
|
"Name",
|
||||||
|
"Metatype",
|
||||||
|
"Age",
|
||||||
|
"Sex",
|
||||||
|
"Nuyen",
|
||||||
|
"Lifestyle",
|
||||||
|
"Total Karma",
|
||||||
|
"Current Karma",
|
||||||
|
"Street Cred",
|
||||||
|
"Notoriety",
|
||||||
|
"Public Awareness"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const vector<string> cAttributes = {
|
||||||
|
"Body",
|
||||||
|
"Agility",
|
||||||
|
"Reaction",
|
||||||
|
"Strength",
|
||||||
|
"Charisma",
|
||||||
|
"Intuition",
|
||||||
|
"Logic",
|
||||||
|
"Willpower",
|
||||||
|
"Edge",
|
||||||
|
"Essence",
|
||||||
|
"Initiative"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const vector<string> cSkillParameters = {
|
||||||
|
"Name",
|
||||||
|
"RTG.",
|
||||||
|
"ATT.",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const vector<string> cContactsParameters = {
|
||||||
|
"Name",
|
||||||
|
"Loyalty",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const vector<string> cRangedWeaponsParameters = {
|
||||||
|
"Weapon",
|
||||||
|
"Damage",
|
||||||
|
"AP",
|
||||||
|
"Mode",
|
||||||
|
"RC",
|
||||||
|
"Ammo"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const vector<string> cImplantParameters = {
|
||||||
|
"Implant",
|
||||||
|
"Rating",
|
||||||
|
"Essence",
|
||||||
|
"Notes",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const vector<string> cMeleeWeaponParameters = {
|
||||||
|
"Weapon",
|
||||||
|
"Reach",
|
||||||
|
"Damage",
|
||||||
|
"AP",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const vector<string> cArmorParamters = {
|
||||||
|
"Armor",
|
||||||
|
"Ballistic",
|
||||||
|
"Impact",
|
||||||
|
"Notes",
|
||||||
|
};
|
||||||
|
|
||||||
|
ShadowrunCharacterForm::ShadowrunCharacterForm() {
|
||||||
|
html.reserve(30000);
|
||||||
|
|
||||||
|
html += "<form hx-post='/api/shadowrun/submit-character' hx-target='#form-response' hx-swap='innerHTML'>";
|
||||||
|
html += HtmxShAttributeList("Character Info", cCharacterInfo).htmx();
|
||||||
|
html += HtmxShAttributeList("Attributes", cAttributes).htmx();
|
||||||
|
|
||||||
|
html += "<div style='display: grid; grid-template-columns: 1fr 1fr; gap: 2em;'>";
|
||||||
|
html += HtmxShItemList("Active Skills", cSkillParameters, 6).htmx();
|
||||||
|
html += HtmxShItemList("Knowledge Skills", cSkillParameters, 6).htmx();
|
||||||
|
|
||||||
|
// add Qualities
|
||||||
|
html += "<div class='section'>"
|
||||||
|
"<h2>Qualities</h2>"
|
||||||
|
"<label>Positive Qualities:"
|
||||||
|
"<textarea name='positive_qualities' rows='4'></textarea>"
|
||||||
|
"</label>"
|
||||||
|
"<label>Negative Qualities:"
|
||||||
|
"<textarea name='negative_qualities' rows='4'></textarea>"
|
||||||
|
"</label>"
|
||||||
|
"</div>";
|
||||||
|
|
||||||
|
// add datapack notes
|
||||||
|
html += "<div class='section'>"
|
||||||
|
"<h2>Datajack / Commlink / Cyberdeck / Notes</h2>"
|
||||||
|
"<label>Notes:"
|
||||||
|
"<textarea name='datapack_notes' rows='6'></textarea>"
|
||||||
|
"</label>"
|
||||||
|
"</div>";
|
||||||
|
|
||||||
|
html += HtmxShCondition("Physical Condition", 18).htmx();
|
||||||
|
html += HtmxShCondition("Stun Condition", 12).htmx();
|
||||||
|
html += HtmxShItemList("Contacts", cContactsParameters, 6).htmx();
|
||||||
|
html += HtmxShItemList("Ranged Weapons", cRangedWeaponsParameters, 7).htmx();
|
||||||
|
html += HtmxShItemList("Cyberware and Bioware", cImplantParameters, 7).htmx();
|
||||||
|
html += HtmxShItemList("Melee Weapons", cMeleeWeaponParameters, 7).htmx();
|
||||||
|
html += HtmxShItemList("Armor", cArmorParamters , 3).htmx();
|
||||||
|
html += "</div>";
|
||||||
|
|
||||||
|
html += "<div style='text-align:center'>"
|
||||||
|
"<button type='submit'>Submit</button>"
|
||||||
|
"</div>"
|
||||||
|
"</form>";
|
||||||
|
}
|
||||||
14
src/shadowrun/ShadowrunCharacterForm.hpp
Normal file
14
src/shadowrun/ShadowrunCharacterForm.hpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef SHADOWRUN_CHARACTER_FORM_HPP
|
||||||
|
#define SHADOWRUN_CHARACTER_FORM_HPP
|
||||||
|
|
||||||
|
#include "htmx/HtmxObject.h"
|
||||||
|
|
||||||
|
class ShadowrunCharacterForm : public HtmxObject {
|
||||||
|
|
||||||
|
public:
|
||||||
|
ShadowrunCharacterForm();
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SHADOWRUN_CHARACTER_FORM_HPP
|
||||||
79
src/utils.cpp
Normal file
79
src/utils.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include "utils.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
expected<bool, string> isLocalPortOpen(uint16_t portno) {
|
||||||
|
const char *hostname = "localhost";
|
||||||
|
|
||||||
|
int sockfd;
|
||||||
|
bool ret;
|
||||||
|
struct sockaddr_in serv_addr;
|
||||||
|
struct hostent *server;
|
||||||
|
|
||||||
|
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sockfd < 0) {
|
||||||
|
close(sockfd);
|
||||||
|
return unexpected("ERROR opening socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
server = gethostbyname(hostname);
|
||||||
|
|
||||||
|
if (server == NULL) {
|
||||||
|
close(sockfd);
|
||||||
|
return unexpected("ERROR, no such host");
|
||||||
|
}
|
||||||
|
|
||||||
|
bzero((char *) &serv_addr, sizeof(serv_addr));
|
||||||
|
serv_addr.sin_family = AF_INET;
|
||||||
|
bcopy((char *)server->h_addr,
|
||||||
|
(char *)&serv_addr.sin_addr.s_addr,
|
||||||
|
server->h_length);
|
||||||
|
|
||||||
|
serv_addr.sin_port = htons(portno);
|
||||||
|
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) {
|
||||||
|
ret = false;
|
||||||
|
} else {
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(sockfd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
string to_id_format(const string& s){
|
||||||
|
string new_s = s;
|
||||||
|
|
||||||
|
// transform(new_s.begin(), new_s.end(), new_s.begin(),
|
||||||
|
// [](unsigned char c){ return std::tolower(c); });
|
||||||
|
|
||||||
|
replace( new_s.begin(), new_s.end(), ' ', '-');
|
||||||
|
|
||||||
|
return new_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
string loadFile(const string& path) {
|
||||||
|
ifstream f(path);
|
||||||
|
stringstream buffer;
|
||||||
|
buffer << f.rdbuf();
|
||||||
|
return buffer.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path getDataDir(){
|
||||||
|
return std::getenv("XDG_DATA_HOME")
|
||||||
|
? std::filesystem::path(std::getenv("XDG_DATA_HOME")) / APPLICATION_NAME
|
||||||
|
: std::filesystem::path(std::getenv("HOME")) / ".local" / "share" / APPLICATION_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
19
src/utils.hpp
Normal file
19
src/utils.hpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef UTILS_HPP
|
||||||
|
#define UTILS_HPP
|
||||||
|
|
||||||
|
#include <expected>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
std::expected<bool, std::string> isLocalPortOpen(uint16_t portno);
|
||||||
|
|
||||||
|
std::string to_id_format(const std::string& s);
|
||||||
|
|
||||||
|
std::string loadFile(const std::string& path);
|
||||||
|
|
||||||
|
std::filesystem::path getDataDir();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
133
templates/shadowrun.html
Normal file
133
templates/shadowrun.html
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<script src="/static/htmx.min.js"></script>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Shadowrun Character Sheet</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', sans-serif;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
margin: 0;
|
||||||
|
padding: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: white;
|
||||||
|
padding: 2em;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2 {
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-2 {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-3 {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-4 {
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-6 {
|
||||||
|
grid-template-columns: repeat(6, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 2fr 1fr 1fr;
|
||||||
|
gap: 0.5em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"], input[type="number"] {
|
||||||
|
padding: 0.4em;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-top: 2em;
|
||||||
|
padding: 0.75em 2em;
|
||||||
|
background-color: #222;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-track {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, auto);
|
||||||
|
gap: 0.25em;
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-box input[type="checkbox"] {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-number {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-weight: bold;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<h1>Shadowrun Character Sheet</h1>
|
||||||
|
|
||||||
|
<div id="character-selector"
|
||||||
|
hx-get="/api/shadowrun/character-list"
|
||||||
|
hx-trigger="load"
|
||||||
|
hx-target="this"
|
||||||
|
hx-swap="outerHTML">
|
||||||
|
</div>
|
||||||
|
<div id="form-container"></div>
|
||||||
|
|
||||||
|
<div id="form-response"></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user