aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2021-01-29 14:10:45 +0100
committerMarvin Borner2021-01-29 14:10:45 +0100
commitaec1e8f2cd4c0fdedd200fc30094587c0834d372 (patch)
tree407946fbe687b252d4133067aa770e0ee24851b1
parent2eff2deb98280aa61241e06163c87155911bbfae (diff)
parent8637186a9f835972a5a0b96e4df1665d6d42557a (diff)
Merge branch 'crop'
-rw-r--r--profile.txt1
-rw-r--r--profile/index.js112
-rw-r--r--profile/public/index.html30
-rw-r--r--profile/public/script.js100
-rw-r--r--profile/public/style.css18
-rw-r--r--profile/public/user.js6
-rw-r--r--profile/public/users.html10
-rw-r--r--profile/public/users.js2
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, "&lt;").replace(/>/g, "&gt;");
- try {
- await db.query("INSERT INTO profile_answers (question_id, user_id, answer) VALUES (?, ?, ?)", [
- qid,
- req.session.uid,
- answer.replace(/</g, "&lt;").replace(/>/g, "&gt;"),
- ]);
- } 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, "&lt;").replace(/>/g, "&gt;");
+ 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, "&lt;").replace(/>/g, "&gt;")}</b> <span>${
+ (question.answer || "nichts").replace(/</g, "&lt;").replace(/>/g, "&gt;") || ""
+ }</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")