fixed bug where lock was never released, attributes look better now, can be accees on other devices

This commit is contained in:
Lukas Forsberg 2026-01-18 23:54:52 +01:00
parent b270a95434
commit 400954babc
6 changed files with 60 additions and 202 deletions

View File

@ -1 +1 @@
export const API_BASE = "http://127.0.0.1:3010";
export const API_BASE = `http://${window.location.hostname}:3010`;

View File

@ -85,48 +85,39 @@
</div>
<h2>Attributes</h2>
<div class="info-container">
<table>
<tbody>
<tr>
<td>
<label for={"field-Agility"}>Agility</label>
<input id={"field-Agility"} type="number" bind:value={characterData.Attributes.Agility} min=0 max=100/>
</td>
<td>
<label for={"field-Body"}>Body</label>
<input id={"field-Body"} type="number" bind:value={characterData.Attributes.Body} min=0 max=100/>
</td>
<td>
<label for={"field-Charisma"}>Charisma</label>
<input id={"field-Charisma"} type="number" bind:value={characterData.Attributes.Charisma} min=0 max=100/>
</td>
<td>
<label for={"field-Edge"}>Edge</label>
<input id={"field-Edge"} type="number" bind:value={characterData.Attributes.Edge} min=0 max=100/>
</td>
<td>Agility</td>
<td><input id={"field-Agility"} type="number" bind:value={characterData.Attributes.Agility} min=0 max=100/></td>
<td>Body</td>
<td><input id={"field-Body"} type="number" bind:value={characterData.Attributes.Body} min=0 max=100/> </td>
<td>Charisma</td>
<td><input id={"field-Charisma"} type="number" bind:value={characterData.Attributes.Charisma} min=0 max=100/></td>
<td>Edge</td>
<td><input id={"field-Edge"} type="number" bind:value={characterData.Attributes.Edge} min=0 max=100/> </td>
</tr>
<tr>
<td>Essence</td>
<td><input id={"field-Essence"} type="number" bind:value={characterData.Attributes.Essence} min=0 max=100/></td>
<td>Initiative</td>
<td><input id={"field-Initiative"} type="number" bind:value={characterData.Attributes.Initiative} min=0 max=100/> </td>
<td>Intuition</td>
<td><input id={"field-Charisma"} type="number" bind:value={characterData.Attributes.Intuition} min=0 max=100/></td>
<td>Logic</td>
<td><input id={"field-Edge"} type="number" bind:value={characterData.Attributes.Logic} min=0 max=100/> </td>
</tr>
<tr>
<td>
<label for={"field-Essence"}>Essence</label>
<input id={"field-Essence"} type="number" bind:value={characterData.Attributes.Essence} min=0 max=100/>
</td>
<td>
<label for={"field-Initiative"}>Initiative</label>
<input id={"field-Initiative"} type="number" bind:value={characterData.Attributes.Initiative} min=0 max=100/>
</td>
<td>
<label for={"field-Charisma"}>Charisma</label>
<input id={"field-Charisma"} type="number" bind:value={characterData.Attributes.Charisma} min=0 max=100/>
</td>
<td>
<label for={"field-Edge"}>Edge</label>
<input id={"field-Edge"} type="number" bind:value={characterData.Attributes.Edge} min=0 max=100/>
</td>
<td>Reaction</td>
<td><input id={"field-Initiative"} type="number" bind:value={characterData.Attributes.Reaction} min=0 max=100/></td>
<td>Strength</td>
<td><input id={"field-Charisma"} type="number" bind:value={characterData.Attributes.Strength} min=0 max=100/></td>
<td>Willpower</td>
<td><input id={"field-Edge"} type="number" bind:value={characterData.Attributes.Willpower} min=0 max=100/></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<h2>Skills</h2>
<table>

View File

@ -1,2 +1,8 @@
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
<script lang="ts">
import { goto } from '$app/navigation';
import { onMount } from 'svelte';
onMount(() => {
goto('/shadowrun', { replaceState: true });
});
</script>

View File

