diff --git a/data/projects.py b/data/projects.py index 11d2412..409b29f 100644 --- a/data/projects.py +++ b/data/projects.py @@ -13,7 +13,7 @@ class Projects(SqlAlchemyBase, UserMixin): name = sqlalchemy.Column(sqlalchemy.String, nullable=False) description = sqlalchemy.Column(sqlalchemy.String, nullable=True) photo = sqlalchemy.Column(sqlalchemy.Text) - date_create = sqlalchemy.Column(sqlalchemy.Date, + date_create = sqlalchemy.Column(sqlalchemy.DateTime, default=date.today()) creator = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey("users.id"), nullable=True, default=None) diff --git a/forms/new_project.py b/forms/new_project.py index 30373ec..c5d9e08 100644 --- a/forms/new_project.py +++ b/forms/new_project.py @@ -7,4 +7,4 @@ class NewProjectForm(FlaskForm): name = StringField('Название', validators=[DataRequired()]) description = TextAreaField('Описание') logo = FileField('Логотип') - submit = SubmitField('Регистрация') + submit = SubmitField('Создать') diff --git a/functions.py b/functions.py index 49e2d32..463c48b 100644 --- a/functions.py +++ b/functions.py @@ -4,6 +4,7 @@ from data.roles import Roles from data.users import User from data.staff_projects import StaffProjects from data import db_session +import uuid def check_password(password=''): @@ -56,6 +57,7 @@ def init_db_default(): def get_user_data(user): resp = { + 'id': user.id, 'name': user.name, 'surname': user.surname, 'login': user.login, @@ -68,12 +70,21 @@ def get_user_data(user): def get_projects_data(project): data_session = db_session.create_session() + staff = data_session.query(StaffProjects.user).filter(StaffProjects.project == project.id).all() resp = { 'id': project.id, 'name': project.name, 'logo': project.photo, 'description': project.description, 'staff': list(map(lambda x: get_user_data(x), data_session.query(User).filter( - User.id.in_(*data_session.query(StaffProjects.user).filter(StaffProjects.id == project.id).all())).all())) + User.id.in_(list(map(lambda x: x[0], staff)))).all())) if staff else [] } + resp['staff'].insert(0, get_user_data(data_session.query(User).filter(User.id == project.creator).first())) return resp + + +def save_project_logo(photo): + filename = f'static/app_files/project_logo/{uuid.uuid4()}.png' + with open(filename, 'wb') as f: + photo.save(f) + return filename diff --git a/main.py b/main.py index 1a80c4a..b01d5b0 100644 --- a/main.py +++ b/main.py @@ -1,15 +1,16 @@ import datetime import os -import pprint from flask import Flask, render_template, request, url_for from flask_login import login_user, current_user, LoginManager, logout_user, login_required +from flask_wtf import CSRFProtect +from flask_restful import abort from werkzeug.datastructures import CombinedMultiDict from werkzeug.utils import redirect from itsdangerous import URLSafeTimedSerializer, SignatureExpired from sqlalchemy import or_ -from functions import check_password, mail, init_db_default, get_projects_data +from functions import check_password, mail, init_db_default, get_projects_data, get_user_data, save_project_logo from forms.edit_profile import EditProfileForm from forms.login import LoginForm from forms.register import RegisterForm @@ -25,6 +26,7 @@ from data import db_session app = Flask(__name__) key = 'test_secret_key' app.config['SECRET_KEY'] = key +csrf = CSRFProtect(app) s = URLSafeTimedSerializer(key) login_manager = LoginManager() login_manager.init_app(app) @@ -38,13 +40,62 @@ def base(): return redirect('/projects') +@app.route('/projects/delete/', methods=['GET', 'POST']) +def delete_project(id_project): + if current_user.is_authenticated: + data_session = db_session.create_session() + project_del = data_session.query(Projects).filter(Projects.id == id_project).first() + if project_del: + if project_del.creator == current_user.id: + staff = data_session.query(StaffProjects).filter(StaffProjects.project == id_project).all() + for i in staff: + data_session.delete(i) + if 'none_project' not in project_del.photo: + os.remove(project_del.photo) + data_session.delete(project_del) + data_session.commit() + data_session.close() + return redirect('/projects') + else: + abort(403) + else: + abort(404) + else: + return redirect('/login') + + @app.route('/projects/new', methods=['GET', 'POST']) def new_project(): if current_user.is_authenticated: form = NewProjectForm() + data_session = db_session.create_session() + list_users = list( + map(lambda x: get_user_data(x), data_session.query(User).filter(User.id != current_user.id).all())) if form.validate_on_submit(): - pass - return render_template('new_project.html', title='Новый проект', form=form) + project = Projects( + name=form.name.data, + description=form.description.data, + date_create=datetime.datetime.now(), + creator=current_user.id + ) + project.photo = save_project_logo(form.logo.data) if form.logo.data else 'static/images/none_project.png' + data_session.add(project) + data_session.flush() + data_session.refresh(project) + for i in list_users: + if request.form.getlist(f"choose_{i['login']}") and i['id'] != current_user.id: + new_staffer = StaffProjects( + user=i['id'], + project=project.id, + role='user', + permission=3 + ) + data_session.add(new_staffer) + data_session.commit() + data_session.close() + return redirect('/projects') + data_session.close() + return render_template('new_project.html', title='Новый проект', form=form, list_users=list_users) else: return redirect('/login') @@ -218,7 +269,12 @@ def confirmation(token): @app.errorhandler(404) def page_not_found(error): - return render_template('page404.html', title='Страница не найдена') + return render_template('page_error.html', title='Страница не найдена', error='404', message='Страница не найдена') + + +@app.errorhandler(403) +def page_not_found(error): + return render_template('page_error.html', title='Ошибка доступа', error='403', message='Доступ сюда запрещен') def main(): diff --git a/static/app_files/project_logo/заглушка b/static/app_files/project_logo/заглушка new file mode 100644 index 0000000..e69de29 diff --git a/static/css/new_project.css b/static/css/new_project.css index a2da0eb..c8100f7 100644 --- a/static/css/new_project.css +++ b/static/css/new_project.css @@ -26,13 +26,108 @@ align-items: center; } .input_button { - width: 10vw; + width: 35vw; height: 5vw; border-radius: 5vw; vertical-align: middle; } .form_label { + margin-top: 10px; font-size: 1.3vw; color: #ffffff; font-weight: bold; +} +.description { + border-radius: 2vw !important; + width: 50vw; +} +.padding_data { + padding-top: 1vw; + padding-left: 1vw; +} +.label_data { + padding-left: 0.8vw; + width: 50vw; +} +.project_button { + margin-top: 15px; + width: 35vw; + height: 5vw; + background-color: #000000; + color: #ffffff; + border-radius: 5vw; + vertical-align: middle; + font-size: 1.5vw; +} +.collaborator_block { + width: 30%; + height: 20vw; + background-color: #EDCBB0; + border-radius: 2vw; + overflow-y: auto; +} +.user { + width: 30vw; + height: 3.5vw; + background-color: #ffffff; + border: 2px solid #9E795A; + border-radius: 3vw; + margin-top: 5px; + display: inline-flex; + justify-content: space-between; +} +.user_logo { + margin-left: 3px; + width: 3vw; + height: 3vw; + border-radius: 5vw; + background-color: #000000; +} +.user_names { + margin-left: 9px; + margin-top: 10px; + overflow-x: auto; +} +.name_form_block { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; +} +.data_form_block { + width: 100%; + display: flex; + align-items: center; + justify-content: center; + flex-direction: row; +} +.buttons_form_block { + width: 45%; + display: flex; + flex-direction: column; + align-items: center; +} +.staff_form_block, .collaborator_block { + margin-top: 10px; + width: 60%; + height: 20vw; + display: flex; + align-items: center; + justify-content: center; +} +.staff_block { + margin: 5%; + width: 90%; + height: 20vw; +} +.choose_user { + align-self: flex-end; + margin-bottom: 1.1vw; + width: 10%; +} +.user_data { + display: inline-flex; + align-items: center; + justify-content: flex-start; + flex-direction: row; } \ No newline at end of file diff --git a/static/css/page404.css b/static/css/page_error.css similarity index 98% rename from static/css/page404.css rename to static/css/page_error.css index 8f618ad..449a1e8 100644 --- a/static/css/page404.css +++ b/static/css/page_error.css @@ -1,7 +1,7 @@ .navbar { display: none !important; } -.page_404 { +.page_error { height: 55vw; background-color: #dcb495; display: flex; diff --git a/static/css/profile.css b/static/css/profile.css index e08cae5..d2d8bfb 100644 --- a/static/css/profile.css +++ b/static/css/profile.css @@ -150,7 +150,7 @@ form { width: 20vw; height: 5vw; vertical-align: middle; - border-radius: 30px; + border-radius: 5vw; } .open_button:hover { text-decoration: none; @@ -162,4 +162,7 @@ form { text-align: center; font-size: 1.5vw; margin-top: 5%; +} +.about { + border-radius: 2vw !important; } \ No newline at end of file diff --git a/static/css/projects.css b/static/css/projects.css index 539b117..a547be7 100644 --- a/static/css/projects.css +++ b/static/css/projects.css @@ -39,8 +39,9 @@ width: 45vw; height: 5vw; color: #776658; - border-radius: 30px; + border-radius: 5vw; vertical-align: middle; + font-size: 1.5vw; } .find_input_button { margin-left: 12px; @@ -49,22 +50,23 @@ width: 10vw; height: 5vw; color: #ffffff; - border-radius: 30px; + border-radius: 5vw; vertical-align: middle; + font-size: 1.5vw; } .list_project_block { margin-left: 3%; - border: 2px solid #694a2d; - border-radius: 25px; + border: 0.2vw solid #694a2d; + border-radius: 4.5vw; width: 94%; height: 45vw; + overflow-y: auto; } .list_project { width: 95%; margin-left: 2.5%; - height: 95%; - margin-top: 2.5%; - overflow-y: auto; + margin-top: 2vw; + overflow-y: hidden; overflow-x: hidden; } .project_header_button { @@ -88,7 +90,7 @@ .project_logo_block { width: 4.5vw; height: 4.5vw; - border:2px solid #ffffff; + border: 0.3vw solid #ffffff; background-color: #ffffff; border-radius: 2vw; display: flex; diff --git a/templates/new_project.html b/templates/new_project.html index a9715fb..7c12a90 100644 --- a/templates/new_project.html +++ b/templates/new_project.html @@ -7,14 +7,14 @@
- {{ form.name(class="input_data", type="name", placeholder='your project name') }} + {{ form.name(class="input_data label_data", type="name", placeholder='your project name') }} {% for error in form.name.errors %} {% endfor %}
- {{ form.description(class="input_data", type="description", placeholder='your project description') }} + {{ form.description(class="input_data description padding_data", type="description", placeholder='your project description') }} {% for error in form.description.errors %} {% endfor %} @@ -22,14 +22,24 @@
-
- +
+
+ {% for user in list_users %} +
+
+ +

{{user.name}}

+
+ +
+ {% endfor %} +
- {{ form.logo(class="input_data file_data", type="file") }} + {{ form.logo(class="input_data padding_data", type="file") }} {% for error in form.logo.errors %} {% endfor %} diff --git a/templates/page404.html b/templates/page404.html deleted file mode 100644 index 1929df3..0000000 --- a/templates/page404.html +++ /dev/null @@ -1,27 +0,0 @@ - -{% extends "base.html" %} {% block content %} -
-
-
-
-
- Ошибка 404 -
-
-
-
-

Страница не найдена

-
-
-
-
-
- -
-{% endblock %} \ No newline at end of file diff --git a/templates/page_error.html b/templates/page_error.html new file mode 100644 index 0000000..b158a9e --- /dev/null +++ b/templates/page_error.html @@ -0,0 +1,27 @@ + +{% extends "base.html" %} {% block content %} +
+
+
+
+
+ {{ error }} +
+
+
+
+

{{ message }}

+
+
+
+
+
+ +
+{% endblock %} \ No newline at end of file diff --git a/templates/profile.html b/templates/profile.html index 4a55ff3..a57cbe4 100644 --- a/templates/profile.html +++ b/templates/profile.html @@ -64,7 +64,7 @@
- {{ form.about(class="input_data dop_data", type="name", + {{ form.about(class="input_data dop_data about", type="name", placeholder='about') }} {% for error in form.about.errors %} {% endfor %} diff --git a/templates/projects.html b/templates/projects.html index 4736ccc..7814c3c 100644 --- a/templates/projects.html +++ b/templates/projects.html @@ -19,12 +19,12 @@
{% for project in list_projects %} -
+
-

+

-
+