added CORS

This commit is contained in:
2026-02-16 23:24:31 +01:00
parent 14b8234e77
commit 58d37b51b7
27 changed files with 80 additions and 32 deletions

View File

@@ -0,0 +1,128 @@
#include "ShadowrunApi.hpp"
#include "ShadowrunDb.hpp"
#include "login.hpp"
#include <vector>
using namespace std;
namespace shadowrun
{
static std::unordered_map<std::string, std::string> parse_query_string(const std::string& query) {
std::unordered_map<std::string, std::string> params;
std::istringstream stream(query);
std::string pair;
while (std::getline(stream, pair, '&')) {
auto pos = pair.find('=');
if (pos != std::string::npos) {
std::string key = pair.substr(0, pos);
std::string value = pair.substr(pos + 1);
params[key] = value; // You may want to URL-decode here
}
}
return params;
}
void initApi(crow::App<CORS>& app){
CROW_ROUTE(app, "/assets/shadowrun/<path>")
([&](const crow::request& req, const std::string& p) {
LOGGIN_REQUIERED(req);
const filesystem::path assets_dir = "assets/shadowrun/";
filesystem::path file_path = assets_dir / p;
return utils::getFile(file_path);
});
CROW_ROUTE(app, "/api/shadowrun/characters")
([&](const crow::request& req) {
LOGGIN_REQUIERED(req);
auto characters = getCharacters();
auto res =
crow::response(200, utils::toJsonArray(characters));
res.set_header("Content-Type", "application/json");
return res;
});
CROW_ROUTE(app, "/api/shadowrun/characters").methods("POST"_method)
([](const crow::request& req) {
LOGGIN_REQUIERED(req);
nlohmann::json data = nlohmann::json::parse(req.body); // parse JSON from HTTP body
auto name = data["name"];
int id = createCharacter(name);
if(id > 0){
auto character = getChracter(id);
if (character.has_value()){
auto res = crow::response(200, nlohmann::json(character.value()).dump());
res.set_header("Content-Type", "application/json");
return res;
}
}
return crow::response(405, "Failed to create character");
});
CROW_ROUTE(app, "/api/shadowrun/characters/<int>")
([&](const crow::request& req, int id) {
LOGGIN_REQUIERED(req);
auto optCharacter = getChracter(id);
if (!optCharacter.has_value())
return crow::response(404, "Character not found");
auto res = crow::response(200, nlohmann::json(optCharacter.value()).dump());
res.set_header("Content-Type", "application/json");
return res;
});
CROW_ROUTE(app, "/api/shadowrun/characters_data/<int>")
([&](const crow::request& req, int id) {
LOGGIN_REQUIERED(req);
nlohmann::json j;
const auto characterData = getChracterData(id);
if(characterData.empty())
return crow::response(405, "Character not found");
for(const auto& data : characterData ){
const auto& key = magic_enum::enum_cast<Type>(data.type);
if(key.has_value()){
auto res = utils::parseJson(data.json);
if(res){
j[magic_enum::enum_name(key.value())] = res.value();
} else {
CROW_LOG_ERROR << "Failed to parse json: " << res.error();
}
} else {
CROW_LOG_ERROR << "Read invalid type from database: " << data.type;
}
}
auto res = crow::response(200, j.dump());
res.set_header("Content-Type", "application/json");
return res;
});
CROW_ROUTE(app, "/api/shadowrun/characters_data/<int>").methods("POST"_method)
([&](const crow::request& req, int id) {
LOGGIN_REQUIERED(req);
nlohmann::json j = nlohmann::json::parse(req.body);
for (auto type : magic_enum::enum_values<Type>()) {
const auto& key = magic_enum::enum_name(type);
if (j.contains(key)){
storeCharacterData(id, type, j[key].dump());
}
}
auto res = crow::response(200, "Saved Character data");
return res;
});
}
}

View File

@@ -0,0 +1,12 @@
#ifndef __SHADOWRUNAPI_H__
#define __SHADOWRUNAPI_H__
#include "cors.h"
#include <crow.h>
namespace shadowrun {
void initApi(crow::App<CORS>& app);
}
#endif // __SHADOWRUNAPI_H__

View File

