Добавил возможность редактировать и удалять задачи

This commit is contained in:
Andrei 2023-02-28 22:39:11 +05:00
parent 913871fc47
commit 2f65e8a0dc
14 changed files with 347 additions and 56 deletions

View File

@ -4,18 +4,18 @@ from wtforms import StringField, SubmitField, TextAreaField, DateField, TimeFiel
from wtforms.validators import DataRequired from wtforms.validators import DataRequired
class NewTask(FlaskForm): class Task(FlaskForm):
name = StringField('Название', validators=[DataRequired()]) name = StringField('Название', validators=[DataRequired()])
description = TextAreaField('Описание', validators=[DataRequired()]) description = TextAreaField('Описание', validators=[DataRequired()])
deadline_date = DateField('Дедлайн', validators=[DataRequired()]) deadline_date = DateField('Дедлайн', validators=[DataRequired()])
deadline_time = TimeField('', validators=[DataRequired()]) deadline_time = TimeField('', validators=[DataRequired()])
submit = SubmitField('Создать') submit = SubmitField('Создать')
save = SubmitField('Сохранить')
delete = SubmitField('Удалить')
class AnswerTask(FlaskForm): class AnswerTask(FlaskForm):
text = TextAreaField('Письменный ответ') text = TextAreaField('Письменный ответ')
file = MultipleFileField('Файловый ответ') file = MultipleFileField('Добавить файлы')
realized = BooleanField('Задача решена') realized = BooleanField('Задача решена')
deadline_date = DateField('Дедлайн', validators=[DataRequired()])
deadline_time = TimeField('', validators=[DataRequired()])
submit = SubmitField('Сохранить') submit = SubmitField('Сохранить')

63
main.py
View File

