Просмотр исходного кода

Сделал задачи в проектах, можно создавать задачу, устанавливать дедлайн, отвечать на задачу файлами или текстом

Andrei 2 лет назад
Родитель
Сommit
88c2430ef4

+ 2 - 3
data/proof_to_quests.py → data/answer.py

@@ -5,12 +5,11 @@ from datetime import datetime
 from .db_session import SqlAlchemyBase
 from .db_session import SqlAlchemyBase
 
 
 
 
-class Proofs(SqlAlchemyBase, UserMixin):
-    __tablename__ = 'proofs'
+class Answer(SqlAlchemyBase, UserMixin):
+    __tablename__ = 'answer'
 
 
     id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True, autoincrement=True)
     id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True, autoincrement=True)
     quest = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey("quests.id"), nullable=True, default=None)
     quest = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey("quests.id"), nullable=True, default=None)
-    file = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey("files.id"), nullable=True, default=None)
     text = sqlalchemy.Column(sqlalchemy.Text, nullable=True, default=None)
     text = sqlalchemy.Column(sqlalchemy.Text, nullable=True, default=None)
     creator = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey("users.id"), nullable=True,
     creator = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey("users.id"), nullable=True,
                                 default=None)
                                 default=None)

+ 12 - 0
data/proof_file.py

@@ -0,0 +1,12 @@
+import sqlalchemy
+from flask_login import UserMixin
+from datetime import datetime
+
+from .db_session import SqlAlchemyBase
+
+
+class FileProof(SqlAlchemyBase, UserMixin):
+    __tablename__ = 'file_proof'
+    id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True, autoincrement=True)
+    answer = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey("answer.id"), nullable=True, default=None)
+    file = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey("files.id"), nullable=True, default=None)

+ 7 - 3
forms/task.py

@@ -1,5 +1,6 @@
 from flask_wtf import FlaskForm
 from flask_wtf import FlaskForm
-from wtforms import StringField, SubmitField, TextAreaField, DateField, TimeField, FileField
+from wtforms import StringField, SubmitField, TextAreaField, DateField, TimeField, MultipleFileField, \
+    BooleanField
 from wtforms.validators import DataRequired
 from wtforms.validators import DataRequired
 
 
 
 
@@ -13,5 +14,8 @@ class NewTask(FlaskForm):
 
 
 class AnswerTask(FlaskForm):
 class AnswerTask(FlaskForm):
     text = TextAreaField('Письменный ответ')
     text = TextAreaField('Письменный ответ')
-    file = FileField('Файловый ответ')
-    submit = SubmitField('Ответить')
+    file = MultipleFileField('Файловый ответ')
+    realized = BooleanField('Задача решена')
+    deadline_date = DateField('Дедлайн', validators=[DataRequired()])
+    deadline_time = TimeField('', validators=[DataRequired()])
+    submit = SubmitField('Сохранить')

+ 35 - 2
functions.py

@@ -1,10 +1,13 @@
 import datetime
 import datetime
+import os
 import smtplib
 import smtplib
 from json import loads
 from json import loads
 from email.message import EmailMessage
 from email.message import EmailMessage
 from data.roles import Roles
 from data.roles import Roles
 from data.users import User
 from data.users import User
 from data.staff_projects import StaffProjects
 from data.staff_projects import StaffProjects
+from data.answer import Answer
+from data.files import Files
 from data import db_session
 from data import db_session
 import uuid
 import uuid
 import pymorphy2
 import pymorphy2
@@ -95,12 +98,14 @@ def save_project_logo(photo):
 
 
 
 
 def overdue_quest_project(quest):
 def overdue_quest_project(quest):
-    if str(quest.deadline.date()) == str(datetime.datetime.now().date()):
+    if quest.deadline is None:
+        quest.overdue = ''
+    elif str(quest.deadline.date()) == str(datetime.datetime.now().date()):
         quest.overdue = 'today'
         quest.overdue = 'today'
     elif quest.deadline < datetime.datetime.now():
     elif quest.deadline < datetime.datetime.now():
         quest.overdue = 'yes'
         quest.overdue = 'yes'
         quest.time_left = 'Просрочено на' + round_date(quest.deadline)
         quest.time_left = 'Просрочено на' + round_date(quest.deadline)
