-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor main code, separate code into modules (#55)
* feat(middlewares): add CustomRequestMiddleware to handle custom form and files properties in Flask requests test(callbacks_controller_test): add test for creating a message in callbacks controller * fix(__init__.py): fix import statement for HookMiddleware class feat(hook_middleware.py): add HookMiddleware class to register hooks for controller methods in blueprints The import statement for the `HookMiddleware` class in `__init__.py` was incorrect. It was fixed to import from the correct module. A new file `hook_middleware.py` was added to the `middlewares` directory. This file contains the `HookMiddleware` class which is responsible for registering hooks for controller methods in blueprints. The `register` method takes a controller instance and a blueprint instance as arguments, and registers the appropriate hooks based on the attributes of the controller instance. The `accept_attributes` property defines the list of attributes that are accepted as hooks. * feat(mvc_flask): add InputMethodHelper class to handle HTML-related operations The InputMethodHelper class is added to the mvc_flask/helpers/html module. This class provides methods for generating HTML input elements with specific methods (like PUT and DELETE) that are not natively supported by HTML forms. The class includes the following methods: - input_hidden_method: Determines the appropriate HTML string to return based on the given method string. - _input_html: Generates a hidden HTML input element. - _put: Generates a hidden input field for the PUT method. - _delete: Generates a hidden input field for the DELETE method. This class is intended to be used in the FlaskMVC class in the mvc_flask/__init__.py file. The inject_stage_and_region method in the FlaskMVC class now uses the InputMethodHelper class to generate the appropriate HTML for the method attribute in the returned dictionary. * refactor(__init__.py): rename MethodOverrideMiddleware class to MethodOverrideMiddleware for consistency and clarity refactor(hook_middleware.py): rename HookMidleware class to HookMiddleware for consistency and clarity feat(__init__.py): add import statements for MethodOverrideMiddleware and CustomRequestMiddleware feat(__init__.py): remove unused Hook class and its related code feat(__init__.py): update app.request_class to use CustomRequestMiddleware instead of CustomRequest feat(__init__.py): update app.wsgi_app to use MethodOverrideMiddleware instead of HTTPMethodOverrideMiddleware * feat(callbacks_controller.py): add CallbacksController class with index method and before_request callback feat(routes.py): add route for callbacks with only index method test(routes_test.py): add tests for the newly added callbacks route and controller * fix(messages_controller.py): change query method from `get` to `filter_by` to handle cases where the message with the given id does not exist * fix(hook_middleware.py): format the list comprehension for better readability fix(custom_request_middleware.py): remove extra blank line fix(callbacks_controller.py): change single quotes to double quotes for consistency fix(routes_test.py): format the assert statement for better readability * fix(mvc_flask): fix typo in method_override_middleware filename feat(mvc_flask): add method_override_middleware to handle HTTP method override functionality The typo in the filename of the method_override_middleware module has been fixed. The correct filename is now method_override_middleware.py. A new file, method_override_middleware.py, has been added to the mvc_flask/middlewares/http directory. This file contains the implementation of the MethodOverrideMiddleware class, which is responsible for handling HTTP method override functionality. The middleware allows clients to override the HTTP method of a request by including a special "_method" parameter in the request body. The allowed methods for override are GET, POST, DELETE, PUT, and PATCH. The middleware also handles cases where the overridden method is a bodyless method (GET, HEAD, OPTIONS, DELETE) by setting the appropriate values in the WSGI environment. * fix(__init__.py): update import statement for RouterMiddleware to reflect new file structure feat(router_middleware.py): add RouterMiddleware class to manage routes in a web application feat(namespace_middleware.py): add NamespaceMiddleware class to create namespaces for routes * refactor(__init__.py): remove unused imports and commented out code feat(blueprint_middleware.py): add BlueprintMiddleware class to handle registering blueprints and routes dynamically * refactor(mvc_flask): reorganize code structure and improve readability - Move FlaskMVC class to a separate file `mvc_flask.py` for better organization - Remove unnecessary imports and unused code from `__init__.py` - Rename `init_app` method in `FlaskMVC` class to `perform` for better clarity - Extract configuration logic into separate methods in `FlaskMVC` class for better modularity and readability - Update method names in `FlaskMVC` class to better reflect their purpose - Update variable names in `FlaskMVC` class for better clarity - Update comments and docstrings in `FlaskMVC` class for better understanding
- Loading branch information
Showing
14 changed files
with
200 additions
and
137 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,79 +1,3 @@ | ||
from importlib import import_module | ||
from .mvc_flask import FlaskMVC, Router | ||
|
||
from flask import Flask | ||
from flask.blueprints import Blueprint | ||
|
||
from .router import Router | ||
from .middlewares.html import HTMLMiddleware | ||
from .middlewares.http_method_override import ( | ||
HTTPMethodOverrideMiddleware, | ||
CustomRequest, | ||
) | ||
|
||
|
||
class FlaskMVC: | ||
def __init__(self, app: Flask = None, path="app"): | ||
if app is not None: | ||
self.init_app(app, path) | ||
|
||
def init_app(self, app: Flask = None, path="app"): | ||
self.hook = Hook() | ||
self.path = path | ||
|
||
app.template_folder = "views" | ||
app.request_class = CustomRequest | ||
app.wsgi_app = HTTPMethodOverrideMiddleware(app.wsgi_app) | ||
|
||
# register blueprint | ||
self.register_blueprint(app) | ||
|
||
@app.context_processor | ||
def inject_stage_and_region(): | ||
return dict(method=HTMLMiddleware().method) | ||
|
||
def register_blueprint(self, app: Flask): | ||
# load routes defined from users | ||
import_module(f"{self.path}.routes") | ||
|
||
for route in Router._method_route().items(): | ||
controller = route[0] | ||
blueprint = Blueprint(controller, controller) | ||
|
||
obj = import_module(f"{self.path}.controllers.{controller}_controller") | ||
view_func = getattr(obj, f"{controller.title()}Controller") | ||
instance_of_controller = view_func() | ||
self.hook.register(instance_of_controller, blueprint) | ||
|
||
for resource in route[1]: | ||
blueprint.add_url_rule( | ||
rule=resource.path, | ||
endpoint=resource.action, | ||
view_func=getattr(instance_of_controller, resource.action), | ||
methods=resource.method, | ||
) | ||
|
||
app.register_blueprint(blueprint) | ||
|
||
|
||
class Hook: | ||
def register(self, instance_of_controller, blueprint): | ||
accept_attributes = [ | ||
"before_request", | ||
"after_request", | ||
"teardown_request", | ||
"after_app_request", | ||
"before_app_request", | ||
"teardown_app_request", | ||
"before_app_first_request", | ||
] | ||
|
||
attrs = [ | ||
attr for attr in dir(instance_of_controller) if attr in accept_attributes | ||
] | ||
|
||
if attrs: | ||
for attr in attrs: | ||
values = getattr(instance_of_controller, attr) | ||
for value in values: | ||
hook_method = getattr(instance_of_controller, value) | ||
getattr(blueprint, attr)(hook_method) | ||
__all__ = ["FlaskMVC", "Router"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
from flask import Flask | ||
from importlib import import_module | ||
|
||
from flask.blueprints import Blueprint | ||
|
||
from .hook_middleware import HookMiddleware | ||
|
||
from .http.router_middleware import RouterMiddleware as Router | ||
|
||
|
||
class BlueprintMiddleware: | ||
def __init__(self, app: Flask, path: str) -> None: | ||
self.app = app | ||
self.path = path | ||
|
||
# load routes defined from users | ||
import_module(f"{self.path}.routes") | ||
|
||
def register(self): | ||
for route in Router._method_route().items(): | ||
controller = route[0] | ||
blueprint = Blueprint(controller, controller) | ||
|
||
obj = import_module(f"{self.path}.controllers.{controller}_controller") | ||
view_func = getattr(obj, f"{controller.title()}Controller") | ||
instance_of_controller = view_func() | ||
|
||
HookMiddleware().register(instance_of_controller, blueprint) | ||
|
||
for resource in route[1]: | ||
blueprint.add_url_rule( | ||
rule=resource.path, | ||
endpoint=resource.action, | ||
view_func=getattr(instance_of_controller, resource.action), | ||
methods=resource.method, | ||
) | ||
|
||
self.app.register_blueprint(blueprint) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
class HookMiddleware: | ||
def register(self, controller_instance, blueprint_instance): | ||
attrs = [ | ||
attr for attr in dir(controller_instance) if attr in self.accept_attributes | ||
] | ||
|
||
if attrs: | ||
for attr in attrs: | ||
values = getattr(controller_instance, attr) | ||
for value in values: | ||
hook_method = getattr(controller_instance, value) | ||
getattr(blueprint_instance, attr)(hook_method) | ||
|
||
@property | ||
def accept_attributes(self): | ||
return [ | ||
"before_request", | ||
"after_request", | ||
"teardown_request", | ||
"after_app_request", | ||
"before_app_request", | ||
"teardown_app_request", | ||
"before_app_first_request", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
from flask import Request | ||
|
||
|
||
class CustomRequestMiddleware(Request): | ||
@property | ||
def form(self): | ||
if "wsgi._post_form" in self.environ: | ||
return self.environ["wsgi._post_form"] | ||
return super().form | ||
|
||
@property | ||
def files(self): | ||
if "wsgi._post_files" in self.environ: | ||
return self.environ["wsgi._post_files"] | ||
return super().files |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 2 additions & 5 deletions
7
mvc_flask/namespace.py → .../middlewares/http/namespace_middleware.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.