@ -37,74 +37,6 @@ std::string get_mime_type(const std::string& path) {
int main() {
crow::SimpleApp app;
/*
CROW_ROUTE(app, "/")([] {
auto data = utils::loadFile("templates/index.html");
if (data.empty())
return crow::response(404);
return crow::response(data);
});
CROW_ROUTE(app, "/static/<string>")([](const std::string& file) {
auto data = utils::loadFile("static/" + file);
if (data.empty())
return crow::response(404);
return crow::response(data);
});
CROW_ROUTE(app, "/templates/<string>")([](const std::string& file) {
auto data = utils::loadFile("templates/" + file);
if (data.empty())
return crow::response(404);
return crow::response(data);
});
// Static file redirector
CROW_ROUTE(app, "/redirect")
(login::login_required([](const crow::request& req) {
auto file_param = req.url_params.get("file");
if (!file_param) {
return crow::response(400, "Missing 'file' parameter");
}
std::string filepath = "/templates/";
filepath += utils::urlDecode(file_param); // Optional: decode %20 etc.
crow::response res;
res.code = 204;
res.add_header("HX-Redirect", filepath);
return res;
}));
CROW_ROUTE(app, "/status")(login::login_required([](const crow::request& req) {
auto table = create_service_table();
return crow::response{table.htmx()};
}));
CROW_ROUTE(app, "/toggle-service").methods(crow::HTTPMethod::Post)
(login::login_required([](const crow::request& req) {
auto body = utils::getBodyName(req.body);
if (!body.has_value())
return crow::response(400);
const string& serviceName = body.value();
auto opt_settings = AppSettings::loadAppSettings();
HtmxTableRow row;
if (opt_settings.has_value()) {
auto& settings = opt_settings.value();
const auto& service_id = settings.getId(serviceName).value_or(serviceName);
systemd::toggle_service(service_id);
row = create_service_table_row(serviceName, service_id);
}
else {
row = create_error_table_row(opt_settings.error());
}
return crow::response{row.htmx()};
}));
*/
const filesystem::path build_dir = "frontend/build/"; // <-- set your build folder
// Root route
@ -184,5 +116,5 @@ int main() {
}
*/
app.loglevel(crow::LogLevel::INFO);
app.port(httpPort).multithreaded().run();
app.bindaddr("0.0.0.0").port(httpPort).multithreaded().run();
}

View File

@ -34,80 +34,6 @@ static crow::response rsp(const std::string& msg){
void initApi(crow::SimpleApp& app)
{
/*
CROW_ROUTE(app, "/api/shadowrun/submit-character").methods("POST"_method)
(login::login_required([](const crow::request& req) {
auto params = parse_query_string(req.body);
auto name_data = params["Character-Info_Name"];
if (name_data.empty()){
CROW_LOG_WARNING << "Character without name submited, will not be saved";
return rsp("Failed : Character without name submited, will not be saved");
}
auto key = getKeyOfCharacter(name_data);
if (key < 0){
CROW_LOG_ERROR << "Failed to create id of character : " << name_data;
return rsp("Failed to create id of character");
}
vector<pair<const string, const string>> idValues;
idValues.reserve(ShadowrunCharacterForm::m_formIds.size());
auto checkboxes = std::set<string>(ShadowrunCharacterForm::m_checkboxIds.begin(), ShadowrunCharacterForm::m_checkboxIds.end());
for (auto& id : ShadowrunCharacterForm::m_formIds) {
auto data = params[id];
if(!data.empty()){
idValues.push_back(make_pair(id, data));
if (checkboxes.contains(id)){
checkboxes.erase(id);
}
}
}
// append the checkboxes
for (auto& checkbox : checkboxes){
idValues.push_back(make_pair(checkbox, "0"));
}
if (!storeCharacterData(key, idValues)){
CROW_LOG_ERROR << "Failed to store character data of " << name_data;
return rsp("Failed to store character data");
};
return rsp(format("Character {} submitted successfully", name_data));
}));
CROW_ROUTE(app, "/api/shadowrun/character-form")
(login::login_required([](const crow::request& req) {
auto query = crow::query_string(req.url_params);
std::string name = query.get("name") ? query.get("name") : "";
auto data = getCharacterDataMap(getKeyOfCharacter(name));
return crow::response{ShadowrunCharacterForm(data).htmx()};
}));
*/
CROW_ROUTE(app, "/api/shadowrun/character-list")
(login::login_required([](const crow::request& req) {
std::ostringstream html;
// Simulated character database
auto characters = getCharacters();
html << "<form hx-get='/api/shadowrun/character-form' hx-target='#form-container' hx-params='*'>"
<< "<label>Character Name: "
<< "<select name='name'>";
for (const auto& character : characters) {
html << "<option value='" << character.name << "'>" << character.name << "</option>";
}
html << "</select></label>"
<< "<button type='submit'>Load Character</button>"
<< "</form>";
return crow::response{html.str()};
}));
CROW_ROUTE(app, "/api/shadowrun/characters")
([&]() {
auto characters = getCharacters();

View File

@ -12,40 +12,36 @@ int64_t createCharacter(const string& name){
if (name.empty())
return -1;
int64_t id;
auto db = dbpool.acquire();
auto character = db->get_all<ShadowrunCharacter>(
where(c(&ShadowrunCharacter::name) == name),
limit(1)
auto character = db->get_optional<ShadowrunCharacter>(
where(c(&ShadowrunCharacter::name) == name)
);
if (!character.empty()) {
return character[0].id;
if (character.has_value()) {
id = character.value().id;
} else {
auto c = newShadowrunCharacter(name);
return db->insert(c);
id = db->insert(c);
}
dbpool.release(db);
return id;
}
std::vector<ShadowrunCharacter> getCharacters(){
auto db = dbpool.acquire();
return db->get_all<ShadowrunCharacter>();
auto characters = db->get_all<ShadowrunCharacter>();
dbpool.release(db);
return characters;
}
optional<ShadowrunCharacter> getChracter(int id)
{
auto db = dbpool.acquire();
auto character = db->get_all<ShadowrunCharacter>(
where(c(&ShadowrunCharacter::id) == id),
limit(1)
);
if (character.empty())
{
return {};
}
else {
return character[0];
}
optional<ShadowrunCharacter> character = db->get_optional<ShadowrunCharacter>(id);
dbpool.release(db);
return character;
}
vector<ShadowrunCharacterData> getChracterData(int character_id)
@ -54,10 +50,12 @@ vector<ShadowrunCharacterData> getChracterData(int character_id)
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(
@ -67,7 +65,7 @@ int storeCharacterData(int characterId, const Type type, const string& json){
if(characterData.empty()){
ShadowrunCharacterData character = newShadowrunCharacterData(characterId, type, json);
return db->insert(character);
id = db->insert(character);
}
else {
if (characterData.size() > 1){
@ -77,21 +75,26 @@ int storeCharacterData(int characterId, const Type type, const string& json){
character.json = json;
character.updated_at = utils::currentTime();
db->update(character);
return character.id;
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()){
return db->insert(data);
id = db->insert(data);
}
else {
db->update(data);
return data.id;
id = data.id;
}
dbpool.release(db);
return id;
}
}