├── .python-version
├── start.py
├── .gitignore
├── .github
└── FUNDING.yml
├── requirements.txt
└── sweater
├── templates
├── index.html
├── main.html
├── login.html
└── register.html
├── __init__.py
├── models.py
└── routes.py
/.python-version:
--------------------------------------------------------------------------------
1 | py_sweater
2 |
--------------------------------------------------------------------------------
/start.py:
--------------------------------------------------------------------------------
1 | from sweater import app
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | *.pyc
3 | __pycache__
4 |
5 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | patreon: letscodedru
2 | custom: ["https://money.yandex.ru/to/41001451675086", "https://paypal.me/letscodedru", "https://qiwi.me/letscode", "https://donate.stream/mrdru"]
3 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | click==6.7
2 | Flask==1.0.2
3 | Flask-Login==0.4.1
4 | Flask-SQLAlchemy==2.3.2
5 | itsdangerous==0.24
6 | Jinja2==2.10
7 | MarkupSafe==1.0
8 | psycopg2-binary==2.8.4
9 | SQLAlchemy==1.2.12
10 | Werkzeug==0.15.3
11 |
--------------------------------------------------------------------------------
/sweater/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Greetings
6 |
7 |
8 | Hello, user
9 | Main page
10 |
11 |
--------------------------------------------------------------------------------
/sweater/__init__.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from flask_sqlalchemy import SQLAlchemy
3 | from flask_login import LoginManager
4 |
5 |
6 | app = Flask(__name__)
7 | app.secret_key = 'some secret salt'
8 | app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://postgres:123@localhost/py_sweater'
9 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
10 | db = SQLAlchemy(app)
11 | manager = LoginManager(app)
12 |
13 | from sweater import models, routes
14 |
15 | db.create_all()
16 |
--------------------------------------------------------------------------------
/sweater/templates/main.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Main page
6 |
7 |
8 | Messages
9 |
14 |
15 | Messages list
16 | {% for message in messages %}
17 | {{ message.text }}
18 | {% for tag in message.tags %}
19 | #{{ tag.text }}
20 | {% endfor %}
21 |
22 | {% endfor %}
23 |
24 |
25 |
--------------------------------------------------------------------------------
/sweater/templates/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 | Login page
9 |
10 | {% with messages = get_flashed_messages() %}
11 | {% if messages %}
12 |
13 | {% for message in messages %}
14 | - {{ message }}
15 | {% endfor %}
16 |
17 | {% endif %}
18 | {% endwith %}
19 |
20 |
36 |
37 |
--------------------------------------------------------------------------------
/sweater/models.py:
--------------------------------------------------------------------------------
1 | from flask_login import UserMixin
2 |
3 | from sweater import db, manager
4 |
5 |
6 | class Message(db.Model):
7 | id = db.Column(db.Integer, primary_key=True)
8 | text = db.Column(db.String(1024), nullable=False)
9 |
10 | def __init__(self, text, tags):
11 | self.text = text.strip()
12 | self.tags = [
13 | Tag(text=tag.strip()) for tag in tags.split(',')
14 | ]
15 |
16 |
17 | class Tag(db.Model):
18 | id = db.Column(db.Integer, primary_key=True)
19 | text = db.Column(db.String(32), nullable=False)
20 |
21 | message_id = db.Column(db.Integer, db.ForeignKey('message.id'), nullable=False)
22 | message = db.relationship('Message', backref=db.backref('tags', lazy=True))
23 |
24 |
25 | class User (db.Model, UserMixin):
26 | id = db.Column(db.Integer, primary_key=True)
27 | login = db.Column(db.String(128), nullable=False, unique=True)
28 | password = db.Column(db.String(255), nullable=False)
29 |
30 |
31 | @manager.user_loader
32 | def load_user(user_id):
33 | return User.query.get(user_id)
34 |
--------------------------------------------------------------------------------
/sweater/templates/register.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 | Register page
9 |
10 | {% with messages = get_flashed_messages() %}
11 | {% if messages %}
12 |
13 | {% for message in messages %}
14 | - {{ message }}
15 | {% endfor %}
16 |
17 | {% endif %}
18 | {% endwith %}
19 |
20 |
40 |
41 |
--------------------------------------------------------------------------------
/sweater/routes.py:
--------------------------------------------------------------------------------
1 | from flask import render_template, redirect, url_for, request, flash
2 | from flask_login import login_user, login_required, logout_user
3 | from werkzeug.security import check_password_hash, generate_password_hash
4 |
5 | from sweater import app, db
6 | from sweater.models import Message, User
7 |
8 |
9 | @app.route('/', methods=['GET'])
10 | def hello_world():
11 | return render_template('index.html')
12 |
13 |
14 | @app.route('/main', methods=['GET'])
15 | @login_required
16 | def main():
17 | return render_template('main.html', messages=Message.query.all())
18 |
19 |
20 | @app.route('/add_message', methods=['POST'])
21 | @login_required
22 | def add_message():
23 | text = request.form['text']
24 | tag = request.form['tag']
25 |
26 | db.session.add(Message(text, tag))
27 | db.session.commit()
28 |
29 | return redirect(url_for('main'))
30 |
31 |
32 | @app.route('/login', methods=['GET', 'POST'])
33 | def login_page():
34 | login = request.form.get('login')
35 | password = request.form.get('password')
36 |
37 | if login and password:
38 | user = User.query.filter_by(login=login).first()
39 |
40 | if user and check_password_hash(user.password, password):
41 | login_user(user)
42 |
43 | next_page = request.args.get('next')
44 |
45 | return redirect(next_page)
46 | else:
47 | flash('Login or password is not correct')
48 | else:
49 | flash('Please fill login and password fields')
50 |
51 | return render_template('login.html')
52 |
53 |
54 | @app.route('/register', methods=['GET', 'POST'])
55 | def register():
56 | login = request.form.get('login')
57 | password = request.form.get('password')
58 | password2 = request.form.get('password2')
59 |
60 | if request.method == 'POST':
61 | if not (login or password or password2):
62 | flash('Please, fill all fields!')
63 | elif password != password2:
64 | flash('Passwords are not equal!')
65 | else:
66 | hash_pwd = generate_password_hash(password)
67 | new_user = User(login=login, password=hash_pwd)
68 | db.session.add(new_user)
69 | db.session.commit()
70 |
71 | return redirect(url_for('login_page'))
72 |
73 | return render_template('register.html')
74 |
75 |
76 | @app.route('/logout', methods=['GET', 'POST'])
77 | @login_required
78 | def logout():
79 | logout_user()
80 | return redirect(url_for('hello_world'))
81 |
82 |
83 | @app.after_request
84 | def redirect_to_signin(response):
85 | if response.status_code == 401:
86 | return redirect(url_for('login_page') + '?next=' + request.url)
87 |
88 | return response
89 |
--------------------------------------------------------------------------------