diff options
author | Marvin Borner | 2021-01-29 14:10:45 +0100 |
---|---|---|
committer | Marvin Borner | 2021-01-29 14:10:45 +0100 |
commit | aec1e8f2cd4c0fdedd200fc30094587c0834d372 (patch) | |
tree | 407946fbe687b252d4133067aa770e0ee24851b1 | |
parent | 2eff2deb98280aa61241e06163c87155911bbfae (diff) | |
parent | 8637186a9f835972a5a0b96e4df1665d6d42557a (diff) |
Merge branch 'crop'
-rw-r--r-- | profile.txt | 1 | ||||
-rw-r--r-- | profile/index.js | 112 | ||||
-rw-r--r-- | profile/public/index.html | 30 | ||||
-rw-r--r-- | profile/public/script.js | 100 | ||||
-rw-r--r-- | profile/public/style.css | 18 | ||||
-rw-r--r-- | profile/public/user.js | 6 | ||||
-rw-r--r-- | profile/public/users.html | 10 | ||||
-rw-r--r-- | profile/public/users.js | 2 |
8 files changed, 194 insertions, 85 deletions
diff --git a/profile.txt b/profile.txt index 66655f7..77cae98 100644 --- a/profile.txt +++ b/profile.txt @@ -8,3 +8,4 @@ Lebensmotto/Seniorquote - text Lieblingsbands/-musiker/-genre - text Lieblingsfach - text Hassfach - text +Kinderbild - file
\ No newline at end of file diff --git a/profile/index.js b/profile/index.js index ee81632..cc0972a 100644 --- a/profile/index.js +++ b/profile/index.js @@ -38,87 +38,57 @@ app.get("/api/questions", async (req, res) => { res.json(questions); }); -app.post("/api/add", async (req, res) => { - try { - for (let qid in req.body) { - if (!req.body.hasOwnProperty(qid) || req.body[qid] === "dbg-image") continue; - let answer = req.body[qid].replace(/</g, "<").replace(/>/g, ">"); - try { - await db.query("INSERT INTO profile_answers (question_id, user_id, answer) VALUES (?, ?, ?)", [ - qid, - req.session.uid, - answer.replace(/</g, "<").replace(/>/g, ">"), - ]); - } catch (e) { - console.error(e); - } - } - for (let fid in req.files) { - if (!req.files.hasOwnProperty(fid)) return; - - let image, imageType, imageName; +app.post("/api/answer", async (req, res) => { + return await answer(req, res, "INSERT INTO profile_answers (answer, question_id, user_id) VALUE (?,?,?)"); +}); +app.put("/api/answer", async (req, res) => { + return await answer(req, res, "UPDATE profile_answers SET answer = ? WHERE question_id = ? AND user_id = ?"); +}); - image = req.files[fid]; - imageType = image.name.split(".").reverse()[0]; - imageName = `${req.session.uid}_${new Date().getTime()}.${imageType}`; - image.mv(__dirname + "/public/uploads/" + imageName); +async function answer(req, res, qs) { + try { + for (const qid in req.body) { + if (!req.body.hasOwnProperty(qid)) continue; + const answer = req.body[qid]; try { - await db.query("INSERT INTO profile_answers (question_id, user_id, answer) VALUES (?, ?, ?)", [ - fid, - req.session.uid, - imageName, - ]); + await db.query(qs, [answer, qid, req.session.uid]); } catch (e) { console.error(e); } } - res.send("ok"); + res.json({ success: true }); } catch (e) { console.error(e); - res.send("error"); + res.json({ success: false }); } +} + +app.post("/api/answerImage", async (req, res) => { + return await answerImage(req, res, "INSERT INTO profile_answers (answer, question_id, user_id) VALUE (?,?,?)"); +}); +app.put("/api/answerImage", async (req, res) => { + return await answerImage(req, res, "UPDATE profile_answers SET answer = ? WHERE question_id = ? AND user_id = ?"); }); -app.put("/api/update", async (req, res) => { +async function answerImage(req, res, qs) { try { - for (let qid in req.body) { - if (!req.body.hasOwnProperty(qid) || req.body[qid] === "dbg-image") continue; - let answer = req.body[qid].replace(/</g, "<").replace(/>/g, ">"); + for (const fid in req.files) { + if (!req.files.hasOwnProperty(fid)) continue; + const image = req.files[fid]; + const name = `child_${req.session.uid}.jpg`; try { - await db.query("UPDATE profile_answers SET answer = ? WHERE question_id = ? AND user_id = ?", [ - answer, - qid, - req.session.uid, - ]); + await image.mv(`${__dirname}/public/uploads/${name}`); + await db.query(qs, [name, fid, req.session.uid]); } catch (e) { console.error(e); } } - for (let fid in req.files) { - if (!req.files.hasOwnProperty(fid)) return; - - let image, imageType, imageName; - - image = req.files[fid]; - imageType = image.name.split(".").reverse()[0]; - imageName = `${req.session.uid}_${new Date().getTime()}.${imageType}`; - image.mv(__dirname + "/public/uploads/" + imageName); - try { - await db.query("UPDATE profile_answers SET answer = ? WHERE question_id = ? AND user_id = ?", [ - imageName, - fid, - req.session.uid, - ]); - } catch (e) { - console.error(e); - } - } - res.send("ok"); + res.json({ success: true }); } catch (e) { console.error(e); - res.send("error"); + res.json({ success: false }); } -}); +} // Comments API app.get("/api/comments/:uid", async (req, res) => { @@ -182,10 +152,10 @@ app.delete("/api/comment", async (req, res) => { // Char API app.get("/api/char/:uid", async (req, res) => { const uid = req.params.uid; - const char = await db.query( - "SELECT txt FROM profile_char WHERE profile_id = ? AND user_id = ?", - [uid, req.session.uid], - ); + const char = await db.query("SELECT txt FROM profile_char WHERE profile_id = ? AND user_id = ?", [ + uid, + req.session.uid, + ]); res.json(char.length > 0 ? char[0] : {}); }); @@ -194,7 +164,11 @@ app.post("/api/char/:uid", async (req, res) => { const { char } = req.body; if (!char || char.length > 255) return res.json({ success: false }); try { - await db.query("INSERT INTO profile_char (profile_id, user_id, txt) VALUE (?,?,?)", [uid, req.session.uid, char]); + await db.query("INSERT INTO profile_char (profile_id, user_id, txt) VALUE (?,?,?)", [ + uid, + req.session.uid, + char, + ]); res.json({ success: true }); } catch (e) { console.error(e); @@ -207,7 +181,11 @@ app.put("/api/char/:uid", async (req, res) => { const { char } = req.body; if (!char || char.length > 255) return res.json({ success: false }); try { - await db.query("UPDATE profile_char SET txt = ? WHERE profile_id = ? AND user_id = ?", [char, uid, req.session.uid]); + await db.query("UPDATE profile_char SET txt = ? WHERE profile_id = ? AND user_id = ?", [ + char, + uid, + req.session.uid, + ]); res.json({ success: true }); } catch (e) { console.error(e); diff --git a/profile/public/index.html b/profile/public/index.html index 672f409..91cb545 100644 --- a/profile/public/index.html +++ b/profile/public/index.html @@ -10,6 +10,12 @@ crossorigin="anonymous" /> <link rel="stylesheet" href="style.css" type="text/css" media="all" /> + <link + rel="stylesheet" + href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.9/cropper.min.css" + integrity="sha512-w+u2vZqMNUVngx+0GVZYM21Qm093kAexjueWOv9e9nIeYJb1iEfiHC7Y+VvmP/tviQyA5IR32mwN/5hTEJx6Ng==" + crossorigin="anonymous" + /> <title>Steckbrief</title> </head> @@ -20,13 +26,33 @@ </div> <main> <h2 id="username"></h2> + <p> + Bitte fülle diese Seite nur mit korrekten Daten aus, da diese direkt in der Abizeitung dargestellt + werden. Auf dem Kinderbild solltest du gut sichtbar und nicht älter als 8 Jahre sein. + </p> <form class="pure-form pure-form-stacked"> <fieldset> - <!-- TODO: Consider autosave --> - <button type="submit" class="pure-button pure-button-primary">Wohooo</button> + <button type="submit" class="pure-button pure-button-primary">Senden</button> </fieldset> </form> </main> + <div class="popup"> + <img id="popup-img" src="https://fengyuanchen.github.io/cropperjs/images/picture.jpg" alt="Picture" /> + <button class="pure-button pure-button-primary" id="save-btn">Übernehmen</button> + <label for="rotation-slider">Drehen</label> + <input id="rotation-slider" type="range" min="-180" max="180" value="0" /> + <div class="control-btns"> + <button class="pure-button pure-button-primary" id="rot45" data-value="-45" data-rot="true">45</button> + <button class="pure-button pure-button-primary" id="nrot45" data-value="45" data-rot="true">-45</button> + <button class="pure-button pure-button-primary" id="norm" data-value="0" data-rot="false">0</button> + </div> + </div> + + <script + src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.9/cropper.min.js" + integrity="sha512-9pGiHYK23sqK5Zm0oF45sNBAX/JqbZEP7bSDHyt+nT3GddF+VFIcYNqREt0GDpmFVZI3LZ17Zu9nMMc9iktkCw==" + crossorigin="anonymous" + ></script> <script src="script.js"></script> </body> </html> diff --git a/profile/public/script.js b/profile/public/script.js index b927f9f..db9a277 100644 --- a/profile/public/script.js +++ b/profile/public/script.js @@ -1,9 +1,42 @@ const fs = document.querySelector("fieldset"); const form = document.querySelector("form"); let init = true; +let imageInit = true; +let imageID = -1; + +const popup = document.querySelector(".popup"); +const popupImage = document.querySelector("#popup-img"); +const saveBtn = document.querySelector("#save-btn"); +const slider = document.querySelector("#rotation-slider"); +const controlButtons = document.querySelectorAll(".control-btns button"); +let cropper = undefined; + +const crop = () => { + cropper = new Cropper(document.getElementById("popup-img"), { + // Consider dataset id + //dragMode: "move", + aspectRatio: 10 / 13, + //autoCropArea: 0.65, + //restore: false, + //guides: false, + //center: false, + //highlight: false, + //cropBoxMovable: false, + //cropBoxResizable: false, + //toggleDragModeOnDblclick: false, + }); +}; + +NodeList.prototype.on = function (listener, event) { + for (const node of this) { + node.addEventListener(listener, event); + } +}; function updateHeading(user) { - document.getElementById("username").textContent = `Steckbrief: ${user.name} ${user.middlename || ""} ${user.surname}`; + document.getElementById("username").textContent = `Steckbrief: ${user.name} ${user.middlename || ""} ${ + user.surname + }`; } function appendQuestions(question) { @@ -19,6 +52,7 @@ function appendQuestions(question) { img.src = "uploads/" + question.answer; img.alt = "Image"; div.appendChild(img); + imageInit = false; } const field = document.createElement("input"); @@ -28,7 +62,21 @@ function appendQuestions(question) { field.value = question.answer || ""; field.placeholder = question.question; field.type = question.type; - if (question.type === "file") field.accept = "image/*"; + if (question.type === "file") { + imageID = question.id; + field.accept = "image/*"; + field.addEventListener("input", (e) => { + const file = e.target.files[0]; + popupImage.file = file; + const reader = new FileReader(); + reader.addEventListener("load", (e) => { + popupImage.src = e.target.result; + popup.style.display = "block"; + crop(); + }); + reader.readAsDataURL(file); + }); + } div.appendChild(field); fs.insertBefore(div, fs.querySelector("button")); @@ -36,20 +84,52 @@ function appendQuestions(question) { form.addEventListener("submit", async (evt) => { evt.preventDefault(); - const url = init ? "api/add" : "api/update"; const method = init ? "POST" : "PUT"; const inputs = form.querySelectorAll("input"); - const body = new FormData(); + const rawBody = {}; for (const input of inputs) { - if (input.type !== "file") body.append(input.name, input.value); - else body.append(input.name, input.files[0] ?? "dbg-image"); + if (input.type !== "file") rawBody[input.name] = input.value; } + const body = JSON.stringify(rawBody); + + const resp = await fetch("api/answer", { method, body, headers: { "Content-Type": "application/json" } }); + const res = await resp.json(); + if (!res.success) alert("An error occurred"); + else init = false; +}); + +saveBtn.addEventListener("click", (e) => { + cropper.getCroppedCanvas().toBlob(async (blob) => { + const url = "api/answerImage"; + const method = imageInit ? "POST" : "PUT"; + const body = new FormData(); + if (imageID === -1) { + return; + } + body.append(imageID, blob); + const resp = await fetch(url, { method, body }); + const res = await resp.json(); + if (!res.success) { + alert("An error occurred"); + } else { + imageInit = false; + popup.style.display = "none"; + cropper.destroy(); + document.querySelectorAll("img").forEach((elem) => { + if (elem.src.startsWith("http")) elem.src += "#" + new Date().getTime(); + }); + } + }, "image/jpeg"); +}); + +slider.addEventListener("input", (e) => { + cropper.rotateTo(-e.target.value); +}); - const resp = await fetch(url, { method, body }); - const res = await resp.text(); - if (res !== "ok") alert("AHHHH"); - else location.reload(); +controlButtons.on("click", (e) => { + if (e.target.dataset.rot === "true") cropper.rotate(+e.target.dataset.value); + else cropper.rotateTo(+e.target.dataset.value); }); fetch("/auth/api/self") diff --git a/profile/public/style.css b/profile/public/style.css index 106e590..becb428 100644 --- a/profile/public/style.css +++ b/profile/public/style.css @@ -54,12 +54,14 @@ img { } #user h1, -#comments h2 { +#comments h2, +#char h2 { cursor: pointer; } #user h1:hover, -#comments h2:hover { +#comments h2:hover, +#char h2:hover { opacity: 0.8; } @@ -132,3 +134,15 @@ img { height: 80%; margin-bottom: 12px; } + +.popup { + z-index: 10; + position: absolute; + display: none; + max-height: 600px; + max-width: 600px; + left: 50%; + top: 50%; + transform: translateX(-50%) translateY(-50%); + border: 1px solid black; +} diff --git a/profile/public/user.js b/profile/public/user.js index 39d6713..963904c 100644 --- a/profile/public/user.js +++ b/profile/public/user.js @@ -10,10 +10,12 @@ function addUser(userData) { const questions = userData.questions; const user = userData.user; for (const questionID in questions) { - if (!questions.hasOwnProperty(questionID)) continue; + if (!questions.hasOwnProperty(questionID) || questions[questionID].type === "file") continue; const question = questions[questionID]; const div = document.createElement("div"); - div.innerHTML = `<b>${question.question}</b> <span>${question.answer || ""}</span>`; + div.innerHTML = `<b>${question.question.replace(/</g, "<").replace(/>/g, ">")}</b> <span>${ + (question.answer || "nichts").replace(/</g, "<").replace(/>/g, ">") || "" + }</span>`; divs.push(div); } const h1 = document.createElement("h1"); diff --git a/profile/public/users.html b/profile/public/users.html index ebca429..f7bd346 100644 --- a/profile/public/users.html +++ b/profile/public/users.html @@ -19,12 +19,20 @@ </div> <main> - <p>Nutzerliste</p> + <p> + Hier kannst du andere Schüler kommentieren und Erkennungsmerkmale schreiben. Diese werden dann auf dem + Steckbrief der jeweiligen Person in der Abizeitung dargestellt. + </p> <div id="student-list"> + TGM13.1 <ul id="class_1"></ul> + TGM13.2 <ul id="class_2"></ul> + TGTM13.1 <ul id="class_3"></ul> + TGI13.1 <ul id="class_4"></ul> + TGI13.2 <ul id="class_5"></ul> </div> </main> diff --git a/profile/public/users.js b/profile/public/users.js index 77bc85c..73f0e4a 100644 --- a/profile/public/users.js +++ b/profile/public/users.js @@ -2,7 +2,7 @@ function addUser(user) { const li = document.createElement("li"); li.textContent = `${user.name} ${user.middlename || ""} ${user.surname}`; li.addEventListener("click", () => window.location.assign(`./user.html?uid=${user.id}`)); - document.getElementById("class_" + user.class_id).appendChild(li); + if (user.class_id < 6) document.getElementById("class_" + user.class_id).appendChild(li); } fetch("/auth/api/list?class=all") |