From 3a8680e41a00c34d12db0e03818e285e201e0569 Mon Sep 17 00:00:00 2001 From: Thomas Rubini <74205383+ThomasRubini@users.noreply.github.com> Date: Sat, 1 Apr 2023 16:22:07 +0200 Subject: [PATCH 1/5] add reactions images to npc view --- truthinquiry/routes/routes_admin.py | 16 ++++++++++++++++ truthinquiry/static/js/admin_npc.js | 11 +++++++++++ truthinquiry/templates/admin/npc.html | 22 ++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/truthinquiry/routes/routes_admin.py b/truthinquiry/routes/routes_admin.py index a4d23b7..2044499 100644 --- a/truthinquiry/routes/routes_admin.py +++ b/truthinquiry/routes/routes_admin.py @@ -35,11 +35,27 @@ def npc(npc_id): answer_list = [answer.TEXT for answer in answer_type.TEXT_LOCALE.TEXTS] npc_answers.append(answer_list) + reactions = [{ + "id": reaction.TRAIT.TRAIT_ID, + "name": reaction.TRAIT.NAME_LOCALE.get_text(DEFAULT_LANG).TEXT, + "url": "/api/v1/getReaction?uuid="+reaction.REACTION_UUID + } for reaction in npc_obj.REACTIONS] + + reactions_to_add = [] + for trait in db.session.query(Trait).all(): + if trait.TRAIT_ID not in [reaction.TRAIT.TRAIT_ID for reaction in npc_obj.REACTIONS]: + reactions_to_add.append({ + "id": trait.TRAIT_ID, + "name": trait.NAME_LOCALE.get_text(DEFAULT_LANG).TEXT + }) + npc_dict = { "id": npc_obj.NPC_ID, "name": npc_obj.NAME_LOCALE.get_text(DEFAULT_LANG).TEXT, "img": npc_obj.NPC_ID, "answers": npc_answers, + "reactions": reactions, + "reactions_to_add": reactions_to_add, } return flask.render_template("admin/npc.html", npc=npc_dict) diff --git a/truthinquiry/static/js/admin_npc.js b/truthinquiry/static/js/admin_npc.js index 0b345d0..bae9baf 100644 --- a/truthinquiry/static/js/admin_npc.js +++ b/truthinquiry/static/js/admin_npc.js @@ -31,3 +31,14 @@ async function deleteNpc() { alert("Opération effectuée avec succès"); document.location = "/admin"; } + +function changeReaction(inputNode){ + const parentNode = inputNode.parentNode; + const imgNode = parentNode.querySelector('img'); + + const reader = new FileReader(); + reader.onload = (e)=>{ + imgNode.src = e.target.result + } + reader.readAsDataURL(inputNode.files[0]); +} \ No newline at end of file diff --git a/truthinquiry/templates/admin/npc.html b/truthinquiry/templates/admin/npc.html index 1742f65..7b672d5 100644 --- a/truthinquiry/templates/admin/npc.html +++ b/truthinquiry/templates/admin/npc.html @@ -34,6 +34,28 @@

Image du personnage

{{'Image du personnage' + (' ' + npc.get('name') if npc.get('name') else '')}} + +
+

Réactions

+ + {%for reaction in npc.get("reactions")%} +
+

{{reaction.get('name')}}

+ + +
+ {%endfor%} + + + {%if npc.get("reaction_to_add")%} + + {%endif%} +
+

Réponses aux questions lors de l'interrogation

