media
search_index
.sass-cache
+*.css.map
exercises.json
\ No newline at end of file
+++ /dev/null
-@charset "UTF-8";
-.box-button {
- background-color: #ed7831;
- border-radius: 0.9375em; }
- .box-button .dl-button {
- color: white;
- padding: 1.0625em 0.75em 1.0625em 0.75em; }
-
-.dl-button {
- color: #363a3e;
- display: block;
- font-weight: bold;
- text-align: center;
- text-transform: uppercase;
- font-size: .9em; }
-
-.dl-button:after {
- content: " ↓"; }
-
-#main-bar section.button {
- margin-bottom: 1.0625em; }
-
-#sidebar {
- position: absolute;
- right: 0;
- top: 0;
- width: 13.75em;
- color: #363a3e; }
- #sidebar section {
- margin-bottom: 1.0625em; }
- #sidebar section h1 {
- margin: 0; }
- #sidebar section h1.realisation {
- font-weight: normal; }
- #sidebar .section {
- border-top: 1px solid #c9ccce;
- padding-top: 1.0625em; }
- #sidebar .section-minor {
- border-top: 1px solid #c9ccce;
- padding-top: 1.0625em; }
- #sidebar .section-minor h1 {
- font-weight: normal;
- font-size: 1em; }
- #sidebar .section-micro {
- font-size: .8em;
- color: #888;
- border-top: 1px solid #c9ccce;
- padding-top: 1.0625em; }
- #sidebar .section-micro h1 {
- font-weight: normal;
- font-size: 1em; }
- #sidebar .section-micro .link-list a {
- color: #888; }
- #sidebar section:first-child {
- border-top: 0;
- padding-top: 0; }
-
-#main-bar {
- width: 40em; }
- #main-bar .top-link {
- float: right; }
- #main-bar .box {
- background-color: #d4d6d8;
- border-radius: 0.9375em;
- padding: 1.0625em; }
- #main-bar .box h1 {
- font-size: 1em;
- text-transform: uppercase; }
- #main-bar .box p {
- margin: 0; }
- #main-bar .box .box-icon {
- margin: -.2em 0 -.2em 1em;
- float: right;
- text-align: center; }
-
-.lesson-footer {
- clear: both;
- border-top: 1px solid #777;
- margin-top: 2em;
- padding-top: 1em; }
- .lesson-footer .section-info {
- text-align: center; }
- .lesson-footer .previous-lesson {
- float: left; }
- .lesson-footer .next-lesson {
- float: right; }
+++ /dev/null
-$px: .0625em;
-$new_black: #363a3e;
-
-.box-button {
- background-color: #ed7831;
- border-radius: 15*$px;
- .dl-button {
- color: white;
- padding: 17*$px 12*$px 17*$px 12*$px;
- }
-}
-.dl-button {
- color: $new_black;
- display: block;
- font-weight: bold;
- text-align: center;
- text-transform: uppercase;
- font-size: .9em;
-}
-.dl-button:after {
- content: " ↓";
-}
-
-#main-bar section.button {
- margin-bottom: 17*$px;
-}
-
-#sidebar {
- position: absolute;
- right: 0;
- top: 0;
- width: 220*$px;
- color: $new_black;
-
- section {
- margin-bottom: 17*$px;
- h1 {
- margin: 0;
- }
- h1.realisation {
- font-weight: normal;
- }
- }
-
- .section {
- border-top: 1px solid #c9ccce;
- padding-top: 17*$px;
- }
- .section-minor {
- border-top: 1px solid #c9ccce;
- padding-top: 17*$px;
- h1 {
- font-weight: normal;
- font-size: 1em;
- }
- }
- .section-micro {
- font-size: .8em;
- color: #888;
- border-top: 1px solid #c9ccce;
- padding-top: 17*$px;
- h1 {
- font-weight: normal;
- font-size: 1em;
- }
- .link-list a {
- color: #888;
- }
- }
- section:first-child {
- border-top: 0;
- padding-top: 0;
- }
-}
-#main-bar {
- width: 640*$px;
-
- .top-link {
- float:right;
- }
-
- .box {
- background-color: #d4d6d8;
- border-radius: 15*$px;
- padding: 17*$px;
- h1 {
- font-size: 1em;
- text-transform: uppercase;
- }
- p {
- margin: 0;
- }
- .box-icon {
- margin: -.2em 0 -.2em 1em;
- float: right;
- text-align: center;
- }
- }
-}
-
-.lesson-footer {
- clear: both;
- border-top: 1px solid #777;
- margin-top: 2em;
- padding-top: 1em;
-
- .section-info {
- text-align: center;
- }
- .previous-lesson {float: left;}
- .next-lesson {float: right;}
-}
.box-button {
background-color: #ed7831;
border-radius: 0.9375em; }
- .box-button .dl-button {
+ .box-button .dl-button, .box-button .nice-button {
color: white;
padding: 1.0625em 0.75em 1.0625em 0.75em; }
-.dl-button {
+.dl-button, .nice-button {
color: #363a3e;
display: block;
font-weight: bold;
float: left; }
.lesson-footer .next-lesson {
float: right; }
+
+/*# sourceMappingURL=layout.css.map */
$px: .0625em;
$new_black: #363a3e;
-
.box-button {
background-color: #ed7831;
border-radius: 15*$px;
- .dl-button {
+ .dl-button, .nice-button {
color: white;
padding: 17*$px 12*$px 17*$px 12*$px;
}
}
-.dl-button {
+.dl-button, .nice-button {
color: $new_black;
display: block;
font-weight: bold;
margin: 1em 0; }
.flatpage img {
- border: 0.3125em solid #eeeeee;
+ border: 0.3125em solid #eee;
margin: 1.3em; }
+
+ul.messages {
+ list-style: none; }
+
+.messages .error {
+ top: 20px;
+ left: 20px;
+ border: 1px solid black;
+ background: red;
+ border-radius: 0.938em;
+ padding: 5px 2px;
+ color: white;
+ text-align: center;
+ font-weight: bold; }
+
+/*# sourceMappingURL=base.css.map */
margin: 1.3em;
}
}
+
+ul.messages {
+ list-style: none;
+}
+
+.messages .error {
+ top: 20px;
+ left: 20px;
+ border: 1px solid black;
+ background: red;
+ border-radius: 0.938em;
+ padding: 5px 2px;
+ color: white;
+ text-align: center;
+ font-weight: bold;
+}
submission = self.instance
answers = submission.get_answers()
posted_answers = json.loads(self.cleaned_data['answers'])
- assert type(posted_answers) == dict, 'answers not dict'
- assert len(posted_answers) == 1, 'answers not single'
- exercise_id = posted_answers.keys()[0]
+ if type(posted_answers) != dict:
+ raise ValueError('answers not dict')
+ if len(posted_answers) != 1:
+ raise ValueError('answers not single')
+ exercise_id, answer = posted_answers.items()[0]
+ # multipost
+ if answers.get(exercise_id) == answer:
+ return
i, exercise = submission.current_exercise()
- assert exercise_id == str(exercise['id']), 'wrong exercise id'
+ if exercise_id != str(exercise['id']):
+ raise ValueError('wrong exercise id')
for answer in posted_answers.values():
answers[exercise_id] = answer
submission.answers = json.dumps(answers)
-Poniżej znajduje się wygenerowany specjalnie dla Ciebie link, pod którym będziesz mógł/mogła rozwiązać zadania I etapu Olimpiady Cyfrowej:
+Dzień dobry,
+Poniżej znajduje się wygenerowany specjalnie dla Ciebie link, pod którym znajdziesz zadania I etapu Olimpiady Cyfrowej:
-https://olimpiadacyfrowa.pl{% url 'form_single' submission_id=submission.id key=submission.key %}
+https://olimpiadacyfrowa.pl{% url 'wtem_start' submission_id=submission.id key=submission.key %}
-I etap Olimpiady odbędzie się we wtorek 15 listopada o godz. 10:00 w sali wyznaczonej przez Komisję Szkolną. Na rozwiązanie testu będziesz mieć ok. 90 min. Aby rozwiązać test, potrzebny Ci będzie komputer ze stabilnym łączem internetowym oraz zainstalowaną i zaktualizowaną przeglądarką.
+I etap Olimpiady odbędzie się w czwartek 23 listopada o godz. 10:00 w sali wyznaczonej przez Twoją Komisję Szkolną. Test będzie się składał z 50 pytań, które otrzymasz w losowej kolejności. Po udzieleniu odpowiedzi na dane pytanie nie ma możliwości powrotu do niego i zmiany odpowiedzi. Na rozwiązanie całego testu będziesz mieć 60 minut.
-Każdy uczestnik otrzymał indywidualny link, pod którym może rozwiązywać zadania samodzielnie. Wszelkie działania mogące świadczyć o tym, że uczestnik nie rozwiązuje testu samodzielnie, np. wchodzenie na stronę z zadaniami przez więcej niż jedną osobę, będą przez nas śledzone i poskutkują dyskwalifikacją.
+Aby rozwiązać test, potrzebny Ci będzie komputer ze stabilnym łączem internetowym oraz zainstalowaną i zaktualizowaną przeglądarką.
-W razie dodatkowych pytań możesz kontaktować się z nami pod adresem olimpiada@nowoczesnapolska.org.pl lub numerem telefonu +48 515-502-666.
+Każdy uczestnik i uczestniczka otrzymuje indywidualny link, pod którym znajdzie zadania I etapu Olimpiady Cyfrowej. Przypominamy, że zgodnie z Regulaminem, każdy zobowiązany jest do samodzielnego rozwiązania testu. Wszelkie działania świadczące o niesamodzielnej pracy poskutkują dyskwalifikacją.
-Przypominamy, że główną nagrodą w Olimpiadzie Cyfrowej jest indeks Collegium Civitas na dowolny kierunek studiów licencjackich oraz zwolnienie z opłat czesnego przez rok.
+W razie dodatkowych pytań możesz kontaktować się z nami pod adresem olimpiada@nowoczesnapolska.org.pl lub numerem telefonu +48 22 465 15 35.
Powodzenia!
-
Zespół Olimpiady Cyfrowej
-fundacja Nowoczesna Polska
\ No newline at end of file
+Fundacja Nowoczesna Polska
\ No newline at end of file
{{para}}
</p>
{% endfor %}
- {% if exercise.points %}
- <span class="instruction">
- {% if exercise.answer|length == 1 %}
- Tylko jedna odpowiedź jest prawidłowa.
- {% else %}
- Zaznacz wszystkie prawidłowe odpowiedzi.
- {% endif %}
- </span>
- {% endif %}
+ <span class="instruction">
+ Zaznacz każdą prawidłową odpowiedź (jedną lub więcej).
+ </span>
</div>
{% endautoescape %}
<div class="question" data-no="1">
<ol class="lista num">
{% for option in exercise.options %}
<li class="question-piece" data-name="{{option.id}}">
- <input type="{% if exercise.answer|length == 1 %}radio{% else %}checkbox{% endif %}" name="{% if exercise.answer|length == 1 %}e{{no}}{% else %}e{{no}}_{{option.id}}{% endif %}" id="e{{no}}_{{option.id}}"{% if option.id|stringformat:"s" in exercise.saved_answer.closed_part %} checked="checked"{% endif %}>
+ <input type="checkbox" name="e{{no}}_{{option.id}}" id="e{{no}}_{{option.id}}"{% if option.id|stringformat:"s" in exercise.saved_answer.closed_part %} checked="checked"{% endif %}>
<label for="e{{no}}_{{option.id}}">{{option.text}}</label>
</li>
{% endfor %}
--- /dev/null
+<div class="exercise exercise-wtem wybor" data-type="wybor" data-id="{{exercise.id}}">
+
+ {% include "wtem/exercises/exercise_no.html" %}
+ {% autoescape off %}
+ <div class="description">
+ {% for para in exercise.description %}
+ <p class="paragraph">
+ {{para}}
+ </p>
+ {% endfor %}
+ {% if exercise.points %}
+ <span class="instruction">
+ {% if exercise.answer|length == 1 %}
+ Tylko jedna odpowiedź jest prawidłowa.
+ {% else %}
+ Zaznacz wszystkie prawidłowe odpowiedzi.
+ {% endif %}
+ </span>
+ {% endif %}
+ </div>
+ {% endautoescape %}
+ <div class="question" data-no="1">
+ <ol class="lista num">
+ {% for option in exercise.options %}
+ <li class="question-piece" data-name="{{option.id}}">
+ <input type="{% if exercise.answer|length == 1 %}radio{% else %}checkbox{% endif %}" name="{% if exercise.answer|length == 1 %}e{{no}}{% else %}e{{no}}_{{option.id}}{% endif %}" id="e{{no}}_{{option.id}}"{% if option.id|stringformat:"s" in exercise.saved_answer.closed_part %} checked="checked"{% endif %}>
+ <label for="e{{no}}_{{option.id}}">{{option.text}}</label>
+ </li>
+ {% endfor %}
+ </ol>
+ </div>
+
+ {% if exercise.open_part %}
+ <div class="open_part">
+ <div class="description">
+ {% for para in exercise.open_part %}
+ <p class="paragraph">
+ {{para}}
+ </p>
+ {% endfor %}
+ </div>
+ <textarea style="width: 100%; margin-top:10px;" rows="{{exercise.open_part_rows|default:10}}">{{ exercise.saved_answer.open_part }}</textarea>
+ </div>
+ {% endif %}
+
+</div>
{% if not exercise.continuation %}
- <h3>Zadanie {{ no }}{# {{exercise.id_show|default:exercise.id}} #}{# ({{ exercise.max_points }} pkt)#}</h3>
+ <h3>Zadanie {{ no }}/{{ exercise_count }}{# {{exercise.id_show|default:exercise.id}} #}{# ({{ exercise.max_points }} pkt)#}</h3>
{% endif %}
\ No newline at end of file
<h1>{% include "wtem/title.html" %}</h1>
-<p>I etap: 15 listopada, 10:00. Czas trwania: ok. 90 minut.</p>
+<p>Witamy w I etapie Olimpiady Cyfrowej.</p>
+<p>Test składa z 50 pytań, które otrzymasz w losowej kolejności. Po udzieleniu odpowiedzi na dane pytanie nie ma możliwości powrotu do niego i zmiany odpowiedzi. Uwaga: część pytań ma jedną, a część kilka poprawnych odpowiedzi.</p>
+<p>Test rozpocznie się 23 listopada o godzinie 10:00 i potrwa do 11:00.</p>
+
+<p>Powodzenia!</p>
+<p>Zespół Olimpiady Cyfrowej<br>
+Fundacja Nowoczesna Polska</p>
{% endblock %}
\ No newline at end of file
{% endblock %}
-
{% block body %}
<style>
.wtem-open-field {
.wtem-open-field textarea {
margin-top:0;
}
- .wtem-fixed-info {
- top: 20px;
- left: 20px;
- border: 1px solid black;
- background: #16a487;
- border-radius: 0.938em;
- padding: 5px 2px;
- color: white;
- text-align: center;
- font-weight: bold;
- }
.wtem-items-inline li {
display: inline-block;
}
font-style: italic;
font-size: .9em;
}
-
</style>
-<h1>{% include "wtem/title.html" %}</h1>
-<div class="wtem-fixed-info">Rozwiązania można wysyłać do godziny {{end_time|default:"11:30"}}. <strong>Nie czekaj na ostatnią chwilę!</strong></div>
+{% if messages %}
+ <ul class="messages">
+ {% for message in messages %}
+ <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
+ {% endfor %}
+ </ul>
+{% endif %}
-<p>Witamy w I etapie Olimpiady Cyfrowej. Na rozwiązanie zadań masz czas do godz. {{end_time|default:"11:30"}}. Test składa się z 30 pytań.</p>
-
-<p>Wszelkie aktualności dotyczące Olimpiady możesz znaleźć <a href="/" target="_info">tutaj</a>.</p>
-
-<p>Powodzenia!<br/>
-Zespół Olimpiady Cyfrowej, fundacja Nowoczesna Polska</p>
+<h1>{% include "wtem/title.html" %}</h1>
-<form method="post" enctype="multipart/form-data">
+<form method="post">
{% cache 300 wtem exercise.id %}
{% with 'wtem/exercises/'|add:exercise.type|add:'.html' as template_name %}
<hr/>
<input type="hidden" name="answers" value=""/>
-<p style="text-align:center; margin-top:20px;">Sprawdź jeszcze raz wszystkie swoje odpowiedzi, a następnie wyślij je do nas, klikając w poniższy przycisk:<br/><br/>
-<input type="submit" value="Wyślij moje odpowiedzi" style="display: block; margin: auto;"/>
+<p style="text-align:center; margin-top:20px;">
+<input type="submit" value="{% if no < exercise_count %}Kolejne pytanie{% else %}Zakończ test{% endif %}" style="display: block; margin: auto;"/>
<br/>
<span class="wtem_spinner">
- <span>Wysyłanie rozwiązań w toku...</span>
+ <span>Wysyłanie rozwiązania w toku...</span>
<img src="{% static 'wtem/spinner.gif' %}"/>
- <span>Spróbuj jeszcze raz, jeśli wysyłanie trwa dłużej niż kilka minut.</span>
+ <span>Spróbuj jeszcze raz, jeśli wysyłanie trwa dłużej niż kilka chwil.</span>
</span>
</p>
-<div class="wtem-fixed-info" style="margin-top:15px;">Rozwiązania można wysyłać do godziny {{end_time|default:"11:30"}}. <strong>Nie czekaj na ostatnią chwilę!</strong></div>
-
</form>
{% endblock %}
--- /dev/null
+{% extends 'base_super.html' %}
+
+{% block body %}
+
+ <h1>{% include "wtem/title.html" %}</h1>
+
+ <p>Witamy w I etapie Olimpiady Cyfrowej.</p>
+
+ <p>Test składa z {{ exercise_count }} pytań, które otrzymasz w losowej kolejności.
+ Po udzieleniu odpowiedzi na dane pytanie nie ma możliwości powrotu do niego i zmiany odpowiedzi.
+ Uwaga: część pytań ma jedną, a część kilka poprawnych odpowiedzi.</p>
+ <p>Test rozpoczyna się o godzinie 10:00 i trwa do 11:00.</p>
+
+ <p>Powodzenia!</p>
+ <p>Zespół Olimpiady Cyfrowej<br>
+ Fundacja Nowoczesna Polska</p>
+
+ <p class="box-button" style="max-width: 10em;"><a href="{% url 'wtem_form' submission_id=submission.id key=submission.key %}" class="nice-button">Start</a></p>
+
+{% endblock %}
<p>Dziękujemy za udział w I etapie Olimpiady Cyfrowej.
Twoja praca została wysłana i poprawnie przyjęta przez system.</p>
-<p>Do końca listopada otrzymasz e-mail z wynikami I etapu. Informacja o uzyskanych przez Ciebie punktach zostanie również przesłana do osoby, która zgłosiła Twój udział w Olimpiadzie.</p>
+<p>Do końca listopada otrzymasz e-mail z wynikami I etapu. Informacja o uzyskanych przez Ciebie punktach zostanie również przesłana do Przewodniczącego Komisji Szkolnej, który zgłosił Twój udział w Olimpiadzie.</p>
-<p>Aktualności związane z Olimpiadą możesz sprawdzać <a href="/">tutaj</a>. W razie dodatkowych pytań możesz kontaktować się z nami pod adresem olimpiada@nowoczesnapolska.org.pl lub numerem telefonu +48 515-502-666.</p>
+<p>Aktualności związane z Olimpiadą możesz sprawdzać <a href="/">tutaj</a>. W razie dodatkowych pytań możesz kontaktować się z nami pod adresem olimpiada@nowoczesnapolska.org.pl lub numerem telefonu <a href="tel:+48224651535">+48 22 465 15 35</a>.</p>
<p>Zespół Olimpiady Cyfrowej<br>
fundacja Nowoczesna Polska</p>
'',
url(r'^potwierdzenie/(?P<id>.*)/(?P<key>.*)/$', views.confirmation, name='student_confirmation'),
url(r'^_test/(?P<key>.*)/$', views.form_during),
- # url(r'^(?P<key>.*)/$', views.form, name='wtem_form'),
- url(r'^(?P<submission_id>.*)/(?P<key>.*)/$', views.form_single, name='form_single'),
+ url(r'^(?P<submission_id>[^/]*)/(?P<key>[^/]*)/$', views.form, name='wtem_form'),
+ url(r'^(?P<submission_id>[^/]*)/(?P<key>[^/]*)/start/$', views.start, name='wtem_start'),
)
from copy import deepcopy
from django.conf import settings
+from django.contrib import messages
from django.core.urlresolvers import reverse
from django.http import HttpResponseForbidden
from django.http.response import HttpResponseRedirect
from .forms import WTEMForm, WTEMSingleForm
from .models import Submission, DEBUG_KEY, exercises, CompetitionState
-WTEM_CONTEST_STAGE = getattr(settings, 'WTEM_CONTEST_STAGE', 'before')
-
@csrf_exempt
-def form(request, key):
- return globals()['form_' + WTEM_CONTEST_STAGE](request, key)
+def form(request, submission_id, key):
+ state = CompetitionState.get_state()
+ if state == CompetitionState.DURING:
+ state = 'single'
+ return globals()['form_' + state](request, submission_id, key)
-def form_before(request, key):
- try:
- Submission.objects.get(key=key)
- except Submission.DoesNotExist:
+def form_before(request, submission_id, key):
+ submission = Submission.objects.get(id=submission_id)
+ if submission.key != key:
return render(request, 'wtem/key_not_found_before.html')
else:
return render(request, 'wtem/main_before.html')
-def form_after(request, key):
+def form_after(request, submission_id, key):
return render(request, 'wtem/main_after.html')
@csrf_exempt
def form_during(request, key):
- if WTEM_CONTEST_STAGE != 'during':
+ if CompetitionState.get_state() != CompetitionState.DURING:
if request.META['REMOTE_ADDR'] not in getattr(settings, 'WTEM_CONTEST_IP_ALLOW', []):
return HttpResponseForbidden('Not allowed')
i, exercise = submission.current_exercise()
+ exercise_count = len(exercises)
+
if not exercise:
return render(request, 'wtem/thanks_single.html')
if request.method == 'GET':
- return render(request, 'wtem/single.html', {'exercise': exercise, 'no': i})
+ return render(request, 'wtem/single.html', {'exercise': exercise, 'no': i, 'exercise_count': exercise_count})
elif request.method == 'POST':
form = WTEMSingleForm(request.POST, request.FILES, instance=submission)
if form.is_valid():
- form.save()
- return HttpResponseRedirect(reverse('form_single', kwargs={'submission_id': submission_id, 'key': key}))
+ try:
+ form.save()
+ except ValueError as e:
+ if e.message == 'wrong exercise id':
+ messages.error(request, u'Próba wysłania odpowiedzi ponownie lub poza kolejnością')
+ print 'wysyłam redirect', i
+ return HttpResponseRedirect(reverse('wtem_form', kwargs={'submission_id': submission_id, 'key': key}))
else:
raise Exception
+@never_cache
+@csrf_exempt
+def start(request, submission_id, key):
+ state = CompetitionState.get_state()
+ if state in (CompetitionState.BEFORE, CompetitionState.AFTER):
+ return globals()['form_' + state](request, submission_id, key)
+
+ submission = Submission.objects.get(id=submission_id)
+ if submission.key != key:
+ return render(request, 'wtem/key_not_found.html')
+
+ i, exercise = submission.current_exercise()
+ if not exercise:
+ return render(request, 'wtem/thanks_single.html')
+
+ return render(request, 'wtem/start.html', {'exercise_count': len(exercises), 'submission': submission})
+
+
def confirmation(request, id, key):
conf = get_object_or_404(Confirmation, id=id, key=key)
was_confirmed = conf.confirmed