main.py 39 KB

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