main.py 42 KB

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