Skip to content

Commit f8f1b64

Browse files
committed
bump app to latest version of python and flask and update dependencies
1 parent 1ab1069 commit f8f1b64

File tree

9 files changed

+87
-74
lines changed

9 files changed

+87
-74
lines changed

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
venv/
22
idea/
33
.idea
4+
.venv
5+
.code
6+
vscode
7+
.vscode
48
.env
59
.DS_Store
610
.__pycache__/
711
__pycache__/
812
tests/__pycache__/
913
.pytest_cache/
1014
migrations/
11-
**.db
15+
**.db
16+
instance

README.md

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,28 @@ Initial scaffolding for a flask rest API development. Starter template for build
1414

1515
This App was developed with the following stack:
1616

17-
- Python
18-
- Flask
19-
- Flask-restful
20-
- Postgres DB
17+
- Python==3.12
18+
- Flask==3.10
19+
- Flask-restful==0.3.10
20+
- Flask-Script==2.0.6
21+
- Flask-SQLAlchemy==3.1.1
22+
- Postgres DB / SQlite
2123
- Gunicorn Web Server
2224

2325
## Requirements
24-
- Python 3.6+
26+
- Python 3.12+
2527
- Python pip
26-
- Postgres SQL
28+
- Postgres / SQlite
2729

2830
## Installation
2931
- fork this repository
3032
- create a .env file as shown in the env_example file
3133
- setup your database
3234
- on the terminal cd into the app folder
3335
- run `pip install -r requirements.txt` to install required modules
34-
- run `python manage.py db init ` to setup alembic migrations
35-
- run `python manage.py db migrate -m='<your migration message>'` to create migration files
36-
- then run `python manage.py db upgrade` to create tables
36+
- run `flask --app manage db init ` to setup alembic migrations
37+
- run `flask --app manage db migrate -m='<your migration message>'` to create migration files
38+
- then run `flask --app python manage db upgrade` to create tables
3739

3840
## Running the App
3941
- on the terminal run `gunicorn main:app`
@@ -48,5 +50,13 @@ This App was developed with the following stack:
4850
- You can modify the app to suit your need.
4951
- Happy usage.
5052

53+
## Update Information
54+
- Flask-JWT has been replaced with Flask-JWT-extended
55+
- Flask-Scripts and dependencies removed.
56+
- Future versions may use Pydantic instead of Marshmallow
57+
58+
## Contributions
59+
- Contributors are needed to keep developing this template with updates to its dependencies. You can reach me on my email.
60+
5161
## Credits
5262
solnsumei@gmail.com

config.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import os
2-
from os.path import join, dirname
32
from dotenv import load_dotenv
43

5-
dotenv_path = join(dirname(__file__), '.env')
6-
load_dotenv(dotenv_path)
4+
load_dotenv()
5+
76

87
app_environment = os.environ.get('FLASK_ENV')
98
JWT_AUTH_URL_RULE = '/api/v1/login'

main.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
import os
21
from flask import Flask, Blueprint
32
from flask_restful import Api
4-
from flask_jwt import JWT
5-
from src.utils.security import authenticate, identity
3+
from flask_jwt_extended import JWTManager
64
from src.models.basemodel import db
75

86

@@ -30,8 +28,6 @@ def create_app():
3028

3129
flask_app.register_blueprint(admin_bp, url_prefix="/api/v1/admin")
3230

33-
JWT(flask_app, authenticate, identity) # /auth
34-
3531
@flask_app.route('/')
3632
def index():
3733
return 'Welcome to Flask Rest API Setup!'
@@ -42,6 +38,7 @@ def index():
4238

4339

4440
app = create_app()
41+
jwt = JWTManager(app)
4542

4643

4744
if __name__ == "__main__":

manage.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import importlib
22
import os
3-
from flask_script import Manager
4-
from flask_migrate import Migrate, MigrateCommand
3+
from flask_migrate import Migrate
54
from src.models.basemodel import db
65
from main import create_app
76

8-
97
app = create_app()
108

119

@@ -24,9 +22,6 @@ def scan_models():
2422

2523
migrate = Migrate(app, db)
2624

27-
manager = Manager(app)
28-
manager.add_command('db', MigrateCommand)
29-
30-
if __name__ == '__main__':
25+
if __name__ == "__main__":
3126
scan_models()
32-
manager.run()
27+

requirements.txt