@ -14,7 +14,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, save_proof_quest, find_files_answer, file_tree, delete_project_data overdue_quest_project, save_proof_quest, find_files_answer, file_tree, delete_project_data, delete_quest_data
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
@ -22,7 +22,7 @@ from forms.register import RegisterForm
from forms.project import ProjectForm, AddFileProject from forms.project import ProjectForm, AddFileProject
from forms.recovery import RecoveryForm, NewPasswordForm from forms.recovery import RecoveryForm, NewPasswordForm
from forms.conf_delete_project import DeleteProjectForm from forms.conf_delete_project import DeleteProjectForm
from forms.task import NewTask, AnswerTask from forms.task import Task, AnswerTask
from data.users import User from data.users import User
from data.quests import Quests from data.quests import Quests
@ -56,6 +56,43 @@ def base():
return redirect('/projects') return redirect('/projects')
@app.route('/project/<int:id_project>/quest/<int:id_task>/edit', methods=['GET', 'POST'])
def edit_quest(id_project, id_task):
if current_user.is_authenticated:
data_session = db_session.create_session()
current_project = data_session.query(Projects).filter(Projects.id == id_project).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 and (
current_task.creator == current_user.id or current_project.creator == current_user.id):
form = Task()
if request.method == 'GET':
form.name.data = current_task.name
form.description.data = current_task.description
form.deadline_time.data = current_task.deadline.time()
form.deadline_date.data = current_task.deadline.date()
if form.delete.data:
delete_quest_data(current_task, data_session)
data_session.delete(current_task)
data_session.commit()
return redirect(f'/project/{str(current_project.id)}')
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.name = form.name.data if form.name.data else None
current_task.description = form.description.data if form.description.data else None
current_task.deadline = deadline
data_session.commit()
return redirect(f'/project/{str(current_project.id)}')
return render_template('edit_task.html', title='Редактирование задачи', form=form, porject=current_project,
task=current_task)
else:
abort(403)
else:
return redirect('/login')
@app.route('/project/<int:id_project>/file/<int:id_file>/delete') @app.route('/project/<int:id_project>/file/<int:id_file>/delete')
def delete_file(id_project, id_file): def delete_file(id_project, id_file):
if current_user.is_authenticated: if current_user.is_authenticated:
@ -98,11 +135,6 @@ def task_project(id_project, id_task):
current_answer = data_session.query(Answer).filter(Answer.quest == current_task.id).first() current_answer = data_session.query(Answer).filter(Answer.quest == current_task.id).first()
list_files = None list_files = None
if form.submit.data and request.method == 'POST': if form.submit.data and request.method == 'POST':
if form.deadline_date.data and form.deadline_time.data:
deadline = datetime.datetime.combine(form.deadline_date.data, form.deadline_time.data)
else:
deadline = current_task.deadline
current_task.deadline = deadline
if current_answer: if current_answer:
current_answer.text = form.text.data current_answer.text = form.text.data
current_answer.date_edit = datetime.datetime.now() current_answer.date_edit = datetime.datetime.now()
@ -152,9 +184,6 @@ def task_project(id_project, id_task):
files = data_session.query(FileProof).filter(FileProof.answer == current_answer.id).all() files = data_session.query(FileProof).filter(FileProof.answer == current_answer.id).all()
if files: if files:
list_files = list(map(lambda x: find_files_answer(x.file), files)) list_files = list(map(lambda x: find_files_answer(x.file), files))
if current_task.deadline and current_task.deadline and request.method == 'GET':
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, return render_template('answer.html', title='Решение', project=current_project, task=current_task,
form=form, list_files=list_files) form=form, list_files=list_files)
else: else:
@ -169,7 +198,7 @@ def new_task_project(id_project):
data_session = db_session.create_session() data_session = db_session.create_session()
current_project = data_session.query(Projects).filter(Projects.id == id_project).first() current_project = data_session.query(Projects).filter(Projects.id == id_project).first()
if current_project: if current_project:
form = NewTask() form = Task()
if form.validate_on_submit(): if form.validate_on_submit():
if form.deadline_date.data and form.deadline_time.data: if form.deadline_date.data and form.deadline_time.data:
deadline = datetime.datetime.combine(form.deadline_date.data, form.deadline_time.data) deadline = datetime.datetime.combine(form.deadline_date.data, form.deadline_time.data)
@ -386,28 +415,28 @@ def new_project():
list_users = list( list_users = list(
map(lambda x: get_user_data(x), data_session.query(User).filter(User.id != current_user.id).all())) map(lambda x: get_user_data(x), data_session.query(User).filter(User.id != current_user.id).all()))
if form.validate_on_submit(): if form.validate_on_submit():
currnet_project = Projects( current_project = Projects(
name=form.name.data, name=form.name.data,
description=form.description.data, description=form.description.data,
date_create=datetime.datetime.now(), date_create=datetime.datetime.now(),
creator=current_user.id creator=current_user.id
) )
currnet_project.photo = save_project_logo( current_project.photo = save_project_logo(
form.logo.data) if form.logo.data else 'static/images/none_project.png' form.logo.data) if form.logo.data else 'static/images/none_project.png'
data_session.add(currnet_project) data_session.add(current_project)
data_session.flush() data_session.flush()
data_session.refresh(currnet_project) data_session.refresh(current_project)
for i in list_users: for i in list_users:
if request.form.getlist(f"choose_{i['login']}") and i['id'] != current_user.id: if request.form.getlist(f"choose_{i['login']}") and i['id'] != current_user.id:
new_staffer = StaffProjects( new_staffer = StaffProjects(
user=i['id'], user=i['id'],
project=currnet_project.id, project=current_project.id,
role='user', role='user',
permission=3 permission=3
) )
data_session.add(new_staffer) data_session.add(new_staffer)
data_session.commit() data_session.commit()
os.mkdir(f'static/app_files/all_projects/{str(currnet_project.id)}') os.mkdir(f'static/app_files/all_projects/{str(current_project.id)}')
return redirect('/projects') return redirect('/projects')
return render_template('new_project.html', title='Новый проект', form=form, list_users=list_users) return render_template('new_project.html', title='Новый проект', form=form, list_users=list_users)
else: else:

View File

