mirror of
https://github.com/Findus23/se-simulator.git
synced 2024-09-19 15:53:45 +02:00
some improvements and basic quiz
This commit is contained in:
parent
8d89773539
commit
49f2ec65ba
8 changed files with 177 additions and 64 deletions
46
server.py
46
server.py
|
@ -1,9 +1,10 @@
|
|||
from datetime import datetime
|
||||
|
||||
import time
|
||||
import sass
|
||||
from flask import render_template, send_from_directory, abort, session, jsonify, make_response
|
||||
from flask_limiter import Limiter
|
||||
from flask_limiter.util import get_remote_address
|
||||
from flask_session import Session
|
||||
from playhouse.flask_utils import PaginatedQuery, get_object_or_404
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
from sassutils.wsgi import SassMiddleware
|
||||
|
@ -15,7 +16,13 @@ from models import *
|
|||
|
||||
app.jinja_env.globals.update(prettydate=utils.prettydate)
|
||||
|
||||
SESSION_TYPE = 'redis'
|
||||
SESSION_COOKIE_SECURE = config.production
|
||||
SESSION_USE_SIGNER = True
|
||||
SESSION_KEY_PREFIX = "StackDataSessions:"
|
||||
app.config.from_object(__name__)
|
||||
app.secret_key = config.secret_key
|
||||
Session(app)
|
||||
|
||||
limiter = Limiter(
|
||||
app,
|
||||
|
@ -46,7 +53,8 @@ def index(site=None):
|
|||
num_pages=paginated_query.get_page_count(),
|
||||
page=paginated_query.get_page(),
|
||||
questions=paginated_query.get_object_list(),
|
||||
site=site_element
|
||||
site=site_element,
|
||||
voted=session["voted"] if "voted" in session and not config.make_cacheable else None
|
||||
)
|
||||
|
||||
|
||||
|
@ -63,7 +71,23 @@ def question(slug):
|
|||
return render_template(
|
||||
"detail.html",
|
||||
question=question,
|
||||
answers=answers
|
||||
answers=answers,
|
||||
voted=session["voted"] if "voted" in session and not config.make_cacheable else None
|
||||
)
|
||||
|
||||
|
||||
@app.route('/quiz')
|
||||
def quiz():
|
||||
time1 = time.time()
|
||||
question = Question.select(Question, Title, User, Site) \
|
||||
.join(Title).switch(Question) \
|
||||
.join(User).switch(Question) \
|
||||
.join(Site).where((Question.upvotes - Question.downvotes >= 0)).order_by(SQL("RAND()")).limit(1).get()
|
||||
time2 = time.time()
|
||||
print('{} ms'.format((time2 - time1) * 1000.0))
|
||||
return render_template(
|
||||
"quiz.html",
|
||||
question=question
|
||||
)
|
||||
|
||||
|
||||
|
@ -78,11 +102,6 @@ def sites():
|
|||
|
||||
@app.route('/test')
|
||||
def sdfdsfds():
|
||||
user = User.select().get()
|
||||
for question in Question.select():
|
||||
question.upvotes = 1
|
||||
question.downvotes = 1
|
||||
question.save()
|
||||
return jsonify(
|
||||
model_to_dict(Answer.select().where((Answer.question.is_null())).get()))
|
||||
|
||||
|
@ -91,11 +110,9 @@ def sdfdsfds():
|
|||
@limiter.limit("10 per minute")
|
||||
def vote(type, id, vote):
|
||||
if "voted" not in session:
|
||||
voted = []
|
||||
else:
|
||||
voted = session["voted"]
|
||||
print(voted)
|
||||
if (type, id) in voted:
|
||||
session["voted"] = {}
|
||||
print(session["voted"])
|
||||
if (type, id) in session["voted"]:
|
||||
abort(403)
|
||||
if type == "question":
|
||||
if vote == "up":
|
||||
|
@ -113,8 +130,7 @@ def vote(type, id, vote):
|
|||
return abort(404)
|
||||
else:
|
||||
return abort(404)
|
||||
voted.append((type, id))
|
||||
session["voted"] = voted
|
||||
session["voted"][(type, id)] = vote == "up"
|
||||
query.execute()
|
||||
if type == "question":
|
||||
query = Question.select(Question.upvotes, Question.downvotes).where(Question.id == id).get()
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
{% block body %}
|
||||
{{ siteheader(question.site) }}
|
||||
<h1>{{ question.title.text }}</h1>
|
||||
|
||||
{% set vote=voted[("question", question.id)] %}
|
||||
<div class="content question">
|
||||
<div class="vote" data-id="{{ question.id }}" data-type="question">
|
||||
<a class="up"></a>
|
||||
<a class="up {{ "active" if vote == True }}"></a>
|
||||
<div>{{ question.upvotes - question.downvotes }}</div>
|
||||
<a class="down"></a>
|
||||
<a class="down {{ "active" if vote == False }}"></a>
|
||||
</div>
|
||||
<div class="contentbox">
|
||||
|
||||
|
@ -26,11 +26,12 @@
|
|||
</div>
|
||||
<h2 class="answerheader">{{ answers|length }} Answers</h2>
|
||||
{% for answer in answers %}
|
||||
{% set vote=voted[("answer", answer.id)] %}
|
||||
<div class="content answer">
|
||||
<div class="vote" data-id="{{ answer.id }}" data-type="answer" data-ranking="{{ answer.ci_lower_bound }}">
|
||||
<a class="up"></a>
|
||||
<a class="up {{ "active" if vote == True }}"></a>
|
||||
<div>{{ answer.upvotes - answer.downvotes }}</div>
|
||||
<a class="down"></a>
|
||||
<a class="down {{ "active" if vote == False }}"></a>
|
||||
</div>
|
||||
<div class="contentbox">
|
||||
{% for paragraph in answer.text.split("\n") %}
|
||||
|
|
|
@ -3,20 +3,21 @@
|
|||
{% block body %}
|
||||
{{ siteheader(site) }}
|
||||
|
||||
<label for="siteselector">Seite</label>
|
||||
<input id="siteselector" class="awesomplete" value="{{ site.url if not site.fallback }}"/>
|
||||
<label class="label-inline" for="siteselector">Seite</label>
|
||||
<input id="siteselector" class="awesomplete" value="{{ site.url if not site.fallback }}" data-mode="filter"/>
|
||||
{% if not site.fallback %}
|
||||
|
||||
<a href="{{ url_for("index") }}">Clear filter</a>
|
||||
{% endif %}
|
||||
{{ pagination(pagearray, num_pages, page, True) }}
|
||||
{% for question in questions %}
|
||||
{% set vote=voted[("question", question.id)] %}
|
||||
<div class="content question"
|
||||
style="border-right-color:{{ question.site.tag_foreground_color }};background-color:{{ question.site.tag_background_color }}">
|
||||
<div class="vote" data-id="{{ question.id }}" data-type="question">
|
||||
<a class="up"></a>
|
||||
<a class="up {{ "active" if vote == True }}"></a>
|
||||
<div>{{ question.upvotes - question.downvotes }}</div>
|
||||
<a class="down"></a>
|
||||
<a class="down {{ "active" if vote == False }}"></a>
|
||||
</div>
|
||||
<div class="contentbox">
|
||||
<a href="https://{{ question.site.url }}" class="sitename" target="_blank" rel="noopener">
|
||||
|
|
29
templates/quiz.html
Normal file
29
templates/quiz.html
Normal file
|
@ -0,0 +1,29 @@
|
|||
{% extends "base.html" %}
|
||||
{% block body %}
|
||||
|
||||
<input id="siteselector" class="awesomplete" data-mode="quiz"/>
|
||||
<button id="check">Check</button>
|
||||
|
||||
<h1>{{ question.title.text }}</h1>
|
||||
<div class="content question">
|
||||
<div class="vote">
|
||||
<a class="up"></a>
|
||||
<div>{{ question.upvotes - question.downvotes }}</div>
|
||||
<a class="down"></a>
|
||||
</div>
|
||||
<div class="contentbox">
|
||||
|
||||
{% for paragraph in question.text.split("\n") %}
|
||||
<p>{{ paragraph }}</p>
|
||||
{% endfor %}
|
||||
<div class="contentfooter">
|
||||
<div class="authorbox">
|
||||
asked {{ prettydate(question.datetime) }}
|
||||
<br>
|
||||
{{ question.user.username }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -1,21 +1,17 @@
|
|||
document.addEventListener("DOMContentLoaded", function (event) {
|
||||
var vote = document.getElementsByClassName("vote");
|
||||
console.warn(vote);
|
||||
Array.prototype.forEach.call(vote, function (elvote) {
|
||||
var id = elvote.dataset.id;
|
||||
var type = elvote.dataset.type;
|
||||
Array.prototype.forEach.call(elvote.querySelectorAll("a"), function (el) {
|
||||
el.addEventListener("click", function (event) {
|
||||
console.info(elvote);
|
||||
var vote = el.classList[0];
|
||||
console.info(type, id, vote);
|
||||
var request = new XMLHttpRequest();
|
||||
request.open("POST", "/api/vote/" + type + "/" + id + "/" + vote, true);
|
||||
|
||||
request.onload = function () {
|
||||
if (this.status >= 200 && this.status < 400) {
|
||||
var resp = JSON.parse(this.response);
|
||||
console.info(resp);
|
||||
el.classList.add("active");
|
||||
elvote.querySelector("div").textContent = resp.upvotes - resp.downvotes
|
||||
} else {
|
||||
|
@ -31,6 +27,8 @@ document.addEventListener("DOMContentLoaded", function (event) {
|
|||
});
|
||||
});
|
||||
var input = document.getElementById("siteselector");
|
||||
if (input) {
|
||||
var mode = input.dataset.mode;
|
||||
var request = new XMLHttpRequest();
|
||||
request.open("GET", "/api/sites", true);
|
||||
|
||||
|
@ -50,14 +48,21 @@ document.addEventListener("DOMContentLoaded", function (event) {
|
|||
}
|
||||
}
|
||||
new Awesomplete(input, {
|
||||
list: list
|
||||
list: list,
|
||||
minChars: 0,
|
||||
autoFirst: true
|
||||
});
|
||||
input.addEventListener("awesomplete-select", function (event) {
|
||||
if (!(event.text.value in resp)) { // shouldn't happen
|
||||
return false
|
||||
}
|
||||
var selectedSite = resp[event.text.value];
|
||||
|
||||
if (mode === "filter") {
|
||||
window.location.href = "/s/" + selectedSite.url
|
||||
} else if (mode === "quiz") {
|
||||
console.log(selectedSite);
|
||||
}
|
||||
|
||||
});
|
||||
} else {
|
||||
|
@ -70,4 +75,6 @@ document.addEventListener("DOMContentLoaded", function (event) {
|
|||
};
|
||||
request.send();
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
// Based on https://github.com/LeaVerou/awesomplete/blob/gh-pages/awesomplete.base.css
|
||||
// Copyright (c) 2015 Lea Verou
|
||||
// MIT License
|
||||
|
||||
|
||||
.awesomplete [hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
|
55
web/static/sass/_awesomplete.custom.scss
Normal file
55
web/static/sass/_awesomplete.custom.scss
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Based on https://github.com/LeaVerou/awesomplete/blob/gh-pages/awesomplete.theme.css
|
||||
// Copyright (c) 2015 Lea Verou
|
||||
// MIT License
|
||||
|
||||
@import "awesomplete.base";
|
||||
|
||||
.awesomplete {
|
||||
> ul {
|
||||
padding: 1rem 1rem 0;
|
||||
margin: .2em 0 0;
|
||||
|
||||
border: 1px solid rgba(0, 0, 0, .3);
|
||||
box-shadow: .05em .2em .6em rgba(0, 0, 0, .2);
|
||||
text-shadow: none;
|
||||
> li {
|
||||
position: relative;
|
||||
padding: .2em .5em;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background: hsl(200, 40%, 80%);
|
||||
color: black;
|
||||
mark {
|
||||
background: hsl(68, 100%, 41%);
|
||||
}
|
||||
}
|
||||
&[aria-selected="true"] {
|
||||
background: hsl(205, 40%, 40%);
|
||||
color: white;
|
||||
mark {
|
||||
background: hsl(86, 100%, 21%);
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:before { // pointer
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -.43em;
|
||||
left: 1em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
padding: .4em;
|
||||
background: white;
|
||||
border: inherit;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
mark {
|
||||
background: hsl(65, 100%, 50%);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,11 +2,10 @@ $link-color: #07C;
|
|||
$link-hover-color: #3af;
|
||||
|
||||
@import "../../milligram/src/milligram";
|
||||
@import "awesomplete.base";
|
||||
@import "awesomplete.custom";
|
||||
@import "pagination";
|
||||
|
||||
body {
|
||||
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
|
||||
font-size: 15px;
|
||||
color: #111;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue