Создана страница добавления проектов, проекты отображаются в списке проектов, добавлена функция удаления проекта
This commit is contained in:
parent
709d2f971d
commit
22da6ee3ef
@ -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)
|
||||
|
||||
@ -7,4 +7,4 @@ class NewProjectForm(FlaskForm):
|
||||
name = StringField('Название', validators=[DataRequired()])
|
||||
description = TextAreaField('Описание')
|
||||
logo = FileField('Логотип')
|
||||
submit = SubmitField('Регистрация')
|
||||
submit = SubmitField('Создать')
|
||||
|
||||
13
functions.py
13
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
|
||||
|
||||
66
main.py
66
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/<int:id_project>', 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():
|
||||
|
||||
0
static/app_files/project_logo/заглушка
Normal file
0
static/app_files/project_logo/заглушка
Normal file
@ -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;
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
.navbar {
|
||||
display: none !important;
|
||||
}
|
||||
.page_404 {
|
||||
.page_error {
|
||||
height: 55vw;
|
||||
background-color: #dcb495;
|
||||
display: flex;
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -7,14 +7,14 @@
|
||||
<div class="name_form_block">
|
||||
<div class="form_data">
|
||||
<label class="form_label">{{ form.name.label }}</label>
|
||||
{{ 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 %}
|
||||
<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", 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 %}
|
||||
<div class="alert alert-danger" role="alert">{{ error }}</div>
|
||||
{% endfor %}
|
||||
@ -22,14 +22,24 @@
|
||||
</div>
|
||||
<div class="data_form_block">
|
||||
<div class="staff_form_block">
|
||||
<div class="staff_list">
|
||||
|
||||
<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>
|
||||
<input class="choose_user" name="choose_{{user.login}}" type="checkbox" value="y">
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons_form_block">
|
||||
<div class="form_data">
|
||||
<label class="form_label">{{ form.logo.label }}</label>
|
||||
{{ form.logo(class="input_data file_data", type="file") }}
|
||||
{{ 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 %}
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
<link rel="stylesheet" href="../static/css/page404.css"/>
|
||||
{% extends "base.html" %} {% block content %}
|
||||
<div class="page_404">
|
||||
<div class="header_block">
|
||||
<div class="header">
|
||||
<hr class="line_top">
|
||||
<div class="header_rect">
|
||||
<strong class="header_rect_text">Ошибка 404</strong>
|
||||
</div>
|
||||
<hr class="line_top">
|
||||
</div>
|
||||
<div class="header">
|
||||
<h2 class="header_title">Страница не найдена</h2>
|
||||
</div>
|
||||
<div class="header">
|
||||
<hr class="line_bottom">
|
||||
</div>
|
||||
</div>
|
||||
<div class="link_block">
|
||||
<div class="block_to_home">
|
||||
<a class="link_to_home" href="/#header_block">
|
||||
<img class="link_image" src="../static/images/logo_w.png">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
27
templates/page_error.html
Normal file
27
templates/page_error.html
Normal file
@ -0,0 +1,27 @@
|
||||
<link rel="stylesheet" href="../../../../static/css/page_error.css"/>
|
||||
{% extends "base.html" %} {% block content %}
|
||||
<div class="page_error">
|
||||
<div class="header_block">
|
||||
<div class="header">
|
||||
<hr class="line_top">
|
||||
<div class="header_rect">
|
||||
<strong class="header_rect_text">{{ error }}</strong>
|
||||
</div>
|
||||
<hr class="line_top">
|
||||
</div>
|
||||
<div class="header">
|
||||
<h2 class="header_title">{{ message }}</h2>
|
||||
</div>
|
||||
<div class="header">
|
||||
<hr class="line_bottom">
|
||||
</div>
|
||||
</div>
|
||||
<div class="link_block">
|
||||
<div class="block_to_home">
|
||||
<a class="link_to_home" href="/#header_block">
|
||||
<img class="link_image" src="../../../../static/images/logo_w.png">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -64,7 +64,7 @@
|
||||
</div>
|
||||
<div class="form_data">
|
||||
<label class="form-label">{{ form.about.label }}</label>
|
||||
{{ 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 %}
|
||||
<div class="alert alert-danger" role="alert">{{ error }}</div>
|
||||
{% endfor %}
|
||||
|
||||
@ -19,12 +19,12 @@
|
||||
</div>
|
||||
<div class="list_project_block">
|
||||
{% for project in list_projects %}
|
||||
<div class="accordion list_project" id="accordionPanelsStayOpenExample">
|
||||
<div class="accordion list_project" id="accordionPanelsStayOpen{{ project.id }}">
|
||||
<div class="accordion-item project">
|
||||
<h2 class="accordion-header project_header" id="panelsStayOpen-headingOne">
|
||||
<h2 class="accordion-header project_header" id="panelsStayOpen-heading{{ project.id }}">
|
||||
<button class="accordion-button project_header_button" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#panelsStayOpen-collapseOne" aria-expanded="true"
|
||||
aria-controls="panelsStayOpen-collapseOne">
|
||||
data-bs-target="#panelsStayOpen-collapse{{ project.id }}" aria-expanded="true"
|
||||
aria-controls="panelsStayOpen-collapse{{ project.id }}">
|
||||
<div class="project_button_block_one">
|
||||
<div class="project_logo_block">
|
||||
<img src="{{ project.logo }}" class="project_logo">
|
||||
@ -35,8 +35,8 @@
|
||||
</div>
|
||||
</button>
|
||||
</h2>
|
||||
<div id="panelsStayOpen-collapseOne" class="accordion-collapse collapse project_description_block"
|
||||
aria-labelledby="panelsStayOpen-headingOne">
|
||||
<div id="panelsStayOpen-collapse{{ project.id }}" class="accordion-collapse collapse project_description_block"
|
||||
aria-labelledby="panelsStayOpen-heading{{ project.id }}">
|
||||
<div class="accordion-body project_description">
|
||||
<div class="collaborator_block">
|
||||
<div class="staff_block">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user