Ver Fonte

Создана страница редактирования информации и удаления проекта, создал таблицу с "задачами"

Andrei há 3 anos atrás
pai
commit
1239819eca

+ 1 - 0
data/quests.py

@@ -1,5 +1,6 @@
 import sqlalchemy
 from flask_login import UserMixin
+from datetime import date
 
 from .db_session import SqlAlchemyBase
 

+ 8 - 0
forms/conf_delete_project.py

@@ -0,0 +1,8 @@
+from flask_wtf import FlaskForm
+from wtforms import StringField, SubmitField
+from wtforms.validators import DataRequired
+
+
+class DeleteProjectForm(FlaskForm):
+    conf = StringField('', validators=[DataRequired()])
+    submit = SubmitField('Подтвердить')

+ 3 - 1
forms/new_project.py → forms/project.py

@@ -3,8 +3,10 @@ from wtforms import StringField, SubmitField, TextAreaField, FileField
 from wtforms.validators import DataRequired
 
 
-class NewProjectForm(FlaskForm):
+class ProjectForm(FlaskForm):
     name = StringField('Название', validators=[DataRequired()])
     description = TextAreaField('Описание')
     logo = FileField('Логотип')
     submit = SubmitField('Создать')
+    del_photo = SubmitField('Удалить фотографию')
+    save = SubmitField('Сохранить')

+ 84 - 21
main.py

@@ -15,8 +15,9 @@ from forms.edit_profile import EditProfileForm
 from forms.login import LoginForm
 from forms.find_project import FindProjectForm
 from forms.register import RegisterForm
-from forms.new_project import NewProjectForm
+from forms.project import ProjectForm
 from forms.recovery import RecoveryForm, NewPasswordForm
+from forms.conf_delete_project import DeleteProjectForm
 
 from data.users import User
 from data.quests import Quests
@@ -43,6 +44,63 @@ def base():
         return redirect('/projects')
 
 
+@app.route('/project/<int:id_project>/edit', methods=['GET', 'POST'])
+def edit_project(id_project):
+    if current_user.is_authenticated:
+        data_session = db_session.create_session()
+        current_project = data_session.query(Projects).filter(Projects.id == id_project).first()
+        if current_project:
+            staff = data_session.query(StaffProjects).filter(StaffProjects.project == current_project.id).all()
+            if current_user.id == current_project.creator or current_user.id in list(map(lambda x: x.user, staff)):
+                list_users = list(
+                    map(lambda x: get_user_data(x), data_session.query(User).filter(User.id != current_user.id).all()))
+                staff = list(map(lambda x: get_user_data(x), data_session.query(User).filter(
+                    User.id.in_(list(map(lambda x: x.user, staff)))).all())) if staff else []
+                form = ProjectForm()
+                if form.save.data:
+                    new_staff = []
+                    for i in list_users:
+                        if request.form.getlist(f"choose_{i['login']}") and i['id'] != current_user.id:
+                            new_staff.append(i)
+                            if i not in staff:
+                                new_staffer = StaffProjects(
+                                    user=i['id'],
+                                    project=current_project.id,
+                                    role='user',
+                                    permission=3
+                                )
+                                data_session.add(new_staffer)
+                        data_session.commit()
+                    if sorted(new_staff, key=lambda x: x['id']) != sorted(staff, key=lambda x: x['id']):
+                        for i in staff:
+                            if i not in new_staff:
+                                data_session.delete(data_session.query(StaffProjects).filter(
+                                    StaffProjects.user == i['id'], StaffProjects.project == current_project.id).first())
+                        data_session.commit()
+                    if form.logo.data:
+                        current_project.photo = save_project_logo(form.logo.data)
+                        data_session.commit()
+                    current_project.name = form.name.data
+                    current_project.description = form.description.data
+                    data_session.commit()
+                    return redirect(f'/project/{current_project.id}/edit')
+                if form.del_photo.data:
+                    os.remove(current_project.photo)
+                    current_project.photo = 'static/images/none_project.png'
+                    data_session.commit()
+                    return redirect(f'/project/{current_project.id}/edit')
+                form.name.data = current_project.name
+                form.description.data = current_project.description
+                return render_template('edit_project.html', title='Изменение проекта', form=form, list_users=list_users,
+                                       staff=staff, project=current_project)
+            else:
+                abort(403)
+        else:
+            abort(404)
+    else:
+        return redirect('/login')
+
+
 @app.route('/project/<int:id_project>')
 def project(id_project):
     if current_user.is_authenticated:
