Skip to content

Commit 1bd1a4b

Browse files
authored
Merge pull request #3 from mshqq/fix/p0-changes
fix: debug/host/port в .env, авторизация админки, порядок проверок и unsubscribe/order-status
2 parents 65baba1 + b2db368 commit 1bd1a4b

9 files changed

Lines changed: 136 additions & 10 deletions

File tree

.envexample

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
SECRET_KEY=
22
app_password=
33
MAX_TOKEN=
4-
USER_ID=
4+
USER_ID=
5+
6+
FLASK_DEBUG=1
7+
FLASK_HOST=0.0.0.0
8+
FLASK_PORT=5000

app.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11
from app import create_app
2+
from dotenv import load_dotenv
3+
from os import getenv
4+
from sys import exit
5+
6+
load_dotenv()
27

38
app = create_app()
49

510
if __name__ == "__main__":
6-
app.run(debug=True, host="0.0.0.0", port=5000)
11+
debug = getenv("FLASK_DEBUG", "0") == "1"
12+
host = getenv("FLASK_HOST", "127.0.0.1")
13+
port = int(getenv("FLASK_PORT", 5000))
14+
15+
if not (1 <= port <= 65535):
16+
exit(f"FLASK_PORT={port} вне диапазона 1-65535")
17+
18+
app.run(
19+
debug=debug,
20+
host=host,
21+
port=port,
22+
)

app/__init__.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,36 @@
11
from flask import Flask
22
from dotenv import load_dotenv
3-
from app.extensions import db, csrf
3+
from app.extensions import db, csrf, login_manager
44
from app.routes.locations import locations_bp
55
from app.routes.main import main_bp
66
from app.routes.orders import orders_bp
77
from app.routes.products import products_bp
88
from app.routes.subscribers import subscribers_bp
9-
import os
9+
from os import getenv
10+
from app.routes.auth import auth_bp
1011

1112

1213
def get_password():
13-
return os.getenv("app_password")
14+
return getenv("app_password")
1415

1516

1617
def create_app():
1718
app = Flask(__name__)
1819
load_dotenv()
19-
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY")
20+
app.config["SECRET_KEY"] = getenv("SECRET_KEY")
2021
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///shaurmania.db"
2122
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
2223
app.json.sort_keys = False
2324

2425
db.init_app(app)
2526
csrf.init_app(app)
27+
login_manager.init_app(app)
28+
29+
from app.models import User
30+
31+
@login_manager.user_loader
32+
def load_user(user_id):
33+
return User.query.get(int(user_id))
2634

2735
with app.app_context():
2836
from app import models # noqa
@@ -36,6 +44,7 @@ def create_app():
3644
app.register_blueprint(orders_bp)
3745
app.register_blueprint(products_bp)
3846
app.register_blueprint(subscribers_bp)
47+
app.register_blueprint(auth_bp)
3948

4049
from app.routes.orders import scheduler
4150

app/extensions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
from flask_sqlalchemy import SQLAlchemy
22
from flask_wtf.csrf import CSRFProtect
3+
from flask_login import LoginManager
34

45
csrf = CSRFProtect()
56
db = SQLAlchemy()
7+
login_manager = LoginManager()
8+
login_manager.login_view = "auth.login"

app/models.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from app.extensions import db
22
from datetime import datetime
33
from uuid import uuid4
4+
from werkzeug.security import generate_password_hash, check_password_hash
5+
from flask_login import UserMixin
46

57

68
class Location(db.Model):
@@ -94,3 +96,21 @@ class Subscriber(db.Model):
9496

9597
def __repr__(self):
9698
return f"<Subscribers {self.email}>"
99+
100+
101+
class User(db.Model, UserMixin):
102+
__tablename__ = "users"
103+
id = db.Column(db.Integer(), primary_key=True)
104+
username = db.Column(db.String(100), nullable=False, unique=True)
105+
email = db.Column(db.String(100), nullable=False, unique=True)
106+
password_hash = db.Column(db.String(255), nullable=False)
107+
created_on = db.Column(db.DateTime(), default=datetime.utcnow)
108+
109+
def __repr__(self):
110+
return f"<{self.id}:{self.username}>"
111+
112+
def set_password(self, password):
113+
self.password_hash = generate_password_hash(password)
114+
115+
def check_password(self, password):
116+
return check_password_hash(self.password_hash, password)

