Поправил requirements.txt, сделал валидацию загрузки логотипа проекта, сделал логирование ошибок, авторизации и выхода, сделал полное удаление проекта и его составляющих
This commit is contained in:
parent
3a7b651960
commit
ab82863761
@ -1,4 +1,5 @@
|
|||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
|
from flask_wtf.file import FileAllowed
|
||||||
from wtforms import StringField, SubmitField, TextAreaField, FileField, MultipleFileField
|
from wtforms import StringField, SubmitField, TextAreaField, FileField, MultipleFileField
|
||||||
from wtforms.validators import DataRequired
|
from wtforms.validators import DataRequired
|
||||||
|
|
||||||
@ -6,7 +7,7 @@ from wtforms.validators import DataRequired
|
|||||||
class ProjectForm(FlaskForm):
|
class ProjectForm(FlaskForm):
|
||||||
name = StringField('Название', validators=[DataRequired()])
|
name = StringField('Название', validators=[DataRequired()])
|
||||||
description = TextAreaField('Описание')
|
description = TextAreaField('Описание')
|
||||||
logo = FileField('Логотип')
|
logo = FileField('Логотип', validators=[FileAllowed(['jpg', 'png', 'bmp', 'ico', 'jpeg'], 'Только изображения')])
|
||||||
submit = SubmitField('Создать')
|
submit = SubmitField('Создать')
|
||||||
del_photo = SubmitField('Удалить фотографию')
|
del_photo = SubmitField('Удалить фотографию')
|
||||||
save = SubmitField('Сохранить')
|
save = SubmitField('Сохранить')
|
||||||
|
|||||||
42
functions.py
42
functions.py
@ -1,8 +1,14 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
import smtplib
|
import smtplib
|
||||||
from json import loads
|
from json import loads
|
||||||
from email.message import EmailMessage
|
from email.message import EmailMessage
|
||||||
|
from sqlalchemy import or_
|
||||||
|
|
||||||
|
from data.answer import Answer
|
||||||
|
from data.proof_file import FileProof
|
||||||
|
from data.quests import Quests
|
||||||
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
|
||||||
@ -27,8 +33,8 @@ def check_password(password=''):
|
|||||||
|
|
||||||
|
|
||||||
def mail(msg, to, topic='Подтверждение почты'):
|
def mail(msg, to, topic='Подтверждение почты'):
|
||||||
with open('incepted.config', 'r', encoding='utf-8').read() as file:
|
with open('incepted.config', 'r', encoding='utf-8') as file:
|
||||||
file = loads(file)
|
file = loads(file.read())
|
||||||
login, password = file["mail_login"], file["mail_password"]
|
login, password = file["mail_login"], file["mail_password"]
|
||||||
email_server = "smtp.yandex.ru"
|
email_server = "smtp.yandex.ru"
|
||||||
sender = "incepted@yandex.ru"
|
sender = "incepted@yandex.ru"
|
||||||
@ -182,3 +188,35 @@ def file_tree(path):
|
|||||||
h += 1
|
h += 1
|
||||||
data_session.close()
|
data_session.close()
|
||||||
return tree
|
return tree
|
||||||
|
|
||||||
|
|
||||||
|
def delete_file_proof_data(file_proof, data_session):
|
||||||
|
file = data_session.query(Files).filter(Files.id == file_proof.file).first()
|
||||||
|
data_session.delete(file)
|
||||||
|
|
||||||
|
|
||||||
|
def delete_answer_data(answer, data_session):
|
||||||
|
file_proofs = data_session.query(FileProof).filter(FileProof.answer == answer.id).all()
|
||||||
|
list(map(lambda file: delete_file_proof_data(file, data_session), file_proofs))
|
||||||
|
list(map(data_session.delete, file_proofs))
|
||||||
|
|
||||||
|
|
||||||
|
def delete_quest_data(quest, data_session):
|
||||||
|
answers = data_session.query(Answer).filter(Answer.quest == quest.id).all()
|
||||||
|
list(map(lambda answer: delete_answer_data(answer, data_session), answers))
|
||||||
|
list(map(data_session.delete, answers))
|
||||||
|
|
||||||
|
|
||||||
|
def delete_project_data(project, data_session):
|
||||||
|
staff = data_session.query(StaffProjects).filter(StaffProjects.project == project.id).all()
|
||||||
|
list(map(data_session.delete, staff))
|
||||||
|
if 'none_project' not in project.photo:
|
||||||
|
os.remove(project.photo)
|
||||||
|
quests = data_session.query(Quests).filter(Quests.project == project.id).all()
|
||||||
|
list(map(lambda quest: delete_quest_data(quest, data_session), quests))
|
||||||
|
list(map(data_session.delete, quests))
|
||||||
|
list(map(data_session.delete,
|
||||||
|
data_session.query(Files).filter(Files.path.contains(f'all_projects/{str(project.id)}/')).all()))
|
||||||
|
shutil.rmtree(f'static/app_files/all_projects/{str(project.id)}')
|
||||||
|
data_session.delete(project)
|
||||||
|
data_session.commit()
|
||||||
|
|||||||
0
logfiles/заглушка
Normal file
0
logfiles/заглушка
Normal file
39
main.py
39
main.py
@ -1,5 +1,7 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import os
|
import os
|
||||||
|
import logging
|
||||||
|
import shutil
|
||||||
|
|
||||||
from flask import Flask, render_template, request, url_for
|
from flask import Flask, render_template, request, url_for
|
||||||
from flask_login import login_user, current_user, LoginManager, logout_user, login_required
|
from flask_login import login_user, current_user, LoginManager, logout_user, login_required
|
||||||
@ -12,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
|
overdue_quest_project, save_proof_quest, find_files_answer, file_tree, delete_project_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
|
||||||
@ -38,6 +40,8 @@ with open('incepted.config', 'r', encoding='utf-8') as file:
|
|||||||
file = loads(file)
|
file = loads(file)
|
||||||
key = file["encrypt_key"]
|
key = file["encrypt_key"]
|
||||||
app.config['SECRET_KEY'] = key
|
app.config['SECRET_KEY'] = key
|
||||||
|
logging.basicConfig(level=logging.INFO, filename="logfiles/main.log", format="%(asctime)s %(levelname)s %(message)s",
|
||||||
|
encoding='utf-8')
|
||||||
csrf = CSRFProtect(app)
|
csrf = CSRFProtect(app)
|
||||||
s = URLSafeTimedSerializer(key)
|
s = URLSafeTimedSerializer(key)
|
||||||
login_manager = LoginManager()
|
login_manager = LoginManager()
|
||||||
@ -100,7 +104,7 @@ def task_project(id_project, id_task):
|
|||||||
deadline = None
|
deadline = None
|
||||||
current_task.deadline = deadline
|
current_task.deadline = deadline
|
||||||
if current_answer:
|
if current_answer:
|
||||||
current_answer.text = form.text.data if form.text.data else None
|
current_answer.text = form.text.data
|
||||||
current_answer.date_edit = datetime.datetime.now()
|
current_answer.date_edit = datetime.datetime.now()
|
||||||
current_task.realized = form.realized.data
|
current_task.realized = form.realized.data
|
||||||
data_session.commit()
|
data_session.commit()
|
||||||
@ -125,7 +129,7 @@ def task_project(id_project, id_task):
|
|||||||
current_task.realized = form.realized.data
|
current_task.realized = form.realized.data
|
||||||
current_answer = Answer(
|
current_answer = Answer(
|
||||||
quest=current_task.id,
|
quest=current_task.id,
|
||||||
text=form.text.data if form.text.data else None,
|
text=form.text.data,
|
||||||
creator=current_user.id,
|
creator=current_user.id,
|
||||||
date_create=datetime.datetime.now(),
|
date_create=datetime.datetime.now(),
|
||||||
date_edit=datetime.datetime.now()
|
date_edit=datetime.datetime.now()
|
||||||
@ -136,19 +140,19 @@ def task_project(id_project, id_task):
|
|||||||
if files:
|
if files:
|
||||||
for i in files:
|
for i in files:
|
||||||
proof_file = FileProof(
|
proof_file = FileProof(
|
||||||
proof=current_answer.id,
|
answer=current_answer.id,
|
||||||
file=i
|
file=i
|
||||||
)
|
)
|
||||||
data_session.add(proof_file)
|
data_session.add(proof_file)
|
||||||
data_session.commit()
|
data_session.commit()
|
||||||
return redirect(f'/project/{current_project.id}')
|
return redirect(f'/project/{current_project.id}')
|
||||||
if current_answer:
|
if current_answer and request.method == 'GET':
|
||||||
form.text.data = current_answer.text
|
form.text.data = current_answer.text
|
||||||
form.realized.data = current_task.realized
|
form.realized.data = current_task.realized
|
||||||
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:
|
if current_task.deadline and current_task.deadline and request.method == 'GET':
|
||||||
form.deadline_date.data = current_task.deadline.date()
|
form.deadline_date.data = current_task.deadline.date()
|
||||||
form.deadline_time.data = current_task.deadline.time()
|
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,
|
||||||
@ -271,6 +275,7 @@ def project(id_project):
|
|||||||
if form_file.file.data[0].filename:
|
if form_file.file.data[0].filename:
|
||||||
files = list(
|
files = list(
|
||||||
map(lambda x: save_proof_quest(current_project, x, current_user.id), form_file.file.data))
|
map(lambda x: save_proof_quest(current_project, x, current_user.id), form_file.file.data))
|
||||||
|
return redirect(f'/project/{str(current_project.id)}')
|
||||||
return render_template('project.html',
|
return render_template('project.html',
|
||||||
project=current_project,
|
project=current_project,
|
||||||
title=current_project.name,
|
title=current_project.name,
|
||||||
@ -338,18 +343,11 @@ def delete_project(id_project):
|
|||||||
if project_del.creator == current_user.id:
|
if project_del.creator == current_user.id:
|
||||||
form = DeleteProjectForm()
|
form = DeleteProjectForm()
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
if form.conf.data != f'delete/{project_del.name}':
|
if str(form.conf.data).lower().strip() != f'delete/{str(project_del.name)}'.lower().strip():
|
||||||
return render_template('delete_project.html', title='Удаление проекта', form=form,
|
return render_template('delete_project.html', title='Удаление проекта', form=form,
|
||||||
project=project_del,
|
project=project_del,
|
||||||
message='Вы не правильно ввели фразу')
|
message='Вы не правильно ввели фразу')
|
||||||
staff = data_session.query(StaffProjects).filter(StaffProjects.project == id_project).all()
|
delete_project_data(project_del, data_session)
|
||||||
for i in staff:
|
|
||||||
data_session.delete(i)
|
|
||||||
if 'none_project' not in project_del.photo:
|
|
||||||
os.remove(project_del.photo)
|
|
||||||
shutil.rmtree(f'static/app_files/all_projects/{str(project_del.id)}')
|
|
||||||
data_session.delete(project_del)
|
|
||||||
data_session.commit()
|
|
||||||
return redirect('/projects')
|
return redirect('/projects')
|
||||||
return render_template('delete_project.html', title='Удаление проекта', form=form, project=project_del,
|
return render_template('delete_project.html', title='Удаление проекта', form=form, project=project_del,
|
||||||
message='')
|
message='')
|
||||||
@ -512,6 +510,7 @@ def login():
|
|||||||
if user and user.check_password(form.password.data):
|
if user and user.check_password(form.password.data):
|
||||||
if user.activated:
|
if user.activated:
|
||||||
login_user(user, remember=form.remember_me.data)
|
login_user(user, remember=form.remember_me.data)
|
||||||
|
logging.info(f'{user.login} logged in')
|
||||||
return redirect('/projects')
|
return redirect('/projects')
|
||||||
else:
|
else:
|
||||||
return render_template('login.html',
|
return render_template('login.html',
|
||||||
@ -531,6 +530,7 @@ def login():
|
|||||||
@app.route('/logout')
|
@app.route('/logout')
|
||||||
@login_required
|
@login_required
|
||||||
def logout():
|
def logout():
|
||||||
|
logging.info(f'{current_user.login} logged out')
|
||||||
logout_user()
|
logout_user()
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
@ -565,6 +565,7 @@ def register():
|
|||||||
link_conf = url_for('confirmation', token=token, _external=True)
|
link_conf = url_for('confirmation', token=token, _external=True)
|
||||||
mail(f'Для завершения регистрации пройдите по ссылке: {link_conf}', form.email.data,
|
mail(f'Для завершения регистрации пройдите по ссылке: {link_conf}', form.email.data,
|
||||||
'Подтверждение регистрации')
|
'Подтверждение регистрации')
|
||||||
|
logging.info(f'{form.login.data} was registered')
|
||||||
return redirect('/login?message=Мы выслали ссылку для подтверждения почты')
|
return redirect('/login?message=Мы выслали ссылку для подтверждения почты')
|
||||||
return render_template('register.html', form=form, message='', title='Регистрация')
|
return render_template('register.html', form=form, message='', title='Регистрация')
|
||||||
else:
|
else:
|
||||||
@ -580,6 +581,7 @@ def confirmation(token):
|
|||||||
if user:
|
if user:
|
||||||
user.activated = True
|
user.activated = True
|
||||||
data_session.commit()
|
data_session.commit()
|
||||||
|
logging.info(f'{user.login} has been confirmed')
|
||||||
return redirect('/login?message=Почта успешно подтверждена')
|
return redirect('/login?message=Почта успешно подтверждена')
|
||||||
else:
|
else:
|
||||||
return redirect('/login?message=Пользователь не найден&danger=True')
|
return redirect('/login?message=Пользователь не найден&danger=True')
|
||||||
@ -614,8 +616,11 @@ def main():
|
|||||||
db_session.global_init(db_path)
|
db_session.global_init(db_path)
|
||||||
if not db:
|
if not db:
|
||||||
init_db_default()
|
init_db_default()
|
||||||
serve(app, host='0.0.0.0', port=5000)
|
serve(app, host='0.0.0.0', port=5000, threads=10)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
try:
|
||||||
|
main()
|
||||||
|
except Exception as error:
|
||||||
|
logging.warning(f'{error}')
|
||||||
|
|||||||
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
@ -170,7 +170,7 @@ form {
|
|||||||
max-height: 20vw;
|
max-height: 20vw;
|
||||||
}
|
}
|
||||||
.form_text_one {
|
.form_text_one {
|
||||||
width: 100%;
|
width: 200%;
|
||||||
}
|
}
|
||||||
.files_block {
|
.files_block {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@ -33,10 +33,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="file_buttons">
|
<div class="file_buttons">
|
||||||
<div class="btn-group file_buttons_groud">
|
<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 %}
|
{% if current_user.id == project.creator or task.creator == current_user.id or
|
||||||
<a href="../file/{{ file.id }}/delete" class="btn btn-primary file_delete"><p class="button_text">Удалить</p></a>
|
file['user'] == current_user.id %}
|
||||||
|
<a href="../file/{{ file.id }}/delete" class="btn btn-primary file_delete"><p
|
||||||
|
class="button_text">Удалить</p></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="../../../{{ file['path'] }}" download="" class="btn btn-primary file_download"><p class="button_text">Скачать</p></a>
|
<a href="../../../{{ file['path'] }}" download="" class="btn btn-primary file_download">
|
||||||
|
<p class="button_text">Скачать</p></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -45,17 +48,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% 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>
|
||||||
<div class="decision_block">
|
<div class="decision_block">
|
||||||
<form action="" method="post" class="answer_form" enctype="multipart/form-data">
|
<form action="" method="post" class="answer_form" enctype="multipart/form-data">
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
|
<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 class="data_block">
|
<div class="data_block">
|
||||||
<div class="form_data bottom_data">
|
<div class="form_data bottom_data">
|
||||||
<label class="form_label">{{ form.file.label }}</label>
|
<label class="form_label">{{ form.file.label }}</label>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user