diff options
author | Jani Peter Karhunen <jkarhun2@local> | 2023-11-25 03:32:29 +0200 |
---|---|---|
committer | Jani Peter Karhunen <jkarhun2@local> | 2023-11-25 03:32:29 +0200 |
commit | d2de3ae10b6f5314bd4b8243218212d2004f35b0 (patch) | |
tree | 2ab448e0c2ec361478851dbcb43bcd176d17b584 | |
parent | c059696450d301b99956d643c21b0e46b4fc39dc (diff) |
MEGA Commit. Rework of routing. Visuals. Answer analysis and much more.
37 files changed, 1017 insertions, 375 deletions
@@ -3,21 +3,36 @@ TO GET IT RUNNING: -Install postgresql for local user & get it running +Install postgresql for local user & get it running (as in course material) - $ wget https://github.com/hy-tsoha/local-pg/raw/master/pg-install.sh - $ bash pg-install.sh - $ postrgres & - + +Install poetry if nessesary. (refer your distro) +- $ pip install --user poetry +- $ pipx install poetry + Clone the source, get tables ready & install poetry dependencies - $ git clone https://github.com/triionhe/kyselma.git - $ cd kyselma -- $ psql < SCHEMA.sql -- $ poetry install +- $ psql < SCHEMA.sql (BE CAREFUL! This drops some tables.) +- $ poetry install --no-root Start the app in poetry virtual environment -- $ SQLALCHEMY_DATABASE_URI="postgresql:///$USER" SECRET_KEY=923987295 poetry run flask run +- $ SQLALCHEMY_DATABASE_URI="postgresql:///$USER" SECRET_KEY=29347884 poetry run flask run + +Surf to the webpage and start two sessions for better testing +- $ firefox http://localhost:5000/ http://127.0.0.1:5000/ + + DONE: +- Vastausten anto +- Vastausten tarkistelu +- Kyselyn luomisen näyttö +- Kyselyn lukitseminen vastattavaksi +- Kysymyksen näyttö +- Ulkoasu - Voi lisätä kyselyn - Kysymyksen mukana lisätään vastaus - Kysymyksen lisäys @@ -31,13 +46,11 @@ DONE: - Nettisivurunko TODO: -- Kyselyn luomisen näyttö -- Kyselyn lukitseminen vastattavaksi -- Kysymyksen näyttö -- Ulkoasu - Moderointi -- Vastausten anto -- Vastausten tarkistelu +- Parempi ulkoasu +- Vastauksen ja luomisen aloittamisen yksinkertaistaminen +- Tietoturvaseikat? +- Eniten ja vähiten yhdenmukaiset vastaajat ... Tarkoitus on luoda sivu jossa voi luoda kysymyksiä ja kyselyitä, joita @@ -92,3 +105,6 @@ Kysymykset, kyselyt, vastaukset tallennetaan asianmukaisiin tauluihin. Ominaisuuksia joiden tekemistä voi harkita: - Jokaisella kyselyllä on elinikä jonka jälkeen ne siivotaan. - Kysymyksiin voi liittää kuvia + +Ikonit (CC) pixellove: +https://www.svgrepo.com/collection/pixellove-bordered-vectors/ @@ -1,3 +1,4 @@ +DROP TABLE users, questions, answers, questionaires, quiz_links; CREATE TABLE users ( id SERIAL PRIMARY KEY, nick TEXT, @@ -21,6 +22,50 @@ CREATE TABLE questionaires ( id SERIAL PRIMARY KEY, questionset INT[] DEFAULT '{}', creator_id INT, - ready BOOLEAN DEFAULT FALSE, created INT ); +CREATE TABLE quiz_links ( + id SERIAL PRIMARY KEY, + quiz_id INT, + link TEXT, + created INT +); +INSERT INTO users (nick, created) VALUES ('Raili Niemi', 57 ); +INSERT INTO users (nick, created) VALUES ('Tea Jalava', 36 ); +INSERT INTO users (nick, created) VALUES ('Eero Metsäranta', 47 ); +INSERT INTO questions (question, neg_answer, pos_answer, created) + VALUES ('Mikä ikä?', '0', '100', 99 ); +INSERT INTO questions (question, neg_answer, pos_answer, created) + VALUES ('Mikä vointi?', 'huono', 'hyvä', 99 ); +INSERT INTO questions (question, neg_answer, pos_answer, created) + VALUES ('Ulkoiletko?', 'viime vuonna', 'joka päivä', 99 ); +INSERT INTO questions (question, neg_answer, pos_answer, created) + VALUES ('kys?', 'ei vielä', 'ei koskaan', 99 ); +INSERT INTO answers (user_id, question_id, answer, created) + VALUES (1, 1, 570, 99 ); +INSERT INTO answers (user_id, question_id, answer, created) + VALUES (1, 2, 670, 99 ); +INSERT INTO answers (user_id, question_id, answer, created) + VALUES (1, 3, 888, 99 ); +INSERT INTO answers (user_id, question_id, answer, created) + VALUES (1, 4, 999, 99 ); +INSERT INTO answers (user_id, question_id, answer, created) + VALUES (2, 1, 360, 99 ); +INSERT INTO answers (user_id, question_id, answer, created) + VALUES (2, 2, 230, 99 ); +INSERT INTO answers (user_id, question_id, answer, created) + VALUES (2, 3, 120, 99 ); +INSERT INTO answers (user_id, question_id, answer, created) + VALUES (2, 4, 123, 99 ); +INSERT INTO answers (user_id, question_id, answer, created) + VALUES (3, 1, 470, 99 ); +INSERT INTO answers (user_id, question_id, answer, created) + VALUES (3, 2, 570, 99 ); +INSERT INTO answers (user_id, question_id, answer, created) + VALUES (3, 3, 321, 99 ); +INSERT INTO answers (user_id, question_id, answer, created) + VALUES (3, 4, 785, 99 ); +INSERT INTO questionaires (questionset, creator_id, created) + VALUES ('{1,2,3,4}', 1, 666); +INSERT INTO quiz_links (quiz_id, link, created) + VALUES (1, 'kyselama', 666); @@ -8,8 +8,8 @@ app.config["SQLALCHEMY_DATABASE_URI"] = getenv("SQLALCHEMY_DATABASE_URI") db.init_app(app) import routes.base -import routes.set.nick -import routes.set.quiz -import routes.set.question -import routes.set.answers -import routes.get.quiz +import routes.answer +import routes.create +import routes.analyse +import routes.question + diff --git a/db_actions.py b/db_actions.py index 5a76b00..5f793fc 100644 --- a/db_actions.py +++ b/db_actions.py @@ -65,6 +65,32 @@ def quiz_add( quiz_id, question_id ): }) db.session.commit() + +def set_quiz_link( quiz_id, link ): + sql = "INSERT \ + INTO quiz_links (quiz_id, link, created) \ + VALUES (:quiz_id, :link, :created)" + result = db.session.execute( text(sql), + { "quiz_id":quiz_id, "link":link, "created":int(time()) } ) + db.session.commit() + + +def find_quiz_by_link( link ): + sql = "SELECT quiz_id \ + FROM quiz_links \ + WHERE link=:link;" + result = db.session.execute(text(sql), { "link":link }).fetchone() + return result[0] if result else result + + +def get_quiz_link( quiz_id ): + sql = "SELECT link \ + FROM quiz_links \ + WHERE quiz_id=:quiz_id;" + result = db.session.execute(text(sql), { "quiz_id":quiz_id }).fetchone() + return result[0] if result else result + + def answer_new(user_id, question_id, answer): sql = "INSERT \ INTO answers (user_id, question_id, answer, created) \ @@ -77,6 +103,7 @@ def answer_new(user_id, question_id, answer): } ) db.session.commit() + def get_questions(quiz_id): sql = "SELECT q.id, q.question, q.neg_answer, q.pos_answer, a.answer \ FROM questionaires quiz \ @@ -85,15 +112,62 @@ def get_questions(quiz_id): WHERE a.question_id = q.id AND quiz.id = (:quiz_id);" return db.session.execute( text(sql), { "quiz_id":quiz_id } ).fetchall() +def get_comparable(quiz_id,user1,user2): + sql = "SELECT q.question, q.neg_answer, q.pos_answer, \ + a1.answer, a2.answer, \ + 100 - ABS( a1.answer - a2.answer ) / 10 \ + FROM questionaires quiz \ + JOIN questions q ON q.id = ANY(quiz.questionset) \ + JOIN answers a1 ON a1.user_id = (:user1) \ + JOIN answers a2 ON a2.user_id = (:user2) \ + WHERE a1.question_id = q.id \ + AND a2.question_id = q.id \ + AND quiz.id = (:quiz_id);" + return db.session.execute( text(sql), { + "quiz_id":quiz_id, + "user1":user1, + "user2":user2 + } ).fetchall() + def get_user_answer(user_id, question_id): sql = "SELECT answer \ - FROM answers \ - WHERE question_id = (:question_id) AND user_id = (:user_id);" + FROM answers \ + WHERE question_id = (:question_id) AND user_id = (:user_id);" result = db.session.execute( text(sql), { 'question_id': question_id, 'user_id': user_id } ).fetchone() return result[0] if result else result -
\ No newline at end of file + +def get_user_answers_for_quiz(quiz_id, user_id): + sql = "SELECT a.question_id, a.answer \ + FROM questionaires quiz \ + JOIN answers a ON a.question_id = ANY(quiz.questionset) \ + WHERE a.user_id = (:user_id) AND quiz.id = (:quiz_id);" + return db.session.execute( text(sql), { + 'user_id': user_id, + 'quiz_id': quiz_id + } ).fetchall() + +def get_users_answered(quiz_id): + sql = "SELECT DISTINCT a.user_id, u.nick \ + FROM questionaires quiz \ + JOIN answers a ON a.question_id = quiz.questionset[1] \ + JOIN users u ON u.id = a.user_id \ + WHERE quiz.id = (:quiz_id);" + return db.session.execute( text(sql), { + 'quiz_id': quiz_id + } ).fetchall() + +def is_user_answered(quiz_id, user_id): + sql = "SELECT a.answer \ + FROM questionaires quiz \ + JOIN answers a ON a.question_id = quiz.questionset[1] \ + WHERE quiz.id = (:quiz_id) AND a.user_id = (:user_id);" + results = db.session.execute( text(sql), { + 'quiz_id': quiz_id, + 'user_id': user_id + } ).fetchone() + return results[0] if results else results diff --git a/routes/analyse.py b/routes/analyse.py new file mode 100644 index 0000000..b333e70 --- /dev/null +++ b/routes/analyse.py @@ -0,0 +1,50 @@ +from app import app +from flask import render_template,session,request,redirect +import db_actions as D +from routes.tools import rows2dicts, get_alert, get_nick, red + +@app.route("/pages/analyse.html") +def analyse(): + if "id" in session: + sid = session["id"] + else: + return red["nick"] + + if "answer_id" in session and D.is_user_answered(session["answer_id"],sid): + aid = session["answer_id"] + else: + return render_template("analyse.html", + alert=get_alert(), + nick=get_nick() + ) + + uid1 = session["anal_user1"] if "anal_user1" in session else sid + uid1 = sid if uid1 != sid and not D.is_user_answered(aid,uid1) else uid1 + + uid2 = session["anal_user2"] if "anal_user2" in session else sid + uid2 = sid if uid2 != sid and not D.is_user_answered(aid,uid2) else uid2 + + comparable = D.get_comparable( aid, uid1, uid2 ) + avg=0 + for i in range(len(comparable)): + avg += comparable[i][5] + avg//=len(comparable) + + + return render_template("analyse.html", + alert=get_alert(), + nick=get_nick(), + code=D.get_quiz_link(aid), + questions = rows2dicts( comparable, ['q','n','p','a1','a2','c'] ), + users = rows2dicts( D.get_users_answered(aid), ['id','nick'] ), + user1=int(uid1), + user2=int(uid2), + avg = avg + ) + +@app.route("/set/compare",methods=["POST"]) +def set_compare(): + session["anal_user1"] = request.form["user1"] + session["anal_user2"] = request.form["user2"] + return redirect("/#analyse") + diff --git a/routes/answer.py b/routes/answer.py new file mode 100644 index 0000000..fa3d138 --- /dev/null +++ b/routes/answer.py @@ -0,0 +1,100 @@ +from app import app +from flask import render_template, session, request, redirect +import db_actions as D +from routes.tools import rows2dicts, get_alert, get_nick, red + + +@app.route("/pages/new_answer.html") +def new_answer(): + if "id" not in session: + return red["nick"] + return render_template("new_answer.html", + alert=get_alert(), + nick=get_nick() + ) + +@app.route("/kys/<link>") +def kys_link(link): + if aid := D.find_quiz_by_link( link ): + session["answer_id"] = aid + return redirect("/#answer") + return redirect("/") + +@app.route("/set/answer_id",methods=["POST"]) +def answer_id(): + if "id" not in session: + session["alert"] = "Nimimerkkiä ei ole asetettu." + return redirect("/#nick") + else: + sid = session["id"] + + if "next" not in request.form: + next = "/#answer" + else: + next = "/#"+request.form["next"] + + if "link" not in request.form or request.form["link"]=="": + session["alert"] = "Kyselmän nimeä ei ole annettu." + return redirect(next) + + if aid := D.find_quiz_by_link( request.form["link"] ): + session["answer_id"] = aid + else: + session["alert"] = "Koodilla ei löytynyt kyselmää" + return redirect(next) + + if next == "/#analyse" and not D.is_user_answered( aid, sid ): + session["alert"] = "Et ole vielä vastannut tähän kyselmään. \ + Voit tutkia vastaksia vastattuasi." + return redirect("/#answer") + + return redirect( next ) + +@app.route("/pages/answer.html") +def answer(): + if "id" in session: + sid = session["id"] + else: + return red["nick"] + + if "answer_id" in session: + aid = session["answer_id"] + else: + return red["new_answer"] + + if D.is_user_answered(aid, sid): + return red["new_answer"] + + return render_template("answer.html", + alert = get_alert(), + nick = get_nick(), + questions = rows2dicts( D.get_questions(aid), ['i','q','n','p'] ), + link = D.get_quiz_link( aid ) + ) + +@app.route("/set/answers",methods=["POST"]) +def set_answers(): + if "id" not in session: + session["alert"]="Nimimerkkiä ei ole vielä valittu!" + return redirect( "/#nick" ) + if "answer_id" not in session: + session["alert"]="Kyselyä ei ole valittu vastaamista varten!" + return redirect( "/#answer" ) + + sid = session["id"] + for qid, answer in request.form.items(): + try: + if int(answer) < 0 or int(answer) > 999: + session["alert"]="Luvattoman pieniä tai suuria lukuja!" + return redirect( "/#answer" ) + elif D.get_user_answer(sid, int(qid) ): + session["alert"]="Kyselyyn olikin jo saatu vastauksia." + return redirect( "/#answer" ) + except ValueError: + session["alert"] = "Vastaukset ei ole lukuja!" + return redirect( "/#answer" ) + + for qid, answer in request.form.items(): + D.answer_new(sid, int(qid), int(answer)) + + return redirect("/#analyse") diff --git a/routes/base.py b/routes/base.py index 144eeef..695388b 100644 --- a/routes/base.py +++ b/routes/base.py @@ -1,24 +1,7 @@ from app import app -from flask import render_template,session +from flask import render_template,session,request,redirect import db_actions as D - -def get_alert(): - if "alert" in session: - alert = session["alert"] - del session["alert"] - return f"{alert}" - return "" - -def get_nick(): - while "id" in session.keys(): - nick = D.user_get_nick(session["id"]) - if not nick: - del session['id'] - if "quiz_id" in session.keys(): - del session['quiz_id'] - break - return nick - return "(ei nimimerkkiä)" +from routes.tools import rows2dicts, get_alert, get_nick @app.route("/") def index(): @@ -29,50 +12,40 @@ def info(): return render_template("info.html", alert=get_alert() ) - -@app.route("/pages/create.html") -def create(): - if "id" not in session.keys(): - return "redirect = #nick" - if "quiz_id" not in session.keys(): - return "redirect = #quiz" - return render_template("create.html", - alert=get_alert(), - nick=get_nick() - ) - -@app.route("/pages/answer.html") -def answer(): - if "id" not in session.keys(): - return "redirect = #nick" - return render_template("answer.html", - alert=get_alert(), - nick=get_nick() - ) - -@app.route("/pages/analyse.html") -def analyse(): - if "id" not in session.keys(): - return "redirect = #nick" - return render_template("analyse.html", - alert=get_alert(), - nick=get_nick() - ) - -@app.route("/pages/moderate.html") -def moderate(): - return render_template("moderate.html", - alert=get_alert() - ) - + @app.route("/pages/nick.html") def nick(): - return render_template("nick.html", alert=get_alert() ) + return render_template("nick.html", + alert=get_alert() + ) -@app.route("/pages/question.html") -def question(): - return render_template("question.html", alert=get_alert() ) +@app.route("/set/nick",methods=["POST"]) +def new_nick(): + if "id" in session.keys(): + session["alert"]="Sinulla on jo nimimerkki. Käytä sitä." + return redirect("/") + if "nick" not in request.form or request.form["nick"]=="": + session["alert"]="Nimimerkkiä ei voi asettaa ilman nimimerkkiä." + return redirect("/#nick") + else: + nick = request.form["nick"] + if len(nick) < 4: + session["alert"]="Nimimerkki on liian lyhyt" + return redirect("/#nick") + if not nick.isalnum(): + session["alert"]="Nimimerkissä saa olla vain kirjaimia ja numeroita." + return redirect("/#nick") + if D.user_exists(nick): + session["alert"]="Nimimerkki jonka olet ottamassa on jo varattu." + return redirect("/#nick") + session["id"] = D.user_new(nick) + return redirect("/") + + + +#@app.route("/pages/moderate.html") +#def moderate(): +# return render_template("moderate.html", +# alert=get_alert() +# ) -@app.route("/pages/quiz.html") -def build(): - return render_template("quiz.html", alert=get_alert() ) diff --git a/routes/create.py b/routes/create.py new file mode 100644 index 0000000..0a2a343 --- /dev/null +++ b/routes/create.py @@ -0,0 +1,55 @@ +from app import app +from flask import render_template,session,request,redirect +import db_actions as D +from routes.tools import rows2dicts, get_alert, get_nick, generate_link, red + + +@app.route("/pages/create.html") +def create(): + if "id" not in session: + return red["nick"] + if "quiz_id" not in session: + return red["quiz"] + if D.get_quiz_link(session["quiz_id"]): + return red["quiz"] + + return render_template("create.html", + alert=get_alert(), + nick=get_nick(), + questions=rows2dicts( + D.get_questions(session["quiz_id"]), + ['i','q','n','p','a'] + ) + ) + +@app.route("/pages/quiz.html") +def build(): + if "id" not in session: + return red["nick"] + return render_template("quiz.html", + alert=get_alert(), + nick=get_nick() + ) + +@app.route("/set/quiz",methods=["POST"]) +def new_quiz(): + if not "id" in session.keys(): + session["alert"]="Tarvitset nimimerkin loudaksesi" + return redirect("/#nick") + user_id = session["id"] + session["quiz_id"] = D.quiz_new( user_id ) + return redirect("/#create") + + +@app.route("/set/quiz_ready",methods=["POST"]) +def quiz_ready(): + if "quiz_id" not in session.keys(): + return "KUOLETTAVA: kyselyä ei ole" + if not D.is_user_answered(session["quiz_id"], session["id"]): + session["alert"] = "Tyhjän kyselmän luominen ei käy päinsä!" + return redirect("/#create") + quiz_id = session["quiz_id"] + session["answer_id"] = session["quiz_id"] + D.set_quiz_link(session["quiz_id"], generate_link()) + return redirect("/#analyse") + diff --git a/routes/get/quiz.py b/routes/get/quiz.py deleted file mode 100644 index 69e2613..0000000 --- a/routes/get/quiz.py +++ /dev/null @@ -1,18 +0,0 @@ -from app import app -from flask import render_template, session, request, redirect, jsonify -import db_actions as D - - -@app.route("/get/quiz_creator",methods=["GET"]) -def get_questions_by_id(): - if "quiz_id" not in session.keys(): - return "KUOLETTAVA: Sessiota / kyselmä id:tä ei ole" - - results = D.get_questions(session['quiz_id']) - r={} - names=['i','q','n','p','a'] - for i in range(len(results)): - r[i]={} - for j in range(len(results[i])): - r[i][names[j]]=results[i][j] - return (jsonify(r)) diff --git a/routes/question.py b/routes/question.py new file mode 100644 index 0000000..02261ca --- /dev/null +++ b/routes/question.py @@ -0,0 +1,49 @@ +from app import app +from flask import render_template,session,request,redirect +import db_actions as D +from routes.tools import rows2dicts, get_alert, get_nick + +@app.route("/pages/question.html") +def question(): + return render_template("question.html", + alert=get_alert(), + nick=get_nick() + ) + +@app.route("/set/question",methods=["POST"]) +def new_question(): + try: + question = request.form["question"] + neg_ans = request.form["neg_ans"] + pos_ans = request.form["pos_ans"] + answer = int(request.form["answer"]) + except (KeyError, ValueError): + session["alert"] = "Nyt kaikkea ei tullut perille tai jotain outoa." + return redirect("/#question") + + try: + sid = session["id"] + except (KeyError): + session["alert"] = "Nimimerkki puuttuukin." + return redirect("/#nick") + + try: + qid = session["quiz_id"] + except (KeyError): + session["alert"] = "Kyselmän luonti ei ollutkaan kesken." + return redirect("/#quiz") + + for entry in [question, neg_ans, pos_ans]: + if len(entry) < 2 or len(entry) > 80: + session["alert"] = "Syötteiden tulee olla 2-80 merkkiä pitkiä" + return redirect("/#question") + + if answer < 0 or answer > 999: + session["alert"] = "Vastauksessasi on nyt jotain häikkää." + return redirect("/#question") + + question_id = D.question_new( question, neg_ans, pos_ans ) + D.quiz_add(qid, question_id) + D.answer_new(sid, question_id, answer) + return redirect("/#create") + diff --git a/routes/set/answers.py b/routes/set/answers.py deleted file mode 100644 index 859d65c..0000000 --- a/routes/set/answers.py +++ /dev/null @@ -1,32 +0,0 @@ -from app import app -from flask import render_template, session, request, redirect -import db_actions as D - -def validate_answer(ans): - if len(ans)<1: - return False - try: - value=int(ans) - if value<0 or value>1000: - return False - except ValueError: - return False - return True - -@app.route("/set/answers",methods=["POST"]) -def set_answers(): - if "id" not in session.keys(): - return "KUOLETTAVA: Nimimerkkiä ei ole vielä valittu!" - if "quiz_id" not in session.keys(): - return "KUOLETTAVA: Yrität vastata kyselyyn ilman sen valintaa!" - - user_id = session["id"] - for id, answer in request.form.items(): - question_id = int(id) - if not validate_answer(answer): - return "KUOLETTAVA: Epäkelpo vastaus!" - if D.get_user_answer(user_id,question_id): - return "KUOLETTAVA: On jo vastattu!" - D.answer_new(user_id, question_id, answer) - - return redirect("/#analyse") diff --git a/routes/set/nick.py b/routes/set/nick.py deleted file mode 100644 index 67ddeea..0000000 --- a/routes/set/nick.py +++ /dev/null @@ -1,28 +0,0 @@ -from app import app -from flask import render_template, session, request, redirect -import db_actions as D - - -@app.route("/set/nick",methods=["POST"]) -def new_nick(): - nick = request.form["nick"] - if "id" in session.keys(): - msg = "You already have a nick." - elif D.user_exists(nick): - msg = "Nick is already reserved." - elif msg := invalid_nick(nick): - pass - else: - session["id"] = D.user_new(nick) - return redirect("/") - session["alert"]="Nick in not created: "+msg - return redirect("/#nick") - - -def invalid_nick(nick): - if len(nick)<4: - return "Nick is too short" - if not nick.isalnum(): - return "Only letters and numbers are allowed" - return 0 -
\ No newline at end of file diff --git a/routes/set/question.py b/routes/set/question.py deleted file mode 100644 index deaf9be..0000000 --- a/routes/set/question.py +++ /dev/null @@ -1,40 +0,0 @@ -from app import app -from flask import render_template, session, request, redirect -import db_actions as D - - -def validate_answer(ans): - if len(ans)<1: - return False - return True - -def validate_question(question): - if len(question)<2: - return False - return True - -@app.route("/set/question",methods=["POST"]) -def new_question(): - question = request.form["question"] - neg_ans = request.form["neg_ans"] - pos_ans = request.form["pos_ans"] - answer = request.form["answer"] - if not validate_question(question): - msg = "Kysymys on virheellinen" - elif not validate_answer(neg_ans): - msg = "Vasen selite on virheellinen" - elif not validate_answer(pos_ans): - msg = "Oikea selite on virheellinen" - elif "id" not in session.keys(): - msg = "Tarvitaan nimimerkki" - elif "quiz_id" not in session.keys(): - msg = "Ei voi lisätä kysymystä ilman kyselmää" - else: - quiz_id = session["quiz_id"] - user_id = session["id"] - question_id = D.question_new( question, neg_ans, pos_ans ) - D.quiz_add(quiz_id, question_id) - D.answer_new(user_id, question_id, answer) - return redirect("/#create") - session["alert"]="Kysymystä ei luotu: "+msg - return redirect("/#create") diff --git a/routes/set/quiz.py b/routes/set/quiz.py deleted file mode 100644 index 9ad13da..0000000 --- a/routes/set/quiz.py +++ /dev/null @@ -1,13 +0,0 @@ -from app import app -from flask import render_template, session, request, redirect -import db_actions as D - - -@app.route("/set/quiz",methods=["POST"]) -def new_quiz(): - if not "id" in session.keys(): - session["alert"]="Tarvitset nimimerkin loudaksesi" - return redirect("/#nick") - user_id = session["id"] - session["quiz_id"] = D.quiz_new( user_id ) - return redirect("/#create") diff --git a/routes/tools.py b/routes/tools.py new file mode 100644 index 0000000..69e6fef --- /dev/null +++ b/routes/tools.py @@ -0,0 +1,46 @@ +from random import randint +from flask import session +import db_actions as D + +red = { + "nick": "<script>window.location.hash=\"nick\"</script>", + "new_answer": "<script>window.location.hash=\"new_answer\"</script>", + "quiz": "<script>window.location.hash=\"quiz\"</script>" +} + + +def rows2dicts( rows, names ): + dlist=[] + for i in range(len(rows)): + row={} + for j in range(len(names)): + row[names[j]]=rows[i][j] + dlist.append(row) + return dlist + +def get_alert(): + if "alert" in session: + alert = session["alert"] + del session["alert"] + return f"{alert}" + return "" + +def get_nick(): + while "id" in session.keys(): + nick = D.user_get_nick(session["id"]) + if not nick: + del session['id'] + if "quiz_id" in session.keys(): + del session['quiz_id'] + break + return nick + return "(ei nimimerkkiä)" + +def generate_link(): + konso="rtpshjklvnm" + vocal="eyuioa" + str="" + for i in range(4): + str+=konso[randint(0,len(konso)-1)] + str+=vocal[randint(0,len(vocal)-1)] + return str diff --git a/static/alert-timeout.js b/static/alert-timeout.js new file mode 100644 index 0000000..01bd260 --- /dev/null +++ b/static/alert-timeout.js @@ -0,0 +1,5 @@ +Array.from(document.getElementsByClassName('kysAlert')).forEach( (a) => { + a.addEventListener('click', (event) => { + event.target.remove(); + }) + }) diff --git a/static/answer.js b/static/answer.js deleted file mode 100644 index 61882a8..0000000 --- a/static/answer.js +++ /dev/null @@ -1,68 +0,0 @@ -var questions = {} - -createQuestionDiv = ( question ) => { - const questionDiv = document.createElement('div') - questionDiv.className = 'kysQuestion' - - const qDiv = document.createElement('div') - qDiv.appendChild( document.createTextNode( question.q ) ) - qDiv.className = 'kysText' - questionDiv.appendChild( qDiv ) - - const npDiv = document.createElement('div') - npDiv.className = 'kysScale' - - const nDiv = document.createElement('div') - nDiv.appendChild( document.createTextNode( question.n ) ) - nDiv.className = 'kysNegative' - npDiv.appendChild( nDiv ) - - const sDiv = document.createElement('div') - sDiv.className = 'kysScaleSpacer' - npDiv.appendChild( sDiv ) - - const pDiv = document.createElement('div') - pDiv.appendChild( document.createTextNode( question.p ) ) - pDiv.className = 'kysPositive' - npDiv.appendChild( pDiv ) - - questionDiv.appendChild( npDiv ) - - const aInput = document.createElement('input') - aInput.className = 'kysAnswer' - aInput.type = 'range' - aInput.min = 0 - aInput.max = 999 - aInput.value = 500 - aInput.name = question.i - questionDiv.appendChild( aInput ) - - return questionDiv -} - -createQuestions = () => { - const kysForm = document.getElementById('questionForm') - const questionsDiv = document.createElement('div') - Object.keys(questions).forEach(k => { - questionsDiv.appendChild( createQuestionDiv( questions[k] ) ) - }) - kysForm.appendChild( questionsDiv ) - const submitInput = document.createElement('input') - submitInput.type='submit' - submitInput.value='Vastaa kyselyyn' - submitInput.className = 'kysSubmitAnswers' - kysForm.appendChild( submitInput ) -} - -loadQuestions = async() => { - await fetch( 'get/quiz_creator' ) - .then( response => response.json() ) - .then( json => questions = json ) - .catch( error => { - alert("dkd") - } ) - - createQuestions() -} - -loadQuestions() diff --git a/static/create.js b/static/create.js deleted file mode 100644 index d34a2da..0000000 --- a/static/create.js +++ /dev/null @@ -1,62 +0,0 @@ -var questions = {} - -createQuestionDiv = ( question ) => { - const questionDiv = document.createElement('div') - questionDiv.className = 'kysQuestion' - - const qDiv = document.createElement('div') - qDiv.appendChild( document.createTextNode( question.q ) ) - qDiv.className = 'kysText' - questionDiv.appendChild( qDiv ) - - const npDiv = document.createElement('div') - npDiv.className = 'kysScale' - - const nDiv = document.createElement('div') - nDiv.appendChild( document.createTextNode( question.n ) ) - nDiv.className = 'kysNegative' - npDiv.appendChild( nDiv ) - - const sDiv = document.createElement('div') - sDiv.className = 'kysScaleSpacer' - npDiv.appendChild( sDiv ) - - const pDiv = document.createElement('div') - pDiv.appendChild( document.createTextNode( question.p ) ) - pDiv.className = 'kysPositive' - npDiv.appendChild( pDiv ) - - questionDiv.appendChild( npDiv ) - - const aDiv = document.createElement('input') - aDiv.className = 'kysAnswer' - aDiv.type = 'range' - aDiv.min = 0 - aDiv.max = 999 - aDiv.disabled = true - aDiv.value = question.a - questionDiv.appendChild( aDiv ) - - return questionDiv -} - -createQuestions = () => { - const questionsDiv = document.getElementById('questions') - questionsDiv.className = 'kysQuestions' - Object.keys(questions).forEach(k => { - questionsDiv.appendChild( createQuestionDiv( questions[k] ) ) - }) -} - -loadQuestions = async() => { - await fetch( 'get/quiz_creator' ) - .then( response => response.json() ) - .then( json => questions = json ) - .catch( error => { - alert("dkd") - } ) - - createQuestions() -} - -loadQuestions() diff --git a/static/icons/cel-rings-love-svgrepo-com.svg b/static/icons/cel-rings-love-svgrepo-com.svg new file mode 100644 index 0000000..2e49668 --- /dev/null +++ b/static/icons/cel-rings-love-svgrepo-com.svg @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+ <title>cel-rings-love</title>
+ <desc>Created with Sketch.</desc>
+ <defs>
+
+</defs>
+ <g id="General" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="SLICES-64px" transform="translate(-630.000000, 0.000000)">
+
+</g>
+ <g id="ICONS" transform="translate(-625.000000, 5.000000)">
+ <g id="cel-rings-love" transform="translate(630.000000, 2.000000)">
+ <path d="M34.4229,9.3516 C36.5259,7.2126 36.5259,3.7446 34.4229,1.6046 C32.3199,-0.5354 28.9109,-0.5344 26.8079,1.6046 L25.9999,2.3476 L25.1929,1.6046 C23.0899,-0.5344 19.6799,-0.5344 17.5769,1.6046 C15.4739,3.7446 15.4749,7.2126 17.5769,9.3516 L25.9999,17.9996 L34.4229,9.3516 Z" id="Fill-747" fill="#F16963">
+
+</path>
+ <path d="M34.4229,9.3516 C36.5259,7.2126 36.5259,3.7446 34.4229,1.6046 C32.3199,-0.5354 28.9109,-0.5344 26.8079,1.6046 L25.9999,2.3476 L25.1929,1.6046 C23.0899,-0.5344 19.6799,-0.5344 17.5769,1.6046 C15.4739,3.7446 15.4749,7.2126 17.5769,9.3516 L25.9999,17.9996 L34.4229,9.3516 Z" id="Stroke-748" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M28.8071,26.4072 C30.8121,29.0802 32.0001,32.4012 32.0001,36.0002 C32.0001,44.8372 24.8361,52.0002 16.0001,52.0002 C7.1631,52.0002 0.0001,44.8372 0.0001,36.0002 C0.0001,27.1632 7.1631,20.0002 16.0001,20.0002 C18.2091,20.0002 20.3131,20.4472 22.2281,21.2582" id="Stroke-749" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M23.1929,45.5928 C21.1879,42.9198 19.9999,39.5988 19.9999,35.9998 C19.9999,27.1628 27.1639,19.9998 35.9999,19.9998 C44.8369,19.9998 51.9999,27.1628 51.9999,35.9998 C51.9999,44.8368 44.8369,51.9998 35.9999,51.9998 C33.5979,51.9998 31.3199,51.4708 29.2759,50.5228" id="Stroke-750" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ </g>
+ </g>
+ </g>
+</svg>
\ No newline at end of file diff --git a/static/icons/cld-server-svgrepo-com.svg b/static/icons/cld-server-svgrepo-com.svg new file mode 100644 index 0000000..b484198 --- /dev/null +++ b/static/icons/cld-server-svgrepo-com.svg @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+ <title>cld-server</title>
+ <desc>Created with Sketch.</desc>
+ <defs>
+
+</defs>
+ <g id="General" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="SLICES-64px" transform="translate(-810.000000, -200.000000)">
+
+</g>
+ <g id="ICONS" transform="translate(-805.000000, -195.000000)">
+ <g id="cld-server" transform="translate(810.000000, 204.000000)">
+ <path d="M48,12 C51.313,12 54,9.313 54,6 C54,2.687 51.313,0 48,0 L6,0 C2.687,0 0,2.687 0,6 C0,9.313 2.687,12 6,12 L48,12 Z" id="Fill-424" fill="#969CE3">
+
+</path>
+ <path d="M10,6 C10,7.104 9.104,8 8,8 C6.896,8 6,7.104 6,6 C6,4.896 6.896,4 8,4 C9.104,4 10,4.896 10,6" id="Fill-425" fill="#7BBDEC">
+
+</path>
+ <path d="M48,30 C51.313,30 54,27.313 54,24 C54,20.687 51.313,18 48,18 L6,18 C2.687,18 0,20.687 0,24 C0,27.313 2.687,30 6,30 L48,30 Z" id="Fill-426" fill="#969CE3">
+
+</path>
+ <path d="M10,24 C10,25.104 9.104,26 8,26 C6.896,26 6,25.104 6,24 C6,22.896 6.896,22 8,22 C9.104,22 10,22.896 10,24" id="Fill-427" fill="#7BBDEC">
+
+</path>
+ <path d="M48,48 C51.313,48 54,45.313 54,42 C54,38.687 51.313,36 48,36 L6,36 C2.687,36 0,38.687 0,42 C0,45.313 2.687,48 6,48 L48,48 Z" id="Fill-428" fill="#969CE3">
+
+</path>
+ <path d="M10,42 C10,43.104 9.104,44 8,44 C6.896,44 6,43.104 6,42 C6,40.896 6.896,40 8,40 C9.104,40 10,40.896 10,42" id="Fill-429" fill="#7BBDEC">
+
+</path>
+ <path d="M48,12 C51.313,12 54,9.313 54,6 C54,2.687 51.313,0 48,0 L6,0 C2.687,0 0,2.687 0,6 C0,9.313 2.687,12 6,12 L48,12 Z" id="Stroke-430" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M10,6 C10,7.104 9.104,8 8,8 C6.896,8 6,7.104 6,6 C6,4.896 6.896,4 8,4 C9.104,4 10,4.896 10,6 Z" id="Stroke-431" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M48,6 L36,6" id="Stroke-432" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M48,30 C51.313,30 54,27.313 54,24 C54,20.687 51.313,18 48,18 L6,18 C2.687,18 0,20.687 0,24 C0,27.313 2.687,30 6,30 L48,30 Z" id="Stroke-433" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M10,24 C10,25.104 9.104,26 8,26 C6.896,26 6,25.104 6,24 C6,22.896 6.896,22 8,22 C9.104,22 10,22.896 10,24 Z" id="Stroke-434" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M48,24 L36,24" id="Stroke-435" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M48,48 C51.313,48 54,45.313 54,42 C54,38.687 51.313,36 48,36 L6,36 C2.687,36 0,38.687 0,42 C0,45.313 2.687,48 6,48 L48,48 Z" id="Stroke-436" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M10,42 C10,43.104 9.104,44 8,44 C6.896,44 6,43.104 6,42 C6,40.896 6.896,40 8,40 C9.104,40 10,40.896 10,42 Z" id="Stroke-437" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M48,42 L36,42" id="Stroke-438" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ </g>
+ </g>
+ </g>
+</svg>
\ No newline at end of file diff --git a/static/icons/cle-spraycan-svgrepo-com.svg b/static/icons/cle-spraycan-svgrepo-com.svg new file mode 100644 index 0000000..86e3c64 --- /dev/null +++ b/static/icons/cle-spraycan-svgrepo-com.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+ <title>cle-spraycan</title>
+ <desc>Created with Sketch.</desc>
+ <defs>
+
+</defs>
+ <g id="General" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="SLICES-64px" transform="translate(-720.000000, -100.000000)">
+
+</g>
+ <g id="ICONS" transform="translate(-715.000000, -95.000000)">
+ <g id="cle-spraycan" transform="translate(728.000000, 100.000000)">
+ <path d="M3,54 L25,54 C26.657,54 28,52.657 28,51 L28,20 L0,20 L0,51 C0,52.657 1.343,54 3,54" id="Fill-295" fill="#F16963">
+
+</path>
+ <polygon id="Fill-296" fill="#E9EFFA" points="18 12 10 12 0 20 28 20">
+
+</polygon>
+ <polygon id="Fill-297" fill="#E9EFFA" points="10 12 18 12 18 4 10 4">
+
+</polygon>
+ <polygon id="Fill-298" fill="#F1F0E2" points="16 46 28 46 28 26 16 26">
+
+</polygon>
+ <polyline id="Stroke-299" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="0 20 10 12 18 12 28 20">
+
+</polyline>
+ <polyline id="Stroke-300" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="10 12 10 4 18 4 18 12">
+
+</polyline>
+ <polyline id="Stroke-301" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="28 46 16 46 16 26 28 26">
+
+</polyline>
+ <path d="M3,54 L25,54 C26.657,54 28,52.657 28,51 L28,20 L0,20 L0,51 C0,52.657 1.343,54 3,54 Z" id="Stroke-302" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M22,8 L24.5,8" id="Stroke-303" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M28.5527,8 L33.4737,8" id="Stroke-304" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="2.895,4.053">
+
+</path>
+ <path d="M35.5,8 L38,8" id="Stroke-305" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M22,5 L24.354,4.159" id="Stroke-306" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M27.7773,2.9365 L31.9333,1.4525" id="Stroke-307" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="2.596,3.635">
+
+</path>
+ <path d="M33.6455,0.8408 L35.9995,-0.0002" id="Stroke-308" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M22,11 L24.354,11.841" id="Stroke-309" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M27.7773,13.0635 L31.9333,14.5475" id="Stroke-310" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="2.596,3.635">
+
+</path>
+ <path d="M33.6455,15.1592 L35.9995,16.0002" id="Stroke-311" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ </g>
+ </g>
+ </g>
+</svg>
\ No newline at end of file diff --git a/static/icons/con-ruler-pencil-svgrepo-com.svg b/static/icons/con-ruler-pencil-svgrepo-com.svg new file mode 100644 index 0000000..2d3d484 --- /dev/null +++ b/static/icons/con-ruler-pencil-svgrepo-com.svg @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+ <title>con-ruler-pencil</title>
+ <desc>Created with Sketch.</desc>
+ <defs>
+
+</defs>
+ <g id="General" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="SLICES-64px" transform="translate(-540.000000, -300.000000)">
+
+</g>
+ <g id="ICONS" transform="translate(-535.000000, -295.000000)">
+ <g id="con-ruler-pencil" transform="translate(548.000000, 298.000000)">
+ <polygon id="Fill-501" fill="#EEC261" points="0 58 14 58 14 0 0 0">
+
+</polygon>
+ <path d="M33,0 L27,0 C25.344,0 24,1.344 24,3 L24,8 L36,8 L36,3 C36,1.344 34.656,0 33,0" id="Fill-502" fill="#F16963">
+
+</path>
+ <polygon id="Fill-503" fill="#99A5B7" points="32.0371 52 27.9631 52 30.0001 58">
+
+</polygon>
+ <polygon id="Fill-504" fill="#F3E777" points="24.375 41.3662 28 38.0002 32 42.0002 36 38.0002 36 8.0002 24 8.0002 24 40.3262 24.355 41.3732">
+
+</polygon>
+ <polygon id="Fill-505" fill="#F1F0E2" points="36 38 32 42 28 38 24.375 41.366 24.355 41.373 27.963 52 32.037 52 36 40.326">
+
+</polygon>
+ <path d="M27.9629,52 L24.3559,41.372" id="Stroke-506" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <polyline id="Stroke-507" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="36 37.9995 36 40.3265 32.037 52.0005">
+
+</polyline>
+ <polyline id="Stroke-508" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="24.375 41.3662 28 38.0002 32 42.0002 36 38.0002">
+
+</polyline>
+ <path d="M27.9629,52 L32.0369,52" id="Stroke-509" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M28,34 L28,12" id="Stroke-510" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <polyline id="Stroke-511" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="32.0371 52.0005 30.0001 58.0005 27.9631 52.0005">
+
+</polyline>
+ <polyline id="Stroke-512" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="24.3555 41.3721 24.0005 40.3261 24.0005 8.0001">
+
+</polyline>
+ <path d="M36,8 L36,38" id="Stroke-513" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <polygon id="Stroke-514" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="0 58 14 58 14 0 0 0">
+
+</polygon>
+ <path d="M6,32 L14,32" id="Stroke-515" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M10,26 L14,26" id="Stroke-516" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M6,20 L14,20" id="Stroke-517" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M6,8 L14,8" id="Stroke-518" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M10,14 L14,14" id="Stroke-519" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M8,50 L14,50" id="Stroke-520" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M6,44 L14,44" id="Stroke-521" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M10,38 L14,38" id="Stroke-522" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M24,8 L36,8" id="Stroke-523" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <path d="M24,8 L24,3 C24,1.344 25.344,0 27,0 L33,0 C34.656,0 36,1.344 36,3 L36,8" id="Stroke-524" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ </g>
+ </g>
+ </g>
+</svg>
\ No newline at end of file diff --git a/static/icons/gen-heart-rate-svgrepo-com.svg b/static/icons/gen-heart-rate-svgrepo-com.svg new file mode 100644 index 0000000..8880970 --- /dev/null +++ b/static/icons/gen-heart-rate-svgrepo-com.svg @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+ <title>gen-heart-rate</title>
+ <desc>Created with Sketch.</desc>
+ <defs>
+
+</defs>
+ <g id="General" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="SLICES-64px" transform="translate(-180.000000, 0.000000)">
+
+</g>
+ <g id="ICONS" transform="translate(-175.000000, 5.000000)">
+ <g id="gen-heart-rate" transform="translate(180.000000, 6.000000)">
+ <path d="M26.0001,5.9995 L28.1011,4.1005 C33.5671,-1.3665 42.4331,-1.3665 47.8991,4.1005 C53.3671,9.5685 53.3661,18.4325 47.8991,23.8985 L26.0001,45.9995 L4.1011,23.8985 C-1.3659,18.4325 -1.3669,9.5685 4.1011,4.1005 C9.5671,-1.3665 18.4331,-1.3665 23.8991,4.1005 L26.0001,5.9995 Z" id="Fill-249" fill="#F16963">
+
+</path>
+ <path d="M26.0001,5.9995 L28.1011,4.1005 C33.5671,-1.3665 42.4331,-1.3665 47.8991,4.1005 C53.3671,9.5685 53.3661,18.4325 47.8991,23.8985 L26.0001,45.9995 L4.1011,23.8985 C-1.3659,18.4325 -1.3669,9.5685 4.1011,4.1005 C9.5671,-1.3665 18.4331,-1.3665 23.8991,4.1005 L26.0001,5.9995 Z" id="Stroke-250" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+ <polyline id="Stroke-251" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="16.0001 23.9995 23.0001 23.9995 26.0001 11.9995 31.0001 33.9995 35.0001 19.9995 37.0001 23.9995 52.0001 23.9995">
+
+</polyline>
+ </g>
+ </g>
+ </g>
+</svg>
\ No newline at end of file diff --git a/static/kyselma.css b/static/kyselma.css index a7a60db..14c7653 100644 --- a/static/kyselma.css +++ b/static/kyselma.css @@ -2,13 +2,17 @@ .kysQuestion { display: flex; flex-direction: column; - max-width: 25em; + max-width: 25em; + padding: 0.5em; + border: 0.15em #fed solid; } .kysText { align-self: center; } .kysScale { display: flex; + width: 100%; + resize: horizontal; } .kysScaleSpacer { flex-grow: 1; @@ -26,3 +30,63 @@ .kysCreateText { width: 100%; } + +.kysNick::before { + content: "Olet:"; + padding-right: 0.4em; +} + +.kysNick { + border: 0.1em solid; + padding: 0.4em; + position: fixed; + top: 100vh; + left: 100vw; + transform: translate(-100%, -100%); + display: block; + background-color: #DAF; +} + +.kysAlert { + border: 0.4em solid; + padding: 0.8em; + display: block; + background-color: #F55; + border-top-color: #F97; + border-left-color: #F96; + border-right-color: #F13; + border-bottom-color: #F14; + position: fixed; + top: 50vh; + left: 50vw; + transform: translate(-50%, -50%); +} + +.kysTotal { + align-self: center; + font-size: xxx-large; +} + +.kysSelectU1 { + background: #faa; +} + +.kysSelectU2 { + background: #aaf; +} + +.kysUser1::-webkit-slider-runnable-track, .kysUser1::-moz-range-track { + background: #faa; +} + +.kysUser2::-webkit-slider-runnable-track, .kysUser2::-moz-range-track { + background: #aaf; +} + +.kysUser1::-webkit-slider-thumb, .kysUser1::-moz-range-thumb { + background: #c00; +} + +.kysUser2::-webkit-slider-thumb, .kysUser2::-moz-range-thumb { + background: #00c; +} diff --git a/static/menu.css b/static/menu.css index 04127ae..4cf7c5f 100644 --- a/static/menu.css +++ b/static/menu.css @@ -93,7 +93,7 @@ .menuHidden, .menuSpacer, .menuTitle { display: flex !important } .menuSpacer { flex-grow: 2; } .menuText { - padding-left: calc(var(--menuHeight)/2); + padding-left: calc(var(--menuHeight)/8); padding-right: calc(var(--menuHeight)/2); } } diff --git a/static/menu.js b/static/menu.js index 5256ef2..8d0baee 100644 --- a/static/menu.js +++ b/static/menu.js @@ -132,7 +132,7 @@ hashToPage = async () => { else document.getElementById(`${currentPage}_page`).className = 'page' pageElement.className = 'page pageActive' - if ( !pageElement.loaded ) await fetch( pages[p].URL ) + if ( pages[p].dynamic || !pageElement.loaded ) await fetch( pages[p].URL ) .then( response => { if (!response.ok) return `ERROR loading "${pages[p].URL}"!` return response.text() @@ -141,10 +141,10 @@ hashToPage = async () => { pageElement.innerHTML = text; pageElement.loaded = true; } ) - if ( pageElement.innerHTML.startsWith("redirect = ") ) { +/* if ( pageElement.innerHTML.startsWith("redirect = ") ) { pageElement.loaded = false; window.location.assign( pageElement.innerHTML.slice( 11 ) ); - } + }*/ // https://plnkr.co/edit/MMegiu by Allen Kim Array.from(pageElement.querySelectorAll("script")).forEach(oldScript => { diff --git a/static/pages.json b/static/pages.json index 618bc7a..37e59e4 100644 --- a/static/pages.json +++ b/static/pages.json @@ -3,7 +3,7 @@ "pages": { "info": { "URL": "pages/info.html", - "menuIcon": "kyselma.svg", + "menuIcon": "icons/gen-heart-rate-svgrepo-com.svg", "menuName": "Kyselmä" }, "spacer-1": { @@ -11,27 +11,36 @@ "create": { "pageTitle": "Luo kysely", "URL": "pages/create.html", - "menuName": "Luo" + "menuIcon": "icons/con-ruler-pencil-svgrepo-com.svg", + "menuName": "Luo", + "dynamic": "yes" }, "answer": { "pageTitle": "Vastaa kyselyyn", "URL": "pages/answer.html", - "menuName": "Vastaa" + "menuIcon": "icons/cld-server-svgrepo-com.svg", + "menuName": "Vastaa", + "dynamic": "yes" }, "analyse": { "pageTitle": "Tutki vastauksia", "URL": "pages/analyse.html", - "menuName": "Tutki" + "menuIcon": "icons/cel-rings-love-svgrepo-com.svg", + "menuName": "Tutki", + "dynamic": "yes" }, "moderate": { "pageTitle": "Moderoi sivustoa", "URL": "pages/moderate.html", + "menuIcon": "icons/cle-spraycan-svgrepo-com.svg", + "hidden": "yes", "menuName": "Moderoi" }, "nick": { "pageTitle": "Anna nimimerkki", "URL": "pages/nick.html", - "hidden": "yes" + "hidden": "yes", + "dynamic": "yes" }, "question": { "pageTitle": "Lisää kysymys", @@ -39,9 +48,14 @@ "hidden": "yes" }, "quiz": { - "pageTitle": "Rakenna kysely", + "pageTitle": "Luodaanko uusi kyselmä?", "URL": "pages/quiz.html", "hidden": "yes" + }, + "new_answer": { + "pageTitle": "Anna kyselyn koodi", + "URL": "pages/new_answer.html", + "hidden": "yes" } } } diff --git a/templates/analyse.html b/templates/analyse.html index 6970764..70fb98e 100644 --- a/templates/analyse.html +++ b/templates/analyse.html @@ -1,4 +1,73 @@ -<div id="nickbox">{{ nick }}</div> -<div id="alertbox">{{ alert }}</div> -<h1>analyse</h1> +{% include 'base.html' %} + +{% if users %} + +Tutkit kyselyä: {{ code }} + + +<div class="kysQuestion"><div class="kysScale"> +<form action="/set/compare" method="POST"> +<input type="submit" value="Vertaa" class="kysButton"> +<select class="kysSelectU1 kysSelect" name="user1"> +{% for user in users %} + {% if user1==user.id %} + <option value="{{ user.id }}" selected>{{ user.nick }}</option> + {% else %} + <option value="{{ user.id }}">{{ user.nick }}</option> + {% endif %} +{% endfor %} +</select> +<select class="kysSelectU2 kysSelect" name="user2"> +{% for user in users %} + {% if user2==user.id %} + <option value="{{ user.id }}" selected>{{ user.nick }}</option> + {% else %} + <option value="{{ user.id }}">{{ user.nick }}</option> + {% endif %} +{% endfor %} +</select> +<div class="kysScaleSpacer"></div> +</form> +</div></div> + +{% endif %} + +{% if code %} + +<div id="questions" class="kysQuestions"> + <div class="kysQuestion"> + <div class="kysTotal">{{ avg }}%</div> + </div> +{% for q in questions %} +<div class="kysQuestion"> + <div class="kysText">{{ q.q }} ({{ q.c }}%)</div> + <input class="kysAnswer kysUser1" type="range" min="0" max="999" + value="{{ q.a1 }}" disabled=""> + <input class="kysAnswer kysUser2" type="range" min="0" max="999" + value="{{ q.a2 }}" disabled=""> + <div class="kysScale"> + <div class="kysNegative">{{ q.n }}</div> + <div class="kysScaleSpacer"></div> + <div class="kysPositive">{{ q.p }}</div> + </div> +</div> +{% endfor %} + +</div> + +{% endif %} + +<form action="/set/answer_id" method="POST"> +Vaihda kyselyn koodia: +<input type="text" name="link"> +<input type="text" name="next" value="analyse" hidden="true"> +<input type="submit" value="Vaihda"> +</form> + +{% if code %} +Linkki tähän kyselyyn: +<a href="http://anal.fi:5000/kys/{{ code }}"> + http://anal.fi:5000/kys/{{ code }} +</a> +{% endif %} diff --git a/templates/answer.html b/templates/answer.html index 0ed0a05..eb49ff8 100644 --- a/templates/answer.html +++ b/templates/answer.html @@ -1,5 +1,21 @@ -<script src="answer.js"></script> -<div id="nickbox">{{ nick }}</div> -<div id="alertbox">{{ alert }}</div> -<h1>answer NOW!</h1> -<form id=questionForm action="/set/answers" method="POST"></form> +{% include 'base.html' %} + +Vastaa kyselmään "{{ link }}": + +<form class="kysQuestionaire" action="/set/answers" method="POST"> +<div id="questions" class="kysQuestions"> +{% for q in questions %} +<div class="kysQuestion"> +<div class="kysText">{{ q.q }}</div> +<div class="kysScale"> + <div class="kysNegative">{{ q.n }}</div> + <div class="kysScaleSpacer"></div> + <div class="kysPositive">{{ q.p }}</div> +</div> +<input class="kysAnswer" type="range" min="0" max="999" name="{{ q.i }}"> +</div> +{% endfor %} +<input class="kysSubmitAnswers" type="submit" value="Vastaa kyselyyn"> +</div> +</form> + diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..839cc88 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,7 @@ +{% if nick %} + <div class="kysNick">{{ nick }}</div> +{% endif %} +{% if alert %} + <div class="kysAlert">{{ alert }}</div> + <script src="alert-timeout.js"></script> +{% endif %} diff --git a/templates/create.html b/templates/create.html index fe2aa24..b369ae8 100644 --- a/templates/create.html +++ b/templates/create.html @@ -1,9 +1,29 @@ -<script src="create.js"></script> -<div id="nickbox">{{ nick }}</div> -<div id="alertbox">{{ alert }}</div> -<h1>create</h1> +{% include 'base.html' %} -<div id=questions></div> -<a href="#question">Lisää kysymys</a> +<div id="questions" class="kysQuestions"> +{% for q in questions %} +<div class="kysQuestion"> +<div class="kysText">{{ q.q }}</div> +<div class="kysScale"> + <div class="kysNegative">{{ q.n }}</div> + <div class="kysScaleSpacer"></div> + <div class="kysPositive">{{ q.p }}</div> +</div> +<input class="kysAnswer" type="range" min="0" max="999" + value="{{ q.a }}" disabled=""></div> +{% endfor %} + +<div class="kysQuestion"> +<div class="kysScale"> +<a href="#question"> + <input type="button" value="Lisää kysymys" class="kysButton"> +</a> +<div class="kysScaleSpacer"></div> +<form action="/set/quiz_ready" method="POST"> +<input type="text" name="ok" hidden=true> +<input type="submit" value="Valmis" class="kysButton"> </form> +<div class="kysScale"> +</div> +</div>
\ No newline at end of file diff --git a/templates/info.html b/templates/info.html index 3f984a6..30e84e2 100644 --- a/templates/info.html +++ b/templates/info.html @@ -1,2 +1,11 @@ -<div id="alertbox">{{ alert }}</div> -<h1>info</h1> +{% include 'base.html' %} +<h1>Kyselmä</h1> + +Tervetuloa kyselmien ihmeelliseen maailmaan. Täällä laadit ikioman kyselmän +ja vastailet kavereidesi luomiin kyselmiin. Vastattuasi pääset vertailemaan +vastauksiasi muiden vatausten kassa. Alkuun pääset painamalla ylhäätä "Luo" +ja tekemällä uuden kyselmän. Tämän jälkeen vain lisäät niin monta kysymystä +vastausvaihtoehtoineen kuin haluat ja lopuksi painat valmis, jonka jälkeen +muutkin pääsee vastaamaan kyselmään koodilla. Tarkastelussa voit valita +mitkä tahansa kaksi vastaaja ja tutkia vastausten samankaltaisuutta ja +kaiken huipuksi vastauksista lasketaan yhtäläisyys prosentti. diff --git a/templates/moderate.html b/templates/moderate.html index 116f2ff..118c8d4 100644 --- a/templates/moderate.html +++ b/templates/moderate.html @@ -1,2 +1,2 @@ -<div id="alertbox">{{ alert }}</div> +{% include 'base.html' %} <h1>moderate</h1> diff --git a/templates/new_answer.html b/templates/new_answer.html new file mode 100644 index 0000000..0d690d4 --- /dev/null +++ b/templates/new_answer.html @@ -0,0 +1,7 @@ +{% include 'base.html' %} +<form action="/set/answer_id" method="POST"> +Vastaa kyselyyn koodilla: +<input type="text" name="link"> +<input type="submit" value="Kyselmään"> +</form> +Saatoit myös päätyä tänne mikäli olet jo vastannut. diff --git a/templates/nick.html b/templates/nick.html index fe4a50a..92e166f 100644 --- a/templates/nick.html +++ b/templates/nick.html @@ -1,6 +1,6 @@ -<div id="alertbox">{{ alert }}</div> +{% include 'base.html' %} <form action="/set/nick" method="POST"> Anna itsellesi nimimerkki ensin: -<input type="text" name="nick" rows="1" cols="40"></textarea> +<input type="text" name="nick"> <input type="submit" value="Lähetä"> </form> diff --git a/templates/question.html b/templates/question.html index 016a1ac..62afaaf 100644 --- a/templates/question.html +++ b/templates/question.html @@ -1,4 +1,4 @@ -<div id="kysAlert">{{ alert }}</div> +{% include 'base.html' %} <form action="/set/question" method="POST"> <div class="kysQuestion"> <div class="kysCreateText">Kysymys:</div> diff --git a/templates/quiz.html b/templates/quiz.html index b2083ae..9e356c3 100644 --- a/templates/quiz.html +++ b/templates/quiz.html @@ -1,4 +1,4 @@ -<div id="alertbox">{{ alert }}</div> +{% include 'base.html' %} <form action="/set/quiz" method="POST"> <input type="submit" value="Aloita uusi kyselmä"> </form> |