Skip to content

Commit 89947f5

Browse files
committed
Добавлена модель пользователя и функционал логина
1 parent 4d21f4d commit 89947f5

File tree

7 files changed

+191
-2
lines changed

7 files changed

+191
-2
lines changed

create_admin.py

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from getpass import getpass
2+
import sys
3+
4+
from webapp import create_app
5+
from webapp.model import db, User
6+
7+
app = create_app()
8+
9+
with app.app_context():
10+
username = input('Введите имя:')
11+
12+
if User.query.filter(User.username == username).count():
13+
print('Пользователь с таким именем уже существует')
14+
sys.exit(0)
15+
16+
password1 = getpass('Введите пароль')
17+
password2 = getpass('Повторите пароль')
18+
19+
if not password1 == password2:
20+
print('Пароли не одинаковые')
21+
sys.exit(0)
22+
23+
new_user = User(username=username, role='admin')
24+
new_user.set_password(password1)
25+
26+
db.session.add(new_user)
27+
db.session.commit()
28+
print('Создан пользователь с id={}'.format(new_user.id))
29+

requirements.txt

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
astroid==2.1.0
2+
beautifulsoup4==4.6.3
3+
certifi==2018.10.15
4+
chardet==3.0.4
5+
Click==7.0
6+
Flask==1.0.2
7+
Flask-Login==0.4.1
8+
Flask-SQLAlchemy==2.3.2
9+
Flask-WTF==0.14.2
10+
idna==2.7
11+
isort==4.3.4
12+
itsdangerous==1.1.0
13+
Jinja2==2.10
14+
lazy-object-proxy==1.3.1
15+
MarkupSafe==1.1.0
16+
mccabe==0.6.1
17+
pylint==2.2.2
18+
requests==2.20.1
19+
six==1.11.0
20+
SQLAlchemy==1.2.15
21+
typed-ast==1.1.0
22+
urllib3==1.24.1
23+
Werkzeug==0.14.1
24+
wrapt==1.10.11
25+
WTForms==2.2.1

webapp/__init__.py

+48-2
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,64 @@
1-
from flask import Flask, render_template
1+
from flask import Flask, flash, render_template, redirect, url_for
2+
from flask_login import LoginManager, current_user, login_required, login_user, logout_user
23

3-
from webapp.model import db, News
4+
from webapp.forms import LoginForm
5+
from webapp.model import db, News, User
46
from webapp.weather import weather_by_city
57

68
def create_app():
79
app = Flask(__name__)
810
app.config.from_pyfile('config.py')
911
db.init_app(app)
1012

13+
login_manager = LoginManager()
14+
login_manager.init_app(app)
15+
login_manager.login_view = 'login'
16+
17+
@login_manager.user_loader
18+
def load_user(user_id):
19+
return User.query.get(user_id)
20+
1121
@app.route('/')
1222
def index():
1323
title = "Новости Python"
1424
weather = weather_by_city(app.config['WEATHER_DEFAULT_CITY'])
1525
news_list = News.query.order_by(News.published.desc()).all()
1626
return render_template('index.html', page_title=title, weather=weather, news_list=news_list)
1727

28+
@app.route('/login')
29+
def login():
30+
if current_user.is_authenticated:
31+
return redirect(url_for('index'))
32+
title = "Авторизация"
33+
login_form = LoginForm()
34+
return render_template('login.html', page_title=title, form=login_form)
35+
36+
@app.route('/process-login', methods=['POST'])
37+
def process_login():
38+
form = LoginForm()
39+
40+
if form.validate_on_submit():
41+
user = User.query.filter(User.username == form.username.data).first()
42+
if user and user.check_password(form.password.data):
43+
login_user(user)
44+
flash('Вы успешно вошли на сайт')
45+
return redirect(url_for('index'))
46+
47+
flash('Неправильные имя пользователя или пароль')
48+
return redirect(url_for('login'))
49+
50+
@app.route('/logout')
51+
def logout():
52+
logout_user()
53+
flash('Вы успешно разлогинились')
54+
return redirect(url_for('index'))
55+
56+
@app.route('/admin')
57+
@login_required
58+
def admin_index():
59+
if current_user.is_admin:
60+
return 'Привет админ!'
61+
else:
62+
return 'Ты не админ!'
63+
1864
return app

