main.py 35 KB

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