main.py 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. import datetime
  2. import os
  3. import logging
  4. from flask import Flask, render_template, request, url_for
  5. from flask_login import login_user, current_user, LoginManager, logout_user, login_required
  6. from flask_wtf import CSRFProtect
  7. from flask_restful import abort
  8. from werkzeug.datastructures import CombinedMultiDict
  9. from werkzeug.utils import redirect
  10. from itsdangerous import URLSafeTimedSerializer, SignatureExpired
  11. from sqlalchemy import or_
  12. from json import loads
  13. from waitress import serve
  14. from functions import check_password, mail, init_db_default, get_projects_data, get_user_data, save_project_logo, \
  15. overdue_quest_project, save_proof_quest, find_files_answer, file_tree, delete_project_data, delete_quest_data, \
  16. copy_template, save_admin_data
  17. from forms.edit_profile import EditProfileForm
  18. from forms.login import LoginForm
  19. from forms.find_project import FindProjectForm
  20. from forms.register import RegisterForm
  21. from forms.project import ProjectForm, AddFileProject
  22. from forms.recovery import RecoveryForm, NewPasswordForm
  23. from forms.conf_delete_project import DeleteProjectForm
  24. from forms.task import Task, AnswerTask
  25. from forms.encrypt_form import EncryptForm
  26. from data.users import User
  27. from data.quests import Quests
  28. from data.answer import Answer
  29. from data.proof_file import FileProof
  30. from data.files import Files
  31. from data.projects import Projects
  32. from data.staff_projects import StaffProjects
  33. from data.roles import Roles
  34. from data import db_session
  35. app = Flask(__name__)
  36. with open('incepted.config', 'r', encoding='utf-8') as file:
  37. file = file.read()
  38. file = loads(file)
  39. key = file["encrypt_key"]
  40. app.config['SECRET_KEY'] = key
  41. app.debug = True
  42. logging.basicConfig(level=logging.INFO, filename="logfiles/main.log", format="%(asctime)s %(levelname)s %(message)s",
  43. encoding='utf-8')
  44. csrf = CSRFProtect(app)
  45. s = URLSafeTimedSerializer(key)
  46. login_manager = LoginManager()
  47. login_manager.init_app(app)
  48. @app.route('/')
  49. def base():
  50. if not current_user.is_authenticated:
  51. return render_template('main.html', title='Главная')
  52. else:
  53. return redirect('/projects')
  54. @app.route('/admin', methods=['GET', 'POST'])
  55. def admin():
  56. if current_user.is_authenticated:
  57. if current_user.role == 1:
  58. data_session = db_session.create_session()
  59. roles, users = data_session.query(Roles).all(), \
  60. data_session.query(User).filter(User.id != current_user.id).all()
  61. form = EncryptForm()
  62. if request.method == 'POST':
  63. data_form = request.form.to_dict()
  64. del data_form['csrf_token'], data_form['submit']
  65. data_form = list(map(lambda x: (x[0], x[1]), data_form.items()))
  66. list(map(lambda x: save_admin_data(x, data_session), data_form))
  67. data_session.commit()
  68. return render_template('admin.html', title='Панель админа', roles=roles, users=users, form=form)
  69. abort(404)
  70. @app.route('/template/<int:id_template>/create')
  71. def create_by_template(id_template):
  72. if current_user.is_authenticated:
  73. data_session = db_session.create_session()
  74. current_template = data_session.query(Projects).filter(Projects.id == id_template).first()
  75. if current_template:
  76. new_project = Projects(
  77. name=current_template.name,
  78. description=current_template.description,
  79. date_create=datetime.datetime.now(),
  80. creator=current_user.id,
  81. is_open=False,
  82. is_template=False
  83. )
  84. data_session.add(new_project)
  85. data_session.flush()
  86. data_session.refresh(new_project)
  87. data_session.commit()
  88. copy_template(current_template, new_project, data_session, current_user)
  89. return redirect('/projects')
  90. else:
  91. abort(403)
  92. else:
  93. return redirect('/login')
  94. @app.route('/template/<int:id_template>')
  95. def template_project(id_template):
  96. if current_user.is_authenticated:
  97. data_session = db_session.create_session()
  98. current_project = data_session.query(Projects).filter(Projects.id == id_template).first()
  99. if current_project:
  100. quests = data_session.query(Quests).filter(Quests.project == current_project.id).all()
  101. files_list = file_tree(f'static/app_files/all_projects/{current_project.id}')
  102. return render_template('template_project.html', title=f'Шаблон {current_project.name}',
  103. project=current_project, quests=quests, file_tree=files_list)
  104. else:
  105. abort(404)
  106. else:
  107. return redirect('/login')
  108. @app.route('/showcase', methods=['GET', 'POST'])
  109. def showcase():
  110. if current_user.is_authenticated:
  111. data_session = db_session.create_session()
  112. list_template = list(map(lambda curr_project: get_projects_data(curr_project),
  113. data_session.query(Projects).filter(Projects.is_template == 1).all()))
  114. return render_template('showcase.html', title='Витрина', list_template=list_template)
  115. else:
  116. return redirect('/login')
  117. @app.route('/project/<int:id_project>/quest/<int:id_task>/edit', methods=['GET', 'POST'])
  118. def edit_quest(id_project, id_task):
  119. if current_user.is_authenticated:
  120. data_session = db_session.create_session()
  121. current_project = data_session.query(Projects).filter(Projects.id == id_project).first()
  122. current_task = data_session.query(Quests).filter(Quests.id == id_task).first()
  123. if current_project and current_task and current_task.project == current_project.id and (
  124. current_task.creator == current_user.id or current_project.creator == current_user.id):
  125. form = Task()
  126. if request.method == 'GET':
  127. form.name.data = current_task.name
  128. form.description.data = current_task.description
  129. form.deadline_time.data = current_task.deadline.time()
  130. form.deadline_date.data = current_task.deadline.date()
  131. if form.delete.data:
  132. delete_quest_data(current_task, data_session)
  133. data_session.delete(current_task)
  134. data_session.commit()
  135. return redirect(f'/project/{str(current_project.id)}')
  136. if form.validate_on_submit():
  137. if form.deadline_date.data and form.deadline_time.data:
  138. deadline = datetime.datetime.combine(form.deadline_date.data, form.deadline_time.data)
  139. else:
  140. deadline = None
  141. current_task.name = form.name.data if form.name.data else None
  142. current_task.description = form.description.data if form.description.data else None
  143. current_task.deadline = deadline
  144. data_session.commit()
  145. return redirect(f'/project/{str(current_project.id)}/quest/{str(current_task.id)}')
  146. return render_template('edit_task.html', title='Редактирование задачи', form=form, porject=current_project,
  147. task=current_task)
  148. else:
  149. abort(403)
  150. else:
  151. return redirect('/login')
  152. @app.route('/project/<int:id_project>/file/<int:id_file>/delete')
  153. def delete_file(id_project, id_file):
  154. if current_user.is_authenticated:
  155. from_path = request.args.get('from') if request.args.get('from') else ''
  156. data_session = db_session.create_session()
  157. current_project = data_session.query(Projects).filter(Projects.id == id_project).first()
  158. current_file = data_session.query(Files).filter(Files.id == id_file).first()
  159. if current_project and current_file:
  160. if current_user.id in map(lambda x: x[0], data_session.query(StaffProjects.user).filter(
  161. StaffProjects.project == current_project.id).all()) or current_user.id == current_project.creator:
  162. current_proof = data_session.query(FileProof).filter(FileProof.file == id_file).all()
  163. os.remove(current_file.path)
  164. data_session.delete(current_file)
  165. if current_proof:
  166. quest = data_session.query(Answer.quest).filter(Answer.id == current_proof[0].answer).first()
  167. for i in current_proof:
  168. data_session.delete(i)
  169. data_session.commit()
  170. if from_path == 'project':
  171. return redirect(f'/project/{current_project.id}')
  172. return redirect(f'/project/{current_project.id}/quest/{quest[0]}')
  173. data_session.commit()
  174. return redirect(f'/project/{current_project.id}')
  175. else:
  176. abort(403)
  177. else:
  178. abort(404)
  179. else:
  180. return redirect('/login')
  181. @app.route('/project/<int:id_project>/quest/<int:id_task>', methods=['GET', 'POST'])
  182. def task_project(id_project, id_task):
  183. if current_user.is_authenticated:
  184. data_session = db_session.create_session()
  185. current_project = data_session.query(Projects).filter(Projects.id == id_project).first()
  186. current_task = data_session.query(Quests).filter(Quests.id == id_task).first()
  187. if current_project and current_task and current_task.project == current_project.id:
  188. form = AnswerTask()
  189. current_answer = data_session.query(Answer).filter(Answer.quest == current_task.id).first()
  190. list_files = None
  191. if form.submit.data and request.method == 'POST':
  192. if current_answer:
  193. current_answer.text = form.text.data
  194. current_answer.date_edit = datetime.datetime.now()
  195. current_task.realized = form.realized.data
  196. data_session.commit()
  197. if form.file.data[0].filename:
  198. files = list(
  199. map(lambda x: save_proof_quest(current_project, x, current_user.id), form.file.data))
  200. for i in files:
  201. if not data_session.query(FileProof).filter(FileProof.answer == current_answer.id,
  202. FileProof.file == i).first():
  203. proof_file = FileProof(
  204. answer=current_answer.id,
  205. file=i
  206. )
  207. data_session.add(proof_file)
  208. data_session.commit()
  209. else:
  210. if form.file.data[0].filename:
  211. files = list(
  212. map(lambda x: save_proof_quest(current_project, x, current_user.id), form.file.data))
  213. else:
  214. files = False
  215. current_task.realized = form.realized.data
  216. current_answer = Answer(
  217. quest=current_task.id,
  218. text=form.text.data,
  219. creator=current_user.id,
  220. date_create=datetime.datetime.now(),
  221. date_edit=datetime.datetime.now()
  222. )
  223. data_session.add(current_answer)
  224. data_session.flush()
  225. data_session.refresh(current_answer)
  226. if files:
  227. for i in files:
  228. proof_file = FileProof(
  229. answer=current_answer.id,
  230. file=i
  231. )
  232. data_session.add(proof_file)
  233. data_session.commit()
  234. return redirect(f'/project/{current_project.id}')
  235. if current_answer and request.method == 'GET':
  236. form.text.data = current_answer.text
  237. form.realized.data = current_task.realized
  238. files = data_session.query(FileProof).filter(FileProof.answer == current_answer.id).all()
  239. if files:
  240. list_files = list(map(lambda x: find_files_answer(x.file), files))
  241. return render_template('answer.html', title='Решение', project=current_project, task=current_task,
  242. form=form, list_files=list_files)
  243. else:
  244. abort(404)
  245. else:
  246. return redirect('/login')
  247. @app.route('/project/<int:id_project>/quest/new', methods=['GET', 'POST'])
  248. def new_task_project(id_project):
  249. if current_user.is_authenticated:
  250. data_session = db_session.create_session()
  251. current_project = data_session.query(Projects).filter(Projects.id == id_project).first()
  252. if current_project:
  253. form = Task()
  254. if form.validate_on_submit():
  255. if form.deadline_date.data and form.deadline_time.data:
  256. deadline = datetime.datetime.combine(form.deadline_date.data, form.deadline_time.data)
  257. else:
  258. deadline = None
  259. quest = Quests(
  260. project=current_project.id,
  261. creator=current_user.id,
  262. name=form.name.data if form.name.data else None,
  263. description=form.description.data if form.description.data else None,
  264. date_create=datetime.datetime.now(),
  265. deadline=deadline,
  266. realized=False
  267. )
  268. data_session.add(quest)
  269. data_session.commit()
  270. return redirect(f'/project/{str(current_project.id)}')
  271. return render_template('new_task.html', title='Новая задача', form=form, porject=current_project)
  272. else:
  273. abort(404)
  274. else:
  275. return redirect('/login')
  276. @app.route('/project/<int:id_project>/edit', methods=['GET', 'POST'])
  277. def edit_project(id_project):
  278. if current_user.is_authenticated:
  279. data_session = db_session.create_session()
  280. current_project = data_session.query(Projects).filter(Projects.id == id_project).first()
  281. if current_project:
  282. staff = data_session.query(StaffProjects).filter(StaffProjects.project == current_project.id).all()
  283. if current_user.id == current_project.creator:
  284. list_users = list(
  285. map(lambda x: get_user_data(x),
  286. data_session.query(User).filter(User.id != current_user.id, User.activated == 1).all()))
  287. staff = list(map(lambda x: get_user_data(x), data_session.query(User).filter(
  288. User.id.in_(list(map(lambda x: x.user, staff)))).all())) if staff else []
  289. form = ProjectForm()
  290. if form.save.data:
  291. new_staff = []
  292. for i in list_users:
  293. if request.form.getlist(f"choose_{i['login']}") and i['id'] != current_user.id:
  294. new_staff.append(i)
  295. if i not in staff:
  296. new_staffer = StaffProjects(
  297. user=i['id'],
  298. project=current_project.id,
  299. role='user',
  300. permission=3
  301. )
  302. data_session.add(new_staffer)
  303. data_session.commit()
  304. if sorted(new_staff, key=lambda x: x['id']) != sorted(staff, key=lambda x: x['id']):
  305. for i in staff:
  306. if i not in new_staff:
  307. data_session.delete(data_session.query(StaffProjects).filter(
  308. StaffProjects.user == i['id'], StaffProjects.project == current_project.id).first())
  309. data_session.commit()
  310. if form.logo.data:
  311. current_project.photo = save_project_logo(form.logo.data)
  312. data_session.commit()
  313. current_project.name = form.name.data
  314. current_project.description = form.description.data
  315. data_session.commit()
  316. return redirect(f'/project/{current_project.id}')
  317. if form.del_photo.data:
  318. os.remove(current_project.photo)
  319. current_project.photo = 'static/images/none_project.png'
  320. data_session.commit()
  321. return redirect(f'/project/{current_project.id}/edit')
  322. form.name.data = current_project.name
  323. form.description.data = current_project.description
  324. return render_template('edit_project.html', title='Изменение проекта', form=form, list_users=list_users,
  325. staff=staff, project=current_project)
  326. else:
  327. abort(403)
  328. else:
  329. abort(404)
  330. else:
  331. return redirect('/login')
  332. @app.route('/project/<int:id_project>', methods=['POST', 'GET'])
  333. def project(id_project):
  334. if current_user.is_authenticated:
  335. data_session = db_session.create_session()
  336. current_project = data_session.query(Projects).filter(Projects.id == id_project).first()
  337. if current_project:
  338. staff = data_session.query(StaffProjects).filter(StaffProjects.project == current_project.id).all()
  339. if current_user.id == current_project.creator or current_user.id in list(map(lambda x: x.user, staff)):
  340. staff = list(map(lambda x: get_user_data(x), data_session.query(User).filter(
  341. User.id.in_(list(map(lambda x: x.user, staff)))).all())) if staff else []
  342. quests = data_session.query(Quests).filter(Quests.project == current_project.id).all()
  343. if quests:
  344. quests_sort = sorted(list(filter(lambda x: x.deadline is not None, quests)),
  345. key=lambda x: (x.realized, x.deadline))
  346. quests = list(filter(lambda x: x.realized == 0, quests_sort)) + list(
  347. filter(lambda x: x.deadline is None, quests)) + list(
  348. filter(lambda x: x.realized == 1, quests_sort))
  349. quests = list(map(lambda x: overdue_quest_project(x), quests))
  350. files_list = file_tree(f'static/app_files/all_projects/{current_project.id}')
  351. form_file = AddFileProject()
  352. if form_file.validate_on_submit():
  353. if form_file.file.data[0].filename:
  354. files = list(
  355. map(lambda x: save_proof_quest(current_project, x, current_user.id), form_file.file.data))
  356. return redirect(f'/project/{str(current_project.id)}')
  357. return render_template('project.html',
  358. project=current_project,
  359. title=current_project.name,
  360. staff=staff,
  361. quests=quests,
  362. file_tree=files_list,
  363. form_file=form_file)
  364. else:
  365. abort(403)
  366. else:
  367. abort(404)
  368. else:
  369. return redirect('/login')
  370. @app.route('/recovery/confirmation/<token>', methods=['GET', 'POST'])
  371. def conf_recovery(token):
  372. try:
  373. user_email = s.loads(token, max_age=86400)
  374. data_session = db_session.create_session()
  375. user = data_session.query(User).filter(User.email == user_email).first()
  376. if user:
  377. form = NewPasswordForm()
  378. if form.validate_on_submit():
  379. if form.password.data != form.repeat_password.data:
  380. return render_template('recovery.html', title='Восстановление', form=form, recovery=0,
  381. message='Пароли не совпадают')
  382. status_password = check_password(form.password.data)
  383. if status_password != 'OK':
  384. return render_template('recovery.html', title='Восстановление', form=form, recovery=0,
  385. message=str(status_password))
  386. user.set_password(form.password.data)
  387. data_session.commit()
  388. mail(f'Для аккаунта {user.login}, успешно был обновлен пароль', user.email,
  389. 'Изменение пароля')
  390. return redirect('/login?message=Пароль обновлен')
  391. return render_template('recovery.html', title='Восстановление', form=form, recovery=0, message='')
  392. else:
  393. return redirect('/login?message=Пользователь не найден&danger=True')
  394. except SignatureExpired:
  395. return redirect('/login?message=Срок действия ссылки истек&danger=True')
  396. @app.route('/recovery', methods=['GET', 'POST'])
  397. def recovery():
  398. if not current_user.is_authenticated:
  399. form = RecoveryForm()
  400. if form.validate_on_submit():
  401. token = s.dumps(form.email.data)
  402. link_conf = url_for('conf_recovery', token=token, _external=True)
  403. mail(f'Для сбросы пароля пройдите по ссылке: {link_conf}', form.email.data,
  404. 'Восстановление доступа')
  405. return redirect('/login?message=Мы выслали ссылку для сброса вам на почту')
  406. return render_template('recovery.html', title='Восстановление пароля', form=form, recovery=True, message='')
  407. else:
  408. return redirect('/')
  409. @app.route('/project/<int:id_project>/delete', methods=['GET', 'POST'])
  410. def delete_project(id_project):
  411. if current_user.is_authenticated:
  412. data_session = db_session.create_session()
  413. project_del = data_session.query(Projects).filter(Projects.id == id_project).first()
  414. if project_del:
  415. if project_del.creator == current_user.id:
  416. form = DeleteProjectForm()
  417. if form.validate_on_submit():
  418. if str(form.conf.data).lower().strip() != f'delete/{str(project_del.name)}'.lower().strip():
  419. return render_template('delete_project.html', title='Удаление проекта', form=form,
  420. project=project_del,
  421. message='Вы не правильно ввели фразу')
  422. delete_project_data(project_del, data_session)
  423. return redirect('/projects')
  424. return render_template('delete_project.html', title='Удаление проекта', form=form, project=project_del,
  425. message='')
  426. else:
  427. abort(403)
  428. else:
  429. abort(404)
  430. else:
  431. return redirect('/login')
  432. @app.route('/user/<string:_login>', methods=['GET', 'POST'])
  433. def user_view(_login):
  434. if current_user.is_authenticated:
  435. data_session = db_session.create_session()
  436. user = data_session.query(User).filter(User.login == _login).first()
  437. if user:
  438. current_projects = data_session.query(Projects).filter(or_(Projects.creator == user.id, Projects.id.in_(
  439. list(map(lambda x: x[0], data_session.query(
  440. StaffProjects.project).filter(
  441. StaffProjects.user == user.id).all()))))).all()
  442. resp = list(map(lambda x: get_projects_data(x), current_projects))
  443. return render_template('user_view.html',
  444. title=user.name if user.name else '' + ' ' + user.surname if user.surname else '',
  445. user=user,
  446. list_projects=resp)
  447. else:
  448. abort(404)
  449. else:
  450. return redirect('/login')
  451. @app.route('/projects/new', methods=['GET', 'POST'])
  452. def new_project():
  453. if current_user.is_authenticated:
  454. form = ProjectForm()
  455. data_session = db_session.create_session()
  456. list_users = list(
  457. map(lambda x: get_user_data(x), data_session.query(User).filter(User.id != current_user.id).all()))
  458. if form.validate_on_submit():
  459. current_project = Projects(
  460. name=form.name.data,
  461. description=form.description.data,
  462. date_create=datetime.datetime.now(),
  463. creator=current_user.id,
  464. is_template=form.is_template.data
  465. )
  466. current_project.photo = save_project_logo(
  467. form.logo.data) if form.logo.data else 'static/images/none_project.png'
  468. data_session.add(current_project)
  469. data_session.flush()
  470. data_session.refresh(current_project)
  471. for i in list_users:
  472. if request.form.getlist(f"choose_{i['login']}") and i['id'] != current_user.id:
  473. new_staffer = StaffProjects(
  474. user=i['id'],
  475. project=current_project.id,
  476. role='user',
  477. permission=3
  478. )
  479. data_session.add(new_staffer)
  480. data_session.commit()
  481. os.mkdir(f'static/app_files/all_projects/{str(current_project.id)}')
  482. return redirect('/projects')
  483. return render_template('new_project.html', title='Новый проект', form=form, list_users=list_users)
  484. else:
  485. return redirect('/login')
  486. @app.route('/projects', methods=['GET', 'POST'])
  487. def projects():
  488. if current_user.is_authenticated:
  489. find = False
  490. form = FindProjectForm()
  491. data_session = db_session.create_session()
  492. resp = []
  493. current_projects = \
  494. data_session.query(Projects).filter(or_(Projects.creator == current_user.id,
  495. Projects.id.in_(
  496. list(map(lambda x: x[0],
  497. data_session.query(
  498. StaffProjects.project).filter(
  499. StaffProjects.user
  500. == current_user.id).all()))))).all()
  501. if form.validate_on_submit():
  502. new_resp = []
  503. for i in range(len(current_projects)):
  504. if str(form.project.data).lower().strip() in str(current_projects[i].name).lower().strip():
  505. new_resp.append(current_projects[i])
  506. current_projects = new_resp
  507. find = True
  508. resp = list(map(lambda x: get_projects_data(x), current_projects))
  509. return render_template('projects.html', title='Проекты', list_projects=resp, form=form, find=find)
  510. else:
  511. return redirect('/login')
  512. @app.route('/profile', methods=['GET', 'POST'])
  513. def profile():
  514. if current_user.is_authenticated:
  515. data_session = db_session.create_session()
  516. form = EditProfileForm(
  517. CombinedMultiDict((request.files, request.form)),
  518. email=current_user.email,
  519. name=current_user.name,
  520. surname=current_user.surname,
  521. about=current_user.about,
  522. birthday=current_user.birthday
  523. )
  524. if form.del_photo.data:
  525. user = data_session.query(User).filter(User.id == current_user.id).first()
  526. if not user:
  527. return render_template('profile.html', title='Профиль', form=form,
  528. message='Ошибка, пользователь ненайден')
  529. os.remove(current_user.photo)
  530. user.photo = 'static/images/none_logo.png'
  531. data_session.commit()
  532. if form.validate_on_submit():
  533. user = data_session.query(User).filter(User.id == current_user.id).first()
  534. if not user:
  535. return render_template('profile.html', title='Профиль', form=form,
  536. message='Ошибка, пользователь ненайден')
  537. if form.email.data != current_user.email:
  538. token = s.dumps(form.email.data)
  539. link_conf = url_for('confirmation', token=token, _external=True)
  540. mail(f'Для изменения почты пройдите по ссылке: {link_conf}', form.email.data,
  541. 'Изменение почты')
  542. user.activated = False
  543. user.email = form.email.data
  544. if form.photo.data:
  545. with open(f'static/app_files/user_logo/{current_user.login}.png', 'wb') as file:
  546. form.photo.data.save(file)
  547. user.photo = f'static/app_files/user_logo/{current_user.login}.png'
  548. user.name = form.name.data
  549. user.surname = form.surname.data
  550. user.about = form.about.data
  551. user.birthday = form.birthday.data
  552. data_session.commit()
  553. return redirect('/profile')
  554. return render_template('profile.html', title='Профиль', form=form, message='')
  555. else:
  556. return redirect('/login')
  557. @login_manager.user_loader
  558. def load_user(user_id):
  559. db_sess = db_session.create_session()
  560. return db_sess.query(User).get(user_id)
  561. @app.route('/login', methods=['GET', 'POST'])
  562. def login():
  563. if not current_user.is_authenticated:
  564. message = request.args.get('message') if request.args.get('message') else ''
  565. danger = request.args.get('danger') if request.args.get('danger') else False
  566. form = LoginForm()
  567. if form.validate_on_submit():
  568. data_session = db_session.create_session()
  569. user = data_session.query(User).filter(User.email == form.login.data).first()
  570. if not user:
  571. user = data_session.query(User).filter(User.login == form.login.data).first()
  572. if user and user.check_password(form.password.data):
  573. if user.activated:
  574. login_user(user, remember=form.remember_me.data)
  575. logging.info(f'{user.login} logged in')
  576. return redirect('/projects')
  577. else:
  578. return render_template('login.html',
  579. message="Ваша почта не подтверждена",
  580. danger=True,
  581. form=form)
  582. return render_template('login.html',
  583. message="Неправильный логин или пароль",
  584. danger=True,
  585. form=form)
  586. return render_template('login.html', title='Авторизация', form=form, message=message,
  587. danger=danger)
  588. else:
  589. return redirect('/projects')
  590. @app.route('/logout')
  591. @login_required
  592. def logout():
  593. logging.info(f'{current_user.login} logged out')
  594. logout_user()
  595. return redirect("/")
  596. @app.route('/register', methods=['GET', 'POST'])
  597. def register():
  598. if not current_user.is_authenticated:
  599. form = RegisterForm()
  600. if form.validate_on_submit():
  601. data_session = db_session.create_session()
  602. if data_session.query(User).filter(User.login == form.login.data).first():
  603. return render_template('register.html', form=form, message="Такой пользователь уже есть",
  604. title='Регистрация')
  605. if data_session.query(User).filter(User.email == form.email.data).first():
  606. return render_template('register.html', form=form, message="Такая почта уже есть", title='Регистрация')
  607. status_password = check_password(form.password.data)
  608. if status_password != 'OK':
  609. return render_template('register.html', form=form, message=status_password, title='Регистрация')
  610. user = User(
  611. email=form.email.data,
  612. name=form.name.data,
  613. login=form.login.data,
  614. activity=datetime.datetime.now(),
  615. data_reg=datetime.date.today(),
  616. photo='static/images/none_logo.png',
  617. role=3
  618. )
  619. user.set_password(form.password.data)
  620. data_session.add(user)
  621. data_session.commit()
  622. token = s.dumps(form.email.data)
  623. link_conf = url_for('confirmation', token=token, _external=True)
  624. mail(f'Для завершения регистрации пройдите по ссылке: {link_conf}', form.email.data,
  625. 'Подтверждение регистрации')
  626. logging.info(f'{form.login.data} was registered')
  627. return redirect('/login?message=Мы выслали ссылку для подтверждения почты')
  628. return render_template('register.html', form=form, message='', title='Регистрация')
  629. else:
  630. return redirect('/projects')
  631. @app.route('/confirmation/<token>')
  632. def confirmation(token):
  633. try:
  634. user_email = s.loads(token, max_age=86400)
  635. data_session = db_session.create_session()
  636. user = data_session.query(User).filter(User.email == user_email).first()
  637. if user:
  638. user.activated = True
  639. data_session.commit()
  640. logging.info(f'{user.login} has been confirmed')
  641. return redirect('/login?message=Почта успешно подтверждена')
  642. else:
  643. return redirect('/login?message=Пользователь не найден&danger=True')
  644. except SignatureExpired:
  645. data_session = db_session.create_session()
  646. users = data_session.query(User).filter(
  647. User.activated == 0 and User.activated < datetime.datetime.now() - datetime.timedelta(days=1)).all()
  648. if users:
  649. list(map(lambda x: data_session.delete(x), users))
  650. data_session.commit()
  651. return redirect('/login?message=Срок действия ссылки истек, данные удалены&danger=True')
  652. @app.errorhandler(500)
  653. def internal_server_error(error):
  654. return render_template('page_error.html', title='Ошибка сервера', error='500', message='Технические шоколадки')
  655. @app.errorhandler(404)
  656. def page_not_found(error):
  657. return render_template('page_error.html', title='Страница не найдена', error='404', message='Страница не найдена')
  658. @app.errorhandler(403)
  659. def access_error(error):
  660. return render_template('page_error.html', title='Ошибка доступа', error='403', message='Доступ сюда запрещен')
  661. def main():
  662. db_path = 'db/incepted.db'
  663. db = os.path.exists(db_path)
  664. db_session.global_init(db_path)
  665. if not db:
  666. init_db_default()
  667. serve(app, host='0.0.0.0', port=5000, threads=100)
  668. if __name__ == '__main__':
  669. try:
  670. main()
  671. except Exception as error:
  672. logging.warning(f'{error}')