-    else:
+    elif quest.deadline > datetime.datetime.now():
         quest.overdue = 'no'
         quest.overdue = 'no'
         quest.time_left = 'Еще есть: ' + round_date(quest.deadline)
         quest.time_left = 'Еще есть: ' + round_date(quest.deadline)
     return quest
     return quest
@@ -120,3 +125,31 @@ def round_date(date_time):
     if difference:
     if difference:
         resp += ', ' if resp else ' ' + f'{difference} {morph.parse("день")[0].make_agree_with_number(difference).word}'
         resp += ', ' if resp else ' ' + f'{difference} {morph.parse("день")[0].make_agree_with_number(difference).word}'
     return f'{resp}'
     return f'{resp}'
+
+
+def save_proof_quest(project, file, user_id):
+    data_session = db_session.create_session()
+    path = f'static/app_files/all_projects/{str(project.id)}/{str(file.filename)}'
+    file_check = data_session.query(Files).filter(Files.path == path).first()
+    file.save(path)
+    if file_check:
+        return file_check.id
+    file = Files(
+        path=path,
+        user=user_id,
+        up_date=datetime.datetime.now()
+    )
+    data_session.add(file)
+    data_session.flush()
+    data_session.refresh(file)
+    file_id = file.id
+    data_session.commit()
+    data_session.close()
+    return file_id
+
+
+def find_files_answer(file_id):
+    data_session = db_session.create_session()
+    file = data_session.query(Files).filter(Files.id == file_id).first()
+    return {'id': file.id, 'path': file.path, 'user': file.user, 'up_date': file.up_date,
+            'current_path': file.path[str(file.path).find('all_projects') + 13:].split('/')}

+ 100 - 6
main.py

@@ -12,7 +12,7 @@ from sqlalchemy import or_
 from json import loads
 from json import loads
 
 
 from functions import check_password, mail, init_db_default, get_projects_data, get_user_data, save_project_logo, \
 from functions import check_password, mail, init_db_default, get_projects_data, get_user_data, save_project_logo, \
-    overdue_quest_project
+    overdue_quest_project, save_proof_quest, find_files_answer
 from forms.edit_profile import EditProfileForm
 from forms.edit_profile import EditProfileForm
 from forms.login import LoginForm
 from forms.login import LoginForm
 from forms.find_project import FindProjectForm
 from forms.find_project import FindProjectForm
@@ -24,6 +24,8 @@ from forms.task import NewTask, AnswerTask
 
 
 from data.users import User
 from data.users import User
 from data.quests import Quests
 from data.quests import Quests
+from data.answer import Answer
+from data.proof_file import FileProof
 from data.files import Files
 from data.files import Files
 from data.projects import Projects
 from data.projects import Projects
 from data.staff_projects import StaffProjects
 from data.staff_projects import StaffProjects
@@ -50,7 +52,35 @@ def base():
         return redirect('/projects')
         return redirect('/projects')
 
 
 
 
-@app.route('/project/<int:id_project>/quest/<int:id_task>')
+@app.route('/project/<int:id_project>/file/<int:id_file>/delete')
+def delete_file(id_project, id_file):
+    if current_user.is_authenticated:
+        data_session = db_session.create_session()
+        current_project = data_session.query(Projects).filter(Projects.id == id_project).first()
+        current_file = data_session.query(Files).filter(Files.id == id_file).first()
+        if current_project and current_file:
+            if current_user.id in map(lambda x: x[0], data_session.query(StaffProjects.user).filter(
+                    StaffProjects.project == current_project.id).all()) or current_user.id == current_project.creator:
+                current_proof = data_session.query(FileProof).filter(FileProof.file == id_file).all()
+                os.remove(current_file.path)
+                data_session.delete(current_file)
+                if current_proof:
+                    quest = data_session.query(Answer.quest).filter(Answer.id == current_proof[0].answer).first()
+                    for i in current_proof:
+                        data_session.delete(i)
+                    data_session.commit()
+                    return redirect(f'/project/{current_project.id}/quest/{quest[0]}')
+                data_session.commit()
+                return redirect(f'/project/{current_project.id}')
+            else:
+                abort(403)
+        else:
+            abort(404)
+    else:
+        return redirect('/login')
+
+
+@app.route('/project/<int:id_project>/quest/<int:id_task>', methods=['GET', 'POST'])
 def task_project(id_project, id_task):
 def task_project(id_project, id_task):
     if current_user.is_authenticated:
     if current_user.is_authenticated:
         data_session = db_session.create_session()
         data_session = db_session.create_session()
