Создана страница редактирования информации и удаления проекта, создал таблицу с "задачами"

This commit is contained in:
Andrei 2023-01-29 23:44:12 +05:00
parent b0837ce46f
commit 1239819eca
14 changed files with 436 additions and 27 deletions

View File

@ -1,5 +1,6 @@
import sqlalchemy
from flask_login import UserMixin
from datetime import date
from .db_session import SqlAlchemyBase

View File

@ -0,0 +1,8 @@
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
class DeleteProjectForm(FlaskForm):
conf = StringField('', validators=[DataRequired()])
submit = SubmitField('Подтвердить')

View File

@ -3,8 +3,10 @@ from wtforms import StringField, SubmitField, TextAreaField, FileField
from wtforms.validators import DataRequired
class NewProjectForm(FlaskForm):
class ProjectForm(FlaskForm):
name = StringField('Название', validators=[DataRequired()])
description = TextAreaField('Описание')
logo = FileField('Логотип')
submit = SubmitField('Создать')
del_photo = SubmitField('Удалить фотографию')
save = SubmitField('Сохранить')

105
main.py
View File

@ -15,8 +15,9 @@ from forms.edit_profile import EditProfileForm
from forms.login import LoginForm
from forms.find_project import FindProjectForm
from forms.register import RegisterForm
from forms.new_project import NewProjectForm
from forms.project import ProjectForm
from forms.recovery import RecoveryForm, NewPasswordForm
from forms.conf_delete_project import DeleteProjectForm
from data.users import User
from data.quests import Quests
@ -43,6 +44,63 @@ def base():
return redirect('/projects')
@app.route('/project/<int:id_project>/edit', methods=['GET', 'POST'])
def edit_project(id_project):
if current_user.is_authenticated:
data_session = db_session.create_session()
current_project = data_session.query(Projects).filter(Projects.id == id_project).first()
if current_project:
staff = data_session.query(StaffProjects).filter(StaffProjects.project == current_project.id).all()
if current_user.id == current_project.creator or current_user.id in list(map(lambda x: x.user, staff)):
list_users = list(
map(lambda x: get_user_data(x), data_session.query(User).filter(User.id != current_user.id).all()))
staff = list(map(lambda x: get_user_data(x), data_session.query(User).filter(
User.id.in_(list(map(lambda x: x.user, staff)))).all())) if staff else []
form = ProjectForm()
if form.save.data:
new_staff = []
for i in list_users:
if request.form.getlist(f"choose_{i['login']}") and i['id'] != current_user.id:
new_staff.append(i)
if i not in staff:
new_staffer = StaffProjects(
user=i['id'],
project=current_project.id,
role='user',
permission=3
)
data_session.add(new_staffer)
data_session.commit()
if sorted(new_staff, key=lambda x: x['id']) != sorted(staff, key=lambda x: x['id']):
for i in staff:
if i not in new_staff:
data_session.delete(data_session.query(StaffProjects).filter(
StaffProjects.user == i['id'], StaffProjects.project == current_project.id).first())
data_session.commit()
if form.logo.data:
current_project.photo = save_project_logo(form.logo.data)
data_session.commit()
current_project.name = form.name.data
current_project.description = form.description.data
data_session.commit()
return redirect(f'/project/{current_project.id}/edit')
if form.del_photo.data:
os.remove(current_project.photo)
current_project.photo = 'static/images/none_project.png'
data_session.commit()
return redirect(f'/project/{current_project.id}/edit')
form.name.data = current_project.name
form.description.data = current_project.description
return render_template('edit_project.html', title='Изменение проекта', form=form, list_users=list_users,
staff=staff, project=current_project)
else:
abort(403)
else:
abort(404)
else:
return redirect('/login')
@app.route('/project/<int:id_project>')
def project(id_project):
if current_user.is_authenticated:
@ -51,6 +109,7 @@ def project(id_project):
if current_project:
staff = data_session.query(StaffProjects).filter(StaffProjects.project == current_project.id).all()
if current_user.id == current_project.creator or current_user.id in list(map(lambda x: x.user, staff)):
return render_template('project.html', project=current_project, title=current_project.name)
else:
abort(403)
@ -103,22 +162,29 @@ def recovery():
return redirect('/')
@app.route('/projects/delete/<int:id_project>', methods=['GET', 'POST'])
@app.route('/project/<int:id_project>/delete', methods=['GET', 'POST'])
def delete_project(id_project):
if current_user.is_authenticated:
data_session = db_session.create_session()
project_del = data_session.query(Projects).filter(Projects.id == id_project).first()
if project_del:
if project_del.creator == current_user.id:
staff = data_session.query(StaffProjects).filter(StaffProjects.project == id_project).all()
for i in staff:
data_session.delete(i)
if 'none_project' not in project_del.photo:
os.remove(project_del.photo)
data_session.delete(project_del)
data_session.commit()
data_session.close()
return redirect('/projects')
form = DeleteProjectForm()
if form.validate_on_submit():
if form.conf.data != f'delete/{project_del.name}':
return render_template('delete_project.html', title='Удаление проекта', form=form,
project=project_del,
message='Вы не правильно ввели фразу')
staff = data_session.query(StaffProjects).filter(StaffProjects.project == id_project).all()
for i in staff:
data_session.delete(i)
if 'none_project' not in project_del.photo:
os.remove(project_del.photo)
data_session.delete(project_del)
data_session.commit()
return redirect('/projects')
return render_template('delete_project.html', title='Удаление проекта', form=form, project=project_del,
message='')
else:
abort(403)
else:
@ -149,7 +215,7 @@ def user_view(_login):
@app.route('/projects/new', methods=['GET', 'POST'])
def new_project():
if current_user.is_authenticated:
form = NewProjectForm()
form = ProjectForm()
data_session = db_session.create_session()
list_users = list(
map(lambda x: get_user_data(x), data_session.query(User).filter(User.id != current_user.id).all()))
@ -175,9 +241,7 @@ def new_project():
)
data_session.add(new_staffer)
data_session.commit()
data_session.close()
return redirect('/projects')
data_session.close()
return render_template('new_project.html', title='Новый проект', form=form, list_users=list_users)
else:
return redirect('/login')
@ -231,7 +295,6 @@ def profile():
os.remove(current_user.photo)
user.photo = 'static/images/none_logo.png'
data_session.commit()
data_session.close()
if form.validate_on_submit():
data_session = db_session.create_session()
user = data_session.query(User).filter(User.id == current_user.id).first()
@ -249,7 +312,6 @@ def profile():
user.about = form.about.data
user.birthday = form.birthday.data
data_session.commit()
data_session.close()
return redirect('/profile')
return render_template('profile.html', title='Профиль', form=form, message='')
else:
@ -273,7 +335,6 @@ def login():
user = data_session.query(User).filter(User.email == form.login.data).first()
if not user:
user = data_session.query(User).filter(User.login == form.login.data).first()
data_session.close()
if user and user.check_password(form.password.data):
if user.activated:
login_user(user, remember=form.remember_me.data)
@ -326,7 +387,6 @@ def register():
user.set_password(form.password.data)
data_session.add(user)
data_session.commit()
data_session.close()
token = s.dumps(form.email.data)
link_conf = url_for('confirmation', token=token, _external=True)
mail(f'Для завершения регистрации пройдите по ссылке: {link_conf}', form.email.data,
@ -346,7 +406,6 @@ def confirmation(token):
if user:
user.activated = True
data_session.commit()
data_session.close()
return redirect('/login?message=Почта успешно подтверждена')
else:
return redirect('/login?message=Пользователь не найден&danger=True')
@ -357,17 +416,21 @@ def confirmation(token):
if users:
list(map(lambda x: data_session.delete(x), users))
data_session.commit()
data_session.close()
return redirect('/login?message=Срок действия ссылки истек, данные удалены&danger=True')
@app.errorhandler(500)
def internal_server_error(error):
return render_template('page_error.html', title='Ошибка сервера', error='500', message='Технические шоколадки')
@app.errorhandler(404)
def page_not_found(error):
return render_template('page_error.html', title='Страница не найдена', error='404', message='Страница не найдена')
@app.errorhandler(403)
def page_not_found(error):
def access_error(error):
return render_template('page_error.html', title='Ошибка доступа', error='403', message='Доступ сюда запрещен')

View File

@ -62,7 +62,7 @@ body {
align-items: center;
}
.nav_user_name {
margin-left: 10px;
margin-left: 1vw;
align-self: center;
}
.nav_chapter_text {
@ -90,10 +90,10 @@ body {
height: 100%;
}
body::-webkit-scrollbar {
width: 12px; /* ширина scrollbar */
width: 0.8vw; /* ширина scrollbar */
}
body::-webkit-scrollbar-thumb {
background-color: #d49d51; /* цвет плашки */
border-radius: 20px; /* закругления плашки */
border: 3px solid #ffffff;
border-radius: 5vw; /* закругления плашки */
border: 0.25vw solid #ffffff;
}

View File

@ -0,0 +1,60 @@
.delete_project_page {
height: 60vw;
background-color: #dcb495;
}
.form_block {
width: 100%;
height: 60vw;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.form_data {
display: flex;
flex-direction: column;
margin-left: 2%;
}
.input_data {
color: #000000;
border: 0.1vw solid #595008;
height: 4.5vw;
min-height: 4.5vw;
width: 35vw;
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;
}
.delete_project_button {
margin-left: 15px;
width: 25vw;
height: 5vw;
background-color: #000000;
color: #ffffff;
border-radius: 5vw;
vertical-align: middle;
font-size: 1.5vw;
}
form {
display: flex;
align-items: flex-end;
justify-content: center;
}
.conf_text {
color: #ff0000;
}
.header_title {
text-align: center;
color: #000000;
font-size: 3.5vw;
width: 100%;
margin-bottom: 15px;
}

149
static/css/edit_project.css Normal file
View File

@ -0,0 +1,149 @@
.edit_project_page {
height: 120vw;
background-color: #dcb495;
}
.form_data, .form_data_button {
display: flex;
flex-direction: column;
margin-left: 2%;
}
.form_data_button {
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: 35vw;
background-color: #dbc3af;
border-radius: 4.5vw;
font-size: 1.3vw;
display: inline-flex;
align-items: center;
}
.input_button {
width: 35vw;
height: 5vw;
border-radius: 5vw;
vertical-align: middle;
}
.form_label {
margin-top: 10px;
font-size: 1.3vw;
color: #ffffff;
font-weight: bold;
}
.description {
border-radius: 2vw !important;
width: 50vw;
}
.padding_data {
padding-top: 1vw;
padding-left: 1vw;
}
.label_data {
padding-left: 0.8vw;
width: 50vw;
}
.project_button, .delete_button, .delete_project_link {
margin-top: 15px;
width: 35vw;
height: 5vw;
background-color: #000000;
color: #ffffff;
border-radius: 5vw;
vertical-align: middle;
font-size: 1.5vw;
}
.collaborator_block {
width: 30%;
height: 20vw;
background-color: #EDCBB0;
border-radius: 2vw;
overflow-y: auto;
}
.user {
width: 30vw;
height: 3.5vw;
background-color: #ffffff;
border: 2px solid #9E795A;
border-radius: 3vw;
margin-top: 5px;
display: inline-flex;
justify-content: space-between;
}
.user_logo {
margin-left: 3px;
width: 3vw;
height: 3vw;
border-radius: 5vw;
background-color: #000000;
}
.user_names {
margin-left: 9px;
margin-top: 10px;
overflow-x: auto;
}
.name_form_block {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.data_form_block {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: row;
}
.buttons_form_block {
width: 45%;
display: flex;
flex-direction: column;
align-items: center;
}
.staff_form_block, .collaborator_block {
margin-top: 10px;
width: 60%;
height: 20vw;
display: flex;
align-items: center;
justify-content: center;
}
.staff_block {
margin: 5%;
width: 90%;
height: 20vw;
}
.choose_user {
align-self: flex-end;
margin-bottom: 1.1vw;
width: 10%;
}
.user_data {
display: inline-flex;
align-items: center;
justify-content: flex-start;
flex-direction: row;
}
.delete_project_link {
background-color: #ff3f3f;
}
.delete_project_link:hover {
background-color: #ff3f3f;
text-decoration: none;
color: #ffffff;
}
.delete_project_link_text {
width: 35vw;
height: 5vw;
display: flex;
align-items: center;
justify-content: center;
margin-top: 10px;
}

View File

@ -22,7 +22,34 @@
flex-direction: column;
align-items: center;
justify-content: space-between;
color: #dcb495
#a8886f
#f5d3b8
#a65b1e
#d49d51
#face7d
#ffe8d6
#a8876b
#fff2e8
#c79b77
#d69d5c;
}
.name_project {
font-size: 3vw;
}
.edit_block {
display: flex;
align-items: center;
justify-content: center;
}
.edit_button {
width: 4.5vw;
height: 4.5vw;
display: flex;
align-items: center;
justify-content: center;
}
.edit_button_image {
height: 3vw;
width: 3vw;
}

BIN
static/images/pen_b.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
static/images/pen_w.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

2
static/js/project.js Normal file
View File

@ -0,0 +1,2 @@
var edit_button = document.getElementById("edit_button");
edit_button.href = String(window.location.href) + '/edit';

View File

@ -0,0 +1,26 @@
<link rel="stylesheet" href="../../static/css/delete_project.css"/>
{% extends "base.html" %} {% block content %}
{% set name = 'delete/' + project.name %}
<div class="delete_project_page">
<div class="form_block">
<h1 class="header_title">Удаление проекта</h1>
<form action="" method="post" class="register_form" enctype="multipart/form-data">
{{ form.hidden_tag() }}
<div class="form_data">
<label class="form_label">Для подтверждения удаления введите <p class="conf_text">delete/{{ project.name
}}</p></label>
{{ form.conf(class="input_data", type="conf", placeholder=name) }}
{% for error in form.conf.errors %}
<div class="alert alert-danger" role="alert">{{ error }}</div>
{% endfor %}
</div>
{{ form.submit(type="submit", class="delete_project_button") }}
</form>
{% if message != '' %}
<div class="alert alert-danger message" role="alert">
{{ message }}
</div>
{% endif %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,68 @@
<link rel="stylesheet" href="../../static/css/edit_project.css"/>
{% extends "base.html" %} {% block content %}
<div class="edit_project_page">
<div class="form_block">
<form action="" method="post" class="register_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="staff_form_block">
<div class="collaborator_block">
<div class="staff_block">
{% for user in list_users %}
<div class="user">
<div class="user_data">
<img class="user_logo" src="../../{{user.photo}}">
<p class="user_names">{{user['name']}}</p>
</div>
{% if user not in staff %}
<input class="choose_user" name="choose_{{user.login}}" type="checkbox" value="y">
{% else %}
<input class="choose_user" name="choose_{{user.login}}" type="checkbox" value="y" checked="yes">
{% endif %}
</div>
{% endfor %}
</div>
</div>
</div>
<div class="buttons_form_block">
{% if 'none' in project.photo %}
<div class="form_data">
<label class="form_label">{{ form.logo.label }}</label>
{{ form.logo(class="input_data padding_data", type="file") }}
{% for error in form.logo.errors %}
<div class="alert alert-danger" role="alert">{{ error }}</div>
{% endfor %}
</div>
{% else %}
<div class="form_data_button">
{{ form.del_photo(type="submit", class="delete_button") }}
</div>
{% endif %}
<div class="form_data_button">
{{ form.save(type="submit", class="project_button") }}
</div>
<a class="delete_project_link form_data_button" id="delete_project_link" href="/project/{{ project.id }}/delete">
<p class="delete_project_link_text">Удалить проект</p>
</a>
</div>
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -3,7 +3,9 @@
<div class="projects_page">
<div class="project_header">
<div class="edit_block">
<a id="edit_button" class="edit_button" href="">
<img class="edit_button_image" src="../static/images/pen_b.png">
</a>
</div>
<div class="brand_block">
<img class="project_logo" src="../{{project.photo}}"/>
@ -25,4 +27,5 @@
</div>
</div>
<script type="text/javascript" src="../static/js/project.js"></script>
{% endblock %}