registration implemented

This commit is contained in:
Egor Matveev
2021-08-29 21:43:34 +03:00
parent f72801d6f5
commit 1307c16ec1
125 changed files with 2158 additions and 4631 deletions

90
templates/account.html Normal file
View File

@@ -0,0 +1,90 @@
{% extends 'base_main.html' %}
{% block title %}Аккаунт{% endblock %}
{% block main %}
<h2 style="margin-bottom: 40px;">Информация об аккаунте</h2>
<div class="row">
<div class="col-3">
<div style="height: 100%; width: 100%;">
<img src="{{ account.userinfo.profile_pic_url }}" height="100%" width="100%" alt="Фото профиля">
</div>
{% if owner %}
<label for="file-upload" class="btn btn-light" style="margin-top: -100px; margin-left: 10%; width: 80%;">
<i class="fa fa-upload"></i> Загрузить фото
</label>
<input type="file" form="photoform" style="display: none;" accept="image/png, image/jpg" class="btn form-control-file" id="file-upload" value="Выбрать файл" name="file" onchange="document.getElementById('photoform').submit();">
<form method="POST" enctype="multipart/form-data" id="photoform">
<input type="hidden" name="action" value="upload_photo">
{% csrf_token %}
</form>
{% endif %}
</div>
<div class="col-9">
<h3>
{{ account.userinfo.surname }} {{ account.userinfo.name }} {{ account.userinfo.middle_name }}
<span style="margin-left: 15px;" class="badge badge-{% if account.userinfo.activity_status == online_status %}success{% else %}secondary{% endif %}">{{ account.userinfo.activity_status }}</span>
</h3>
<table>
<tr>
<td>
<h2><i class="fa fa-user"></i></h2>
</td>
<td><div style="width: 20px;"></div></td>
<td>
<p style="padding-top: 8px; font-size: 24px;">{{ account.username }}</p>
</td>
</tr>
<tr>
<td>
<h2><i class="fa fa-at"></i></h2>
</td>
<td><div style="width: 20px;"></div></td>
<td>
<p style="padding-top: 8px; font-size: 24px;">{{ account.email }}</p>
</td>
</tr>
<tr>
<td>
<h2><i class="fa fa-star"></i></h2>
</td>
<td><div style="width: 20px;"></div></td>
<td>
<p style="padding-top: 8px; font-size: 24px;">{{ account.userinfo.rating }}</p>
</td>
</tr>
<tr>
<td>
<h2><i class="fa fa-arrow-up"></i></h2>
</td>
<td><div style="width: 20px;"></div></td>
<td>
<p style="padding-top: 8px; font-size: 24px;">{{ account.userinfo.place }}</p>
</td>
</tr>
<tr>
<td>
<h2><i class="fa fa-calendar"></i></h2>
</td>
<td><div style="width: 20px;"></div></td>
<td>
<p style="padding-top: 8px; font-size: 24px;">{{ account.date_joined.date }}</p>
</td>
</tr>
</table>
</div>
</div>
<hr><hr>
{% if owner %}
<p style="color: red;">{{ error_message }}</p>
<form method="POST">
{% csrf_token %}
<input type="hidden" name="action" value="change_password">
<h2 style="margin-bottom: 40px; margin-top: 40px;">Смена пароля</h2>
<input type="password" placeholder="Текущий пароль" name="password" style="margin-bottom: 20px; width: 300px;"><br>
<input type="password" placeholder="Новый пароль" name="new_password" style="margin-bottom: 20px; width: 300px;"><br>
<input type="password" placeholder="Повторить пароль" name="repeat" style="margin-bottom: 20px; width: 300px;"><br>
<button type="submit" class="btn btn-light">Сменить пароль</button>
</form>
{% endif %}
{% endblock %}

View File