@@ -58,15 +88,75 @@ def task_project(id_project, id_task):
         current_task = data_session.query(Quests).filter(Quests.id == id_task).first()
         current_task = data_session.query(Quests).filter(Quests.id == id_task).first()
         if current_project and current_task and current_task.project == current_project.id:
         if current_project and current_task and current_task.project == current_project.id:
             form = AnswerTask()
             form = AnswerTask()
-            return render_template('decision.html', title='Решение', project=current_project, task=current_task,
-                                   form=form)
+            current_answer = data_session.query(Answer).filter(Answer.quest == current_task.id).first()
+            list_files = None
+            if form.validate_on_submit():
+                if form.deadline_date.data and form.deadline_time.data:
+                    deadline = datetime.datetime.combine(form.deadline_date.data, form.deadline_time.data)
+                else:
+                    deadline = None
+                current_task.deadline = deadline
+                if current_answer:
+                    current_answer.text = form.text.data if form.text.data else None
+                    current_answer.date_edit = datetime.datetime.now()
+                    current_task.realized = form.realized.data
+                    data_session.commit()
+                    if form.file.data[0].filename:
+                        files = list(
+                            map(lambda x: save_proof_quest(current_project, x, current_user.id), form.file.data))
+                        for i in files:
+                            if not data_session.query(FileProof).filter(FileProof.answer == current_answer.id,
+                                                                        FileProof.file == i).first():
+                                proof_file = FileProof(
+                                    answer=current_answer.id,
+                                    file=i
+                                )
+                                data_session.add(proof_file)
+                                data_session.commit()
+                else:
+                    if form.file.data[0].filename:
+                        files = list(
+                            map(lambda x: save_proof_quest(current_project, x, current_user.id), form.file.data))
+                    else:
+                        files = False
+                    current_task.realized = form.realized.data
+                    current_answer = Answer(
+                        quest=current_task.id,
+                        text=form.text.data if form.text.data else None,
+                        creator=current_user.id,
+                        date_create=datetime.datetime.now(),
+                        date_edit=datetime.datetime.now()
+                    )
+                    data_session.add(current_answer)
+                    data_session.flush()
+                    data_session.refresh(current_answer)
+                    if files:
+                        for i in files:
+                            proof_file = FileProof(
+                                proof=current_answer.id,
+                                file=i
+                            )
+                            data_session.add(proof_file)
+                    data_session.commit()
+                return redirect(f'/project/{current_project.id}')
+            if current_answer:
+                form.text.data = current_answer.text
+                form.realized.data = current_task.realized
+                files = data_session.query(FileProof).filter(FileProof.answer == current_answer.id).all()
+                if files:
+                    list_files = list(map(lambda x: find_files_answer(x.file), files))
+            if current_task.deadline and current_task.deadline:
+                form.deadline_date.data = current_task.deadline.date()
+                form.deadline_time.data = current_task.deadline.time()
+            return render_template('answer.html', title='Решение', project=current_project, task=current_task,
+                                   form=form, list_files=list_files)
         else:
         else:
             abort(404)
             abort(404)
     else:
     else:
         return redirect('/login')
         return redirect('/login')
 
 
 
 
-@app.route('/project/<int:id_project>/task/new', methods=['GET', 'POST'])
+@app.route('/project/<int:id_project>/quest/new', methods=['GET', 'POST'])
 def new_task_project(id_project):
 def new_task_project(id_project):
     if current_user.is_authenticated:
     if current_user.is_authenticated:
         data_session = db_session.create_session()
         data_session = db_session.create_session()
@@ -166,7 +256,11 @@ def project(id_project):
                     User.id.in_(list(map(lambda x: x.user, staff)))).all())) if staff else []
                     User.id.in_(list(map(lambda x: x.user, staff)))).all())) if staff else []
                 quests = data_session.query(Quests).filter(Quests.project == current_project.id).all()
                 quests = data_session.query(Quests).filter(Quests.project == current_project.id).all()
                 if quests:
                 if quests:
-                    quests.sort(key=lambda x: (x.realized, x.deadline))
+                    quests_sort = sorted(list(filter(lambda x: x.deadline is not None, quests)),
+                                         key=lambda x: (x.realized, x.deadline))
+                    quests = list(filter(lambda x: x.realized == 0, quests_sort)) + list(
+                        filter(lambda x: x.deadline is None, quests)) + list(
+                        filter(lambda x: x.realized == 1, quests_sort))
                     quests = list(map(lambda x: overdue_quest_project(x), quests))
                     quests = list(map(lambda x: overdue_quest_project(x), quests))
                 return render_template('project.html',
                 return render_template('project.html',
                                        project=current_project,
                                        project=current_project,

+ 0 - 0
static/app_files/all_projects/заглушка


+ 243 - 0
static/css/answer.css

@@ -0,0 +1,243 @@
+body {
+    background-color: #dcb495 !important;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+}
+.decision_page {
+    background-color: #dcb495;
+    min-height: 100vw;
+    height: auto;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    margin: 3vw;
+    margin-bottom: 20vw;
+}
+.link_back_block {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-direction: column;
+    flex-wrap: nowrap;
+}
+.link_back {
+    background-color: #ffffff;
+    color: #000000;
+    width: 15vw;
+    height: 4.5vw;
+    vertical-align: middle;
+    border-radius: 5vw;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+.link_back:hover {
+    text-decoration: none;
+    color: #000000;
+}
+.link_back_text {
+    font-size: 1.5vw;
+    margin-top: 15px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+.name_block {
+    margin-top: 3vw;
+    width: 90%;
+    height:  auto;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+.title_block {
+    width: 90%;
+    display: flex;
+    justify-content: center;
+}
+.title_task, .files_title {
+    text-align: center;
+    color: #000000;
+    font-size: 4vw;
+}
+.description_task {
+    width: 80%;
+    background-color: #EDCBB0;
+    height: auto;
+    max-height: 15vw;
+    border-radius: 2vw;
+    display: flex;
+    overflow-y: auto;
+}
+.description_task::-webkit-scrollbar {
+    width: 0.8vw !important;
+    height: auto;
+}
+.description_task::-webkit-scrollbar-thumb {
+    background-color: #d49d51 !important;    /* цвет плашки */
+    border-radius: 5vw !important;       /* закругления плашки */
+    border: 0.25vw solid #ffffff !important;
+}
+.description {
+    margin: 15px;
+}
+.description_text {
+    font-size: 1.5vw;
+    text-align: justify;
+}
+.data_block {
+    width: 100%;
+    display: flex;
+    align-items: flex-start;
+    justify-content: center
+}
+.bottom_data {
+    margin: 2vw;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+}
+.form_label {
+    margin-top: 10px;
+    font-size: 1.3vw;
+    color: #000000;
+    font-weight: bold;
+}
+.input_data {
+    color: #000000;
+    border: 0.1vw solid #595008;
+    height: 4.5vw;
+    min-height: 4.5vw;
+    width: 30vw;
+    background-color: #dbc3af;
+    border-radius: 5vw;
+    font-size: 1.3vw;
+    display: inline-flex;
+    align-items: center;
+}
+.input_button {
+    width: 10vw;
+    height: 5vw;
+    border-radius: 5vw;
+    vertical-align: middle;
+}
+.form_data {
+    display: flex;
+    flex-direction: column;
+    margin-left: 2%;
+}
+.decision_block {
+    margin-top: 3vw;
+    width: 90%;
+    height: 25vw;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+.padding_data {
+    padding: 1vw;
+}
+.quest_button {
+    color: #ffffff;
+    width: 13vw;
+    height: 5vw;
+    background-color: #000000;
+    border: 2px solid #ffffff;
+    border-radius: 3vw;
+    margin-left: 2vw;
+}
+form {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+.form_data_button {
+    margin-top: 20px;
+    display: flex;
+    width: 30vw;
+    align-items: center;
+    justify-content: space-between;
+}
+.deadline {
+    margin-top: 5px;
+}
+.text_data {
+    width: 80%;
+    border-radius: 2vw !important;
+    min-height: 10vw;
+    max-height: 20vw;
+}
+.form_text_one {
+    width: 100%;
+}
+.files_block {
+    width: 100%;
+    margin: 2vw;
+    background-color: #dbc3af;
+    display: flex;
+    flex-direction: column;
+    align-items: stretch;
+    border-radius: 2vw;
+    min-height: 25vw;
+}
+.files_list {
+    margin: 2vw;
+    height: auto;
+    overflow-y: auto;
+    overflow-x: hidden;
+}
+.files {
+    width: 80%;
+    margin: 2vw;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    min-height: 25vw;
+    max-height: 30vw;
+}
+.file {
+    width: 98%;
+    display: flex;
+    background-color: #694a2d;
+    margin: 0.5vw;
+    align-items: center;
+    justify-content: space-between;
+    flex-direction: row;
+    height: 4.5vw;
+    border-radius: 2vw;
+}
+.file_head {
+    width: 30vw;
+    margin-left: 1vw;
+    height: 4vw;
+    background-color: #694a2d !important;
+    overflow-y: hidden;
+    overflow-x: auto;
+}
+.file_head_path, .file_path {
+    font-size: 1.5vw;
+    color: #ffffff !important;
+    font-weight: bold;
+    height: 3vw;
+    display: flex;
+    align-items: flex-start;
+    background-color: #694a2d !important;
+}
+.file_buttons {
+    margin-right: 2vw; 
+}
+.file_delete, .file_download {
+    border-radius: 1vw !important;
+    margin: 1vw;
+    width: 8vw;
+    height: 3vw;
+}
+.file_delete {
+    background-color: hsla(0, 100%, 62%, 0.785) !important;
+    border-color: hsla(0, 100%, 62%, 0.785) !important;
+}
+.button_text {
+    font-size: 1.3vw;
+}

+ 0 - 124
static/css/decision.css

@@ -1,124 +0,0 @@
-.decision_page {
-    height: 90vw;
-    background-color: #dcb495;
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-}
-.link_back_block {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    flex-direction: column;
-    flex-wrap: nowrap;
-}
-.link_back {
-    background-color: #ffffff;
-    color: #000000;
-    width: 15vw;
-    height: 4.5vw;
-    vertical-align: middle;
-    border-radius: 5vw;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-}
-.link_back:hover {
-    text-decoration: none;
-    color: #000000;
-}
-.link_back_text {
-    font-size: 1.5vw;
-    margin-top: 15px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-}
-.name_block {
-    margin-top: 3vw;
-    width: 90%;
-    height: 25vw;
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-}
-.title_block {
-    width: 90%;
-    display: flex;
-    justify-content: center;
-}
-.title_task {
-    text-align: center;
-    color: #000000;
-    font-size: 4vw;
-}
-.description_task {
-    width: 80%;
-    background-color: #EDCBB0;
-    height: auto;
-    max-height: 15vw;
-    border-radius: 2vw;
-    display: flex;
-    overflow-y: auto;
-}
-.description {
-    margin: 15px;
-}
-.description_text {
-    font-size: 1.5vw;
-    text-align: justify;
-}
-.data_block {
-    width: 90%;
-    display: flex;
-    align-items: flex-start;
-    justify-content: center
-}
-.bottom_data {
-    margin: 2vw;
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-}
-.form_label {
-    margin-top: 10px;
-    font-size: 1.3vw;
-    color: #000000;
-    font-weight: bold;
-}
-.input_data {
-    color: #000000;
-    border: 0.1vw solid #595008;
-    height: 4.5vw;
-    min-height: 4.5vw;
-    width: 30vw;
-    background-color: #dbc3af;
-    border-radius: 5vw;
-    font-size: 1.3vw;
-    display: inline-flex;
-    align-items: center;
-}
-.input_button {
-    width: 10vw;
-    height: 5vw;
-    border-radius: 5vw;
-    vertical-align: middle;
-}
-.text_data {
-    border-radius: 2vw !important;
-    width: 35vw;
-}
-.form_data {
-    display: flex;
-    flex-direction: column;
-    margin-left: 2%;
-}
-.decision_block {
-    margin-top: 3vw;
-    width: 90%;
-    height: 25vw;
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-}

+ 2 - 1
static/js/project.js

@@ -2,6 +2,7 @@ var edit_button = document.getElementById("edit_button"),
 new_task_link = document.getElementById("new_task_link"),
 new_task_link = document.getElementById("new_task_link"),
 quest_solve_link = document.getElementById("quest_solve_link"),
 quest_solve_link = document.getElementById("quest_solve_link"),
 quest_solve_link_id = document.getElementById("quest_solve_link_id");
 quest_solve_link_id = document.getElementById("quest_solve_link_id");
+
 edit_button.href = String(window.location.href) + '/edit';
 edit_button.href = String(window.location.href) + '/edit';
-new_task_link.href = String(window.location.href) + '/task/new';
+new_task_link.href = String(window.location.href) + '/quest/new';
 quest_solve_link.href = String(window.location.href) + '/quest/' + quest_solve_link_id.className;
 quest_solve_link.href = String(window.location.href) + '/quest/' + quest_solve_link_id.className;

+ 94 - 0
templates/answer.html

@@ -0,0 +1,94 @@
+<link rel="stylesheet" href="../../../static/css/answer.css"/>
+{% extends "base.html" %} {% block content %}
+<div class="decision_page">
+    <div class="link_back_block">
+        <a class="link_back" href="../../../project/{{ project.id }}">
+            <p class="link_back_text">К проекту</p>
+        </a>
+    </div>
+    <div class="name_block">
+        <div class="title_block">
+            <h3 class="title_task">{{ task.name }}</h3>
+        </div>
+        <div class="description_task">
+            <div class="description">
+                <p class="description_text">{{ task.description }}</p>
+            </div>
+        </div>
+        {% if list_files %}
+        <div class="files">
+            <h2 class="files_title">Файлы</h2>
+            <div class="files_block">
+                <div class="files_list">
+                    {% for file in list_files %}
+                    <div class="file">
+                        <div class="file_head">
+                            <nav class="file_head_group" style="--bs-breadcrumb-divider: '>';" aria-label="breadcrumb">
+                                <ol class="breadcrumb file_head_path">
+                                    {% for path in file['current_path'] %}
+                                    <li class="breadcrumb-item active file_path" aria-current="page">{{ path }}</li>
+                                    {% endfor %}
+                                </ol>
+                            </nav>
+                        </div>
+                        <div class="file_buttons">
+                            <div class="btn-group file_buttons_groud">
+                                {% if current_user.id == project.creator or task.creator == current_user.id or file.user == current_user.id %}
+                                <a href="../file/{{ file.id }}/delete" class="btn btn-primary file_delete"><p class="button_text">Удалить</p></a>
+                                {% endif %}
+                                <a href="../../../{{ file['path'] }}" download="" class="btn btn-primary file_download"><p class="button_text">Скачать</p></a>
+                            </div>
+                        </div>
+                    </div>
+                    {% endfor %}
+                </div>
+            </div>
+        </div>
+        {% endif %}
+        <div class="form_data bottom_data form_text_one">
+            <label class="form_label">{{ form.text.label }}</label>
+            {{ form.text(class="input_data text_data", type="text", id="text_data", placeholder='your answer') }}
+            {% for error in form.text.errors %}
+            <div class="alert alert-danger" role="alert">{{ error }}</div>
+            {% endfor %}
+        </div>
+    </div>
+    <div class="decision_block">
+        <form action="" method="post" class="answer_form" enctype="multipart/form-data">
+            {{ form.hidden_tag() }}
+            <div class="data_block">
+                <div class="form_data bottom_data">
+                    <label class="form_label">{{ form.file.label }}</label>
+                    {{ form.file(class="input_data padding_data", type="file") }}
+                    {% for error in form.file.errors %}
+                    <div class="alert alert-danger" role="alert">{{ error }}</div>
+                    {% endfor %}
+                </div>
+            </div>
+            {% if current_user.id == project.creator %}
+            <div class="form_data">
+                <label class="form_label">{{ form.deadline_date.label }}</label>
+                {{ form.deadline_date(class="input_data deadline padding_data", type="date") }}
+                {% for error in form.deadline_date.errors %}
+                <div class="alert alert-danger" role="alert">{{ error }}</div>
+                {% endfor %}
+                {{ form.deadline_time(class="input_data deadline padding_data", type="time") }}
+                {% for error in form.deadline_time.errors %}
+                <div class="alert alert-danger" role="alert">{{ error }}</div>
+                {% endfor %}
+            </div>
+            {% endif %}
+            <div class="form_data_button">
+                {{ form.submit(type="submit", class="quest_button") }}
+                <div class="box">
+                    {{ form.realized(class="realized")}}
+                    {{form.realized.label }}<br/>
+                    {% for error in form.realized.errors %}
+                    <div class="alert alert-danger" role="alert">{{ error }}</div>
+                    {% endfor %}
+                </div>
+            </div>
+        </form>
+    </div>
+</div>
+{% endblock %}

+ 0 - 41
templates/decision.html

@@ -1,41 +0,0 @@
-<link rel="stylesheet" href="../../../static/css/decision.css"/>
-{% extends "base.html" %} {% block content %}
-<div class="decision_page">
-    <div class="link_back_block">
-        <a class="link_back" href="../../../project/{{ project.id }}">
-            <p class="link_back_text">К проекту</p>
-        </a>
-    </div>
-    <div class="name_block">
-        <div class="title_block">
-            <h3 class="title_task">{{ task.name }}</h3>
-        </div>
-        <div class="description_task">
-            <div class="description">
-                <p class="description_text">{{ task.description }}</p>
-            </div>
-        </div>
-    </div>
-    <div class="decision_block">
-        <form action="" method="post" class="answer_form" enctype="multipart/form-data">
-            {{ form.hidden_tag() }}
-            <div class="data_block">
-                <div class="form_data bottom_data">
-                    <label class="form_label">{{ form.text.label }}</label>
-                    {{ form.text(class="input_data label_data text_data", type="text", placeholder='your answer') }}
-                    {% for error in form.text.errors %}
-                    <div class="alert alert-danger" role="alert">{{ error }}</div>
-                    {% endfor %}
-                </div>
-                <div class="form_data bottom_data">
-                    <label class="form_label">{{ form.file.label }}</label>
-                    {{ form.file(class="input_data padding_data", type="file") }}
-                    {% for error in form.file.errors %}
-                    <div class="alert alert-danger" role="alert">{{ error }}</div>
-                    {% endfor %}
-                </div>
-            </div>
-        </form>
-    </div>
-</div>
-{% endblock %}

+ 1 - 2
templates/login.html

@@ -32,8 +32,7 @@
                     </div>
                     </div>
                 </div>
                 </div>
                 <div class="box">
                 <div class="box">
-                    {{ form.remember_me(class="remember")}} {{
-                    form.remember_me.label }}<br/>
+                    {{ form.remember_me(class="remember")}} {{form.remember_me.label }}<br/>
                     {% for error in form.remember_me.errors %}
                     {% for error in form.remember_me.errors %}
                     <div class="alert alert-danger" role="alert">{{ error }}</div>
                     <div class="alert alert-danger" role="alert">{{ error }}</div>
                     {% endfor %}
                     {% endfor %}

+ 18 - 3
templates/project.html

@@ -72,6 +72,10 @@
                                     <div class="deadline_block alert alert-success" role="alert">
                                     <div class="deadline_block alert alert-success" role="alert">
                                         {{ quest.time_left }}
                                         {{ quest.time_left }}
                                     </div>
                                     </div>
+                                    {% elif quest.overdue == '' and quest.realized != 1 %}
+                                    <div class="deadline_block alert alert-warning" role="alert">
+                                        Дедлайна нет
+                                    </div>
                                     {% else %}
                                     {% else %}
                                     <div class="deadline_block alert alert-success" role="alert">
                                     <div class="deadline_block alert alert-success" role="alert">
                                         Задача выполнена
                                         Задача выполнена
@@ -92,14 +96,25 @@
                                             </div>
                                             </div>
                                         </div>
                                         </div>
                                         <div class="quest_solve_button">
                                         <div class="quest_solve_button">
-                                            <a class="quest_solve_link" id="quest_solve_link">
-                                                <p id="quest_solve_link_id" class="{{ quest.id }}"></p>
+                                            <a class="quest_solve_link" href="{{ project.id }}/quest/{{ quest.id }}">
                                                 <p class="quest_solve_text">Решить</p>
                                                 <p class="quest_solve_text">Решить</p>
                                             </a>
                                             </a>
                                         </div>
                                         </div>
                                     </div>
                                     </div>
                                     {% else %}
                                     {% else %}
-
+                                    <div class="quest_body">
+                                        <div class="quest_description_block">
+                                            <p class="quest_description_title">Описание</p>
+                                            <div class="quest_description">
+                                                <p class="quest_description_text">{{ quest.description }}</p>
+                                            </div>
+                                        </div>
+                                        <div class="quest_solve_button">
+                                            <a class="quest_solve_link" href="{{ project.id }}/quest/{{ quest.id }}">
+                                                <p class="quest_solve_text">Посмотреть</p>
+                                            </a>
+                                        </div>
+                                    </div>
                                     {% endif %}
                                     {% endif %}
                                 </div>
                                 </div>
                             </div>
                             </div>