diff --git a/data/users.py b/data/users.py index ebb0173..c2823e6 100644 --- a/data/users.py +++ b/data/users.py @@ -23,8 +23,9 @@ class User(SqlAlchemyBase, UserMixin): data_reg = sqlalchemy.Column(sqlalchemy.Date, default=date.today()) role = sqlalchemy.Column(sqlalchemy.String, nullable=True) - activity = sqlalchemy.Column(sqlalchemy.Date, nullable=True) + activity = sqlalchemy.Column(sqlalchemy.DateTime, nullable=True) birthday = sqlalchemy.Column(sqlalchemy.Date, nullable=True) + activated = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False, default=False) def check_password(self, password): return check_password_hash(self.password, password) diff --git a/forms/login.py b/forms/login.py new file mode 100644 index 0000000..2d168dc --- /dev/null +++ b/forms/login.py @@ -0,0 +1,10 @@ +from flask_wtf import FlaskForm +from wtforms import EmailField, PasswordField, BooleanField, SubmitField +from wtforms.validators import DataRequired + + +class LoginForm(FlaskForm): + email = EmailField('Почта', validators=[DataRequired()]) + password = PasswordField('Пароль', validators=[DataRequired()]) + remember_me = BooleanField('Запомнить меня') + submit = SubmitField('Войти') \ No newline at end of file diff --git a/forms/register.py b/forms/register.py new file mode 100644 index 0000000..5872b19 --- /dev/null +++ b/forms/register.py @@ -0,0 +1,12 @@ +from flask_wtf import FlaskForm +from flask_wtf.file import FileAllowed +from wtforms import EmailField, StringField, PasswordField, SubmitField, FileField, DateField, TextAreaField +from wtforms.validators import DataRequired + + +class RegisterForm(FlaskForm): + email = EmailField('Почта', validators=[DataRequired()]) + name = StringField('Имя', validators=[DataRequired()]) + login = StringField('Логин', validators=[DataRequired()]) + password = PasswordField('Пароль', validators=[DataRequired()]) + submit = SubmitField('Регистрация') \ No newline at end of file diff --git a/functions.py b/functions.py new file mode 100644 index 0000000..215254e --- /dev/null +++ b/functions.py @@ -0,0 +1,37 @@ +import smtplib +from email.message import EmailMessage + + +def check_password(password=''): + smb = 'qwertyuiopasdfghjklzxcvbnm' + if len(password) < 6: + return 'Пароль должен быть длиннее 6 символов' + elif False in [True if i.isalpha() and i.lower() in smb or i.isdigit() else False for i in password]: + return 'Пароль может содержать только буквы латинского алфавита и цифры' + elif True not in [True if i.isdigit() else False for i in password]: + return 'Пароль должен содержать буквы разного регистра и цифры' + elif False not in [True if i.islower() and i.isalpha() else False for i in password]: + return 'Пароль должен содержать буквы разного регистра и цифры' + else: + return 'OK' + + +def mail(msg, to, topic='Подтверждение почты'): + file = open('mail.incepted', 'r', encoding='utf-8').readline().split() + login, password = file[0], file[1] + email_server = "smtp.yandex.ru" + sender = "incepted@yandex.ru" + em = EmailMessage() + em.set_content(msg) + em['To'] = to + em['From'] = sender + em['Subject'] = topic + mailServer = smtplib.SMTP(email_server) + mailServer.set_debuglevel(1) + mailServer.ehlo() + mailServer.starttls() + mailServer.ehlo() + mailServer.login(login, password) + mailServer.ehlo() + mailServer.send_message(em) + mailServer.quit() diff --git a/main.py b/main.py index 41f476a..869e31b 100644 --- a/main.py +++ b/main.py @@ -1,15 +1,124 @@ -from flask import Flask, render_template +import datetime + +from flask import Flask, render_template, request, url_for +from flask_login import login_user, current_user, LoginManager, logout_user, login_required +from werkzeug.utils import redirect +from itsdangerous import URLSafeTimedSerializer, SignatureExpired + +from functions import check_password, mail +from forms.login import LoginForm +from forms.register import RegisterForm from data.users import User from waitress import serve from data import db_session app = Flask(__name__) -app.config['SECRET_KEY'] = 'test_secret_key' +key = 'test_secret_key' +app.config['SECRET_KEY'] = key +s = URLSafeTimedSerializer(key) +login_manager = LoginManager() +login_manager.init_app(app) @app.route('/') def base(): - return render_template('main.html') + return render_template('main.html', title='Главная') + + +@login_manager.user_loader +def load_user(user_id): + db_sess = db_session.create_session() + return db_sess.query(User).get(user_id) + + +@app.route('/login', methods=['GET', 'POST']) +def login(): + if not current_user.is_authenticated: + message = request.args.get('message') if request.args.get('message') else '' + email_repeat = request.args.get('email_repeat') if request.args.get('email_repeat') else False + form = LoginForm() + if form.validate_on_submit(): + db_sess = db_session.create_session() + user = db_sess.query(User).filter(User.email == form.email.data).first() + if user and user.check_password(form.password.data): + if user.activated: + login_user(user, remember=form.remember_me.data) + return redirect('/') + else: + return render_template('login.html', + message="Ваша почта не подтверждена", + form=form) + return render_template('login.html', + message="Неправильный логин или пароль", + form=form) + return render_template('login.html', title='Авторизация', form=form, message=message, email_repeat=email_repeat) + else: + return redirect('/') + + +@app.route('/logout') +@login_required +def logout(): + logout_user() + return redirect("/") + + +@app.route('/register', methods=['GET', 'POST']) +def register(): + if not current_user.is_authenticated: + form = RegisterForm() + if form.validate_on_submit(): + data_session = db_session.create_session() + if data_session.query(User).filter(User.login == form.login.data).first(): + return render_template('register.html', form=form, message="Такой пользователь уже есть", + title='Регистрация') + if data_session.query(User).filter(User.email == form.email.data).first(): + return render_template('register.html', form=form, message="Такая почта уже есть", title='Регистрация') + status_password = check_password(form.password.data) + if status_password != 'OK': + return render_template('register.html', form=form, message=status_password, title='Регистрация') + user = User( + email=form.email.data, + name=form.name.data, + login=form.login.data, + activity=datetime.datetime.now() + ) + 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, + 'Подтверждение регистрации') + return redirect('/login?message=Мы выслали ссылку для подтверждения почты') + return render_template('register.html', form=form, message='', title='Регистрация') + else: + return redirect('/') + + +@app.route('/confirmation/') +def confirmation(token): + try: + user_email = s.loads(token, max_age=86400) + data_session = db_session.create_session() + user = data_session.query(User).filter(User.email == user_email).first() + if user: + user.activated = True + data_session.commit() + data_session.close() + return redirect('/login?message=Почта успешно подтверждена') + else: + return redirect('/login?message=Пользователь не найден') + except SignatureExpired: + data_session = db_session.create_session() + users = data_session.query(User).filter( + User.activated == 0 and User.activated < datetime.datetime.now() - datetime.timedelta(days=1)).all() + if users: + list(map(lambda x: data_session.delete(x), users)) + data_session.commit() + data_session.close() + return redirect('/login?message=Срок действия ссылки истек, данные удалены') def main(): diff --git a/static/css/base.css b/static/css/base.css index 1a4fd9a..b3bdc56 100644 --- a/static/css/base.css +++ b/static/css/base.css @@ -1,4 +1,21 @@ +html { + background-color: #fdf5e6; + height: 100%; +} +body { + min-height: 100%; +} .navbar { - display: flex; - justify-content: flex-end; + background-color: #dcb495; + display: inline-flex; +} +.auth_button { + color: #ffffff; + font-size: 1.5vw; + transition: font-size 0.5s ease-in, text-shadow 1s ease-in; +} +.auth_button:hover { + font-size: 1.55vw; + color: #ffffff; + text-shadow: 0px 0px 20px #ffffff; } \ No newline at end of file diff --git a/static/css/login.css b/static/css/login.css new file mode 100644 index 0000000..42cc7ac --- /dev/null +++ b/static/css/login.css @@ -0,0 +1,69 @@ +body { + background-image: url(../images/back_main_one.jpg); +} +.login_page { + background-color: #dbc3af; + width: 90%; + height: 55%; + margin-left: 5%; + margin-right: 5%; + margin-top: 5%; + border-radius: 22px; + display: flex; + align-items: center; + justify-content: center; +} +.header_title { + text-align: center; + width: 100%; + height: auto; + transition: font-size 0.5s ease-in, text-shadow 1s ease-in; +} +.header_title:hover { + font-size: 53; + text-shadow: 0px 0px 20px #ffffff; +} +.login { + width: 60%; + align-self: center; + justify-content: center; +} +.buttons_from { + width: 100%; + display: inline-flex; + align-items: center; + justify-content: space-evenly; +} +.button { + width: 150px; + height: 35px; + border-radius: 5px; + text-align: center; + background-color: #000000; + color: #ffffff; + font: bold; + margin-left: 5px; + margin-top: 5px; + transition: background-color 0.5s ease-in, border-radius 1s ease-in, box-shadow 1s ease-in; +} +.button:hover { + background-color: #61350f; + border-color: #61350f; + color: #ffffff; + border-radius: 7px; + box-shadow: 0px 0px 50px #fff; +} +.data_block { + width: 100%; + display: inline-flex; + justify-content: space-evenly; +} +.box { + display: inline-flex; + align-content: center; +} +.register { + width: 100%; + height: 100%; + text-align: center; +} \ No newline at end of file diff --git a/static/css/main.css b/static/css/main.css index e69de29..4ba80a4 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -0,0 +1,33 @@ +.header_block { + background-image: url(../images/back_main_one.jpg); + ​​​​​​​background-repeat: no-repeat; + width: 100%; + height: 50%; + background-position: center; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} +.header_title { + color: #ffffff; + -webkit-text-stroke: 1px rgba(0, 0, 0, 0.486); + font: bold; + font-size: 3.5vw; + transition: font-size 0.5s ease-in, text-shadow 1s ease-in; +} +.header_title:hover { + font-size: 3.55vw; + text-shadow: 0px 0px 20px #ffffff; +} +.header_title_2 { + color: #ffffff; + -webkit-text-stroke: 1px rgba(0, 0, 0, 0.486); + font: bold; + font-size: 2vw; + transition: font-size 0.5s ease-in, text-shadow 1s ease-in; +} +.header_title_2:hover { + font-size: 2.05vw; + text-shadow: 0px 0px 20px #ffffff; +} \ No newline at end of file diff --git a/static/css/register.css b/static/css/register.css new file mode 100644 index 0000000..c84aa26 --- /dev/null +++ b/static/css/register.css @@ -0,0 +1,69 @@ +body { + background-image: url(../images/back_main_one.jpg); +} +.register_page { + background-color: #dbc3af; + width: 90%; + height: 55%; + margin-left: 5%; + margin-right: 5%; + margin-top: 5%; + border-radius: 22px; + display: flex; + align-items: center; + justify-content: center; +} +.header_title { + text-align: center; + width: 100%; + height: auto; + transition: font-size 0.5s ease-in, text-shadow 1s ease-in; +} +.header_title:hover { + font-size: 53; + text-shadow: 0px 0px 20px #ffffff; +} +.register { + width: 60%; + align-self: center; + justify-content: center; +} +.buttons_from { + width: 100%; + display: inline-flex; + align-items: center; + justify-content: space-evenly; +} +.button { + width: 150px; + height: 35px; + border-radius: 5px; + text-align: center; + background-color: #000000; + color: #ffffff; + font: bold; + margin-left: 5px; + margin-top: 5px; + transition: background-color 0.5s ease-in, border-radius 1s ease-in, box-shadow 1s ease-in; +} +.button:hover { + background-color: #61350f; + border-color: #61350f; + color: #ffffff; + border-radius: 7px; + box-shadow: 0px 0px 50px #fff; +} +.data_block { + width: 100%; + display: inline-flex; + justify-content: space-evenly; +} +.box { + display: inline-flex; + align-content: center; +} +.register { + width: 100%; + height: 100%; + text-align: center; +} \ No newline at end of file diff --git a/static/images/back_main_one.jpg b/static/images/back_main_one.jpg new file mode 100644 index 0000000..f8e0afc Binary files /dev/null and b/static/images/back_main_one.jpg differ diff --git a/static/images/logo_b.ico b/static/images/logo_b.ico new file mode 100644 index 0000000..54b0d84 Binary files /dev/null and b/static/images/logo_b.ico differ diff --git a/static/images/logo_b.png b/static/images/logo_b.png new file mode 100644 index 0000000..9e04d48 Binary files /dev/null and b/static/images/logo_b.png differ diff --git a/static/images/logo_w.ico b/static/images/logo_w.ico new file mode 100644 index 0000000..2a5cfb8 Binary files /dev/null and b/static/images/logo_w.ico differ diff --git a/static/images/logo_w.png b/static/images/logo_w.png new file mode 100644 index 0000000..f128b02 Binary files /dev/null and b/static/images/logo_w.png differ diff --git a/static/main_files/заглушка b/static/main_files/заглушка deleted file mode 100644 index e69de29..0000000 diff --git a/templates/base.html b/templates/base.html index 27d6322..727d288 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,21 +1,42 @@ - - - + + + + {{title}} - + crossorigin="anonymous" +> + -
- {% block content %}{% endblock %} -
+
{% block content %}{% endblock %}
- \ No newline at end of file + diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000..b355f0b --- /dev/null +++ b/templates/login.html @@ -0,0 +1,45 @@ + +{% extends "base.html" %} {% block content %} +
+ +
+{% endblock %} diff --git a/templates/main.html b/templates/main.html index 9c12a3d..288afab 100644 --- a/templates/main.html +++ b/templates/main.html @@ -2,1095 +2,8 @@ {% extends "base.html" %} {% block content %} - Qattro
-
-
#1 сайт по проектированию!
-
Создавай, пользуйся, составляй!
-
-
-
-
-
Видео-продакшн
-
-
Макетирование
-
-
Образовательное направление
-
-
Арт-Дизайн
Video Scribing
There are many ways to explain video scribing. For instance, it's like whiteboard animation or maybe whiteboard illustration. But at the end of the day, it's an experience. It's video-based storytelling.
We do video scribing for:
company presentations
products and services
educational programs
conferences & events
We also: write scenarios and storyboards for video scribing, video storytelling, illustrate video in scribing-style, make multimedia projects: scribing, flash, animation, shootings
-
Scribing at the conference
Scribing is a useful tool for the accompaniment of conferences, seminars, strategic sessions. Visual thinking helps catch the main point, memorize the information and understand complicated themes.
-
We scribe: speakers reports, program events, promotional materials for the event, for the site of the event at workshops, seminars, at closed strategy sessions.
Urgent Scribing!
We will come to you immediately on the day of the event to impress your customers and partners with our scribing capabilities!
Call us and we will decorate your board by scribing on the event day!
Urgent Scribing is an urgent call on the day of the event with 1-2 illustrators attending the event.
Scribing School
We will teach you the basics of scribing and visual thinking! Scribing is a tool that is needed for any modern specialist to be competitive and efficient.
Upcoming event:
on January 25, 2021, 10 AM — 6 PM
Place:
No.505 Wulumuqi North Road, Jing'an District, Shanghai
-
-
We will teach you: the basics of scribing, visual vocabulary, the basics of visual language, the technique of 'storytelling' and 'visual thinking'
Scribing for business
book scribing
+1 212-123-4567
This site was made on Tilda — a website builder that helps to create a website without any code
Create a website
+
+

#1 Сайт по проектированию!

+ Создавай, пользуйся, составляй! +
{% endblock %} \ No newline at end of file diff --git a/templates/register.html b/templates/register.html new file mode 100644 index 0000000..7bfe0f4 --- /dev/null +++ b/templates/register.html @@ -0,0 +1,49 @@ + +{% extends "base.html" %} {% block content %} +
+
+

Регистрация

+
+
+ {{ form.hidden_tag() }} +
+
+ + {{ form.email(class="form-control data", type="email") }} {% for + error in form.email.errors %} + + {% endfor %} +
+
+ + {{ form.name(class="form-control data", type="name") }} {% + for error in form.name.errors %} + + {% endfor %} +
+
+ + {{ form.login(class="form-control data", type="login") }} {% + for error in form.login.errors %} + + {% endfor %} +
+
+ + {{ form.password(class="form-control data", type="password") }} {% + for error in form.password.errors %} + + {% endfor %} +
+
+
+ {{ form.submit(type="submit", class="button") }} +
+ {% if message != '' %} + + {% endif %} +
+
+
+
+{% endblock %}