@@ -1,90 +0,0 @@
{% extends 'base.html' %}
{% block title %}Админка{% endblock %}
{% block styles %}
.form {
margin-bottom: 15px;
}
{% endblock %}
{% block scripts %}
function change() {
let surname = document.getElementById('surname').value;
let name = document.getElementById('name').value;
let middle_name = document.getElementById('middle_name').value;
let group = document.getElementById('group').value;
let email = document.getElementById('email').value;
let invite = document.getElementById('inviteButton');
console.log(surname + ' ' + name + ' ' + middle_name + ' ' + group + ' ' + email);
let dis = surname == '' || name == '' || middle_name == '' || group == '' || email == '' || email.indexOf('@') == -1 || email.indexOf('.') == -1 || email.indexOf('.') < email.indexOf('@');
console.log(dis);
invite.disabled = dis;
}
{% endblock %}
{% block content %}
<h2>Доступные курсы</h2>
{% for key, value in blocks.items %}
<h5>{{ key.name }}</h5>
{% for block in value %}
<a href="/admin/block?id={{ block.id }}">{{ block.name }}</a><br>
{% endfor %}
{% if is_teacher %}
<button type="button" class="btn btn-dark" data-toggle="modal" data-target="#example_{{ key.id }}" style="margin-top: 20px;">
<i class="fa fa-plus-circle"></i> Новый блок
</button>
<!-- Modal -->
<div class="modal fade" id="example_{{ key.id }}" tabindex="-1" role="dialog" aria-labelledby="exampleModalLongTitle" aria-hidden="true">
<div class="modal-dialog" role="document">
<form method="POST">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Новый блок в курсе {{ key.name }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-12">
{% csrf_token %}
<input type="text" name="name" placeholder="Имя блока">
<input type="hidden" name="course_id" value="{{ key.id }}">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-times-circle"></i> Закрыть</button>
<button type="submit" class="btn btn-success"><i class="fa fa-plus-circle"></i> Создать</button>
</div>
</div>
</form>
</div>
</div>
<button class="btn btn-dark" onclick="window.location.href = '/admin/users_settings?course_id={{ key.id }}'" style="margin-top: 20px;"><i class="fa fa-users"></i> Участники курса</button>
{% endif %}
{% endfor %}
{% if is_superuser %}
<h3 style="margin-top: 30px;">Пригласить пользователя</h3>
<form method="POST">
{% csrf_token %}
<input name="surname" placeholder="Фамилия" class="form" id="surname" onchange="change();"><br>
<input name="name" placeholder="Имя" class="form" id="name" onchange="change();"><br>
<input name="middle_name" placeholder="Отчество" class="form" id="middle_name" onchange="change();"><br>
<input name="group" placeholder="Группа" class="form" id="group" onchange="change();"><br>
<input name="email" placeholder="Почта" class="form" id="email" onchange="change();"><br>
<button type="submit" id='inviteButton' name="invite" value="Пригласить" class="btn btn-dark" disabled>Пригласить</button>
</form>
<div>
<center>
<button target="_blank" rel="noopener noreferrer" type="submit" class="btn btn-dark" onclick="window.location.href = '/admin/'" value="Django admin"><i class="fa fa-shield"></i> Django admin</button>
</center>
</div>
{% endif %}
<center>
<button class="btn btn-dark" style="margin-top: 20px;" onclick="window.location.href='/admin/docs'"><i class="fa fa-file"></i> Методичка</button>
</center>
{% endblock %}

View File

@@ -26,37 +26,69 @@
</script>
<script type="text/javascript" src={% static "js/scripts.js" %}></script>
<style type="text/css">
.center {
height: 400px;
width: 400px;
position: fixed;
top: 50%;
left: 50%;
margin-top: -200px;
margin-left: -200px;
}
h1 {
font-size: 500%;
}
.form {
border: none;
border-bottom: 2px solid;
outline: none;
text-align: center;
width: 300px;
margin-top: 20px;
}
.sub {
margin-top: 20px;
}
.main_div {
margin-left: 10%;
margin-right: 10%;
margin-bottom: 20px;
}
.header {
margin-top: 5px;
margin-bottom: 15px;
display: flex;
}
.header-button {
width: 170px;
}
.button-right {
display: flex;
}
.task-settings-input {
width: 50%;
}
.task-settings-textarea {
height: 300px;
resize: none;
}
@media screen and (max-width: 700px){
.header-button {
width:50px;
}
}
{% block styles %}{% endblock %}
</style>
<script type="text/javascript">
{% block scripts %}{% endblock %}
</script>
</head>
<body onload="{% block onload %}{% endblock %}">
<div class="main_div">
<header class="mt-2 mb-2" role="banner">
<div class="row no-gutters top-buffer">
<div class="col" style="min-width: 100px;">
<button type="button" class="btn {% if current_page == 'main' %}btn-dark{% else %}btn-light{% endif %} btn-block top-button" onclick="main()"><i class="fa fa-random"></i> Sprint</button>
</div>
{% if is_admin %}
<div class="col" style="min-width: 100px;">
<button type="button" class="btn {% if current_page == 'admin' %}btn-dark{% else %}btn-light{% endif %} btn-block top-button" onclick="admin()"><i class="fa fa-user"></i> Админка</button>
</div>
{% endif %}
<div class="col" style="min-width: 100px;">
<button type="button" class="btn {% if current_page == 'settings' %}btn-dark{% else %}btn-light{% endif %} btn-block top-button" onclick="settings()"><i class="fa fa-cog"></i> Настройки</button>
</div>
<div class="col-{% if is_admin %}8{% else %}9{% endif %}">
</div>
<div class="col" style="min-width: 100px;">
<button type="button" style="max-width: 200px;" class="btn btn-light btn-block top-button" onclick="logout()"><i class="fa fa-sign-out"></i> Выход</button>
</div>
</div>
</header>
{% block content %}{% endblock %}
{% block body %}
{% endblock %}
</div>
</body>
</html>

35
templates/base_main.html Normal file
View File

@@ -0,0 +1,35 @@
{% extends 'base.html' %}
{% block body %}
<div class="header">
<button
class="btn btn-light header-button"
onclick="window.location.href='/'">
<i class="fa fa-random"></i> Главная
</button>
<button class="btn btn-light header-button"
onclick="window.location.href='/tasks'">
<i class="fa fa-tasks"></i> Задачи
</button>
<button class="btn btn-light header-button"
onclick="window.location.href='/sets'">
<i class="fa fa-th-large"></i> Сеты
</button>
<button class="btn btn-light header-button"
onclick="window.location.href='/rating'">
<i class="fa fa-arrow-up"></i> Рейтинг
</button>
<div class="button-right" style="margin-top: -35px;">
<button class="btn btn-light header-button"
onclick="window.location.href='/account'">
<i class="fa fa-user"></i> Аккаунт
</button>
<button class="btn btn-light header-button"
onclick="window.location.href='/exit'">
<i class="fa fa-sign-out"></i> Выход
</button>
</div>
</div>
{% block main %}
{% endblock %}
{% endblock %}

View File

@@ -1,39 +0,0 @@
{% extends 'base.html' %}
{% load filters %}
{% block title %}{{ Block.name }}{% endblock %}
{% block content %}
<h3>{{ Block.name }} {% if can_edit %}<a style="color: black;" href="/admin/block?id={{ Block.id }}"><i class="fa fa-pencil"></i></a> {% endif %}</h3>
<h5>Таски</h5>
<table>
{% for task in Block.tasks %}
<tr>
<td>
<a href="/task?id={{ task.id }}">{{ task.name }}</a>
</td>
<td>
{% with mark=task|mark_for_task:user %}
{% if mark|marked %}
<div style="margin-left: 20px; border: 1px solid black; background: {{ mark|mark_color }}; width: 25px; text-align: center;">
{{ mark }}
</div>
{% endif %}
{% endwith %}
</td>
</tr>
{% endfor %}
</table>
{% if Block.show_rating %}
<a href="/rating?block_id={{ Block.id }}" class="btn btn-dark" style="margin-top: 15px;"><i class="fa fa-star"></i> Рейтинг</a>
{% endif %}
<a href="/messages?block_id={{ Block.id }}" class="btn btn-dark" style="margin-top: 15px;"><i class="fa fa-comments"></i> Сообщения</a>
<hr>
{% if Block.opened %}
Открыто для просмотра
{% else %}
Закрыто для просмотра
{% endif %}
<br>Доступно с <b>{{ Block.time_start }}</b> до <b>{{ Block.time_end }}</b>
{% endblock %}

View File

@@ -1,126 +0,0 @@
{% extends 'base.html' %}
{% load filters %}
{% block title %}{{ Block.name }}|настройки{% endblock %}
{% block styles %}
input[type="file"] {
display: none;
}
{% endblock %}
{% block scripts %}
function uploaded() {
document.getElementById('is_uploaded').style.display = 'block';
document.getElementById('is_uploaded').nodeValue = document.getElementById('file-upload').nodeValue;
}
{% endblock %}
{% block content %}
<h3>{{ Block.name }} <a style="color: black;" href="/block?id={{ Block.id }}"><i class="fa fa-eye"></i></a></h3>
<h5>Таски</h5>
{% for task in Block.tasks %}
<a href="/admin/task?id={{ task.id }}">{{ task.name }}</a><br>
{% endfor %}
{% if is_superuser %}
<button type="button" class="btn btn-dark" data-toggle="modal" data-target="#example" style="margin-top: 20px;">
<i class="fa fa-plus-circle"></i> Новый таск
</button>
<!-- Modal -->
<div class="modal fade" id="example" tabindex="-1" role="dialog" aria-labelledby="exampleModalLongTitle" aria-hidden="true">
<div class="modal-dialog" role="document">
<form method="POST">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Новый таск в блоке {{ Block.name }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-12">
{% csrf_token %}
<input type="text" name="name" placeholder="Имя таска">
<input type="hidden" name="block_id" value="{{ Block.id }}">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-times-circle"></i> Закрыть</button>
<button type="submit" class="btn btn-success"><i class="fa fa-plus-circle"></i> Создать</button>
</div>
</div>
</form>
</div>
</div>
<hr>
<h5>Импортировать задачу из Я.Контест</h5>
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<label for="file-upload" class="btn btn-dark" style="margin-top: 20px;">
<i class="fa fa-upload"></i> Загрузить архив
</label>
<span id="is_uploaded" style="display: none;">Архив загружен</span>
<input type="file" class="btn form-control-file" id="file-upload" value="Выбрать файл" name="file" onchange="uploaded()">
<br><button type="submit" value="Импортировать" class="btn btn-outline-dark"><i class="fa fa-play-circle"></i> Импортировать</button>
</form>
{% endif %}
<hr>
{% if is_superuser %}
<h3>Ограничения по времени</h3>
<form method="POST">
{% csrf_token %}
<table>
<tr>
<td>
<input type="datetime-local" name="time_start" value="{{ Block.time_start_chrome }}">
</td>
<td>
<input type="datetime-local" name="time_end" value="{{ Block.time_end_chrome }}">
</td>
</tr>
<tr>
<td>
Открыто для просмотра<input type="checkbox" name="opened" style="margin-left:15px;" {{ Block.is_opened }}>
</td>
</tr>
<tr>
<td>
Показывать рейтинг участникам<input type="checkbox" name="rating" style="margin-left: 15px;" {% if Block.show_rating %}checked{% endif %}>
</td>
</tr>
<tr>
<td>
Приоритет <select name="priority">
{% for i in 10|num_range %}
<option {% if i == Block.priority %}selected{% endif %}>{{ i }}</option>
{% endfor %}
</select>
</td>
</tr>
</table>
<button class="btn btn-dark" value="Установить" type="submit" style="margin-top: 20px;"><i class="fa fa-save"></i> Установить</button>
</form>
<hr>
{% endif %}
<div>
<a class="btn btn-dark" href="/admin/rating?block_id={{ Block.id }}"><i class="fa fa-star"></i> Рейтинг</a>
<button type="button" class="btn btn-dark" onclick="window.location.href = '/admin/solutions?block_id=' + {{ Block.id }}" value="Посмотреть решения"><i class="fa fa-list-ul"></i> Посмотреть решения</button>
<a class="btn btn-dark" href="/admin/queue?block_id={{ Block.id }}"><i class="fa fa-align-left"></i> Очередь тестирования</a>
<a class="btn btn-dark" href="/admin/cheating?block_id={{ Block.id }}"><i class="fa fa-bomb"></i> Проверка на списывание</a>
{% if is_superuser %}
<form method="POST" onsubmit="return confirm('Сейчас ты пытаешься сделать то, что может привести к серьезным последствиям. Если ты удалишь этот блок, то вместе с ним удалятся все таски, условия, тесты, дополнительные файлы и решения, сдаваемые в этот блок. Все данные будут безвозвратно утеряны. Оно нам надо?');">
{% csrf_token %}
<input type="hidden" name="block_delete" value="{{ Block.id }}">
<button type="submit" value="Удалить блок" class="btn btn-dark" style="margin-top: 10px;"><i class="fa fa-trash"></i> Удалить блок</button>
</form>
{% endif %}
</div>
<hr>
{% endblock %}

View File

@@ -1,133 +0,0 @@
{% extends 'base.html' %}
{% load filters %}
{% block title %}{{ Block.name }} | списывание{% endblock %}
{% block links %}
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.4.0/build/styles/default.min.css">
<script src="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.4.0/build/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
{% endblock %}
{% block scripts %}
function check_list(entity_type) {
var cbox = document.getElementById('check_' + entity_type + '_all');
var boxes = document.getElementsByClassName('check_' + entity_type);
for (var i = 0; i < boxes.length; i++) {
boxes[i].checked = cbox.checked;
}
}
function prepare_for_submit() {
var conf = confirm('Точно запускаем проверку? Новую проверку можно будет запустить только после завершения данной');
if (conf) {
document.getElementById('main_form').submit();
}
}
{% endblock %}
{% block content %}
<h3>Списывание в <a href="/admin/block?id={{ Block.id }}">{{ Block.name }}</a></h3>
<hr>
<form method="POST" id="main_form">
{% csrf_token %}
<h5>Проверить таски</h5>
<b><input type="checkbox" id="check_task_all" onchange="check_list('task')" checked> Все</b><br>
{% for task in Block.tasks %}
<input type="checkbox" class="check_task" name="check_task_{{ task.id }}" checked> {{ task.name }}<br>
{% endfor %}
<hr>
<h5>Проверить пользователей</h5>
<b><input type="checkbox" id="check_user_all" onchange="check_list('user')" checked> Все</b><br>
{% for sub in Block.course.students %}
<input type="checkbox" class="check_user" name="check_user_{{ sub.user.id }}" checked> {{ sub.user.userinfo }}<br>
{% endfor %}
<hr>
<h5>Дополнительно</h5>
<table>
<tr>
<td>
<input type="checkbox" name="best_result">
</td>
<td>
Проверять только решения с лучшим результатом
</td>
</tr>
<tr>
<td>
<input type="checkbox" name="last_solution">
</td>
<td>
Проверять только последнее решение
</td>
</tr>
<tr>
<td>
<input type="checkbox" name="all_tests">
</td>
<td>
Проверять только прошедшие все тесты
</td>
</tr>
<tr>
<td>
<select name="cheating_percent">
{% for i in 100|num_range %}
<option>{{ i }}</option>
{% endfor %}
</select>
</td>
<td>
Какой процент схожести считать списыванием
</td>
</tr>
</table>
<hr>
<button type="button" {% if Block.cheating_checking %}class="btn btn-secondary"{% else %}class="btn btn-dark" onclick="prepare_for_submit()"{% endif %}><i class="fa fa-rocket"></i> Запустить проверку</button>
</form>
<hr>
<center><h1>{{ Block.cheating_status }}</h1></center>
{% if Block.cheating_checked %}
<h1>Результаты проверки</h1>
{% for data in Block.cheating_results %}
{% with user=data|user_by_id cheating_data=Block.cheating_results|dict_key:data %}
<br><h3>{{ user.userinfo }} [{{ cheating_data|length }}]</h3>
<button class="btn btn-link" onclick="var content = document.getElementById('div_{{ user.id }}'); content.hidden = !content.hidden;">Отчет</button>
<div id="div_{{ user.id }}" hidden>
{% for cheat in cheating_data %}
{% with solution=cheat.solution|solution_by_id %}
<div class="row">
<div class="col-5">
<h5><a href="/solution?id={{ solution.id }}">{{ solution.id }}</a> | {{ solution.user.userinfo }} | {{ cheat.file }}</h5>
<pre>
<code class="c# border border-dark">
{{ solution|solution_file_text:cheat.file }}
</code>
</pre>
</div>
<div class="col-2">
<center>
<a href="/task?id={{ solution.task.id }}">{{ solution.task.name }}</a><br>
<b>{{ cheat.similarity }}%</b><br>
<i class="fa fa-arrow-{% if cheat.source %}right{% else %}left{% endif %}"></i>
</center>
</div>
<div class="col-5">
{% with solution2=cheat.similar|solution_by_id %}
<h5><a href="/solution?id={{ solution2.id }}">{{ solution2.id }}</a> | {{ solution2.user.userinfo }} | {{ cheat.file }}</h5>
<pre>
<code class="c# border border-dark">
{{ solution2|solution_file_text:cheat.file }}
</code>
</pre>
{% endwith %}
</div>
</div>
{% endwith %}
{% endfor %}
</div>
{% endwith %}
{% endfor %}
{% endif %}
{% endblock %}

View File

@@ -1,235 +0,0 @@
{% extends 'base.html' %}
{% load static %}
{% block title %}Методичка{% endblock %}
{% block styles %}
.screenshot {
width: 100%;
}
.screenshot_div {
margin-top: 20px;
width: 80%;
margin-bottom: 20px;
}
.code {
padding: 15px;
margin-top: 15px;
margin-bottom: 15px;
}
{% endblock %}
{% block content %}
<h1>Методичка</h1>
<hr>
<h2><b>О системе</b></h2>
<h3>Структура сервиса</h3>
В сервисе существует два режима работы:
<ul>
<li>Режим студента</li>
<li>Режим администратора</li>
</ul>
И одна компанента:
<ul>
<li>Darwin</li>
</ul>
<hr>
<h3>Режим студента</h3>
Режим студента показывает курсы, на которые подписан пользователь, а также блоки, содержащиеся в них.<br>
Напротив каждого блока стоит (или отсутствует) оценка за данный блок.
<div class="border border-dark screenshot_div">
<img src="{% static 'img/main_page.png' %}" class="screenshot" />
</div>
При нажатии на блок пользователь попадает в настройки выбранного блока.<br>
На странице отображаются таски и (опционально) оценки за них.<br>
Под списком тасков отображается информация о возможности отправки решений в блок, а также временной интервал активности блока.
<div class="border border-dark screenshot_div">
<img src="{% static 'img/block_page.png' %}" class="screenshot" />
</div>
Страница таска представляет из себя подробное описание задания, предлагаемого к решению.<br>
Описание таска содержит в себе следующие атрибуты:
<ul>
<li>Легена</li>
<li>Формат входных данных</li>
<li>Формат выходных данных</li>
<li>Спецификации</li>
</ul>
Далее находится форма для отправки решения (.zip архив) и список отправленных решений.<br>
Решение содержит в себе следующие атрибуты:
<ul>
<li>id</li>
<li>Дата и время отправки</li>
<li>Результат тестирования</li>
<li>Оценка, выставленная преподавателем или ассистентом</li>
<li>Комментарий к решению</li>
</ul>
Sprint поддерживает следующие варианты результатов тестирования:
<ul>
<li>M/N - решение прошло M тестов из N</li>
<li>Time limit - превышен предел времени, отведенного на тестирование</li>
<li>Compilation error - не удалось скомпилировать решение</li>
<li>TEST ERROR - ошибка тестирования (может быть связана с некорректыми тестами)</li>
<li>TESTING - решение находится в процессе тестирования</li>
<li>IN QUEUE - решение находится в очереди на тестирование</li>
</ul>
<div class="border border-dark screenshot_div">
<img src="{% static 'img/task_page.png' %}" class="screenshot" />
</div>
При нажатии на результат тестирование можно получить информацию о том, какие именно тесты были пройдены, а какие - нет.
<div class="border border-dark screenshot_div">
<img src="{% static 'img/test_datails.png' %}" class="screenshot" />
</div>
При нажатии на id решения пользователь попадает на страницу решения.<br>
Страница с решением содержит ту же информацию, что и на странице таска.<br>
Помимо этого, на данной странице можно выставить оценку за решение и оставить комментарий. Для сохранения результата необходимо нажать на кнопку "Зачесть".<br>
Для выставления оценки 0 или максимальной оценки за таск, необходимо нажать на кнопку "Незачесть" или "Выставить максимальный балл" соответственно.<br>
Комментарий будет сохранен при нажатии на любую из кнопок.<br>
Внизу страницы отображаются файлы решения, содержащие только символы Unicode, иначе говоря, файлы с кодом.
<div class="border border-dark screenshot_div">
<img src="{% static 'img/solution_page.png' %}" class="screenshot" />
</div>
<hr>
<h3>Режим администратора</h3>
<i>Некоторые функции доступны только преподавателям</i><br>
Главная страница режима администратора показывает доступные для администрирования курсы, блоки в них и ссылку на данную методичку.<br>
Добавление нового блока в курс происходит по нажатии кнопки "Новый блок".
<div class="border border-dark screenshot_div">
<img src="{% static 'img/admin_page.png' %}" class="screenshot" />
</div>
При нажатии на кнопку "Участники курса" открывается страница с настройками участников курса.<br>
Для подписки существующих студентов или преподавателей на курс, необходимо ввести в форму "Добавить участников" ФИО студента или email, на который зарегестрирован аккаунт.<br>
Для подписки всех студентов определенной группы, нужно ввести название группы.<br>
Для отписки студента от курса, нужно нажать на кнопку "отписка" рядом с нужным студентом.<br>
Для того, чтобы сделать подписчика курса ассистентом или снятия с него таких прав, необходимо выбрать почту этого студента в форме "Назначить или разжаловать" и нажать на кнопку применить. Статус студента будет отображен в таблице ниже.
<div class="border border-dark screenshot_div">
<img src="{% static 'img/users_settings_page.png' %}" class="screenshot" />
</div>
В Sprint отсутствует регистрация в обычном понимании данного термина, поэтому регистрация студентов происходит при первом добавлении его к некоторому курсу.<br>
Прежде всего необходимо создать JSON файл по определенным правилам, описанным на странице участников курса.
<div class="border border-dark screenshot_div">
<img src="{% static 'img/upload_rules.png' %}" class="screenshot" />
</div>
При нажатии на блок, отображается страница с настройками блока.<br>
Страница настроек блока содержит следующие аттрибуты:
<ul>
<li>Набор тасков</li>
<li>Интервал времени, в течение которого можно отправлять решения</li>
<li>Решения, отправленные в данный блок</li>
</ul>
Ограничения по времени были внедрены для того, чтобы отложить запуск блока. Блок будет доступен студентам только если данный момент времени входит в интервал между временем начала и временем конца (границы включаются), и блок открыт для отправки решений.<br>
После установки нужных значений необходимо нажать на кнопку "Сохранить".<br>
Для создания нового таска после списка тасков есть кнопка "Новый таск".
<div class="border border-dark screenshot_div">
<img src="{% static 'img/admin_block_page.png' %}" class="screenshot" />
</div>
При нажатии на таск из списка, откроется страница с настройками таска.<br>
Поля "Легенда", "Входные данные", "Выходные данные" и "Спецификации" заполняются с помощью html разметки, которая потом будет отображена в режиме студента.<br>
<div class="border border-dark screenshot_div">
<img src="{% static 'img/task_settings_page_1.png' %}" class="screenshot" />
</div>
В настройках таска содержатся еще несколько аттрибутов:
<ul>
<li>Ограничения по времени - количество миллисекунд, которое отводится на тестирование решения (целое число)</li>
<li>Вес задачи - доля значимости таска в блоке (вещественное число, может быть больше единицы, а суммарно таски могут иметь вес отличный от единицы)</li>
<li>Максимальная оценка - максмальная оценка, которую можно выставить за таск (целое число)</li>
<li>Максимум решений - максимальное количество решений, которое можно отправить к таску (целое число, ограничение не действует на ассистентов и преподавателей)</li>
</ul>
В форму загрузки тестов загружается .cs файл с Unit тестами библиотеки Nunit. По нажатии на кнопку "Посмотреть" можно посмотреть тесты и отредактировать их. Для сохранения файла необходимо нажать на кнопку "Сохранить" внизу страницы.<br>
В форму "Дополнительные файлы" можно загрузить файлы, которые будут скорированы в директорию с исполняемыми файлами при тестировании.
<div class="border border-dark screenshot_div">
<img src="{% static 'img/task_settings_page_2.png' %}" class="screenshot" />
</div>
При нажатии на кнопку "Посмотреть решения" на странице настроек блока открывается страница решений, загруженных в текущий блок.<br>
Функциональность таблицы решений внизу страницы схожа с подобной в режиме студента.<br>
Фильтр на данной странице содержит следующие поля:
<ul>
<li>id - id решения</li>
<li>Таск - имя таска</li>
<li>Пользователь - почта студента</li>
<li>Группа - решения от студентов из данной группы</li>
<li>Последнее решение - последнее отправленное решение от каждого студента к каждому таску</li>
<li>Лучший результат - решения с наибольшим количеством пройденных тестов от каждого студента к каждому таску</li>
<li>Только студенты - исключить из фильтра решения от ассистентов и преподавателей</li>
</ul>
При нажатии на кнопку "Перетест" отфильтрованные решения будут перетестированы.
<div class="border border-dark screenshot_div">
<img src="{% static 'img/solutions_page.png' %}" class="screenshot" />
</div>
<hr>
<h3>Darwin</h3>
Одним из ограниений Unit тестирования является невозможность тестирования приватных методов и приватных классов.<br>
Для решения данной проблемы в Sprint содержится компонента Darwin. Загрузить библиотеку можно по данной <a href="{% static '/files/Darwin.dll' %}" download>ссылке</a>.<br>
Darwin позволяет создавать объекты приватных классов, задавать значения приватным полям и свойствам, а также вызывать приватные методы.<br>
Основой библиотеки является класс <b>DObject</b>.<br>
В конструктор передается имя того класса, объект которого необходимо создать, с указанием пространства имен.
<div class="border border-dark code">
<pre>
using Darwin;
using Nunit.Framework;
[TestFixture]
public class Tests
{
[Test]
public void Test1()
{
DObject d = new DObject("Calculator.Calc");
}
}
</pre>
</div>
Для доступа к полям и свойствам класса нужно использовать индексатор.<br>
<div class="border border-dark code">
<pre>
using Darwin;
using Nunit.Framework;
[TestFixture]
public class Tests
{
[Test]
public void Test1()
{
DObject d = new DObject("Calculator.Calc");
d["a"] = 5;
Assert.AreEqual(d["a"], 5);
}
}
</pre>
</div>
Для вызова методов класса используется метод InvokeMethod.<br>
В качетсве параметров передается имя метода и массив параметров.<br>
Тип возвращаемого значения метода InvokeMethod - object, поэтому необходимо проводить каст к нужному типу после вызова.
<div class="border border-dark code">
<pre>
using Darwin;
using Nunit.Framework;
[TestFixture]
public class Tests
{
[Test]
public void Test1()
{
DObject d = new DObject("Calculator.Calc");
d["a"] = 5;
Assert.AreEqual(d["a"], 5);
int val = (int)d.InvokeMethod("GetNumber", new object[] { d["a"] });
Assert.AreEqual(val, d["a"]);
}
}
</pre>
</div>
<hr>
<h2><b>Use cases</b></h2>
<h3>Как собрать таск</h3>
<hr>
<h3>Как написать Unit тест правильно</h3>
<hr>
<h3>Как написать тест на входные и выходные данные</h3>
<hr>
<h3>Что необходимо указать в спецификациях</h3>
<hr>
<h3>Полезные html тэги</h3>
{% endblock %}

View File

@@ -1,67 +1,30 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
{% load static %}
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>
Sprint
</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href={% static "css/styles.css" %}>
<script src="https://use.fontawesome.com/49b98aaeb5.js"></script>
<script type="text/javascript" src={% static "js/scripts.js" %}></script>
<style type="text/css">
.center {
height: 400px;
width: 400px;
{% extends 'base.html' %}
position: fixed;
top: 50%;
left: 50%;
margin-top: -200px;
margin-left: -200px;
}
h1 {
font-size: 500%;
}
.form {
border: none;
border-bottom: 2px solid;
outline: none;
text-align: center;
width: 300px;
margin-top: 20px;
}
.sub {
margin-top: 20px;
}
</style>
</head>
<body>
<div class="center">
<center>
<div>
<h1>
<i class="fa fa-random"></i> Sprint
</h1>
</div>
<div>
<p style="color: red;">{{ error_message }}</p>
<form method="POST">
{% csrf_token %}
<input type="text" class="form" name="email" placeholder="email or username"><br>
<input type="password" class="form" name="password" placeholder="password"><br>
<input type="submit" value="Вход" class="sub btn btn-dark form">
</form>
</div>
<div>
<button onclick="window.location.href='/restore'" class="sub btn btn-dark form">Восстановить пароль</button>
</div>
<div>
<button onclick="window.location.href='/register'" class="sub btn btn-dark form">Регистрация</button>
</div>
</center>
</div>
</body>
</html>
{% block title %}Вход{% endblock %}
{% block body %}
<div class="center">
<center>
<div>
<h1>
<i class="fa fa-random"></i> Sprint
</h1>
</div>
<div>
<p style="color: red;">{{ error_message }}</p>
<form method="POST">
{% csrf_token %}
<input type="text" class="form" name="email" placeholder="email or username"><br>
<input type="password" class="form" name="password" placeholder="password"><br>
<input type="submit" value="Вход" class="sub btn btn-dark form">
</form>
</div>
<div>
<button onclick="window.location.href='/restore'" class="sub btn btn-dark form">Восстановить пароль</button>
</div>
<div>
<button onclick="window.location.href='/register'" class="sub btn btn-dark form">Регистрация</button>
</div>
</center>
</div>
{% endblock %}

View File

@@ -1,30 +1,7 @@
{% extends 'base.html' %}
{% load filters %}
{% extends 'base_main.html' %}
{% block title %}Главная{% endblock %}
{% block content %}
<h2>Доступные курсы</h2>
{% for key, value in blocks.items %}
<h5>{{ key.name }}</h5>
{% for block in value %}
<table>
<tr>
<td>
<a href="/block?id={{ block.id }}">{{ block.name }}</a>
</td>
<td>
{% with mark=block|mark_for_block:user %}
{% if mark|marked %}
<div style="margin-left: 20px; border: 1px solid black; background: {{ mark|mark_color }}; width: 25px; text-align: center;">
{{ mark }}
</div>
{% endif %}
{% endwith %}
</td>
</tr>
</table>
{% endfor %}
{% endfor %}
{% block main %}
<h2>Мои группы</h2>
{% endblock %}

View File

@@ -1,31 +0,0 @@
{% extends 'base.html' %}
{% load filters %}
{% block content %}
<h3 style="margin-bottom: 30px;">Сообщения</h3>
{% for message in Block.messages %}
<div class="row">
<div class="col-2"></div>
<div class="col-8" style="margin-bottom: 50px;">
{% with userinfo=message.sender|userinfo_by_user %}
<div style="background-color: #DDDDDD; padding: 15px;">
<b>
{{ userinfo }} | {{ userinfo.group }} |
<a href="/{% if current_page == 'admin' %}admin/{% endif %}task?id={{ message.task.id }}">{{ message.task.name }}</a>
{% if is_admin %} | <a href="/admin/solutions?block_id={{ Block.id }}&task_name={{ message.task.name }}&user={{ userinfo }}">Решения участника</a>{% endif %}
</b>
</div>
<div class="border border-dark bg-light" style="padding: 30px;">
{{ message.text }}
</div>
<div>
<button class="btn btn-danger" style="right: 0;">Ответить всем</button>
<button class="btn btn-success" style="right: 0;">Ответить</button>
</div>
{% endwith %}
</div>
<div class="col-2"></div>
</div>
{% endfor %}
{% endblock %}

View File

@@ -1,33 +0,0 @@
{% extends 'base.html' %}
{% load filters %}
{% block title %}{{ Block.name }} | очередь{% endblock %}
{% block scripts %}
function doPoll() {
jQuery.get('/queue_table?block_id={{ Block.id }}', function(data) {
document.getElementById('body').innerHTML = data;
setTimeout(function() {doPoll()}, 2000);
})
}
{% endblock %}
{% block onload %}doPoll(){% endblock %}
{% block content %}
<h3><a href="/admin/block?id={{ Block.id }}">{{ Block.name }}</a></h3>
<h4>Очередь тестирования</h4>
<table class="table">
<thead>
<th scope="col">id</th>
<th scope="col">Таск</th>
<th scope="col">Дата и время отправки</th>
<th scope="col">Студент</th>
<th scope="col">Статус</th>
</thead>
<tbody id="body">
</tbody>
</table>
{% endblock %}

View File

@@ -1,19 +0,0 @@
{% for solution in solutions %}
<tr style="background-color: {% if solution.result == 'TESTING' %}#FFE2B7{% else %}{% if solution.result == 'IN QUEUE' %}#EAEAFF{% endif %}{% endif %};">
<td>
<b><a href="/admin/solution?id={{ solution.id }}">{{ solution.id }}</a></b>
</td>
<td>
<a href="/admin/task?id={{ solution.task.id }}">{{ solution.task.name }}</a>
</td>
<td>
{{ solution.time_sent }}
</td>
<td>
{{ solution.userinfo.surname }} {{ solution.userinfo.name }} {{ solution.userinfo.middle_name }}
</td>
<td>
<b>{{ solution.result }}</b>
</td>
</tr>
{% endfor %}

View File

@@ -1,49 +1,34 @@
{% extends 'base.html' %}
{% extends 'base_main.html' %}
{% load filters %}
{% block title %}Рейтинг{% endblock %}
{% block content %}
<h3>Рейтинг (beta)</h3>
<h4><a style="color: black;" href="/{% if current_page == 'admin' %}admin/{% endif %}block?id={{ Block.id }}">{{ Block.name }}</a></h4>
<table border="1px solid black" style="width: 100%;">
<thead>
<tr>
<th scope="col">Студент</th>
{% for task in Block.tasks %}
<th>{% if admin_course %}<a href="/admin/solutions?block_id={{ Block.id }}&task_name={{ task.name }}">{{ task.name }}</a>{% else %}{{ task.name }}{% endif %}</th>
{% endfor %}
<th scope="col" style="background-color: lightblue;">Оценка</th>
</tr>
</thead>
<tbody>
{% for sub in Block.course.students %}
<tr>
<th scope="row">{% if admin_course %}<a href="/admin/solutions?block_id={{ Block.id }}&user={{ sub.user|userinfo_by_user }}">{{ sub.user|userinfo_by_user }}</a>{% else %}{{ sub.user|userinfo_by_user }}{% endif %}</th>
{% for task in Block.tasks %}
{% with status=sub.user|mark_status:task %}
<th style="background-color: {% if status == '-' %}white{% else %}{% if sub.user|fully_marked:task %}lime{% else %}yellow{% endif %}{% endif %};">
{% if current_page == 'admin' and status != '-' %}
<a style="color: black;" href="/admin/solutions?block_id={{ Block.id }}&user={{ sub.user|userinfo_by_user }}&task_name={{ task.name }}">{{ status }}</a>
{% else %}
{{ status }}
{% endif %}
</th>
{% endwith %}
{% endfor %}
<td style="background-color: lightblue;">
{% with mark=Block|mark_for_block:sub.user %}
{% if mark|marked %}
<div style="margin-left: 20px; border: 1px solid black; background: {{ mark|mark_color }}; width: 25px; text-align: center;">
{{ mark }}
</div>
{% endif %}
{% endwith %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<button class="btn btn-dark" style="margin-top: 30px;" onclick="window.location.href='/admin/download_rating?block_id={{ Block.id }}'">Скачать csv</button>
{% block main %}
<h4>Рейтинг</h4>
<table class="table">
<thead>
<tr>
<th scope="col" style="text-align: center; vertical-align: middle; width: 70px;">#</th>
<th scope="col" style="vertical-align: middle;">Пользователь</th>
<th scope="col" style="vertical-align: middle;">Дата регистрации</th>
<th scope="col" style="text-align: center; vertical-align: middle;">Рейтинг</th>
</tr>
</thead>
<tbody>
{% for u in users %}
<tr {% if user == u %}style="background-color: #0000FF1E;"{% endif %}>
<td style="text-align: center; vertical-align: middle; width: 70px;">
{{ u.userinfo.place }}
</td>
<td style="vertical-align: middle;">
<img src="{{ u.userinfo.profile_pic_url }}" width="50px" height="50px" style="border-radius: 50%;">
<a href="/account?username={{ u.username }}">{{ u.username }}</a>
</td>
<td style="vertical-align: middle;">
{{ u.date_joined.date }}
</td>
<td style="text-align: center; vertical-align: middle;">
{{ u.userinfo.rating }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@@ -1,29 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
{% load static %}
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>
Sprint
</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href={% static "css/styles.css" %}>
<script type="text/javascript" src={% static "js/scripts.js" %}></script>
</head>
<body>
<center>
<h1>
<font color="black"><a href="/enter">Sprint</a></font>
</h1>
{{ error }}
<form method="POST">
{% csrf_token %}
<table>
{{ form }}
</table>
<input type="submit" value="Установить пароль" class="btn btn-dark" style="margin-top: 20px;">
</form>
</center>
</body>
</html>

View File

@@ -1,36 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
{% load static %}
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>
Восстановление пароля
</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href={% static "css/styles.css" %}>
<script type="text/javascript" src={% static "js/scripts.js" %}></script>
</head>
<body>
<center>
<h1>
<font color="black"><a href="{% url 'enter' %}">Sprint</a></font>
</h1>
<form method="POST">
{% csrf_token %}
<table>
<tr>
<td>
<font color="black">Почта</font>
</td>
<td>
<input type="email" name="email" class="input_simple">
</td>
</tr>
</table>
<input type="submit" value="Восстановить" class="btn btn-dark" style="margin-top: 20px;">
</form>
Если данный электронный адрес есть в базе, то на него будет отправлена ссылка для восстановления пароля.
</center>
</body>
</html>

47
templates/sets.html Normal file
View File

@@ -0,0 +1,47 @@
{% extends 'base_main.html' %}
{% block main %}
<table>
<tr>
<td>
<h2>Сеты</h2>
</td>
{% if user.userinfo.can_create %}
<td>
<button style="margin-left: 20px;" class="btn btn-success" data-toggle="modal" data-target="#example"><i class="fa fa-plus"></i></button>
<div class="modal fade" id="example" tabindex="-1" role="dialog" aria-labelledby="exampleModalLongTitle" aria-hidden="true">
<div class="modal-dialog" role="document">
<form method="POST">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Создать новый сет</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-12">
{% csrf_token %}
<input type="text" name="name" placeholder="Название сета">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-times-circle"></i> Закрыть</button>
<button type="submit" class="btn btn-success"><i class="fa fa-plus-circle"></i> Создать</button>
</div>
</div>
</form>
</div>
</div>
</td>
{% endif %}
</tr>
</table>
{% for set in user.userinfo.available_sets %}
<a href="/set?set_id={{ set.id }}">{{ set.name }}</a> {% if set.creator == user %}<a href="/admin/set?set_id={{ set.id }}"><i class="fa fa-pencil"></i> </a>{% endif %}<br>
{% endfor %}
{% endblock %}

View File

@@ -1,18 +0,0 @@
{% extends 'base.html' %}
{% block title %}Настройки{% endblock %}
{% block content %}
<h2>
Сменить пароль
</h2>
<font color="red">{{ error }}</font>
<form method="POST">
{% csrf_token %}
<table>
{{ form }}
</table>
<button type="submit" class="btn btn-dark" value="Сменить" style="margin-top: 20px;"><i class="fa fa-check"></i> Сменить</button>
</form>
<hr>
{% endblock %}

View File

@@ -1,271 +0,0 @@
{% extends 'base.html' %}
{% block title %}{{ solution.task.name }}|решение{% endblock %}
{% block links %}
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.4.0/build/styles/default.min.css">
<script src="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.4.0/build/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
{% endblock %}
{% load filters %}
{% block scripts %}
{% if can_edit %}
function findGetParameter(parameterName) {
var result = null,
tmp = [];
location.search
.substr(1)
.split("&")
.forEach(function (item) {
tmp = item.split("=");
if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]);
});
return result;
}
function next() {
const solutions_request = findGetParameter('solutions');
const solutions = solutions_request.split(' ');
const current = findGetParameter('id');
const current_index = solutions.findIndex((element) => element == current);
if (current_index != solutions.length - 1) {
var next_element = document.getElementById('next');
next_element.setAttribute('href', '/admin/solution?id=' + solutions[current_index + 1] + '&solutions=' + solutions_request);
next_element.innerHTML = '->';
}
}
function previous() {
const solutions_request = findGetParameter('solutions');
const solutions = solutions_request.split(' ');
const current = findGetParameter('id');
const current_index = solutions.findIndex((element) => element == current);
if (current_index != 0) {
var next_element = document.getElementById('previous');
next_element.setAttribute('href', '/admin/solution?id=' + solutions[current_index - 1] + '&solutions=' + solutions_request);
next_element.innerHTML = '<-';
}
}
function fillContent() {
next();
previous();
}
{% if can_edit %}
function showHideTests() {
var text = document.getElementById('tests_text');
var button = document.getElementById('tests_button');
text.hidden = !text.hidden;
if (text.hidden) {
button.textContent = 'Показать тесты';
} else {
button.textContent = 'Скрыть тесты';
}
}
function showHideLog() {
var text = document.getElementById('log_text');
var button = document.getElementById('log_button');
text.hidden = !text.hidden;
if (text.hidden) {
button.textContent = 'Показать лог';
} else {
button.textContent = 'Скрыть лог';
}
}
function retest() {
let del = confirm("Подтвердите перетест");
if (del) {
const sols = findGetParameter('solutions');
const link = '/admin/retest?block_id={{ solution.task.block.id }}&solution_id={{ solution.id }}&next={% autoescape off %}{{ path }}?id={{ solution.id }}{% if current_page == 'admin' %}%26solutions={% endif %}{% endautoescape %}'{% if current_page == 'admin' %} + sols.replaceAll(' ', '%20'){% endif %};
window.location.href = link;
}
}
{% endif %}
{% endif %}
{% endblock %}
{% block onload %}{% if can_edit %}fillContent(){% endif %}{% endblock %}
{% block content %}
<div class="row">
<div class="col-6">
<h5>
<form method="POST">
<table class="table">
<tr>
<td>
Блок
</td>
<td>
<a href="{% if current_page == 'admin' %}/admin{% endif %}/block?id={{ solution.task.block.id }}">{{ solution.task.block.name }}</a>
{% if current_page == 'admin' %}
| <a style="margin-top: 15px;" href="/admin/solutions?block_id={{ solution.task.block.id }}">К посылкам</a> | <a style="margin-top: 15px;" href="/admin/rating?block_id={{ solution.task.block.id }}">К рейтингу</a>
{% endif %}
</td>
</tr>
<tr>
<td>
Таск
</td>
<td>
<a href="{% if current_page == 'admin' %}/admin{% endif %}/task?id={{ solution.task.id }}">{{ solution.task.name }}</a>
</td>
</tr>
<tr>
<td>
Студент
</td>
<td>
{{ solution.userinfo.surname }} {{ solution.userinfo.name }} {{ solution.userinfo.middle_name }}
</td>
</tr>
<tr>
<td>
id решения
</td>
<td>
<div style="text-align: center;"></div>
{% if can_edit %}
<a id="previous"></a>
{% endif %}
{{ solution.id }}
{% if can_edit %}
<a id="next"></a>
{% endif %}
</div>
</td>
</tr>
<tr>
<td>
Результат
</td>
<td>
{% if can_edit or solution.task.show_details %}
<!-- Button trigger modal -->
<button type="button" class="btn btn-link" data-toggle="modal" data-target="#resultModalLong{{ solution.id }}">
{{ solution.result }}
</button>
<!-- Modal -->
<div class="modal fade" id="resultModalLong{{ solution.id }}" tabindex="-1" role="dialog" aria-labelledby="resultModalLongTitle{{ solution.id }}" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="resultModalLongTitle{{ solution.id }}">Подробная информация о тестировании {{ solution.id }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-12">
{% autoescape off %}
{{ solution.details }}
{% endautoescape %}
{% if can_edit %}
<hr>
<pre id="tests_text" hidden>
<h4>Тесты</h4><br>
{{ solution.task.tests_text }}
</pre>
<hr>
<pre id="log_text" hidden>
<h4>Лог</h4><br>
{{ solution.log_text }}
</pre>
{% endif %}
</div>
</div>
</div>
</div>
<div class="modal-footer">
{% if can_edit %}
<button type="button" id="log_button" class="btn btn-warning" onclick="showHideLog()">Показать лог</button>
<button type="button" id="tests_button" class="btn btn-primary" onclick="showHideTests()">Показать тесты</button>
{% endif %}
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
{% else %}
{% if solution.task.show_result %}
{{ solution.result }}
{% else %}
Accepted
{% endif %}
{% endif %}
</td>
</tr>
<tr>
<td>
Оценка
</td>
<td>
{% if can_edit %}
{% csrf_token %}
<label>
<select name="mark">
{% autoescape off %}
{{ solution.mark_select }}
{% endautoescape %}
</select>
</label>
{% else %}
{% if solution.task.show_result %}
{{ solution.mark_property }}
{% else %}
{% if solution.mark == null %}
Checking
{% else %}
Checked
{% endif %}
{% endif %}
{% endif %}
</td>
</tr>
<tr>
<td>
Комментарий
</td>
<td>
{% if can_edit %}
<textarea rows="10" cols="50" style="resize: none;" name="comment">{{ solution.comment }}</textarea>
{% else %}
<pre>
{{ solution.comment_property }}
</pre>
{% endif %}
</td>
</tr>
</table>
{% if can_edit %}
<button type="submit" name="action" value="Зачесть" class="btn btn-dark"><i class="fa fa-check"></i> Зачесть</button>
<button type="submit" name="action" value="Незачесть" class="btn btn-dark"><i class="fa fa-times"></i> Не зачесть</button>
<button type="submit" name="action" value="Выставить макс. балл" class="btn btn-dark"><i class="fa fa-arrow-up"></i> Выставить макс. балл</button>
<button type="button" class="btn btn-dark" onclick="retest()"><i class="fa fa-undo"></i> Перетест</button>
{% endif %}
<button type="button" class="btn btn-dark"><i class="fa fa-question-circle"></i> Помощь</button>
</form>
</h5>
</div>
</div>
<h3>Files</h3>
{% for filename, text in solution.files.items %}
<h5>{{ filename }}</h5>
{% if filename|is_code %}
<pre>
<code class="c# border border-dark">
{{ text }}
</code>
</pre>
{% else %}
<div class="border border-dark bg-light" style="padding: 15px;">
<pre>
{{ text }}
</pre>
</div>
{% endif %}
<hr>
{% endfor %}
{% endblock %}

View File

@@ -1,315 +0,0 @@
{% extends 'base.html' %}
{% load filters %}
{% block title %}{{ Block.name }} | решения{% endblock %}
{% block scripts %}
function filter() {
const idi = document.getElementById('idi').value;
const task = document.getElementById('task_name').value;
const user = document.getElementById('user').value;
const group = document.getElementById('group').value;
const last_solution = document.getElementById('last_solution').checked;
const best_result = document.getElementById('best_result').checked;
const only_students = document.getElementById('only_students').checked;
const not_seen = document.getElementById('not_seen').checked;
var req = '';
if (idi) {
req += '&solution_id=' + idi;
}
if (not_seen) {
req += '&not_seen=' + not_seen;
}
if (task) {
req += '&task_name=' + task;
}
if (user) {
req += '&user=' + user;
}
if (group) {
req += '&group=' + group;
}
if (last_solution) {
req += '&last_solution=' + last_solution;
}
if (best_result) {
req += '&best_result=' + best_result;
}
if (only_students) {
req += '&only_students=' + only_students;
}
window.location.href = '/admin/solutions?block_id={{ Block.id }}' + req;
}
function retest() {
let del = confirm("Подтвердите перетест");
if (del)
window.location.href = '/admin/retest?block_id={{ Block.id }}{% autoescape off %}{{ req }}{% endautoescape %}';
}
function download() {
let del = confirm("Подтвердите скачивание");
if (del) {
window.location.href = '/admin/download?block_id={{ Block.id }}{% autoescape off %}{{ req }}{% endautoescape %}';
}
}
function showHideTests() {
var text = document.getElementById('tests_text');
var button = document.getElementById('tests_button');
text.hidden = !text.hidden;
if (text.hidden) {
button.textContent = 'Показать тесты';
} else {
button.textContent = 'Скрыть тесты';
}
}
function showHideLog() {
var text = document.getElementById('log_text');
var button = document.getElementById('log_button');
text.hidden = !text.hidden;
if (text.hidden) {
button.textContent = 'Показать лог';
} else {
button.textContent = 'Скрыть лог';
}
}
function fillModalResults(id) {
jQuery.get('/get_result_data?id=' + id, function(data) {
const response = JSON.parse(data);
if (response['success'] == true) {
document.getElementById('resultModalLongTitle').innerHTML = 'Подробная информация о тестировании ' + id;
document.getElementById('results_text').innerHTML = response['results_text'];
document.getElementById('tests_text').innerHTML = '<h4>Тесты</h4><br>' + response['tests_text'];
document.getElementById('log_text').innerHTML = '<h4>Лог</h4><br>' + response['log_text'];
}
});
}
function fillModalComments(id) {
jQuery.get('/get_comment_data?id=' + id, function(data) {
const response = JSON.parse(data);
if (response['success'] == true) {
document.getElementById('commentModalLongTitle').innerHTML = 'Комментарий к решению ' + id;
document.getElementById('comment_text').innerHTML = response['comment_text'];
}
});
}
{% endblock %}
{% block styles %}
.input_field {
width: 500px;
}
{% endblock %}
{% block content %}
<!-- Modal -->
<div class="modal fade" id="resultModalLong" tabindex="-1" role="dialog" aria-labelledby="resultModalLongTitle" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="resultModalLongTitle"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div id="results_text"></div>
<hr>
<pre id="tests_text" hidden></pre>
<hr>
<pre id="log_text" hidden></pre>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" id="log_button" class="btn btn-warning" onclick="showHideLog()">Показать лог</button>
<button type="button" id="tests_button" class="btn btn-primary" onclick="showHideTests()">Показать тесты</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!-- Modal -->
<div class="modal fade" id="commentModalLong" tabindex="-1" role="dialog" aria-labelledby="commentModalLongTitle" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="commentModalLongTitle"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-12">
<pre id="comment_text"></pre>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<h2><a href="/admin/block?id={{ Block.id }}">{{ Block.name }}</a></h2>
<div class="row">
<div class="col-6">
<h4>Фильтр</h4>
<table>
<tr>
<td>Id</td>
<td><input class="input_field" type="text" placeholder="Id" id="idi" name="idi" value="{{ options.solution_id }}"></td>
</tr>
<tr>
<td>Таск</td>
<td>
<select class="input_field" id="task_name" name="task_name">
<option value="">Все</option>
{% for task in solutions_info.tasks %}
<option value="{{ task.name }}" {% if options.task_name == task.name %}selected{% endif %}>{{ task.name }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td>Пользователь</td>
<td>
<select class="input_field" id="user" name="user">
<option value="">Все</option>
{% for u in solutions_info.users %}
<option value="{{ u }}" {% if options.user == u %}selected{% endif %}>{{ u }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td>Группа</td>
<td>
<select class="input_field" id="group" name="group">
<option value="">Все</option>
{% for group in solutions_info.groups %}
<option value="{{ group }}" {% if options.group == group %}selected{% endif %}>{{ group }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td>Последнее решение</td>
<td><input type="checkbox" id="last_solution" name="last_solution" {% if options.last_solution %}checked{% endif %}>{{ option.last_solution }}</td>
</tr>
<tr>
<td>Лучший результат</td>
<td><input type="checkbox" id="best_result" name="best_result" {% if options.best_result %}checked{% endif %}></td>
</tr>
<tr>
<td>Только студенты</td>
<td><input type="checkbox" id="only_students" name="only_students" {% if options.only_students %}checked{% endif %}></td>
</tr>
<tr>
<td>Еще не проверено</td>
<td><input type="checkbox" id="not_seen" name="not_seen" {% if options.not_seen %}checked{% endif %}></td>
</tr>
</table>
<button type="button" class="btn btn-dark" id="control" onclick="filter()" style="margin-top: 20px;"><i class="fa fa-check"></i> Применить</button><br>
<button type="button" class="btn btn-dark" id="control" onclick="window.location.href='/admin/solutions?block_id={{ Block.id }}'" style="margin-top: 10px;"><i class="fa fa-times"></i> Сбросить</button><br>
<button style="margin-top: 10px;" class="btn btn-dark" onclick="download()"><i class="fa fa-download"></i> Скачать решения</button><br>
<button style="margin-top: 10px;" class="btn btn-dark" onclick="retest()"><i class="fa fa-undo"></i> Перетест</button>
</div>
<div class="col-6">
<h4>Статистика по таскам</h4>
<table class="table">
<thead>
<th scope="col">Таск</th>
<th scope="col">Верно</th>
<th scope="col">Частично</th>
<th scope="col">С ошибкой</th>
<th scope="col">Все</th>
</thead>
<tbody>
{% for task in Block.tasks %}
<tr>
<th scope="row">{{ task.name }}</th>
<td>{{ task.correct_count }}</td>
<td>{{ task.partially_passed }}</td>
<td>{{ task.solutions_with_error }}</td>
<td>{{ task.solutions_count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<hr>
<h5>Решения</h5>
<form method="POST" id="delete_form">
{% csrf_token %}
</form>
<table class="table">
<thead>
<tr>
<th scope="col">id</th>
<th scope="col">Таск</th>
<th scope="col">Пользователь</th>
<th scope="col">Время отправки</th>
<th scope="col">Группа</th>
<th scope="col">Результат</th>
<th scope="col">Оценка</th>
<th scope="col">Комментарий</th>
<th scope="col">Действия</th>
</tr>
</thead>
<tbody>
{% for solution in solutions %}
<tr style="background-color: {% if solution.result == 'TESTING' %}#FFE2B7{% else %}{% if solution.result == 'IN QUEUE' %}#EAEAFF{% endif %}{% endif %};">
<th scope="row">
<a href="/admin/solution?id={{ solution.id }}&solutions={{ filter }}">{{ solution.id }}</a>
</th>
<td>
<a href="/admin/task?id={{ solution.task.id }}">{{ solution.task.name }}</a>
</td>
<td>
{{ solution.userinfo.surname }} {{ solution.userinfo.name }} {{ solution.userinfo.middle_name }}
</td>
<td>
{{ solution.time_sent }}
</td>
<td>
{{ solution.userinfo.group }}
</td>
<td>
<!-- Button trigger modal -->
<button type="button" class="btn btn-link" data-toggle="modal" data-target="#resultModalLong" onclick="fillModalResults({{ solution.id }})">
{{ solution.result }}
</button>
</td>
<td>
{{ solution.mark_property }}
</td>
<td>
{% if solution.comment %}
<!-- Button trigger modal -->
<button type="button" class="btn btn-link" data-toggle="modal" data-target="#commentModalLong" onclick="fillModalComments({{ solution.id }})">
Посмотреть
</button>
{% else %}
<p>Нет комментария</p>
{% endif %}
</td>
<td>
<button class="btn btn-primary" onclick="window.location.href='/admin/download?block_id={{ Block.id }}&solution_id={{ solution.id }}';"><i class="fa fa-download"></i></button>
<button name="DELETE_SOLUTION" form="delete_form" value="{{ solution.id }}" onclick="var del = confirm('Подтвердите удаление');if (del){this.form.submit();}" class="btn btn-danger" type="игеещт"><i class="fa fa-trash"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@@ -1,45 +1,19 @@
{% for solution in solutions %}
<tr>
<th scope="row">
<a href="/solution?id={{ solution.id }}">{{ solution.id }}</a>
</th>
<td>
{{ solution.time_sent }}
</td>
<td>
{% if can_edit or task.show_details %}
<!-- Button trigger modal -->
<button type="button" class="btn btn-link" data-toggle="modal" data-target="#resultModalLong" onclick="showData('{{ solution.id }}')">
{{ solution.result }}
</button>
<div id="details_{{ solution.id }}" hidden>{% autoescape off %}{{ solution.details }}{% endautoescape %}</div>
{% if can_edit %}
<div id="tests_{{ solution.id }}" hidden>{{ solution.task.tests_text }}</div>
<div id="log_{{ solution.id }}" hidden>{% autoescape off %}{{ solution.log_text }}{% endautoescape %}</div>
{% endif %}
{% else %}{% if task.show_result %}
{{ solution.result }}
{% else %}
Accepted
{% endif %}
{% endif %}
</td>
<td>
{% if task.show_result or can_edit %}
{{ solution.mark_property }}
{% else %}
{% if solution.mark == null %}
Checking
{% else %}
Checked
{% endif %}
{% endif %}
</td>
<td>
<pre>
{{ solution.comment_property }}
</pre>
</td>
</tr>
<tr>
<td>
<b><a href="">{{ solution.id }}</a></b>
</td>
<td>
{{ solution.time_sent }}
</td>
<td>
<img src="{{ solution.language.logo.url }}" width="30px" height="30px">
{{ solution.language }}
</td>
<td>
<h4>
<span class="badge badge-{% if solution.result == in_queue_status %}secondary{% else %}{% if solution.result == ok_status %}success{% else %}{% if solution.result == testing_status %}info{% else %}danger{% endif %}{% endif %}{% endif %}">{% if solution.result == testing_status %}<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="circle-notch" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="width: 20px;" class="svg-inline--fa fa-circle-notch fa-w-16 fa-spin fa-lg"><path fill="currentColor" d="M288 39.056v16.659c0 10.804 7.281 20.159 17.686 23.066C383.204 100.434 440 171.518 440 256c0 101.689-82.295 184-184 184-101.689 0-184-82.295-184-184 0-84.47 56.786-155.564 134.312-177.219C216.719 75.874 224 66.517 224 55.712V39.064c0-15.709-14.834-27.153-30.046-23.234C86.603 43.482 7.394 141.206 8.003 257.332c.72 137.052 111.477 246.956 248.531 246.667C393.255 503.711 504 392.788 504 256c0-115.633-79.14-212.779-186.211-240.236C302.678 11.889 288 23.456 288 39.056z" class=""></path></svg> {% endif %}{{ solution.result }}</span>
</h4>
</td>
</tr>
{% endfor %}

View File

@@ -1,85 +0,0 @@
{% extends 'base.html' %}
{% block title %}Режим Бога{% endblock %}
{% block content %}
<h1>Настройки системы</h1>
<form method="POST">
{% csrf_token %}
<div class="row">
<div class="col-6">
<table class="table">
<thead>
<tr>
<th scope="col">Параметр</th>
<th scope="col">Значение</th>
</tr>
</thead>
<tbody>
{% for param in params %}
<tr>
<td>{{ param.key }}</td>
<td><input style="width: 100%;" name="{{ param.key }}" value="{{ param.value }}"></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<input type="submit" class="btn btn-dark" value="Сохранить">
</form>
<hr>
<h1>Курсы</h1>
<table border="1px solid black">
<tr>
<td>
<b>id</b>
</td>
<td>
Название
</td>
<td>
Преподаватели
</td>
<td></td>
</tr>
<form method="POST">
{% csrf_token %}
<tr>
<td></td>
<td>
<input type="text" name="course_name">
</td>
<td>
<select name="teacher">
{% for teacher in teachers %}
<option value="{{ teacher.email }}">{{ teacher.email }}</option>
{% endfor %}
</select>
</td>
<td>
<input class="btn btn-dark" type="submit" value="Создать">
</td>
</tr>
</form>
{% for course in courses %}
<tr>
<td>
{{ course.id }}
</td>
<td>
{{ course.name }}
</td>
<td>
{% for teacher in course.teachers %}
{{ teacher.surname }} {{ teacher.name }} {{ teacher.middle_name }}
{% endfor %}
</td>
<td>
</td>
</tr>
{% endfor %}
</table>
<hr>
<button class="btn btn-dark" onclick="window.location.href='/admin/'">Django admin</button>
<hr>
{% endblock %}

View File

@@ -1,290 +1,105 @@
{% extends 'base.html' %}
{% load filters %}
{% block title %}{{ task.name }}{% endblock %}
{% block styles %}
input[type="file"] {
display: none;
}
{% endblock %}
{% block onload %}doPoll(){% endblock %}
{% block links %}
<script>
var current_solution = null;
</script>
{% endblock %}
{% extends 'base_main.html' %}
{% block scripts %}
function partyhard() {
var elem = document.getElementById('paint');
elem.hidden = false;
}
function uploaded() {
document.getElementById('is_uploaded').style.display = 'block';
document.getElementById('is_uploaded').nodeValue = document.getElementById('file-upload').nodeValue;
function change(num) {
inp = document.getElementById('soltype');
if (inp.value == num) return;
document.getElementById('button' + inp.value).classList.remove('btn-dark');
document.getElementById('button' + inp.value).classList.add('btn-light');
document.getElementById('button' + inp.value).focused = false;
document.getElementById('input' + inp.value).hidden = true;
inp.value = 1 - inp.value;
document.getElementById('button' + inp.value).classList.remove('btn-light');
document.getElementById('button' + inp.value).classList.add('btn-dark');
document.getElementById('button' + inp.value).focused = false;
document.getElementById('input' + inp.value).hidden = false;
document.getElementById('chosen').hidden = true;
document.getElementById('file-upload').value = null;
document.getElementById('input0').value = "";
}
function doPoll() {
jQuery.get('/solutions_table?id={{ task.id }}', function(data) {
jQuery.get('/solutions_table?task_id={{ task.id }}', function(data) {
if (data == 'done') {
return
}
else {
document.getElementById('solutions').innerHTML = data;
if (current_solution != null) {
{% if can_edit %}
document.getElementById('log').innerHTML = document.getElementById('log_' + current_solution).innerHTML;
{% endif %}
document.getElementById('details').innerHTML = document.getElementById('details_' + current_solution).innerHTML;
}
setTimeout(function() {doPoll()}, 2000);
}
})
jQuery.get('/solutions_table?id={{ task.id }}&render=true', function(data) {
jQuery.get('/solutions_table?task_id={{ task.id }}&render=true', function(data) {
document.getElementById('solutions').innerHTML = data;
if (current_solution != null) {
{% if can_edit %}
document.getElementById('log').innerHTML = document.getElementById('log_' + current_solution).innerHTML;
{% endif %}
document.getElementById('details').innerHTML = document.getElementById('details_' + current_solution).innerHTML;
}
})
}
{% if can_edit %}
function showHideTests(id) {
var text = document.getElementById('tests_text_' + id);
var button = document.getElementById('tests_button_' + id);
text.hidden = !text.hidden;
if (text.hidden) {
button.textContent = 'Показать тесты';
} else {
button.textContent = 'Скрыть тесты';
}
}
function showHideLog(id) {
var text = document.getElementById('log_text_' + id);
var button = document.getElementById('log_button_' + id);
text.hidden = !text.hidden;
if (text.hidden) {
button.textContent = 'Показать лог';
} else {
button.textContent = 'Скрыть лог';
}
}
{% endif %}
{% if task.show_details or can_edit %}
function showData(id) {
current_solution = id;
const dataTypes = ['details'{% if can_edit %}, 'tests', 'log'{% endif %}];
for (const dt of dataTypes) {
document.getElementById(dt).innerHTML = document.getElementById(dt + '_' + id).innerHTML;
}
document.getElementById('resultModalLongTitle').innerHTML = 'Подробная информация о тестировании ' + id;
}
{% endif %}
{% endblock %}
{% block content %}
<!--
Помогите! Меня взяли в заложники и заставляют писать на Python!!!
Я уже пятый день сижу в подвале и прикручиваю Docker, избавьте меня от мучений и спасите!
-->
<h5>
<a href="/block?id={{ task.block.id }}">Обратно к блоку</a>
</h5>
<h2>
{{ task.name }}
{% if can_edit %}
<a style="color: black;" href="/admin/task?id={{ task.id }}"><i class="fa fa-pencil"></i></a>
{% endif %}
<a style="color: black;" href="" data-toggle="modal" data-target="#messageModal"><!--i class="fa fa-comment"></i--></a>
</h2>
<div class="modal fade" id="messageModal" tabindex="-1" role="dialog" aria-labelledby="messageModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="messageModalLabel">Написать сообщение преподавателям</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form method="POST">
{% csrf_token %}
<div class="modal-body">
<textarea name="message" rows="10" cols="50" style="resize: none;"></textarea>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Закрыть</button>
<button type="submit" class="btn btn-primary">Отправить</button>
</div>
</form>
</div>
</div>
</div>
<hr>
<div class="row">
<div class="col-9">
<h3>Легенда</h3>
{% autoescape off %}
{{ task.legend }}
{% endautoescape %}
<hr>
<h3>Формат входных данных</h3>
{% autoescape off %}
{% block onload %}doPoll(){% endblock %}
{{ task.input }}
{% endautoescape %}
<hr>
<h3>Формат выходных данных</h3>
{% autoescape off %}
{{ task.output }}
{% endautoescape %}
<hr>
<h3>Спецификации</h3>
{% autoescape off %}
{{ task.specifications }}
{% endautoescape %}
</div>
<div class="col"></div>
<div class="col-2">
<h5>Таски</h5>
<table>
{% for t in task.block.tasks %}
<tr>
{% with mark=t|mark_for_task:user %}
{% if mark|marked %}
<td>
<div style="margin-left: 20px; border: 1px solid black; background: {{ mark|mark_color }}; width: 25px; text-align: center;">
{{ mark }}
</div>
</td>
{% endif %}
{% endwith %}
<td>
<a href="/task?id={{ t.id }}">{% if t.id == task.id %}<b>{{ t.name }}</b>{% else %}{{ t.name }}{% endif %}</a><br>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
<hr>
<h3>Самплы</h3>
{% for sample in task.samples %}
<h5>Пример {{ sample.input.num }}</h5><br>
<b>
<table style="width: 100%">
<tr>
<td>
Входные данные
</td>
<td>
Выходные данные
</td>
</tr>
</table>
</b>
<hr>
<table style="width: 100%;">
<tr>
<td style="width: 50%; vertical-align: top;">
<pre>
{{ sample.input.text }}
</pre>
</td>
<td style="width: 50%; vertical-align: top;">
<pre>
{{ sample.output.text }}
</pre>
</td>
</tr>
</table>
<hr>
{% endfor %}
<hr>
{% if can_send or can_edit %}
<h2>Отправить решение</h2>
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<label for="file-upload" class="btn btn-dark" style="margin-top: 20px;">
<i class="fa fa-upload"></i> Загрузить файл
</label>
<span id="is_uploaded" style="display: none;">Решение загружено</span>
<input type="file" class="btn form-control-file" id="file-upload" value="Выбрать файл" name="file" onchange="uploaded()">
<br><button type="submit" value="Отправить" class="btn btn-outline-dark"><i class="fa fa-share"></i> Отправить</button>
</form>
{% endif %}
{% if not can_edit and can_send %}
Осталось попыток: {{ user|last_attempts:task }}
{% endif %}
{% if can_edit or task.show_details %}
<!-- Modal -->
<div class="modal fade" id="resultModalLong" tabindex="-1" role="dialog" aria-labelledby="resultModalLongTitle" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="resultModalLongTitle">Подробная информация о тестировании</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-12">
{% block main %}
<h2>{{ task.name }}</h2>
{% if task.legend %}
<h4>Легенда</h4>
{% autoescape off %}
<div id="details"></div>
{{ task.legend }}
{% endautoescape %}
{% if can_edit %}
<hr>
<pre id="tests_text_{{ solution.id }}" hidden>
<h4>Тесты</h4><br>
<div id="tests"></div>
</pre>
{% endif %}
{% if task.input_format %}
<h4>Формат входных данных</h4>
{% autoescape off %}
{{ task.input_format }}
{% endautoescape %}
<hr>
<pre id="log_text_{{ solution.id }}" hidden>
<h4>Лог</h4><br>
<div id="log"></div>
</pre>
{% endif %}
</div>
</div>
</div>
</div>
<div class="modal-footer">
{% if can_edit %}
<button type="button" id="log_button_{{ solution.id }}" class="btn btn-warning" onclick="showHideLog('{{ solution.id }}')">Показать лог</button>
<button type="button" id="tests_button_{{ solution.id }}" class="btn btn-primary" onclick="showHideTests('{{ solution.id }}')">Показать тесты</button>
{% endif %}
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
{% if task.output_format %}
<h4>Формат выходных данных</h4>
{% autoescape off %}
{{ task.output_format }}
{% endautoescape %}
<hr>
{% endif %}
<h2 style="margin-top: 20px;">Решения</h2>
<table class="table">
<thead>
<tr>
<th scope="col">id</th>
<th scope="col">Дата и время отправки</th>
<th scope="col">Результат</th>
<th scope="col">Оценка</th>
<th scope="col">Комментарий</th>
</tr>
</thead>
<tbody id="solutions">
</tbody>
</table>
<iframe id="paint" src="https://jspaint.app/" style="width: 100%; height: 1000px;" hidden></iframe>
{% if task.specifications %}
<h4>Примечания</h4>
{% autoescape off %}
{{ task.specifications }}
{% endautoescape %}
<hr>
{% endif %}
<h2>Отправить решение</h2>
<table style="margin-bottom: 10px;">
<tr>
<input type="hidden" form="solform" name="action" id="soltype" value="0">
<td><button class="btn btn-dark" id="button0" onclick="change('0')">Текст</button></td>
<td><button class="btn btn-light" id="button1" onclick="change('1')">Файл</button></td>
</tr>
</table>
<form method="POST" enctype="multipart/form-data" id="solform">
{% csrf_token %}
<select name="language" style="margin-bottom: 30px; width: 10%;">
<option disabled>Выберите язык</option>
{% for lang in languages %}
<option value="{{ lang.id }}">{{ lang }}</option>
{% endfor %}
</select><br>
<textarea id="input0" style="width: 1000px; height: 400px; resize: none;" name="code" placeholder="Вставьте сюда свой код"></textarea>
<label for="file-upload" class="btn btn-outline-dark" id="input1" hidden>
<i class="fa fa-upload"></i> Загрузить файл
</label>
<p id="chosen" hidden>Файл выбран</p>
<input type="file" style="display: none;" onchange="document.getElementById('chosen').hidden = false;" class="btn form-control-file" id="file-upload" value="Выбрать файл" name="file">
<br><button type="submit" style="margin-top: 30px; margin-bottom: 30px;" class="btn btn-dark">Отправить</button>
</form>
<hr>
<h2>Решения</h2>
<table class="table" style="margin-top: 30px;">
<thead>
<th scope="col">id</th>
<th scope="col">Время отправки</th>
<th scope="col">Язык</th>
<th scope="col">Результат</th>
</thead>
<tbody id="solutions">
</tbody>
</table>
{% endblock %}

View File

@@ -1,327 +1,150 @@
{% extends 'base.html' %}
{% extends 'base_main.html' %}
{% load filters %}
{% block title %}{{ task.name }}|настройки{% endblock %}
{% block title %}{{ task.name }}{% endblock %}
{% block scripts %}
function uploaded() {
document.getElementById('is_uploaded').style.display = 'block';
document.getElementById('is_uploaded').nodeValue = document.getElementById('file-upload').nodeValue;
}
function uploaded1() {
document.getElementById('send').style.display = 'block';
document.getElementById('is_uploaded1').nodeValue = document.getElementById('file-upload1').nodeValue;
}
function valueChanged() {
const other = document.getElementById('show_details');
other.disabled = !document.getElementById('show_result').checked;
console.log('changed');
if (other.disabled) {
other.checked = false;
function deleteFile(file_id) {
$.ajax({
type: "POST",
url: "/admin/task?task_id={{ task.id }}",
data: {"id": file_id, "csrfmiddlewaretoken": document.getElementsByName("csrfmiddlewaretoken")[0].value, "action": "delete_file"},
success: function(data) {
if (data == "ok") {
var elem = document.getElementById("file_" + file_id);
elem.parentNode.removeChild(elem);
}
}
}
function set_checkboxes() {
if (!document.getElementById('show_result').checked) {
document.getElementById('show_details').disabled = true;
}
}
});
}
function setActionCreate(action) {
document.getElementById('action_create').value = action;
}
{% endblock %}
{% block onload %}set_checkboxes(){% endblock %}
{% block styles %}
input[type="file"] {
display: none;
}
input[name="new_file"] {
display: none;
}
.my_td {
vertical-align: middle;
height: 20px;
}
.params {
margin-top: 20px;
}
.in {
width: 500%;
}
{% endblock %}
{% block content %}
<h5><a href="/admin/block?id={{ task.block.id }}">{{ task.block.name }}</a></h5>
<h2>{{ task.name }} <a style="color: black;" href="/task?id={{ task.id }}"><i class="fa fa-eye"></i></a></h2>
<form action="" method="POST" id="main_form" enctype="multipart/form-data">
{% block main %}
<h3 style="margin-bottom: 40px;">Настройки задачи</h3>
<form method="POST">
{% csrf_token %}
<table style="width: 100%;">
<tr>
<td style="width: 250px;">
Название задачи
</td>
<td>
<h4><input type="text" value="{{ task.name }}" name="name" class="task-settings-input" placeholder="Новая задача"></h4>
</td>
</tr>
<tr>
<td>
Легенда
</td>
<td>
<textarea class="task-settings-input task-settings-textarea" name="legend">{{ task.legend }}</textarea>
</td>
</tr>
<tr>
<td>
Формат входных данных
</td>
<td>
<textarea class="task-settings-input task-settings-textarea" name="input_format">{{ task.input_format }}</textarea>
</td>
</tr>
<tr>
<td>
Формат выходных данных
</td>
<td>
<textarea class="task-settings-input task-settings-textarea" name="output_format">{{ task.output_format }}</textarea>
</td>
</tr>
<tr>
<td>
Примечания
</td>
<td>
<textarea class="task-settings-input task-settings-textarea" name="specifications">{{ task.specifications }}</textarea>
</td>
</tr>
<tr>
<td>
Ограничение по времени (мс)
</td>
<td>
<input type="text" name="time_limit" value="{{ task.time_limit }}" class="task-settings-input">
</td>
</tr>
</table>
<button type="submit" class="btn btn-light" style="margin-top: 15px;"><i class="fa fa-save"></i> Сохранить</button>
</form>
<hr><hr>
<h3 style="margin-bottom: 40px;">Загрузка тестов и файлов</h3>
<p style="color: red">{{ error_message }}</p>
<table style="width: 80%;">
<tr>
<td>
<h4>Тесты</h4>
</td>
<td>
<h4>Файлы</h4>
</td>
</tr>
<tr>
<td>
{% for test in task.tests %}
<div id="file_{{ test.id }}">
<i class="fa fa-file"></i> <button class="btn btn-link" {% if not test.readable %}style="color: red;"{% endif %}>{{ test.filename }}</button><button class="btn btn-link" style="color: black;" onclick="deleteFile({{ test.id }});"><i class="fa fa-times"></i> </button><br>
</div>
{% endfor %}
<input type="file" style="display: none;" form="form_test_upload" onchange="this.form.submit();" class="btn form-control-file" id="test-upload" value="Выбрать файл" name="file">
<label for="test-upload" class="btn btn-primary"><i class="fa fa-upload"></i> Загрузить тесты</label><button style="margin-left: 10px; margin-top: -8px;" class="btn btn-success" data-toggle="modal" data-target="#exampleModalLongnewtest" onclick="setActionCreate('create_test');"><i class="fa fa-plus"></i></button>
<form method="POST" enctype="multipart/form-data" id="form_test_upload">
<input name="action" type="hidden" value="test_upload">
{% csrf_token %}
</form>
</td>
<td>
{% for file in task.files %}
<div id="file_{{ file.id }}">
<i class="fa fa-file"></i> <button class="btn btn-link" {% if not file.readable %}style="color: red;"{% endif %}>{{ file.filename }}</button><button class="btn btn-link" style="color: black;" onclick="deleteFile({{ file.id }});"><i class="fa fa-times"></i> </button><br>
</div>
{% endfor %}
<input type="file" style="display: none;" form="form_file_upload" onchange="this.form.submit();" class="btn form-control-file" id="file-upload" value="Выбрать файл" name="file">
<label for="file-upload" class="btn btn-primary"><i class="fa fa-upload"></i> Загрузить файлы</label><button style="margin-left: 10px; margin-top: -8px;" class="btn btn-success" data-toggle="modal" data-target="#exampleModalLongnewtest" onclick="setActionCreate('create_file');"><i class="fa fa-plus"></i></button>
<form method="POST" enctype="multipart/form-data" id="form_file_upload">
<input name="action" type="hidden" value="file_upload">
{% csrf_token %}
</form>
</td>
</tr>
</table>
<form method="POST">
{% csrf_token %}
<table>
<tr class="params">
<td>
Легенда
</td>
<td>
<textarea form="main_form" rows="15" class="in" style="resize: none;" name="legend">{{ task.legend }}</textarea>
</td>
</tr>
<tr class="params">
<td>
Формат входных данных
</td>
<td>
<textarea form="main_form" rows="15" class="in" style="resize: none;" name="input">{{ task.input }}</textarea>
</td>
</tr>
<tr class="params">
<td>
Формат выходных данных
</td>
<td>
<textarea form="main_form" rows="15" class="in" style="resize: none;" name="output">{{ task.output }}</textarea>
</td>
</tr>
<tr class="params">
<td>
Спецификации
</td>
<td>
<textarea form="main_form" rows="15" class="in" style="resize: none;" name="specifications">{{ task.specifications }}</textarea>
</td>
</tr>
<tr>
<td>
Ограничения по времени
</td>
<td>
<input form="main_form" type="text" name="time_limit" class="in" value="{{ task.time_limit }}">
</td>
</tr>
<tr>
<td>
Вес задачи
</td>
<td>
<input form="main_form" type="text" name="weight" class="in" value="{{ task.weight }}">
</td>
</tr>
<tr>
<td>
Максимальная оценка
</td>
<td>
<input form="main_form" type="text" name="max_mark" class="in" value="{{ task.max_mark }}">
</td>
</tr>
<tr>
<td>
Максимум решений
</td>
<td>
<input form="main_form" type="text" name="max_solutions_count" class="in" value="{{ task.max_solutions_count }}">
</td>
</tr>
<tr>
<td>
Формула оценки
</td>
<td>
<input form="main_form" type="text" name="mark_formula" class="in" value="{{ task.mark_formula }}">
</td>
</tr>
<tr>
<td>
Сдается полное решение
</td>
<td>
<input form="main_form" type="checkbox" name="full_solution" {{ task.is_full_solution }}>
</td>
</tr>
<tr>
<td>
Показывать результат тестирования
</td>
<td>
<input form="main_form" type="checkbox" id="show_result" name="show_result" onchange="valueChanged()" {% if task.show_result %}checked{% endif %}>
</td>
</tr>
<tr>
<td>
Показывать детали тестирования
</td>
<td>
<input form="main_form" type="checkbox" id="show_details" name="show_details" {{ task.showable }}>
</td>
</tr>
<tr>
<td>
Приоритет
</td>
<td>
<select name="priority">
{% for i in 10|num_range %}
<option {% if task.priority == i %}selected{% endif %}>{{ i }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td>
Тесты
</td>
<td>
<!-- Button trigger modal -->
<button type="button" class="btn btn-link" data-toggle="modal" data-target="#exampleModalLong">
Посмотреть
</button>
<!-- Modal -->
<div class="modal fade bd-example-modal-lg" id="exampleModalLong" tabindex="-1" role="dialog" aria-labelledby="exampleModalLongTitle" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Unit тесты</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-12">
<textarea cols="82" rows="30" name="tests_text">{{ task.tests_text }}</textarea>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal"><i class="fa fa-times"></i> Close</button>
<button type="submit" class="btn btn-primary" name="ACTION" value="SAVE_TESTS"><i class="fa fa-save"></i> Save</button>
</div>
</div>
</div>
<div class="modal fade" id="exampleModalLongnewtest" tabindex="-1" role="dialog" aria-labelledby="exampleModalLongTitlenewtest" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitlenewtest">Создать новый файл</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-12">
<input type="text" placeholder="Имя файла" name="newfile_name">
</div>
</td>
</tr>
<tr>
<td style="vertical-align: top; padding-top: 10px;">
Дополнительные файлы и самплы
</td>
<td style="vertical-align: top;">
<table>
{% for file in task.files %}
<tr>
<td>
{% if file.can_be_sample %}
<input form="main_form" type="checkbox" name="sample_{{ file.id }}" {{ file.is_sample }}>
{% endif %}
</td>
<td>
<button type="submit" class="close" name="ACTION" value="DELETE_FILE_{{ file.id }}">
<span aria-hidden="true">&times;</span>
</button>
</td>
<td>
<img width="14px" height="14px" src="https://image.flaticon.com/icons/svg/876/876755.svg">
</td>
<td>
{% if file.readable %}
<button type="button" class="btn btn-link" data-toggle="modal" data-target="#filesModalLong{{ file.id }}">
{{ file.filename }}
</button>
<!-- Modal -->
<div class="modal fade bd-example-modal-lg" id="filesModalLong{{ file.id }}" tabindex="-1" role="dialog" aria-labelledby="filesModalLongTitle{{ file.id }}" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="filesModalLongTitle{{ file.id }}">{{ file.filename }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-12">
<textarea cols="82" rows="30" name="extra_file_text_{{ file.id }}">{{ file.text }}</textarea>
</div>
</div>
</div>
</div>
<div class="modal-footer">
Файл для компиляции <input type="checkbox" name="{{ file.id }}_for_compilation" {{ file.is_for_compilation }}>
<button type="button" class="btn btn-secondary" data-dismiss="modal"><i class="fa fa-times"></i> Close</button>
<button type="submit" class="btn btn-primary" name="ACTION" value="SAVE_EXTRA_FILE_{{ file.id }}"><i class="fa fa-save"></i> Save</button>
</div>
</div>
</div>
</div>
{% else %}
<button type="button" class="btn btn-link" style="color: red;">
{{ file.filename }}
</button>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
<label for="files" class="btn btn-primary">
<i class="fa fa-upload"></i> Загрузить файл
</label>
<form method="POST">
<input type="file" class="btn form-control-file" id="files" value="Выбрать файл" name="file" onchange="uploaded1()">
</form>
<label for="add_file" class="btn btn-success">
<i class="fa fa-plus"></i>
</label>
<input type="button" class="btn btn-success" id="add_file" value="Создать файл" name="new_file" data-toggle="modal" data-target="#exampleModalLongnewfile">
<button name="ACTION" value="UPLOAD_EXTRA_FILE" type="submit" class="btn btn-success" style="display: none;" id="send">Отправить</button>
<form method="POST">
{% csrf_token %}
<div class="modal fade" id="exampleModalLongnewfile" tabindex="-1" role="dialog" aria-labelledby="exampleModalLongTitlenewfile" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitlenewfile">Создать новый файл</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-12">
<input type="text" placeholder="Имя файла" name="newfile_name">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal"><i class="fa fa-times"></i> Закрыть</button>
<button name="ACTION" value="CREATE_EXTRA_FILE" type="submit" class="btn btn-primary"><i class="fa fa-file"></i> Создать</button>
</div>
</div>
</div>
</div>
</form>
</td>
</tr>
</table>
<hr>
<button type="submit" name="ACTION" value="SAVE" class="btn btn-dark"><i class="fa fa-save"></i> Сохранить</button>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-times"></i> Закрыть</button>
<button type="submit" class="btn btn-success"><i class="fa fa-file"></i> Создать</button>
<input id="action_create" type="hidden" name="action" value="">
</div>
</div>
</div>
</div>
</form>
{% if is_superuser %}
<form style="margin-top: 15px;" id="another_form" method="POST">
{% csrf_token %}
<input type="hidden" name="ACTION" value="DELETE" form="another_form">
<button form="another_form" type="button" onclick="let del = confirm('Данное действие приведет к удалению условия, тестов, дополнительных файлов и решений, привязанных к этому таску. Точно удаляем?'); if (del) {this.form.submit();}" class="btn btn-dark"><i class="fa fa-trash"></i> Удалить таск</button>
</form>
{% endif %}
{% endblock %}

49
templates/tasks.html Normal file
View File

@@ -0,0 +1,49 @@
{% extends 'base_main.html' %}
{% block title %}Задачи{% endblock %}
{% block main %}
<table>
<tr>
<td>
<h2>Задачи</h2>
</td>
{% if user.userinfo.can_create %}
<td>
<button style="margin-left: 20px;" class="btn btn-success" data-toggle="modal" data-target="#example"><i class="fa fa-plus"></i></button>
<div class="modal fade" id="example" tabindex="-1" role="dialog" aria-labelledby="exampleModalLongTitle" aria-hidden="true">
<div class="modal-dialog" role="document">
<form method="POST">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Создать новую задачу</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-12">
{% csrf_token %}
<input type="text" name="name" placeholder="Название задачи">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-times-circle"></i> Закрыть</button>
<button type="submit" class="btn btn-success"><i class="fa fa-plus-circle"></i> Создать</button>
</div>
</div>
</form>
</div>
</div>
</td>
{% endif %}
</tr>
</table>
{% for task in user.userinfo.available_tasks %}
<a href="/task?task_id={{ task.id }}">{{ task.name }}</a> {% if task.creator == user %}<a href="/admin/task?task_id={{ task.id }}"><i class="fa fa-pencil"></i> </a>{% endif %}<br>
{% endfor %}
{% endblock %}

View File

@@ -1,165 +0,0 @@
{% extends 'base.html' %}
{% block title %}{{ course.name }}|настройки{% endblock %}
{% block scripts %}
function uploaded() {
document.getElementById('is_uploaded').style.display = 'block';
document.getElementById('is_uploaded').nodeValue = document.getElementById('file-upload').nodeValue;
}
{% endblock %}
{% block styles %}
input[type="file"] {
display: none;
}
{% endblock %}
{% block content %}
<h3>{{ course.name }}</h3>
<h5>Добавить участников</h5>
<form method="POST">
{% csrf_token %}
<table>
<tr>
<td>
<input name="input" type="text" placeholder="ФИО, почта или группа" style="width: 200px;">
</td>
<td>
<input type="submit" value="Добавить" class="btn btn-dark">
</td>
</tr>
</table>
</form>
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<label for="file-upload" class="btn btn-dark" style="margin-top: 20px;">
Загрузить файл
</label>
<span id="is_uploaded" style="display: none;">Файл загружен</span>
<input type="file" class="btn form-control-file" id="file-upload" value="Выбрать файл" name="file" onchange="uploaded()">
<br><input type="submit" value="Отправить" class="btn btn-outline-dark">
</form>
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#example" style="margin-top: 20px;">
Правила загрузки файла
</button>
<!-- Modal -->
<div class="modal fade" id="example" tabindex="-1" role="dialog" aria-labelledby="exampleModalLongTitle" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Инструкция к загружаемому файлу</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-12">
<pre>
Загружаемый файл должен представлять из себя
JSON файл, составленый следующим образом:
[
{
"email": "samplename@samplemail.com",
"surname": "Иванов",
"name": "Иван",
"middle_name": "Иванович",
"group": "БПИ183"
},
{
"email": "samplename2@samplemail.com",
"surname": "Чуйкин",
"name": "Виктор",
"middle_name": "Вениаминович",
"group": "БПИ9000"
}
]
Пояснения к заполняемым полям:
email - почта
surname - фамилия
name - имя
middle_name - отчество
group - группа
Все пользователи будут зарегестрированы на сервисе,
и каждому из них на указанные почты будут
отправлены сгенерированные пароли.
Также каждый пользователь будет подписан на
данный курс. Если пользователь уже был
зарегестрирован в системе, запись о нем
будет проигнорирована.
</pre>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Понял(-а)</button>
</div>
</div>
</div>
</div>
<hr>
<h1>Участники</h1>
<table class="table">
<thead>
<tr>
<th scope="col">Фамилия</th>
<th scope="col">Имя</th>
<th scope="col">Отчество</th>
<th scope="col">Группа</th>
<th scope="col">Почта</th>
<th scope="col">Роль</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{% for user in course.subscribes %}
<tr>
<td>
{{ user.userinfo.surname }}
</td>
<td>
{{ user.userinfo.name }}
</td>
<td>
{{ user.userinfo.middle_name }}
</td>
<td>
{{ user.userinfo.group }}
</td>
<td>
{{ user.userinfo.user.email }}
</td>
<td>
{% with role=user.role %}
{% if role == 'Студент' or role == 'Ассистент' %}
<form method="POST">
{% csrf_token %}
<select name="role_{{ user.userinfo.user.email }}" onchange="this.form.submit();">
<option {% if role == 'Студент' %}selected{% endif %}>Студент</option>
<option {% if role == 'Ассистент' %}selected{% endif %}>Ассистент</option>
</select>
</form>
{% else %}
{{ user.role }}
{% endif %}
{% endwith %}
</td>
<td>
<form method="POST" onsubmit="return confirm('Точно отписываем?');">
{% csrf_token %}
<input type="hidden" name="user_delete" value="{{ user.userinfo.user.email }}">
<input type="submit" value="Отписка" class="btn btn-outline-danger">
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}