@@ -51,6 +109,7 @@ def project(id_project):
         if current_project:
             staff = data_session.query(StaffProjects).filter(StaffProjects.project == current_project.id).all()
             if current_user.id == current_project.creator or current_user.id in list(map(lambda x: x.user, staff)):
+
                 return render_template('project.html', project=current_project, title=current_project.name)
             else:
                 abort(403)
@@ -103,22 +162,29 @@ def recovery():
         return redirect('/')
 
 
-@app.route('/projects/delete/<int:id_project>', methods=['GET', 'POST'])
+@app.route('/project/<int:id_project>/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')
+                form = DeleteProjectForm()
+                if form.validate_on_submit():
+                    if form.conf.data != f'delete/{project_del.name}':
+                        return render_template('delete_project.html', title='Удаление проекта', form=form,
+                                               project=project_del,
+                                               message='Вы не правильно ввели фразу')
+                    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()
+                    return redirect('/projects')
+                return render_template('delete_project.html', title='Удаление проекта', form=form, project=project_del,
+                                       message='')
             else:
                 abort(403)
         else:
@@ -149,7 +215,7 @@ def user_view(_login):
 @app.route('/projects/new', methods=['GET', 'POST'])
 def new_project():
     if current_user.is_authenticated:
-        form = NewProjectForm()
+        form = ProjectForm()
         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()))
@@ -175,9 +241,7 @@ def new_project():
                     )
                     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')
@@ -231,7 +295,6 @@ def profile():
             os.remove(current_user.photo)
             user.photo = 'static/images/none_logo.png'
             data_session.commit()
-            data_session.close()
         if form.validate_on_submit():
             data_session = db_session.create_session()
             user = data_session.query(User).filter(User.id == current_user.id).first()
@@ -249,7 +312,6 @@ def profile():
             user.about = form.about.data
             user.birthday = form.birthday.data
             data_session.commit()
-            data_session.close()
             return redirect('/profile')
         return render_template('profile.html', title='Профиль', form=form, message='')
     else:
@@ -273,7 +335,6 @@ def login():
             user = data_session.query(User).filter(User.email == form.login.data).first()
             if not user:
                 user = data_session.query(User).filter(User.login == form.login.data).first()
-            data_session.close()
             if user and user.check_password(form.password.data):
                 if user.activated:
                     login_user(user, remember=form.remember_me.data)
@@ -326,7 +387,6 @@ def register():
             user.set_password(form.password.data)
             data_session.add(user)
             data_session.commit()
