diff --git a/app.py b/app.py index aa1fbaab..54f400b8 100644 --- a/app.py +++ b/app.py @@ -117,6 +117,9 @@ def create_app() -> Flask: app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(minutes=15) app.config["JWT_REFRESH_TOKEN_EXPIRES"] = timedelta(days=30) + # Other configuration settings + app.config["MAX_CONTENT_LENGTH"] = 16 * 1024 * 1024 + app.secret_key = get_flask_app_cookie_encryption_key() app.wsgi_app = ReverseProxied(app.wsgi_app) CORS(app) diff --git a/middleware/schema_and_dto_logic/dynamic_logic/dynamic_schema_request_content_population.py b/middleware/schema_and_dto_logic/dynamic_logic/dynamic_schema_request_content_population.py index 097694d1..73426410 100644 --- a/middleware/schema_and_dto_logic/dynamic_logic/dynamic_schema_request_content_population.py +++ b/middleware/schema_and_dto_logic/dynamic_logic/dynamic_schema_request_content_population.py @@ -85,14 +85,7 @@ def _get_data_from_sources(fields: dict, schema: SchemaTypes) -> SourceDataInfo: metadata = field_value.metadata source: SourceMappingEnum = _get_required_argument("source", metadata, schema) if isinstance(field_value, marshmallow.fields.Nested): - if source != SourceMappingEnum.JSON: - raise InvalidSourceMappingError( - "Nested fields can only be populated from JSON sources" - ) - if "nested_dto_class" not in metadata: - raise InvalidSourceMappingError( - "Nested fields must have a 'nested_dto_class' metadata" - ) + _check_for_errors(metadata, source) nested_dto_class = metadata["nested_dto_class"] nested_dto_info_list.append( NestedDTOInfo(key=field_name, class_=nested_dto_class) @@ -105,6 +98,17 @@ def _get_data_from_sources(fields: dict, schema: SchemaTypes) -> SourceDataInfo: return SourceDataInfo(data=data, nested_dto_info_list=nested_dto_info_list) +def _check_for_errors(metadata: dict, source: SourceMappingEnum): + if source != SourceMappingEnum.JSON: + raise InvalidSourceMappingError( + "Nested fields can only be populated from JSON sources" + ) + if "nested_dto_class" not in metadata: + raise InvalidSourceMappingError( + "Nested fields must have a 'nested_dto_class' metadata" + ) + + def _apply_transformation_functions_to_dict(fields: dict, intermediate_data: dict): """ Apply transformation functions to the data, diff --git a/middleware/schema_and_dto_logic/dynamic_logic/model_helpers_with_schemas.py b/middleware/schema_and_dto_logic/dynamic_logic/model_helpers_with_schemas.py deleted file mode 100644 index 5f99b22c..00000000 --- a/middleware/schema_and_dto_logic/dynamic_logic/model_helpers_with_schemas.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -These include helpers for constructing Flask-Restx models and parsers -That rely on schemas - -They are isolated from other code to prevent circular imports. -""" - -from flask_restx import Namespace, Model - -from middleware.primary_resource_logic.user_queries import UserRequestSchema -from middleware.schema_and_dto_logic.common_schemas_and_dtos import ( - EntryDataRequestSchema, -) -from middleware.schema_and_dto_logic.dynamic_logic.dynamic_schema_documentation_construction import ( - get_restx_param_documentation, -) -from middleware.schema_and_dto_logic.common_response_schemas import ( - IDAndMessageSchema, - GetManyResponseSchema, - EntryDataResponseSchema, -) - - -def create_user_model(namespace: Namespace) -> Model: - doc_info = get_restx_param_documentation( - namespace, - UserRequestSchema, - model_name="UserEmailAndPassword", - ) - return doc_info.model - - -def create_entry_data_request_model(namespace: Namespace) -> Model: - doc_info = get_restx_param_documentation( - namespace, - EntryDataRequestSchema, - ) - return doc_info.model - - -def create_entry_data_response_model( - namespace: Namespace, entry_data_response_schema=EntryDataResponseSchema -) -> Model: - doc_info = get_restx_param_documentation( - namespace, - schema=entry_data_response_schema, - ) - return doc_info.model - - -def create_id_and_message_model(namespace: Namespace) -> Model: - doc_info = get_restx_param_documentation( - namespace, - IDAndMessageSchema, - ) - return doc_info.model - - -def create_get_many_response_model( - namespace: Namespace, get_many_response_schema=GetManyResponseSchema -) -> Model: - doc_info = get_restx_param_documentation( - namespace=namespace, - schema=get_many_response_schema, - ) - return doc_info.model - - -class CRUDModels: - """ - A model that initializes and returns all standard models for CRUD operations - """ - - def __init__( - self, namespace: Namespace, get_many_response_schema=GetManyResponseSchema - ): - self.entry_data_request_model = create_entry_data_request_model(namespace) - self.entry_data_response_model = create_entry_data_response_model(namespace) - self.id_and_message_model = create_id_and_message_model(namespace) - self.get_many_response_model = create_get_many_response_model( - namespace, get_many_response_schema - ) diff --git a/middleware/schema_and_dto_logic/util.py b/middleware/schema_and_dto_logic/util.py index 7c8360c5..01900478 100644 --- a/middleware/schema_and_dto_logic/util.py +++ b/middleware/schema_and_dto_logic/util.py @@ -23,6 +23,8 @@ def _get_required_argument( def _get_source_getting_function(source: SourceMappingEnum) -> Callable: + # TODO: Consider moving this to separate map variable, + # rather than define within the function source_mapping: dict[SourceMappingEnum, Callable] = { SourceMappingEnum.QUERY_ARGS: request.args.get, SourceMappingEnum.FORM: request.form.get, @@ -30,6 +32,7 @@ def _get_source_getting_function(source: SourceMappingEnum) -> Callable: request.json.get(key) if request.json else None ), SourceMappingEnum.PATH: request.view_args.get, + SourceMappingEnum.FILE: request.files.get, } return source_mapping[source] diff --git a/resources/Login.py b/resources/Login.py index 9de25af3..a5cb9506 100644 --- a/resources/Login.py +++ b/resources/Login.py @@ -5,17 +5,13 @@ from middleware.decorators import endpoint_info from middleware.primary_resource_logic.login_queries import try_logging_in from resources.endpoint_schema_config import SchemaConfigs -from resources.resource_helpers import create_jwt_tokens_model, ResponseInfo -from middleware.schema_and_dto_logic.dynamic_logic.model_helpers_with_schemas import ( - create_user_model, -) +from resources.resource_helpers import ResponseInfo + from utilities.namespace import create_namespace from resources.PsycopgResource import PsycopgResource, handle_exceptions namespace_login = create_namespace() -user_model = create_user_model(namespace_login) -jwt_tokens_model = create_jwt_tokens_model(namespace_login) @namespace_login.route("/login") diff --git a/resources/resource_helpers.py b/resources/resource_helpers.py index 68a9a3f8..d2e89633 100644 --- a/resources/resource_helpers.py +++ b/resources/resource_helpers.py @@ -106,103 +106,6 @@ def create_response_dictionary( } -def create_jwt_tokens_model(namespace: Namespace) -> Model: - return namespace.model( - "JWTTokens", - { - "access_token": fields.String( - required=True, description="The access token of the user" - ), - "refresh_token": fields.String( - required=True, description="The refresh token of the user" - ), - }, - ) - - -def create_search_model(namespace: Namespace) -> Model: - search_result_inner_model = namespace.model( - "SearchResultInner", - { - "airtable_uid": fields.String( - required=True, description="Airtable UID of the record" - ), - "agency_name": fields.String(description="Name of the agency"), - "municipality": fields.String(description="Name of the municipality"), - "state_iso": fields.String(description="ISO code of the state"), - "data_source_name": fields.String(description="Name of the data source"), - "description": fields.String(description="Description of the record"), - "record_type": fields.String(description="Type of the record"), - "source_url": fields.String(description="URL of the data source"), - "record_format": fields.String(description="Format of the record"), - "coverage_start": fields.String(description="Coverage start date"), - "coverage_end": fields.String(description="Coverage end date"), - "agency_supplied": fields.String( - description="If the record is supplied by the agency" - ), - "jurisdiction_type": fields.String( - description="Type of jursidiction for agency" - ), - }, - ) - - search_result_inner_wrapper_model = namespace.model( - "SearchResultInnerWrapper", - { - "count": fields.Integer( - required=True, - description="Count of SearchResultInnerWrapper items", - attribute="count", - ), - "results": fields.List( - fields.Nested( - search_result_inner_model, - description="List of results for the given jurisdiction", - ) - ), - }, - ) - - search_result_jurisdictions_wrapper_model = namespace.model( - name="SearchResultJurisdictionsWrapper", - model={ - "federal": fields.Nested( - search_result_inner_wrapper_model, - description="Results for the federal jurisdiction", - ), - "state": fields.Nested( - search_result_inner_wrapper_model, - description="Results for the state jurisdiction", - ), - "county": fields.Nested( - search_result_inner_wrapper_model, - description="Results for the county jurisdiction", - ), - "locality": fields.Nested( - search_result_inner_wrapper_model, - description="Results for the locality jurisdiction", - ), - }, - ) - - search_result_outer_model = namespace.model( - "SearchResultOuter", - { - "count": fields.Integer( - required=True, - description="Count of SearchResultInner items", - attribute="count", - ), - "data": fields.Nested( - attribute="data", - model=search_result_jurisdictions_wrapper_model, - ), - }, - ) - - return search_result_outer_model - - def column_permissions_description( head_description: str, column_permissions_str_table: str, diff --git a/utilities/enums.py b/utilities/enums.py index 366f7b44..77060cdf 100644 --- a/utilities/enums.py +++ b/utilities/enums.py @@ -24,6 +24,7 @@ class SourceMappingEnum(Enum): FORM = "form" JSON = "json" PATH = "path" + FILE = "file" class ParserLocation(Enum):