1
0
Fork 0
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:
Lukas Winkler 2018-03-27 20:41:57 +02:00
parent 8d89773539
commit 49f2ec65ba
8 changed files with 177 additions and 64 deletions

View file

@ -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()

View file

@ -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") %}

View file

@ -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
View 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 %}

View file

@ -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,43 +27,54 @@ document.addEventListener("DOMContentLoaded", function (event) {
});
});
var input = document.getElementById("siteselector");
var request = new XMLHttpRequest();
request.open("GET", "/api/sites", true);
if (input) {
var mode = input.dataset.mode;
var request = new XMLHttpRequest();
request.open("GET", "/api/sites", true);
request.onload = function () {
if (this.status >= 200 && this.status < 400) {
var resp = JSON.parse(this.response);
var list = [];
for (var key in resp) {
if (resp.hasOwnProperty(key)) {
var site, shortname;
site = resp[key];
shortname = site.url.replace(".stackexchange.com", ".SE");
list.push({
label: site.name + " (" + shortname + ")",
value: site.url
});
request.onload = function () {
if (this.status >= 200 && this.status < 400) {
var resp = JSON.parse(this.response);
var list = [];
for (var key in resp) {
if (resp.hasOwnProperty(key)) {
var site, shortname;
site = resp[key];
shortname = site.url.replace(".stackexchange.com", ".SE");
list.push({
label: site.name + " (" + shortname + ")",
value: site.url
});
}
}
new Awesomplete(input, {
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 {
// We reached our target server, but it returned an error
}
new Awesomplete(input, {
list: list
});
input.addEventListener("awesomplete-select", function (event) {
if (!(event.text.value in resp)) { // shouldn't happen
return false
}
var selectedSite=resp[event.text.value];
window.location.href="/s/"+selectedSite.url
});
} else {
// We reached our target server, but it returned an error
};
request.onerror = function () {
// There was a connection error of some sort
};
request.send();
}
};
request.onerror = function () {
// There was a connection error of some sort
};
request.send();
}
});

View file

@ -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;
}

View 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%);
}
}

View file

@ -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;
}