webapp/forms.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from flask_wtf import FlaskForm
2+
from wtforms import StringField, PasswordField, SubmitField
3+
from wtforms.validators import DataRequired
4+
5+
class LoginForm(FlaskForm):
6+
username = StringField('Имя пользователя', validators=[DataRequired()], render_kw={"class": "form-control"})
7+
password = PasswordField('Пароль', validators=[DataRequired()], render_kw={"class": "form-control"})
8+
submit = SubmitField('Отправить!', render_kw={"class": "btn btn-primary"})

webapp/model.py

+21
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
from flask_login import UserMixin
12
from flask_sqlalchemy import SQLAlchemy
3+
from werkzeug.security import generate_password_hash, check_password_hash
24

35
db = SQLAlchemy()
46

@@ -11,3 +13,22 @@ class News(db.Model):
1113

1214
def __repr__(self):
1315
return '<News {} {}>'.format(self.title, self.url)
16+
17+
class User(db.Model, UserMixin):
18+
id = db.Column(db.Integer, primary_key=True)
19+
username = db.Column(db.String(50), index=True, unique=True)
20+
password = db.Column(db.String(128))
21+
role = db.Column(db.String(10), index=True)
22+
23+
def set_password(self, password):
24+
self.password = generate_password_hash(password)
25+
26+
def check_password(self, password):
27+
return check_password_hash(self.password, password)
28+
29+
@property
30+
def is_admin(self):
31+
return self.role == 'admin'
32+
33+
def __repr__(self):
34+
return '<User name={} id={}>'.format(self.username, self.id)

webapp/templates/index.html

+9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@
1515
<h1>{{ page_title }}</h1>
1616
<div class="row">
1717
<div class="col-8">
18+
{% with messages = get_flashed_messages() %}
19+
{% if messages %}
20+
<div class="alert alert-warning" role="alert">
21+
{% for message in messages %}
22+
{{ message }}<br>
23+
{% endfor %}
24+
</div>
25+
{% endif %}
26+
{% endwith %}
1827
<h2>Новости</h2>
1928
{% for news in news_list %}
2029
<h3><a href="{{ news.url }}">{{ news.title }}</a></h3>

webapp/templates/login.html

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<!doctype html>
2+
<html lang="ru">
3+
<head>
4+
<!-- Required meta tags -->
5+
<meta charset="utf-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
7+
8+
<!-- Bootstrap CSS -->
9+
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
10+
11+
<title>{{ page_title }}</title>
12+
</head>
13+
<body>
14+
<div class="container">
15+
<h1>{{ page_title }}</h1>
16+
<div class="row">
17+
<div class="col-4">
18+
{% with messages = get_flashed_messages() %}
19+
{% if messages %}
20+
<div class="alert alert-warning" role="alert">
21+
{% for message in messages %}
22+
{{ message }}<br>
23+
{% endfor %}
24+
</div>
25+
{% endif %}
26+
{% endwith %}
27+
<form action="{{ url_for('process_login') }}" method="POST">
28+
{{ form.hidden_tag() }}
29+
<div class="form-group">
30+
{{ form.username.label }}
31+
{{ form.username() }}
32+
</div>
33+
<div class="form-group">
34+
{{ form.password.label }}
35+
{{ form.password() }}
36+
</div>
37+
{{ form.submit() }}
38+
</form>
39+
</div>
40+
<div class="col-8">
41+
42+
</div>
43+
</div>
44+
</div>
45+
<!-- Optional JavaScript -->
46+
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
47+
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
48+
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
49+
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
50+
</body>
51+
</html>

0 commit comments

Comments
 (0)