app/routes/auth.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from flask_login import login_user, logout_user, login_required
2+
from flask import Blueprint, jsonify, request
3+
from app.models import User
4+
5+
auth_bp = Blueprint("auth", __name__)
6+
7+
8+
@auth_bp.route("/login", methods=["POST"])
9+
def login():
10+
data = request.get_json()
11+
if not data:
12+
return jsonify({"error": "Запрос не содержит JSON"}), 400
13+
14+
username = data.get("username")
15+
password = data.get("password")
16+
17+
if not username or not password:
18+
return jsonify({"error": "Не указан логин или пароль"}), 400
19+
20+
user = User.query.filter_by(username=username).first()
21+
22+
if not user or not user.check_password(password):
23+
return jsonify({"error": "Неверный логин или пароль"}), 401
24+
25+
login_user(user)
26+
return jsonify({"message": "Успешный вход"}), 200
27+
28+
29+
@auth_bp.route("/logout", methods=["POST"])
30+
@login_required
31+
def logout():
32+
logout_user()
33+
return jsonify({"message": "Вы вышли"}), 200

app/routes/orders.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ def setStatus(app, id, status):
3030
@orders_bp.route("/api/order/status/<string:token>", methods=["GET"])
3131
def get_order_status(token):
3232
order = Order.query.filter(Order.public_token == token).first()
33+
if not order:
34+
return jsonify({"error": "Не найден заказ"}), 404
3335
status = order.status
3436

3537
return jsonify({"status": status}), 200

app/routes/subscribers.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from flask_login import login_required
12
from flask import Blueprint, jsonify, request
23
from app.models import Subscriber
34
from app.extensions import db, csrf
@@ -16,12 +17,12 @@
1617
def unsubscribe(token):
1718
sub = Subscriber.query.filter(Subscriber.unsubscribe_token == token).first()
1819

19-
if sub.is_active is False:
20-
return jsonify({"error": "Вы уже отписались от рассылки!"}), 400
21-
2220
if not sub:
2321
return jsonify({"error": "Токен не найден или устарел!"}), 404
2422

23+
if sub.is_active is False:
24+
return jsonify({"error": "Вы уже отписались от рассылки!"}), 400
25+
2526
try:
2627
sub.is_active = False
2728
db.session.commit()
@@ -32,8 +33,8 @@ def unsubscribe(token):
3233
return jsonify({"error": "Произошла ошибка при отписке!"}), 500
3334

3435

35-
@csrf.exempt
3636
@subscribers_bp.route("/admin/subscribers")
37+
@login_required
3738
def view_subscribers():
3839
subs = Subscriber.query.filter(Subscriber.is_active == True).all() # noqa
3940
sub_list = [

scripts/create_admin.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import sys
2+
import os
3+
4+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
5+
6+
from getpass import getpass
7+
from app import create_app
8+
from app.extensions import db
9+
from app.models import User
10+
from sys import exit
11+
12+
13+
def create_admin():
14+
app = create_app()
15+
with app.app_context():
16+
username = input("Юзернейм: ").strip()
17+
email = input("Email: ").strip()
18+
password = getpass("Пароль: ").strip()
19+
20+
if not username or not email or not password:
21+
exit("Все поля обязательны")
22+
23+
if User.query.filter_by(username=username).first():
24+
exit(f"Пользователь {username} уже существует")
25+
26+
if User.query.filter_by(email=email).first():
27+
exit(f"Email {email} уже занят")
28+
29+
user = User(username=username, email=email) # pyrefly: ignore
30+
user.set_password(password)
31+
db.session.add(user)
32+
db.session.commit()
33+
34+
print(f"Создан пользователь {username} (id={user.id})")
35+
36+
37+
if __name__ == "__main__":
38+
create_admin()

0 commit comments

Comments
 (0)