main.py 42 KB

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