From 665451c783ef3a5a26c844a1e7c386f89e8789ca Mon Sep 17 00:00:00 2001 From: Harm Manders Date: Fri, 20 Oct 2023 17:23:52 +0200 Subject: [PATCH 01/21] parse campaigns and encounters --- .../userContent/ImportUserContent.vue | 57 +++++++++++++++---- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/src/components/userContent/ImportUserContent.vue b/src/components/userContent/ImportUserContent.vue index 2ee1408e..a244f3c0 100644 --- a/src/components/userContent/ImportUserContent.vue +++ b/src/components/userContent/ImportUserContent.vue @@ -307,14 +307,20 @@ export default { spells: 0, }, import_key_map: { + campaigns: {}, + encounters: {}, npcs: {}, spells: {}, }, parsed_data: { + campaigns: [], + encounters: [], npcs: [], spells: [], }, selected: { + campaigns: [], + encounters: [], npcs: [], spells: [], }, @@ -379,7 +385,7 @@ export default { }, methods: { ...mapActions("campaigns", ["add_campaign", "get_campaign", "get_campaigns"]), - ...mapActions("encounters", ["add_encounter", "get_encounter", "get_encounters"]), + ...mapActions("encounters", ["add_encounter", "get_encounter", "get_campaign_encounters"]), ...mapActions("npcs", ["add_npc", "edit_npc", "get_npcs", "get_npc", "reserve_npc_id"]), ...mapActions("spells", [ "add_spell", @@ -482,30 +488,57 @@ export default { this.parseNPC(key, npc); }); } - // if (data.campaigns && data.encounters) { - // Object.entries(data.campaigns).forEach(([key, campaign]) => { - // this.parseCampaign(key, campaign); - // }); - // Object.entries(data.encounters).forEach(([key, encounter]) => { - // this.parseEncounter(key, encounter); - // }); - // } + if (data.campaigns && data.encounters) { + console.log("Will parse encounters and campaigns"); + console.log(data); + Object.entries(data.campaigns).forEach(([campaign_key, campaign]) => { + this.parseCampaign(campaign_key, campaign); + Object.entries(data.encounters[campaign_key]).forEach(([encounter_key, encounter]) => { + this.parseEncounter(encounter_key, campaign_key, encounter); + }); + }); + } + console.log("to import", this.parsed_data); }, - async parseCampaign(key, campaign) {}, + async parseCampaign(key, campaign) { + console.log("Parsing campaign", campaign); + delete campaign.key; + this.removeTimestamps(campaign); + + const valid = ajv.validate(campaignSchema, campaign); + + campaign.meta = { key }; + // Always duplicate an imported campaign + campaign.meta.duplicate = false; + campaign.meta.overwrite = undefined; + + if (!valid) { + campaign.meta.errors = ajv.errors; + } + + this.parsed_data.campaigns.push(campaign); + console.log("parsed Campaign", campaign.name); + }, async parseEncounter(key, campaign_key, encounter) { + console.log("Parsing encounter", encounter); delete encounter.key; this.removeTimestamps(encounter); const valid = ajv.validate(encounterSchema, encounter); + console.log("Encounter", encounter.name, "is valid", valid); encounter.meta = { key, campaign_key }; - encounter.meta.duplicate = await this.checkIfDuplicateEncounter(encounter); - encounter.meta.overwrite = encounter.meta.duplicate ? "duplicate" : undefined; + // Always duplicate encounters and campaigns + encounter.meta.duplicate = false; + encounter.meta.overwrite = undefined; if (!valid) { encounter.meta.errors = ajv.errors; } + + this.parsed_data.encounters.push(encounter); + console.log("parsed Encounter", encounter.name); }, async parseNPC(key, npc) { /** From 698b7b6dac47963c507706910eb11fc2d045b320 Mon Sep 17 00:00:00 2001 From: Harm Manders Date: Fri, 20 Oct 2023 17:24:24 +0200 Subject: [PATCH 02/21] add campaign --- src/components/userContent/ImportUserContent.vue | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/components/userContent/ImportUserContent.vue b/src/components/userContent/ImportUserContent.vue index a244f3c0..e98a6e64 100644 --- a/src/components/userContent/ImportUserContent.vue +++ b/src/components/userContent/ImportUserContent.vue @@ -702,7 +702,20 @@ export default { console.log("Failed NPC import", error, npc, key); } } - } + }); + + this.selected.campaigns.forEach(async (campaign) => { + const key = this.import_key_map[campaign.meta.key]; + const meta = { ...campaign.meta }; + delete campaign.meta; + try { + await this.add_campaign(campaign); + this.imported++; + } catch (error) { + this.failed_imports.push(campaign); + console.log("Failed Campaign import", error, campaign, key); + } + }); }, copySchema() { try { From a44e28319bf2526988c662fd08f654019286518c Mon Sep 17 00:00:00 2001 From: Harm Manders Date: Fri, 3 Nov 2023 14:38:42 +0100 Subject: [PATCH 03/21] Get linked items for each import type --- .../userContent/ImportUserContent.vue | 90 ++++++++++++++++++- 1 file changed, 86 insertions(+), 4 deletions(-) diff --git a/src/components/userContent/ImportUserContent.vue b/src/components/userContent/ImportUserContent.vue index e98a6e64..c8d2ece6 100644 --- a/src/components/userContent/ImportUserContent.vue +++ b/src/components/userContent/ImportUserContent.vue @@ -118,7 +118,24 @@ {{ props.row.name.capitalizeEach() }} - + From 5fdb1ad30df7de608814c87c2407fcc01847da69 Mon Sep 17 00:00:00 2001 From: Harm Manders Date: Fri, 10 Nov 2023 15:53:00 +0100 Subject: [PATCH 15/21] check campaign uid on uid lvl nog campaign id lvl --- firebase-rules.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firebase-rules.json b/firebase-rules.json index 38a35b2a..978cfc0f 100644 --- a/firebase-rules.json +++ b/firebase-rules.json @@ -2,9 +2,9 @@ "rules": { "campaigns": { "$uid": { + ".write": "$uid === auth.uid || root.child('users').child(auth.uid).child('admin').exists()", + ".indexOn": "private", "$campaignId": { - ".write": "$uid === auth.uid || root.child('users').child(auth.uid).child('admin').exists()", - ".indexOn": "private", ".validate": "newData.hasChildren(['name'])", "timestamp": { ".validate": "newData.isNumber()" From 450bb4cb908bf4dda7c2a6a55ba573abf93a995c Mon Sep 17 00:00:00 2001 From: Harm Manders Date: Fri, 10 Nov 2023 17:02:13 +0100 Subject: [PATCH 16/21] encounter fb rules --- firebase-rules.json | 206 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) diff --git a/firebase-rules.json b/firebase-rules.json index 978cfc0f..aef71849 100644 --- a/firebase-rules.json +++ b/firebase-rules.json @@ -1352,6 +1352,212 @@ "$campaignId": { ".indexOn": "entities/id", "$encounterId": { + ".validate": "newData.hasChildren(['name','round','turn'])", + "timestamp": { + ".validate": "newData.isNumber()" + }, + "name": { + ".validate": "newData.isString() && newData.val().length <= 200" + }, + "turn": { + ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 999" + }, + "round": { + ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 999" + }, + "finished": { + ".validate": "newData.isBoolean()" + }, + "audio": { + ".validate": "newData.isString() && newData.val().length <= 2000" + }, + "background": { + ".validate": "newData.isString() && newData.val().length <= 2000" + }, + "hk_background": { + ".validate": "newData.isString() && newData.val().length <= 2000" + }, + "currency": { + "$coin": { + ".validate": "$coin.match(/^(cp|sp|ep|gp|pp)$/)" + } + }, + "loot": { + "$itemId": { + "linked_item": { + "custom": { + ".validate": "newData.isBoolean()" + }, + "key": { + ".validate": "newData.isString() && newData.val().length <= 100" + } + }, + "public_name": { + ".validate": "newData.isString() && newData.val().length <= 100" + }, + "public_description": { + ".validate": "newData.isString() && newData.val().length <= 9999" + } + } + }, + "xp": { + "calculated": { + ".validate": "newData.isNumber() && newData.val() >= 0" + }, + "overwrite": { + ".validate": "newData.isString() || newData.isNumber()" + } + }, + "weather": { + "$idx": { + ".validate": "$idx.matches(/^(ash|fog|hail|lightning|quake|rain|sand|smoke|snow)$/)" + } + }, + "entities": { + "$entityId": { + "id": { + ".validate": "newData.isString() && newData.val().length <= 100" + }, + "key": { + ".validate": "newData.isString() && newData.val().length <= 100" + }, + "entityType": { + ".validate": "newData.isString() && newData.val().matches(/^(player|npc|companion)$/)" + }, + "npc": { + ".validate": "newData.isString() && newData.val().matches(/^(srd|custom|api)$/)" + }, + "name": { + ".validate": "newData.isString() && newData.val().length <= 200" + }, + "active": { + ".validate": "newData.isBoolean()" + }, + "hidden": { + ".validate": "newData.isBoolean()" + }, + "initiative": { + ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 9999" + }, + "ac": { + ".validate": "newData.isNumber() && newData.val() >= 1 && newData.val() <= 9999" + }, + "ac_bonus": { + ".validate": "newData.isNumber() && newData.val() >= -999 && newData.val() <= 9999" + }, + "curHp": { + ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 9999" + }, + "maxHp": { + ".validate": "newData.isNumber() && newData.val() >= 1 && newData.val() <= 9999" + }, + "maxHpMod": { + ".validate": "newData.isNumber() && newData.val() >= -9999 && newData.val() <= 9999" + }, + "tempHp": { + ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 9999" + }, + "color_label": { + ".validate": "newData.isString() && newData.val().length <= 10" + }, + "conditions": { + "exhaustion": { + ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 6" + }, + "$condition": { + ".validate": "newData.isBoolean && $condition.matches(/^(blinded|charmed|deafened|exhaustion|frightened|grappled|incapacitated|invisible|paralyzed|petrified|poisoned|prone|restrained|stunned|unconscious)$/)" + } + }, + "reminders": { + "$remindId": { + "action": { + ".validate": "newData.isString() && newData.val().matches(/^(remove|notify)$/)" + }, + "color": { + ".validate": "newData.isString() && newData.val().matches(/^(green-light|yellow-light|orange-light|red-light|purple|blue-light)$/)" + }, + "trigger": { + ".validate": "newData.isString() && newData.val().matches(/^(endTurn|startTurn|damage|timed)$/)" + }, + "rounds": { + ".validate": "newData.isString() && newData.val().length <= 5" + }, + "title": { + ".validate": "newData.isString() && newData.val().length <= 999" + }, + "notify": { + ".validate": "newData.isString() && newData.val().length <= 999" + }, + "variables": { + "$varName": { + "$vi": { + ".validate": "newData.isString() && newData.val().length <= 5" + } + } + } + } + }, + "settings": { + "ac": { + ".validate": "newData.isBoolean()" + }, + "health": { + ".validate": "newData.isBoolean() || newData.val().matches(/^(obscured)$/)" + }, + "name": { + ".validate": "newData.isBoolean()" + } + }, + "meters": { + "damage": { + ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 999999" + }, + "damageTaken": { + ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 999999" + }, + "overkill": { + ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 999999" + }, + "overkillTaken": { + ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 999999" + }, + "healing": { + ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 999999" + }, + "healingTaken": { + ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 999999" + }, + "overhealing": { + ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 999999" + }, + "overhealingTaken": { + ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 999999" + } + }, + "limited_uses": { + "caster": { + "$lvl": { + ".validate": "newData.isNumber() && newData.val() <= 100" + } + }, + "innate": { + "$spellId": { + ".validate": "newData.isNumber() && newData.val() <= 100" + } + }, + "actions": { + "$actionId": { + ".validate": "newData.isNumber() && newData.val() <= 100" + } + }, + "legendary_actions": { + "legendaries_used": { + ".validate": "newData.isNumber() && newData.val() <= 100" + } + } + } + } + }, "requests": { ".write": true } From 7a97f8763c0ee85dc3399d55704bd0d34bc75d61 Mon Sep 17 00:00:00 2001 From: Harm Manders Date: Fri, 10 Nov 2023 17:08:30 +0100 Subject: [PATCH 17/21] clean more from entity before export --- src/components/userContent/ExportUserContent.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/userContent/ExportUserContent.vue b/src/components/userContent/ExportUserContent.vue index e2e073a2..c4dc2beb 100644 --- a/src/components/userContent/ExportUserContent.vue +++ b/src/components/userContent/ExportUserContent.vue @@ -216,11 +216,13 @@ export default { delete entity.tempHp; delete entity.maxHpMod; delete entity.ac_bonus; + delete entity.conditions; delete entity.reminders; delete entity.settings; - delete entity.surprised; delete entity.tempHp; delete entity.meters; + delete entity.limited_uses; + return [entity_id, entity]; }); encounter.entities = Object.fromEntries(entities); From 4bf5129ecd7f9be59271e6f4af64677104c30bb3 Mon Sep 17 00:00:00 2001 From: Harm Manders Date: Fri, 10 Nov 2023 18:11:54 +0100 Subject: [PATCH 18/21] encounter name used to be called encounter --- firebase-rules.json | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/firebase-rules.json b/firebase-rules.json index aef71849..9836a25f 100644 --- a/firebase-rules.json +++ b/firebase-rules.json @@ -1352,13 +1352,15 @@ "$campaignId": { ".indexOn": "entities/id", "$encounterId": { - ".validate": "newData.hasChildren(['name','round','turn'])", "timestamp": { ".validate": "newData.isNumber()" }, "name": { ".validate": "newData.isString() && newData.val().length <= 200" }, + "encounter": { + ".validate": "newData.isString() && newData.val().length <= 200" + }, "turn": { ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 999" }, @@ -1379,7 +1381,7 @@ }, "currency": { "$coin": { - ".validate": "$coin.match(/^(cp|sp|ep|gp|pp)$/)" + ".validate": "$coin.matches(/^(cp|sp|ep|gp|pp)$/)" } }, "loot": { @@ -1440,7 +1442,7 @@ ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 9999" }, "ac": { - ".validate": "newData.isNumber() && newData.val() >= 1 && newData.val() <= 9999" + ".validate": "(newData.isNumber() && newData.val() >= 1 && newData.val() <= 9999) || (newData.isString() && newData.val().length <= 10)" }, "ac_bonus": { ".validate": "newData.isNumber() && newData.val() >= -999 && newData.val() <= 9999" @@ -1465,7 +1467,7 @@ ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 6" }, "$condition": { - ".validate": "newData.isBoolean && $condition.matches(/^(blinded|charmed|deafened|exhaustion|frightened|grappled|incapacitated|invisible|paralyzed|petrified|poisoned|prone|restrained|stunned|unconscious)$/)" + ".validate": "newData.isBoolean() && $condition.matches(/^(blinded|charmed|deafened|exhaustion|frightened|grappled|incapacitated|invisible|paralyzed|petrified|poisoned|prone|restrained|stunned|unconscious)$/)" } }, "reminders": { @@ -1480,7 +1482,7 @@ ".validate": "newData.isString() && newData.val().matches(/^(endTurn|startTurn|damage|timed)$/)" }, "rounds": { - ".validate": "newData.isString() && newData.val().length <= 5" + ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 99" }, "title": { ".validate": "newData.isString() && newData.val().length <= 999" @@ -1560,7 +1562,8 @@ }, "requests": { ".write": true - } + }, + "$other": { ".validate": false } } } }, From c6f6dcf6e8ca3a52b22fdfffe7686c6c0102b49a Mon Sep 17 00:00:00 2001 From: Harm Manders Date: Fri, 17 Nov 2023 14:11:56 +0100 Subject: [PATCH 19/21] Store timed reminder rounds as number --- src/components/ReminderForm.vue | 290 ++++++++++-------- .../encounter/reminders/TargetReminders.vue | 11 +- 2 files changed, 175 insertions(+), 126 deletions(-) diff --git a/src/components/ReminderForm.vue b/src/components/ReminderForm.vue index 3d75fb86..9b6a3bb0 100644 --- a/src/components/ReminderForm.vue +++ b/src/components/ReminderForm.vue @@ -1,16 +1,18 @@ \ No newline at end of file +.select { + max-width: 400px; + margin-bottom: 20px; +} + From dd27e1c411179dd1eb5042ed9bfd2a42bdc8cf43 Mon Sep 17 00:00:00 2001 From: Harm Manders Date: Fri, 17 Nov 2023 14:36:27 +0100 Subject: [PATCH 21/21] rename encounters with generate search tables --- src/views/Admin/GenerateSearchTable.vue | 30 ++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/views/Admin/GenerateSearchTable.vue b/src/views/Admin/GenerateSearchTable.vue index a3a092cd..9a307314 100644 --- a/src/views/Admin/GenerateSearchTable.vue +++ b/src/views/Admin/GenerateSearchTable.vue @@ -93,22 +93,32 @@ export default { if (encounter.encounter !== undefined) { if (encounter.name === undefined) { // Encounter name stored in .encounter should be in .name - await db.ref(`encounters/${uid}/${cid}/${key}/name`).set(entry.encounter); + await db.ref(`encounters/${uid}/${cid}/${key}/name`).set(encounter.encounter); + encounter.name = encounter.encounter; } // .encounter should be removed await db.ref(`encounters/${uid}/${cid}/${key}/encounter`).remove(); + delete encounter.encounter; } - // const search_entry = this.extractFields(entry, this.search_fields[this.ref]); - // const search_ref = db.ref(`${this.search_ref[this.ref]}/${uid}/results/${cid}/${key}`); - // try { - // // await search_ref.set(search_entry) - // } catch(error) { - // console.error(`Couldn't update ${this.search_ref[this.ref]} table`, key, entry.name, error, search_entry) - // } + const search_entry = this.extractFields(encounter, this.search_fields[this.ref]); + const search_ref = db.ref( + `${this.search_ref[this.ref]}/${uid}/results/${cid}/${key}` + ); + try { + await search_ref.set(search_entry); + } catch (error) { + console.error( + `Couldn't update ${this.search_ref[this.ref]} table`, + key, + encounter.name, + error, + search_entry + ); + } } - // const count_ref = db.ref(`${this.search_ref[this.ref]}/${uid}/metadata/${cid}/count`); - // await count_ref.set(Object.keys(entries).length); + const count_ref = db.ref(`${this.search_ref[this.ref]}/${uid}/metadata/${cid}/count`); + await count_ref.set(Object.keys(entries).length); } console.groupEnd(); } else if (this.ref === "campaigns") {