From d5199a6ef153237737d702d31bc3cd3901a0f2c1 Mon Sep 17 00:00:00 2001 From: Thomas Rubini <74205383+ThomasRubini@users.noreply.github.com> Date: Sat, 1 Apr 2023 17:47:48 +0200 Subject: [PATCH 2/5] allow to add and delete reactions (frontend only) --- truthinquiry/static/js/admin_npc.js | 31 ++++++++++++++++++++++++++ truthinquiry/templates/admin/npc.html | 32 +++++++++++++-------------- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/truthinquiry/static/js/admin_npc.js b/truthinquiry/static/js/admin_npc.js index bae9baf..71e23e5 100644 --- a/truthinquiry/static/js/admin_npc.js +++ b/truthinquiry/static/js/admin_npc.js @@ -41,4 +41,35 @@ function changeReaction(inputNode){ imgNode.src = e.target.result } reader.readAsDataURL(inputNode.files[0]); +} + +function deleteReaction(node){ + const reactionNode = node.parentNode; + const reactionId = reactionNode.querySelector(".reaction_id").value; + const reactionName = reactionNode.querySelector("p").innerText; + + reactionNode.parentNode.removeChild(reactionNode); + + const option = document.createElement("option"); + option.value = reactionId + option.innerText = reactionName + + reactions_to_add.appendChild(option); +} + +function addReaction(selectNode){ + const selectedOptionNode = selectNode.selectedOptions[0]; + + const reactionId = selectedOptionNode.value; + const reactionName = selectedOptionNode.innerText; + + selectNode.removeChild(selectedOptionNode); + + const newReaction = reactions.querySelector("div").cloneNode(true); + newReaction.querySelector("img").src = ""; + newReaction.querySelector(".img_input").value = null; + newReaction.querySelector(".reaction_id").value = reactionId + newReaction.querySelector("p").innerText = reactionName + + reactions.appendChild(newReaction); } \ No newline at end of file diff --git a/truthinquiry/templates/admin/npc.html b/truthinquiry/templates/admin/npc.html index 7b672d5..6e98c63 100644 --- a/truthinquiry/templates/admin/npc.html +++ b/truthinquiry/templates/admin/npc.html @@ -35,27 +35,27 @@ {{'Image du personnage' + (' ' + npc.get('name') if npc.get('name') else '')}}
-
+

Réactions

- {%for reaction in npc.get("reactions")%} -
-

{{reaction.get('name')}}

- - -
- {%endfor%} - - - {%if npc.get("reaction_to_add")%} - + + + {%endfor%} - - {%endif%}
+ +

Réponses aux questions lors de l'interrogation