@@ -0,0 +1,101 @@
#include "ShadowrunDb.hpp"
#include <optional>
#include "databasepool.h"
#include "utils.hpp"
#include "crow/logging.h"
using namespace std;
using namespace sqlite_orm;
namespace shadowrun {
int64_t createCharacter(const string& name){
if (name.empty())
return -1;
int64_t id;
auto db = dbpool->acquire();
auto character = db->get_optional<ShadowrunCharacter>(
where(c(&ShadowrunCharacter::name) == name)
);
if (character.has_value()) {
id = character.value().id;
} else {
auto c = newShadowrunCharacter(name);
id = db->insert(c);
}
dbpool->release(db);
return id;
}
std::vector<ShadowrunCharacter> getCharacters(){
auto db = dbpool->acquire();
auto characters = db->get_all<ShadowrunCharacter>();
dbpool->release(db);
return characters;
}
optional<ShadowrunCharacter> getChracter(int id)
{
auto db = dbpool->acquire();
optional<ShadowrunCharacter> character = db->get_optional<ShadowrunCharacter>(id);
dbpool->release(db);
return character;
}
vector<ShadowrunCharacterData> getChracterData(int character_id)
{
auto db = dbpool->acquire();
auto characterData = db->get_all<ShadowrunCharacterData>(
where(c(&ShadowrunCharacterData::character_id) == character_id)
);
dbpool->release(db);
return characterData;
}
int storeCharacterData(int characterId, const Type type, const string& json){
int id;
auto db = dbpool->acquire();
auto characterData = db->get_all<ShadowrunCharacterData>(
where(
(c(&ShadowrunCharacterData::character_id) == characterId) and
(c(&ShadowrunCharacterData::type) == static_cast<int>(type)))
);
if(characterData.empty()){
ShadowrunCharacterData character = newShadowrunCharacterData(characterId, type, json);
id = db->insert(character);
}
else {
if (characterData.size() > 1){
CROW_LOG_ERROR << "Character ID: " << characterId << "has mote than 1 type: " << magic_enum::enum_name(type);
}
auto& character = characterData[0];
character.json = json;
character.updated_at = utils::currentTime();
db->update(character);
id = character.id;
}
dbpool->release(db);
return id;
}
int storeCharacterData(const ShadowrunCharacterData& data){
int id;
auto db = dbpool->acquire();
auto characterData = db->get_optional<ShadowrunCharacterData>(data.id);
if(!characterData.has_value()){
id = db->insert(data);
}
else {
db->update(data);
id = data.id;
}
dbpool->release(db);
return id;
}
}

View File

@@ -0,0 +1,73 @@
#ifndef __SHADOWRUNDB_H__
#define __SHADOWRUNDB_H__
#include <cstdint>
#include <string>
#include <vector>
#include <optional>
#include "json.hpp"
#include "utils.hpp"
#include "sqlite_orm.h"
#include "magic_enum.hpp"
namespace shadowrun {
enum class Type {
Unknown = 0,
Info = 1,
Attributes = 2,
Skills = 3,
Connections = 4,
RangedWeapons = 5,
MeleeWeapons = 6,
Cyberware = 7,
Bioware = 8,
PositiveQualities = 9,
NegativeQualities = 10,
Notes = 11,
};
struct ShadowrunCharacter {
int id;
std::string name;
std::string created_at; // SQLite stores DATETIME as TEXT
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ShadowrunCharacter, id, name, created_at)
inline ShadowrunCharacter newShadowrunCharacter(const std::string& name){
return ShadowrunCharacter {-1, name, utils::currentTime()};
}
struct ShadowrunCharacterData {
int id;
int character_id;
int type;
std::string json;
std::string created_at;
std::string updated_at;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ShadowrunCharacterData, id, character_id, type, json, created_at, updated_at);
inline ShadowrunCharacterData newShadowrunCharacterData(int character_id, Type type, const std::string json){
std::string time = utils::currentTime();
return ShadowrunCharacterData {
.id = -1,
.character_id = character_id,
.type = static_cast<int>(type),
.json = json,
.created_at = time,
.updated_at = time,
};
}
int64_t createCharacter(const std::string& name);
std::vector<ShadowrunCharacter> getCharacters();
std::optional<ShadowrunCharacter> getChracter(int id);
std::vector<ShadowrunCharacterData> getChracterData(int character_id);
int storeCharacterData(const ShadowrunCharacterData& data);
int storeCharacterData(int characterId, const Type type, const std::string& json);
}
#endif // __SHADOWRUNDB_H__