diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..48f823a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +end_of_file = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/ennead/app.py b/ennead/app.py index 2c17a27..6b73f3a 100644 --- a/ennead/app.py +++ b/ennead/app.py @@ -6,11 +6,12 @@ from ennead.config import Config +from ennead.views.file import upload_file, uploaded_file, files_page from ennead.views.auth import register, register_page, login, login_page, logout from ennead.views.tasks import index -from ennead.views.admin import adm_task_list_page, task_edit_page, task_edit, task_delete from ennead.views.system import render_markdown_endpoint -from ennead.views.file import upload_file, uploaded_file, files_page +from ennead.views.admin import (adm_task_list_page, add_task_set, choose_task_set, + task_edit_page, task_edit, task_delete) from ennead.models.base import database from ennead.models.file import File @@ -63,6 +64,9 @@ def create_app(config_path: Optional[str] = None) -> Flask: app.add_url_rule('/login', 'login', login, methods=['POST']) app.add_url_rule('/logout', 'logout', logout) + app.add_url_rule('/adm/task_set', 'add_task_set', add_task_set, methods=['POST']) + app.add_url_rule('/adm/task_set/choose', 'choose_task_set', choose_task_set, methods=['POST']) + app.add_url_rule('/adm/tasks', 'adm_task_list_page', adm_task_list_page) app.add_url_rule('/adm/tasks/', 'task_edit_page', task_edit_page) app.add_url_rule('/adm/tasks', 'task_edit', task_edit, methods=['POST']) diff --git a/ennead/templates/adm_task_list.html b/ennead/templates/adm_task_list.html index e188ef9..c95f489 100644 --- a/ennead/templates/adm_task_list.html +++ b/ennead/templates/adm_task_list.html @@ -2,25 +2,68 @@ {% block title %}Редактирование задач{% endblock %} +{% set current_task_set = task_set %} + +{% block head %} + +{% endblock %} + {% block body %} -

Задачи {{task_set.name}}

- {% for task in task_set.tasks %} -
-
-
-

- {{task.name}} -

+
+
+
+
+
-
- Баллы: {{task.base_score}} + +
+ +
+
+
+ +
+ +
+
+
+ {% if task_set %} + {% for task in task_set.tasks %} +
+
+
+

+ {{task.name}} +

+
+
+ Баллы: {{task.base_score}} +
+ + Редактировать +
- - Редактировать -
-
- {% endfor %} -

Добавить задачу

- {% include 'task_edit_form.html' %} + {% endfor %} +

Добавить задачу

+ {% include 'task_edit_form.html' %} + {% endif %} {% endblock %} diff --git a/ennead/views/admin.py b/ennead/views/admin.py index 2d61903..71806b2 100644 --- a/ennead/views/admin.py +++ b/ennead/views/admin.py @@ -1,9 +1,14 @@ """Views, used for task creation and editing""" +from typing import Any, Dict + from flask import abort, redirect, render_template, request, url_for from werkzeug.wrappers import Response +from peewee import PeeweeException + from ennead.utils import require_teacher +from ennead.models.base import database from ennead.models.task import Task, TaskSet @@ -11,7 +16,20 @@ def adm_task_list_page() -> Response: """GET /adm/tasks: list of tasks & creation of new""" - return render_template('adm_task_list.html', task_set=TaskSet.get(active=True)) + task_set = None + task_set_criterion: Dict[str, Any] = {'active': True} + task_set_id = request.args.get('task_set') + if isinstance(task_set_id, (str, int)): + try: + task_set_criterion = {'id': int(task_set_id)} + except (TypeError, ValueError): + abort(400) + try: + task_set = TaskSet.get(**task_set_criterion) + except TaskSet.DoesNotExist: + pass + + return render_template('adm_task_list.html', task_set=task_set, task_set_list=TaskSet.select()) @require_teacher @@ -62,3 +80,49 @@ def task_delete(task_id: int) -> Response: Task.delete().where(Task.id == task_id).execute() return redirect(url_for('adm_task_list_page')) + + +@require_teacher +def add_task_set() -> Response: + """POST /adm/task_set: add a new task set""" + + if 'name' not in request.form: + abort(400) + + task_set = TaskSet() + task_set.name = request.form['name'] + task_set.active = True + + with database.atomic() as transaction: + try: + TaskSet.update({TaskSet.active: False}).execute(database) + task_set.save() + except PeeweeException: + transaction.rollback() + abort(500) + + return redirect(url_for('adm_task_list_page')) + + +@require_teacher +def choose_task_set() -> Response: + """"POST /adm/task_set/choose: select active task set""" + + if 'task_set' not in request.form: + abort(400) + + try: + task_set = TaskSet.get_by_id(int(request.form['task_set'])) + except (ValueError, TypeError, TaskSet.DoesNotExist): + abort(400) + + task_set.active = True + with database.atomic() as transaction: + try: + TaskSet.update({TaskSet.active: False}).execute(database) + task_set.save() + except PeeweeException: + transaction.rollback() + abort(500) + + return redirect(url_for('adm_task_list_page'))