Изменена страница списка проектов, создан шаблон страницы создания нового проекта, изменены таблицы в базе данных

This commit is contained in:
Andrei 2023-01-21 22:08:52 +05:00
parent afca8cf50c
commit 709d2f971d
14 changed files with 395 additions and 20 deletions

View File

@ -11,7 +11,7 @@ class Projects(SqlAlchemyBase, UserMixin):
id = sqlalchemy.Column(sqlalchemy.Integer,
primary_key=True, autoincrement=True)
name = sqlalchemy.Column(sqlalchemy.String, nullable=False)
about = sqlalchemy.Column(sqlalchemy.String, nullable=True)
description = sqlalchemy.Column(sqlalchemy.String, nullable=True)
photo = sqlalchemy.Column(sqlalchemy.Text)
date_create = sqlalchemy.Column(sqlalchemy.Date,
default=date.today())

View File

@ -11,6 +11,8 @@ class StaffProjects(SqlAlchemyBase, UserMixin):
primary_key=True, autoincrement=True)
user = sqlalchemy.Column(sqlalchemy.Integer,
sqlalchemy.ForeignKey("users.id"), nullable=True, default=None)
project = sqlalchemy.Column(sqlalchemy.Integer,
sqlalchemy.ForeignKey("projects.id"), nullable=True, default=None)
role = sqlalchemy.Column(sqlalchemy.Text)
permission = sqlalchemy.Column(sqlalchemy.Integer,
sqlalchemy.ForeignKey("roles.id"), nullable=True, default=None)
sqlalchemy.ForeignKey("roles.id"), nullable=True, default=None)

View File

@ -7,7 +7,7 @@ from wtforms.validators import DataRequired
class EditProfileForm(FlaskForm):
email = EmailField('Почта', validators=[DataRequired()])
name = StringField('Имя', validators=[DataRequired()])
surname = StringField('Фамилия', )
surname = StringField('Фамилия')
about = TextAreaField('Расскажите о себе', default='')
birthday = DateField('Дата рождения')
photo = FileField('Фото', validators=[FileAllowed(['jpg', 'png', 'bmp'], 'Только фотографии!')])

10
forms/new_project.py Normal file
View File

@ -0,0 +1,10 @@
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, TextAreaField, FileField
from wtforms.validators import DataRequired
class NewProjectForm(FlaskForm):
name = StringField('Название', validators=[DataRequired()])
description = TextAreaField('Описание')
logo = FileField('Логотип')
submit = SubmitField('Регистрация')

View File

@ -1,5 +1,4 @@
from flask_wtf import FlaskForm
from flask_wtf.file import FileAllowed
from wtforms import EmailField, StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired

View File

@ -1,6 +1,8 @@
import smtplib
from email.message import EmailMessage
from data.roles import Roles
from data.users import User
from data.staff_projects import StaffProjects
from data import db_session
@ -50,3 +52,28 @@ def init_db_default():
data_session.add(role)
data_session.commit()
data_session.close()
def get_user_data(user):
resp = {
'name': user.name,
'surname': user.surname,
'login': user.login,
'email': user.email,
'photo': user.photo,
'role': user.role
}
return resp
def get_projects_data(project):
data_session = db_session.create_session()
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()))
}
return resp

30
main.py
View File

@ -1,18 +1,24 @@
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 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
from functions import check_password, mail, init_db_default, get_projects_data
from forms.edit_profile import EditProfileForm
from forms.login import LoginForm
from forms.register import RegisterForm
from forms.new_project import NewProjectForm
from data.users import User
from data.files import Files
from data.projects import Projects
from data.staff_projects import StaffProjects
from waitress import serve
from data import db_session
@ -32,12 +38,30 @@ def base():
return redirect('/projects')
@app.route('/projects/new', methods=['GET', 'POST'])
def new_project():
if current_user.is_authenticated:
form = NewProjectForm()
if form.validate_on_submit():
pass
return render_template('new_project.html', title='Новый проект', form=form)
else:
return redirect('/login')
@app.route('/projects', methods=['GET', 'POST'])
def project():
if current_user.is_authenticated:
data_session = db_session.create_session()
resp = []
if request.method == 'POST':
print(request.form.to_dict())
return render_template('projects.html', title='Проекты')
pass
else:
projects = data_session.query(Projects).filter(or_(Projects.creator == current_user.id, current_user.id in
data_session.query(StaffProjects.project).filter(
StaffProjects.user == current_user.id).all())).all()
resp = list(map(lambda x: get_projects_data(x), projects))
return render_template('projects.html', title='Проекты', list_projects=resp)
else:
return redirect('/login')