Lines changed: 42 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,45 @@
1-
alembic==1.4.3
2-
aniso8601==8.0.0
3-
attrs==20.2.0
4-
bcrypt==3.2.0
5-
cffi==1.14.3
6-
click==7.1.2
7-
dnspython==1.16.0
8-
eventlet==0.31.0
9-
Flask==1.1.2
10-
Flask-JWT==0.3.2
11-
Flask-Migrate==2.5.3
12-
Flask-RESTful==0.3.8
1+
alembic==1.14.1
2+
aniso8601==10.0.0
3+
attrs==25.1.0
4+
bcrypt==4.2.1
5+
blinker==1.9.0
6+
cffi==1.17.1
7+
click==8.1.8
8+
dnspython==2.7.0
9+
eventlet==0.39.0
10+
Flask==3.1.0
11+
Flask-JWT-Extended==4.7.1
12+
Flask-Migrate==4.1.0
13+
Flask-RESTful==0.3.10
1314
Flask-Script==2.0.6
14-
Flask-SQLAlchemy==2.4.4
15-
greenlet==0.4.17
16-
gunicorn==20.0.4
17-
iniconfig==1.0.1
18-
itsdangerous==1.1.0
19-
Jinja2==2.11.3
20-
Mako==1.2.2
21-
MarkupSafe==1.1.1
22-
marshmallow==3.8.0
23-
monotonic==1.5
24-
packaging==20.4
25-
passlib==1.7.2
26-
pluggy==0.13.1
27-
psycopg2-binary==2.8.6
28-
py==1.10.0
29-
pycparser==2.20
30-
PyJWT==1.4.2
31-
pyparsing==2.4.7
32-
pytest==6.1.0
33-
python-dateutil==2.8.1
34-
python-dotenv==0.14.0
15+
Flask-SQLAlchemy==3.1.1
16+
greenlet==3.1.1
17+
gunicorn==23.0.0
18+
iniconfig==2.0.0
19+
itsdangerous==2.2.0
20+
Jinja2==3.1.5
21+
Mako==1.3.9
22+
MarkupSafe==3.0.2
23+
marshmallow==3.26.1
24+
monotonic==1.6
25+
packaging==24.2
26+
passlib==1.7.4
27+
pluggy==1.5.0
28+
psycopg2-binary==2.9.10
29+
pycparser==2.22
30+
PyJWT==2.10.1
31+
pyparsing==3.2.1
32+
pytest==8.3.4
33+
python-dateutil==2.9.0.post0
34+
python-dotenv==1.0.1
3535
python-editor==1.0.4
36-
python-slugify==4.0.1
37-
pytz==2020.1
38-
six==1.15.0
39-
SQLAlchemy==1.3.19
36+
python-slugify==8.0.4
37+
pytz==2025.1
38+
six==1.17.0
39+
SQLAlchemy==2.0.38
4040
text-unidecode==1.3
41-
toml==0.10.1
42-
urllib3==1.26.5
43-
webargs==6.1.1
44-
Werkzeug==1.0.1
41+
toml==0.10.2
42+
typing_extensions==4.12.2
43+
urllib3==2.3.0
44+
webargs==8.6.0
45+
Werkzeug==3.1.3

src/api/resources/auth.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from flask_restful import Resource
2-
from werkzeug.security import safe_str_cmp
2+
from hmac import compare_digest
33
from src.models.user import UserModel
44
from src.models.schemas.user import UserSchema, user_summary
55

@@ -11,7 +11,7 @@ class Register(Resource):
1111
@UserSchema.validate_fields(location=('json',))
1212
def post(args):
1313

14-
if not safe_str_cmp(args['password'], args['password_confirmation']):
14+
if not compare_digest(args['password'], args['password_confirmation']):
1515
return {
1616
'success': False,
1717
'errors': {
@@ -43,4 +43,3 @@ def post(args):
4343
'success': True,
4444
'user': user_summary.dump(user).data
4545
}, 201
46-

src/middlewares/admin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from functools import wraps
2-
from flask_jwt import current_identity
2+
from flask_jwt_extended import current_user
33

44

55
def admin_required():
66
def decorator(f):
77
@wraps(f)
88
def decorated_function(*args, **kwargs):
9-
if not current_identity.is_admin:
9+
if not current_user.is_admin:
1010
return {"error": "Unauthorized user"}, 403
1111
return f(*args, **kwargs)
1212
return decorated_function

src/utils/security.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from src.models.user import UserModel
2+
from main import jwt
23

34

45
def authenticate(email, password):
@@ -7,6 +8,12 @@ def authenticate(email, password):
78
return user
89

910

10-
def identity(payload):
11-
user_id = payload['identity']
11+
@jwt.user_identity_loader
12+
def user_identity_lookup(user):
13+
return user.id
14+
15+
16+
@jwt.user_lookup_loader
17+
def identity(_jwt_header, jwt_data):
18+
user_id = jwt_data['sub']
1219
return UserModel.find_by_id(user_id)

0 commit comments

Comments
 (0)