@ -15,12 +15,46 @@ body {
margin-bottom: 20vw; margin-bottom: 20vw;
} }
.link_back_block { .link_back_block {
margin-right: 0.5vw;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
flex-wrap: nowrap; flex-wrap: nowrap;
} }
.head_buttons_block {
display: flex;
flex-direction: row;
}
.link_edit_block {
margin-left: 0.5vw;
background-color: #9E795A;
border: #9E795A;
width: 13vw;
height: 4.5vw;
color: #ffffff;
border-radius: 5vw;
vertical-align: middle;
font-size: 1.5vw;
}
.link_edit {
width: 13vw;
height: 4.5vw;
}
.link_edit:hover {
text-decoration: none;
color: #000000;
}
.link_edit_text {
width: 13vw;
height: 4.5vw;
text-align: center;
font-size: 1.5vw;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
.link_back { .link_back {
background-color: #ffffff; background-color: #ffffff;
color: #000000; color: #000000;
@ -60,6 +94,9 @@ body {
text-align: center; text-align: center;
color: #000000; color: #000000;
font-size: 4vw; font-size: 4vw;
max-width: 80%;
overflow-x: auto;
overflow-y: hidden;
} }
.description_task { .description_task {
width: 80%; width: 80%;

View File

@ -12,6 +12,7 @@ body {
height: 8vw; height: 8vw;
} }
#navbar { #navbar {
margin-top: -80px;
position: fixed; position: fixed;
width: 100%; width: 100%;
transition: top 0.3s; transition: top 0.3s;

View File

@ -147,3 +147,33 @@
justify-content: center; justify-content: center;
margin-top: 10px; margin-top: 10px;
} }
.link_back_block {
margin-right: 0.5vw;
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;
}

106
static/css/edit_task.css Normal file
View File

@ -0,0 +1,106 @@
.new_task_page {
height: 50vw;
background-color: #dcb495;
}
.form_data {
display: flex;
flex-direction: column;
margin-left: 2%;
}
.form_block {
display: flex;
align-items: center;
justify-content: center;
}
.form_data_button {
margin-top: 2.5vw;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.input_data {
color: #000000;
border: 0.1vw solid #595008;
height: 4.5vw;
min-height: 4.5vw;
width: 50vw;
background-color: #dbc3af;
border-radius: 4.5vw;
font-size: 1.3vw;
display: inline-flex;
align-items: center;
}
.form_label {
margin-top: 10px;
font-size: 1.3vw;
color: #ffffff;
font-weight: bold;
}
.description {
border-radius: 2vw !important;
width: 50vw;
max-height: 10vw !important;
}
.name_form_block {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.deadline {
width: 20vw;
}
.quest_button {
margin-top: 1vw;
margin-left: 5vw;
width: 20vw;
height: 5vw;
background-color: #000000;
color: #ffffff;
border-radius: 5vw;
vertical-align: middle;
font-size: 1.5vw;
}
.data_form_block {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.deadline {
margin: 5px;
}
.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;
}
.delete_project_link {
background-color: #ff3f3f;
border: #ff3f3f;
}

View File

@ -39,6 +39,7 @@
.description { .description {
border-radius: 2vw !important; border-radius: 2vw !important;
width: 50vw; width: 50vw;
max-height: 10vw;
} }
.name_form_block { .name_form_block {
width: 100%; width: 100%;

View File

@ -22,6 +22,7 @@
} }
.brand_block { .brand_block {
height: 25vw; height: 25vw;
margin-left: -8vw;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
@ -38,15 +39,30 @@
justify-content: center; justify-content: center;
} }
.edit_button { .edit_button {
width: 4.5vw; background-color: #9E795A;
height: 4.5vw; border: #9E795A;
width: 12vw;
height: 5vw;
color: #ffffff;
border-radius: 5vw;
vertical-align: middle;
font-size: 1.5vw;
}
.edit_button_text {
color: #ffffff;
height: 5vw;
margin-top: 32%;
}
.edit_button_link {
width: 12vw;
height: 5vw;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.edit_button_image { .edit_button_link:hover {
height: 3vw; text-decoration: none;
width: 3vw; color: #ffffff;
} }
.collaborator_block { .collaborator_block {
width: 95%; width: 95%;
@ -140,12 +156,32 @@
flex-direction: row; flex-direction: row;
} }
.new_task_block { .new_task_block {
width: 4.5vw; width: 13vw;
height: 4.5vw; height: 5vw;
background-color: #000000;
border: 2px solid #ffffff;
border-radius: 3vw;
margin-left: 2vw;
margin-bottom: 0.5vw;
} }
.new_task_link { .new_task_link {
width: 4.5vw; color: #ffffff;
height: 4.5vw; width: 13vw;
height: 5vw;
}
.new_task_link:hover {
text-decoration: none;
color: #ffffff;
}
.new_task_text {
width: 13vw;
height: 5vw;
text-align: center;
font-size: 1.5vw;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
} }
.new_task_image { .new_task_image {
width: 4.5vw; width: 4.5vw;

View File

@ -252,7 +252,7 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.new_project_button_lin, find_project_button_linkk { .new_project_button_link, find_project_button_linkk {
width: 13vw; width: 13vw;
height: 5vw; height: 5vw;
} }

View File

@ -1,10 +1,19 @@
<link rel="stylesheet" href="../../../static/css/answer.css"/> <link rel="stylesheet" href="../../../static/css/answer.css"/>
{% extends "base.html" %} {% block content %} {% extends "base.html" %} {% block content %}
<div class="decision_page"> <div class="decision_page">
<div class="link_back_block"> <div class="head_buttons_block">
<a class="link_back" href="../../../project/{{ project.id }}"> <div class="link_back_block">
<p class="link_back_text">К проекту</p> <a class="link_back" href="../../../project/{{ project.id }}">
</a> <p class="link_back_text">К проекту</p>
</a>
</div>
{% if task.creator == current_user.id or project.creator == current_user.id %}
<div class="link_edit_block">
<a class="link_edit" href="{{ task.id }}/edit">
<p class="link_edit_text">Редактировать</p>
</a>
</div>
{% endif %}
</div> </div>
<div class="name_block"> <div class="name_block">
<div class="title_block"> <div class="title_block">
@ -68,19 +77,6 @@
{% endfor %} {% endfor %}
</div> </div>
</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"> <div class="form_data_button">
{{ form.submit(type="submit", class="quest_button") }} {{ form.submit(type="submit", class="quest_button") }}
<div class="box"> <div class="box">

View File

@ -2,7 +2,7 @@
<html lang="ru"> <html lang="ru">
<head> <head>
<meta charset="UTF-8"/> <meta charset="UTF-8"/>
<link rel="stylesheet" href="../../../static/css/base.css"/> <link rel="stylesheet" href="../../../../static/css/base.css"/>
<link <link
rel="stylesheet" rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
@ -41,7 +41,7 @@
<nav class="navbar" id="navbar"> <nav class="navbar" id="navbar">
<div class="container-fluid"> <div class="container-fluid">
<a class="navbar-brand" href="/"> <a class="navbar-brand" href="/">
<img src="../../../static/images/logo_b.png" class="nav_logo"/> <img src="../../../../static/images/logo_b.png" class="nav_logo"/>
</a> </a>
<a class="auth_button" href="/login">Авторизация</a> <a class="auth_button" href="/login">Авторизация</a>
</div> </div>
@ -52,7 +52,7 @@
<footer class="footer"> <footer class="footer">
<div class="footer_block"> <div class="footer_block">
<a href="/#header_block" <a href="/#header_block"
><img class="footer_logo" src="../../../static/images/logo_w.png" ><img class="footer_logo" src="../../../../static/images/logo_w.png"
/></a> /></a>
<strong class="footer_rights">© All rights reserved</strong> <strong class="footer_rights">© All rights reserved</strong>
</div> </div>

View File

@ -1,6 +1,11 @@
<link rel="stylesheet" href="../../static/css/edit_project.css"/> <link rel="stylesheet" href="../../static/css/edit_project.css"/>
{% extends "base.html" %} {% block content %} {% extends "base.html" %} {% block content %}
<div class="edit_project_page"> <div class="edit_project_page">
<div class="link_back_block">
<a class="link_back" href="../../../project/{{ project.id }}">
<p class="link_back_text">К проекту</p>
</a>
</div>
<div class="form_block"> <div class="form_block">
<form action="" method="post" class="register_form" enctype="multipart/form-data"> <form action="" method="post" class="register_form" enctype="multipart/form-data">
{{ form.hidden_tag() }} {{ form.hidden_tag() }}

48
templates/edit_task.html Normal file
View File

@ -0,0 +1,48 @@
<link rel="stylesheet" href="../../../../static/css/edit_task.css"/>
{% extends "base.html" %} {% block content %}
<div class="new_task_page">
<div class="link_back_block">
<a class="link_back" href="../{{ task.id }}">
<p class="link_back_text">К задаче</p>
</a>
</div>
<div class="form_block">
<form action="" method="post" class="new_task_form" enctype="multipart/form-data">
{{ form.hidden_tag() }}
<div class="name_form_block">
<div class="form_data">
<label class="form_label">{{ form.name.label }}</label>
{{ form.name(class="input_data label_data", type="name", placeholder='your project name') }}
{% for error in form.name.errors %}
<div class="alert alert-danger" role="alert">{{ error }}</div>
{% endfor %}
</div>
<div class="form_data">
<label class="form_label">{{ form.description.label }}</label>
{{ form.description(class="input_data description padding_data", type="description", placeholder='your project description') }}
{% for error in form.description.errors %}
<div class="alert alert-danger" role="alert">{{ error }}</div>
{% endfor %}
</div>
</div>
<div class="data_form_block">
<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>
<div class="form_data_button">
{{ form.save(type="submit", class="quest_button") }}
{{ form.delete(type="submit", class="quest_button delete_project_link") }}
</div>
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -9,11 +9,13 @@
<div class="project_header"> <div class="project_header">
<div class="edit_block"> <div class="edit_block">
{% if current_user.id == project.creator %} {% if current_user.id == project.creator %}
<a id="edit_button" class="edit_button" href=""> <div class="edit_button">
<img class="edit_button_image" src="../static/images/pen_b.png"> <a id="edit_button" class="edit_button_link" href="">
</a> <p class="edit_button_text">Редактировать</p>
</a>
</div>
{% else %} {% else %}
<p class="edit_button"> </p> <p style="width: 12vw;"> </p>
{% endif %} {% endif %}
</div> </div>
<div class="brand_block"> <div class="brand_block">
@ -45,7 +47,7 @@
<h3 class="header_title_2">Задачи</h3> <h3 class="header_title_2">Задачи</h3>
<div class="new_task_block"> <div class="new_task_block">
<a class="new_task_link" id="new_task_link" href="/"> <a class="new_task_link" id="new_task_link" href="/">
<img class="new_task_image" src="../static/images/plus_b.png"> <p class="new_task_text">Добавить</p>
</a> </a>
</div> </div>
</div> </div>