View File

@ -0,0 +1,38 @@
.new_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: 10vw;
height: 5vw;
border-radius: 5vw;
vertical-align: middle;
}
.form_label {
font-size: 1.3vw;
color: #ffffff;
font-weight: bold;
}

View File

@ -51,7 +51,6 @@ form {
display: flex;
flex-direction: column;
margin-left: 2%;
margin-left: 2%;
}
.form_data_button {
display: flex;

View File

@ -64,4 +64,201 @@
margin-left: 2.5%;
height: 95%;
margin-top: 2.5%;
overflow-y: auto;
overflow-x: hidden;
}
.project_header_button {
height: 5.5vw;
width: 100%;
text-align: left;
border-radius: 5vw;
background-color: #9E795A;
border-color: #9E795A;
border-bottom-color: #9E795A;
color: #ffffff;
display: flex;
align-items: center;
}
.project_description_block {
background-color: #9E795A;
width: 100%;
height: 20vw;
border-radius: 2vw;
}
.project_logo_block {
width: 4.5vw;
height: 4.5vw;
border:2px solid #ffffff;
background-color: #ffffff;
border-radius: 2vw;
display: flex;
justify-content: center;
align-items: center;
}
.project_logo {
width: 4vw;
height: 4vw;
border-radius: 5vw;
}
.project_title_block {
width: 70%;
height: 4vw;
}
.project_title {
font-size: 3.5vw;
}
.project_button_block_one {
width: 50%;
display: flex;
justify-content: space-evenly;
align-items: flex-start;
}
.project_description {
width: 98%;
height: 100%;
margin-left: 1%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
align-items: center;
justify-content: space-evenly;
}
.collaborator_block {
width: 22%;
height: 90%;
background-color: #EDCBB0;
border-radius: 2vw;
overflow-y: auto;
}
.description_block {
width: 48%;
height: 90%;
display: flex;
flex-direction: column;
align-items: center;
flex-wrap: nowrap;
}
.description_header_text {
font-size: 2vw;
}
.description_block_text {
width: 90% !important;
height: 80% !important;
width: 50%;
background-color: #dcb495;
border-radius: 2vw;
}
.description_text {
width: 100% !important;
height: 100%;
font-size: 1.5vw;
overflow-wrap: normal; /* не поддерживает IE, Firefox; является копией word-wrap */
word-wrap: normal;
word-break: normal; /* не поддерживает Opera12.14, значение keep-all не поддерживается IE, Chrome */
line-break: auto; /* нет поддержки для русского языка */
hyphens: manual; /* значение auto не поддерживается Chrome */
margin: 2vw;
}
.open_project_block {
width: 20%;
height: 90%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
flex-wrap: nowrap;
}
.open_button {
background-color: #ffffff;
color: #000000;
width: 15vw;
height: 4.5vw;
vertical-align: middle;
border-radius: 5vw;
display: flex;
align-items: center;
justify-content: center;
}
.open_button:hover {
text-decoration: none;
color: #000000;
}
.open_button_text {
font-size: 1.5vw;
margin-top: 15px;
display: flex;
align-items: center;
justify-content: center;
}
.open_button, .open_button_link {
display: flex;
align-items: center;
justify-content: center;
width: 15vw;
height: 4.5vw;
color: #000000;
}
.open_button_link:hover {
text-decoration: none;
color: #000000;
}
.staff_block {
margin: 20px;
}
.user {
width: 16vw;
height: 3.5vw;
background-color: #ffffff;
border: 2px solid #9E795A;
border-radius: 3vw;
margin-top: 5px;
display: flex;
align-items: center;
justify-content: flex-start;
flex-direction: row;
flex-wrap: no-wrap;
}
.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;
}
.new_project_button {
width: 13vw;
height: 5vw;
background-color: #000000;
border: 2px solid #ffffff;
border-radius: 3vw;
margin-left: 2vw;
}
.new_project_button_text {
width: 13vw;
height: 5vw;
text-align: center;
font-size: 1.5vw;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
.new_project_button_link {
width: 13vw;
height: 5vw;
}
.new_project_button_link:hover {
text-decoration: none;
color: #000000;
}
.form_project_block {
display: flex;
align-items: center;
justify-content: center;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -0,0 +1,45 @@
<link rel="stylesheet" href="../static/css/new_project.css"/>
{% extends "base.html" %} {% block content %}
<div class="new_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", 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') }}
{% 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="staff_list">
</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") }}
{% for error in form.logo.errors %}
<div class="alert alert-danger" role="alert">{{ error }}</div>
{% endfor %}
</div>
<div class="form_data_button">
{{ form.submit(type="submit", class="project_button") }}
</div>
</div>
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -5,7 +5,8 @@
<div class="open_button_content">
<h2 class="open_button_title">Профиль</h2>
<p class="open_button_article">Здесь можно поменять настройки учетной записи</p>
<a class="open_button" data-bs-toggle="collapse" href="#collapseExample" role="button" aria-expanded="false" aria-controls="collapseExample">
<a class="open_button" data-bs-toggle="collapse" href="#collapseExample" role="button" aria-expanded="false"
aria-controls="collapseExample">
<div class="open_button_text">
Редикторовать
</div>

View File

@ -7,34 +7,67 @@
добавлять участников в своей проект.</strong>
</div>
<div class="find_block">
<form action="" method="post">
<form action="" method="post" class="form_project_block">
<input class="find_input_text" type="text" placeholder="Имя проекта" name="find_text">
<button class="find_input_button">Поиск</button>
<div class="new_project_button">
<a class="new_project_button_link" href="/projects/new">
<p class="new_project_button_text">Создать</p>
</a>
</div>
</form>
</div>
<div class="list_project_block">
{% for project in list_projects %}
<div class="accordion list_project" id="accordionPanelsStayOpenExample">
<div class="accordion-item project">
<h2 class="accordion-header project_header" id="panelsStayOpen-headingOne">
<button class="accordion-button priject_header_button" type="button" data-bs-toggle="collapse"
<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">
Project 1
<div class="project_button_block_one">
<div class="project_logo_block">
<img src="{{ project.logo }}" class="project_logo">
</div>
<div class="project_title_block">
<p class="project_title">{{ project.name }}</p>
</div>
</div>
</button>
</h2>
<div id="panelsStayOpen-collapseOne" class="accordion-collapse collapse"
<div id="panelsStayOpen-collapseOne" class="accordion-collapse collapse project_description_block"
aria-labelledby="panelsStayOpen-headingOne">
<div class="accordion-body">
<strong>This is the first item's accordion body.</strong> It is shown by default, until the
collapse plugin adds the appropriate classes that we use to style each element. These classes
control the overall appearance, as well as the showing and hiding via CSS transitions. You can
modify any of this with custom CSS or overriding our default variables. It's also worth noting
that just about any HTML can go within the <code>.accordion-body</code>, though the transition
does limit overflow.
<div class="accordion-body project_description">
<div class="collaborator_block">
<div class="staff_block">
{% for user in project.staff %}
<div class="user">
<img class="user_logo" src="{{user.photo}}">
<p class="user_names">{{user.name}}</p>
</div>
{% endfor %}
</div>
</div>
<div class="description_block">
<div class="description_header_block">
<p class="description_header_text">Описание</p>
</div>
<div class="description_block_text">
<p class="description_text">{{ project.description }}</p>
</div>
</div>
<div class="open_project_block">
<div class="open_button">
<a class="open_button_link" href="/projects/{{ project.id }}">
<p class="open_button_text">Открыть</p>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}