-            data_session.close()
             token = s.dumps(form.email.data)
             link_conf = url_for('confirmation', token=token, _external=True)
             mail(f'Для завершения регистрации пройдите по ссылке: {link_conf}', form.email.data,
@@ -346,7 +406,6 @@ def confirmation(token):
         if user:
             user.activated = True
             data_session.commit()
-            data_session.close()
             return redirect('/login?message=Почта успешно подтверждена')
         else:
             return redirect('/login?message=Пользователь не найден&danger=True')
@@ -357,17 +416,21 @@ def confirmation(token):
         if users:
             list(map(lambda x: data_session.delete(x), users))
             data_session.commit()
-        data_session.close()
         return redirect('/login?message=Срок действия ссылки истек, данные удалены&danger=True')
 
 
+@app.errorhandler(500)
+def internal_server_error(error):
+    return render_template('page_error.html', title='Ошибка сервера', error='500', message='Технические шоколадки')
+
+
 @app.errorhandler(404)
 def page_not_found(error):
     return render_template('page_error.html', title='Страница не найдена', error='404', message='Страница не найдена')
 
 
 @app.errorhandler(403)
-def page_not_found(error):
+def access_error(error):
     return render_template('page_error.html', title='Ошибка доступа', error='403', message='Доступ сюда запрещен')
 
 

+ 4 - 4
static/css/base.css

@@ -62,7 +62,7 @@ body {
     align-items: center;
 }
 .nav_user_name {
-    margin-left: 10px;
+    margin-left: 1vw;
     align-self: center;
 }
 .nav_chapter_text {
@@ -90,10 +90,10 @@ body {
     height: 100%;
 }
 body::-webkit-scrollbar {
-  width: 12px;               /* ширина scrollbar */
+  width: 0.8vw;               /* ширина scrollbar */
 }
 body::-webkit-scrollbar-thumb {
   background-color: #d49d51;    /* цвет плашки */
-  border-radius: 20px;       /* закругления плашки */
-  border: 3px solid #ffffff;
+  border-radius: 5vw;       /* закругления плашки */
+  border: 0.25vw solid #ffffff;
 }

+ 60 - 0
static/css/delete_project.css

@@ -0,0 +1,60 @@
+.delete_project_page {
+    height: 60vw;
+    background-color: #dcb495;
+}
+.form_block {
+    width: 100%;
+    height: 60vw;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-direction: column;
+}
+.form_data {
+    display: flex;
+    flex-direction: column;
+    margin-left: 2%;
+}
+.input_data {
+    color: #000000;
+    border: 0.1vw solid #595008;
+    height: 4.5vw;
+    min-height: 4.5vw;
+    width: 35vw;
+    background-color: #dbc3af;
+    border-radius: 4.5vw;
+    font-size: 1.3vw;
+    display: inline-flex;
+    align-items: center;
+}
+.form_label {
+    margin-top: 10px;
+    font-size: 1.3vw;
+    color: #ffffff;
+    font-weight: bold;
+}
+.delete_project_button {
+    margin-left: 15px;
+    width: 25vw;
+    height: 5vw;
+    background-color: #000000;
+    color: #ffffff;
+    border-radius: 5vw;
+    vertical-align: middle;
+    font-size: 1.5vw;
+}
+form {
+    display: flex;
+    align-items: flex-end;
+    justify-content: center;
+}
+.conf_text {
+    color: #ff0000;
+}
+.header_title {
+    text-align: center;
+    color: #000000;
+    font-size: 3.5vw;
+    width: 100%;
+    margin-bottom: 15px;
+}

+ 149 - 0
static/css/edit_project.css

@@ -0,0 +1,149 @@
+.edit_project_page {
+    height: 120vw;
+    background-color: #dcb495;
+}
+.form_data, .form_data_button {
+    display: flex;
+    flex-direction: column;
+    margin-left: 2%;
+}
+.form_data_button {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+}
+.input_data {
+    color: #000000;
+    border: 0.1vw solid #595008;
+    height: 4.5vw;
+    min-height: 4.5vw;
+    width: 35vw;
+    background-color: #dbc3af;
+    border-radius: 4.5vw;
+    font-size: 1.3vw;
+    display: inline-flex;
+    align-items: center;
+}
+.input_button {
+    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, .delete_button, .delete_project_link {
+    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;
+}
+.delete_project_link {
+    background-color: #ff3f3f;
+}
+.delete_project_link:hover {
+    background-color: #ff3f3f;
+    text-decoration: none;
+    color: #ffffff;
+}
+.delete_project_link_text {
+    width: 35vw;
+    height: 5vw;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-top: 10px;
+}

+ 27 - 0
static/css/project.css

@@ -22,7 +22,34 @@
     flex-direction: column;
     align-items: center;
     justify-content: space-between;
+    color: #dcb495
+    #a8886f
+    #f5d3b8
+    #a65b1e
+    #d49d51
+    #face7d
+    #ffe8d6
+    #a8876b
+    #fff2e8
+    #c79b77
+    #d69d5c;
 }
 .name_project {
     font-size: 3vw;
+}
+.edit_block {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+.edit_button {
+    width: 4.5vw;
+    height: 4.5vw;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+.edit_button_image {
+    height: 3vw;
+    width: 3vw;
 }

BIN
static/images/pen_b.png


BIN
static/images/pen_w.png


+ 2 - 0
static/js/project.js

@@ -0,0 +1,2 @@
+var edit_button = document.getElementById("edit_button");
+edit_button.href = String(window.location.href) + '/edit';

+ 26 - 0
templates/delete_project.html

@@ -0,0 +1,26 @@
+<link rel="stylesheet" href="../../static/css/delete_project.css"/>
+{% extends "base.html" %} {% block content %}
+{% set name = 'delete/' + project.name %}
+<div class="delete_project_page">
+    <div class="form_block">
+        <h1 class="header_title">Удаление проекта</h1>
+        <form action="" method="post" class="register_form" enctype="multipart/form-data">
+            {{ form.hidden_tag() }}
+            <div class="form_data">
+                <label class="form_label">Для подтверждения удаления введите <p class="conf_text">delete/{{ project.name
+                    }}</p></label>
+                {{ form.conf(class="input_data", type="conf", placeholder=name) }}
+                {% for error in form.conf.errors %}
+                <div class="alert alert-danger" role="alert">{{ error }}</div>
+                {% endfor %}
+            </div>
+            {{ form.submit(type="submit", class="delete_project_button") }}
+        </form>
+        {% if message != '' %}
+        <div class="alert alert-danger message" role="alert">
+            {{ message }}
+        </div>
+        {% endif %}
+    </div>
+</div>
+{% endblock %}

+ 68 - 0
templates/edit_project.html

@@ -0,0 +1,68 @@
+<link rel="stylesheet" href="../../static/css/edit_project.css"/>
+{% extends "base.html" %} {% block content %}
+<div class="edit_project_page">
+    <div class="form_block">
+        <form action="" method="post" class="register_form" enctype="multipart/form-data">
+            {{ form.hidden_tag() }}
+            <div class="name_form_block">
+                <div class="form_data">
+                    <label class="form_label">{{ form.name.label }}</label>
+                    {{ form.name(class="input_data label_data", type="name", placeholder='your project name') }}
+                    {% for error in form.name.errors %}
+                    <div class="alert alert-danger" role="alert">{{ error }}</div>
+                    {% endfor %}
+                </div>
+                <div class="form_data">
+                    <label class="form_label">{{ form.description.label }}</label>
+                    {{ form.description(class="input_data description padding_data", type="description", placeholder='your project description') }}
+                    {% for error in form.description.errors %}
+                    <div class="alert alert-danger" role="alert">{{ error }}</div>
+                    {% endfor %}
+                </div>
+            </div>
+            <div class="data_form_block">
+                <div class="staff_form_block">
+                    <div class="collaborator_block">
+                        <div class="staff_block">
+                            {% for user in list_users %}
+                            <div class="user">
+                                <div class="user_data">
+                                    <img class="user_logo" src="../../{{user.photo}}">
+                                    <p class="user_names">{{user['name']}}</p>
+                                </div>
+                                {% if user not in staff %}
+                                <input class="choose_user" name="choose_{{user.login}}" type="checkbox" value="y">
+                                {% else %}
+                                <input class="choose_user" name="choose_{{user.login}}" type="checkbox" value="y" checked="yes">
+                                {% endif %}
+                            </div>
+                            {% endfor %}
+                        </div>
+                    </div>
+                </div>
+                <div class="buttons_form_block">
+                    {% if 'none' in project.photo %}
+                        <div class="form_data">
+                            <label class="form_label">{{ form.logo.label }}</label>
+                            {{ form.logo(class="input_data padding_data", type="file") }}
+                            {% for error in form.logo.errors %}
+                            <div class="alert alert-danger" role="alert">{{ error }}</div>
+                            {% endfor %}
+                        </div>
+                        {% else %}
+                        <div class="form_data_button">
+                            {{ form.del_photo(type="submit", class="delete_button") }}
+                        </div>
+                        {% endif %}
+                    <div class="form_data_button">
+                        {{ form.save(type="submit", class="project_button") }}
+                    </div>
+                    <a class="delete_project_link form_data_button" id="delete_project_link" href="/project/{{ project.id }}/delete">
+                        <p class="delete_project_link_text">Удалить проект</p>
+                    </a>
+                </div>
+            </div>
+        </form>
+    </div>
+</div>
+{% endblock %}

+ 4 - 1
templates/project.html

@@ -3,7 +3,9 @@
 <div class="projects_page">
     <div class="project_header">
         <div class="edit_block">
-
+            <a id="edit_button" class="edit_button" href="">
+                <img class="edit_button_image" src="../static/images/pen_b.png">
+            </a>
         </div>
         <div class="brand_block">
             <img class="project_logo" src="../{{project.photo}}"/>
@@ -25,4 +27,5 @@
 
     </div>
 </div>
+<script type="text/javascript" src="../static/js/project.js"></script>
 {% endblock %}