Skip to content

Commit 83a5b94

Browse files
author
Joe Gasewicz
authored
Merge pull request #122 from joegasewicz/models_to_init
Add Models to JWTRoutes class & init_app method #119
2 parents f7c6263 + a5cfed5 commit 83a5b94

9 files changed

+108
-42
lines changed

CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44

55
### Changed
66

7-
- Replaced the the `entity_type` kwarg to `table_name` in the public method `register_entity` [Issue #111](https://github.com/joegasewicz/Flask-JWT-Router/issues/111)
7+
- Replaced the the `entity_type` kwarg to `table_name` in the public method `register_entity` [Issue #111](https://github.com/joegasewicz/Flask-JWT-Router/issues/111)
8+
- Add Models to JWTRoutes class & init_app method [Issue #119](https://github.com/joegasewicz/Flask-JWT-Router/issues/119)

Pipfile

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pytest = "*"
88
twine = "*"
99
pyjwt = "*"
1010
Flask-SQLAlchemy = "*"
11+
Sphinx = "*"
1112

1213
[packages]
1314
flask = "*"

README.md

+11-6
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,17 @@ def register():
7878
class UserModel(db.Model):
7979
id = db.Column(db.Integer, primary_key=True)
8080
name = db.Column(db.String)
81+
8182
# You can define the primary key name with `ENTITY_KEY` on Flask's config
8283
app.config["ENTITY_KEY"] = "user_id"
83-
# (`id` is used by default)
84-
JwtRoutes(app)
8584

86-
# You can also specify a list of entity model classes
85+
# (`id` is used by default)
86+
JwtRoutes(app, entity_models=[UserModel, TeacherModel, ...etc])
8787

88-
app.config["ENTITY_MODELS"] = [ UserModel, TeacherModel, ...etc ]
88+
# Or pass later with `init_app`
89+
def create_app(config):
90+
...
91+
jwt_routes.init_app(app, entity_models=[UserModel, TeacherModel, ...etc])
8992

9093
```
9194

@@ -181,7 +184,9 @@ An Example configuration for registering & logging in users of different types:
181184
("POST", "/auth/user"), ("POST", "/auth/user/login"),
182185
("POST", "/auth/teacher"), ("POST", "/auth/teacher/login"),
183186
]
184-
app.config["ENTITY_MODELS"] = [UserModel, TeacherModel]
187+
188+
# Optionally, you can pass your models to Flask's config:
189+
app.config["ENTITY_MODELS"] = [ UserModel, TeacherModel, ...etc ]
185190
```
186191
## Authors
187192

@@ -198,7 +203,7 @@ Then run:
198203
tox
199204
```
200205

201-
To update docs run:
206+
To check the docs look good locally you can run:
202207
```bash
203208
make html
204209
```

flask_jwt_router/_authentication.py

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def update_entity(self, extensions: Config, exp: int, table_name, **kwarg):
3838
# pylint:disable=missing-function-docstring
3939
pass
4040

41+
@abstractmethod
4142
def encode_token(self, extensions: Config, entity_id: Any, exp: int, table_name: str):
4243
# pylint:disable=missing-function-docstring
4344
pass

flask_jwt_router/_extensions.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
"""
22
The main configuration class for Flask-JWT-Router
33
"""
4-
from abc import ABC
5-
from typing import Dict, Any
4+
from abc import ABC, abstractmethod
5+
from typing import Dict, Any, List
6+
7+
from ._entity import _ORMType
68

79

810
class Config:
@@ -33,23 +35,27 @@ def __init__(self,
3335

3436
class BaseExtension(ABC):
3537
"""Abstract Base Class for Extensions"""
36-
def init_extensions(self, config: Dict[str, Any]) -> Config:
38+
@abstractmethod
39+
def init_extensions(self, config: Dict[str, Any], **kwargs) -> Config:
3740
# pylint: disable=missing-function-docstring
3841
pass
3942

4043

4144
class Extensions(BaseExtension):
4245
"""Contains the main configuration values"""
43-
def init_extensions(self, config: Any) -> Config:
46+
entity_models: List[_ORMType]
47+
48+
def init_extensions(self, config: Any, **kwargs) -> Config:
4449
"""
4550
:param config:
4651
:return:
4752
"""
53+
entity_models = kwargs.get("entity_models")
4854
return Config(
4955
config.get("SECRET_KEY") or "DEFAULT_SECRET_KEY",
5056
config.get("ENTITY_KEY") or "id",
5157
config.get("WHITE_LIST_ROUTES") or [],
5258
config.get("JWT_ROUTER_API_NAME"),
5359
config.get("IGNORED_ROUTES") or [],
54-
config.get("ENTITY_MODELS") or [],
60+
entity_models or config.get("ENTITY_MODELS") or [],
5561
)

flask_jwt_router/_jwt_router.py

+13-6
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
import logging
66
from warnings import warn
7+
from typing import List
78

89
from ._extensions import BaseExtension, Extensions, Config
9-
from ._entity import BaseEntity, Entity
10+
from ._entity import BaseEntity, Entity, _ORMType
1011
from ._routing import BaseRouting, Routing
1112
from ._authentication import BaseAuthStrategy
1213

@@ -27,6 +28,9 @@ class FlaskJWTRouter:
2728
#: The Flask application instance.
2829
app = None
2930

31+
#: A list of entity models
32+
entity_models: List[_ORMType]
33+
3034
#: Token expiry value. eg. 30 = 30 days from creation date.
3135
exp: int = 30
3236

@@ -50,20 +54,23 @@ class FlaskJWTRouter:
5054
#: for more information.
5155
ext: BaseExtension
5256

53-
def __init__(self, app=None):
57+
def __init__(self, app=None, **kwargs):
58+
self.entity_models = kwargs.get("entity_models")
5459
self.ext = Extensions()
60+
self.app = app
5561
if app:
56-
self.init_app(app)
62+
self.init_app(app, entity_models=self.entity_models)
5763

58-
def init_app(self, app):
64+
def init_app(self, app=None, **kwargs):
5965
"""
6066
You can use this to set up your config at runtime
6167
:param app: Flask application instance
6268
:return:
6369
"""
64-
self.app = app
70+
self.app = self.app or app
71+
entity_models = self.entity_models or kwargs.get("entity_models")
6572
config = self.get_app_config(app)
66-
self.extensions = self.ext.init_extensions(config)
73+
self.extensions = self.ext.init_extensions(config, entity_models=entity_models)
6774
self.entity = Entity(self.extensions)
6875
self.routing = Routing(self.app, self.extensions, self.entity)
6976
self.app.before_request(self.routing.before_middleware)

flask_jwt_router/_jwt_routes.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,16 @@ def register():
6666
# Create your entity model (example uses Flask-SqlAlchemy)
6767
6868
class UserModel(db.Model):
69+
__tablename__ = "users"
6970
id = db.Column(db.Integer, primary_key=True)
7071
name = db.Column(db.String)
7172
72-
# You can also specify a list of entity model classes
73+
JwtRoutes(app, entity_models=[UserModel, TeacherModel, ...etc])
7374
74-
app.config["ENTITY_MODELS"] = [ UserModel, TeacherModel ]
75-
76-
# (`id` is used by default)
77-
JwtRoutes(app)
75+
# Or pass later with `init_app`
76+
def create_app(config):
77+
...
78+
jwt_routes.init_app(app, entity_models=[UserModel, TeacherModel, ...etc])
7879
7980
8081
Authorization & Tokens

tests/test_extensions.py

+27-19
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,37 @@
11
from flask_jwt_router._jwt_routes import JwtRoutes
2+
from flask_jwt_router._extensions import Extensions
3+
from tests.fixtures.model_fixtures import MockEntityModel
24

35

46
class TestExtension:
7+
IGNORED_ROUTES = [
8+
("GET", "/"),
9+
("GET", "/ignore"),
10+
]
11+
WHITE_LIST_ROUTES = [
12+
("GET", "/test"),
13+
]
514

6-
def test_config(self):
7-
IGNORED_ROUTES = [
8-
("GET", "/"),
9-
("GET", "/ignore"),
10-
]
11-
WHITE_LIST_ROUTES = [
12-
("GET", "/test"),
13-
]
14-
class App:
15-
config = {
15+
config = {
1616
"IGNORED_ROUTES": IGNORED_ROUTES,
1717
"WHITE_LIST_ROUTES": WHITE_LIST_ROUTES,
18+
"SECRET_KEY": "a sectrect key",
19+
"JWT_ROUTER_API_NAME": "api/v1",
20+
"ENTITY_KEY": "user_id",
1821
}
19-
def before_request(self, t):
20-
pass
21-
flask_jwt_router = JwtRoutes(App())
22-
assert flask_jwt_router.extensions.ignored_routes == IGNORED_ROUTES
23-
assert flask_jwt_router.extensions.whitelist_routes == WHITE_LIST_ROUTES
24-
flask_jwt = JwtRoutes()
25-
flask_jwt.init_app(App())
26-
assert flask_jwt.extensions.ignored_routes == IGNORED_ROUTES
27-
assert flask_jwt.extensions.whitelist_routes == WHITE_LIST_ROUTES
2822

23+
def test_init_extensions(self, MockEntityModel):
24+
extensions = Extensions()
25+
config = extensions.init_extensions(self.config, entity_models=[MockEntityModel])
26+
27+
assert config.whitelist_routes == self.WHITE_LIST_ROUTES
28+
assert config.ignored_routes == self.IGNORED_ROUTES
29+
assert config.entity_models == [MockEntityModel]
30+
assert config.entity_key == "user_id"
31+
assert config.api_name == "api/v1"
32+
33+
config = {**self.config, "ENTITY_MODELS": [MockEntityModel]}
34+
con = extensions.init_extensions(config)
35+
36+
assert con.entity_models == [MockEntityModel]
2937

tests/test_jwt_routes.py

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from flask import Flask
2+
3+
4+
from flask_jwt_router._jwt_routes import JwtRoutes
5+
from tests.fixtures.model_fixtures import MockEntityModel
6+
7+
8+
class TestJwtRoutes:
9+
10+
app = Flask(__name__)
11+
12+
def test_init_app(self, MockEntityModel):
13+
jwt = JwtRoutes(self.app, entity_models=[MockEntityModel])
14+
assert jwt.extensions.entity_models[0] == MockEntityModel
15+
assert jwt.app == self.app
16+
17+
jwt = JwtRoutes()
18+
jwt.init_app(self.app, entity_models=[MockEntityModel])
19+
assert jwt.extensions.entity_models[0] == MockEntityModel
20+
assert jwt.app == self.app
21+
22+
jwt = JwtRoutes(self.app)
23+
jwt.init_app(entity_models=[MockEntityModel])
24+
assert jwt.extensions.entity_models[0] == MockEntityModel
25+
assert jwt.app == self.app
26+
27+
jwt = JwtRoutes(entity_models=[MockEntityModel])
28+
jwt.init_app(self.app)
29+
assert jwt.extensions.entity_models[0] == MockEntityModel
30+
assert jwt.app == self.app
31+
32+
self.app.config["ENTITY_MODELS"] = [MockEntityModel]
33+
jwt = JwtRoutes()
34+
jwt.init_app(self.app)
35+
assert jwt.extensions.entity_models[0] == MockEntityModel
36+
assert jwt.app == self.app

0 commit comments

Comments
 (0)