diff --git a/tests/config.defaults.json b/tests/config.defaults.json index 78262cb..0588ef8 100644 --- a/tests/config.defaults.json +++ b/tests/config.defaults.json @@ -11,6 +11,7 @@ "TASK_BASE_URL": "http://sovietov.com/kispython", "FINAL_TASKS": null, "ENABLE_REGISTRATION": false, + "HIDE_GROUPS": false, "IMAP_LOGIN": "example@example.com", "IMAP_PASSWORD": "CHANGE_ME", "ENABLE_LKS_OAUTH": false, diff --git a/tests/ui/test_auth.py b/tests/ui/test_auth.py index a117943..6064281 100644 --- a/tests/ui/test_auth.py +++ b/tests/ui/test_auth.py @@ -116,20 +116,6 @@ def test_register_off_get(db: AppDatabase, client: FlaskClient): assert response.status_code == 302 -def test_login_off_post(client: FlaskClient, db: AppDatabase): - create_student(db) - - response = client.post("/login") - assert response.status_code == 302 - - -def test_login_off_get(client: FlaskClient, db: AppDatabase): - create_student(db) - - response = client.get("/login") - assert response.status_code == 302 - - @mode('registration') @pytest.mark.parametrize("password, message", [ ("1234", "Пароль содержит как минимум 8 символов."), diff --git a/tests/ui/test_teacher.py b/tests/ui/test_teacher.py index e91c0be..6374086 100644 --- a/tests/ui/test_teacher.py +++ b/tests/ui/test_teacher.py @@ -12,13 +12,13 @@ def test_login_logout(db: AppDatabase, client: FlaskClient): assert "login" not in response.request.path assert "Выгрузка всех присланных сообщений" in response.get_data(as_text=True) - response = client.get("/teacher/logout", follow_redirects=True) + response = client.get("/logout", follow_redirects=True) - assert "login" in response.request.path + assert response.request.path == "/" def test_false_login(db: AppDatabase, client: FlaskClient): - response = client.post("/teacher/login", data={ + response = client.post("/login", data={ "login": "badLogin", "password": "evenWorsePassword" }, follow_redirects=True) @@ -93,7 +93,7 @@ def test_anonymous_submission(db: AppDatabase, client: FlaskClient): assert db.groups.get_by_id(gid).title in response.get_data(as_text=True) assert code in response.get_data(as_text=True) - assert "студент" not in response.get_data(as_text=True) + assert ", студент" not in response.get_data(as_text=True) def test_invalid_page_redirect(db: AppDatabase, client: FlaskClient): diff --git a/tests/utils.py b/tests/utils.py index 7fd7f19..008a46d 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -9,7 +9,7 @@ from flask.testing import FlaskClient -from webapp.managers import TeacherManager +from webapp.managers import StudentManager from webapp.repositories import AppDatabase @@ -57,12 +57,13 @@ def get_tags( def teacher_login(db: AppDatabase, client: FlaskClient): - login = unique_str() + email = f'{unique_str()}@{unique_str()}.ru' password = unique_str() - tm = TeacherManager(db.teachers) - tm.create(login, password) - return client.post("/teacher/login", data={ - "login": login, + students = StudentManager(None, db.students, db.mailers) + students.create(email, password, True) + db.students.confirm(email) + return client.post("/login", data={ + "login": email, "password": password }, follow_redirects=True) diff --git a/webapp/alembic/versions/20240514.22-12.students_as_teachers.py b/webapp/alembic/versions/20240514.22-12.students_as_teachers.py new file mode 100644 index 0000000..99960ab --- /dev/null +++ b/webapp/alembic/versions/20240514.22-12.students_as_teachers.py @@ -0,0 +1,31 @@ +""" + +Revision ID: 0ed9e0bfabcb +Revises: 30b579748cec +Create Date: 2024-05-14 22:12:06.014972 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '0ed9e0bfabcb' +down_revision = '30b579748cec' +branch_labels = None +depends_on = None + + +def upgrade(): + op.add_column("students", sa.Column("teacher", sa.Boolean, nullable=True)) + op.drop_table("teachers") + + +def downgrade(): + op.drop_column("students", "teacher") + op.create_table( + 'teachers', + sa.Column("id", sa.Integer, primary_key=True, nullable=False), + sa.Column("login", sa.String, nullable=False), + sa.Column("password_hash", sa.String, nullable=False), + ) diff --git a/webapp/config.defaults.json b/webapp/config.defaults.json index 1a9d2f7..c37d381 100644 --- a/webapp/config.defaults.json +++ b/webapp/config.defaults.json @@ -9,6 +9,7 @@ "READONLY": false, "TASK_BASE_URL": "http://kispython.ru/docs", "ENABLE_REGISTRATION": false, + "HIDE_GROUPS": false, "IMAP_LOGIN": null, "IMAP_PASSWORD": null, "FINAL_TASKS": { diff --git a/webapp/dto.py b/webapp/dto.py index f27a224..a93ca2e 100644 --- a/webapp/dto.py +++ b/webapp/dto.py @@ -27,6 +27,7 @@ def __init__(self, config: Config): self.places_in_group: int = config["PLACES_IN_GROUP"] self.groups: dict = config["GROUPS"] self.allow_ip: list[str] = config["ALLOW_IP"] + self.hide_groups: bool = config["HIDE_GROUPS"] @property def exam(self) -> bool: diff --git a/webapp/forms.py b/webapp/forms.py index 6027c3e..d3e552a 100644 --- a/webapp/forms.py +++ b/webapp/forms.py @@ -15,15 +15,21 @@ class StudentMessageForm(FlaskForm): ]) -class TeacherLoginForm(FlaskForm): - login = StringField('login', [DataRequired(message="Данное поле не может быть пустым!")]) +class StudentLoginForm(FlaskForm): + def __init__(self, lks_oauth_enabled: bool = False, *args, **kwargs): + super().__init__(*args, **kwargs) + self.lks_oauth_enabled = lks_oauth_enabled + + login = StringField('email', [ + DataRequired(message="Данное поле не может быть пустым!"), + ]) + password = PasswordField('password', [ DataRequired(message="Данное поле не может быть пустым!"), - Length(min=8, message="Пароль содержит как минимум 8 символов."), ]) -class StudentLoginForm(FlaskForm): +class StudentRegisterForm(FlaskForm): def __init__(self, lks_oauth_enabled: bool = False, *args, **kwargs): super().__init__(*args, **kwargs) self.lks_oauth_enabled = lks_oauth_enabled @@ -35,14 +41,13 @@ def __init__(self, lks_oauth_enabled: bool = False, *args, **kwargs): "Убедитесь, что строка не включает пробелы." )) ]) + password = PasswordField('password', [ DataRequired(message="Данное поле не может быть пустым!"), Length(min=8, message="Пароль содержит как минимум 8 символов."), NoneOf(["12345678", "password"], message="Не используйте такие пароли, как 12345678 и password.") ]) - -class StudentRegisterForm(StudentLoginForm): confirm = PasswordField('password', [ DataRequired(message="Данное поле не может быть пустым!"), EqualTo('password', message="Пароли не совпадают!") diff --git a/webapp/managers.py b/webapp/managers.py index fb91d5e..affcb15 100644 --- a/webapp/managers.py +++ b/webapp/managers.py @@ -19,7 +19,7 @@ TaskStatusDto, VariantDto ) -from webapp.models import FinalSeed, Group, Message, MessageCheck, Student, Task, TaskStatus, Teacher, Variant +from webapp.models import FinalSeed, Group, Message, MessageCheck, Student, Task, TaskStatus, Variant from webapp.repositories import ( FinalSeedRepository, GroupRepository, @@ -29,7 +29,6 @@ StudentRepository, TaskRepository, TaskStatusRepository, - TeacherRepository, VariantRepository ) @@ -482,10 +481,10 @@ def email_allowed(self, email: str) -> bool: exists = self.mailers.exists(domain) return exists - def create(self, email: str, password: str) -> int: + def create(self, email: str, password: str, teacher=False) -> int: given = password.encode('utf8') hashed = bcrypt.hashpw(given, bcrypt.gensalt()) - student = self.students.create(email, hashed.decode('utf8')) + student = self.students.create(email, hashed.decode('utf8'), teacher) return student.id @@ -599,22 +598,3 @@ def __create_csv(self, table: list[list[str]], delimiter: str): bom = u"\uFEFF" value = bom + si.getvalue() return value - - -class TeacherManager: - def __init__(self, teachers: TeacherRepository): - self.teachers = teachers - - def check_password(self, login: str, password: str) -> Teacher | None: - teacher = self.teachers.find_by_login(login) - if teacher: - given = password.encode('utf8') - actual = teacher.password_hash.encode('utf8') - if bcrypt.checkpw(given, actual): - return teacher - - def create(self, login: str, password: str): - given = password.encode('utf8') - hashed = bcrypt.hashpw(given, bcrypt.gensalt()) - teacher = self.teachers.create(login, hashed.decode('utf8')) - return teacher.id diff --git a/webapp/models.py b/webapp/models.py index 01dbe58..673bff7 100644 --- a/webapp/models.py +++ b/webapp/models.py @@ -122,13 +122,6 @@ class FinalSeed(Base): group = sa.Column("group", sa.Integer, sa.ForeignKey('groups.id'), primary_key=True, nullable=False) -class Teacher(Base): - __tablename__ = "teachers" - id = sa.Column("id", sa.Integer, primary_key=True, nullable=False) - login = sa.Column("login", sa.String, nullable=False) - password_hash = sa.Column("password_hash", sa.String, nullable=False) - - class Student(Base): __tablename__ = "students" id = sa.Column("id", sa.Integer, primary_key=True, nullable=False) @@ -139,6 +132,7 @@ class Student(Base): password_hash = sa.Column("password_hash", sa.String, nullable=True) unconfirmed_hash = sa.Column("unconfirmed_hash", sa.String, nullable=True) blocked = sa.Column("blocked", sa.Boolean, nullable=False) + teacher = sa.Column("teacher", sa.Boolean, nullable=True) class Mailer(Base): diff --git a/webapp/repositories.py b/webapp/repositories.py index 8bd1522..e85f22b 100644 --- a/webapp/repositories.py +++ b/webapp/repositories.py @@ -15,7 +15,6 @@ Student, Task, TaskStatus, - Teacher, Variant, create_session_maker ) @@ -457,30 +456,6 @@ def delete_final_seed(self, group: int): .delete() -class TeacherRepository: - def __init__(self, db: DbContextManager): - self.db = db - - def get_by_id(self, id: int) -> Teacher | None: - with self.db.create_session() as session: - teacher = session.query(Teacher).get(id) - return teacher - - def find_by_login(self, login: str) -> Teacher | None: - with self.db.create_session() as session: - teacher = session.query(Teacher) \ - .filter_by(login=login) \ - .first() - return teacher - - def create(self, login: str, password: str): - with self.db.create_session() as session: - teacher = Teacher(login=login, - password_hash=password) - session.add(teacher) - return teacher - - class StudentRepository: def __init__(self, db: DbContextManager): self.db = db @@ -524,10 +499,10 @@ def confirm(self, email: str): unconfirmed_hash=None, )) - def create(self, email: str, password: str) -> Student: + def create(self, email: str, password: str, teacher=False) -> Student: email = email.lower() with self.db.create_session() as session: - student = Student(email=email, unconfirmed_hash=password, blocked=False) + student = Student(email=email, unconfirmed_hash=password, teacher=teacher, blocked=False) session.add(student) return student @@ -580,6 +555,5 @@ def __init__(self, get_connection: Callable[[], str]): self.messages = MessageRepository(db) self.checks = MessageCheckRepository(db) self.seeds = FinalSeedRepository(db) - self.teachers = TeacherRepository(db) self.students = StudentRepository(db) self.mailers = MailerRepository(db) diff --git a/webapp/templates/error.jinja b/webapp/templates/error.jinja index 204395f..32fa4a8 100644 --- a/webapp/templates/error.jinja +++ b/webapp/templates/error.jinja @@ -13,4 +13,4 @@ -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/layout.jinja b/webapp/templates/layout.jinja index e87bdad..9eed1e7 100644 --- a/webapp/templates/layout.jinja +++ b/webapp/templates/layout.jinja @@ -1,73 +1,159 @@ + Цифровой ассистент преподавателя - - - - + + + + - {% block head %}{% endblock %} + {% block head %}{% endblock %} + -{% block content %}{% endblock %} -{% block footer %}{% endblock %} + {% block content %} + +
+ {% block main %} {% endblock %} +
+ {% endblock %} + {% block footer %}{% endblock %} - + + \ No newline at end of file diff --git a/webapp/templates/student/dashboard.jinja b/webapp/templates/student/dashboard.jinja index b3f47d3..e3354d8 100644 --- a/webapp/templates/student/dashboard.jinja +++ b/webapp/templates/student/dashboard.jinja @@ -1,32 +1,31 @@ -{% extends 'student/student_layout.jinja' %} - +{% extends 'layout.jinja' %} {% block header %} - + {% endblock %} {% block main %} -
- {% if exam %} Режим зачёта {% else %} Перечень групп {% endif %} -
-
- Нажмите на группу, чтобы перейти к вариантам заданий группы. -
+
+ {% if exam %} Режим зачёта {% else %} Перечень групп {% endif %} +
+
+ Нажмите на группу, чтобы перейти к вариантам заданий группы. +
+
+ {% for key, grouping in groupings.items() %}
- {% for key, grouping in groupings.items() %} -
- - {{ key }} - - {% for group in grouping %} - - {{ group.title }} - - {% endfor %} -
+ + {{ key }} + + {% for group in grouping %} + + {{ group.title }} + {% endfor %}
+ {% endfor %} +
{% endblock %} {% block footer %} diff --git a/webapp/templates/student/group.jinja b/webapp/templates/student/group.jinja index 58ada92..702df04 100644 --- a/webapp/templates/student/group.jinja +++ b/webapp/templates/student/group.jinja @@ -1,71 +1,113 @@ -{% extends 'student/student_layout.jinja' %} +{% extends 'layout.jinja' %} +{% block head %} + +{% endblock %} {% block header %} - + {% endblock %} {% block main %} - {% if blocked %} -
- Зачёт ещё не начат -
-
- Зачёт для группы {{ group.title }} ещё не начат. -
- {% else %} -
- Варианты заданий группы - - {{ group.title }} - -
-
- Список вариантов. Нажмите на соответствующую Вашему варианту ячейку, чтобы перейти к отправке. -
-
- - - - - {% for task in group.tasks %} - - {% endfor %} - - - - {% for variant in group.variants %} - - - {% for status in variant.statuses %} - - {% endfor %} - +{% if blocked %} +
+ Зачёт ещё не начат +
+
+ Зачёт для группы {{ group.title }} ещё не начат. +
+{% else %} +
+ Варианты заданий группы + + {{ group.title }} + +
+
+ Список вариантов. Нажмите на соответствующую Вашему варианту ячейку, чтобы перейти к отправке. +
+
+
+
Вариант - - №{{ task.formulation if task.formulation else task.id + 1 }} - -
- - {{ variant.id + 1 }} - - - - {{ status.code }} - {% if status.earned > 1 %} - - {{ status.earned }} - - {% endif %} - -
+ + + + {% for task in group.tasks %} + + {% endfor %} + + + + {% for variant in group.variants %} + + + {% for status in variant.statuses %} + {% endfor %} - -
Вариант + + №{{ task.formulation if task.formulation else task.id + 1 }} + +
+ + {{ variant.id + 1 }} + + + + {{ status.code }} + {% if status.earned > 1 %} + + {{ status.earned }} + + {% endif %} + +
+ + {% endfor %} + + +
+ {% if hide_groups and registration and not student %} +
+ +
Для просмотра страницы необходимо:
+ + Войти на сайт + +
{% endif %} -{% endblock %} + +{% endif %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/student/groups_rating.jinja b/webapp/templates/student/groups_rating.jinja index 43c1501..11b17be 100644 --- a/webapp/templates/student/groups_rating.jinja +++ b/webapp/templates/student/groups_rating.jinja @@ -1,40 +1,39 @@ -{% extends 'student/student_layout.jinja' %} +{% extends 'layout.jinja' %} {% block header %} - + {% endblock %} {% block main %} - {% if blocked %} -
- Зачёт ещё не начат -
- {% else %} -
- Рейтинг групп -
-
- Рейтинг групп на основании количества полученных допусков студентами группы. -
-
- {% for score, groups in groupings.items() %} -
- {% for group in groups %} -
-
- -
- {{ group.group.title }} -
-
- {{ group.earned }} -
-
- {% endfor %} -
- {% endfor %} -
- {% endif %} -{% endblock %} +{% if blocked %} +
+ Зачёт ещё не начат +
+{% else %} +
+ Рейтинг групп +
+
+ Рейтинг групп на основании количества полученных допусков студентами группы. +
+
+ {% for score, groups in groupings.items() %} +
+ {% for group in groups %} +
+
+ +
+ {{ group.group.title }} +
+
+ {{ group.earned }} +
+
+ {% endfor %} +
+ {% endfor %} +
+{% endif %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/student/login.jinja b/webapp/templates/student/login.jinja index 1e20271..4898c31 100644 --- a/webapp/templates/student/login.jinja +++ b/webapp/templates/student/login.jinja @@ -1,87 +1,76 @@ {% extends 'layout.jinja' %} -{% block content %} - -
-
-
-
- - Авторизация -
- - - Введите адрес электронной почты. + {% if registration %} + - {% if form.login.errors %} - - {% for error in form.login.errors %} -
{{ error }}
- {% endfor %} -
- {% endif %} -
- - - Введите пароль. + - {% if form.password.errors %} - - {% for error in form.password.errors %} -
{{ error }}
- {% endfor %} -
{% endif %} - {{ form.csrf_token }} - + {% if form.lks_oauth_enabled %} + + {% endif %} +
-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/student/password.jinja b/webapp/templates/student/password.jinja index 9022dac..a23d3ac 100644 --- a/webapp/templates/student/password.jinja +++ b/webapp/templates/student/password.jinja @@ -1,81 +1,68 @@ {% extends 'layout.jinja' %} -{% block content %} - -
-
-
-
-
- Сброс пароля -
- - - Введите адрес электронной почты. -
- {% if form.login.errors %} - - {% for error in form.login.errors %} -
{{ error }}
- {% endfor %} -
- {% endif %} -
- - - Введите пароль. -
- {% if form.password.errors %} - - {% for error in form.password.errors %} -
{{ error }}
- {% endfor %} -
- {% endif %} -
- - - Подтвердите пароль. +{% block header %} + +{% endblock %} + +{% block main %} +
+
+
+ + Сброс пароля +
+ + + Введите адрес электронной почты. +
+ {% if form.login.errors %} + + {% for error in form.login.errors %} +
{{ error }}
+ {% endfor %} +
+ {% endif %} +
+ + + Введите пароль. +
+ {% if form.password.errors %} + + {% for error in form.password.errors %} +
{{ error }}
+ {% endfor %} +
+ {% endif %} +
+ + + Подтвердите пароль. +
+ {% if form.confirm.errors %} + + {% for error in form.confirm.errors %} +
{{ error }}
+ {% endfor %} +
+ {% endif %} + {{ form.csrf_token }} +
+
+
- {% if form.confirm.errors %} - - {% for error in form.confirm.errors %} -
{{ error }}
- {% endfor %} -
- {% endif %} - {{ form.csrf_token }} -
-
- -
- + - -
+
+
-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/student/rating.jinja b/webapp/templates/student/rating.jinja index cdf8a7c..62661a4 100644 --- a/webapp/templates/student/rating.jinja +++ b/webapp/templates/student/rating.jinja @@ -1,53 +1,52 @@ -{% extends 'student/student_layout.jinja' %} +{% extends 'layout.jinja' %} {% block header %} - + {% endblock %} {% block main %} - {% if blocked %} -
- Зачёт ещё не начат -
- {% else %} -
- Рейтинг студентов -
-
- Рейтинг студентов на основании количества решенных разными способами задач. -
-
- {% for score, students in groupings.items() %} -
- - {% if loop.index == 1 %} - 🥇 Топ 1 - {% elif loop.index == 2 %} - 🥈 Топ 2 - {% elif loop.index == 3 %} - 🥉 Топ 3 - {% else %} - Топ {{ loop.index }} - {% endif %} - -
- {% for student in students %} - - {% endfor %} -
-
- {% endfor %} +{% if blocked %} +
+ Зачёт ещё не начат +
+{% else %} +
+ Рейтинг студентов +
+
+ Рейтинг студентов на основании количества решенных разными способами задач. +
+
+ {% for score, students in groupings.items() %} +
+ + {% if loop.index == 1 %} + 🥇 Топ 1 + {% elif loop.index == 2 %} + 🥈 Топ 2 + {% elif loop.index == 3 %} + 🥉 Топ 3 + {% else %} + Топ {{ loop.index }} + {% endif %} + +
+ {% for student in students %} +
+ - {% endif %} -{% endblock %} +
+ {% endfor %} +
+
+ {% endfor %} +
+{% endif %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/student/register.jinja b/webapp/templates/student/register.jinja index 16d9bdf..75741ba 100644 --- a/webapp/templates/student/register.jinja +++ b/webapp/templates/student/register.jinja @@ -1,94 +1,81 @@ {% extends 'layout.jinja' %} -{% block content %} - -
-
-
-
-
- Регистрация -
- - - Введите адрес электронной почты. -
- {% if form.login.errors %} - - {% for error in form.login.errors %} -
{{ error }}
- {% endfor %} -
- {% endif %} -
- - - Введите пароль. +{% block header %} + +{% endblock %} + +{% block main %} +
+
+
+ + Регистрация +
+ + + Введите адрес электронной почты. +
+ {% if form.login.errors %} + + {% for error in form.login.errors %} +
{{ error }}
+ {% endfor %} +
+ {% endif %} +
+ + + Введите пароль. +
+ {% if form.password.errors %} + + {% for error in form.password.errors %} +
{{ error }}
+ {% endfor %} +
+ {% endif %} +
+ + + Подтвердите пароль. +
+ {% if form.confirm.errors %} + + {% for error in form.confirm.errors %} +
{{ error }}
+ {% endfor %} +
+ {% endif %} + {{ form.csrf_token }} +
+
+
- {% if form.password.errors %} - - {% for error in form.password.errors %} -
{{ error }}
- {% endfor %} -
- {% endif %} -
- - - Подтвердите пароль. + - {% if form.confirm.errors %} - - {% for error in form.confirm.errors %} -
{{ error }}
- {% endfor %} -
- {% endif %} - {{ form.csrf_token }} -
-
- -
- +
+ {% if form.lks_oauth_enabled %} + + {% endif %} +
-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/student/student_layout.jinja b/webapp/templates/student/student_layout.jinja deleted file mode 100644 index 14b7def..0000000 --- a/webapp/templates/student/student_layout.jinja +++ /dev/null @@ -1,62 +0,0 @@ -{% extends 'layout.jinja' %} -{% block content %} - -
- {% block main %} {% endblock %} -
-{% endblock %} diff --git a/webapp/templates/student/submissions.jinja b/webapp/templates/student/submissions.jinja index 4f5dd88..2f137f7 100644 --- a/webapp/templates/student/submissions.jinja +++ b/webapp/templates/student/submissions.jinja @@ -1,86 +1,79 @@ -{% extends 'student/student_layout.jinja' %} - +{% extends 'layout.jinja' %} {% block head %} - + {% endblock %} {% block header %} - + {% endblock %} {% block main %} -
- Отправленные решения -
-
- Новые решения показаны сверху. Страница {{ page + 1 }}. -
- {% if submissions is defined and submissions|length > 0 %} - {% for submission in submissions %} -
-
- Задача №{{ submission.status.task + 1 }}, - вариант №{{ submission.status.variant + 1 }}, - группа {{ submission.status.group_title }} -
-
- {{ submission.status.name }} - Отправлено: {{ submission.sent.strftime('%d.%m.%Y %H:%M') }} - Проверено: {{ submission.checked.strftime('%d.%m.%Y %H:%M') }} -
- {% if submission.status.error_message is not none and submission.status.error_message %} -
Подробные сведения об ошибке:
-
{{ submission.status.error_message | e }}
- {% else %} -
- {% endif %} - -
- {% endfor %} +
+ Отправленные решения +
+
+ Новые решения показаны сверху. Страница {{ page + 1 }}. +
+{% if submissions is defined and submissions|length > 0 %} +{% for submission in submissions %} +
+
+ Задача №{{ submission.status.task + 1 }}, + вариант №{{ submission.status.variant + 1 }}, + группа {{ submission.status.group_title }} +
+
+ {{ submission.status.name }} + Отправлено: {{ submission.sent.strftime('%d.%m.%Y %H:%M') }} + Проверено: {{ submission.checked.strftime('%d.%m.%Y %H:%M') }} +
+ {% if submission.status.error_message is not none and submission.status.error_message %} +
Подробные сведения об ошибке:
+
{{ submission.status.error_message | e }}
+ {% else %} +
+ {% endif %} + +
+{% endfor %} - {{ pagination.links }} - {% else %} - Список отправленных решений пуст - {% endif %} +{{ pagination.links }} +{% else %} +Список отправленных решений пуст +{% endif %} - {% if highlight %} - - - - {% endif %} -{% endblock %} +{% if highlight %} + + + +{% endif %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/student/success.jinja b/webapp/templates/student/success.jinja index 0596f4d..6f7b91d 100644 --- a/webapp/templates/student/success.jinja +++ b/webapp/templates/student/success.jinja @@ -1,31 +1,30 @@ -{% extends 'student/student_layout.jinja' %} - +{% extends 'layout.jinja' %} {% block header %} - - - + + + {% endblock %} {% block main %} -
- Задача №{{ status.task + 1 }}, - вариант №{{ status.variant + 1 }}, - группа {{ status.group_title }} -
-
- Ответ на задание успешно отправлен. Результат проверки вскоре отобразится на странице задания. -
- - Вернуться на страницу задания - -{% endblock %} +
+ Задача №{{ status.task + 1 }}, + вариант №{{ status.variant + 1 }}, + группа {{ status.group_title }} +
+
+ Ответ на задание успешно отправлен. Результат проверки вскоре отобразится на странице задания. +
+ + Вернуться на страницу задания + +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/student/task.jinja b/webapp/templates/student/task.jinja index ac80bad..d467e9d 100644 --- a/webapp/templates/student/task.jinja +++ b/webapp/templates/student/task.jinja @@ -1,134 +1,137 @@ -{% extends 'student/student_layout.jinja' %} - +{% extends 'layout.jinja' %} {% block header %} - - + + {% endblock %} {% block main %} +
+ Задача №{{ status.formulation if status.formulation + else status.task + 1 }}, + вариант №{{ status.variant + 1 }}, + группа {{ status.group_title }} +
+
+ Здесь Вы можете отправить ответ на задание №{{ status.formulation if status.formulation else status.task + 1 }} для + варианта №{{ status.variant + 1 }}. +
+ +
- Задача №{{ status.formulation if status.formulation else status.task + 1 }}, - вариант №{{ status.variant + 1 }}, - группа {{ status.group_title }} + Состояние задачи
- Здесь Вы можете отправить ответ на задание №{{ status.formulation if status.formulation else status.task + 1 }} для варианта №{{ status.variant + 1 }}. + В данной секции Вы можете отслеживать состояние отправленного задания.
-
- - Перейти к задаче №{{ status.external.task + 1 }} варианта №{{ status.external.variant + 1 }} группы {{ status.external.group_title }} - + {% if status.status == 4 %} +
После отправки выполненного задания Вы сможете отслеживать его состояние здесь.
+ {% else %} +
+ {{ status.name }}
-
-
- Состояние задачи -
-
- В данной секции Вы можете отслеживать состояние отправленного задания. -
- {% if status.status == 4 %} -
После отправки выполненного задания Вы сможете отслеживать его состояние здесь.
- {% else %} -
- {{ status.name }} -
- {% if status.error_message is not none and status.error_message %} -
Подробные сведения об ошибке:
-
{{ status.error_message | e }}
- {% else %} -
- {% endif %} - {% endif %} + {% if status.error_message is not none and status.error_message %} +
Подробные сведения об ошибке:
+
{{ status.error_message | e }}
+ {% else %} +
+ {% endif %} + {% endif %} +
+{% if status.show_achievements %} +
+
+ Разблокированные достижения + + {{ status.earned }} из {{ status.achievements | length }} + +
+
+ Сможете ли Вы решить задачу всеми способами, известными искусственной нейронной сети? +
+ {% if status.achievements %} + {% for dto in status.achievements %} +
+
{{ dto.title }} {{ '✓' if dto.active else '' }}
+ {{ dto.description }}
- {% if status.show_achievements %} -
-
- Разблокированные достижения - - {{ status.earned }} из {{ status.achievements | length }} - -
-
- Сможете ли Вы решить задачу всеми способами, известными искусственной нейронной сети? -
- {% if status.achievements %} - {% for dto in status.achievements %} -
-
{{ dto.title }} {{ '✓' if dto.active else '' }}
- {{ dto.description }} -
- {% endfor %} - {% endif %} -
+ {% endfor %} {% endif %} -
-
-
Добавить новый ответ
-
- Во избежание утери данных рекомендуется сохранять отправляемые программы локально. +
+{% endif %} +
+ +
Добавить новый ответ
+
+ Во избежание утери данных рекомендуется сохранять отправляемые программы локально. +
+ {% if registration and not student %} +
+ - {% if registration and not student %} - - {% else %} -
- - -
- Введите ответ в поле выше. В отправляемом коде на языке программирования Python должна присутствовать функция - main и не должно быть какого-либо ввода/вывода. Поддерживается - использование модулей только из стандартной библиотеки Python. -
-
-
- {% if form.code.errors %} -
    - {% for error in form.code.errors %} -
  • {{ error }}
  • - {% endfor %} -
- {% endif %} - {{ form.csrf_token }} -
-
- -
+
+ {% else %} +
+ + +
+ Введите ответ в поле выше. В отправляемом коде на языке программирования Python должна присутствовать функция + main и не должно быть какого-либо ввода/вывода. Поддерживается + использование модулей только из стандартной библиотеки Python.
+
+
+ {% if form.code.errors %} +
    + {% for error in form.code.errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} + {{ form.csrf_token }} +
+
+ +
+ {% if student and student.teacher %} + {% endif %} - -
+
+ {% endif %} + +
{% if highlight and not (status.disabled or registration and not student) %} - - - + + + {% endif %} -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/teacher/dashboard.jinja b/webapp/templates/teacher/dashboard.jinja index ad920e1..096d4ba 100644 --- a/webapp/templates/teacher/dashboard.jinja +++ b/webapp/templates/teacher/dashboard.jinja @@ -1,107 +1,92 @@ {% extends 'layout.jinja' %} -{% block content %} - -
-
- {% if groups is not none %} -
- Управление группами -
- - -
-
- {% endif %} -
- Выгрузка всех присланных сообщений -
- - - -
-
-
- Просмотр решений студентов -
- - - - -
-
- {% if exam %} -
- Действия с группами -
- -
-
- -
- {% if clearable %} -
- -
- {% endif %} -
+ {% endif %} +
+ Выгрузка всех присланных сообщений +
+ + + +
+
+
+ Просмотр решений студентов +
+ + + + +
+
+ {% if exam %} +
+ Действия с группами +
+ +
+
+ +
+ {% if clearable %} +
+ +
{% endif %}
+ {% endif %}
-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/teacher/exam.jinja b/webapp/templates/teacher/exam.jinja index ae9e64e..1f1fc3b 100644 --- a/webapp/templates/teacher/exam.jinja +++ b/webapp/templates/teacher/exam.jinja @@ -1,86 +1,71 @@ {% extends 'layout.jinja' %} -{% block content %} - -
- {% if seed == None %} -
Зачёт ещё не начат
-
- - -
- {% elif seed.active == false %} -
Зачёт завершён
- -
Выгрузка результатов
-
- - - -
-
Продолжить зачёт
- -
- -
- {% else %} -
Зачёт начат
-
- - -
-
Выгрузка промежуточных результатов
-
- - - -
- {% endif %} - {% if seed == None or seed.active == false %} -
- -
- {% endif %} +{% block header %} + + + +{% endblock %} + +{% block main %} +{% if seed == None %} +
Зачёт ещё не начат
+
+ + +
+{% elif seed.active == false %} +
Зачёт завершён
+ +
Выгрузка результатов
+
+ + + +
+
Продолжить зачёт
+ +
+ +
+{% else %} +
Зачёт начат
+
+ + +
+
Выгрузка промежуточных результатов
+
+ + + +
+{% endif %} +{% if seed == None or seed.active == false %} +
+ +
+{% endif %} {% endblock %} \ No newline at end of file diff --git a/webapp/templates/teacher/login.jinja b/webapp/templates/teacher/login.jinja deleted file mode 100644 index 8a4ea03..0000000 --- a/webapp/templates/teacher/login.jinja +++ /dev/null @@ -1,64 +0,0 @@ -{% extends 'layout.jinja' %} -{% block content %} - -
-
-
-
-
- Авторизация -
- - - Введите имя пользователя. -
- {% if form.login.errors %} - - {% for error in form.login.errors %} -
{{ error }}
- {% endfor %} -
- {% endif %} -
- - - Введите пароль. -
- {% if form.password.errors %} - - {% for error in form.password.errors %} -
{{ error }}
- {% endfor %} -
- {% endif %} - {{ form.csrf_token }} -
-
- -
-
-
-
-
-
-
-{% endblock %} diff --git a/webapp/templates/teacher/queue.jinja b/webapp/templates/teacher/queue.jinja index 1ff6627..9547cfb 100644 --- a/webapp/templates/teacher/queue.jinja +++ b/webapp/templates/teacher/queue.jinja @@ -1,75 +1,52 @@ {% extends 'layout.jinja' %} -{% block content %} - -
-
- {% if message is not none %} -
- +
+
+ +
+
+ + +
+
+ Сведения о сообщении +
Группа: {{ group.title }}
+
Вариант: {{ message.variant + 1 }}
+
Задача: {{ message.task + 1 }}
+
Прислано: {{ message.time }}
-
-
- -
-
- - -
-
- Сведения о сообщении -
Группа: {{ group.title }}
-
Вариант: {{ message.variant + 1 }}
-
Задача: {{ message.task + 1 }}
-
Прислано: {{ message.time }}
-
-
- {% else %} -
- Новых сообщений нет -
- {% endif %}
+ {% else %} +
+ Новых сообщений нет +
+ {% endif %}
{% endblock %} \ No newline at end of file diff --git a/webapp/templates/teacher/submissions.jinja b/webapp/templates/teacher/submissions.jinja index c4d2555..3f855c1 100644 --- a/webapp/templates/teacher/submissions.jinja +++ b/webapp/templates/teacher/submissions.jinja @@ -1,101 +1,70 @@ {% extends 'layout.jinja' %} -{% block content %} - -
-
-
-
- Отправленные решения -
-
- Новые решения показаны сверху. Страница {{ page + 1 }}. -
-
- {% if submissions is defined and submissions|length > 0 %} - {% for submission in submissions %} -
-
- Задача №{{ submission.status.task + 1 }}, - вариант №{{ submission.status.variant + 1 }}, - группа {{ submission.status.group_title }} - {% if submission.student %} - , - студент {{ submission.student.email | hide }}, - id {{ submission.student.id }} - - {% endif %} -
-
- {{ submission.status.name }} - Отправлено: {{ submission.sent.strftime('%d.%m.%Y %H:%M') }} - Проверено: {{ submission.checked.strftime('%d.%m.%Y %H:%M') }} -
- {% if submission.status.error_message is not none and submission.status.error_message %} -
Подробные сведения об ошибке:
-
{{ submission.status.error_message | e }}
- {% else %} -
- {% endif %} - -
- {% endfor %} - - {{ pagination.links }} - {% else %} - Список отправленных решений пуст - {% endif %} -
+{% block header %} + +{% endblock %} - {% if highlight %} - - - - {% endif %} +{% block main %} +
+
+
+ Отправленные решения +
+
+ Новые решения показаны сверху. Страница {{ page + 1 }}. +
+
+ {% if submissions is defined and submissions|length > 0 %} + {% for submission in submissions %} +
+
+ Задача №{{ submission.status.task + 1 }}, + вариант №{{ submission.status.variant + 1 }}, + группа {{ submission.status.group_title }} + {% if submission.student %} + , студент {{ submission.student.email | hide }}, + id {{ submission.student.id }} + {% endif %} +
+
+ {{ submission.status.name }} + Отправлено: {{ submission.sent.strftime('%d.%m.%Y %H:%M') }} + Проверено: {{ submission.checked.strftime('%d.%m.%Y %H:%M') }}
-{% endblock %} + {% if submission.status.error_message is not none and submission.status.error_message %} +
Подробные сведения об ошибке:
+
{{ submission.status.error_message | e }}
+ {% else %} +
+ {% endif %} + +
+ {% endfor %} + {{ pagination.links }} + {% else %} + Список отправленных решений пуст + {% endif %} +
+ +{% if highlight %} + + + +{% endif %} +{% endblock %} \ No newline at end of file diff --git a/webapp/utils.py b/webapp/utils.py index c75eb65..977ab05 100644 --- a/webapp/utils.py +++ b/webapp/utils.py @@ -4,21 +4,21 @@ import traceback from functools import wraps -from flask_jwt_extended import get_jwt, get_jwt_identity, unset_jwt_cookies, verify_jwt_in_request +from flask_jwt_extended import get_jwt_identity, unset_jwt_cookies, verify_jwt_in_request from jwt import PyJWTError from flask import Request, redirect from webapp.managers import AppConfigManager -from webapp.repositories import StudentRepository, TeacherRepository +from webapp.repositories import StudentRepository -def student_jwt_reset(config: AppConfigManager, path: str): +def student_jwt_reset(config: AppConfigManager, path: str, auth_redirect=True): def wrapper(function): @wraps(function) def decorator(*args, **kwargs): - if not config.config.registration: - return redirect('/') + if not config.config.registration and auth_redirect: + return redirect("/") if verify_jwt_in_request(True): response = redirect(path) unset_jwt_cookies(response) @@ -36,27 +36,21 @@ def decorator(*args, **kwargs): identity = get_jwt_identity() if identity is None: return function(None, *args, **kwargs) - claims = get_jwt() - if "teacher" in claims: - return function(None, *args, **kwargs) student = students.get_by_id(identity) return function(student, *args, **kwargs) return decorator return wrapper -def teacher_jwt_required(teachers: TeacherRepository): +def teacher_jwt_required(students: StudentRepository): def wrapper(function): @wraps(function) def decorator(*args, **kwargs): verify_jwt_in_request() - claims = get_jwt() - if "teacher" in claims: - identity = get_jwt_identity() - teacher = teachers.get_by_id(identity) - if teacher: - return function(teacher, *args, **kwargs) - raise PyJWTError() + identity = get_jwt_identity() + student = students.get_by_id(identity) + if student.teacher: + return function(student, *args, **kwargs) raise PyJWTError() return decorator return wrapper diff --git a/webapp/views/student.py b/webapp/views/student.py index 31f7295..8106c13 100644 --- a/webapp/views/student.py +++ b/webapp/views/student.py @@ -101,6 +101,7 @@ def group(student: Student | None, group_id: int): "student/group.jinja", group=group, blocked=blocked, + hide_groups=config.config.hide_groups, registration=config.config.registration, group_rating=config.config.groups, exam=config.config.exam, @@ -188,17 +189,26 @@ def submit_task(student: Student | None, gid: int, vid: int, tid: int): @blueprint.route("/login", methods=['GET', 'POST']) -@student_jwt_reset(config, "/login") +@student_jwt_reset(config, "/login", False) def login(): form = StudentLoginForm(lks_oauth_enabled=config.config.enable_lks_oauth) if not form.validate_on_submit(): - return render_template("student/login.jinja", form=form) + return render_template( + "student/login.jinja", + registration=config.config.registration, + group_rating=config.config.groups, + form=form + ) error = students.login(form.login.data, form.password.data) if error: form.login.errors.append(error) - return render_template("student/login.jinja", form=form) - response = redirect("/") + return render_template( + "student/login.jinja", + registration=config.config.registration, + group_rating=config.config.groups, + form=form) student = db.students.find_by_email(form.login.data) + response = redirect("/teacher" if student.teacher else "/") set_access_cookies(response, create_access_token(identity=student.id)) return response @@ -250,7 +260,12 @@ def register(): form = StudentRegisterForm(lks_oauth_enabled=config.config.enable_lks_oauth) if form.validate_on_submit(): form.login.errors.append(students.register(form.login.data, form.password.data)) - return render_template("student/register.jinja", form=form) + return render_template( + "student/register.jinja", + registration=config.config.registration, + group_rating=config.config.groups, + form=form + ) @blueprint.route("/change-password", methods=['GET', 'POST']) @@ -259,7 +274,12 @@ def change_password(): form = StudentChangePasswordForm() if form.validate_on_submit(): form.login.errors.append(students.change_password(form.login.data, form.password.data)) - return render_template("student/password.jinja", form=form) + return render_template( + "student/password.jinja", + registration=config.config.registration, + group_rating=config.config.groups, + form=form + ) @blueprint.route("/logout", methods=['GET']) diff --git a/webapp/views/teacher.py b/webapp/views/teacher.py index a450cc0..a6ee866 100644 --- a/webapp/views/teacher.py +++ b/webapp/views/teacher.py @@ -1,4 +1,4 @@ -from flask_jwt_extended import create_access_token, set_access_cookies, unset_jwt_cookies, verify_jwt_in_request +from flask_jwt_extended import unset_jwt_cookies from flask_jwt_extended.exceptions import JWTExtendedException from flask_paginate import Pagination from jwt.exceptions import PyJWTError @@ -7,10 +7,9 @@ from flask import current_app as app from flask import make_response, redirect, render_template, request -from webapp.forms import TeacherLoginForm -from webapp.managers import AppConfigManager, ExportManager, StatusManager, StudentManager, TeacherManager -from webapp.models import Group, Message, Status, Task, Teacher, Variant -from webapp.repositories import AppDatabase, DbContextManager +from webapp.managers import AppConfigManager, ExportManager, StatusManager, StudentManager +from webapp.models import Message, Student +from webapp.repositories import AppDatabase from webapp.utils import get_exception_info, teacher_jwt_required @@ -21,13 +20,12 @@ students = StudentManager(config, db.students, db.mailers) statuses = StatusManager(db.tasks, db.groups, db.variants, db.statuses, config, db.seeds, db.checks) exports = ExportManager(db.groups, db.messages, statuses, db.variants, db.tasks, db.students, students) -teachers = TeacherManager(db.teachers) @blueprint.route("/teacher/submissions/group//variant//task/", methods=["GET"], defaults={'page': 0}) @blueprint.route("/teacher/submissions/group//variant//task//", methods=["GET"]) -@teacher_jwt_required(db.teachers) -def teacher_submissions(teacher: Teacher, gid: int, vid: int, tid: int, page: int): +@teacher_jwt_required(db.students) +def teacher_submissions(teacher: Student, gid: int, vid: int, tid: int, page: int): size = 5 submissions_statuses = statuses.get_submissions_statuses_by_info(gid, vid, tid, (page - 1) * size, size) if not submissions_statuses and page > 0: @@ -48,15 +46,18 @@ def teacher_submissions(teacher: Teacher, gid: int, vid: int, tid: int, page: in "teacher/submissions.jinja", submissions=submissions_statuses, highlight=config.config.highlight_syntax, + registration=config.config.registration, + group_rating=config.config.groups, page=page, info=(gid, vid, tid), pagination=pagination, + student=teacher, ) @blueprint.route("/teacher/submissions", methods=["GET"]) -@teacher_jwt_required(db.teachers) -def select_submissions(teacher: Teacher): +@teacher_jwt_required(db.students) +def select_submissions(teacher: Student): gid = request.args.get('gid') vid = request.args.get('vid') tid = request.args.get('tid') @@ -64,15 +65,18 @@ def select_submissions(teacher: Teacher): @blueprint.route("/teacher", methods=["GET"]) -@teacher_jwt_required(db.teachers) -def dashboard(teacher: Teacher): +@teacher_jwt_required(db.students) +def dashboard(teacher: Student): groups = db.groups.get_all() if config.config.no_background_worker or config.config.final_tasks else None glist = db.groups.get_all() vlist = db.variants.get_all() tlist = db.tasks.get_all() return render_template( "teacher/dashboard.jinja", + student=teacher, clearable=config.config.clearable_database, + registration=config.config.registration, + group_rating=config.config.groups, exam=config.config.exam, groups=groups, glist=glist, @@ -82,8 +86,8 @@ def dashboard(teacher: Teacher): @blueprint.route("/teacher/group/select", methods=["GET"]) -@teacher_jwt_required(db.teachers) -def select_group(teacher: Teacher): +@teacher_jwt_required(db.students) +def select_group(teacher: Student): group = request.args.get('group') if config.config.exam: return redirect(f'/teacher/group/{group}/exam') @@ -91,16 +95,23 @@ def select_group(teacher: Teacher): @blueprint.route("/teacher/group//exam", methods=["GET"]) -@teacher_jwt_required(db.teachers) -def exam(teacher: Teacher, group_id: int): +@teacher_jwt_required(db.students) +def exam(teacher: Student, group_id: int): group = db.groups.get_by_id(group_id) seed = db.seeds.get_final_seed(group_id) - return render_template("teacher/exam.jinja", group=group, seed=seed) + return render_template( + "teacher/exam.jinja", + registration=config.config.registration, + group_rating=config.config.groups, + group=group, + seed=seed, + student=teacher + ) @blueprint.route("/teacher/group//exam/toggle", methods=["GET"]) -@teacher_jwt_required(db.teachers) -def exam_toggle(teacher: Teacher, group_id: int): +@teacher_jwt_required(db.students) +def exam_toggle(teacher: Student, group_id: int): seed = db.seeds.get_final_seed(group_id) if seed is None and config.config.final_tasks: db.seeds.begin_final_test(group_id) @@ -112,8 +123,8 @@ def exam_toggle(teacher: Teacher, group_id: int): @blueprint.route("/teacher/exam/start", methods=["GET"]) -@teacher_jwt_required(db.teachers) -def exam_startall(teacher: Teacher): +@teacher_jwt_required(db.students) +def exam_startall(teacher: Student): groups = db.groups.get_all() for group in groups: seed = db.seeds.get_final_seed(group.id) @@ -125,8 +136,8 @@ def exam_startall(teacher: Teacher): @blueprint.route("/teacher/exam/end", methods=["GET"]) -@teacher_jwt_required(db.teachers) -def exam_endall(teacher: Teacher): +@teacher_jwt_required(db.students) +def exam_endall(teacher: Student): groups = db.groups.get_all() for group in groups: db.seeds.end_final_test(group.id) @@ -134,8 +145,8 @@ def exam_endall(teacher: Teacher): @blueprint.route("/teacher/exam/delete", methods=["GET"]) -@teacher_jwt_required(db.teachers) -def exam_deleteall(teacher: Teacher): +@teacher_jwt_required(db.students) +def exam_deleteall(teacher: Student): if not config.config.final_tasks or not config.config.clearable_database: return redirect('/teacher') groups = db.groups.get_all() @@ -146,8 +157,8 @@ def exam_deleteall(teacher: Teacher): @blueprint.route("/teacher/group//exam/delete", methods=["GET"]) -@teacher_jwt_required(db.teachers) -def exam_delete(teacher: Teacher, group_id: int): +@teacher_jwt_required(db.students) +def exam_delete(teacher: Student, group_id: int): if not config.config.final_tasks or not config.config.clearable_database: return redirect(f'/teacher/group/{group_id}/exam') db.statuses.delete_group_task_statuses(group_id) @@ -156,8 +167,8 @@ def exam_delete(teacher: Teacher, group_id: int): @blueprint.route("/teacher/group//exam/csv", methods=["GET"]) -@teacher_jwt_required(db.teachers) -def exam_csv(teacher: Teacher, group_id: int): +@teacher_jwt_required(db.students) +def exam_csv(teacher: Student, group_id: int): delimiter = request.args.get('delimiter') value = exports.export_exam_results(group_id, delimiter) output = make_response(value) @@ -167,8 +178,8 @@ def exam_csv(teacher: Teacher, group_id: int): @blueprint.route("/teacher/messages", methods=["GET"]) -@teacher_jwt_required(db.teachers) -def messages(teacher: Teacher): +@teacher_jwt_required(db.students) +def messages(teacher: Student): separator = request.args.get('separator') count = request.args.get('count') value = exports.export_messages(count, separator) @@ -179,19 +190,26 @@ def messages(teacher: Teacher): @blueprint.route("/teacher/group/", methods=["GET"]) -@teacher_jwt_required(db.teachers) -def queue(teacher: Teacher, group_id: int): +@teacher_jwt_required(db.students) +def queue(teacher: Student, group_id: int): group = db.groups.get_by_id(group_id) message = db.messages.get_next_pending_message() matches = message is None or group.id == message.group if matches and config.config.no_background_worker: - return render_template("teacher/queue.jinja", group=group, message=message) + return render_template( + "teacher/queue.jinja", + registration=config.config.registration, + group_rating=config.config.groups, + group=group, + message=message, + student=teacher + ) return redirect(f'/teacher') @blueprint.route("/teacher/group//queue//accept", methods=["GET"]) -@teacher_jwt_required(db.teachers) -def accept(teacher: Teacher, group_id: int, message_id: int): +@teacher_jwt_required(db.students) +def accept(teacher: Student, group_id: int, message_id: int): group = db.groups.get_by_id(group_id) message = db.messages.get_by_id(message_id) if group.id == message.group and config.config.no_background_worker: @@ -200,8 +218,8 @@ def accept(teacher: Teacher, group_id: int, message_id: int): @blueprint.route("/teacher/group//queue//reject", methods=["GET"]) -@teacher_jwt_required(db.teachers) -def reject(teacher: Teacher, group_id: int, message_id: int): +@teacher_jwt_required(db.students) +def reject(teacher: Student, group_id: int, message_id: int): group = db.groups.get_by_id(group_id) message = db.messages.get_by_id(message_id) if group.id == message.group and config.config.no_background_worker: @@ -210,31 +228,6 @@ def reject(teacher: Teacher, group_id: int, message_id: int): return redirect(f"/teacher/group/{group_id}") -@blueprint.route("/teacher/login", methods=['GET', 'POST']) -def login(): - if verify_jwt_in_request(True): - response = redirect('/teacher/login') - unset_jwt_cookies(response) - return response - form = TeacherLoginForm() - if not form.validate_on_submit(): - return render_template("teacher/login.jinja", form=form) - teacher = teachers.check_password(form.login.data, form.password.data) - if teacher is None: - return render_template("teacher/login.jinja", form=form) - access = create_access_token(identity=teacher.id, additional_claims={"teacher": True}) - response = redirect("/teacher") - set_access_cookies(response, access) - return response - - -@blueprint.route("/teacher/logout", methods=['GET']) -def logout(): - response = redirect("/teacher/login") - unset_jwt_cookies(response) - return response - - @blueprint.errorhandler(Exception) def handle_view_errors(e): print(get_exception_info()) @@ -244,7 +237,7 @@ def handle_view_errors(e): @blueprint.errorhandler(JWTExtendedException) @blueprint.errorhandler(PyJWTError) def handle_authorization_errors(e): - response = redirect('/teacher/login') + response = redirect('/login') unset_jwt_cookies(response) return response