From 1cd238b4ab6bca6320c7eebf20f479f2e06fea58 Mon Sep 17 00:00:00 2001 From: Thomas Rubini <74205383+ThomasRubini@users.noreply.github.com> Date: Sat, 1 Apr 2023 18:19:56 +0200 Subject: [PATCH 3/5] add content type form --- truthinquiry/static/js/api.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/truthinquiry/static/js/api.js b/truthinquiry/static/js/api.js index b49f660..a55b5bc 100644 --- a/truthinquiry/static/js/api.js +++ b/truthinquiry/static/js/api.js @@ -17,6 +17,8 @@ async function makeAPIRequest(endpoint, body, options={}) { if (options["content"] === 'json') { fetchOptions["headers"]["Content-Type"] = 'application/json' fetchOptions["body"] = JSON.stringify(body) + } else if (options["content"] === 'form') { + fetchOptions["body"] = body; } else { fetchOptions["body"] = new URLSearchParams(body); } From 93409c5e54d0ec55e0e95b9f48dba595906f2a88 Mon Sep 17 00:00:00 2001 From: Thomas Rubini <74205383+ThomasRubini@users.noreply.github.com> Date: Sat, 1 Apr 2023 18:54:08 +0200 Subject: [PATCH 4/5] allow to add and delete reactions (backend) --- truthinquiry/routes/routes_api_admin.py | 35 ++++++++++++++++++- truthinquiry/static/js/admin_npc.js | 45 ++++++++++++++++++++++--- truthinquiry/templates/admin/npc.html | 2 +- 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/truthinquiry/routes/routes_api_admin.py b/truthinquiry/routes/routes_api_admin.py index 09ad261..b267825 100644 --- a/truthinquiry/routes/routes_api_admin.py +++ b/truthinquiry/routes/routes_api_admin.py @@ -1,7 +1,7 @@ import os import flask -from sqlalchemy import select, delete, or_ +from sqlalchemy import select, delete, and_ from truthinquiry.ext.database.models import * from truthinquiry.ext.database.fsa import db @@ -176,3 +176,36 @@ def delete_npc(): db.session.execute(delete(Npc).where(Npc.NPC_ID==input_npc_id)) db.session.commit() return {} + +@routes_api_admin.route("/setReaction", methods=["GET", "POST"]) +@require_admin(api=True) +def setReaction(): + input_npc_id = flask.request.values["npc_id"] + input_trait_id = flask.request.values["trait_id"] + + row = db.session.execute( + select(Reaction) + .where(and_( + Reaction.NPC_ID==input_npc_id, + Reaction.TRAIT_ID==input_trait_id + )) + ).first() + + reaction = None if row == None else row[0] + + + if len(flask.request.files) == 0: # want to delete + if reaction: + db.session.delete(reaction) + else: + return {"msg": "No such reaction"} # Not an error because this can be intentional + else: + input_reaction_file = flask.request.files['file'] + if not reaction: + reaction = Reaction(None, input_npc_id, input_trait_id) + db.session.add(reaction) + reaction.IMG = input_reaction_file.read() + + db.session.commit() + + return {} diff --git a/truthinquiry/static/js/admin_npc.js b/truthinquiry/static/js/admin_npc.js index 71e23e5..cda9de1 100644 --- a/truthinquiry/static/js/admin_npc.js +++ b/truthinquiry/static/js/admin_npc.js @@ -1,4 +1,7 @@ -function createOrUpdateNpc() { + +const reactionsDelta = {} + +async function createOrUpdateNpc() { const data = {}; data["id"] = document.querySelector("#npc_id").value; data["name"] = document.querySelector("#npc_name").value; @@ -16,9 +19,36 @@ function createOrUpdateNpc() { }); } - makeAPIRequest("admin/setNpc", {"npc": data, "lang": "FR"}, {"content": "json"}).then(() => { - alert("Opération effectuée avec succès"); - }); + await makeAPIRequest("admin/setNpc", {"npc": data, "lang": "FR"}, {"content": "json"}); + + await uploadReactionsDelta(); + + alert("Opération effectuée avec succès"); +} + +async function uploadReactionsDelta() { + let requests = []; + + + for(const [reactionId, reactionNode] of Object.entries(reactionsDelta)){ + const formData = new FormData(); + formData.append("npc_id", npc_id.value); + formData.append("trait_id", reactionId); + + if(reactionNode === null) formData.append("file", "null"); + else{ + const file = reactionNode.querySelector(".img_input").files[0] + formData.append("file", file ? file : ""); + } + + requests.push(makeAPIRequest("admin/setReaction", formData, {"content": "form"})); + } + + for(request of requests){ + await request; + } + + } async function deleteNpc() { @@ -35,12 +65,15 @@ async function deleteNpc() { function changeReaction(inputNode){ const parentNode = inputNode.parentNode; const imgNode = parentNode.querySelector('img'); + const reactionId = parentNode.querySelector('.reaction_id').value; const reader = new FileReader(); reader.onload = (e)=>{ imgNode.src = e.target.result } reader.readAsDataURL(inputNode.files[0]); + + reactionsDelta[reactionId] = parentNode; } function deleteReaction(node){ @@ -55,6 +88,8 @@ function deleteReaction(node){ option.innerText = reactionName reactions_to_add.appendChild(option); + + reactionsDelta[reactionId] = null; } function addReaction(selectNode){ @@ -72,4 +107,6 @@ function addReaction(selectNode){ newReaction.querySelector("p").innerText = reactionName reactions.appendChild(newReaction); + + reactionsDelta[reactionId] = newReaction; } \ No newline at end of file diff --git a/truthinquiry/templates/admin/npc.html b/truthinquiry/templates/admin/npc.html index 6e98c63..e817808 100644 --- a/truthinquiry/templates/admin/npc.html +++ b/truthinquiry/templates/admin/npc.html @@ -51,7 +51,7 @@ From d9ddb96e808a7a77d5fe3d625d0bdb98f55f00e2 Mon Sep 17 00:00:00 2001 From: Thomas Rubini <74205383+ThomasRubini@users.noreply.github.com> Date: Sat, 1 Apr 2023 18:55:51 +0200 Subject: [PATCH 5/5] remove reaction_id with trait_id --- truthinquiry/static/js/admin_npc.js | 20 ++++++++++---------- truthinquiry/templates/admin/npc.html | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/truthinquiry/static/js/admin_npc.js b/truthinquiry/static/js/admin_npc.js index cda9de1..b495208 100644 --- a/truthinquiry/static/js/admin_npc.js +++ b/truthinquiry/static/js/admin_npc.js @@ -30,10 +30,10 @@ async function uploadReactionsDelta() { let requests = []; - for(const [reactionId, reactionNode] of Object.entries(reactionsDelta)){ + for(const [traitId, reactionNode] of Object.entries(reactionsDelta)){ const formData = new FormData(); formData.append("npc_id", npc_id.value); - formData.append("trait_id", reactionId); + formData.append("trait_id", traitId); if(reactionNode === null) formData.append("file", "null"); else{ @@ -65,7 +65,7 @@ async function deleteNpc() { function changeReaction(inputNode){ const parentNode = inputNode.parentNode; const imgNode = parentNode.querySelector('img'); - const reactionId = parentNode.querySelector('.reaction_id').value; + const traitId = parentNode.querySelector('.trait_id').value; const reader = new FileReader(); reader.onload = (e)=>{ @@ -73,29 +73,29 @@ function changeReaction(inputNode){ } reader.readAsDataURL(inputNode.files[0]); - reactionsDelta[reactionId] = parentNode; + reactionsDelta[traitId] = parentNode; } function deleteReaction(node){ const reactionNode = node.parentNode; - const reactionId = reactionNode.querySelector(".reaction_id").value; + const traitId = reactionNode.querySelector(".trait_id").value; const reactionName = reactionNode.querySelector("p").innerText; reactionNode.parentNode.removeChild(reactionNode); const option = document.createElement("option"); - option.value = reactionId + option.value = traitId option.innerText = reactionName reactions_to_add.appendChild(option); - reactionsDelta[reactionId] = null; + reactionsDelta[traitId] = null; } function addReaction(selectNode){ const selectedOptionNode = selectNode.selectedOptions[0]; - const reactionId = selectedOptionNode.value; + const traitId = selectedOptionNode.value; const reactionName = selectedOptionNode.innerText; selectNode.removeChild(selectedOptionNode); @@ -103,10 +103,10 @@ function addReaction(selectNode){ const newReaction = reactions.querySelector("div").cloneNode(true); newReaction.querySelector("img").src = ""; newReaction.querySelector(".img_input").value = null; - newReaction.querySelector(".reaction_id").value = reactionId + newReaction.querySelector(".trait_id").value = traitId newReaction.querySelector("p").innerText = reactionName reactions.appendChild(newReaction); - reactionsDelta[reactionId] = newReaction; + reactionsDelta[traitId] = newReaction; } \ No newline at end of file diff --git a/truthinquiry/templates/admin/npc.html b/truthinquiry/templates/admin/npc.html index e817808..972a8b8 100644 --- a/truthinquiry/templates/admin/npc.html +++ b/truthinquiry/templates/admin/npc.html @@ -43,7 +43,7 @@

{{reaction.get('name')}}

- +
{%endfor%} @@ -52,7 +52,7 @@