Skip to content

Commit

Permalink
Merge pull request #122 from joegasewicz/models_to_init
Browse files Browse the repository at this point in the history
Add Models to JWTRoutes class & init_app method #119
  • Loading branch information
joegasewicz committed Dec 10, 2019
2 parents f7c6263 + a5cfed5 commit 83a5b94
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 42 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@

### Changed

- 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)
- 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)
- Add Models to JWTRoutes class & init_app method [Issue #119](https://github.com/joegasewicz/Flask-JWT-Router/issues/119)
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pytest = "*"
twine = "*"
pyjwt = "*"
Flask-SQLAlchemy = "*"
Sphinx = "*"

[packages]
flask = "*"
Expand Down
17 changes: 11 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,17 @@ def register():
class UserModel(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)

# You can define the primary key name with `ENTITY_KEY` on Flask's config
app.config["ENTITY_KEY"] = "user_id"
# (`id` is used by default)
JwtRoutes(app)

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

app.config["ENTITY_MODELS"] = [ UserModel, TeacherModel, ...etc ]
# Or pass later with `init_app`
def create_app(config):
...
jwt_routes.init_app(app, entity_models=[UserModel, TeacherModel, ...etc])

```

Expand Down Expand Up @@ -181,7 +184,9 @@ An Example configuration for registering & logging in users of different types:
("POST", "/auth/user"), ("POST", "/auth/user/login"),
("POST", "/auth/teacher"), ("POST", "/auth/teacher/login"),
]
app.config["ENTITY_MODELS"] = [UserModel, TeacherModel]

# Optionally, you can pass your models to Flask's config:
app.config["ENTITY_MODELS"] = [ UserModel, TeacherModel, ...etc ]
```
## Authors

Expand All @@ -198,7 +203,7 @@ Then run:
tox
```

To update docs run:
To check the docs look good locally you can run:
```bash
make html
```
Expand Down
1 change: 1 addition & 0 deletions flask_jwt_router/_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def update_entity(self, extensions: Config, exp: int, table_name, **kwarg):
# pylint:disable=missing-function-docstring
pass

@abstractmethod
def encode_token(self, extensions: Config, entity_id: Any, exp: int, table_name: str):
# pylint:disable=missing-function-docstring
pass
Expand Down
16 changes: 11 additions & 5 deletions flask_jwt_router/_extensions.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"""
The main configuration class for Flask-JWT-Router
"""
from abc import ABC
from typing import Dict, Any
from abc import ABC, abstractmethod
from typing import Dict, Any, List

from ._entity import _ORMType


class Config:
Expand Down Expand Up @@ -33,23 +35,27 @@ def __init__(self,

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


class Extensions(BaseExtension):
"""Contains the main configuration values"""
def init_extensions(self, config: Any) -> Config:
entity_models: List[_ORMType]

def init_extensions(self, config: Any, **kwargs) -> Config:
"""
:param config:
:return:
"""
entity_models = kwargs.get("entity_models")
return Config(
config.get("SECRET_KEY") or "DEFAULT_SECRET_KEY",
config.get("ENTITY_KEY") or "id",
config.get("WHITE_LIST_ROUTES") or [],
config.get("JWT_ROUTER_API_NAME"),
config.get("IGNORED_ROUTES") or [],
config.get("ENTITY_MODELS") or [],
entity_models or config.get("ENTITY_MODELS") or [],
)
19 changes: 13 additions & 6 deletions flask_jwt_router/_jwt_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

import logging
from warnings import warn
from typing import List

from ._extensions import BaseExtension, Extensions, Config
from ._entity import BaseEntity, Entity
from ._entity import BaseEntity, Entity, _ORMType
from ._routing import BaseRouting, Routing
from ._authentication import BaseAuthStrategy

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

#: A list of entity models
entity_models: List[_ORMType]

#: Token expiry value. eg. 30 = 30 days from creation date.
exp: int = 30

Expand All @@ -50,20 +54,23 @@ class FlaskJWTRouter:
#: for more information.
ext: BaseExtension

def __init__(self, app=None):
def __init__(self, app=None, **kwargs):
self.entity_models = kwargs.get("entity_models")
self.ext = Extensions()
self.app = app
if app:
self.init_app(app)
self.init_app(app, entity_models=self.entity_models)

def init_app(self, app):
def init_app(self, app=None, **kwargs):
"""
You can use this to set up your config at runtime
:param app: Flask application instance
:return:
"""
self.app = app
self.app = self.app or app
entity_models = self.entity_models or kwargs.get("entity_models")
config = self.get_app_config(app)
self.extensions = self.ext.init_extensions(config)
self.extensions = self.ext.init_extensions(config, entity_models=entity_models)
self.entity = Entity(self.extensions)
self.routing = Routing(self.app, self.extensions, self.entity)
self.app.before_request(self.routing.before_middleware)
Expand Down
11 changes: 6 additions & 5 deletions flask_jwt_router/_jwt_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,16 @@ def register():
# Create your entity model (example uses Flask-SqlAlchemy)
class UserModel(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
# You can also specify a list of entity model classes
JwtRoutes(app, entity_models=[UserModel, TeacherModel, ...etc])
app.config["ENTITY_MODELS"] = [ UserModel, TeacherModel ]
# (`id` is used by default)
JwtRoutes(app)
# Or pass later with `init_app`
def create_app(config):
...
jwt_routes.init_app(app, entity_models=[UserModel, TeacherModel, ...etc])
Authorization & Tokens
Expand Down
46 changes: 27 additions & 19 deletions tests/test_extensions.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
from flask_jwt_router._jwt_routes import JwtRoutes
from flask_jwt_router._extensions import Extensions
from tests.fixtures.model_fixtures import MockEntityModel


class TestExtension:
IGNORED_ROUTES = [
("GET", "/"),
("GET", "/ignore"),
]
WHITE_LIST_ROUTES = [
("GET", "/test"),
]

def test_config(self):
IGNORED_ROUTES = [
("GET", "/"),
("GET", "/ignore"),
]
WHITE_LIST_ROUTES = [
("GET", "/test"),
]
class App:
config = {
config = {
"IGNORED_ROUTES": IGNORED_ROUTES,
"WHITE_LIST_ROUTES": WHITE_LIST_ROUTES,
"SECRET_KEY": "a sectrect key",
"JWT_ROUTER_API_NAME": "api/v1",
"ENTITY_KEY": "user_id",
}
def before_request(self, t):
pass
flask_jwt_router = JwtRoutes(App())
assert flask_jwt_router.extensions.ignored_routes == IGNORED_ROUTES
assert flask_jwt_router.extensions.whitelist_routes == WHITE_LIST_ROUTES
flask_jwt = JwtRoutes()
flask_jwt.init_app(App())
assert flask_jwt.extensions.ignored_routes == IGNORED_ROUTES
assert flask_jwt.extensions.whitelist_routes == WHITE_LIST_ROUTES

def test_init_extensions(self, MockEntityModel):
extensions = Extensions()
config = extensions.init_extensions(self.config, entity_models=[MockEntityModel])

assert config.whitelist_routes == self.WHITE_LIST_ROUTES
assert config.ignored_routes == self.IGNORED_ROUTES
assert config.entity_models == [MockEntityModel]
assert config.entity_key == "user_id"
assert config.api_name == "api/v1"

config = {**self.config, "ENTITY_MODELS": [MockEntityModel]}
con = extensions.init_extensions(config)

assert con.entity_models == [MockEntityModel]

36 changes: 36 additions & 0 deletions tests/test_jwt_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from flask import Flask


from flask_jwt_router._jwt_routes import JwtRoutes
from tests.fixtures.model_fixtures import MockEntityModel


class TestJwtRoutes:

app = Flask(__name__)

def test_init_app(self, MockEntityModel):
jwt = JwtRoutes(self.app, entity_models=[MockEntityModel])
assert jwt.extensions.entity_models[0] == MockEntityModel
assert jwt.app == self.app

jwt = JwtRoutes()
jwt.init_app(self.app, entity_models=[MockEntityModel])
assert jwt.extensions.entity_models[0] == MockEntityModel
assert jwt.app == self.app

jwt = JwtRoutes(self.app)
jwt.init_app(entity_models=[MockEntityModel])
assert jwt.extensions.entity_models[0] == MockEntityModel
assert jwt.app == self.app

jwt = JwtRoutes(entity_models=[MockEntityModel])
jwt.init_app(self.app)
assert jwt.extensions.entity_models[0] == MockEntityModel
assert jwt.app == self.app

self.app.config["ENTITY_MODELS"] = [MockEntityModel]
jwt = JwtRoutes()
jwt.init_app(self.app)
assert jwt.extensions.entity_models[0] == MockEntityModel
assert jwt.app == self.app

0 comments on commit 83a5b94

Please sign in to comment.