From bf321d8a4d332cf6c2072b76fba48f191ab129c4 Mon Sep 17 00:00:00 2001 From: lseixas Date: Thu, 27 Mar 2025 15:23:11 -0300 Subject: [PATCH 001/167] added modules --- iac/stacks/lambda_stack.py | 13 ++- requirements-dev.txt | 4 +- .../app/generate_report_aggregator.py | 108 ++++++++++++++++++ .../app/generate_report_extractor.py | 18 +++ .../app/generate_report_sender.py | 12 ++ .../app/generate_report_transformer.py | 28 +++++ .../booking_repository_interface.py | 9 ++ src/shared/helpers/errors/usecase_errors.py | 3 + .../repositories/booking_repository_dynamo.py | 11 ++ .../repositories/booking_repository_mock.py | 10 ++ tests/modules/generate_report/__init__.py | 0 tests/modules/generate_report/app/__init__.py | 0 .../app/test_generate_report_aggregator.py | 19 +++ .../app/test_generate_report_transformer.py | 24 ++++ 14 files changed, 254 insertions(+), 5 deletions(-) create mode 100644 src/modules/generate_report/app/generate_report_aggregator.py create mode 100644 src/modules/generate_report/app/generate_report_extractor.py create mode 100644 src/modules/generate_report/app/generate_report_sender.py create mode 100644 src/modules/generate_report/app/generate_report_transformer.py create mode 100644 tests/modules/generate_report/__init__.py create mode 100644 tests/modules/generate_report/app/__init__.py create mode 100644 tests/modules/generate_report/app/test_generate_report_aggregator.py create mode 100644 tests/modules/generate_report/app/test_generate_report_transformer.py diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index 827a37b..fb3463e 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -6,8 +6,8 @@ ) from constructs import Construct from aws_cdk.aws_apigateway import Resource, LambdaIntegration -from aws_cdk.aws_events import Rule, Schedule -from aws_cdk.aws_events_targets import LambdaFunction +from aws_cdk.aws_events import Rule, Schedule, EventField +from aws_cdk.aws_events_targets import LambdaFunction, RuleTargetInput class LambdaStack(Construct): @@ -48,11 +48,16 @@ def create_lambda_event_bridge_integration(self, ) rule = Rule( - self, f"{module_name.title()}EventRule", + self, f"{module_name.title()}EventRuleForWeeklyUpload", schedule=cron_schedule ) - rule.add_target(LambdaFunction(function)) + input_transformer = RuleTargetInput.from_object({ + "current_date": EventField.time, + "message": "weekly report trigger!" + }) + + rule.add_target(LambdaFunction(function, event=input_transformer)) return function diff --git a/requirements-dev.txt b/requirements-dev.txt index ab21f95..e9092c9 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,4 +3,6 @@ pytest-cov==4.0.0 boto3==1.24.88 python-dotenv==0.21.0 aws-lambda-powertools==2.9.0 -aws_xray_sdk==2.11.0 \ No newline at end of file +aws_xray_sdk==2.11.0 +pandas==2.2.3 +XlsxWriter==3.2.2 \ No newline at end of file diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py new file mode 100644 index 0000000..94bbe2b --- /dev/null +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -0,0 +1,108 @@ +from src.shared.domain.entities.booking import Booking +from .generate_report_extractor import GenerateReportExtractor +from typing import List + + +class GenerateReportAggregator: + + def __init__(self, extractor: GenerateReportExtractor): + self.extractor = extractor + + def __call__(self, initial_date, final_date): + + bookings = self.extractor(initial_date, final_date) + + users_statistics = {} + + for booking in bookings: + if booking.user_id not in users_statistics: + users_statistics[booking.user_id] = { + "reservas_feitas": 0, + "Tennis": 0, + "Football": 0, + "Basketball": 0, + "Volleyball": 0, + "Handball": 0, + "Futsal": 0, + "Rugby": 0, + "Ping Pong": 0, + 1: 0, + 2: 0, + 3: 0, + 4: 0, + 5: 0, + "tempo_em_quadra": 0 + } + + users_statistics[booking.user_id]["reservas_feitas"] += 1 + users_statistics[booking.user_id][booking.sport.value] += 1 + users_statistics[booking.user_id][booking.court_number] += 1 + users_statistics[booking.user_id]["tempo_em_quadra"] += booking.end_date - booking.start_date + + + #court statistics logic + court_statistics = {} + + for booking in bookings: + court_key = booking.court_number + + if court_key not in court_statistics: + court_statistics[court_key] = { + "reservas_feitas": 0, + "tempo_de_uso": 0, + "Tennis": 0, + "Football": 0, + "Basketball": 0, + "Volleyball": 0, + "Handball": 0, + "Futsal": 0, + "Rugby": 0, + "Ping Pong": 0 + } + + sport_column = booking.sport.value + if sport_column not in court_statistics[court_key]: + court_statistics[court_key][sport_column] = 0 + + user_column = f"user_{booking.user_id}" + if user_column not in court_statistics[court_key]: + court_statistics[court_key][user_column] = 0 + + court_statistics[court_key]["reservas_feitas"] += 1 + court_statistics[court_key]["tempo_de_uso"] += (booking.end_date - booking.start_date) + court_statistics[court_key][sport_column] += 1 + court_statistics[court_key][user_column] += 1 + + + #sport_statistics logic + sport_statistics = {} + + for booking in bookings: + sport_key = booking.sport.value + + # Se ainda não existir, inicializa + if sport_key not in sport_statistics: + sport_statistics[sport_key] = { + "Reservas Feitas": 0, + "quadra 1": 0, + "quadra 2": 0, + "quadra 3": 0, + "quadra 4": 0, + "quadra 5": 0, + "Tempo Total Praticado": 0, + } + + # Atualiza os valores + sport_statistics[sport_key]["Reservas Feitas"] += 1 + sport_statistics[sport_key][f"quadra {booking.court_number}"] += 1 + sport_statistics[sport_key]["Tempo Total Praticado"] += (booking.end_date - booking.start_date) + + user_column = f"Usuário: {booking.user_id}" + if user_column not in sport_statistics[sport_key]: + sport_statistics[sport_key][user_column] = 0 + + sport_statistics[sport_key][user_column] += 1 + + #sport_statistics logic + + return users_statistics, court_statistics, sport_statistics diff --git a/src/modules/generate_report/app/generate_report_extractor.py b/src/modules/generate_report/app/generate_report_extractor.py new file mode 100644 index 0000000..1c2a4e9 --- /dev/null +++ b/src/modules/generate_report/app/generate_report_extractor.py @@ -0,0 +1,18 @@ +from src.shared.domain.repositories.booking_repository_interface import IBookingRepository +from src.shared.helpers.errors.usecase_errors import DynamoDBBaseError + + +class GenerateReportExtractor: + + def __init__(self, booking_repository: IBookingRepository): + self.booking_repository = booking_repository + + def __call__(self, initial_date, final_date): + + try: + bookings = self.booking_repository.get_all_bookings_by_date_range(initial_date, final_date) + + except: + raise DynamoDBBaseError("Error extracting bookings from dynamo") + + return bookings diff --git a/src/modules/generate_report/app/generate_report_sender.py b/src/modules/generate_report/app/generate_report_sender.py new file mode 100644 index 0000000..8a58ff2 --- /dev/null +++ b/src/modules/generate_report/app/generate_report_sender.py @@ -0,0 +1,12 @@ + + +def lambda_handler(event, context): + """ + Lambda handler function for the generate_report module + """ + print("IM ALIVE!! LAMBDA TRIGGERED BY EVENTBRIDGE") + print('event: ', event) + print('context', context) + + + diff --git a/src/modules/generate_report/app/generate_report_transformer.py b/src/modules/generate_report/app/generate_report_transformer.py new file mode 100644 index 0000000..59adba0 --- /dev/null +++ b/src/modules/generate_report/app/generate_report_transformer.py @@ -0,0 +1,28 @@ +from .generate_report_aggregator import GenerateReportAggregator +import pandas as pd +import io + +class GenerateReportTransformer: + + def __init__(self, aggregator: GenerateReportAggregator): + self.aggregator = aggregator + + def __call__(self, initial_date, final_date): + + user_statistics, court_statistics, sports_statistics = self.aggregator(initial_date, final_date) + + df_users = pd.DataFrame.from_dict(user_statistics, orient="index") + df_courts = pd.DataFrame.from_dict(court_statistics, orient="index") + df_sports = pd.DataFrame.from_dict(sports_statistics, orient="index") + + output = io.BytesIO() + + with pd.ExcelWriter(output, engine="xlsxwriter") as writer: + df_users.to_excel(writer, sheet_name="Usuários") + df_courts.to_excel(writer, sheet_name="Quadras") + df_sports.to_excel(writer, sheet_name="Esportes") + + output.seek(0) + + return output + diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index b744281..d230cb0 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -49,3 +49,12 @@ def get_all_bookings(self): Returns all bookings ''' pass + + @abstractmethod + def get_all_bookings_by_date_range(self, + initial_date: int, + final_date: int) -> Optional[List[Booking]]: + ''' + Returns all bookings that are in the date range + ''' + pass diff --git a/src/shared/helpers/errors/usecase_errors.py b/src/shared/helpers/errors/usecase_errors.py index bb403d0..2c70add 100644 --- a/src/shared/helpers/errors/usecase_errors.py +++ b/src/shared/helpers/errors/usecase_errors.py @@ -12,3 +12,6 @@ class ForbiddenAction(BaseError): def __init__(self, message: str): super().__init__(f'That action is forbidden for this {message}') +class DynamoDBBaseError(BaseError): + def __init__(self, message: str): + super().__init__(f'Error extracting bookings from dynamo: {message}') \ No newline at end of file diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index 3b13223..242159e 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -98,5 +98,16 @@ def get_all_bookings(self) -> Optional[List[Booking]]: if item.get('entity') == 'booking': all_bookings.append(BookingDynamoDTO.from_dynamo(item).to_entity()) + def get_all_bookings_by_date_range(self, initial_date: int, final_date: int) -> Optional[List[Booking]]: + + all_bookings = [] + all_items = self.dynamo.get_all_items().get('Items') + + for item in all_items: + if item.get('entity') == 'booking': + booking = BookingDynamoDTO.from_dynamo(item).to_entity() + if initial_date <= booking.start_date/1000 <= final_date: + all_bookings.append(booking) + return all_bookings diff --git a/src/shared/infra/repositories/booking_repository_mock.py b/src/shared/infra/repositories/booking_repository_mock.py index 25ba97e..9486a92 100644 --- a/src/shared/infra/repositories/booking_repository_mock.py +++ b/src/shared/infra/repositories/booking_repository_mock.py @@ -136,3 +136,13 @@ def delete_booking(self, booking_id: str): def get_all_bookings(self) -> List[Booking]: return self.bookings + + def get_all_bookings_by_date_range(self, initial_date, final_date): + + all_bookings = [] + for booking in self.bookings: + if initial_date <= booking.start_date <= final_date: + all_bookings.append(booking) + + return all_bookings + diff --git a/tests/modules/generate_report/__init__.py b/tests/modules/generate_report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/modules/generate_report/app/__init__.py b/tests/modules/generate_report/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/modules/generate_report/app/test_generate_report_aggregator.py b/tests/modules/generate_report/app/test_generate_report_aggregator.py new file mode 100644 index 0000000..8a6eba9 --- /dev/null +++ b/tests/modules/generate_report/app/test_generate_report_aggregator.py @@ -0,0 +1,19 @@ +from src.modules.generate_report.app.generate_report_aggregator import GenerateReportAggregator +from src.modules.generate_report.app.generate_report_extractor import GenerateReportExtractor +from src.shared.infra.repositories.booking_repository_dynamo import BookingRepositoryDynamo + + +class TestGenerateReportAggregator: + + def test_generate_report_aggregator(self): + + repo = BookingRepositoryDynamo() + + # Arrange + extractor = GenerateReportExtractor(booking_repository=repo) + aggregator = GenerateReportAggregator(extractor) + + # Act + result = aggregator(1577836800, 1767225600) + + print(result) \ No newline at end of file diff --git a/tests/modules/generate_report/app/test_generate_report_transformer.py b/tests/modules/generate_report/app/test_generate_report_transformer.py new file mode 100644 index 0000000..3480aa7 --- /dev/null +++ b/tests/modules/generate_report/app/test_generate_report_transformer.py @@ -0,0 +1,24 @@ +from src.modules.generate_report.app.generate_report_aggregator import GenerateReportAggregator +from src.modules.generate_report.app.generate_report_extractor import GenerateReportExtractor +from src.modules.generate_report.app.generate_report_transformer import GenerateReportTransformer +from src.shared.infra.repositories.booking_repository_dynamo import BookingRepositoryDynamo +import tempfile +import os + +class TestGenerateReportTransformer: + + def test_generate_report_transformer(self): + + repo = BookingRepositoryDynamo() + extractor = GenerateReportExtractor(booking_repository=repo) + aggregator = GenerateReportAggregator(extractor=extractor) + + transformer = GenerateReportTransformer(aggregator=aggregator) + + output = transformer(1577836800, 1767225600) + + with tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") as tmp_file: + tmp_file.write(output.read()) + tmp_file_path = tmp_file.name + + os.startfile(tmp_file_path) \ No newline at end of file From 787632066e8bda21870adf1d8f5219b0206f3212 Mon Sep 17 00:00:00 2001 From: lseixas Date: Thu, 27 Mar 2025 15:27:01 -0300 Subject: [PATCH 002/167] pytest markskip for modules that use dynamo --- .../generate_report/app/test_generate_report_aggregator.py | 3 +++ .../generate_report/app/test_generate_report_transformer.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/tests/modules/generate_report/app/test_generate_report_aggregator.py b/tests/modules/generate_report/app/test_generate_report_aggregator.py index 8a6eba9..6b2fcd3 100644 --- a/tests/modules/generate_report/app/test_generate_report_aggregator.py +++ b/tests/modules/generate_report/app/test_generate_report_aggregator.py @@ -1,3 +1,5 @@ +import pytest + from src.modules.generate_report.app.generate_report_aggregator import GenerateReportAggregator from src.modules.generate_report.app.generate_report_extractor import GenerateReportExtractor from src.shared.infra.repositories.booking_repository_dynamo import BookingRepositoryDynamo @@ -5,6 +7,7 @@ class TestGenerateReportAggregator: + @pytest.mark.skip("Can't run test in gh actions") def test_generate_report_aggregator(self): repo = BookingRepositoryDynamo() diff --git a/tests/modules/generate_report/app/test_generate_report_transformer.py b/tests/modules/generate_report/app/test_generate_report_transformer.py index 3480aa7..5bfbd70 100644 --- a/tests/modules/generate_report/app/test_generate_report_transformer.py +++ b/tests/modules/generate_report/app/test_generate_report_transformer.py @@ -1,3 +1,5 @@ +import pytest + from src.modules.generate_report.app.generate_report_aggregator import GenerateReportAggregator from src.modules.generate_report.app.generate_report_extractor import GenerateReportExtractor from src.modules.generate_report.app.generate_report_transformer import GenerateReportTransformer @@ -7,6 +9,7 @@ class TestGenerateReportTransformer: + @pytest.mark.skip("Can't run test in gh actions") def test_generate_report_transformer(self): repo = BookingRepositoryDynamo() From f1947c5b16601b1f5c6f0b88c4057f555f61c2ff Mon Sep 17 00:00:00 2001 From: lseixas Date: Tue, 15 Apr 2025 13:42:59 -0300 Subject: [PATCH 003/167] added manager --- .../app/generate_report_sender.py | 44 +++++++++++++++--- src/shared/environments.py | 3 ++ .../infra/repositories/util/S3Manager.py | 46 +++++++++++++++++++ 3 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 src/shared/infra/repositories/util/S3Manager.py diff --git a/src/modules/generate_report/app/generate_report_sender.py b/src/modules/generate_report/app/generate_report_sender.py index 8a58ff2..f918574 100644 --- a/src/modules/generate_report/app/generate_report_sender.py +++ b/src/modules/generate_report/app/generate_report_sender.py @@ -1,12 +1,44 @@ +import datetime +import time + +from src.shared.environments import Environments + +from .generate_report_extractor import GenerateReportExtractor +from .generate_report_aggregator import GenerateReportAggregator + +repo = Environments.get_envs().get_booking_repo()() def lambda_handler(event, context): - """ - Lambda handler function for the generate_report module - """ - print("IM ALIVE!! LAMBDA TRIGGERED BY EVENTBRIDGE") - print('event: ', event) - print('context', context) + extractor = GenerateReportExtractor(repo) + #"2025-04-03T15:00:00Z" date format + + current_date_str = event.get("current_date", None) + + if current_date_str: + current_date = datetime.datetime.fromisoformat(current_date_str.replace('Z', '+00:00')) + + year = current_date.year + year_start_date = datetime.datetime(year, 1, 1) + + start_date = int(time.mktime(year_start_date.timetuple())) + final_date = int(time.mktime(current_date.timetuple())) + + file_fomart = f"relatorio_gerado_em_{current_date.day}_{current_date.month}_{current_date.year}.xlsx" + + else: + start_date = int(time.mktime(datetime.datetime(datetime.datetime.now().year, 1, 1).timetuple())) + final_date = int(time.mktime(datetime.datetime.now().timetuple())) + + file_format = f"relatorio_gerado_em_{datetime.datetime.now().day}_{datetime.datetime.now().month}_{datetime.datetime.now().year}.xlsx" + + + extractor = GenerateReportExtractor(repo) + aggregator = GenerateReportAggregator(extractor) + report = aggregator(start_date, final_date) + + if report: + Environments.get_envs() diff --git a/src/shared/environments.py b/src/shared/environments.py index af15aa1..1f35132 100644 --- a/src/shared/environments.py +++ b/src/shared/environments.py @@ -52,6 +52,9 @@ def load_envs(self): self.dynamo_partition_key = "PK" self.dynamo_sort_key = "SK" self.cloud_front_distribution_domain = "https://d3q9q9q9q9q9q9.cloudfront.net" + self.client_id = "local-client-id" + self.client_secret = "local-client-secret" + self.bucket_endpoint_url = "http://localhost:8001" else: self.s3_bucket_name = os.environ.get("S3_BUCKET_NAME") diff --git a/src/shared/infra/repositories/util/S3Manager.py b/src/shared/infra/repositories/util/S3Manager.py new file mode 100644 index 0000000..7d710a7 --- /dev/null +++ b/src/shared/infra/repositories/util/S3Manager.py @@ -0,0 +1,46 @@ +import boto3 + +from src.shared.environments import Environments + + +class S3Manager: + + def __init__(self): + self.__envs = Environments.get_envs() + stage = self.__envs.stage.value + if stage == "TEST": + self.s3 = boto3.client( + "s3", + aws_access_key_id=self.__envs.client_id, + aws_secret_access_key=self.__envs.client_secret, + endpoint_url=self.__envs.endpoint_url_s3bucket_back, + region_name=self.__envs.region, + config=boto3.session.Config(signature_version="s3v4"), + ) + else: + self.s3 = boto3.client("s3") + + def upload_file(self, key, file_type, decode_string): + + response = self.s3.put_object( + Bucket=self.__envs.s3_bucket_name, + Key=key, + Body=decode_string, + ContentType=file_type.replace(".", ""), + ) + + return { + 's3_response': response, + 'key': key + } + + def delete_file(self): + pass + def get_all_files(self): + pass + def get_file(self): + pass + def generate_presigned_url(self, expiration_time: int, object_name: str, method: str, content_type: str): + pass + + From 7642b426e8f34b8dc71ba38fddcb235dc36eddd1 Mon Sep 17 00:00:00 2001 From: lseixas Date: Tue, 15 Apr 2025 15:09:24 -0300 Subject: [PATCH 004/167] added local minio image for testing bucket upload --- iac/local/minio/docker-compose-minio.yml | 29 +++++++++++++++++++ .../app/test_generate_report_sender.py | 0 2 files changed, 29 insertions(+) create mode 100644 iac/local/minio/docker-compose-minio.yml create mode 100644 tests/modules/generate_report/app/test_generate_report_sender.py diff --git a/iac/local/minio/docker-compose-minio.yml b/iac/local/minio/docker-compose-minio.yml new file mode 100644 index 0000000..b5081d1 --- /dev/null +++ b/iac/local/minio/docker-compose-minio.yml @@ -0,0 +1,29 @@ +version: '3' + +services: + minio: + image: minio/minio:latest + container_name: minio-reservation + ports: + - 9000:9000 + - 9001:9001 + environment: + - MINIO_ROOT_USER=${CLIENT_ID} + - MINIO_ROOT_PASSWORD=${CLIENT_SECRET} + volumes: + - minio-data:/data + command: server /data --console-address :9001 + + create-bucket: + image: minio/mc:latest + depends_on: + - minio + entrypoint: > + /bin/sh -c " + /usr/bin/mc config host add --api s3v4 s3 http://minio:9000 ${CLIENT_ID} ${CLIENT_SECRET}; + /usr/bin/mc mb s3/bucket-test; + /usr/bin/mc policy set public s3/bucket-test; + " + +volumes: + minio-data: diff --git a/tests/modules/generate_report/app/test_generate_report_sender.py b/tests/modules/generate_report/app/test_generate_report_sender.py new file mode 100644 index 0000000..e69de29 From 0e87d4e4a6614d623ad0a40d9578a2aa95b3aac6 Mon Sep 17 00:00:00 2001 From: lseixas Date: Tue, 15 Apr 2025 15:13:54 -0300 Subject: [PATCH 005/167] fixed environment client variables and local bucket endpoint url --- src/shared/environments.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shared/environments.py b/src/shared/environments.py index 1f35132..ab28e2f 100644 --- a/src/shared/environments.py +++ b/src/shared/environments.py @@ -52,9 +52,9 @@ def load_envs(self): self.dynamo_partition_key = "PK" self.dynamo_sort_key = "SK" self.cloud_front_distribution_domain = "https://d3q9q9q9q9q9q9.cloudfront.net" - self.client_id = "local-client-id" - self.client_secret = "local-client-secret" - self.bucket_endpoint_url = "http://localhost:8001" + self.client_id = "local_client_id" + self.client_secret = "local_client_secret" + self.bucket_endpoint_url = "http://localhost:9000" else: self.s3_bucket_name = os.environ.get("S3_BUCKET_NAME") From 925881828600194b9c10917427facb3d99fb47d6 Mon Sep 17 00:00:00 2001 From: lseixas Date: Tue, 15 Apr 2025 15:14:32 -0300 Subject: [PATCH 006/167] added sender test --- .../app/test_generate_report_sender.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/modules/generate_report/app/test_generate_report_sender.py b/tests/modules/generate_report/app/test_generate_report_sender.py index e69de29..197fcdf 100644 --- a/tests/modules/generate_report/app/test_generate_report_sender.py +++ b/tests/modules/generate_report/app/test_generate_report_sender.py @@ -0,0 +1,32 @@ +import pytest + +from src.modules.generate_report.app.generate_report_aggregator import GenerateReportAggregator +from src.modules.generate_report.app.generate_report_extractor import GenerateReportExtractor +from src.modules.generate_report.app.generate_report_sender import lambda_handler +from src.modules.generate_report.app.generate_report_transformer import GenerateReportTransformer +from src.shared.infra.repositories.booking_repository_dynamo import BookingRepositoryDynamo + + +class TestGenerateReportSender: + + @pytest.mark.skip("Can't run test in gh actions") + def test_generate_report_sender(self): + + event_from_event_bridge = { + "version": "0", + "id": "12345678-1234-1234-1234-123456789012", + "detail-type": "EC2 Instance State-change Notification", + "source": "aws.ec2", + "account": "123456789012", + "time": "2023-11-11T12:00:00Z", + "region": "us-east-1", + "resources": [ + "arn:aws:ec2:us-east-1:123456789012:instance/i-1234567890abcdef0" + ], + "detail": { + "instance-id": "i-1234567890abcdef0", + "state": "running" + } + } + + sender = lambda_handler(event_from_event_bridge, None) From 7200033daea0916b7485814b351f88e43afddabb Mon Sep 17 00:00:00 2001 From: lseixas Date: Tue, 15 Apr 2025 15:14:57 -0300 Subject: [PATCH 007/167] added s3manager --- src/shared/infra/repositories/util/S3Manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/infra/repositories/util/S3Manager.py b/src/shared/infra/repositories/util/S3Manager.py index 7d710a7..318e02e 100644 --- a/src/shared/infra/repositories/util/S3Manager.py +++ b/src/shared/infra/repositories/util/S3Manager.py @@ -13,7 +13,7 @@ def __init__(self): "s3", aws_access_key_id=self.__envs.client_id, aws_secret_access_key=self.__envs.client_secret, - endpoint_url=self.__envs.endpoint_url_s3bucket_back, + endpoint_url=self.__envs.bucket_endpoint_url, region_name=self.__envs.region, config=boto3.session.Config(signature_version="s3v4"), ) From d961fa0b37350641a89c1f8d8e115ec1b3ebfcb8 Mon Sep 17 00:00:00 2001 From: lseixas Date: Tue, 15 Apr 2025 15:16:16 -0300 Subject: [PATCH 008/167] finished sender --- .../app/generate_report_sender.py | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/modules/generate_report/app/generate_report_sender.py b/src/modules/generate_report/app/generate_report_sender.py index f918574..823c50c 100644 --- a/src/modules/generate_report/app/generate_report_sender.py +++ b/src/modules/generate_report/app/generate_report_sender.py @@ -2,9 +2,11 @@ import time from src.shared.environments import Environments +from src.shared.infra.repositories.util.S3Manager import S3Manager from .generate_report_extractor import GenerateReportExtractor from .generate_report_aggregator import GenerateReportAggregator +from .generate_report_transformer import GenerateReportTransformer repo = Environments.get_envs().get_booking_repo()() @@ -13,32 +15,43 @@ def lambda_handler(event, context): extractor = GenerateReportExtractor(repo) #"2025-04-03T15:00:00Z" date format - current_date_str = event.get("current_date", None) + current_date = datetime.datetime.now() - if current_date_str: - current_date = datetime.datetime.fromisoformat(current_date_str.replace('Z', '+00:00')) + year = current_date.year + month = current_date.month + year_start_date = datetime.datetime(year, 1, 1) - year = current_date.year - year_start_date = datetime.datetime(year, 1, 1) + start_date = int(time.mktime(year_start_date.timetuple())) * 1000 + final_date = int(time.mktime(current_date.timetuple())) * 1000 - start_date = int(time.mktime(year_start_date.timetuple())) - final_date = int(time.mktime(current_date.timetuple())) + file_name = f"relatorio_gerado_em_{current_date.day}_{month}_{year}.xlsx" + file_path = f"relatorios/" - file_fomart = f"relatorio_gerado_em_{current_date.day}_{current_date.month}_{current_date.year}.xlsx" + extractor = GenerateReportExtractor(booking_repository=repo) + aggregator = GenerateReportAggregator(extractor=extractor) + transformer = GenerateReportTransformer(aggregator=aggregator) + report = transformer(start_date, final_date) - else: - start_date = int(time.mktime(datetime.datetime(datetime.datetime.now().year, 1, 1).timetuple())) - final_date = int(time.mktime(datetime.datetime.now().timetuple())) + if report: - file_format = f"relatorio_gerado_em_{datetime.datetime.now().day}_{datetime.datetime.now().month}_{datetime.datetime.now().year}.xlsx" + bucket_manager = S3Manager() + try: - extractor = GenerateReportExtractor(repo) - aggregator = GenerateReportAggregator(extractor) - report = aggregator(start_date, final_date) + response = bucket_manager.upload_file(key=file_path + file_name, + file_type=".xlsx", + decode_string=report, + ) - if report: + print("Report generated and uploaded successfully") - Environments.get_envs() + return 1 + except: + + raise Exception("Error uploading file to S3") + + + else: + raise Exception("Error generating report") From cfaf80a69023f8c657a48b352cbf470bfe149619 Mon Sep 17 00:00:00 2001 From: lseixas Date: Tue, 15 Apr 2025 15:18:04 -0300 Subject: [PATCH 009/167] commented that sender test will not work with current mock dates --- .../generate_report/app/test_generate_report_sender.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/modules/generate_report/app/test_generate_report_sender.py b/tests/modules/generate_report/app/test_generate_report_sender.py index 197fcdf..ad84489 100644 --- a/tests/modules/generate_report/app/test_generate_report_sender.py +++ b/tests/modules/generate_report/app/test_generate_report_sender.py @@ -10,6 +10,9 @@ class TestGenerateReportSender: @pytest.mark.skip("Can't run test in gh actions") + + #WONT WORK WITH CURRENT MOCK, ALL DATES ARE OUTDATED AND DO NOT MATCH WITH CURRENT YEAR + def test_generate_report_sender(self): event_from_event_bridge = { @@ -30,3 +33,6 @@ def test_generate_report_sender(self): } sender = lambda_handler(event_from_event_bridge, None) + + #WONT WORK WITH CURRENT MOCK, ALL DATES ARE OUTDATED AND DO NOT MATCH WITH CURRENT YEAR + From 7b23ecde9bf26ebf36d7133f8bbc66e1b989333d Mon Sep 17 00:00:00 2001 From: tokujiTO Date: Tue, 6 May 2025 10:20:17 -0300 Subject: [PATCH 010/167] feat: setup aws account id --- .github/workflows/CD.yml | 86 +++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 37 deletions(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index 8a5c558..10fdf27 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -1,4 +1,3 @@ - name: CD on: @@ -13,45 +12,58 @@ on: jobs: DeployToAWS: environment: - name: ${{ github.ref_name }} + name: ${{ github.ref_name }} runs-on: ubuntu-latest permissions: id-token: write contents: read steps: - - uses: actions/checkout@v2 - - name: Setup AWS Credentials - uses: aws-actions/configure-aws-credentials@v2 - with: - aws-region: ${{ vars.AWS_REGION }} - role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/GithubActionsRole - role-session-name: github-action - - - name: Setting stage and stack name - run: | - echo "STAGE=${{ github.ref_name }}" - echo "STACK_NAME=ReservationStackScheduleANDCourts${{github.ref_name}}" >> $GITHUB_ENV - - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: '3.9' - - - name: Installing Dependencies - run: | - npm install -g aws-cdk - cd iac - pip install -r requirements.txt - - - name: DeployWithCDK - run: | - cd iac - cdk synth - cdk deploy --require-approval never - - env: - AWS_REGION: ${{ vars.AWS_REGION }} - AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} - STACK_NAME: ${{ env.STACK_NAME }} - GITHUB_REF_NAME: ${{ github.ref_name }} \ No newline at end of file + - uses: actions/checkout@v2 + + - name: Determine AWS Account ID + run: | + if [[ "${{ github.ref_name }}" == "dev" ]]; then + echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_DEV }}" >> $GITHUB_ENV + elif [[ "${{ github.ref_name }}" == "homolog" ]]; then + echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_HOML }}" >> $GITHUB_ENV + elif [[ "${{ github.ref_name }}" == "prod" ]]; then + echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_PROD }}" >> $GITHUB_ENV + else + echo "Invalid branch name!" && exit 1 + fi + + - name: Setup AWS Credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-region: ${{ vars.AWS_REGION }} + role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/GithubActionsRole + role-session-name: github-action + + - name: Setting stage and stack name + run: | + echo "STAGE=${{ github.ref_name }}" + echo "STACK_NAME=ReservationStackScheduleANDCourts${{github.ref_name}}" >> $GITHUB_ENV + + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: "3.9" + + - name: Installing Dependencies + run: | + npm install -g aws-cdk + cd iac + pip install -r requirements.txt + + - name: DeployWithCDK + run: | + cd iac + cdk synth + cdk deploy --require-approval never + + env: + AWS_REGION: ${{ vars.AWS_REGION }} + AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} + STACK_NAME: ${{ env.STACK_NAME }} + GITHUB_REF_NAME: ${{ github.ref_name }} From fc84f2be1a085805634e856a82ef4228caeea617 Mon Sep 17 00:00:00 2001 From: tokujiTO Date: Tue, 6 May 2025 10:39:26 -0300 Subject: [PATCH 011/167] feat: fix env setup accountid to env --- .github/workflows/CD.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index 10fdf27..0081707 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -64,6 +64,6 @@ jobs: env: AWS_REGION: ${{ vars.AWS_REGION }} - AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} + AWS_ACCOUNT_ID: ${{ env.AWS_ACCOUNT_ID }} STACK_NAME: ${{ env.STACK_NAME }} GITHUB_REF_NAME: ${{ github.ref_name }} From 0d9509e3811eef1b2b890b49bed3c339a609c844 Mon Sep 17 00:00:00 2001 From: tokujiTO Date: Tue, 6 May 2025 10:50:05 -0300 Subject: [PATCH 012/167] feat: add branch on push --- .github/workflows/CD.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index 0081707..a0914ac 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -6,6 +6,7 @@ on: - prod - dev - homolog + - fix/githubActions workflow_dispatch: @@ -25,6 +26,8 @@ jobs: run: | if [[ "${{ github.ref_name }}" == "dev" ]]; then echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_DEV }}" >> $GITHUB_ENV + elif [[ "${{ github.ref_name }}" == "fix/githubActions" ]]; then + echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_DEV }}" >> $GITHUB_ENV elif [[ "${{ github.ref_name }}" == "homolog" ]]; then echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_HOML }}" >> $GITHUB_ENV elif [[ "${{ github.ref_name }}" == "prod" ]]; then From aeae0038a4f79aab430db5c3c8e870c23fe36ac0 Mon Sep 17 00:00:00 2001 From: tokujiTO Date: Tue, 6 May 2025 10:57:26 -0300 Subject: [PATCH 013/167] feat: fix s3 name to dev --- .github/workflows/CD.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index a0914ac..17fd059 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -46,7 +46,18 @@ jobs: - name: Setting stage and stack name run: | echo "STAGE=${{ github.ref_name }}" - echo "STACK_NAME=ReservationStackScheduleANDCourts${{github.ref_name}}" >> $GITHUB_ENV + if [[ "${{ github.ref_name }}" == "prod" ]]; then + echo "STAGE=prod" >> $GITHUB_ENV + elif [[ "${{ github.ref_name }}" == "homolog" ]]; then + echo "STAGE=homolog" >> $GITHUB_ENV + elif [[ "${{ github.ref_name }}" == "dev" ]]; then + echo "STAGE=dev" >> $GITHUB_ENV + elif [[ "${{ github.ref_name }}" == "fix/githubActions" ]]; then + echo "STAGE=dev" >> $GITHUB_ENV + else + echo "Invalid branch name!" && exit 1 + fi + echo "STACK_NAME=ReservationStackScheduleANDCourts${{env.STAGE}}" >> $GITHUB_ENV - uses: actions/checkout@v3 - uses: actions/setup-python@v4 @@ -69,4 +80,4 @@ jobs: AWS_REGION: ${{ vars.AWS_REGION }} AWS_ACCOUNT_ID: ${{ env.AWS_ACCOUNT_ID }} STACK_NAME: ${{ env.STACK_NAME }} - GITHUB_REF_NAME: ${{ github.ref_name }} + GITHUB_REF_NAME: ${{ env.STAGE }} From b4ecd572959815501b38f6cca7649792b2297619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ant=C3=B4nnio=20Martinez?= Date: Fri, 16 May 2025 19:02:36 -0300 Subject: [PATCH 014/167] feat: get_all_users route made integrated with reservation_mss_user microservice --- src/modules/get_all_users/__init__.py | 0 src/modules/get_all_users/app/__init__.py | 0 .../app/get_all_users_controller.py | 28 +++++++ .../app/get_all_users_presenter.py | 16 ++++ .../app/get_all_users_usecase.py | 75 +++++++++++++++++++ .../app/get_all_users_viewmodel.py | 28 +++++++ .../app/test_get_all_bookings_usecase.py | 2 +- tests/modules/get_all_users/__init__.py | 0 tests/modules/get_all_users/app/__init__.py | 0 .../app/test_get_all_users_controller.py | 18 +++++ .../app/test_get_all_users_presenter.py | 54 +++++++++++++ .../app/test_get_all_users_usecase.py | 13 ++++ .../app/test_get_all_users_viewmodel.py | 31 ++++++++ 13 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 src/modules/get_all_users/__init__.py create mode 100644 src/modules/get_all_users/app/__init__.py create mode 100644 src/modules/get_all_users/app/get_all_users_controller.py create mode 100644 src/modules/get_all_users/app/get_all_users_presenter.py create mode 100644 src/modules/get_all_users/app/get_all_users_usecase.py create mode 100644 src/modules/get_all_users/app/get_all_users_viewmodel.py create mode 100644 tests/modules/get_all_users/__init__.py create mode 100644 tests/modules/get_all_users/app/__init__.py create mode 100644 tests/modules/get_all_users/app/test_get_all_users_controller.py create mode 100644 tests/modules/get_all_users/app/test_get_all_users_presenter.py create mode 100644 tests/modules/get_all_users/app/test_get_all_users_usecase.py create mode 100644 tests/modules/get_all_users/app/test_get_all_users_viewmodel.py diff --git a/src/modules/get_all_users/__init__.py b/src/modules/get_all_users/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/get_all_users/app/__init__.py b/src/modules/get_all_users/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/get_all_users/app/get_all_users_controller.py b/src/modules/get_all_users/app/get_all_users_controller.py new file mode 100644 index 0000000..a05100a --- /dev/null +++ b/src/modules/get_all_users/app/get_all_users_controller.py @@ -0,0 +1,28 @@ +from src.modules.get_all_users.app.get_all_users_usecase import GetAllUsersUseCase +from src.modules.get_all_users.app.get_all_users_viewmodel import GetAllUsersViewModel +from src.shared.helpers.errors.controller_errors import MissingParameters +from src.shared.helpers.errors.domain_errors import EntityError +from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse +from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, InternalServerError + + +class GetAllUsersController: + def __init__(self, usecase: GetAllUsersUseCase): + self.usecase = usecase + + def __call__(self, request: IRequest) -> IResponse: + + try: + users = self.usecase() + viewmodel = GetAllUsersViewModel(users) + + return OK(viewmodel.to_dict()) + + except EntityError as e: + return BadRequest(body=e.message) + + except MissingParameters as err: + return BadRequest(body=err.message) + + except Exception as err: + return InternalServerError(body=str(err)) \ No newline at end of file diff --git a/src/modules/get_all_users/app/get_all_users_presenter.py b/src/modules/get_all_users/app/get_all_users_presenter.py new file mode 100644 index 0000000..1ef0a42 --- /dev/null +++ b/src/modules/get_all_users/app/get_all_users_presenter.py @@ -0,0 +1,16 @@ +from src.modules.get_all_users.app.get_all_users_controller import GetAllUsersController +from src.modules.get_all_users.app.get_all_users_usecase import GetAllUsersUseCase +from src.shared.environments import Environments +from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse +from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock + +repo = BookingRepositoryMock() +usecase = GetAllUsersUseCase(repo) +controller = GetAllUsersController(usecase) + +def lambda_handler(event, context): + httpRequest = LambdaHttpRequest(data = event) + response = controller(httpRequest) + httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body) + + return httpResponse.toDict() \ No newline at end of file diff --git a/src/modules/get_all_users/app/get_all_users_usecase.py b/src/modules/get_all_users/app/get_all_users_usecase.py new file mode 100644 index 0000000..52d1761 --- /dev/null +++ b/src/modules/get_all_users/app/get_all_users_usecase.py @@ -0,0 +1,75 @@ +from src.shared.domain.repositories.booking_repository_interface import IBookingRepository +from dotenv import load_dotenv +import os +import requests + +load_dotenv() + +class GetAllUsersUseCase: + def __init__(self, repo: IBookingRepository): + self.repo = repo + + def __call__(self): + users_id_by_booking = self.repo.get_all_users() + if not users_id_by_booking: + return "nenhum usuário encontrado" + + users_id_by_booking = list(set(users_id_by_booking)) + + users_data = call_other_microservice() + if not users_data: + print("nenhum dado de usuário foi retornado pelo microserviço.") + + valid_users_data = [ + { + "user_id": user["user_id"], + "name": user["name"] + } + for user in users_data + if isinstance(user, dict) and "user_id" in user and "name" in user + ] + + if len(valid_users_data) != len(users_data): + print("dados invalidos/incompletos foram retornados pelo microserviço.") + + user_id_to_name = {user["user_id"]: user["name"] for user in valid_users_data} + + users_with_names = [ + {"user_id": user_id, "name": user_id_to_name.get(user_id)} + for user_id in users_id_by_booking #verificao se o user_id existe no booking e assim faz a troca + if user_id_to_name.get(user_id) is not None + ] + + users_with_names.sort(key=lambda user: user["name"]) # Ordena os nomes dos usuarios por ordem alfabetica + #feito desta forma pois, o set() não garante a ordem dos elementos + + return users_with_names + +def call_other_microservice(): + + load_dotenv() + + url = os.getenv("GET_ALL_USERS_API_URL") + + payload={} + headers = { + 'User-Agent': os.getenv("GET_ALL_USERS_USER_AGENT"), + 'Authorization': os.getenv("GET_ALL_USERS_AUTHORIZATION_TOKEN"), + 'Accept': '*/*', + 'Host': os.getenv("GET_ALL_USERS_HOST"), + 'Connection': 'keep-alive' + } + + try: + response = requests.get(url, headers=headers, data=payload) + response.raise_for_status() + + data = response.json() + if not isinstance(data, dict) or "users" not in data: + print("Erro: Resposta inesperada do microserviço.") + return [] + + return data.get("users", []) + except Exception as e: + print(f"Erro ao processar a resposta do serviço: {e}") + return [] \ No newline at end of file diff --git a/src/modules/get_all_users/app/get_all_users_viewmodel.py b/src/modules/get_all_users/app/get_all_users_viewmodel.py new file mode 100644 index 0000000..dfa98e5 --- /dev/null +++ b/src/modules/get_all_users/app/get_all_users_viewmodel.py @@ -0,0 +1,28 @@ +from src.shared.domain.entities.booking import Booking + + +class UserViewModel: + user_id: str + name: str + + def __init__(self, user_id: str, name: str): + self.user_id = user_id + self.name = name + + def to_dict(self): + return { + 'user_id': self.user_id, + 'name': self.name + } + +class GetAllUsersViewModel: + users: list[UserViewModel] + + def __init__(self, users: list[dict]): + self.users = [UserViewModel(user["user_id"], user["name"]) for user in users] + + def to_dict(self): + return { + 'users': [user.to_dict() for user in self.users], + 'message': 'the users were retrieved' + } \ No newline at end of file diff --git a/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py b/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py index 084b881..ff93fab 100644 --- a/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py +++ b/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py @@ -15,6 +15,6 @@ def test_get_all_bookings_usecase(self): assert bookings[0].start_date == 1634576165000 assert bookings[0].end_date == 1634583365000 assert bookings[0].sport == SPORT.TENNIS - assert bookings[0].user_id == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + assert bookings[0].user_id == '1f25448b-3429-4c19-8287-d9e64f17bc3a' assert bookings[0].booking_id == 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' assert bookings[0].materials == ['Raquete', 'Bola', 'Rede', 'Tenis'] \ No newline at end of file diff --git a/tests/modules/get_all_users/__init__.py b/tests/modules/get_all_users/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/modules/get_all_users/app/__init__.py b/tests/modules/get_all_users/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/modules/get_all_users/app/test_get_all_users_controller.py b/tests/modules/get_all_users/app/test_get_all_users_controller.py new file mode 100644 index 0000000..efa4697 --- /dev/null +++ b/tests/modules/get_all_users/app/test_get_all_users_controller.py @@ -0,0 +1,18 @@ +from src.modules.get_all_users.app.get_all_users_usecase import GetAllUsersUseCase +from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock +from src.modules.get_all_users.app.get_all_users_controller import GetAllUsersController +from src.shared.helpers.external_interfaces.http_models import HttpRequest + +class Test_GetAllUsersController: + def test_get_all_users_controller(self): + + repo = BookingRepositoryMock() + usecase = GetAllUsersUseCase(repo=repo) + controller = GetAllUsersController(usecase=usecase) + request = HttpRequest() + response = controller(request) + + assert response.status_code == 200 + assert len(response.body['users']) == 3 + assert response.body['message'] == 'the users were retrieved' + assert response.body['users'][0]['user_id'] == '1f25448b-3429-4c19-8287-d9e64f17bc3a' \ No newline at end of file diff --git a/tests/modules/get_all_users/app/test_get_all_users_presenter.py b/tests/modules/get_all_users/app/test_get_all_users_presenter.py new file mode 100644 index 0000000..8aedc74 --- /dev/null +++ b/tests/modules/get_all_users/app/test_get_all_users_presenter.py @@ -0,0 +1,54 @@ +import json +from src.modules.get_all_users.app.get_all_users_presenter import lambda_handler +from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock + +repo = BookingRepositoryMock() + +class Test_GetAllUsersPresenter: + def test_get_all_users_presenter(self): + + event = { + "version": "2.0", + "routeKey": "$default", + "rawPath": "/my/path", + "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", + "cookies": [ + "cookie1", + "cookie2" + ], + "headers": { + "header1": "value1", + "header2": "value1,value2" + }, + "requestContext": { + "accountId": "123456789012", + "apiId": "", + "authentication": None, + "authorizer": { + }, + "domainName": ".lambda-url.us-west-2.on.aws", + "domainPrefix": "", + "external_interfaces": { + "method": "POST", + "path": "/my/path", + "protocol": "HTTP/1.1", + "sourceIp": "123.123.123.123", + "userAgent": "agent" + }, + "requestId": "id", + "routeKey": "$default", + "stage": "$default", + "time": "12/Mar/2020:19:03:58 +0000", + "timeEpoch": 1583348638390 + }, + "body": "Hello from client!", + "pathParameters": None, + "isBase64Encoded": None, + "stageVariables": None + } + + response = lambda_handler(event, None) + + assert response['statusCode'] == 200 + assert json.loads(response['body'])["message"] == "the users were retrieved" + assert len(json.loads(response['body'])["users"]) == 3 \ No newline at end of file diff --git a/tests/modules/get_all_users/app/test_get_all_users_usecase.py b/tests/modules/get_all_users/app/test_get_all_users_usecase.py new file mode 100644 index 0000000..29d5c59 --- /dev/null +++ b/tests/modules/get_all_users/app/test_get_all_users_usecase.py @@ -0,0 +1,13 @@ +from src.modules.get_all_users.app.get_all_users_usecase import GetAllUsersUseCase +from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock + +class Test_GetAllUsersUsecase: + def test_get_all_users_usecase(self): + repo = BookingRepositoryMock() + + usecase = GetAllUsersUseCase(repo) + + result = usecase() + + assert len(result) == 3 + assert result[0]["user_id"] == "1f25448b-3429-4c19-8287-d9e64f17bc3a" \ No newline at end of file diff --git a/tests/modules/get_all_users/app/test_get_all_users_viewmodel.py b/tests/modules/get_all_users/app/test_get_all_users_viewmodel.py new file mode 100644 index 0000000..dfdba63 --- /dev/null +++ b/tests/modules/get_all_users/app/test_get_all_users_viewmodel.py @@ -0,0 +1,31 @@ +from src.modules.get_all_users.app.get_all_users_usecase import GetAllUsersUseCase +from src.modules.get_all_users.app.get_all_users_viewmodel import GetAllUsersViewModel +from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock + + +class Test_GetAllUsersViewModel: + def test_get_all_users_viewmodel(self): + repo = BookingRepositoryMock() + usecase = GetAllUsersUseCase(repo) + + user_list = usecase() + + viewmodel = GetAllUsersViewModel(user_list) + + assert viewmodel.to_dict() == { + 'users': [ + { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'GUSTAVO ALVES GOMES' + }, + { + 'user_id': 'd351a9b1-937f-423c-a9d1-9929b5795be1', + 'name': 'LEONARDO LUIZ SEIXAS IORIO' + }, + { + 'user_id': 'c07e0862-3c07-4227-ab0f-511a267cb7ff', + 'name': 'VICTOR AUGUSTO DE GASPERI' + } + ], + 'message': 'the users were retrieved' + } From fbffc2e5e9589e2d4ef90ae7686dbd5ef8b3269b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ant=C3=B4nnio=20Martinez?= Date: Fri, 16 May 2025 19:03:10 -0300 Subject: [PATCH 015/167] feat: added interface and function get_all_users --- .../repositories/booking_repository_interface.py | 6 ++---- .../infra/repositories/booking_repository_mock.py | 10 +++++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index d230cb0..61835c2 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -51,10 +51,8 @@ def get_all_bookings(self): pass @abstractmethod - def get_all_bookings_by_date_range(self, - initial_date: int, - final_date: int) -> Optional[List[Booking]]: + def get_all_users(Self): ''' - Returns all bookings that are in the date range + Returns name users by user id ''' pass diff --git a/src/shared/infra/repositories/booking_repository_mock.py b/src/shared/infra/repositories/booking_repository_mock.py index 9486a92..5eb3a70 100644 --- a/src/shared/infra/repositories/booking_repository_mock.py +++ b/src/shared/infra/repositories/booking_repository_mock.py @@ -14,7 +14,7 @@ def __init__(self): end_date=1634583365000, court_number=1, sport=SPORT.TENNIS, - user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', + user_id='1f25448b-3429-4c19-8287-d9e64f17bc3a', booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Raquete', 'Bola', 'Rede', 'Tenis'] ), @@ -24,7 +24,7 @@ def __init__(self): end_date=1634567400000, court_number=2, sport=SPORT.FOOTBALL, - user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', + user_id='c07e0862-3c07-4227-ab0f-511a267cb7ff', booking_id='b2d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Bola', 'Chuteira'] ), @@ -34,7 +34,7 @@ def __init__(self): end_date=1634571000000, court_number=3, sport=SPORT.BASKETBALL, - user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', + user_id='d351a9b1-937f-423c-a9d1-9929b5795be1', booking_id='b3d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Bola'] ), @@ -145,4 +145,8 @@ def get_all_bookings_by_date_range(self, initial_date, final_date): all_bookings.append(booking) return all_bookings + + def get_all_users(self) -> List[str]: + users_id = list(set([booking.user_id for booking in self.bookings])) + return users_id From 6fa3e85d97843094ec6d7816bce5b1f45abfab22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ant=C3=B4nnio=20Martinez?= Date: Fri, 16 May 2025 19:03:56 -0300 Subject: [PATCH 016/167] fix: changing other routes for microservice integration to work --- .../delete_bookings/app/test_delete_booking_viewmodel.py | 2 +- tests/modules/get_booking/app/test_get_booking_controller.py | 2 +- tests/modules/get_booking/app/test_get_booking_presenter.py | 2 +- tests/modules/get_booking/app/test_get_booking_viewmodel.py | 2 +- tests/shared/infra/repositories/test_booking_repository_mock.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py b/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py index 4bd889d..171cf26 100644 --- a/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py +++ b/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py @@ -17,7 +17,7 @@ def test_delete_booking_viewmodel(self): 'end_date': 1634583365000, 'court_number': 1, 'sport': 'Tennis', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] }, diff --git a/tests/modules/get_booking/app/test_get_booking_controller.py b/tests/modules/get_booking/app/test_get_booking_controller.py index e89e0df..3cdfc18 100644 --- a/tests/modules/get_booking/app/test_get_booking_controller.py +++ b/tests/modules/get_booking/app/test_get_booking_controller.py @@ -25,7 +25,7 @@ def test_get_booking_controller(self): assert response.body['booking']['end_date'] == 1634567400000 assert response.body['booking']['court_number'] == 2 assert response.body['booking']['sport'] == 'Football' - assert response.body['booking']['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + assert response.body['booking']['user_id'] == 'c07e0862-3c07-4227-ab0f-511a267cb7ff' assert response.body['booking']['materials'] == ['Bola', 'Chuteira'] def test_get_booking_controller_missing_booking_id(self): diff --git a/tests/modules/get_booking/app/test_get_booking_presenter.py b/tests/modules/get_booking/app/test_get_booking_presenter.py index b85c5e5..dcab6cb 100644 --- a/tests/modules/get_booking/app/test_get_booking_presenter.py +++ b/tests/modules/get_booking/app/test_get_booking_presenter.py @@ -57,7 +57,7 @@ def test_get_booking_presenter(self): assert json.loads(response['body'])['booking']['end_date'] == 1634583365000 assert json.loads(response['body'])['booking']['court_number'] == 1 assert json.loads(response['body'])['booking']['sport'] == 'Tennis' - assert json.loads(response['body'])['booking']['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + assert json.loads(response['body'])['booking']['user_id'] == '1f25448b-3429-4c19-8287-d9e64f17bc3a' assert json.loads(response['body'])['booking']['materials'] == ['Raquete', 'Bola', 'Rede', 'Tenis'] diff --git a/tests/modules/get_booking/app/test_get_booking_viewmodel.py b/tests/modules/get_booking/app/test_get_booking_viewmodel.py index a3b80a6..6cec5ef 100644 --- a/tests/modules/get_booking/app/test_get_booking_viewmodel.py +++ b/tests/modules/get_booking/app/test_get_booking_viewmodel.py @@ -16,7 +16,7 @@ def test_get_booking_viewmodel(self): 'end_date': 1634583365000, 'court_number': 1, 'sport': 'Tennis', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] }, diff --git a/tests/shared/infra/repositories/test_booking_repository_mock.py b/tests/shared/infra/repositories/test_booking_repository_mock.py index c42e320..a22fcd7 100644 --- a/tests/shared/infra/repositories/test_booking_repository_mock.py +++ b/tests/shared/infra/repositories/test_booking_repository_mock.py @@ -40,7 +40,7 @@ def test_get_booking(self): assert booking is not None assert booking.booking_id == booking_id - assert booking.user_id == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + assert booking.user_id == '1f25448b-3429-4c19-8287-d9e64f17bc3a' assert booking.sport == SPORT.TENNIS assert booking.court_number == 1 assert booking.start_date == 1634576165000 From 255c3f94370e712910d40ebdf6b73c01a3022358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ant=C3=B4nnio=20Martinez?= Date: Fri, 16 May 2025 19:04:15 -0300 Subject: [PATCH 017/167] TODO on generate_report --- .../generate_report/app/generate_report_aggregator.py | 5 +++++ src/modules/generate_report/app/generate_report_extractor.py | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index 94bbe2b..48f8b58 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -12,6 +12,11 @@ def __call__(self, initial_date, final_date): bookings = self.extractor(initial_date, final_date) + #fazer logica aqui + #trocar os bookings por users + #dps instalar as dependencias do requirements-dev.txt + + users_statistics = {} for booking in bookings: diff --git a/src/modules/generate_report/app/generate_report_extractor.py b/src/modules/generate_report/app/generate_report_extractor.py index 1c2a4e9..eb8e0c1 100644 --- a/src/modules/generate_report/app/generate_report_extractor.py +++ b/src/modules/generate_report/app/generate_report_extractor.py @@ -10,6 +10,9 @@ def __init__(self, booking_repository: IBookingRepository): def __call__(self, initial_date, final_date): try: + #TODO fazer chamada get_all_users + #retornar booking, users + bookings = self.booking_repository.get_all_bookings_by_date_range(initial_date, final_date) except: From 4c64758ff0a260e4a9fc36a18daa823dd01f41a1 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 21 May 2025 00:41:54 -0300 Subject: [PATCH 018/167] chore: add temporary macos files to .gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 97af28c..9d783f9 100644 --- a/.gitignore +++ b/.gitignore @@ -133,4 +133,7 @@ dmypy.json /.vscode/ /.idea/ -iac/local/docker/dynamodb/shared-local-instance.db \ No newline at end of file +iac/local/docker/dynamodb/shared-local-instance.db + +# MACOS temp files +.DS_Store \ No newline at end of file From 21a13c950b82e88c76e06607423ed7d29fc4e75f Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 21 May 2025 00:44:17 -0300 Subject: [PATCH 019/167] fix: defining get_all_users so load_booking_mock_to_dynamo can work --- src/shared/domain/repositories/booking_repository_interface.py | 2 +- src/shared/infra/repositories/booking_repository_dynamo.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index 61835c2..ebcb773 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -51,7 +51,7 @@ def get_all_bookings(self): pass @abstractmethod - def get_all_users(Self): + def get_all_users(self) -> List[str]: ''' Returns name users by user id ''' diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index 242159e..9b38a21 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -110,4 +110,7 @@ def get_all_bookings_by_date_range(self, initial_date: int, final_date: int) -> all_bookings.append(booking) return all_bookings + + def get_all_users(self): + return super().get_all_users() From b9ef6f88d35aaff3d6952eda0e8965da030e70ad Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 21 May 2025 00:44:55 -0300 Subject: [PATCH 020/167] feat: implement user_api_client Facade --- .../generate_report/app/user_api_client.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/modules/generate_report/app/user_api_client.py diff --git a/src/modules/generate_report/app/user_api_client.py b/src/modules/generate_report/app/user_api_client.py new file mode 100644 index 0000000..da0080a --- /dev/null +++ b/src/modules/generate_report/app/user_api_client.py @@ -0,0 +1,25 @@ +import json +import os +import requests + +from src.shared.environments import Environments + +class UserAPIClient: + + def __init__(self): + self.all_users = self.retrieve_users() + + def get_user_name(self, user_id): + user = next((user for user in self.all_users if user["user_id"] == user_id), None) + return user["name"] if user is not None else None + + @staticmethod + def retrieve_users(): + + api_url= os.environ.get("USER_API_URL") + try: + response = requests.get(api_url) + users = response.json().get("users") + return users + except: + raise Exception('Couldn\'t retrieve users') From 7c1872fd97aa238282ba7db9be53f548971f4b4b Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 21 May 2025 00:45:07 -0300 Subject: [PATCH 021/167] test: user_api_client tested --- .../generate_report/app/test_user_api_client.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/modules/generate_report/app/test_user_api_client.py diff --git a/tests/modules/generate_report/app/test_user_api_client.py b/tests/modules/generate_report/app/test_user_api_client.py new file mode 100644 index 0000000..26133ad --- /dev/null +++ b/tests/modules/generate_report/app/test_user_api_client.py @@ -0,0 +1,13 @@ +import pytest +from src.modules.generate_report.app.user_api_client import UserAPIClient + + +class TestUserAPIClient: + + @pytest.mark.skip("Can't run test in gh actions") + def test_get_user(self): + + user_client = UserAPIClient() + user_name = user_client.get_user_name('1f25448b-3429-4c19-8287-d9e64f17bc3a') + + assert user_name == 'GUSTAVO ALVES GOMES' \ No newline at end of file From 5b3ead4fb2345254f3e3b3482568e25afc621ffc Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 21 May 2025 00:45:35 -0300 Subject: [PATCH 022/167] feat(report_aggregator): adds the user name on the excel file --- .../generate_report/app/generate_report_aggregator.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index 48f8b58..b2243c4 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -1,3 +1,4 @@ +from src.modules.generate_report.app.user_api_client import UserAPIClient from src.shared.domain.entities.booking import Booking from .generate_report_extractor import GenerateReportExtractor from typing import List @@ -19,9 +20,13 @@ def __call__(self, initial_date, final_date): users_statistics = {} + user_api_client = UserAPIClient() + for booking in bookings: if booking.user_id not in users_statistics: + user_name = user_api_client.get_user_name(booking.user_id) users_statistics[booking.user_id] = { + "nome": user_name, "reservas_feitas": 0, "Tennis": 0, "Football": 0, @@ -39,6 +44,8 @@ def __call__(self, initial_date, final_date): "tempo_em_quadra": 0 } + + users_statistics[booking.user_id]["reservas_feitas"] += 1 users_statistics[booking.user_id][booking.sport.value] += 1 users_statistics[booking.user_id][booking.court_number] += 1 From a72e1b66ed8b923c31cb832a1f4b322afdb689d8 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 21 May 2025 00:48:34 -0300 Subject: [PATCH 023/167] feat(test_generate_report_transformer): update file opening logic for cross-platform compatibility --- .../app/test_generate_report_transformer.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/modules/generate_report/app/test_generate_report_transformer.py b/tests/modules/generate_report/app/test_generate_report_transformer.py index 5bfbd70..daacfd2 100644 --- a/tests/modules/generate_report/app/test_generate_report_transformer.py +++ b/tests/modules/generate_report/app/test_generate_report_transformer.py @@ -1,3 +1,5 @@ +import platform +import subprocess import pytest from src.modules.generate_report.app.generate_report_aggregator import GenerateReportAggregator @@ -24,4 +26,10 @@ def test_generate_report_transformer(self): tmp_file.write(output.read()) tmp_file_path = tmp_file.name - os.startfile(tmp_file_path) \ No newline at end of file + # os.startfile(tmp_file_path) + + system = platform.system() + if system == 'Windows': + os.startfile(tmp_file_path) + else: # macOS + subprocess.call(['open', tmp_file_path]) \ No newline at end of file From d37e34c5ff229f2258adfffdcb14fd830d3478ea Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 21 May 2025 00:49:42 -0300 Subject: [PATCH 024/167] feat(test_generate_report_transformer): update file opening logic for cross-platform compatibility --- .../generate_report/app/test_generate_report_transformer.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/modules/generate_report/app/test_generate_report_transformer.py b/tests/modules/generate_report/app/test_generate_report_transformer.py index daacfd2..9a9e831 100644 --- a/tests/modules/generate_report/app/test_generate_report_transformer.py +++ b/tests/modules/generate_report/app/test_generate_report_transformer.py @@ -31,5 +31,7 @@ def test_generate_report_transformer(self): system = platform.system() if system == 'Windows': os.startfile(tmp_file_path) - else: # macOS - subprocess.call(['open', tmp_file_path]) \ No newline at end of file + elif system == 'Darwin': + subprocess.call(['open', tmp_file_path]) + else: + subprocess.call(['xdg-open', tmp_file_path]) \ No newline at end of file From acebfd4b168f8fde7cac7f2cd00b82432387c9a2 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 21 May 2025 00:54:15 -0300 Subject: [PATCH 025/167] chore: add requests package to requirements-dev.txt --- requirements-dev.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index e9092c9..44455a7 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -5,4 +5,5 @@ python-dotenv==0.21.0 aws-lambda-powertools==2.9.0 aws_xray_sdk==2.11.0 pandas==2.2.3 -XlsxWriter==3.2.2 \ No newline at end of file +XlsxWriter==3.2.2 +requests==2.32.3 \ No newline at end of file From 6cf72d26eb32830d9514065488d8a8de789e88dd Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 21 May 2025 20:37:56 -0300 Subject: [PATCH 026/167] feat(generate_report_aggregator): update user statistics key handling for improved user identification --- .../app/generate_report_aggregator.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index b2243c4..4e35277 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -25,8 +25,8 @@ def __call__(self, initial_date, final_date): for booking in bookings: if booking.user_id not in users_statistics: user_name = user_api_client.get_user_name(booking.user_id) - users_statistics[booking.user_id] = { - "nome": user_name, + key = user_name if user_name is not None else booking.user_id + users_statistics[key] = { "reservas_feitas": 0, "Tennis": 0, "Football": 0, @@ -46,10 +46,10 @@ def __call__(self, initial_date, final_date): - users_statistics[booking.user_id]["reservas_feitas"] += 1 - users_statistics[booking.user_id][booking.sport.value] += 1 - users_statistics[booking.user_id][booking.court_number] += 1 - users_statistics[booking.user_id]["tempo_em_quadra"] += booking.end_date - booking.start_date + users_statistics[key]["reservas_feitas"] += 1 + users_statistics[key][booking.sport.value] += 1 + users_statistics[key][booking.court_number] += 1 + users_statistics[key]["tempo_em_quadra"] += booking.end_date - booking.start_date #court statistics logic From 054fcd189ab3e31fa48211e847ba8fee84549eae Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 23 May 2025 14:22:47 -0300 Subject: [PATCH 027/167] Revert "Merge branch 'dev' into user-on-generate-report" This reverts commit bb057fdad056bd8c3e4d359c82d254c7e91308a8, reversing changes made to 36a0ce1bba1aa2a6c0b88a79f3e01c8f1780c232. --- .github/workflows/CD.yml | 3 +- .gitignore | 1 - iac/stacks/iac_stack.py | 1 - iac/stacks/lambda_stack.py | 36 +- src/functions/__init__.py | 0 src/functions/graph_authorizer/__init__.py | 0 .../graph_authorizer/graph_authorizer.py | 109 ----- .../app/create_booking_controller.py | 15 +- .../app/create_booking_presenter.py | 1 - .../app/delete_booking_controller.py | 33 +- .../app/delete_booking_presenter.py | 1 - .../app/delete_booking_usecase.py | 20 +- ...oller.py => get_all_booking_controller.py} | 6 +- ...senter.py => get_all_booking_presenter.py} | 4 +- ..._usecase.py => get_all_booking_usecase.py} | 2 + ...wmodel.py => get_all_booking_viewmodel.py} | 0 .../get_booking/app/get_booking_controller.py | 25 +- .../get_booking/app/get_booking_usecase.py | 16 +- src/modules/get_bookings/__init__.py | 0 src/modules/get_bookings/app/__init__.py | 0 .../app/get_bookings_controller.py | 95 ---- .../app/get_bookings_presenter.py | 17 - .../get_bookings/app/get_bookings_usecase.py | 52 --- .../app/get_bookings_viewmodel.py | 16 - .../app/update_booking_controller.py | 64 +-- .../app/update_booking_usecase.py | 58 +-- .../booking_repository_interface.py | 19 +- .../helpers/errors/controller_errors.py | 10 +- src/shared/helpers/errors/domain_errors.py | 2 +- src/shared/helpers/errors/usecase_errors.py | 7 +- .../repositories/booking_repository_dynamo.py | 36 +- .../repositories/booking_repository_mock.py | 39 +- .../app/test_create_booking_controller.py | 373 ++++++++-------- .../app/test_create_booking_presenter.py | 7 +- .../app/test_delete_booking_controller.py | 62 +-- .../app/test_delete_booking_presenter.py | 20 - .../app/test_delete_booking_usecase.py | 17 +- .../app/test_delete_booking_viewmodel.py | 3 +- .../app/test_get_all_bookings_controller.py | 4 +- .../app/test_get_all_bookings_presenter.py | 2 +- .../app/test_get_all_bookings_usecase.py | 2 +- .../app/test_get_all_bookings_viewmodel.py | 4 +- .../app/test_get_booking_controller.py | 6 + .../app/test_get_booking_presenter.py | 2 +- tests/modules/get_bookings/__init__.py | 0 tests/modules/get_bookings/app/__init__.py | 0 .../app/test_get_bookings_controller.py | 218 --------- .../app/test_get_bookings_presenter.py | 297 ------------- .../app/test_get_bookings_usecase.py | 26 -- .../app/test_get_bookings_viewmodel.py | 26 -- .../app/test_update_booking_controller.py | 414 +++++++++--------- .../app/test_update_booking_usecase.py | 133 ++---- .../test_booking_repository_dynamo.py | 239 +--------- 53 files changed, 570 insertions(+), 1973 deletions(-) delete mode 100644 src/functions/__init__.py delete mode 100644 src/functions/graph_authorizer/__init__.py delete mode 100644 src/functions/graph_authorizer/graph_authorizer.py rename src/modules/get_all_bookings/app/{get_all_bookings_controller.py => get_all_booking_controller.py} (75%) rename src/modules/get_all_bookings/app/{get_all_bookings_presenter.py => get_all_booking_presenter.py} (81%) rename src/modules/get_all_bookings/app/{get_all_bookings_usecase.py => get_all_booking_usecase.py} (79%) rename src/modules/get_all_bookings/app/{get_all_bookings_viewmodel.py => get_all_booking_viewmodel.py} (100%) delete mode 100644 src/modules/get_bookings/__init__.py delete mode 100644 src/modules/get_bookings/app/__init__.py delete mode 100644 src/modules/get_bookings/app/get_bookings_controller.py delete mode 100644 src/modules/get_bookings/app/get_bookings_presenter.py delete mode 100644 src/modules/get_bookings/app/get_bookings_usecase.py delete mode 100644 src/modules/get_bookings/app/get_bookings_viewmodel.py delete mode 100644 tests/modules/get_bookings/__init__.py delete mode 100644 tests/modules/get_bookings/app/__init__.py delete mode 100644 tests/modules/get_bookings/app/test_get_bookings_controller.py delete mode 100644 tests/modules/get_bookings/app/test_get_bookings_presenter.py delete mode 100644 tests/modules/get_bookings/app/test_get_bookings_usecase.py delete mode 100644 tests/modules/get_bookings/app/test_get_bookings_viewmodel.py diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index c065d30..8a5c558 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -54,5 +54,4 @@ jobs: AWS_REGION: ${{ vars.AWS_REGION }} AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} STACK_NAME: ${{ env.STACK_NAME }} - GITHUB_REF_NAME: ${{ github.ref_name }} - GRAPH_MICROSOFT_ENDPOINT: ${{ secrets.GRAPH_MICROSOFT_ENDPOINT }} \ No newline at end of file + GITHUB_REF_NAME: ${{ github.ref_name }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7f429f5..9d783f9 100644 --- a/.gitignore +++ b/.gitignore @@ -135,6 +135,5 @@ dmypy.json /.idea/ iac/local/docker/dynamodb/shared-local-instance.db - # MACOS temp files .DS_Store \ No newline at end of file diff --git a/iac/stacks/iac_stack.py b/iac/stacks/iac_stack.py index 7ef8b21..a7a1918 100644 --- a/iac/stacks/iac_stack.py +++ b/iac/stacks/iac_stack.py @@ -55,7 +55,6 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: "DYNAMO_PARTITION_KEY": "PK", "DYNAMO_SORT_KEY": "SK", "REGION": self.aws_region, - "GRAPH_MICROSOFT_ENDPOINT": os.getenv("GRAPH_MICROSOFT_ENDPOINT") } diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index dfd90e2..062889c 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -3,7 +3,6 @@ from aws_cdk import ( aws_lambda as lambda_, NestedStack, Duration, - aws_apigateway as apigw, ) from constructs import Construct from aws_cdk.aws_apigateway import Resource, LambdaIntegration @@ -80,30 +79,11 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment compatible_runtimes=[lambda_.Runtime.PYTHON_3_9] ) - self.graph_authorizer_lambda = lambda_.Function( - self, "GraphAuthorizerLambdaReservationStacksANDCourts", - code=lambda_.Code.from_asset("../src/functions/graph_authorizer"), - handler="graph_authorizer.lambda_handler", - runtime=lambda_.Runtime.PYTHON_3_9, - layers=[self.lambda_layer], - environment=environment_variables, - timeout=Duration.seconds(15), - ) - - self.token_authorizer_graph = apigw.TokenAuthorizer( - self, "TokenAuthorizerGraphReservationStacksANDCourts", - handler=self.graph_authorizer_lambda, - identity_source=apigw.IdentitySource.header("Authorization"), - authorizer_name="GraphAuthorizerReservationStacksANDCourts", - results_cache_ttl=Duration.seconds(0) - ) - self.create_booking = self.create_lambda_api_gateway_integration( module_name="create_booking", method="POST", api_resource=api_gateway_resource, - environment_variables=environment_variables, - authorizer=self.token_authorizer_graph + environment_variables=environment_variables ) self.update_booking = self.create_lambda_api_gateway_integration( @@ -120,19 +100,11 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment environment_variables=environment_variables ) - self.get_bookings = self.create_lambda_api_gateway_integration( - module_name="get_bookings", - method="GET", - api_resource=api_gateway_resource, - environment_variables=environment_variables, - ) - self.delete_booking = self.create_lambda_api_gateway_integration( module_name="delete_booking", method="DELETE", api_resource=api_gateway_resource, - environment_variables=environment_variables, - authorizer=self.token_authorizer_graph + environment_variables=environment_variables ) self.get_all_bookings = self.create_lambda_api_gateway_integration( @@ -200,9 +172,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment self.get_booking, self.update_booking, self.delete_booking, - self.get_all_bookings, - self.get_bookings, - self.graph_authorizer_lambda + self.get_all_bookings ] self.functions_that_need_s3_permissions = [ diff --git a/src/functions/__init__.py b/src/functions/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/functions/graph_authorizer/__init__.py b/src/functions/graph_authorizer/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/functions/graph_authorizer/graph_authorizer.py b/src/functions/graph_authorizer/graph_authorizer.py deleted file mode 100644 index d771966..0000000 --- a/src/functions/graph_authorizer/graph_authorizer.py +++ /dev/null @@ -1,109 +0,0 @@ -import os -import re -import json -import urllib3 - -def lambda_handler(event, context): - """ - This function is used to authorize the user to access the API Gateway. - It uses the Microsoft Graph API to fetch the user information and check if the user is from Maua. - - Args: - event (dict): The event data passed to the Lambda function. - context (object): The context object representing the current invocation. - - Returns: - dict: The response object containing the policy document. - """ - - try: - # Fetching the Microsoft Graph endpoint from the environment variables - GRAPH_MICROSOFT_ENDPOINT = os.environ.get("GRAPH_MICROSOFT_ENDPOINT", None) - if not GRAPH_MICROSOFT_ENDPOINT: - raise Exception("MS_GRAPH_ENDPOINT environment variable not set") - - # Creating a HTTP client - http = urllib3.PoolManager() - - # Extracting the token from the event data - token = event["authorizationToken"].replace("Bearer ", "") - - print(f"token: {token}") - print(f"graph_endpoint: {GRAPH_MICROSOFT_ENDPOINT}") - - # Fetching the user information from the Microsoft Graph API - graph_endpoint = GRAPH_MICROSOFT_ENDPOINT - methodArn = event["methodArn"] - headers = {"Authorization": f"Bearer {token}"} - response = http.request("GET", graph_endpoint, headers=headers) - - # Checking if the request was successful - if response.status != 200: - raise Exception("Failed to fetch user information") - - # Parsing the user data - user_data = json.loads(response.data.decode("utf-8")) - - print("CHECK BEFORE REGEX") - print(user_data) - - # Checking if the user is from Maua - email_regex = r"[\d]{2}\.[\d]{5}-[\d]@maua\.br" # Regex to match the Maua email - if not re.match(email_regex, user_data.get("mail", "")): - return generate_policy("user", "Deny", methodArn) - - print("USER_ID: ", user_data.get("id", "did not find id")) - - print("CHECK PASSED REGEX AND GET USER") - - policy = generate_policy( - user_data.get("id", "user"), "Allow", methodArn, {"user": json.dumps(user_data)} - ) - - print(policy) - - return policy - - # Handling exceptions - except Exception as e: - print(f"Error: {e}") - methodArn = event["methodArn"] - return generate_policy("user", "Deny", methodArn) - - -def generate_policy(principal_id, effect, method_arn, context=None): - ''' - This function generates the policy document based on the principal ID, effect, method ARN, and context. - - Args: - principal_id (str): The principal ID. - effect (str): The effect (Allow or Deny). - method_arn (str): The method ARN. - context (dict): The context object. - - Returns: - dict: The policy document. - ''' - - # Generating the policy document - auth_response = {"principalId": principal_id} - - if effect: - policy_document = { - "Version": "2012-10-17", # Version of the policy - "Statement": [ - { - "Action": "execute-api:Invoke", # Action to allow - "Effect": effect, # Effect (Allow or Deny) - "Resource": method_arn, # Resource path - } - ], - } - auth_response["policyDocument"] = policy_document - - if context: - auth_response["context"] = context # Adding the context to the response - - print("PASSED AUTH RESPONSE") - - return auth_response \ No newline at end of file diff --git a/src/modules/create_booking/app/create_booking_controller.py b/src/modules/create_booking/app/create_booking_controller.py index 085b678..8efb383 100644 --- a/src/modules/create_booking/app/create_booking_controller.py +++ b/src/modules/create_booking/app/create_booking_controller.py @@ -1,8 +1,6 @@ -import json - from .create_booking_usecase import CreateBookingUsecase from .create_booking_viewmodel import CreateBookingViewmodel -from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter, AuthorizerError +from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.errors.usecase_errors import DuplicatedItem from src.shared.helpers.external_interfaces.external_interface import IRequest @@ -16,20 +14,11 @@ def __init__(self, create_booking_use_case: CreateBookingUsecase): def __call__(self, request: IRequest): - user_from_authorizer = request.data.get('user_from_authorizer', None) - - if not isinstance(request.data.get('user_from_authorizer'), dict): - - user_from_authorizer = json.loads(request.data.get('user_from_authorizer')) - - if user_from_authorizer is None: - raise AuthorizerError() - start_date = request.data.get('start_date', None) end_date = request.data.get('end_date', None) court_number = request.data.get('court_number', None) sport = request.data.get('sport', None) - user_id = user_from_authorizer.get('id', None) + user_id = request.data.get('user_id', None) materials = request.data.get('materials', None) try: diff --git a/src/modules/create_booking/app/create_booking_presenter.py b/src/modules/create_booking/app/create_booking_presenter.py index c67b811..f2e9100 100644 --- a/src/modules/create_booking/app/create_booking_presenter.py +++ b/src/modules/create_booking/app/create_booking_presenter.py @@ -9,7 +9,6 @@ def lambda_handler(event, context): httpRequest = LambdaHttpRequest(data=event) - httpRequest.data['user_from_authorizer'] = event.get('requestContext', {}).get('authorizer', {}).get('user', None) response = controller(request=httpRequest) httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) diff --git a/src/modules/delete_booking/app/delete_booking_controller.py b/src/modules/delete_booking/app/delete_booking_controller.py index ed24ede..e4de475 100644 --- a/src/modules/delete_booking/app/delete_booking_controller.py +++ b/src/modules/delete_booking/app/delete_booking_controller.py @@ -1,13 +1,13 @@ -import json - +from typing import Any +from src.shared.domain.entities.booking import Booking from .delete_booking_usecase import DeleteBookingUsecase from .delete_booking_viewmodel import DeleteBookingViewModel -from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter, AuthorizerError +from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.errors.usecase_errors import NoItemsFound, ForbiddenAction +from src.shared.helpers.errors.usecase_errors import NoItemsFound from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse -from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, InternalServerError, NotFound, Forbidden - +from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, Created, InternalServerError, NotFound +from src.shared.domain.enums.sport import SPORT class DeleteBookingController: @@ -16,34 +16,15 @@ def __init__(self, usecase: DeleteBookingUsecase): def __call__(self, request: IRequest) -> IResponse: try: - - user_from_authorizer = request.data.get('user_from_authorizer', None) - - if not isinstance(request.data.get('user_from_authorizer'), dict): - - user_from_authorizer = json.loads(request.data.get('user_from_authorizer')) - - if user_from_authorizer is None: - raise AuthorizerError() - - user_id = user_from_authorizer.get('id', None) - if request.data.get('booking_id') is None: raise MissingParameters('booking_id') - booking = self.usecase(booking_id=request.data.get('booking_id'), - user_id=user_id) + booking = self.usecase(booking_id=request.data.get('booking_id')) viewmodel = DeleteBookingViewModel(booking) return OK(viewmodel.to_dict()) except MissingParameters as err: return BadRequest(body=err.message) - - except ForbiddenAction as err: - return Forbidden(body=err.message) - - except AuthorizerError as err: - return InternalServerError(body=err.message) except WrongTypeParameter as err: return BadRequest(body=err.message) diff --git a/src/modules/delete_booking/app/delete_booking_presenter.py b/src/modules/delete_booking/app/delete_booking_presenter.py index 5d2836e..5183e6f 100644 --- a/src/modules/delete_booking/app/delete_booking_presenter.py +++ b/src/modules/delete_booking/app/delete_booking_presenter.py @@ -9,7 +9,6 @@ def lambda_handler(event, context): httpRequest = LambdaHttpRequest(data=event) - httpRequest.data['user_from_authorizer'] = event.get('requestContext', {}).get('authorizer', {}).get('user', {}) response = controller(request=httpRequest) httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) diff --git a/src/modules/delete_booking/app/delete_booking_usecase.py b/src/modules/delete_booking/app/delete_booking_usecase.py index ceda421..09f07ef 100644 --- a/src/modules/delete_booking/app/delete_booking_usecase.py +++ b/src/modules/delete_booking/app/delete_booking_usecase.py @@ -1,30 +1,22 @@ from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT -from src.shared.domain.repositories.booking_repository_interface import IBookingRepository -from src.shared.helpers.errors.usecase_errors import DuplicatedItem, ForbiddenAction +from src.shared.helpers.errors.usecase_errors import DuplicatedItem from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.errors.usecase_errors import NoItemsFound from src.shared.domain.repositories.reservation_repository_interface import IReservationRepository class DeleteBookingUsecase: - def __init__(self, repo: IBookingRepository): + def __init__(self, repo:IReservationRepository): self.repo = repo - def __call__(self, - booking_id: str, - user_id: str): + def __call__(self, booking_id: int): if not Booking.validate_booking_id(booking_id): raise EntityError('booking_id') - - booking = self.repo.get_booking(booking_id=booking_id) - - if booking is None: - raise NoItemsFound('booking') - - if booking.user_id != user_id: - raise ForbiddenAction('user; trying to delete booking that is not his') booking = self.repo.delete_booking(booking_id=booking_id) + if booking is None: + raise NoItemsFound('booking') + return booking \ No newline at end of file diff --git a/src/modules/get_all_bookings/app/get_all_bookings_controller.py b/src/modules/get_all_bookings/app/get_all_booking_controller.py similarity index 75% rename from src/modules/get_all_bookings/app/get_all_bookings_controller.py rename to src/modules/get_all_bookings/app/get_all_booking_controller.py index df4369a..5eceb5c 100644 --- a/src/modules/get_all_bookings/app/get_all_bookings_controller.py +++ b/src/modules/get_all_bookings/app/get_all_booking_controller.py @@ -1,5 +1,7 @@ -from .get_all_bookings_usecase import GetAllBookingsUsecase -from .get_all_bookings_viewmodel import GetAllBookingViewModel +from typing import Any +from .get_all_booking_usecase import GetAllBookingsUsecase +from .get_all_booking_viewmodel import GetAllBookingViewModel +from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.external_interfaces.external_interface import IRequest from src.shared.helpers.external_interfaces.http_codes import BadRequest, OK, InternalServerError diff --git a/src/modules/get_all_bookings/app/get_all_bookings_presenter.py b/src/modules/get_all_bookings/app/get_all_booking_presenter.py similarity index 81% rename from src/modules/get_all_bookings/app/get_all_bookings_presenter.py rename to src/modules/get_all_bookings/app/get_all_booking_presenter.py index b396c76..91dec82 100644 --- a/src/modules/get_all_bookings/app/get_all_bookings_presenter.py +++ b/src/modules/get_all_bookings/app/get_all_booking_presenter.py @@ -1,5 +1,5 @@ -from .get_all_bookings_controller import GetAllBookingsController -from .get_all_bookings_usecase import GetAllBookingsUsecase +from .get_all_booking_controller import GetAllBookingsController +from .get_all_booking_usecase import GetAllBookingsUsecase from src.shared.environments import Environments from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse diff --git a/src/modules/get_all_bookings/app/get_all_bookings_usecase.py b/src/modules/get_all_bookings/app/get_all_booking_usecase.py similarity index 79% rename from src/modules/get_all_bookings/app/get_all_bookings_usecase.py rename to src/modules/get_all_bookings/app/get_all_booking_usecase.py index 70acd06..fe4533e 100644 --- a/src/modules/get_all_bookings/app/get_all_bookings_usecase.py +++ b/src/modules/get_all_bookings/app/get_all_booking_usecase.py @@ -1,4 +1,6 @@ +from typing import Any from src.shared.domain.repositories.booking_repository_interface import IBookingRepository +from src.shared.domain.entities.booking import Booking class GetAllBookingsUsecase: def __init__(self, repo: IBookingRepository): diff --git a/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py b/src/modules/get_all_bookings/app/get_all_booking_viewmodel.py similarity index 100% rename from src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py rename to src/modules/get_all_bookings/app/get_all_booking_viewmodel.py diff --git a/src/modules/get_booking/app/get_booking_controller.py b/src/modules/get_booking/app/get_booking_controller.py index 2939634..3d9d0a2 100644 --- a/src/modules/get_booking/app/get_booking_controller.py +++ b/src/modules/get_booking/app/get_booking_controller.py @@ -1,6 +1,6 @@ from .get_booking_viewmodel import GetBookingViewmodel from .get_booking_usecase import GetBookingUseCase -from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter, EmptyQueryParameters +from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.errors.usecase_errors import NoItemsFound from src.shared.helpers.external_interfaces.external_interface import IRequest @@ -13,26 +13,25 @@ def __init__(self, usecase: GetBookingUseCase): def __call__(self, request: IRequest): try: - - booking_id = request.data.get('booking_id', None) + if request.data.get('booking_id') is None: + raise MissingParameters('booking_id') + + booking_id = request.data.get('booking_id') if booking_id is not None: - if not isinstance(booking_id, str): - raise WrongTypeParameter('booking_id', - fieldTypeReceived=type(booking_id).__name__, - fieldTypeExpected='str') - else: - raise MissingParameters('booking_id') + if type(booking_id) is not str: + raise WrongTypeParameter( + 'booking_id', + 'str', + (type(booking_id)).__name__ + ) booking = self.usecase( - booking_id=booking_id + booking_id = request.data.get('booking_id') ) booking_viewmodel = GetBookingViewmodel(booking) return OK(booking_viewmodel.to_dict()) - except EmptyQueryParameters as err: - return BadRequest(body=err.message) - except MissingParameters as err: return BadRequest(body=err.message) diff --git a/src/modules/get_booking/app/get_booking_usecase.py b/src/modules/get_booking/app/get_booking_usecase.py index c31b44b..ecc32e8 100644 --- a/src/modules/get_booking/app/get_booking_usecase.py +++ b/src/modules/get_booking/app/get_booking_usecase.py @@ -1,9 +1,7 @@ -from typing import Optional - from src.shared.domain.entities.booking import Booking from src.shared.domain.repositories.booking_repository_interface import IBookingRepository from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.errors.usecase_errors import NoItemsFound, DependantFilter +from src.shared.helpers.errors.usecase_errors import NoItemsFound class GetBookingUseCase: repo: IBookingRepository @@ -11,15 +9,11 @@ class GetBookingUseCase: def __init__(self, repo: IBookingRepository): self.repo = repo - def __call__(self, - booking_id: str): - - if not Booking.validate_booking_id(booking_id): + def __call__(self, booking_id: str): + if not Booking.validate_booking_id(booking_id=booking_id): raise EntityError('booking_id') - - booking = self.repo.get_booking( - booking_id=booking_id - ) + + booking = self.repo.get_booking(booking_id=booking_id) if booking is None: raise NoItemsFound('booking_id') diff --git a/src/modules/get_bookings/__init__.py b/src/modules/get_bookings/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/modules/get_bookings/app/__init__.py b/src/modules/get_bookings/app/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/modules/get_bookings/app/get_bookings_controller.py b/src/modules/get_bookings/app/get_bookings_controller.py deleted file mode 100644 index 5715e8d..0000000 --- a/src/modules/get_bookings/app/get_bookings_controller.py +++ /dev/null @@ -1,95 +0,0 @@ -import json - -from .get_bookings_viewmodel import GetBookingsViewmodel -from .get_bookings_usecase import GetBookingsUseCase -from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter, EmptyQueryParameters, \ - AuthorizerError -from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.errors.usecase_errors import NoItemsFound, DependantFilter -from src.shared.helpers.external_interfaces.external_interface import IRequest -from src.shared.helpers.external_interfaces.http_codes import BadRequest, OK, NotFound, InternalServerError - - -class GetBookingsController: - def __init__(self, usecase: GetBookingsUseCase): - self.usecase = usecase - - def __call__(self, request: IRequest): - try: - - booking_id = request.data.get('booking_id', None) - user_id = request.data.get('user_id', None) - sport = request.data.get('sport', None) - court_number = request.data.get('court_number', None) - end_date = request.data.get('end_date', None) - start_date = request.data.get('start_date', None) - - booking_id = booking_id if booking_id != "" else None - user_id = user_id if user_id != "" else None - sport = sport if sport != "" else None - court_number = court_number if court_number != "" else None - end_date = end_date if end_date != "" else None - start_date = start_date if start_date != "" else None - - if not booking_id and not user_id and not sport and not court_number and not end_date and not start_date: - raise EmptyQueryParameters( - 'At least one of the filters must be provided: booking_id, user_id, sport, court_number, end_date, start_date') - - if court_number is not None: - try: - court_number = int(court_number) - except ValueError: - raise WrongTypeParameter(fieldName='court_number', - fieldTypeExpected='int', - fieldTypeReceived=court_number) - - if end_date is not None: - try: - end_date = int(end_date) - except ValueError: - raise WrongTypeParameter(fieldName='end_date', - fieldTypeExpected='int', - fieldTypeReceived=end_date) - - if start_date is not None: - try: - start_date = int(start_date) - except ValueError: - raise WrongTypeParameter(fieldName='start_date', - fieldTypeExpected='int', - fieldTypeReceived=start_date) - - booking = self.usecase( - booking_id=booking_id, - user_id=user_id, - sport=sport, - court_number=court_number, - end_date=end_date, - start_date=start_date - ) - booking_viewmodel = GetBookingsViewmodel(booking) - return OK(booking_viewmodel.to_dict()) - - except AuthorizerError as err: - return BadRequest(body=err.message) - - except EmptyQueryParameters as err: - return BadRequest(body=err.message) - - except DependantFilter as err: - return BadRequest(body=err.message) - - except MissingParameters as err: - return BadRequest(body=err.message) - - except EntityError as err: - return BadRequest(body=err.message) - - except NoItemsFound as err: - return NotFound(body=err.message) - - except WrongTypeParameter as err: - return BadRequest(body=err.message) - - except Exception as err: - return InternalServerError(body=err.args[0]) diff --git a/src/modules/get_bookings/app/get_bookings_presenter.py b/src/modules/get_bookings/app/get_bookings_presenter.py deleted file mode 100644 index 1815d57..0000000 --- a/src/modules/get_bookings/app/get_bookings_presenter.py +++ /dev/null @@ -1,17 +0,0 @@ -from .get_bookings_controller import GetBookingsController -from .get_bookings_usecase import GetBookingsUseCase -from src.shared.environments import Environments -from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse -from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock - -repo = Environments.get_booking_repo()() -usecase = GetBookingsUseCase(repo=repo) -controller = GetBookingsController(usecase=usecase) - - -def lambda_handler(event, context): - httpRequest = LambdaHttpRequest(data=event) - response = controller(request=httpRequest) - httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) - - return httpResponse.toDict() diff --git a/src/modules/get_bookings/app/get_bookings_usecase.py b/src/modules/get_bookings/app/get_bookings_usecase.py deleted file mode 100644 index 614b675..0000000 --- a/src/modules/get_bookings/app/get_bookings_usecase.py +++ /dev/null @@ -1,52 +0,0 @@ -from typing import Optional - -from src.shared.domain.entities.booking import Booking -from src.shared.domain.enums.sport import SPORT -from src.shared.domain.repositories.booking_repository_interface import IBookingRepository -from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.errors.usecase_errors import NoItemsFound, DependantFilter - -class GetBookingsUseCase: - repo: IBookingRepository - - def __init__(self, repo: IBookingRepository): - self.repo = repo - - def __call__(self, - booking_id: Optional[str] = None, - user_id: Optional[str] = None, - sport: Optional[str] = None, - court_number: Optional[int] = None, - end_date: Optional[int] = None, - start_date: Optional[int] = None): - - if booking_id: - if not Booking.validate_booking_id(booking_id): - raise EntityError('booking_id') - if user_id: - if not Booking.validate_user_id(user_id): - raise EntityError('user_id') - if sport: - if not Booking.validate_sport(SPORT(sport)): - raise EntityError('sport') - if court_number: - if not Booking.validate_court(court_number): - raise EntityError('court_number') - if end_date and start_date: - if not Booking.validate_dates(end_date, start_date): - raise EntityError('end_date or start_date') - - if (start_date and not end_date) or (end_date and not start_date): - raise DependantFilter('start_date and end_date') - - bookings = self.repo.get_bookings( - booking_id=booking_id if booking_id else None, - user_id=user_id if user_id else None, - sport=SPORT(sport) if sport else None, - court_number=court_number if court_number else None, - end_date=end_date if end_date else None, - start_date=start_date if start_date else None) - if bookings is None or bookings == []: - raise NoItemsFound('booking filters passed') - - return bookings diff --git a/src/modules/get_bookings/app/get_bookings_viewmodel.py b/src/modules/get_bookings/app/get_bookings_viewmodel.py deleted file mode 100644 index 94cdb07..0000000 --- a/src/modules/get_bookings/app/get_bookings_viewmodel.py +++ /dev/null @@ -1,16 +0,0 @@ -from typing import List -from src.shared.domain.entities.booking import Booking - - -class GetBookingsViewmodel: - bookings: List[Booking] - - def __init__(self, bookings: list): - self.bookings = bookings - - def to_dict(self): - return { - 'bookings': [booking.to_dict() for booking in self.bookings], - 'message': 'the bookings were retrieved' - } - diff --git a/src/modules/update_booking/app/update_booking_controller.py b/src/modules/update_booking/app/update_booking_controller.py index ecdd232..ae03073 100644 --- a/src/modules/update_booking/app/update_booking_controller.py +++ b/src/modules/update_booking/app/update_booking_controller.py @@ -4,8 +4,7 @@ from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse -from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, InternalServerError, NotFound -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, InternalServerError class UpdateBookingController: def __init__(self, update_booking_use_case: UpdateBookingUsecase): @@ -15,49 +14,33 @@ def __call__(self, request: IRequest) -> IResponse: try: if request.data.get('booking_id') is None: raise MissingParameters('booking_id') + + if request.data.get('start_date') is None: + raise MissingParameters('start_date') - booking_id = request.data.get('booking_id') - start_date = request.data.get('start_date') - end_date = request.data.get('end_date') - court_number = request.data.get('court_number') - sport_value = request.data.get('sport') - materials = request.data.get('materials') + if request.data.get('end_date') is None: + raise MissingParameters('end_date') + if request.data.get('court_number') is None: + raise MissingParameters('court_number') - if not isinstance(booking_id, str): - raise WrongTypeParameter('booking_id', 'str', type(booking_id).__name__) - - if start_date is not None and not isinstance(start_date, int): - raise WrongTypeParameter('start_date', 'int', type(start_date).__name__) - - if end_date is not None and not isinstance(end_date, int): - raise WrongTypeParameter('end_date', 'int', type(end_date).__name__) - - if court_number is not None and not isinstance(court_number, int): - raise WrongTypeParameter('court_number', 'int', type(court_number).__name__) - - sport = None - if sport_value is not None: - if not isinstance(sport_value, str): - raise WrongTypeParameter('sport', 'str', type(sport_value).__name__) - - if sport_value not in [sport_type.value for sport_type in SPORT]: - raise EntityError('sport') - - sport = SPORT(sport_value) + if request.data.get('sport') is None: + raise MissingParameters('sport') + sport = request.data.get('sport') + + if sport not in [sport_type.value for sport_type in SPORT]: + raise EntityError('sport') - if materials is not None and not isinstance(materials, list): - raise WrongTypeParameter('materials', 'list', type(materials).__name__) + if request.data.get('materials') is None: + raise MissingParameters('materials') - booking = self.UpdateBookingUsecase( - booking_id=booking_id, - start_date=start_date, - end_date=end_date, - court_number=court_number, - sport=sport, - materials=materials - ) + booking = self.UpdateBookingUsecase(booking_id=request.data.get('booking_id'), + start_date=request.data.get('start_date'), + end_date=request.data.get('end_date'), + court_number=request.data.get('court_number'), + sport=SPORT(sport), + materials=request.data.get('materials')) viewmodel = UpdateBookingViewmodel(booking=booking) @@ -72,8 +55,5 @@ def __call__(self, request: IRequest) -> IResponse: except EntityError as err: return BadRequest(body=err.message) - except NoItemsFound as err: - return NotFound(body=f"Booking not found: {err.message}") - except Exception as err: return InternalServerError(body=err.args[0]) \ No newline at end of file diff --git a/src/modules/update_booking/app/update_booking_usecase.py b/src/modules/update_booking/app/update_booking_usecase.py index 5c3e7c4..cf469f2 100644 --- a/src/modules/update_booking/app/update_booking_usecase.py +++ b/src/modules/update_booking/app/update_booking_usecase.py @@ -1,38 +1,25 @@ -from typing import List, Optional +from typing import List from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT from src.shared.domain.repositories.booking_repository_interface import IBookingRepository -from src.shared.helpers.errors.domain_errors import EntityError, EntityParameterOrderDatesError -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.errors.domain_errors import EntityError, EntityParameterOrderDatesError, EntityParameterTimeError + class UpdateBookingUsecase: def __init__(self, booking_repo: IBookingRepository): self.booking_repo = booking_repo def __call__(self, - booking_id: str, - start_date: int = None, - end_date: int = None, - court_number: int = None, - sport: SPORT = None, - materials: List[str] = None, - user_id: str = None): + booking_id: str, + start_date: int, + end_date: int, + court_number: int, + sport: SPORT, + materials: List[str] = None): if Booking.validate_booking_id(booking_id) is False: raise EntityError('booking_id') - existing_booking = self.booking_repo.get_booking(booking_id) - if existing_booking is None: - raise NoItemsFound('booking') - - - start_date = start_date if start_date is not None else existing_booking.start_date - end_date = end_date if end_date is not None else existing_booking.end_date - court_number = court_number if court_number is not None else existing_booking.court_number - sport = sport if sport is not None else existing_booking.sport - materials = materials if materials is not None else existing_booking.materials - - if Booking.validate_dates(start_date, end_date) is False: raise EntityError("date") @@ -41,23 +28,24 @@ def __call__(self, if Booking.validate_court(court_number) is False: raise EntityError("court_number") - + if Booking.validate_sport(sport) is False: raise EntityError("sport") if Booking.validate_materials(materials) is False: raise EntityError("materials") - - booking = self.booking_repo.update_booking( - booking_id=booking_id, - start_date=start_date, - end_date=end_date, - court_number=court_number, - sport=sport, - materials=materials - ) + + booking = self.booking_repo.update_booking(booking_id=booking_id, + start_date=start_date, + end_date=end_date, + court_number=court_number, + sport=sport, + materials=materials) + + return booking + + + - if booking.user_id != existing_booking.user_id: - booking.user_id = existing_booking.user_id - return booking \ No newline at end of file + diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index 3560d10..ebcb773 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -29,29 +29,14 @@ def update_booking(self, pass @abstractmethod - def get_booking(self, - booking_id: str) -> Optional[Booking]: + def get_booking(self, booking_id: str) -> Optional[Booking]: ''' If the booking exists, returns it, else returns None ''' pass @abstractmethod - def get_bookings(self, - booking_id: Optional[str] = None, - user_id: Optional[str] = None, - sport: Optional[SPORT] = None, - court_number: Optional[int] = None, - end_date: Optional[int] = None, - start_date: Optional[int] = None) -> List[Optional[Booking]]: - ''' - If the booking exists, returns it, else returns None - ''' - pass - - @abstractmethod - def delete_booking(self, - booking_id: str) -> Optional[Booking]: + def delete_booking(self, booking_id: int) -> Optional[Booking]: ''' If booking exists, deletes it and returns it else returns None diff --git a/src/shared/helpers/errors/controller_errors.py b/src/shared/helpers/errors/controller_errors.py index 7ea6d12..c319375 100644 --- a/src/shared/helpers/errors/controller_errors.py +++ b/src/shared/helpers/errors/controller_errors.py @@ -6,12 +6,4 @@ def __init__(self, message: str): super().__init__(f'Field {message} is missing') class WrongTypeParameter(BaseError): def __init__(self, fieldName: str, fieldTypeExpected: str, fieldTypeReceived: str): - super().__init__(f'Field {fieldName} isn\'t in the right type.\n Received: {fieldTypeReceived}.\n Expected: {fieldTypeExpected}') - -class EmptyQueryParameters(BaseError): - def __init__(self, message: str): - super().__init__(f'Empty query parameters: {message}') - -class AuthorizerError(BaseError): - def __init__(self): - super().__init__('User was not returned from authorizer') \ No newline at end of file + super().__init__(f'Field {fieldName} isn\'t in the right type.\n Received: {fieldTypeReceived}.\n Expected: {fieldTypeExpected}') \ No newline at end of file diff --git a/src/shared/helpers/errors/domain_errors.py b/src/shared/helpers/errors/domain_errors.py index 305be4c..bf54248 100644 --- a/src/shared/helpers/errors/domain_errors.py +++ b/src/shared/helpers/errors/domain_errors.py @@ -30,4 +30,4 @@ def message(self): class EntityParameterTimeError(BaseError): def __init__(self, start_Date: int, end_date: int): super().__init__(f'Initial time {start_Date} must be less than or equal to end time {end_date}') - + \ No newline at end of file diff --git a/src/shared/helpers/errors/usecase_errors.py b/src/shared/helpers/errors/usecase_errors.py index 9f6c934..2c70add 100644 --- a/src/shared/helpers/errors/usecase_errors.py +++ b/src/shared/helpers/errors/usecase_errors.py @@ -12,11 +12,6 @@ class ForbiddenAction(BaseError): def __init__(self, message: str): super().__init__(f'That action is forbidden for this {message}') - class DynamoDBBaseError(BaseError): def __init__(self, message: str): - super().__init__(f'Error extracting bookings from dynamo: {message}') - -class DependantFilter(BaseError): - def __init__(self, message: str): - super().__init__(f'Filters have to be provided together: {message}') \ No newline at end of file + super().__init__(f'Error extracting bookings from dynamo: {message}') \ No newline at end of file diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index 9ab2b0d..9b38a21 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -57,7 +57,7 @@ def update_booking(self, "start_date": start_date if start_date is not None else booking_to_update.start_date, "end_date": end_date if end_date is not None else booking_to_update.end_date, "court_number": court_number if court_number is not None else booking_to_update.court_number, - "sport": sport.value if sport is not None else booking_to_update.sport.value, + "sport": sport if sport is not None else booking_to_update.sport, "materials": materials if materials is not None else booking_to_update.materials } @@ -70,40 +70,6 @@ def update_booking(self, return BookingDynamoDTO.from_dynamo(resp['Attributes']).to_entity() - def get_bookings(self, - booking_id: Optional[str] = None, - user_id: Optional[str] = None, - sport: Optional[SPORT] = None, - court_number: Optional[int] = None, - end_date: Optional[int] = None, - start_date: Optional[int] = None) -> List[Optional[Booking]]: - - filters = locals().copy() - filters.pop('self') - filters.pop('end_date') - filters.pop('start_date') - - filters = {k: v for k, v in filters.items() if v is not None} - - all_bookings = self.get_all_bookings() - - bookings = [] - - for booking in all_bookings: - booking_dict = booking.__dict__ - if start_date and end_date: - if all( - booking_dict.get(key) == value for key, value in filters.items() - ) and booking.start_date >= start_date and booking.end_date <= end_date: - bookings.append(booking) - else: - if all( - booking_dict.get(key) == value for key, value in filters.items() - ): - bookings.append(booking) - - return bookings - def get_booking(self, booking_id: str) -> Optional[Booking]: dynamo_object = self.dynamo.get_item(partition_key=self.booking_partition_key_format(), diff --git a/src/shared/infra/repositories/booking_repository_mock.py b/src/shared/infra/repositories/booking_repository_mock.py index 25e9d70..5eb3a70 100644 --- a/src/shared/infra/repositories/booking_repository_mock.py +++ b/src/shared/infra/repositories/booking_repository_mock.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import List from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT from src.shared.domain.repositories.booking_repository_interface import IBookingRepository @@ -121,44 +121,11 @@ def update_booking(self, return booking - def get_bookings(self, - booking_id: Optional[str] = None, - user_id: Optional[str] = None, - sport: Optional[str] = None, - court_number: Optional[int] = None, - end_date: Optional[int] = None, - start_date: Optional[int] = None) -> List[Optional[Booking]]: - - filters = locals().copy() - filters.pop('self') - filters.pop('end_date') - filters.pop('start_date') - - filters = {k: v for k, v in filters.items() if v is not None} - - bookings = [] - - for booking in self.bookings: - booking_dict = booking.__dict__ - if start_date and end_date: - if all( - booking_dict.get(key) == value for key, value in filters.items() - ) and booking.start_date >= start_date and booking.end_date <= end_date: - bookings.append(booking) - else: - if all( - booking_dict.get(key) == value for key, value in filters.items() - ): - bookings.append(booking) - - return bookings - - def get_booking(self, - booking_id: str) -> Optional[Booking]: - + def get_booking(self, booking_id: str): for booking in self.bookings: if booking.booking_id == booking_id: return booking + return None def delete_booking(self, booking_id: str): booking = self.get_booking(booking_id) diff --git a/tests/modules/create_booking/app/test_create_booking_controller.py b/tests/modules/create_booking/app/test_create_booking_controller.py index c349251..2c4df9e 100644 --- a/tests/modules/create_booking/app/test_create_booking_controller.py +++ b/tests/modules/create_booking/app/test_create_booking_controller.py @@ -7,96 +7,75 @@ class TestCreateBookingController: def test_create_booking_controller(self): + repo = BookingRepositoryMock() usecase = CreateBookingUsecase(repo) controller = CreateBookingController(usecase) - request = HttpRequest( - body={ - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": 1, - "sport": "Tennis", - "materials": ["racket", "balls"] - }, - headers={ - "user_from_authorizer": { - "displayName": 'Lebron James', - "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - } - } - ) + request = HttpRequest(body= { + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": 1, + "sport": "Tennis", + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "materials": ["racket", "balls"] + }) response = controller(request) assert response.status_code == 201 def test_create_booking_controller_missing_start_date(self): - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - - request = HttpRequest( - body={ - "end_date": 1630003600, - "court_number": 1, - "sport": "Tennis", - "materials": ["racket", "balls"] - }, - headers={ - "user_from_authorizer": { - "displayName": 'Lebron James', - "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - } - }) - - response = controller(request) - - assert response.body == "Field start_date is missing" - assert response.status_code == 400 - def test_create_booking_controller_wrong_type_start_date(self): repo = BookingRepositoryMock() usecase = CreateBookingUsecase(repo) controller = CreateBookingController(usecase) - request = HttpRequest(body={ - "start_date": "1630000000", + request = HttpRequest(body= { "end_date": 1630003600, "court_number": 1, "sport": "Tennis", + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', "materials": ["racket", "balls"] - }, headers={ - "user_from_authorizer": { - "displayName": 'Lebron James', - "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - } }) response = controller(request) - assert response.body == "Field start_date isn't in the right type.\n Received: str.\n Expected: int" + assert response.body == "Field start_date is missing" assert response.status_code == 400 + def test_create_booking_controller_wrong_type_start_date(self): + + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) + + request = HttpRequest(body= { + "start_date": "1630000000", + "end_date": 1630003600, + "court_number": 1, + "sport": "Tennis", + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "materials": ["racket", "balls"] + }) + + response = controller(request) + + assert response.body == "Field start_date isn't in the right type.\n Received: str.\n Expected: int" + assert response.status_code == 400 + def test_create_booking_controller_missing_end_date(self): + repo = BookingRepositoryMock() usecase = CreateBookingUsecase(repo) controller = CreateBookingController(usecase) - request = HttpRequest(body={ + request = HttpRequest(body= { "start_date": 1630000000, "court_number": 1, "sport": "Tennis", + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', "materials": ["racket", "balls"] - }, headers={ - "user_from_authorizer": { - "displayName": 'Lebron James', - "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - } }) response = controller(request) @@ -105,190 +84,198 @@ def test_create_booking_controller_missing_end_date(self): assert response.status_code == 400 def test_create_booking_controller_wrong_type_end_date(self): - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - request = HttpRequest(body={ - "start_date": 1630000000, - "end_date": "1630003600", - "court_number": 1, - "sport": "Tennis", - "materials": ["racket", "balls"] - }, headers={ - "user_from_authorizer": { - "displayName": 'Lebron James', - "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - } - }) + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) - response = controller(request) + request = HttpRequest(body= { + "start_date": 1630000000, + "end_date": "1630003600", + "court_number": 1, + "sport": "Tennis", + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "materials": ["racket", "balls"] + }) - assert response.body == "Field end_date isn't in the right type.\n Received: str.\n Expected: int" - assert response.status_code == 400 + response = controller(request) + + assert response.body == "Field end_date isn't in the right type.\n Received: str.\n Expected: int" + assert response.status_code == 400 def test_create_booking_wrong_type_court_number(self): - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - request = HttpRequest(body={ - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": "1", - "sport": "Tennis", - "materials": ["racket", "balls"] - }, headers={ - "user_from_authorizer": { - "displayName": 'Lebron James', - "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - } - }) + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) - response = controller(request) + request = HttpRequest(body= { + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": "1", + "sport": "Tennis", + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "materials": ["racket", "balls"] + }) - assert response.body == "Field court_number isn't in the right type.\n Received: str.\n Expected: int" - assert response.status_code == 400 + response = controller(request) + + assert response.body == "Field court_number isn't in the right type.\n Received: str.\n Expected: int" + assert response.status_code == 400 def test_create_booking_controller_missing_court_number(self): - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - request = HttpRequest(body={ - "start_date": 1630000000, - "end_date": 1630003600, - "sport": "Tennis", - "materials": ["racket", "balls"] - }, headers={ - "user_from_authorizer": { - "displayName": 'Lebron James', - "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - } - }) + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) - response = controller(request) + request = HttpRequest(body= { + "start_date": 1630000000, + "end_date": 1630003600, + "sport": "Tennis", + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "materials": ["racket", "balls"] + }) - assert response.body == "Field court_number is missing" - assert response.status_code == 400 + response = controller(request) + + assert response.body == "Field court_number is missing" + assert response.status_code == 400 def test_create_booking_controller_missing_sport(self): - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - request = HttpRequest(body={ - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": 1, - "materials": ["racket", "balls"] - }, headers={ - "user_from_authorizer": { - "displayName": 'Lebron James', - "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - } - }) + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) - response = controller(request) + request = HttpRequest(body= { + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": 1, + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "materials": ["racket", "balls"] + }) - assert response.body == "Field sport is missing" - assert response.status_code == 400 + response = controller(request) + + assert response.body == "Field sport is missing" + assert response.status_code == 400 def test_create_booking_controller_wrong_type_sport(self): - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - request = HttpRequest(body={ - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": 1, - "sport": 1, - "materials": ["racket", "balls"] - }, headers={ - "user_from_authorizer": { - "displayName": 'Lebron James', - "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - } - }) + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) - response = controller(request) + request = HttpRequest(body= { + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": 1, + "sport": 1, + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "materials": ["racket", "balls"] + }) - assert response.body == "Field sport isn't in the right type.\n Received: int.\n Expected: str" - assert response.status_code == 400 + response = controller(request) + + assert response.body == "Field sport isn't in the right type.\n Received: int.\n Expected: str" + assert response.status_code == 400 + + def test_create_booking_controller_missing_user_id(self): + + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) + + request = HttpRequest(body= { + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": 1, + "sport": "Tennis", + "materials": ["racket", "balls"] + }) + + response = controller(request) + + assert response.body == "Field user_id is missing" + assert response.status_code == 400 + + def test_create_booking_controller_wrong_type_user_id(self): + + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) + + request = HttpRequest(body= { + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": 1, + "sport": "Tennis", + "user_id": 1, + "materials": ["racket", "balls"] + }) + + response = controller(request) + + assert response.body == "Field user_id isn't in the right type.\n Received: int.\n Expected: str" + assert response.status_code == 400 def test_create_booking_controller_missing_materials(self): - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - request = HttpRequest(body={ - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": 1, - "sport": "Tennis", - }, headers={ - "user_from_authorizer": { - "displayName": 'Lebron James', - "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - } - }) + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) - response = controller(request) + request = HttpRequest(body= { + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": 1, + "sport": "Tennis", + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + }) - assert response.body == "Field materials is missing" - assert response.status_code == 400 + response = controller(request) + + assert response.body == "Field materials is missing" + assert response.status_code == 400 def test_create_booking_controller_wrong_type_materials(self): - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - request = HttpRequest(body={ - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": 1, - "sport": "Tennis", - "materials": "racket" - }, headers={ - "user_from_authorizer": { - "displayName": 'Lebron James', - "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - } - }) + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) - response = controller(request) + request = HttpRequest(body= { + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": 1, + "sport": "Tennis", + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "materials": "racket" + }) - assert response.body == "Field materials isn't in the right type.\n Received: str.\n Expected: list" - assert response.status_code == 400 + response = controller(request) + + assert response.body == "Field materials isn't in the right type.\n Received: str.\n Expected: list" + assert response.status_code == 400 def test_create_booking_controller_wrong_type_inside_list(self): + repo = BookingRepositoryMock() usecase = CreateBookingUsecase(repo) controller = CreateBookingController(usecase) - request = HttpRequest(body={ + request = HttpRequest(body= { "start_date": 1630000000, "end_date": 1630003600, "court_number": 1, "sport": "Tennis", + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', "materials": ["racket", 1] - }, headers={ - "user_from_authorizer": { - "displayName": 'Lebron James', - "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - } }) response = controller(request) assert response.body == "Invalid material type" assert response.status_code == 400 + diff --git a/tests/modules/create_booking/app/test_create_booking_presenter.py b/tests/modules/create_booking/app/test_create_booking_presenter.py index 0a6ea41..8bce079 100644 --- a/tests/modules/create_booking/app/test_create_booking_presenter.py +++ b/tests/modules/create_booking/app/test_create_booking_presenter.py @@ -28,11 +28,6 @@ def test_create_booking_presenter(self): "apiId": "", "authentication": None, "authorizer": { - "user": { - "displayName": 'Lebron James', - "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -49,7 +44,7 @@ def test_create_booking_presenter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": '{"start_date": 1610617200, "end_date": 1610620800, "court_number": 1, "sport": "Tennis", "materials": ["ball", "racket"]}', + "body": '{"start_date": 1610617200, "end_date": 1610620800, "court_number": 1, "sport": "Tennis", "user_id": "123e4567-e89b-12d3-a456-426614174000", "materials": ["ball", "racket"]}', "pathParameters": None, "isBase64Encoded": None, "stageVariables": None diff --git a/tests/modules/delete_booking/app/test_delete_booking_controller.py b/tests/modules/delete_booking/app/test_delete_booking_controller.py index 226724f..399c28e 100644 --- a/tests/modules/delete_booking/app/test_delete_booking_controller.py +++ b/tests/modules/delete_booking/app/test_delete_booking_controller.py @@ -3,20 +3,13 @@ from src.shared.helpers.external_interfaces.http_models import HttpRequest from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock - class TestDeleteBookingController: def test_delete_booking_controller(self): repo = BookingRepositoryMock() - usecase = DeleteBookingUsecase(repo=repo) + usecase = DeleteBookingUsecase(repo= repo) controller = DeleteBookingController(usecase=usecase) - request = HttpRequest(body={ + request = HttpRequest(body= { "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' - }, headers={ - 'user_from_authorizer': { - 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'displayName': 'John Doe', - 'mail': 'JD@maua.br' - } }) response = controller(request) @@ -25,16 +18,10 @@ def test_delete_booking_controller(self): def test_delete_booking_controller_missing_booking_id(self): repo = BookingRepositoryMock() - usecase = DeleteBookingUsecase(repo=repo) + usecase = DeleteBookingUsecase(repo= repo) controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body={ "booking_id": None - }, headers={ - 'user_from_authorizer': { - 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'displayName': 'John Doe', - 'mail': 'JD@maua.br' - } }) response = controller(request) @@ -43,18 +30,12 @@ def test_delete_booking_controller_missing_booking_id(self): def test_delete_booking_controller_booking_id_entity_error(self): repo = BookingRepositoryMock() - usecase = DeleteBookingUsecase(repo=repo) + usecase = DeleteBookingUsecase(repo= repo) controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body={ "booking_id": 0 - }, headers={ - 'user_from_authorizer': { - 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'displayName': 'John Doe', - 'mail': 'JD@maua.br' - } }) - + reponse = controller(request) assert reponse.status_code == 400 assert reponse.body == "Field booking_id is not valid" @@ -64,13 +45,7 @@ def test_delete_booking_controller_wrong_type_parameter(self): usecase = DeleteBookingUsecase(repo=repo) controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body={ - "booking_id": "not an id" - }, headers={ - 'user_from_authorizer': { - 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'displayName': 'John Doe', - 'mail': 'JD@maua.br' - } + "booking_id": "wrong_type" }) response = controller(request) @@ -83,31 +58,8 @@ def test_delete_booking_controller_not_found(self): controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body={ "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2926' - }, headers={ - 'user_from_authorizer': { - 'id': 'c8435c66-23a4-4641-9d54-773b4b8ccc99', - 'displayName': 'John Doe', - 'mail': 'JD@maua.br' - } }) response = controller(request) assert response.status_code == 404 - assert response.body == "No items found for booking" - - def test_delete_bookings_controller_forbidden(self): - repo = BookingRepositoryMock() - usecase = DeleteBookingUsecase(repo=repo) - controller = DeleteBookingController(usecase=usecase) - request = HttpRequest(body={ - "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' - }, headers={ - 'user_from_authorizer': { - 'id': 'c8435c66-23a4-4641-9d54-773b4b8ccc99', - 'displayName': 'John Doe', - 'mail': 'JD@maua.br' - } - }) - response = controller(request) - - assert response.status_code == 403 + assert response.body == "No items found for booking" \ No newline at end of file diff --git a/tests/modules/delete_booking/app/test_delete_booking_presenter.py b/tests/modules/delete_booking/app/test_delete_booking_presenter.py index c81563e..60812bd 100644 --- a/tests/modules/delete_booking/app/test_delete_booking_presenter.py +++ b/tests/modules/delete_booking/app/test_delete_booking_presenter.py @@ -25,11 +25,6 @@ def test_delete_booking_presenter(self): "apiId": "", "authentication": None, "authorizer": { - 'user': { - 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'displayName': 'John Doe', - 'mail': 'JD@maua.br' - } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -79,11 +74,6 @@ def test_delete_booking_presenter_missing_booking_id(self): "apiId": "", "authentication": None, "authorizer": { - 'user': { - 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'displayName': 'John Doe', - 'mail': 'JD@maua.br' - } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -133,11 +123,6 @@ def test_delete_booking_not_found(self): "apiId": "", "authentication": None, "authorizer": { - 'user': { - 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'displayName': 'John Doe', - 'mail': 'JD@maua.br' - } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -187,11 +172,6 @@ def test_delete_booking_wrong_type(self): "apiId": "", "authentication": None, "authorizer": { - 'user': { - 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'displayName': 'John Doe', - 'mail': 'JD@maua.br' - } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", diff --git a/tests/modules/delete_booking/app/test_delete_booking_usecase.py b/tests/modules/delete_booking/app/test_delete_booking_usecase.py index 7fc7a34..43d5d0d 100644 --- a/tests/modules/delete_booking/app/test_delete_booking_usecase.py +++ b/tests/modules/delete_booking/app/test_delete_booking_usecase.py @@ -1,8 +1,13 @@ import pytest +from typing import Any, Optional +from src.shared.domain.entities.booking import Booking +from src.shared.domain.enums.status_enum import STATUS +from src.shared.helpers.errors.usecase_errors import DuplicatedItem from src.shared.helpers.errors.domain_errors import EntityError from src.modules.delete_booking.app.delete_booking_usecase import DeleteBookingUsecase from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.domain.repositories.booking_repository_interface import IBookingRepository class Test_DeleteBookingUsecase: def test_delete_booking_usecase(self): @@ -10,25 +15,21 @@ def test_delete_booking_usecase(self): usecase = DeleteBookingUsecase(repo=repo) len_before = len(repo.bookings) - booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', - user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98') + booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925') assert len(repo.bookings) == len_before - 1 def test_delete_booking_usecase_no_items_found(self): repo = BookingRepositoryMock() usecase = DeleteBookingUsecase(repo=repo) with pytest.raises(NoItemsFound): - booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2926', - user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98') + booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2926') def test_delete_booking_usecase_invalid_booking_id(self): repo = BookingRepositoryMock() usecase = DeleteBookingUsecase(repo=repo) with pytest.raises(EntityError): - usecase(booking_id=-1, - user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98') + usecase(booking_id=-1) with pytest.raises(EntityError): - usecase(booking_id=None, - user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98') \ No newline at end of file + usecase(booking_id=None) \ No newline at end of file diff --git a/tests/modules/delete_booking/app/test_delete_booking_viewmodel.py b/tests/modules/delete_booking/app/test_delete_booking_viewmodel.py index 0250ce6..171cf26 100644 --- a/tests/modules/delete_booking/app/test_delete_booking_viewmodel.py +++ b/tests/modules/delete_booking/app/test_delete_booking_viewmodel.py @@ -8,8 +8,7 @@ class Test_DeleteBookingViewModel: def test_delete_booking_viewmodel(self): repo = BookingRepositoryMock() usecase = DeleteBookingUsecase(repo=repo) - booking = usecase(booking_id=repo.bookings[0].booking_id, - user_id=repo.bookings[0].user_id) + booking = usecase(booking_id=repo.bookings[0].booking_id) viewmodel = DeleteBookingViewModel(booking=booking).to_dict() expected = { diff --git a/tests/modules/get_all_bookings/app/test_get_all_bookings_controller.py b/tests/modules/get_all_bookings/app/test_get_all_bookings_controller.py index d51e0d0..5fed98e 100644 --- a/tests/modules/get_all_bookings/app/test_get_all_bookings_controller.py +++ b/tests/modules/get_all_bookings/app/test_get_all_bookings_controller.py @@ -1,8 +1,8 @@ -from src.modules.get_all_bookings.app.get_all_bookings_usecase import GetAllBookingsUsecase +from src.modules.get_all_bookings.app.get_all_booking_usecase import GetAllBookingsUsecase from src.shared.helpers.external_interfaces.http_models import HttpRequest from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock from src.shared.domain.entities.booking import Booking -from src.modules.get_all_bookings.app.get_all_bookings_controller import GetAllBookingsController +from src.modules.get_all_bookings.app.get_all_booking_controller import GetAllBookingsController class Test_GetAllBookingsController: def test_get_all_bookings_controller(self): diff --git a/tests/modules/get_all_bookings/app/test_get_all_bookings_presenter.py b/tests/modules/get_all_bookings/app/test_get_all_bookings_presenter.py index ef2d463..41298e8 100644 --- a/tests/modules/get_all_bookings/app/test_get_all_bookings_presenter.py +++ b/tests/modules/get_all_bookings/app/test_get_all_bookings_presenter.py @@ -1,5 +1,5 @@ import json -from src.modules.get_all_bookings.app.get_all_bookings_presenter import lambda_handler +from src.modules.get_all_bookings.app.get_all_booking_presenter import lambda_handler class TestGetAllBookingsPresenter: def test_lambda_handler(self): diff --git a/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py b/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py index 17b0a56..ff93fab 100644 --- a/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py +++ b/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py @@ -1,4 +1,4 @@ -from src.modules.get_all_bookings.app.get_all_bookings_usecase import GetAllBookingsUsecase +from src.modules.get_all_bookings.app.get_all_booking_usecase import GetAllBookingsUsecase from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock from src.shared.domain.enums.sport import SPORT from src.shared.domain.entities.booking import Booking diff --git a/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py b/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py index a4ca114..958341a 100644 --- a/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py +++ b/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py @@ -1,5 +1,5 @@ -from src.modules.get_all_bookings.app.get_all_bookings_usecase import GetAllBookingsUsecase -from src.modules.get_all_bookings.app.get_all_bookings_viewmodel import GetAllBookingViewModel +from src.modules.get_all_bookings.app.get_all_booking_usecase import GetAllBookingsUsecase +from src.modules.get_all_bookings.app.get_all_booking_viewmodel import GetAllBookingViewModel from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock from src.shared.domain.entities.booking import Booking diff --git a/tests/modules/get_booking/app/test_get_booking_controller.py b/tests/modules/get_booking/app/test_get_booking_controller.py index 4874a60..d8339ca 100644 --- a/tests/modules/get_booking/app/test_get_booking_controller.py +++ b/tests/modules/get_booking/app/test_get_booking_controller.py @@ -32,6 +32,7 @@ def test_get_booking_controller_missing_booking_id(self): assert response.status_code == 400 assert response.body == 'Field booking_id is missing' + def test_get_booking_controller_wrong_type_booking_id(self): repo = BookingRepositoryMock() @@ -59,3 +60,8 @@ def test_get_booking_controller_booking_not_found(self): response = controller(request) assert response.status_code == 404 assert response.body == 'No items found for booking_id' + + + + + \ No newline at end of file diff --git a/tests/modules/get_booking/app/test_get_booking_presenter.py b/tests/modules/get_booking/app/test_get_booking_presenter.py index b60adfc..0533efd 100644 --- a/tests/modules/get_booking/app/test_get_booking_presenter.py +++ b/tests/modules/get_booking/app/test_get_booking_presenter.py @@ -107,7 +107,7 @@ def test_get_booking_presenter_missing_parameters(self): response = lambda_handler(event, None) assert response['statusCode'] == 400 - assert json.loads(response['body']) == "Field booking_id is missing" + assert json.loads(response['body']) == 'Field booking_id is missing' def test_get_booking_presenter_entity_error(self): event = { diff --git a/tests/modules/get_bookings/__init__.py b/tests/modules/get_bookings/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/modules/get_bookings/app/__init__.py b/tests/modules/get_bookings/app/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/modules/get_bookings/app/test_get_bookings_controller.py b/tests/modules/get_bookings/app/test_get_bookings_controller.py deleted file mode 100644 index c32de5b..0000000 --- a/tests/modules/get_bookings/app/test_get_bookings_controller.py +++ /dev/null @@ -1,218 +0,0 @@ -import pytest - -from src.modules.get_bookings.app.get_bookings_controller import GetBookingsController -from src.modules.get_bookings.app.get_bookings_usecase import GetBookingsUseCase -from src.shared.helpers.errors.usecase_errors import DependantFilter -from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock -from src.shared.helpers.external_interfaces.http_models import HttpRequest - -class TestGetBookingsController: - def setup_method(self): - repo = BookingRepositoryMock() - usecase = GetBookingsUseCase(repo=repo) - self.controller = GetBookingsController(usecase=usecase) - - def test_get_bookings_controller(self): - repo = BookingRepositoryMock() - usecase = GetBookingsUseCase(repo=repo) - controller = GetBookingsController(usecase=usecase) - request = HttpRequest(query_params={ - 'booking_id': 'b2d3bebf-dc0d-4fc1-861c-506a40cc2925', - 'user_id': "c8435c66-13a4-4641-9d54-773b4b8ccc98" - }) - response = controller(request) - - assert response.status_code == 200 - assert response.body['bookings'][0]['booking_id'] == 'b2d3bebf-dc0d-4fc1-861c-506a40cc2925' - assert response.body['bookings'][0]['start_date'] == 1634563800000 - assert response.body['bookings'][0]['end_date'] == 1634567400000 - assert response.body['bookings'][0]['court_number'] == 2 - assert response.body['bookings'][0]['sport'] == 'Football' - assert response.body['bookings'][0]['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - assert response.body['bookings'][0]['materials'] == ['Bola', 'Chuteira'] - - def test_get_bookings_controller_empty_query(self): - repo = BookingRepositoryMock() - usecase = GetBookingsUseCase(repo=repo) - controller = GetBookingsController(usecase=usecase) - request = HttpRequest(query_params={ - }) - response = controller(request) - - assert response.status_code == 400 - assert response.body == 'Empty query parameters: At least one of the filters must be provided: booking_id, user_id, sport, court_number, end_date, start_date' - - def test_get_bookings_controller_wrong_type_booking_id(self): - repo = BookingRepositoryMock() - usecase = GetBookingsUseCase(repo=repo) - controller = GetBookingsController(usecase=usecase) - request = HttpRequest(query_params={ - 'booking_id': '123', - }) - response = controller(request) - - assert response.status_code == 400 - assert "Field booking_id is not valid" in response.body - - def test_get_bookings_controller_booking_not_found(self): - repo = BookingRepositoryMock() - usecase = GetBookingsUseCase(repo=repo) - controller = GetBookingsController(usecase=usecase) - request = HttpRequest(query_params={ - 'booking_id': 'b2d3bebf-dc0d-4fc1-861c-506a40cc2943', - }) - - response = controller(request) - assert response.status_code == 404 - assert response.body == 'No items found for booking filters passed' - - def test_get_bookings_controller_sport(self): - repo = BookingRepositoryMock() - usecase = GetBookingsUseCase(repo=repo) - controller = GetBookingsController(usecase=usecase) - request = HttpRequest(query_params={ - 'sport': 'Tennis', - }) - response = controller(request) - - assert response.status_code == 200 - - for booking in response.body['bookings']: - assert booking['sport'] == 'Tennis' - - def test_get_bookings_controller_court_number(self): - repo = BookingRepositoryMock() - usecase = GetBookingsUseCase(repo=repo) - controller = GetBookingsController(usecase=usecase) - request = HttpRequest(query_params={ - 'court_number': '1', - }) - response = controller(request) - - assert response.status_code == 200 - - for booking in response.body['bookings']: - assert booking['court_number'] == 1 - - def test_get_bookings_controller_user_id(self): - repo = BookingRepositoryMock() - usecase = GetBookingsUseCase(repo=repo) - controller = GetBookingsController(usecase=usecase) - request = HttpRequest(query_params={ - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - }) - response = controller(request) - - assert response.status_code == 200 - - for booking in response.body['bookings']: - assert booking['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - - def test_get_bookings_controller_start_date_error(self): - - repo = BookingRepositoryMock() - usecase = GetBookingsUseCase(repo=repo) - controller = GetBookingsController(usecase=usecase) - request = HttpRequest(query_params={ - 'start_date': '1634563800000', - }) - response = controller(request) - - assert response.status_code == 400 - assert response.body == "Filters have to be provided together: start_date and end_date" - - def test_get_bookings_controller_end_date_error(self): - repo = BookingRepositoryMock() - usecase = GetBookingsUseCase(repo=repo) - controller = GetBookingsController(usecase=usecase) - request = HttpRequest(query_params={ - 'end_date': '1634567400000', - }) - response = controller(request) - - assert response.status_code == 400 - assert response.body == "Filters have to be provided together: start_date and end_date" - - def test_get_bookings_controller_start_date_end_date(self): - repo = BookingRepositoryMock() - usecase = GetBookingsUseCase(repo=repo) - controller = GetBookingsController(usecase=usecase) - request = HttpRequest(query_params={ - 'start_date': '1634563800000', - 'end_date': '16345674000000', - }) - response = controller(request) - - assert response.status_code == 200 - - for booking in response.body['bookings']: - assert booking['start_date'] >= 1634563800000 - assert booking['end_date'] <= 16345674000000 - - def test_get_bookings_controller_five_filters(self): - # booking_id + user_id + sport + court_number + date_range - start = '1634583600000' - end = '1634585400000' - request = HttpRequest(query_params={ - 'booking_id': 'b6d3bebf-dc0d-4fc1-861c-506a40cc2925', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'sport': 'Futsal', - 'court_number': 5, - 'start_date': start, - 'end_date': end - }) - response = self.controller(request) - assert response.status_code == 200 - bookings = response.body['bookings'] - assert len(bookings) == 1 - b = bookings[0] - assert b['booking_id'] == 'b6d3bebf-dc0d-4fc1-861c-506a40cc2925' - assert b['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - assert b['sport'] == 'Futsal' - assert b['court_number'] == 5 - assert b['start_date'] >= int(start) and b['end_date'] <= int(end) - - def test_get_bookings_controller_four_filters(self): - # user_id + sport + court_number + date_range - start = '1634574600000' - end = '1634578200000' - request = HttpRequest(query_params={ - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'sport': 'Volleyball', - 'court_number': 4, - 'start_date': start, - 'end_date': end - }) - response = self.controller(request) - assert response.status_code == 200 - bookings = response.body['bookings'] - assert len(bookings) == 1 - b = bookings[0] - assert b['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - assert b['sport'] == 'Volleyball' - assert b['court_number'] == 4 - assert b['start_date'] >= int(start) and b['end_date'] <= int(end) - - def test_get_bookings_controller_three_filters(self): - # sport + court_number + user_id - request = HttpRequest(query_params={ - 'sport': 'Rugby', - 'court_number': 5, - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - }) - response = self.controller(request) - assert response.status_code == 200 - bookings = response.body['bookings'] - assert len(bookings) == 1 - b = bookings[0] - assert b['sport'] == 'Rugby' - assert b['court_number'] == 5 - assert b['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - - def test_get_bookings_user_id_not_valid(self): - request = HttpRequest(query_params={ - 'user_id': '1' - }) - response = self.controller(request) - assert response.status_code == 400 - diff --git a/tests/modules/get_bookings/app/test_get_bookings_presenter.py b/tests/modules/get_bookings/app/test_get_bookings_presenter.py deleted file mode 100644 index d150375..0000000 --- a/tests/modules/get_bookings/app/test_get_bookings_presenter.py +++ /dev/null @@ -1,297 +0,0 @@ -import json -from src.modules.get_bookings.app.get_bookings_presenter import lambda_handler -from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock - -class Test_GetBookingPresenter: - - def test_get_bookings_presenter(self): - event = { - "version": "2.0", - "routeKey": "$default", - "rawPath": "/my/path", - "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", - "cookies": [ - "cookie1", - "cookie2" - ], - "headers": { - "header1": "value1", - "header2": "value1,value2" - }, - "queryStringParameters": { - "booking_id": "b1d3bebf-dc0d-4fc1-861c-506a40cc2925", - "user_id": "", - "sport": "", - "court_number": "", - "end_date": "", - "start_date": "" - }, - "requestContext": { - "accountId": "123456789012", - "apiId": "", - "authentication": None, - "authorizer": { - "user": { - "id": "c8435c66-13a4-4641-9d54-773b4b8ccc98", - "displayName": "User", - "mail": "lbj@maua.br" - } - }, - "domainName": ".lambda-url.us-west-2.on.aws", - "domainPrefix": "", - "external_interfaces": { - "method": "POST", - "path": "/my/path", - "protocol": "HTTP/1.1", - "sourceIp": "123.123.123.123", - "userAgent": "agent" - }, - "requestId": "id", - "routeKey": "$default", - "stage": "$default", - "time": "12/Mar/2020:19:03:58 +0000", - "timeEpoch": 1583348638390 - }, - "body": {}, - "pathParameters": None, - "isBase64Encoded": None, - "stageVariables": None - } - - - response = lambda_handler(event, None) - assert response['statusCode'] == 200 - assert json.loads(response['body'])['message'] == 'the bookings were retrieved' - assert json.loads(response['body'])['bookings'][0]['booking_id'] == 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' - assert json.loads(response['body'])['bookings'][0]['start_date'] == 1634576165000 - assert json.loads(response['body'])['bookings'][0]['end_date'] == 1634583365000 - assert json.loads(response['body'])['bookings'][0]['court_number'] == 1 - assert json.loads(response['body'])['bookings'][0]['sport'] == 'Tennis' - assert json.loads(response['body'])['bookings'][0]['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - assert json.loads(response['body'])['bookings'][0]['materials'] == ['Raquete', 'Bola', 'Rede', 'Tenis'] - - - def test_get_bookings_presenter_missing_parameters(self): - event = { - "version": "2.0", - "routeKey": "$default", - "rawPath": "/my/path", - "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", - "cookies": [ - "cookie1", - "cookie2" - ], - "headers": { - "header1": "value1", - "header2": "value1,value2" - }, - "queryStringParameters": { - "parameter1": "1" - }, - "requestContext": { - "accountId": "123456789012", - "apiId": "", - "authentication": None, - "authorizer": { - "user": { - "id": "c8435c66-13a4-4641-9d54-773b4b8ccc98", - "displayName": "User", - "mail": "lbj@maua.br" - } - }, - "domainName": ".lambda-url.us-west-2.on.aws", - "domainPrefix": "", - "external_interfaces": { - "method": "POST", - "path": "/my/path", - "protocol": "HTTP/1.1", - "sourceIp": "123.123.123.123", - "userAgent": "agent" - }, - "requestId": "id", - "routeKey": "$default", - "stage": "$default", - "time": "12/Mar/2020:19:03:58 +0000", - "timeEpoch": 1583348638390 - }, - "body": {}, - "pathParameters": None, - "isBase64Encoded": None, - "stageVariables": None - } - - response = lambda_handler(event, None) - assert response['statusCode'] == 400 - assert json.loads(response['body']) == 'Empty query parameters: At least one of the filters must be provided: booking_id, user_id, sport, court_number, end_date, start_date' - - def test_get_bookings_presenter_entity_error(self): - event = { - "version": "2.0", - "routeKey": "$default", - "rawPath": "/my/path", - "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", - "cookies": [ - "cookie1", - "cookie2" - ], - "headers": { - "header1": "value1", - "header2": "value1,value2" - }, - "queryStringParameters": { - "booking_id":'teste' - }, - "requestContext": { - "accountId": "123456789012", - "apiId": "", - "authentication": None, - "authorizer": { - "user": { - "id": "c8435c66-13a4-4641-9d54-773b4b8ccc98", - "displayName": "User", - "mail": "lbj@maua.br" - } - }, - "domainName": ".lambda-url.us-west-2.on.aws", - "domainPrefix": "", - "external_interfaces": { - "method": "POST", - "path": "/my/path", - "protocol": "HTTP/1.1", - "sourceIp": "123.123.123.123", - "userAgent": "agent" - }, - "requestId": "id", - "routeKey": "$default", - "stage": "$default", - "time": "12/Mar/2020:19:03:58 +0000", - "timeEpoch": 1583348638390 - }, - "body": {}, - "pathParameters": None, - "isBase64Encoded": None, - "stageVariables": None - } - - response = lambda_handler(event, None) - - assert response['statusCode'] == 400 - assert json.loads(response['body']) == 'Field booking_id is not valid' - - - def test_get_bookings_presenter_wrong_type_parameter(self): - event = { - "version": "2.0", - "routeKey": "$default", - "rawPath": "/my/path", - "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", - "cookies": [ - "cookie1", - "cookie2" - ], - "headers": { - "header1": "value1", - "header2": "value1,value2" - }, - "queryStringParameters": { - "booking_id": '10' - }, - "requestContext": { - "accountId": "123456789012", - "apiId": "", - "authentication": None, - "authorizer": { - "user": { - "id": "c8435c66-13a4-4641-9d54-773b4b8ccc98", - "displayName": "User", - "mail": "lbj@maua.br" - } - }, - "domainName": ".lambda-url.us-west-2.on.aws", - "domainPrefix": "", - "external_interfaces": { - "method": "POST", - "path": "/my/path", - "protocol": "HTTP/1.1", - "sourceIp": "123.123.123.123", - "userAgent": "agent" - }, - "requestId": "id", - "routeKey": "$default", - "stage": "$default", - "time": "12/Mar/2020:19:03:58 +0000", - "timeEpoch": 1583348638390 - }, - "body": {}, - "pathParameters": None, - "isBase64Encoded": None, - "stageVariables": None - } - - response = lambda_handler(event, None) - - assert response['statusCode'] == 400 - assert json.loads(response['body']) == 'Field booking_id is not valid' - - - def test_get_bookings_presenter_entity_not_found(self): - event = { - "version": "2.0", - "routeKey": "$default", - "rawPath": "/my/path", - "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", - "cookies": [ - "cookie1", - "cookie2" - ], - "headers": { - "header1": "value1", - "header2": "value1,value2" - }, - "queryStringParameters": { - "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2989' - }, - "requestContext": { - "accountId": "123456789012", - "apiId": "", - "authentication": None, - "authorizer": { - "user": { - "id": "c8435c66-13a4-4641-9d54-773b4b8ccc98", - "displayName": "User", - "mail": "lbj@maua.br" - } - }, - "domainName": ".lambda-url.us-west-2.on.aws", - "domainPrefix": "", - "external_interfaces": { - "method": "POST", - "path": "/my/path", - "protocol": "HTTP/1.1", - "sourceIp": "123.123.123.123", - "userAgent": "agent" - }, - "requestId": "id", - "routeKey": "$default", - "stage": "$default", - "time": "12/Mar/2020:19:03:58 +0000", - "timeEpoch": 1583348638390 - }, - "body": {}, - "pathParameters": None, - "isBase64Encoded": None, - "stageVariables": None - } - - response = lambda_handler(event, None) - - assert response['statusCode'] == 404 - assert json.loads(response['body']) == 'No items found for booking filters passed' - - - - - - - - diff --git a/tests/modules/get_bookings/app/test_get_bookings_usecase.py b/tests/modules/get_bookings/app/test_get_bookings_usecase.py deleted file mode 100644 index de767b0..0000000 --- a/tests/modules/get_bookings/app/test_get_bookings_usecase.py +++ /dev/null @@ -1,26 +0,0 @@ -import pytest - -from src.modules.get_bookings.app.get_bookings_usecase import GetBookingsUseCase -from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock -from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.errors.usecase_errors import NoItemsFound - -class TestGetBookingsUseCase: - def test_get_bookings_usecase(self): - repo = BookingRepositoryMock() - usecase = GetBookingsUseCase(repo=repo) - booking = repo.bookings[0].booking_id - response = usecase(booking) - assert response[0] == repo.bookings[0] - - def test_get_bookings_usecase_invalid_id(self): - with pytest.raises(EntityError): - repo = BookingRepositoryMock() - usecase = GetBookingsUseCase(repo = repo) - usecase('invalid_id') - - def test_get_bookings_usecase_no_items_found(self): - with pytest.raises(NoItemsFound): - repo = BookingRepositoryMock() - usecase = GetBookingsUseCase(repo = repo) - usecase('b3d3b3b3-dc0d-4fc1-861c-506a40cc2925') \ No newline at end of file diff --git a/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py b/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py deleted file mode 100644 index 27bcd57..0000000 --- a/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py +++ /dev/null @@ -1,26 +0,0 @@ -from src.modules.get_bookings.app.get_bookings_viewmodel import GetBookingsViewmodel -from src.modules.get_bookings.app.get_bookings_usecase import GetBookingsUseCase -from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock - -class Test_GetBookingsViewModel: - def test_get_bookings_viewmodel(self): - repo = BookingRepositoryMock() - usecase = GetBookingsUseCase(repo) - booking = usecase(booking_id=repo.bookings[0].booking_id) - - viewmodel = GetBookingsViewmodel(bookings=booking).to_dict() - - expected = { - 'bookings': [{ - 'start_date': 1634576165000, - 'end_date': 1634583365000, - 'court_number': 1, - 'sport': 'Tennis', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', - 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] - }], - 'message': 'the bookings were retrieved' - } - - assert viewmodel == expected \ No newline at end of file diff --git a/tests/modules/update_booking/app/test_update_booking_controller.py b/tests/modules/update_booking/app/test_update_booking_controller.py index 02f02d2..f006a91 100644 --- a/tests/modules/update_booking/app/test_update_booking_controller.py +++ b/tests/modules/update_booking/app/test_update_booking_controller.py @@ -1,5 +1,4 @@ import pytest -import uuid from src.modules.update_booking.app.update_booking_controller import UpdateBookingController from src.modules.update_booking.app.update_booking_usecase import UpdateBookingUsecase @@ -9,256 +8,245 @@ class Test_UpdateBookingController: def test_update_booking_controller(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) - response = controller(request) + response = controller(request) - assert response.status_code == 200 - assert response.body['message'] == "the booking was retrieved" + assert response.status_code == 200 + assert response.body['message'] == "the booking was retrieved" def test_update_booking_controller_booking_id_missing(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) + + request = HttpRequest(body={ + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) + + response = controller(request) + + assert response.status_code == 400 + assert response.body == "Field booking_id is missing" + + def test_update_booking_controller_start_date_missing(self): + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) + + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) + + response = controller(request) + + assert response.status_code == 400 + assert response.body == "Field start_date is missing" + + def test_update_controller_end_date_missing(self): + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) + + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) + + response = controller(request) + + assert response.status_code == 400 + assert response.body == "Field end_date is missing" + + def test_update_controller_court_number_missing(self): + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) + + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) + + response = controller(request) + + assert response.status_code == 400 + assert response.body == "Field court_number is missing" + + def test_update_controller_sport_missing(self): + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) + + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) + + response = controller(request) + + assert response.status_code == 400 + assert response.body == "Field sport is missing" + + def test_update_controller_materials_missing(self): + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) - request = HttpRequest(body={ - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis" + }) - response = controller(request) + response = controller(request) - assert response.status_code == 400 - assert response.body == "Field booking_id is missing" + assert response.status_code == 400 + assert response.body == "Field materials is missing" def test_update_booking_controller_booking_id_wrong_type(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) - request = HttpRequest(body={ - "booking_id": 123, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) + request = HttpRequest(body={ + "booking_id": 123, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) - response = controller(request) + response = controller(request) - assert response.status_code == 400 - assert "booking_id" in response.body - assert "str" in response.body + assert response.status_code == 400 + assert response.body == "Field booking_id is not valid" def test_update_booking_controller_start_date_wrong_type(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": "123", - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": "123", + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) - response = controller(request) + response = controller(request) - assert response.status_code == 400 - assert "start_date" in response.body - assert "int" in response.body + assert response.status_code == 400 + assert response.body == "Field date is not valid" def test_update_booking_controller_end_date_wrong_type(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": "123", - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": "123", + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) - response = controller(request) + response = controller(request) - assert response.status_code == 400 - assert "end_date" in response.body - assert "int" in response.body + assert response.status_code == 400 + assert response.body == "Field date is not valid" def test_update_booking_controller_court_number_wrong_type(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": "1", - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": "1", + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) - response = controller(request) + response = controller(request) - assert response.status_code == 400 - assert "court_number" in response.body - assert "int" in response.body + assert response.status_code == 400 + assert response.body == "Field court_number is not valid" def test_update_booking_controller_sport_wrong_type(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": 123, - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": 123, + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) - response = controller(request) + response = controller(request) - assert response.status_code == 400 - assert "sport" in response.body - assert "str" in response.body + assert response.status_code == 400 + assert response.body == "Field sport is not valid" def test_update_booking_controller_materials_wrong_type(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) - - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": "Raquete, Bola, Rede, Tenis" - }) - - response = controller(request) - - assert response.status_code == 400 - assert "materials" in response.body - assert "list" in response.body - - def test_update_booking_controller_only_booking_id(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) - - original_booking = booking_repo.bookings[0] - booking_id = original_booking.booking_id - - request = HttpRequest(body={ - "booking_id": booking_id - }) - - response = controller(request) - - assert response.status_code == 200 - assert response.body['booking']['booking_id'] == booking_id - - def test_update_booking_controller_user_id_ignored(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) - - original_booking = booking_repo.bookings[0] - original_user_id = original_booking.user_id - new_user_id = "novo-user-id-que-nao-deve-ser-usado" - - request = HttpRequest(body={ - "booking_id": original_booking.booking_id, - "start_date": original_booking.start_date, - "end_date": original_booking.end_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'], - "user_id": new_user_id - }) - - response = controller(request) - - assert response.status_code == 200 - assert response.body['booking']['user_id'] == original_user_id - assert response.body['booking']['user_id'] != new_user_id - - def test_update_booking_controller_booking_not_found(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) - - non_existent_booking_id = str(uuid.uuid4()) - - original_get_booking = booking_repo.get_booking - - def get_booking_mock(booking_id): - if booking_id == non_existent_booking_id: - return None - return original_get_booking(booking_id) - - booking_repo.get_booking = get_booking_mock - - request = HttpRequest(body={ - "booking_id": non_existent_booking_id, - "start_date": 1634576165000, - "end_date": 1634583365000, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) - - response = controller(request) - booking_repo.get_booking = original_get_booking - - assert response.status_code == 404 - assert "not found" in response.body.lower() - - - def test_update_booking_controller_partial_update(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) controller = UpdateBookingController(update_booking_use_case=usecase) - - original_booking = booking_repo.bookings[0] - booking_id = original_booking.booking_id - original_court_number = original_booking.court_number - new_court_number = original_court_number + 1 - + request = HttpRequest(body={ - "booking_id": booking_id, - "court_number": new_court_number + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": "Raquete, Bola, Rede, Tenis" }) - + response = controller(request) - - assert response.status_code == 200 - assert response.body['booking']['court_number'] == new_court_number - assert response.body['booking']['start_date'] == original_booking.start_date - assert response.body['booking']['end_date'] == original_booking.end_date - assert response.body['booking']['sport'] == original_booking.sport.value - assert response.body['booking']['materials'] == original_booking.materials \ No newline at end of file + + assert response.status_code == 400 + assert response.body == "Field materials is not valid" + + + diff --git a/tests/modules/update_booking/app/test_update_booking_usecase.py b/tests/modules/update_booking/app/test_update_booking_usecase.py index 2b6a3d4..acfe9dd 100644 --- a/tests/modules/update_booking/app/test_update_booking_usecase.py +++ b/tests/modules/update_booking/app/test_update_booking_usecase.py @@ -97,56 +97,41 @@ def test_update_booking_usecase_none_booking_id(self): def test_update_booking_usecase_none_court_number(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) - - original_booking = booking_repo.bookings[0] - original_court_number = original_booking.court_number - - booking = usecase( - booking_id=original_booking.booking_id, - court_number=None, - start_date=1634576165000, - end_date=1634583365000, - sport=SPORT.TENNIS, - materials=['Raquete', 'Bola', 'Rede', 'Tenis'] - ) - - assert booking.court_number == original_court_number + + with pytest.raises(EntityError): + booking = usecase(booking_id=booking_repo.bookings[0].booking_id, + court_number=None, + start_date=1634576165000, + end_date=1634583365000, + sport=SPORT.TENNIS, + materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + ) def test_update_booking_usecase_none_start_date(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) - - original_booking = booking_repo.bookings[0] - original_start_date = original_booking.start_date - - booking = usecase( - booking_id=original_booking.booking_id, - court_number=2, - start_date=None, - end_date=1634583365000, - sport=SPORT.TENNIS, - materials=['Raquete', 'Bola', 'Rede', 'Tenis'] - ) - - assert booking.start_date == original_start_date + + with pytest.raises(EntityError): + booking = usecase(booking_id=booking_repo.bookings[0].booking_id, + court_number=2, + start_date=None, + end_date=1634583365000, + sport=SPORT.TENNIS, + materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + ) def test_update_booking_usecase_none_end_date(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) - - original_booking = booking_repo.bookings[0] - original_end_date = original_booking.end_date - - booking = usecase( - booking_id=original_booking.booking_id, - court_number=2, - start_date=1634576165000, - end_date=None, - sport=SPORT.TENNIS, - materials=['Raquete', 'Bola', 'Rede', 'Tenis'] - ) - - assert booking.end_date == original_end_date + + with pytest.raises(EntityError): + booking = usecase(booking_id=booking_repo.bookings[0].booking_id, + court_number=2, + start_date=1634576165000, + end_date=None, + sport=SPORT.TENNIS, + materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + ) def test_update_booking_usecase_order_dates_incorrect(self): booking_repo = BookingRepositoryMock() @@ -164,55 +149,25 @@ def test_update_booking_usecase_order_dates_incorrect(self): def test_update_booking_usecase_none_sport(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) - - original_booking = booking_repo.bookings[0] - original_sport = original_booking.sport - - booking = usecase( - booking_id=original_booking.booking_id, - court_number=2, - start_date=1634576165000, - end_date=1634583365000, - sport=None, - materials=['Raquete', 'Bola', 'Rede', 'Tenis'] - ) - - assert booking.sport == original_sport - def test_update_booking_usecase_none_materials(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - - original_booking = booking_repo.bookings[0] - original_materials = original_booking.materials - - booking = usecase( - booking_id=original_booking.booking_id, - court_number=2, - start_date=1634576165000, - end_date=1634583365000, - sport=SPORT.TENNIS, - materials=None - ) - - assert booking.materials == original_materials + with pytest.raises(EntityError): + booking = usecase(booking_id=booking_repo.bookings[0].booking_id, + court_number=2, + start_date=1634576165000, + end_date=1634583365000, + sport=None, + materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + ) - def test_update_booking_usecase_cannot_update_user_id(self): + def test_update_booking_usecase_none_materials(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) - original_booking = booking_repo.bookings[0] - booking_id = original_booking.booking_id - original_user_id = original_booking.user_id - - booking = usecase( - booking_id=booking_id, - court_number=2, - start_date=1634576165000, - end_date=1634583365000, - sport=SPORT.TENNIS, - materials=['Raquete', 'Bola', 'Rede', 'Tenis'], - user_id="novo-user-id-que-nao-deve-ser-usado" - ) - - assert booking.user_id == original_user_id \ No newline at end of file + with pytest.raises(EntityError): + booking = usecase(booking_id=booking_repo.bookings[0].booking_id, + court_number=2, + start_date=1634576165000, + end_date=1634583365000, + sport=SPORT.TENNIS, + materials=None + ) \ No newline at end of file diff --git a/tests/shared/infra/repositories/test_booking_repository_dynamo.py b/tests/shared/infra/repositories/test_booking_repository_dynamo.py index 59c0241..f9b4ece 100644 --- a/tests/shared/infra/repositories/test_booking_repository_dynamo.py +++ b/tests/shared/infra/repositories/test_booking_repository_dynamo.py @@ -12,26 +12,7 @@ def test_dynamo_get_all_bookings(self): mock_repo = BookingRepositoryMock() dynamo_bookings = dynamo_repo.get_all_bookings() mock_bookings = mock_repo.get_all_bookings() - assert len(dynamo_bookings) == len(mock_bookings) - - - @pytest.mark.skip("Can't run test in github actions") - def test_dynamo_get_booking(self): - dynamo_repo = BookingRepositoryDynamo() - resp= dynamo_repo.get_booking('b1d3bebf-dc0d-4fc1-861c-506a40cc2925') - assert resp.booking_id == 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' - - - @pytest.mark.skip("Can't run test in github actions") - def test_dynamo_get_bookings_sport(self): - dynamo_repo = BookingRepositoryDynamo() - mock_repo = BookingRepositoryMock() - - dynamo_bookings = dynamo_repo.get_bookings(sport=SPORT.TENNIS.value) - mock_bookings = mock_repo.get_bookings(sport=SPORT.TENNIS.value) - - assert len(dynamo_bookings) == len(mock_bookings) - + assert len(dynamo_bookings) == len(mock_bookings) + 1 for d_booking, m_booking in zip(dynamo_bookings, mock_bookings): assert d_booking.start_date == m_booking.start_date assert d_booking.end_date == m_booking.end_date @@ -41,194 +22,29 @@ def test_dynamo_get_bookings_sport(self): assert d_booking.booking_id == m_booking.booking_id assert d_booking.materials == m_booking.materials - @pytest.mark.skip("Can't run test in github actions") - def test_get_bookings_by_user_id(self): - dynamo_repo = BookingRepositoryDynamo() - mock_repo = BookingRepositoryMock() - - all_mock_bookings = mock_repo.get_all_bookings() - test_user_id = all_mock_bookings[0].user_id - - dynamo_bookings = dynamo_repo.get_bookings(user_id=test_user_id) - mock_bookings = mock_repo.get_bookings(user_id=test_user_id) - - assert len(dynamo_bookings) == len(mock_bookings) - - for booking in dynamo_bookings: - assert booking.user_id == test_user_id - - - @pytest.mark.skip("Can't run test in github actions") - def test_get_bookings_by_court_number(self): - dynamo_repo = BookingRepositoryDynamo() - mock_repo = BookingRepositoryMock() - - for court_number in [1, 2, 3]: - dynamo_bookings = dynamo_repo.get_bookings(court_number=court_number) - mock_bookings = mock_repo.get_bookings(court_number=court_number) - - assert len(dynamo_bookings) == len(mock_bookings) - - for booking in dynamo_bookings: - assert booking.court_number == court_number - - - @pytest.mark.skip("Can't run test in github actions") - def test_get_bookings_by_booking_id(self): - dynamo_repo = BookingRepositoryDynamo() - mock_repo = BookingRepositoryMock() - - test_booking_id = 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' - - dynamo_bookings = dynamo_repo.get_bookings(booking_id=test_booking_id) - mock_bookings = mock_repo.get_bookings(booking_id=test_booking_id) - - assert len(dynamo_bookings) == len(mock_bookings) - assert len(dynamo_bookings) == 1 - assert dynamo_bookings[0].booking_id == test_booking_id - - - @pytest.mark.skip("Can't run test in github actions") - def test_get_bookings_by_sport_and_court(self): - dynamo_repo = BookingRepositoryDynamo() - mock_repo = BookingRepositoryMock() - - test_combinations = [ - (SPORT.TENNIS, 1), - (SPORT.FOOTBALL, 2), - (SPORT.BASKETBALL, 3) - ] - - for sport, court_number in test_combinations: - dynamo_bookings = dynamo_repo.get_bookings(sport=sport.value, court_number=court_number) - mock_bookings = mock_repo.get_bookings(sport=sport.value, court_number=court_number) - - assert len(dynamo_bookings) == len(mock_bookings) - - for booking in dynamo_bookings: - assert booking.sport == sport - assert booking.court_number == court_number - - - @pytest.mark.skip("Can't run test in github actions") - def test_get_bookings_by_sport_and_user(self): - dynamo_repo = BookingRepositoryDynamo() - mock_repo = BookingRepositoryMock() - - all_mock_bookings = mock_repo.get_all_bookings() - test_user_id = all_mock_bookings[0].user_id - - for sport in SPORT: - dynamo_bookings = dynamo_repo.get_bookings(sport=sport.value, user_id=test_user_id) - mock_bookings = mock_repo.get_bookings(sport=sport.value, user_id=test_user_id) - - assert len(dynamo_bookings) == len(mock_bookings) - - for booking in dynamo_bookings: - assert booking.sport == sport - assert booking.user_id == test_user_id - - - @pytest.mark.skip("Can't run test in github actions") - def test_get_bookings_by_user_and_court(self): + def test_dynamo_delete_booking(self): dynamo_repo = BookingRepositoryDynamo() mock_repo = BookingRepositoryMock() - - all_mock_bookings = mock_repo.get_all_bookings() - test_user_id = all_mock_bookings[0].user_id - - for court_number in [1, 2, 3]: - dynamo_bookings = dynamo_repo.get_bookings(user_id=test_user_id, court_number=court_number) - mock_bookings = mock_repo.get_bookings(user_id=test_user_id, court_number=court_number) - - assert len(dynamo_bookings) == len(mock_bookings) - - for booking in dynamo_bookings: - assert booking.user_id == test_user_id - assert booking.court_number == court_number + booking = mock_repo.get_booking('b5d3bebf-dc0d-4fc1-861c-506a40cc2925') + deleted_booking = dynamo_repo.delete_booking(booking.booking_id) + retrieved_booking = dynamo_repo.get_booking(booking.booking_id) + assert retrieved_booking is None + assert deleted_booking.booking_id == booking.booking_id - @pytest.mark.skip("Can't run test in github actions") - def test_get_bookings_by_three_filters(self): + def test_dynamo_delete_booking_not_found(self): dynamo_repo = BookingRepositoryDynamo() - mock_repo = BookingRepositoryMock() - - all_mock_bookings = mock_repo.get_all_bookings() - test_user_id = all_mock_bookings[0].user_id - - test_combinations = [ - (SPORT.TENNIS, 1, test_user_id), - (SPORT.FOOTBALL, 2, test_user_id) - ] - - for sport, court_number, user_id in test_combinations: - dynamo_bookings = dynamo_repo.get_bookings( - sport=sport.value, - court_number=court_number, - user_id=user_id - ) - mock_bookings = mock_repo.get_bookings( - sport=sport.value, - court_number=court_number, - user_id=user_id - ) - - assert len(dynamo_bookings) == len(mock_bookings) - - for booking in dynamo_bookings: - assert booking.sport == sport - assert booking.court_number == court_number - assert booking.user_id == user_id - + deleted_booking = dynamo_repo.delete_booking('bau3bebf-dc0d-4fc1-861c-506a40cc2997') + assert deleted_booking is None @pytest.mark.skip("Can't run test in github actions") - def test_get_bookings_by_date_range(self): + def test_dynamo_get_booking(self): dynamo_repo = BookingRepositoryDynamo() - mock_repo = BookingRepositoryMock() - - start_date = 1634400000000 - end_date = 1634700000000 - - dynamo_bookings = dynamo_repo.get_bookings(start_date=start_date, end_date=end_date) - mock_bookings = mock_repo.get_bookings(start_date=start_date, end_date=end_date) - - assert len(dynamo_bookings) == len(mock_bookings) - - for booking in dynamo_bookings: - assert booking.start_date >= start_date - assert booking.end_date <= end_date - + resp= dynamo_repo.get_booking('b1d3bebf-dc0d-4fc1-861c-506a40cc2925') + assert resp.booking_id == 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' @pytest.mark.skip("Can't run test in github actions") - def test_get_bookings_by_sport_and_date_range(self): - dynamo_repo = BookingRepositoryDynamo() - mock_repo = BookingRepositoryMock() - - start_date = 1634400000000 - end_date = 1634700000000 - - for sport in SPORT: - dynamo_bookings = dynamo_repo.get_bookings( - sport=sport.value, - start_date=start_date, - end_date=end_date - ) - mock_bookings = mock_repo.get_bookings( - sport=sport.value, - start_date=start_date, - end_date=end_date - ) - - assert len(dynamo_bookings) == len(mock_bookings) - - for booking in dynamo_bookings: - assert booking.sport == sport - assert booking.start_date >= start_date - assert booking.end_date <= end_date - - - @pytest.mark.skip("Can't run test in github actions") def test_dynamo_update_booking(self): dynamo_repo = BookingRepositoryDynamo() booking_id = 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' @@ -236,7 +52,7 @@ def test_dynamo_update_booking(self): booking_id=booking_id, start_date=1234567890, court_number=2, - sport=SPORT.BASKETBALL + sport=SPORT.TENNIS.value ) @@ -244,9 +60,8 @@ def test_dynamo_update_booking(self): assert updated_booking.booking_id == booking_id assert updated_booking.start_date == 1234567890 assert updated_booking.court_number == 2 - assert updated_booking.sport == SPORT.BASKETBALL + assert updated_booking.sport == SPORT.TENNIS - @pytest.mark.skip("Can't run test in github actions") def test_dynamo_create_booking(self): dynamo_repo = BookingRepositoryDynamo() @@ -278,26 +93,4 @@ def test_dynamo_create_booking(self): assert retrieved_booking.sport == new_booking.sport assert retrieved_booking.user_id == new_booking.user_id assert retrieved_booking.booking_id == new_booking.booking_id - assert retrieved_booking.materials == new_booking.materials - - dynamo_repo.delete_booking(new_booking.booking_id) - - - @pytest.mark.skip("Can't run test in github actions") - def test_dynamo_delete_booking(self): - dynamo_repo = BookingRepositoryDynamo() - mock_repo = BookingRepositoryMock() - booking = mock_repo.get_booking('b5d3bebf-dc0d-4fc1-861c-506a40cc2925') - deleted_booking = dynamo_repo.delete_booking(booking.booking_id) - retrieved_booking = dynamo_repo.get_booking(booking.booking_id) - assert retrieved_booking is None - assert deleted_booking.booking_id == booking.booking_id - - - @pytest.mark.skip("Can't run test in github actions") - def test_dynamo_delete_booking_not_found(self): - dynamo_repo = BookingRepositoryDynamo() - deleted_booking = dynamo_repo.delete_booking('bau3bebf-dc0d-4fc1-861c-506a40cc2997') - assert deleted_booking is None - - + assert retrieved_booking.materials == new_booking.materials \ No newline at end of file From f4f37d14470dab656ad0df7fa2995c1c1f8f3643 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 23 May 2025 14:23:23 -0300 Subject: [PATCH 028/167] Revert "Merge branch 'dev' into user-on-generate-report" This reverts commit 36a0ce1bba1aa2a6c0b88a79f3e01c8f1780c232, reversing changes made to 6cf72d26eb32830d9514065488d8a8de789e88dd. --- iac/stacks/lambda_stack.py | 6 +- .../app/create_booking_controller.py | 9 +++ .../app/create_booking_usecase.py | 12 +--- .../app/get_all_courts_controller.py | 1 - .../app/get_all_courts_usecase.py | 2 + .../get_court/app/get_court_controller.py | 23 ++++---- .../reservation_repository_dynamo.py | 3 +- .../app/test_create_booking_controller.py | 55 +++++++++++++++++++ .../app/test_create_booking_presenter.py | 2 +- .../app/test_create_booking_usecase.py | 15 ++--- .../__init__.py | 0 .../app/__init__.py | 0 .../app/test_delete_booking_controller.py | 0 .../app/test_delete_booking_presenter.py | 0 .../app/test_delete_booking_usecase.py | 0 .../app/test_delete_booking_viewmodel.py | 0 tests/modules/get_all_courts/__init__.py | 0 tests/modules/get_all_courts/app/__init__.py | 0 .../__init__.py | 0 .../app/__init__.py | 0 .../app/test_get_all_courts_controller.py | 0 .../app/test_get_all_courts_presenter.py | 2 +- .../app/test_get_all_courts_usecase.py | 0 .../app/test_get_all_courts_viewmodel.py | 0 .../app/test_get_booking_controller.py | 32 +++++++++-- .../app/test_get_booking_presenter.py | 16 +++--- .../app/test_get_court_controller.py | 14 +++-- .../get_court/app/test_get_court_presenter.py | 16 +++--- .../test_booking_repository_dynamo.py | 9 ++- .../test_reservation_repository_dynamo.py | 7 +-- 30 files changed, 154 insertions(+), 70 deletions(-) rename tests/modules/{delete_booking => delete_bookings}/__init__.py (100%) rename tests/modules/{delete_booking => delete_bookings}/app/__init__.py (100%) rename tests/modules/{delete_booking => delete_bookings}/app/test_delete_booking_controller.py (100%) rename tests/modules/{delete_booking => delete_bookings}/app/test_delete_booking_presenter.py (100%) rename tests/modules/{delete_booking => delete_bookings}/app/test_delete_booking_usecase.py (100%) rename tests/modules/{delete_booking => delete_bookings}/app/test_delete_booking_viewmodel.py (100%) delete mode 100644 tests/modules/get_all_courts/__init__.py delete mode 100644 tests/modules/get_all_courts/app/__init__.py rename tests/modules/{delete_court => get_all_courts_usecase}/__init__.py (100%) rename tests/modules/{delete_court => get_all_courts_usecase}/app/__init__.py (100%) rename tests/modules/{get_all_courts => get_all_courts_usecase}/app/test_get_all_courts_controller.py (100%) rename tests/modules/{get_all_courts => get_all_courts_usecase}/app/test_get_all_courts_presenter.py (95%) rename tests/modules/{get_all_courts => get_all_courts_usecase}/app/test_get_all_courts_usecase.py (100%) rename tests/modules/{get_all_courts => get_all_courts_usecase}/app/test_get_all_courts_viewmodel.py (100%) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index 062889c..fb3463e 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -95,7 +95,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment self.get_booking = self.create_lambda_api_gateway_integration( module_name="get_booking", - method="GET", + method="POST", api_resource=api_gateway_resource, environment_variables=environment_variables ) @@ -123,7 +123,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment self.get_court = self.create_lambda_api_gateway_integration( module_name="get_court", - method="GET", + method="POST", api_resource=api_gateway_resource, environment_variables=environment_variables ) @@ -158,7 +158,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment self.generate_report = self.create_lambda_event_bridge_integration( module_name="generate_report", - cron_schedule=Schedule.cron(minute="0", hour="18", week_day="FRI"), + cron_schedule=Schedule.cron(week_day="FRI", hour="18"), environment_variables=environment_variables ) diff --git a/src/modules/create_booking/app/create_booking_controller.py b/src/modules/create_booking/app/create_booking_controller.py index 8efb383..c6850d1 100644 --- a/src/modules/create_booking/app/create_booking_controller.py +++ b/src/modules/create_booking/app/create_booking_controller.py @@ -19,6 +19,7 @@ def __call__(self, request: IRequest): court_number = request.data.get('court_number', None) sport = request.data.get('sport', None) user_id = request.data.get('user_id', None) + booking_id = request.data.get('booking_id', None) materials = request.data.get('materials', None) try: @@ -58,6 +59,13 @@ def __call__(self, request: IRequest): fieldTypeExpected='str', fieldTypeReceived=type(user_id).__name__) + if booking_id is None: + raise MissingParameters('booking_id') + if not isinstance(booking_id, str): + raise WrongTypeParameter(fieldName='booking_id', + fieldTypeExpected='str', + fieldTypeReceived=type(booking_id).__name__) + if materials is None: raise MissingParameters('materials') if not isinstance(materials, list): @@ -71,6 +79,7 @@ def __call__(self, request: IRequest): court_number=court_number, sport=sport, user_id=user_id, + booking_id=booking_id, materials=materials ) diff --git a/src/modules/create_booking/app/create_booking_usecase.py b/src/modules/create_booking/app/create_booking_usecase.py index 6a0636e..eb68ea0 100644 --- a/src/modules/create_booking/app/create_booking_usecase.py +++ b/src/modules/create_booking/app/create_booking_usecase.py @@ -1,4 +1,3 @@ -import uuid from typing import List from src.shared.domain.entities.booking import Booking @@ -25,11 +24,10 @@ def __call__(self, court_number: int, sport: str, user_id: str, + booking_id: str, materials: List[str] ) -> Booking: - booking_id = str(uuid.uuid4()) - if self.repo.get_booking(booking_id): raise DuplicatedItem("Booking already exists") @@ -42,13 +40,7 @@ def __call__(self, if not isinstance(material, str): raise ValueError("Invalid material type") - resp = self.repo.create_booking(Booking(start_date, - end_date, - court_number, - self.sport, - user_id, - booking_id, - materials)) + resp = self.repo.create_booking(Booking(start_date, end_date, court_number, self.sport, user_id, booking_id, materials)) return resp diff --git a/src/modules/get_all_courts/app/get_all_courts_controller.py b/src/modules/get_all_courts/app/get_all_courts_controller.py index ef80113..afeda0f 100644 --- a/src/modules/get_all_courts/app/get_all_courts_controller.py +++ b/src/modules/get_all_courts/app/get_all_courts_controller.py @@ -17,7 +17,6 @@ def __call__(self, request: IRequest): courts = self.usecase() viewmodel = GetAllCourtsViewModel(courts).to_dict() return OK(viewmodel) - except EntityError as err: return BadRequest(body=err.message) diff --git a/src/modules/get_all_courts/app/get_all_courts_usecase.py b/src/modules/get_all_courts/app/get_all_courts_usecase.py index 85f5943..4814e43 100644 --- a/src/modules/get_all_courts/app/get_all_courts_usecase.py +++ b/src/modules/get_all_courts/app/get_all_courts_usecase.py @@ -1,4 +1,6 @@ +from typing import Any from src.shared.domain.repositories.reservation_repository_interface import IReservationRepository +from src.shared.domain.entities.court import Court class GetAllCourtsUsecase: def __init__(self, repo: IReservationRepository): diff --git a/src/modules/get_court/app/get_court_controller.py b/src/modules/get_court/app/get_court_controller.py index 35427bd..ad2e675 100644 --- a/src/modules/get_court/app/get_court_controller.py +++ b/src/modules/get_court/app/get_court_controller.py @@ -15,21 +15,18 @@ def __call__(self, request: IRequest): try: if request.data.get('number') is None: raise MissingParameters('number') - + number = request.data.get('number') if number is not None: - - try: - number = int(number) - - except ValueError: + if type(number) is not int: raise WrongTypeParameter('number', 'int', type(number).__name__) - court = self.usecase( - number=number - ) - court_viewmodel = GetCourtViewmodel(court=court) + + court = self.usecase( + number= request.data.get('number') + ) + court_viewmodel = GetCourtViewmodel(court= court) return OK(court_viewmodel.to_dict()) @@ -48,3 +45,9 @@ def __call__(self, request: IRequest): except Exception as err: return InternalServerError(body=err.args[0]) + + + + + + diff --git a/src/shared/infra/repositories/reservation_repository_dynamo.py b/src/shared/infra/repositories/reservation_repository_dynamo.py index 5a65f38..195d1c8 100644 --- a/src/shared/infra/repositories/reservation_repository_dynamo.py +++ b/src/shared/infra/repositories/reservation_repository_dynamo.py @@ -49,8 +49,7 @@ def get_all_courts(self) -> list[Court]: all_items = self.dynamo.get_all_items().get('Items') for item in all_items: - if item.get("entity") == "Court": - all_courts.append(CourtDynamoDTO.from_dynamo(item).to_entity()) + all_courts.append(CourtDynamoDTO.from_dynamo(item).to_entity()) return all_courts diff --git a/tests/modules/create_booking/app/test_create_booking_controller.py b/tests/modules/create_booking/app/test_create_booking_controller.py index 2c4df9e..6ef738d 100644 --- a/tests/modules/create_booking/app/test_create_booking_controller.py +++ b/tests/modules/create_booking/app/test_create_booking_controller.py @@ -18,6 +18,7 @@ def test_create_booking_controller(self): "court_number": 1, "sport": "Tennis", "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', "materials": ["racket", "balls"] }) @@ -36,6 +37,7 @@ def test_create_booking_controller_missing_start_date(self): "court_number": 1, "sport": "Tennis", "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', "materials": ["racket", "balls"] }) @@ -56,6 +58,7 @@ def test_create_booking_controller_wrong_type_start_date(self): "court_number": 1, "sport": "Tennis", "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', "materials": ["racket", "balls"] }) @@ -75,6 +78,7 @@ def test_create_booking_controller_missing_end_date(self): "court_number": 1, "sport": "Tennis", "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', "materials": ["racket", "balls"] }) @@ -95,6 +99,7 @@ def test_create_booking_controller_wrong_type_end_date(self): "court_number": 1, "sport": "Tennis", "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', "materials": ["racket", "balls"] }) @@ -115,6 +120,7 @@ def test_create_booking_wrong_type_court_number(self): "court_number": "1", "sport": "Tennis", "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', "materials": ["racket", "balls"] }) @@ -134,6 +140,7 @@ def test_create_booking_controller_missing_court_number(self): "end_date": 1630003600, "sport": "Tennis", "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', "materials": ["racket", "balls"] }) @@ -153,6 +160,7 @@ def test_create_booking_controller_missing_sport(self): "end_date": 1630003600, "court_number": 1, "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', "materials": ["racket", "balls"] }) @@ -173,6 +181,7 @@ def test_create_booking_controller_wrong_type_sport(self): "court_number": 1, "sport": 1, "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', "materials": ["racket", "balls"] }) @@ -192,6 +201,7 @@ def test_create_booking_controller_missing_user_id(self): "end_date": 1630003600, "court_number": 1, "sport": "Tennis", + "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', "materials": ["racket", "balls"] }) @@ -212,6 +222,7 @@ def test_create_booking_controller_wrong_type_user_id(self): "court_number": 1, "sport": "Tennis", "user_id": 1, + "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', "materials": ["racket", "balls"] }) @@ -220,6 +231,47 @@ def test_create_booking_controller_wrong_type_user_id(self): assert response.body == "Field user_id isn't in the right type.\n Received: int.\n Expected: str" assert response.status_code == 400 + def test_create_booking_controller_missing_booking_id(self): + + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) + + request = HttpRequest(body= { + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": 1, + "sport": "Tennis", + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "materials": ["racket", "balls"] + }) + + response = controller(request) + + assert response.body == "Field booking_id is missing" + assert response.status_code == 400 + + def test_create_booking_controller_wrong_type_booking_id(self): + + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) + + request = HttpRequest(body= { + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": 1, + "sport": "Tennis", + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "booking_id": 1, + "materials": ["racket", "balls"] + }) + + response = controller(request) + + assert response.body == "Field booking_id isn't in the right type.\n Received: int.\n Expected: str" + assert response.status_code == 400 + def test_create_booking_controller_missing_materials(self): repo = BookingRepositoryMock() @@ -232,6 +284,7 @@ def test_create_booking_controller_missing_materials(self): "court_number": 1, "sport": "Tennis", "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', }) response = controller(request) @@ -251,6 +304,7 @@ def test_create_booking_controller_wrong_type_materials(self): "court_number": 1, "sport": "Tennis", "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', "materials": "racket" }) @@ -271,6 +325,7 @@ def test_create_booking_controller_wrong_type_inside_list(self): "court_number": 1, "sport": "Tennis", "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', "materials": ["racket", 1] }) diff --git a/tests/modules/create_booking/app/test_create_booking_presenter.py b/tests/modules/create_booking/app/test_create_booking_presenter.py index 8bce079..fb5b6bd 100644 --- a/tests/modules/create_booking/app/test_create_booking_presenter.py +++ b/tests/modules/create_booking/app/test_create_booking_presenter.py @@ -44,7 +44,7 @@ def test_create_booking_presenter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": '{"start_date": 1610617200, "end_date": 1610620800, "court_number": 1, "sport": "Tennis", "user_id": "123e4567-e89b-12d3-a456-426614174000", "materials": ["ball", "racket"]}', + "body": '{"start_date": 1610617200, "end_date": 1610620800, "court_number": 1, "sport": "Tennis", "user_id": "123e4567-e89b-12d3-a456-426614174000", "booking_id": "123e4567-e89b-12d3-a456-426614174000", "materials": ["ball", "racket"]}', "pathParameters": None, "isBase64Encoded": None, "stageVariables": None diff --git a/tests/modules/create_booking/app/test_create_booking_usecase.py b/tests/modules/create_booking/app/test_create_booking_usecase.py index 63202b7..231383d 100644 --- a/tests/modules/create_booking/app/test_create_booking_usecase.py +++ b/tests/modules/create_booking/app/test_create_booking_usecase.py @@ -16,8 +16,8 @@ def test_create_booking_usecase(self): court_number=1, sport=SPORT.TENNIS, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', - materials=['Raquete', 'Bola', 'Rede', 'Tenis'], - booking_id='c8435c66-13a4-4641-9d54-773b4b8ccc98' + booking_id='e1d3bebf-dc0d-4fc1-861c-506a40cc2925', + materials=['Raquete', 'Bola', 'Rede', 'Tenis'] ) booking_repository = BookingRepositoryMock() @@ -30,16 +30,11 @@ def test_create_booking_usecase(self): court_number=1, sport="Tennis", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', + booking_id='e1d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Raquete', 'Bola', 'Rede', 'Tenis'] ) - assert response is not None - assert response.start_date == booking.start_date - assert response.end_date == booking.end_date - assert response.court_number == booking.court_number - assert response.sport == booking.sport - assert response.user_id == booking.user_id - assert response.booking_id != booking.booking_id + assert booking == response def test_create_booking_usecase_invalid_sport(self): @@ -55,6 +50,7 @@ def test_create_booking_usecase_invalid_sport(self): court_number=1, sport="Invalid sport but string", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', + booking_id='e1d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Raquete', 'Bola', 'Rede', 'Tenis'] ) @@ -72,6 +68,7 @@ def test_create_booking_usecase_invalid_materials(self): court_number=1, sport="Tennis", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', + booking_id='e1d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=[1, 2, 3] ) diff --git a/tests/modules/delete_booking/__init__.py b/tests/modules/delete_bookings/__init__.py similarity index 100% rename from tests/modules/delete_booking/__init__.py rename to tests/modules/delete_bookings/__init__.py diff --git a/tests/modules/delete_booking/app/__init__.py b/tests/modules/delete_bookings/app/__init__.py similarity index 100% rename from tests/modules/delete_booking/app/__init__.py rename to tests/modules/delete_bookings/app/__init__.py diff --git a/tests/modules/delete_booking/app/test_delete_booking_controller.py b/tests/modules/delete_bookings/app/test_delete_booking_controller.py similarity index 100% rename from tests/modules/delete_booking/app/test_delete_booking_controller.py rename to tests/modules/delete_bookings/app/test_delete_booking_controller.py diff --git a/tests/modules/delete_booking/app/test_delete_booking_presenter.py b/tests/modules/delete_bookings/app/test_delete_booking_presenter.py similarity index 100% rename from tests/modules/delete_booking/app/test_delete_booking_presenter.py rename to tests/modules/delete_bookings/app/test_delete_booking_presenter.py diff --git a/tests/modules/delete_booking/app/test_delete_booking_usecase.py b/tests/modules/delete_bookings/app/test_delete_booking_usecase.py similarity index 100% rename from tests/modules/delete_booking/app/test_delete_booking_usecase.py rename to tests/modules/delete_bookings/app/test_delete_booking_usecase.py diff --git a/tests/modules/delete_booking/app/test_delete_booking_viewmodel.py b/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py similarity index 100% rename from tests/modules/delete_booking/app/test_delete_booking_viewmodel.py rename to tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py diff --git a/tests/modules/get_all_courts/__init__.py b/tests/modules/get_all_courts/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/modules/get_all_courts/app/__init__.py b/tests/modules/get_all_courts/app/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/modules/delete_court/__init__.py b/tests/modules/get_all_courts_usecase/__init__.py similarity index 100% rename from tests/modules/delete_court/__init__.py rename to tests/modules/get_all_courts_usecase/__init__.py diff --git a/tests/modules/delete_court/app/__init__.py b/tests/modules/get_all_courts_usecase/app/__init__.py similarity index 100% rename from tests/modules/delete_court/app/__init__.py rename to tests/modules/get_all_courts_usecase/app/__init__.py diff --git a/tests/modules/get_all_courts/app/test_get_all_courts_controller.py b/tests/modules/get_all_courts_usecase/app/test_get_all_courts_controller.py similarity index 100% rename from tests/modules/get_all_courts/app/test_get_all_courts_controller.py rename to tests/modules/get_all_courts_usecase/app/test_get_all_courts_controller.py diff --git a/tests/modules/get_all_courts/app/test_get_all_courts_presenter.py b/tests/modules/get_all_courts_usecase/app/test_get_all_courts_presenter.py similarity index 95% rename from tests/modules/get_all_courts/app/test_get_all_courts_presenter.py rename to tests/modules/get_all_courts_usecase/app/test_get_all_courts_presenter.py index 2f214f4..61198b0 100644 --- a/tests/modules/get_all_courts/app/test_get_all_courts_presenter.py +++ b/tests/modules/get_all_courts_usecase/app/test_get_all_courts_presenter.py @@ -40,7 +40,7 @@ def test_lambda_handler(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": None, + "body": '{"number": 7, "status": "AVAILABLE", "is_field": false, "photo": "photo"}', "pathParameters": None, "isBase64Encoded": None, "stageVariables": None diff --git a/tests/modules/get_all_courts/app/test_get_all_courts_usecase.py b/tests/modules/get_all_courts_usecase/app/test_get_all_courts_usecase.py similarity index 100% rename from tests/modules/get_all_courts/app/test_get_all_courts_usecase.py rename to tests/modules/get_all_courts_usecase/app/test_get_all_courts_usecase.py diff --git a/tests/modules/get_all_courts/app/test_get_all_courts_viewmodel.py b/tests/modules/get_all_courts_usecase/app/test_get_all_courts_viewmodel.py similarity index 100% rename from tests/modules/get_all_courts/app/test_get_all_courts_viewmodel.py rename to tests/modules/get_all_courts_usecase/app/test_get_all_courts_viewmodel.py diff --git a/tests/modules/get_booking/app/test_get_booking_controller.py b/tests/modules/get_booking/app/test_get_booking_controller.py index d8339ca..3cdfc18 100644 --- a/tests/modules/get_booking/app/test_get_booking_controller.py +++ b/tests/modules/get_booking/app/test_get_booking_controller.py @@ -8,8 +8,14 @@ def test_get_booking_controller(self): repo = BookingRepositoryMock() usecase = GetBookingUseCase(repo=repo) controller = GetBookingController(usecase=usecase) - request = HttpRequest(query_params={ + request = HttpRequest(body={ 'booking_id': 'b2d3bebf-dc0d-4fc1-861c-506a40cc2925', + 'start_date': 1634563800000, + 'end_date': 1634567400000, + 'court_number': 2, + 'sport': 'FOOTBALL', + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + }) response = controller(request) @@ -26,7 +32,13 @@ def test_get_booking_controller_missing_booking_id(self): repo = BookingRepositoryMock() usecase = GetBookingUseCase(repo=repo) controller = GetBookingController(usecase=usecase) - request = HttpRequest(query_params={ + request = HttpRequest(body={ + 'start_date': 1634563800000, + 'end_date': 1634567400000, + 'court_number': 2, + 'sport': 'Football', + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + }) response = controller(request) @@ -38,8 +50,14 @@ def test_get_booking_controller_wrong_type_booking_id(self): repo = BookingRepositoryMock() usecase = GetBookingUseCase(repo=repo) controller = GetBookingController(usecase=usecase) - request = HttpRequest(query_params={ + request = HttpRequest(body={ 'booking_id': 123, + 'start_date': 1634563800000, + 'end_date': 1634567400000, + 'court_number': 2, + 'sport': 'Football', + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + }) response = controller(request) @@ -53,8 +71,14 @@ def test_get_booking_controller_booking_not_found(self): repo = BookingRepositoryMock() usecase = GetBookingUseCase(repo=repo) controller = GetBookingController(usecase=usecase) - request = HttpRequest(query_params={ + request = HttpRequest(body={ 'booking_id': 'b2d3bebf-dc0d-4fc1-861c-506a40cc2943', + 'start_date': 1634563800000, + 'end_date': 1634567400000, + 'court_number': 2, + 'sport': 'Football', + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + }) response = controller(request) diff --git a/tests/modules/get_booking/app/test_get_booking_presenter.py b/tests/modules/get_booking/app/test_get_booking_presenter.py index 0533efd..dcab6cb 100644 --- a/tests/modules/get_booking/app/test_get_booking_presenter.py +++ b/tests/modules/get_booking/app/test_get_booking_presenter.py @@ -19,7 +19,7 @@ def test_get_booking_presenter(self): "header2": "value1,value2" }, "queryStringParameters": { - "booking_id": "b1d3bebf-dc0d-4fc1-861c-506a40cc2925" + "parameter1": "1" }, "requestContext": { "accountId": "123456789012", @@ -42,7 +42,7 @@ def test_get_booking_presenter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {}, + "body": {"booking_id":'b1d3bebf-dc0d-4fc1-861c-506a40cc2925'}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -124,7 +124,7 @@ def test_get_booking_presenter_entity_error(self): "header2": "value1,value2" }, "queryStringParameters": { - "booking_id":'teste' + "parameter1": "1" }, "requestContext": { "accountId": "123456789012", @@ -147,7 +147,7 @@ def test_get_booking_presenter_entity_error(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {}, + "body": {"booking_id":'teste'}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -174,7 +174,7 @@ def test_get_booking_presenter_wrong_type_parameter(self): "header2": "value1,value2" }, "queryStringParameters": { - "booking_id":10 + "parameter1": "1" }, "requestContext": { "accountId": "123456789012", @@ -197,7 +197,7 @@ def test_get_booking_presenter_wrong_type_parameter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {}, + "body": {"booking_id":10}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -224,7 +224,7 @@ def test_get_booking_presenter_entity_not_found(self): "header2": "value1,value2" }, "queryStringParameters": { - "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2989' + "parameter1": "1" }, "requestContext": { "accountId": "123456789012", @@ -247,7 +247,7 @@ def test_get_booking_presenter_entity_not_found(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {}, + "body": {"booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2989'}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None diff --git a/tests/modules/get_court/app/test_get_court_controller.py b/tests/modules/get_court/app/test_get_court_controller.py index f6055a4..5a4a39a 100644 --- a/tests/modules/get_court/app/test_get_court_controller.py +++ b/tests/modules/get_court/app/test_get_court_controller.py @@ -10,7 +10,7 @@ def test_get_court_controller(self): repo = ReservationRepositoryMock() usecase = GetCourtUsecase(repo=repo) controller = GetCourtController(usecase=usecase) - request = HttpRequest(query_params={ + request = HttpRequest(body={ "number": 2 }) @@ -27,7 +27,7 @@ def test_get_court_controller_missing_number(self): repo = ReservationRepositoryMock() usecase = GetCourtUsecase(repo=repo) controller = GetCourtController(usecase=usecase) - request = HttpRequest(query_params={ + request = HttpRequest(body={ "status": "AVAILABLE", "is_field": False, "photo": "https://www.linkedin.com/in/giovanna-albuquerque-16917a245/" @@ -43,8 +43,11 @@ def test_get_court_controller_wrong_type_parameters(self): repo = ReservationRepositoryMock() usecase = GetCourtUsecase(repo=repo) controller = GetCourtController(usecase=usecase) - request = HttpRequest(query_params={ + request = HttpRequest(body={ "number": "cavalo", + "status": "AVAILABLE", + "is_field": False, + "photo": "https://www.linkedin.com/in/giovanna-albuquerque-16917a245/" }) response = controller(request) @@ -58,8 +61,11 @@ def test_get_court_controller_court_not_found(self): repo = ReservationRepositoryMock() usecase = GetCourtUsecase(repo=repo) controller = GetCourtController(usecase=usecase) - request = HttpRequest(query_params={ + request = HttpRequest(body={ "number": 10, + "status": "AVAILABLE", + "is_field": False, + "photo": "https://www.linkedin.com/in/giovanna-albuquerque-16917a245/" }) response = controller(request) diff --git a/tests/modules/get_court/app/test_get_court_presenter.py b/tests/modules/get_court/app/test_get_court_presenter.py index 7f93dfb..46ee487 100644 --- a/tests/modules/get_court/app/test_get_court_presenter.py +++ b/tests/modules/get_court/app/test_get_court_presenter.py @@ -19,7 +19,7 @@ def test_get_court_presenter(self): "header2": "value1,value2" }, "queryStringParameters": { - "number": "1" #tem que passar ja que no querry sempre vem como string + "parameter1": "1" }, "requestContext": { "accountId": "123456789012", @@ -42,7 +42,7 @@ def test_get_court_presenter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {}, + "body": {"number":1}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -117,7 +117,7 @@ def test_get_court_presenter_entity_error(self): "header2": "value1,value2" }, "queryStringParameters": { - "number": 15 + "parameter1": "1" }, "requestContext": { "accountId": "123456789012", @@ -140,7 +140,7 @@ def test_get_court_presenter_entity_error(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {}, + "body": {"number": 15}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -166,7 +166,7 @@ def test_get_court_presenter_wrong_type_parameter(self): "header2": "value1,value2" }, "queryStringParameters": { - "code": "1" + "parameter1": "1" }, "requestContext": { "accountId": "123456789012", @@ -189,7 +189,7 @@ def test_get_court_presenter_wrong_type_parameter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {}, + "body": {"code": "1"}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -216,7 +216,7 @@ def test_get_court_presenter_not_found(self): "header2": "value1,value2" }, "queryStringParameters": { - "number": 8 + "parameter1": "1" }, "requestContext": { "accountId": "123456789012", @@ -239,7 +239,7 @@ def test_get_court_presenter_not_found(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {}, + "body": {"number": 8}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None diff --git a/tests/shared/infra/repositories/test_booking_repository_dynamo.py b/tests/shared/infra/repositories/test_booking_repository_dynamo.py index f9b4ece..17c338d 100644 --- a/tests/shared/infra/repositories/test_booking_repository_dynamo.py +++ b/tests/shared/infra/repositories/test_booking_repository_dynamo.py @@ -5,14 +5,14 @@ from src.shared.domain.entities.booking import Booking class TestBookingRepositoryDynamo: - + @pytest.mark.skip("Can't run test in github actions") def test_dynamo_get_all_bookings(self): dynamo_repo = BookingRepositoryDynamo() mock_repo = BookingRepositoryMock() dynamo_bookings = dynamo_repo.get_all_bookings() mock_bookings = mock_repo.get_all_bookings() - assert len(dynamo_bookings) == len(mock_bookings) + 1 + assert len(dynamo_bookings) == len(mock_bookings) for d_booking, m_booking in zip(dynamo_bookings, mock_bookings): assert d_booking.start_date == m_booking.start_date assert d_booking.end_date == m_booking.end_date @@ -21,8 +21,7 @@ def test_dynamo_get_all_bookings(self): assert d_booking.user_id == m_booking.user_id assert d_booking.booking_id == m_booking.booking_id assert d_booking.materials == m_booking.materials - - @pytest.mark.skip("Can't run test in github actions") + @pytest.mark.skip("Can't run test in github actions") def test_dynamo_delete_booking(self): dynamo_repo = BookingRepositoryDynamo() mock_repo = BookingRepositoryMock() @@ -51,7 +50,7 @@ def test_dynamo_update_booking(self): updated_booking = dynamo_repo.update_booking( booking_id=booking_id, start_date=1234567890, - court_number=2, + court_number=2, sport=SPORT.TENNIS.value ) diff --git a/tests/shared/infra/repositories/test_reservation_repository_dynamo.py b/tests/shared/infra/repositories/test_reservation_repository_dynamo.py index b486e55..fe65af8 100644 --- a/tests/shared/infra/repositories/test_reservation_repository_dynamo.py +++ b/tests/shared/infra/repositories/test_reservation_repository_dynamo.py @@ -10,7 +10,6 @@ class TestReservationRepositoryDynamo: - @pytest.mark.skip("Can't run test in github actions") def test_dynamo_delete_court(self): dynamo_repo = ReservationRepositoryDynamo() @@ -30,7 +29,7 @@ def test_dynamo_delete_court_not_found(self): @pytest.mark.skip("Can't run test in github actions") def test_update_court(self): repo = ReservationRepositoryDynamo() - resp = repo.update_court(number=3, photo="https://www.linkedin.com/in/giovanna-albuquerque-16917a245/") + resp = repo.update_court(number=3, new_photo="https://www.linkedin.com/in/giovanna-albuquerque-16917a245/") assert resp.number == 3 assert resp.photo == "https://www.linkedin.com/in/giovanna-albuquerque-16917a245/" @@ -62,6 +61,6 @@ def test_dynamo_create_court(self): new_court = Court(number=6, status=STATUS.MAINTENANCE, is_field=False, photo=None) size = len(dynamo_repo.get_all_courts()) - assert new_court.__dict__ == dynamo_repo.create_court(new_court).__dict__ - assert dynamo_repo.get_court(6).__dict__ == new_court.__dict__ + assert new_court == dynamo_repo.create_court(new_court) + assert dynamo_repo.get_court(6) == new_court From 6e25e19ee99984422d330124be61302bc0bc321c Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 23 May 2025 14:40:06 -0300 Subject: [PATCH 029/167] fix: trying to resolve merge errors --- .../modules/get_all_users/app/test_get_all_users_controller.py | 2 ++ .../modules/get_all_users/app/test_get_all_users_presenter.py | 3 +++ tests/modules/get_all_users/app/test_get_all_users_usecase.py | 2 ++ .../modules/get_all_users/app/test_get_all_users_viewmodel.py | 2 ++ 4 files changed, 9 insertions(+) diff --git a/tests/modules/get_all_users/app/test_get_all_users_controller.py b/tests/modules/get_all_users/app/test_get_all_users_controller.py index efa4697..bf576c2 100644 --- a/tests/modules/get_all_users/app/test_get_all_users_controller.py +++ b/tests/modules/get_all_users/app/test_get_all_users_controller.py @@ -1,9 +1,11 @@ +import pytest from src.modules.get_all_users.app.get_all_users_usecase import GetAllUsersUseCase from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock from src.modules.get_all_users.app.get_all_users_controller import GetAllUsersController from src.shared.helpers.external_interfaces.http_models import HttpRequest class Test_GetAllUsersController: + @pytest.mark.skip("Can't run test in github actions") def test_get_all_users_controller(self): repo = BookingRepositoryMock() diff --git a/tests/modules/get_all_users/app/test_get_all_users_presenter.py b/tests/modules/get_all_users/app/test_get_all_users_presenter.py index 8aedc74..c6a97d2 100644 --- a/tests/modules/get_all_users/app/test_get_all_users_presenter.py +++ b/tests/modules/get_all_users/app/test_get_all_users_presenter.py @@ -1,10 +1,13 @@ import json + +import pytest from src.modules.get_all_users.app.get_all_users_presenter import lambda_handler from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock repo = BookingRepositoryMock() class Test_GetAllUsersPresenter: + @pytest.mark.skip("Can't run test in github actions") def test_get_all_users_presenter(self): event = { diff --git a/tests/modules/get_all_users/app/test_get_all_users_usecase.py b/tests/modules/get_all_users/app/test_get_all_users_usecase.py index 29d5c59..c1d9be4 100644 --- a/tests/modules/get_all_users/app/test_get_all_users_usecase.py +++ b/tests/modules/get_all_users/app/test_get_all_users_usecase.py @@ -1,7 +1,9 @@ +import pytest from src.modules.get_all_users.app.get_all_users_usecase import GetAllUsersUseCase from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock class Test_GetAllUsersUsecase: + @pytest.mark.skip("Can't run test in github actions") def test_get_all_users_usecase(self): repo = BookingRepositoryMock() diff --git a/tests/modules/get_all_users/app/test_get_all_users_viewmodel.py b/tests/modules/get_all_users/app/test_get_all_users_viewmodel.py index dfdba63..e0ba9ea 100644 --- a/tests/modules/get_all_users/app/test_get_all_users_viewmodel.py +++ b/tests/modules/get_all_users/app/test_get_all_users_viewmodel.py @@ -1,9 +1,11 @@ +import pytest from src.modules.get_all_users.app.get_all_users_usecase import GetAllUsersUseCase from src.modules.get_all_users.app.get_all_users_viewmodel import GetAllUsersViewModel from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock class Test_GetAllUsersViewModel: + @pytest.mark.skip("Can't run test in github actions") def test_get_all_users_viewmodel(self): repo = BookingRepositoryMock() usecase = GetAllUsersUseCase(repo) From f0ceaf889317af58fbb5147a49c5265a65ca8af4 Mon Sep 17 00:00:00 2001 From: lseixas Date: Mon, 7 Jul 2025 18:04:54 -0300 Subject: [PATCH 030/167] added 15 min intolerance in booking sheduling, added comments to code for better understanding, added tests --- .../app/create_booking_usecase.py | 9 ++++- .../booking_repository_interface.py | 5 +++ .../app/test_create_booking_usecase.py | 40 ++++++++++++++++++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/modules/create_booking/app/create_booking_usecase.py b/src/modules/create_booking/app/create_booking_usecase.py index aca8453..0d2bdf7 100644 --- a/src/modules/create_booking/app/create_booking_usecase.py +++ b/src/modules/create_booking/app/create_booking_usecase.py @@ -45,8 +45,13 @@ def __call__(self, all_bookings = self.repo.get_all_bookings() for booking in all_bookings: - if (booking.start_date < end_date and booking.end_date > start_date - and booking.court_number == court_number): + if ( + ( + booking.start_date < end_date + (15 * 60 * 1000) #15 minutes in mseconds + and booking.end_date > start_date - (15 * 60 * 1000) #15 minutes in mseconds + and booking.court_number == court_number + ) + ): raise InvalidSchedule() resp = self.repo.create_booking(Booking(start_date, diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index afb26a5..37ae8e8 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -12,6 +12,9 @@ class IBookingRepository(ABC): def create_booking(self, booking: Booking) -> Optional[Booking]: ''' If booking does not exist, creates it and returns it + + !!!Must do time validations outside this method!!!! + Keep it simples, only appending or putting into repostitory ''' pass @@ -25,6 +28,8 @@ def update_booking(self, materials: List[str] = None) -> Optional[Booking]: ''' If booking exists, updates it and returns it + + !!!Must do time validations outside this method!!!! ''' pass diff --git a/tests/modules/create_booking/app/test_create_booking_usecase.py b/tests/modules/create_booking/app/test_create_booking_usecase.py index 2781dee..948cc39 100644 --- a/tests/modules/create_booking/app/test_create_booking_usecase.py +++ b/tests/modules/create_booking/app/test_create_booking_usecase.py @@ -76,7 +76,7 @@ def test_create_booking_usecase_invalid_materials(self): materials=[1, 2, 3] ) - def test_create_booking_usecase_invalid_schedule(self): + def test_create_booking_usecase_invalid_schedule_overlap(self): with pytest.raises(InvalidSchedule) as e: @@ -92,3 +92,41 @@ def test_create_booking_usecase_invalid_schedule(self): user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=["colete"] ) + + def test_create_booking_usecase_invalid_schedule_15min(self): + + with pytest.raises(InvalidSchedule) as e: + + booking_repository = BookingRepositoryMock() + + usecase = CreateBookingUsecase(repo=booking_repository) + + booking_repository.create_booking( + booking=Booking( + start_date=20000000, + end_date=30000000, + court_number=5, + sport=SPORT.FUTSAL, + user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', + materials=['Bola', 'Chuteira'], + booking_id='ddd35c66-13a4-4641-9d54-773b4b8ccc98' + ) + ) + + response = usecase( + start_date=10000000, + end_date=19100001, #15 minutos de intolerância na criação + court_number=5, + sport=SPORT.FUTSAL, + user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', + materials=['Bola', 'Chuteira'] + ) + + response = usecase( + start_date=30899999, #15 minutos de intolerância na criação + end_date=40000000, + court_number=5, + sport=SPORT.FUTSAL, + user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', + materials=['Bola', 'Chuteira'] + ) From e437a64ad1548e48504e983dafb68f18bf59093b Mon Sep 17 00:00:00 2001 From: lseixas Date: Mon, 7 Jul 2025 18:13:32 -0300 Subject: [PATCH 031/167] added error message validation to tests --- src/shared/helpers/errors/usecase_errors.py | 2 +- .../app/test_create_booking_usecase.py | 26 +++++++++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/shared/helpers/errors/usecase_errors.py b/src/shared/helpers/errors/usecase_errors.py index 75d75b1..5609355 100644 --- a/src/shared/helpers/errors/usecase_errors.py +++ b/src/shared/helpers/errors/usecase_errors.py @@ -18,5 +18,5 @@ def __init__(self, message: str): class InvalidSchedule(BaseError): def __init__(self): - super().__init__('Court is already booked for the selected time slot') + super().__init__('Court is already booked for the selected time slot or has to have 15 min tolerance') diff --git a/tests/modules/create_booking/app/test_create_booking_usecase.py b/tests/modules/create_booking/app/test_create_booking_usecase.py index 948cc39..3d79879 100644 --- a/tests/modules/create_booking/app/test_create_booking_usecase.py +++ b/tests/modules/create_booking/app/test_create_booking_usecase.py @@ -93,6 +93,9 @@ def test_create_booking_usecase_invalid_schedule_overlap(self): materials=["colete"] ) + assert e.value == "Court is already booked for the selected time slot or has to have 15 min tolerance" + + def test_create_booking_usecase_invalid_schedule_15min(self): with pytest.raises(InvalidSchedule) as e: @@ -122,11 +125,18 @@ def test_create_booking_usecase_invalid_schedule_15min(self): materials=['Bola', 'Chuteira'] ) - response = usecase( - start_date=30899999, #15 minutos de intolerância na criação - end_date=40000000, - court_number=5, - sport=SPORT.FUTSAL, - user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', - materials=['Bola', 'Chuteira'] - ) + assert e.value == "Court is already booked for the selected time slot or has to have 15 min tolerance" + + with pytest.raises(InvalidSchedule) as e2: + + + response2 = usecase( + start_date=30899999, # 15 minutos de intolerância na criação + end_date=40000000, + court_number=5, + sport=SPORT.FUTSAL, + user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', + materials=['Bola', 'Chuteira'] + ) + + assert e2.value == "Court is already booked for the selected time slot or has to have 15 min tolerance" From 0c5cbc7e8f456f036aac34dbf662dae8b7aa9f63 Mon Sep 17 00:00:00 2001 From: lseixas Date: Mon, 7 Jul 2025 18:32:56 -0300 Subject: [PATCH 032/167] added 15 min and overlap intolerance to update_booking module, added respective tests --- .../app/update_booking_usecase.py | 19 ++++++++- .../app/test_update_booking_usecase.py | 40 ++++++++++++++++++- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/modules/update_booking/app/update_booking_usecase.py b/src/modules/update_booking/app/update_booking_usecase.py index 5c3e7c4..e039294 100644 --- a/src/modules/update_booking/app/update_booking_usecase.py +++ b/src/modules/update_booking/app/update_booking_usecase.py @@ -1,9 +1,9 @@ -from typing import List, Optional +from typing import List from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT from src.shared.domain.repositories.booking_repository_interface import IBookingRepository from src.shared.helpers.errors.domain_errors import EntityError, EntityParameterOrderDatesError -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.errors.usecase_errors import NoItemsFound, InvalidSchedule class UpdateBookingUsecase: def __init__(self, booking_repo: IBookingRepository): @@ -47,6 +47,21 @@ def __call__(self, if Booking.validate_materials(materials) is False: raise EntityError("materials") + + all_bookings = self.booking_repo.get_all_bookings() + + for booking in all_bookings: + if ( + (booking.booking_id != booking_id) + and ( + ( + booking.start_date < end_date + (15 * 60 * 1000) #15 minutes in mseconds + and booking.end_date > start_date - (15 * 60 * 1000) #15 minutes in mseconds + and booking.court_number == court_number + ) + ) + ): + raise InvalidSchedule() booking = self.booking_repo.update_booking( booking_id=booking_id, diff --git a/tests/modules/update_booking/app/test_update_booking_usecase.py b/tests/modules/update_booking/app/test_update_booking_usecase.py index 2b6a3d4..e47862a 100644 --- a/tests/modules/update_booking/app/test_update_booking_usecase.py +++ b/tests/modules/update_booking/app/test_update_booking_usecase.py @@ -3,7 +3,7 @@ from src.modules.update_booking.app.update_booking_usecase import UpdateBookingUsecase from src.shared.domain.enums.sport import SPORT from src.shared.helpers.errors.domain_errors import EntityError, EntityParameterOrderDatesError, EntityParameterTimeError -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.errors.usecase_errors import InvalidSchedule from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock @@ -29,6 +29,44 @@ def test_update_booking_usecase(self): assert booking_repo.bookings[0].sport == booking.sport assert booking_repo.bookings[0].materials == booking.materials + def test_update_booking_usecase_invalid_schedule_overlap(self): + + with pytest.raises(InvalidSchedule) as e: + + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + + booking_id = booking_repo.bookings[0].booking_id + + booking = usecase(booking_id=booking_id, + court_number=3, + start_date=1634569200000, + end_date=1634570000000, + sport=SPORT.TENNIS, + materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + ) + + assert e.value == "Court is already booked for the selected time slot or has to have 15 min tolerance" + + def test_update_booking_usecase_invalid_schedule_15min_intolerance(self): + + with pytest.raises(InvalidSchedule) as e: + + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + + booking_id = booking_repo.bookings[0].booking_id + + booking = usecase(booking_id=booking_id, + court_number=3, + start_date=1634571899999, + end_date=1734571000000, + sport=SPORT.TENNIS, + materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + ) + + assert e.value == "Court is already booked for the selected time slot or has to have 15 min tolerance" + def test_update_booking_usecase_invalid_booking_id(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) From 167a3e3af7fd7c4e9ba3a0cb447942626e505cf5 Mon Sep 17 00:00:00 2001 From: lseixas Date: Mon, 7 Jul 2025 19:04:28 -0300 Subject: [PATCH 033/167] fixed merge, removed get_all_users as it was unused --- .../app/create_booking_controller.py | 24 +- .../app/create_booking_presenter.py | 1 + .../app/create_booking_usecase.py | 5 +- src/modules/get_all_users/__init__.py | 0 src/modules/get_all_users/app/__init__.py | 0 .../app/get_all_users_controller.py | 28 -- .../app/get_all_users_presenter.py | 16 - .../app/get_all_users_usecase.py | 75 --- .../app/get_all_users_viewmodel.py | 28 -- .../app/update_booking_controller.py | 64 ++- .../app/update_booking_usecase.py | 32 +- .../helpers/errors/controller_errors.py | 10 +- src/shared/helpers/errors/domain_errors.py | 3 +- src/shared/helpers/errors/usecase_errors.py | 5 + .../app/test_create_booking_controller.py | 428 ++++++++---------- .../app/test_create_booking_presenter.py | 7 +- .../app/test_create_booking_usecase.py | 15 +- tests/modules/get_all_users/__init__.py | 0 tests/modules/get_all_users/app/__init__.py | 0 .../app/test_get_all_users_controller.py | 20 - .../app/test_get_all_users_presenter.py | 57 --- .../app/test_get_all_users_usecase.py | 15 - .../app/test_get_all_users_viewmodel.py | 33 -- .../app/test_update_booking_controller.py | 414 +++++++++-------- .../app/test_update_booking_usecase.py | 133 ++++-- 25 files changed, 608 insertions(+), 805 deletions(-) delete mode 100644 src/modules/get_all_users/__init__.py delete mode 100644 src/modules/get_all_users/app/__init__.py delete mode 100644 src/modules/get_all_users/app/get_all_users_controller.py delete mode 100644 src/modules/get_all_users/app/get_all_users_presenter.py delete mode 100644 src/modules/get_all_users/app/get_all_users_usecase.py delete mode 100644 src/modules/get_all_users/app/get_all_users_viewmodel.py delete mode 100644 tests/modules/get_all_users/__init__.py delete mode 100644 tests/modules/get_all_users/app/__init__.py delete mode 100644 tests/modules/get_all_users/app/test_get_all_users_controller.py delete mode 100644 tests/modules/get_all_users/app/test_get_all_users_presenter.py delete mode 100644 tests/modules/get_all_users/app/test_get_all_users_usecase.py delete mode 100644 tests/modules/get_all_users/app/test_get_all_users_viewmodel.py diff --git a/src/modules/create_booking/app/create_booking_controller.py b/src/modules/create_booking/app/create_booking_controller.py index 451a0de..8e737e9 100644 --- a/src/modules/create_booking/app/create_booking_controller.py +++ b/src/modules/create_booking/app/create_booking_controller.py @@ -1,6 +1,8 @@ +import json + from .create_booking_usecase import CreateBookingUsecase from .create_booking_viewmodel import CreateBookingViewmodel -from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter +from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter, AuthorizerError from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.errors.usecase_errors import DuplicatedItem, InvalidSchedule from src.shared.helpers.external_interfaces.external_interface import IRequest @@ -14,12 +16,20 @@ def __init__(self, create_booking_use_case: CreateBookingUsecase): def __call__(self, request: IRequest): + user_from_authorizer = request.data.get('user_from_authorizer', None) + + if not isinstance(request.data.get('user_from_authorizer'), dict): + + user_from_authorizer = json.loads(request.data.get('user_from_authorizer')) + + if user_from_authorizer is None: + raise AuthorizerError() + start_date = request.data.get('start_date', None) end_date = request.data.get('end_date', None) court_number = request.data.get('court_number', None) sport = request.data.get('sport', None) - user_id = request.data.get('user_id', None) - booking_id = request.data.get('booking_id', None) + user_id = user_from_authorizer.get('id', None) materials = request.data.get('materials', None) try: @@ -59,13 +69,6 @@ def __call__(self, request: IRequest): fieldTypeExpected='str', fieldTypeReceived=type(user_id).__name__) - if booking_id is None: - raise MissingParameters('booking_id') - if not isinstance(booking_id, str): - raise WrongTypeParameter(fieldName='booking_id', - fieldTypeExpected='str', - fieldTypeReceived=type(booking_id).__name__) - if materials is None: raise MissingParameters('materials') if not isinstance(materials, list): @@ -79,7 +82,6 @@ def __call__(self, request: IRequest): court_number=court_number, sport=sport, user_id=user_id, - booking_id=booking_id, materials=materials ) diff --git a/src/modules/create_booking/app/create_booking_presenter.py b/src/modules/create_booking/app/create_booking_presenter.py index f2e9100..c67b811 100644 --- a/src/modules/create_booking/app/create_booking_presenter.py +++ b/src/modules/create_booking/app/create_booking_presenter.py @@ -9,6 +9,7 @@ def lambda_handler(event, context): httpRequest = LambdaHttpRequest(data=event) + httpRequest.data['user_from_authorizer'] = event.get('requestContext', {}).get('authorizer', {}).get('user', None) response = controller(request=httpRequest) httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) diff --git a/src/modules/create_booking/app/create_booking_usecase.py b/src/modules/create_booking/app/create_booking_usecase.py index 662c050..0d2bdf7 100644 --- a/src/modules/create_booking/app/create_booking_usecase.py +++ b/src/modules/create_booking/app/create_booking_usecase.py @@ -1,3 +1,4 @@ +import uuid from typing import List from src.shared.domain.entities.booking import Booking @@ -24,10 +25,11 @@ def __call__(self, court_number: int, sport: str, user_id: str, - booking_id: str, materials: List[str] ) -> Booking: + booking_id = str(uuid.uuid4()) + if self.repo.get_booking(booking_id): raise DuplicatedItem("Booking already exists") @@ -40,7 +42,6 @@ def __call__(self, if not isinstance(material, str): raise ValueError("Invalid material type") - all_bookings = self.repo.get_all_bookings() for booking in all_bookings: diff --git a/src/modules/get_all_users/__init__.py b/src/modules/get_all_users/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/modules/get_all_users/app/__init__.py b/src/modules/get_all_users/app/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/modules/get_all_users/app/get_all_users_controller.py b/src/modules/get_all_users/app/get_all_users_controller.py deleted file mode 100644 index a05100a..0000000 --- a/src/modules/get_all_users/app/get_all_users_controller.py +++ /dev/null @@ -1,28 +0,0 @@ -from src.modules.get_all_users.app.get_all_users_usecase import GetAllUsersUseCase -from src.modules.get_all_users.app.get_all_users_viewmodel import GetAllUsersViewModel -from src.shared.helpers.errors.controller_errors import MissingParameters -from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse -from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, InternalServerError - - -class GetAllUsersController: - def __init__(self, usecase: GetAllUsersUseCase): - self.usecase = usecase - - def __call__(self, request: IRequest) -> IResponse: - - try: - users = self.usecase() - viewmodel = GetAllUsersViewModel(users) - - return OK(viewmodel.to_dict()) - - except EntityError as e: - return BadRequest(body=e.message) - - except MissingParameters as err: - return BadRequest(body=err.message) - - except Exception as err: - return InternalServerError(body=str(err)) \ No newline at end of file diff --git a/src/modules/get_all_users/app/get_all_users_presenter.py b/src/modules/get_all_users/app/get_all_users_presenter.py deleted file mode 100644 index 1ef0a42..0000000 --- a/src/modules/get_all_users/app/get_all_users_presenter.py +++ /dev/null @@ -1,16 +0,0 @@ -from src.modules.get_all_users.app.get_all_users_controller import GetAllUsersController -from src.modules.get_all_users.app.get_all_users_usecase import GetAllUsersUseCase -from src.shared.environments import Environments -from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse -from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock - -repo = BookingRepositoryMock() -usecase = GetAllUsersUseCase(repo) -controller = GetAllUsersController(usecase) - -def lambda_handler(event, context): - httpRequest = LambdaHttpRequest(data = event) - response = controller(httpRequest) - httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body) - - return httpResponse.toDict() \ No newline at end of file diff --git a/src/modules/get_all_users/app/get_all_users_usecase.py b/src/modules/get_all_users/app/get_all_users_usecase.py deleted file mode 100644 index 52d1761..0000000 --- a/src/modules/get_all_users/app/get_all_users_usecase.py +++ /dev/null @@ -1,75 +0,0 @@ -from src.shared.domain.repositories.booking_repository_interface import IBookingRepository -from dotenv import load_dotenv -import os -import requests - -load_dotenv() - -class GetAllUsersUseCase: - def __init__(self, repo: IBookingRepository): - self.repo = repo - - def __call__(self): - users_id_by_booking = self.repo.get_all_users() - if not users_id_by_booking: - return "nenhum usuário encontrado" - - users_id_by_booking = list(set(users_id_by_booking)) - - users_data = call_other_microservice() - if not users_data: - print("nenhum dado de usuário foi retornado pelo microserviço.") - - valid_users_data = [ - { - "user_id": user["user_id"], - "name": user["name"] - } - for user in users_data - if isinstance(user, dict) and "user_id" in user and "name" in user - ] - - if len(valid_users_data) != len(users_data): - print("dados invalidos/incompletos foram retornados pelo microserviço.") - - user_id_to_name = {user["user_id"]: user["name"] for user in valid_users_data} - - users_with_names = [ - {"user_id": user_id, "name": user_id_to_name.get(user_id)} - for user_id in users_id_by_booking #verificao se o user_id existe no booking e assim faz a troca - if user_id_to_name.get(user_id) is not None - ] - - users_with_names.sort(key=lambda user: user["name"]) # Ordena os nomes dos usuarios por ordem alfabetica - #feito desta forma pois, o set() não garante a ordem dos elementos - - return users_with_names - -def call_other_microservice(): - - load_dotenv() - - url = os.getenv("GET_ALL_USERS_API_URL") - - payload={} - headers = { - 'User-Agent': os.getenv("GET_ALL_USERS_USER_AGENT"), - 'Authorization': os.getenv("GET_ALL_USERS_AUTHORIZATION_TOKEN"), - 'Accept': '*/*', - 'Host': os.getenv("GET_ALL_USERS_HOST"), - 'Connection': 'keep-alive' - } - - try: - response = requests.get(url, headers=headers, data=payload) - response.raise_for_status() - - data = response.json() - if not isinstance(data, dict) or "users" not in data: - print("Erro: Resposta inesperada do microserviço.") - return [] - - return data.get("users", []) - except Exception as e: - print(f"Erro ao processar a resposta do serviço: {e}") - return [] \ No newline at end of file diff --git a/src/modules/get_all_users/app/get_all_users_viewmodel.py b/src/modules/get_all_users/app/get_all_users_viewmodel.py deleted file mode 100644 index dfa98e5..0000000 --- a/src/modules/get_all_users/app/get_all_users_viewmodel.py +++ /dev/null @@ -1,28 +0,0 @@ -from src.shared.domain.entities.booking import Booking - - -class UserViewModel: - user_id: str - name: str - - def __init__(self, user_id: str, name: str): - self.user_id = user_id - self.name = name - - def to_dict(self): - return { - 'user_id': self.user_id, - 'name': self.name - } - -class GetAllUsersViewModel: - users: list[UserViewModel] - - def __init__(self, users: list[dict]): - self.users = [UserViewModel(user["user_id"], user["name"]) for user in users] - - def to_dict(self): - return { - 'users': [user.to_dict() for user in self.users], - 'message': 'the users were retrieved' - } \ No newline at end of file diff --git a/src/modules/update_booking/app/update_booking_controller.py b/src/modules/update_booking/app/update_booking_controller.py index ae03073..ecdd232 100644 --- a/src/modules/update_booking/app/update_booking_controller.py +++ b/src/modules/update_booking/app/update_booking_controller.py @@ -4,7 +4,8 @@ from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse -from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, InternalServerError +from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, InternalServerError, NotFound +from src.shared.helpers.errors.usecase_errors import NoItemsFound class UpdateBookingController: def __init__(self, update_booking_use_case: UpdateBookingUsecase): @@ -14,33 +15,49 @@ def __call__(self, request: IRequest) -> IResponse: try: if request.data.get('booking_id') is None: raise MissingParameters('booking_id') - - if request.data.get('start_date') is None: - raise MissingParameters('start_date') - if request.data.get('end_date') is None: - raise MissingParameters('end_date') + booking_id = request.data.get('booking_id') + start_date = request.data.get('start_date') + end_date = request.data.get('end_date') + court_number = request.data.get('court_number') + sport_value = request.data.get('sport') + materials = request.data.get('materials') - if request.data.get('court_number') is None: - raise MissingParameters('court_number') - if request.data.get('sport') is None: - raise MissingParameters('sport') - - sport = request.data.get('sport') + if not isinstance(booking_id, str): + raise WrongTypeParameter('booking_id', 'str', type(booking_id).__name__) + + if start_date is not None and not isinstance(start_date, int): + raise WrongTypeParameter('start_date', 'int', type(start_date).__name__) + + if end_date is not None and not isinstance(end_date, int): + raise WrongTypeParameter('end_date', 'int', type(end_date).__name__) - if sport not in [sport_type.value for sport_type in SPORT]: - raise EntityError('sport') + if court_number is not None and not isinstance(court_number, int): + raise WrongTypeParameter('court_number', 'int', type(court_number).__name__) + + sport = None + if sport_value is not None: + if not isinstance(sport_value, str): + raise WrongTypeParameter('sport', 'str', type(sport_value).__name__) + + if sport_value not in [sport_type.value for sport_type in SPORT]: + raise EntityError('sport') + + sport = SPORT(sport_value) + - if request.data.get('materials') is None: - raise MissingParameters('materials') + if materials is not None and not isinstance(materials, list): + raise WrongTypeParameter('materials', 'list', type(materials).__name__) - booking = self.UpdateBookingUsecase(booking_id=request.data.get('booking_id'), - start_date=request.data.get('start_date'), - end_date=request.data.get('end_date'), - court_number=request.data.get('court_number'), - sport=SPORT(sport), - materials=request.data.get('materials')) + booking = self.UpdateBookingUsecase( + booking_id=booking_id, + start_date=start_date, + end_date=end_date, + court_number=court_number, + sport=sport, + materials=materials + ) viewmodel = UpdateBookingViewmodel(booking=booking) @@ -55,5 +72,8 @@ def __call__(self, request: IRequest) -> IResponse: except EntityError as err: return BadRequest(body=err.message) + except NoItemsFound as err: + return NotFound(body=f"Booking not found: {err.message}") + except Exception as err: return InternalServerError(body=err.args[0]) \ No newline at end of file diff --git a/src/modules/update_booking/app/update_booking_usecase.py b/src/modules/update_booking/app/update_booking_usecase.py index 777f0a7..e039294 100644 --- a/src/modules/update_booking/app/update_booking_usecase.py +++ b/src/modules/update_booking/app/update_booking_usecase.py @@ -10,16 +10,29 @@ def __init__(self, booking_repo: IBookingRepository): self.booking_repo = booking_repo def __call__(self, - booking_id: str, - start_date: int, - end_date: int, - court_number: int, - sport: SPORT, - materials: List[str] = None): + booking_id: str, + start_date: int = None, + end_date: int = None, + court_number: int = None, + sport: SPORT = None, + materials: List[str] = None, + user_id: str = None): if Booking.validate_booking_id(booking_id) is False: raise EntityError('booking_id') + existing_booking = self.booking_repo.get_booking(booking_id) + if existing_booking is None: + raise NoItemsFound('booking') + + + start_date = start_date if start_date is not None else existing_booking.start_date + end_date = end_date if end_date is not None else existing_booking.end_date + court_number = court_number if court_number is not None else existing_booking.court_number + sport = sport if sport is not None else existing_booking.sport + materials = materials if materials is not None else existing_booking.materials + + if Booking.validate_dates(start_date, end_date) is False: raise EntityError("date") @@ -28,7 +41,7 @@ def __call__(self, if Booking.validate_court(court_number) is False: raise EntityError("court_number") - + if Booking.validate_sport(sport) is False: raise EntityError("sport") @@ -59,4 +72,7 @@ def __call__(self, materials=materials ) - + if booking.user_id != existing_booking.user_id: + booking.user_id = existing_booking.user_id + + return booking \ No newline at end of file diff --git a/src/shared/helpers/errors/controller_errors.py b/src/shared/helpers/errors/controller_errors.py index c319375..7ea6d12 100644 --- a/src/shared/helpers/errors/controller_errors.py +++ b/src/shared/helpers/errors/controller_errors.py @@ -6,4 +6,12 @@ def __init__(self, message: str): super().__init__(f'Field {message} is missing') class WrongTypeParameter(BaseError): def __init__(self, fieldName: str, fieldTypeExpected: str, fieldTypeReceived: str): - super().__init__(f'Field {fieldName} isn\'t in the right type.\n Received: {fieldTypeReceived}.\n Expected: {fieldTypeExpected}') \ No newline at end of file + super().__init__(f'Field {fieldName} isn\'t in the right type.\n Received: {fieldTypeReceived}.\n Expected: {fieldTypeExpected}') + +class EmptyQueryParameters(BaseError): + def __init__(self, message: str): + super().__init__(f'Empty query parameters: {message}') + +class AuthorizerError(BaseError): + def __init__(self): + super().__init__('User was not returned from authorizer') \ No newline at end of file diff --git a/src/shared/helpers/errors/domain_errors.py b/src/shared/helpers/errors/domain_errors.py index bf54248..6b00235 100644 --- a/src/shared/helpers/errors/domain_errors.py +++ b/src/shared/helpers/errors/domain_errors.py @@ -29,5 +29,4 @@ def message(self): class EntityParameterTimeError(BaseError): def __init__(self, start_Date: int, end_date: int): - super().__init__(f'Initial time {start_Date} must be less than or equal to end time {end_date}') - \ No newline at end of file + super().__init__(f'Initial time {start_Date} must be less than or equal to end time {end_date}') \ No newline at end of file diff --git a/src/shared/helpers/errors/usecase_errors.py b/src/shared/helpers/errors/usecase_errors.py index 223f72d..371c9c7 100644 --- a/src/shared/helpers/errors/usecase_errors.py +++ b/src/shared/helpers/errors/usecase_errors.py @@ -12,6 +12,10 @@ class ForbiddenAction(BaseError): def __init__(self, message: str): super().__init__(f'That action is forbidden for this {message}') +class DependantFilter(BaseError): + def __init__(self, message: str): + super().__init__(f'Filters have to be provided together: {message}') + class DynamoDBBaseError(BaseError): def __init__(self, message: str): super().__init__(f'Error extracting bookings from dynamo: {message}') @@ -19,3 +23,4 @@ def __init__(self, message: str): class InvalidSchedule(BaseError): def __init__(self): super().__init__('Court is already booked for the selected time slot or has to have 15 min tolerance') + diff --git a/tests/modules/create_booking/app/test_create_booking_controller.py b/tests/modules/create_booking/app/test_create_booking_controller.py index 6ef738d..c349251 100644 --- a/tests/modules/create_booking/app/test_create_booking_controller.py +++ b/tests/modules/create_booking/app/test_create_booking_controller.py @@ -7,39 +7,50 @@ class TestCreateBookingController: def test_create_booking_controller(self): - repo = BookingRepositoryMock() usecase = CreateBookingUsecase(repo) controller = CreateBookingController(usecase) - request = HttpRequest(body= { - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": 1, - "sport": "Tennis", - "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', - "materials": ["racket", "balls"] - }) + request = HttpRequest( + body={ + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": 1, + "sport": "Tennis", + "materials": ["racket", "balls"] + }, + headers={ + "user_from_authorizer": { + "displayName": 'Lebron James', + "mail": 'lbj@maua.br', + "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + } + } + ) response = controller(request) assert response.status_code == 201 def test_create_booking_controller_missing_start_date(self): - repo = BookingRepositoryMock() usecase = CreateBookingUsecase(repo) controller = CreateBookingController(usecase) - request = HttpRequest(body= { - "end_date": 1630003600, - "court_number": 1, - "sport": "Tennis", - "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', - "materials": ["racket", "balls"] - }) + request = HttpRequest( + body={ + "end_date": 1630003600, + "court_number": 1, + "sport": "Tennis", + "materials": ["racket", "balls"] + }, + headers={ + "user_from_authorizer": { + "displayName": 'Lebron James', + "mail": 'lbj@maua.br', + "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + } + }) response = controller(request) @@ -47,39 +58,45 @@ def test_create_booking_controller_missing_start_date(self): assert response.status_code == 400 def test_create_booking_controller_wrong_type_start_date(self): + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - - request = HttpRequest(body= { - "start_date": "1630000000", - "end_date": 1630003600, - "court_number": 1, - "sport": "Tennis", - "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', - "materials": ["racket", "balls"] - }) + request = HttpRequest(body={ + "start_date": "1630000000", + "end_date": 1630003600, + "court_number": 1, + "sport": "Tennis", + "materials": ["racket", "balls"] + }, headers={ + "user_from_authorizer": { + "displayName": 'Lebron James', + "mail": 'lbj@maua.br', + "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + } + }) - response = controller(request) + response = controller(request) - assert response.body == "Field start_date isn't in the right type.\n Received: str.\n Expected: int" - assert response.status_code == 400 + assert response.body == "Field start_date isn't in the right type.\n Received: str.\n Expected: int" + assert response.status_code == 400 def test_create_booking_controller_missing_end_date(self): - repo = BookingRepositoryMock() usecase = CreateBookingUsecase(repo) controller = CreateBookingController(usecase) - request = HttpRequest(body= { + request = HttpRequest(body={ "start_date": 1630000000, "court_number": 1, "sport": "Tennis", - "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', "materials": ["racket", "balls"] + }, headers={ + "user_from_authorizer": { + "displayName": 'Lebron James', + "mail": 'lbj@maua.br', + "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + } }) response = controller(request) @@ -88,249 +105,190 @@ def test_create_booking_controller_missing_end_date(self): assert response.status_code == 400 def test_create_booking_controller_wrong_type_end_date(self): + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - - request = HttpRequest(body= { - "start_date": 1630000000, - "end_date": "1630003600", - "court_number": 1, - "sport": "Tennis", - "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', - "materials": ["racket", "balls"] - }) + request = HttpRequest(body={ + "start_date": 1630000000, + "end_date": "1630003600", + "court_number": 1, + "sport": "Tennis", + "materials": ["racket", "balls"] + }, headers={ + "user_from_authorizer": { + "displayName": 'Lebron James', + "mail": 'lbj@maua.br', + "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + } + }) - response = controller(request) + response = controller(request) - assert response.body == "Field end_date isn't in the right type.\n Received: str.\n Expected: int" - assert response.status_code == 400 + assert response.body == "Field end_date isn't in the right type.\n Received: str.\n Expected: int" + assert response.status_code == 400 def test_create_booking_wrong_type_court_number(self): + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - - request = HttpRequest(body= { - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": "1", - "sport": "Tennis", - "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', - "materials": ["racket", "balls"] - }) + request = HttpRequest(body={ + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": "1", + "sport": "Tennis", + "materials": ["racket", "balls"] + }, headers={ + "user_from_authorizer": { + "displayName": 'Lebron James', + "mail": 'lbj@maua.br', + "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + } + }) - response = controller(request) + response = controller(request) - assert response.body == "Field court_number isn't in the right type.\n Received: str.\n Expected: int" - assert response.status_code == 400 + assert response.body == "Field court_number isn't in the right type.\n Received: str.\n Expected: int" + assert response.status_code == 400 def test_create_booking_controller_missing_court_number(self): + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - - request = HttpRequest(body= { - "start_date": 1630000000, - "end_date": 1630003600, - "sport": "Tennis", - "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', - "materials": ["racket", "balls"] - }) + request = HttpRequest(body={ + "start_date": 1630000000, + "end_date": 1630003600, + "sport": "Tennis", + "materials": ["racket", "balls"] + }, headers={ + "user_from_authorizer": { + "displayName": 'Lebron James', + "mail": 'lbj@maua.br', + "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + } + }) - response = controller(request) + response = controller(request) - assert response.body == "Field court_number is missing" - assert response.status_code == 400 + assert response.body == "Field court_number is missing" + assert response.status_code == 400 def test_create_booking_controller_missing_sport(self): + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - - request = HttpRequest(body= { - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": 1, - "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', - "materials": ["racket", "balls"] - }) + request = HttpRequest(body={ + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": 1, + "materials": ["racket", "balls"] + }, headers={ + "user_from_authorizer": { + "displayName": 'Lebron James', + "mail": 'lbj@maua.br', + "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + } + }) - response = controller(request) + response = controller(request) - assert response.body == "Field sport is missing" - assert response.status_code == 400 + assert response.body == "Field sport is missing" + assert response.status_code == 400 def test_create_booking_controller_wrong_type_sport(self): + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - - request = HttpRequest(body= { - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": 1, - "sport": 1, - "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', - "materials": ["racket", "balls"] - }) - - response = controller(request) - - assert response.body == "Field sport isn't in the right type.\n Received: int.\n Expected: str" - assert response.status_code == 400 - - def test_create_booking_controller_missing_user_id(self): - - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - - request = HttpRequest(body= { - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": 1, - "sport": "Tennis", - "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', - "materials": ["racket", "balls"] - }) - - response = controller(request) - - assert response.body == "Field user_id is missing" - assert response.status_code == 400 - - def test_create_booking_controller_wrong_type_user_id(self): - - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - - request = HttpRequest(body= { - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": 1, - "sport": "Tennis", - "user_id": 1, - "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', - "materials": ["racket", "balls"] - }) - - response = controller(request) - - assert response.body == "Field user_id isn't in the right type.\n Received: int.\n Expected: str" - assert response.status_code == 400 - - def test_create_booking_controller_missing_booking_id(self): - - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - - request = HttpRequest(body= { - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": 1, - "sport": "Tennis", - "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - "materials": ["racket", "balls"] - }) - - response = controller(request) - - assert response.body == "Field booking_id is missing" - assert response.status_code == 400 - - def test_create_booking_controller_wrong_type_booking_id(self): - - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - - request = HttpRequest(body= { - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": 1, - "sport": "Tennis", - "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - "booking_id": 1, - "materials": ["racket", "balls"] - }) + request = HttpRequest(body={ + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": 1, + "sport": 1, + "materials": ["racket", "balls"] + }, headers={ + "user_from_authorizer": { + "displayName": 'Lebron James', + "mail": 'lbj@maua.br', + "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + } + }) - response = controller(request) + response = controller(request) - assert response.body == "Field booking_id isn't in the right type.\n Received: int.\n Expected: str" - assert response.status_code == 400 + assert response.body == "Field sport isn't in the right type.\n Received: int.\n Expected: str" + assert response.status_code == 400 def test_create_booking_controller_missing_materials(self): + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - - request = HttpRequest(body= { - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": 1, - "sport": "Tennis", - "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', - }) + request = HttpRequest(body={ + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": 1, + "sport": "Tennis", + }, headers={ + "user_from_authorizer": { + "displayName": 'Lebron James', + "mail": 'lbj@maua.br', + "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + } + }) - response = controller(request) + response = controller(request) - assert response.body == "Field materials is missing" - assert response.status_code == 400 + assert response.body == "Field materials is missing" + assert response.status_code == 400 def test_create_booking_controller_wrong_type_materials(self): + repo = BookingRepositoryMock() + usecase = CreateBookingUsecase(repo) + controller = CreateBookingController(usecase) - repo = BookingRepositoryMock() - usecase = CreateBookingUsecase(repo) - controller = CreateBookingController(usecase) - - request = HttpRequest(body= { - "start_date": 1630000000, - "end_date": 1630003600, - "court_number": 1, - "sport": "Tennis", - "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', - "materials": "racket" - }) + request = HttpRequest(body={ + "start_date": 1630000000, + "end_date": 1630003600, + "court_number": 1, + "sport": "Tennis", + "materials": "racket" + }, headers={ + "user_from_authorizer": { + "displayName": 'Lebron James', + "mail": 'lbj@maua.br', + "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + } + }) - response = controller(request) + response = controller(request) - assert response.body == "Field materials isn't in the right type.\n Received: str.\n Expected: list" - assert response.status_code == 400 + assert response.body == "Field materials isn't in the right type.\n Received: str.\n Expected: list" + assert response.status_code == 400 def test_create_booking_controller_wrong_type_inside_list(self): - repo = BookingRepositoryMock() usecase = CreateBookingUsecase(repo) controller = CreateBookingController(usecase) - request = HttpRequest(body= { + request = HttpRequest(body={ "start_date": 1630000000, "end_date": 1630003600, "court_number": 1, "sport": "Tennis", - "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - "booking_id": 'e1d3bebf-dc0d-4fc1-861c-506a40cc2925', "materials": ["racket", 1] + }, headers={ + "user_from_authorizer": { + "displayName": 'Lebron James', + "mail": 'lbj@maua.br', + "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + } }) response = controller(request) assert response.body == "Invalid material type" assert response.status_code == 400 - diff --git a/tests/modules/create_booking/app/test_create_booking_presenter.py b/tests/modules/create_booking/app/test_create_booking_presenter.py index fb5b6bd..0a6ea41 100644 --- a/tests/modules/create_booking/app/test_create_booking_presenter.py +++ b/tests/modules/create_booking/app/test_create_booking_presenter.py @@ -28,6 +28,11 @@ def test_create_booking_presenter(self): "apiId": "", "authentication": None, "authorizer": { + "user": { + "displayName": 'Lebron James', + "mail": 'lbj@maua.br', + "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -44,7 +49,7 @@ def test_create_booking_presenter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": '{"start_date": 1610617200, "end_date": 1610620800, "court_number": 1, "sport": "Tennis", "user_id": "123e4567-e89b-12d3-a456-426614174000", "booking_id": "123e4567-e89b-12d3-a456-426614174000", "materials": ["ball", "racket"]}', + "body": '{"start_date": 1610617200, "end_date": 1610620800, "court_number": 1, "sport": "Tennis", "materials": ["ball", "racket"]}', "pathParameters": None, "isBase64Encoded": None, "stageVariables": None diff --git a/tests/modules/create_booking/app/test_create_booking_usecase.py b/tests/modules/create_booking/app/test_create_booking_usecase.py index fb2fb12..3d79879 100644 --- a/tests/modules/create_booking/app/test_create_booking_usecase.py +++ b/tests/modules/create_booking/app/test_create_booking_usecase.py @@ -17,8 +17,8 @@ def test_create_booking_usecase(self): court_number=1, sport=SPORT.TENNIS, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', - booking_id='e1d3bebf-dc0d-4fc1-861c-506a40cc2925', - materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + materials=['Raquete', 'Bola', 'Rede', 'Tenis'], + booking_id='c8435c66-13a4-4641-9d54-773b4b8ccc98' ) booking_repository = BookingRepositoryMock() @@ -31,11 +31,16 @@ def test_create_booking_usecase(self): court_number=1, sport="Tennis", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', - booking_id='e1d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Raquete', 'Bola', 'Rede', 'Tenis'] ) - assert booking == response + assert response is not None + assert response.start_date == booking.start_date + assert response.end_date == booking.end_date + assert response.court_number == booking.court_number + assert response.sport == booking.sport + assert response.user_id == booking.user_id + assert response.booking_id != booking.booking_id def test_create_booking_usecase_invalid_sport(self): @@ -51,7 +56,6 @@ def test_create_booking_usecase_invalid_sport(self): court_number=1, sport="Invalid sport but string", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', - booking_id='e1d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Raquete', 'Bola', 'Rede', 'Tenis'] ) @@ -69,7 +73,6 @@ def test_create_booking_usecase_invalid_materials(self): court_number=1, sport="Tennis", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', - booking_id='e1d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=[1, 2, 3] ) diff --git a/tests/modules/get_all_users/__init__.py b/tests/modules/get_all_users/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/modules/get_all_users/app/__init__.py b/tests/modules/get_all_users/app/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/modules/get_all_users/app/test_get_all_users_controller.py b/tests/modules/get_all_users/app/test_get_all_users_controller.py deleted file mode 100644 index bf576c2..0000000 --- a/tests/modules/get_all_users/app/test_get_all_users_controller.py +++ /dev/null @@ -1,20 +0,0 @@ -import pytest -from src.modules.get_all_users.app.get_all_users_usecase import GetAllUsersUseCase -from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock -from src.modules.get_all_users.app.get_all_users_controller import GetAllUsersController -from src.shared.helpers.external_interfaces.http_models import HttpRequest - -class Test_GetAllUsersController: - @pytest.mark.skip("Can't run test in github actions") - def test_get_all_users_controller(self): - - repo = BookingRepositoryMock() - usecase = GetAllUsersUseCase(repo=repo) - controller = GetAllUsersController(usecase=usecase) - request = HttpRequest() - response = controller(request) - - assert response.status_code == 200 - assert len(response.body['users']) == 3 - assert response.body['message'] == 'the users were retrieved' - assert response.body['users'][0]['user_id'] == '1f25448b-3429-4c19-8287-d9e64f17bc3a' \ No newline at end of file diff --git a/tests/modules/get_all_users/app/test_get_all_users_presenter.py b/tests/modules/get_all_users/app/test_get_all_users_presenter.py deleted file mode 100644 index c6a97d2..0000000 --- a/tests/modules/get_all_users/app/test_get_all_users_presenter.py +++ /dev/null @@ -1,57 +0,0 @@ -import json - -import pytest -from src.modules.get_all_users.app.get_all_users_presenter import lambda_handler -from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock - -repo = BookingRepositoryMock() - -class Test_GetAllUsersPresenter: - @pytest.mark.skip("Can't run test in github actions") - def test_get_all_users_presenter(self): - - event = { - "version": "2.0", - "routeKey": "$default", - "rawPath": "/my/path", - "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", - "cookies": [ - "cookie1", - "cookie2" - ], - "headers": { - "header1": "value1", - "header2": "value1,value2" - }, - "requestContext": { - "accountId": "123456789012", - "apiId": "", - "authentication": None, - "authorizer": { - }, - "domainName": ".lambda-url.us-west-2.on.aws", - "domainPrefix": "", - "external_interfaces": { - "method": "POST", - "path": "/my/path", - "protocol": "HTTP/1.1", - "sourceIp": "123.123.123.123", - "userAgent": "agent" - }, - "requestId": "id", - "routeKey": "$default", - "stage": "$default", - "time": "12/Mar/2020:19:03:58 +0000", - "timeEpoch": 1583348638390 - }, - "body": "Hello from client!", - "pathParameters": None, - "isBase64Encoded": None, - "stageVariables": None - } - - response = lambda_handler(event, None) - - assert response['statusCode'] == 200 - assert json.loads(response['body'])["message"] == "the users were retrieved" - assert len(json.loads(response['body'])["users"]) == 3 \ No newline at end of file diff --git a/tests/modules/get_all_users/app/test_get_all_users_usecase.py b/tests/modules/get_all_users/app/test_get_all_users_usecase.py deleted file mode 100644 index c1d9be4..0000000 --- a/tests/modules/get_all_users/app/test_get_all_users_usecase.py +++ /dev/null @@ -1,15 +0,0 @@ -import pytest -from src.modules.get_all_users.app.get_all_users_usecase import GetAllUsersUseCase -from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock - -class Test_GetAllUsersUsecase: - @pytest.mark.skip("Can't run test in github actions") - def test_get_all_users_usecase(self): - repo = BookingRepositoryMock() - - usecase = GetAllUsersUseCase(repo) - - result = usecase() - - assert len(result) == 3 - assert result[0]["user_id"] == "1f25448b-3429-4c19-8287-d9e64f17bc3a" \ No newline at end of file diff --git a/tests/modules/get_all_users/app/test_get_all_users_viewmodel.py b/tests/modules/get_all_users/app/test_get_all_users_viewmodel.py deleted file mode 100644 index e0ba9ea..0000000 --- a/tests/modules/get_all_users/app/test_get_all_users_viewmodel.py +++ /dev/null @@ -1,33 +0,0 @@ -import pytest -from src.modules.get_all_users.app.get_all_users_usecase import GetAllUsersUseCase -from src.modules.get_all_users.app.get_all_users_viewmodel import GetAllUsersViewModel -from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock - - -class Test_GetAllUsersViewModel: - @pytest.mark.skip("Can't run test in github actions") - def test_get_all_users_viewmodel(self): - repo = BookingRepositoryMock() - usecase = GetAllUsersUseCase(repo) - - user_list = usecase() - - viewmodel = GetAllUsersViewModel(user_list) - - assert viewmodel.to_dict() == { - 'users': [ - { - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', - 'name': 'GUSTAVO ALVES GOMES' - }, - { - 'user_id': 'd351a9b1-937f-423c-a9d1-9929b5795be1', - 'name': 'LEONARDO LUIZ SEIXAS IORIO' - }, - { - 'user_id': 'c07e0862-3c07-4227-ab0f-511a267cb7ff', - 'name': 'VICTOR AUGUSTO DE GASPERI' - } - ], - 'message': 'the users were retrieved' - } diff --git a/tests/modules/update_booking/app/test_update_booking_controller.py b/tests/modules/update_booking/app/test_update_booking_controller.py index f006a91..02f02d2 100644 --- a/tests/modules/update_booking/app/test_update_booking_controller.py +++ b/tests/modules/update_booking/app/test_update_booking_controller.py @@ -1,4 +1,5 @@ import pytest +import uuid from src.modules.update_booking.app.update_booking_controller import UpdateBookingController from src.modules.update_booking.app.update_booking_usecase import UpdateBookingUsecase @@ -8,245 +9,256 @@ class Test_UpdateBookingController: def test_update_booking_controller(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) - response = controller(request) + response = controller(request) - assert response.status_code == 200 - assert response.body['message'] == "the booking was retrieved" + assert response.status_code == 200 + assert response.body['message'] == "the booking was retrieved" def test_update_booking_controller_booking_id_missing(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) - - request = HttpRequest(body={ - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) - - response = controller(request) - - assert response.status_code == 400 - assert response.body == "Field booking_id is missing" - - def test_update_booking_controller_start_date_missing(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) - - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) - - response = controller(request) - - assert response.status_code == 400 - assert response.body == "Field start_date is missing" - - def test_update_controller_end_date_missing(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) - - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) - - response = controller(request) - - assert response.status_code == 400 - assert response.body == "Field end_date is missing" - - def test_update_controller_court_number_missing(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) - - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) - - response = controller(request) - - assert response.status_code == 400 - assert response.body == "Field court_number is missing" - - def test_update_controller_sport_missing(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) - - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) - - response = controller(request) - - assert response.status_code == 400 - assert response.body == "Field sport is missing" - - def test_update_controller_materials_missing(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis" - }) + request = HttpRequest(body={ + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) - response = controller(request) + response = controller(request) - assert response.status_code == 400 - assert response.body == "Field materials is missing" + assert response.status_code == 400 + assert response.body == "Field booking_id is missing" def test_update_booking_controller_booking_id_wrong_type(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) - request = HttpRequest(body={ - "booking_id": 123, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) + request = HttpRequest(body={ + "booking_id": 123, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) - response = controller(request) + response = controller(request) - assert response.status_code == 400 - assert response.body == "Field booking_id is not valid" + assert response.status_code == 400 + assert "booking_id" in response.body + assert "str" in response.body def test_update_booking_controller_start_date_wrong_type(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": "123", - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": "123", + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) - response = controller(request) + response = controller(request) - assert response.status_code == 400 - assert response.body == "Field date is not valid" + assert response.status_code == 400 + assert "start_date" in response.body + assert "int" in response.body def test_update_booking_controller_end_date_wrong_type(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": "123", - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": "123", + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) - response = controller(request) + response = controller(request) - assert response.status_code == 400 - assert response.body == "Field date is not valid" + assert response.status_code == 400 + assert "end_date" in response.body + assert "int" in response.body def test_update_booking_controller_court_number_wrong_type(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": "1", - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": "1", + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) - response = controller(request) + response = controller(request) - assert response.status_code == 400 - assert response.body == "Field court_number is not valid" + assert response.status_code == 400 + assert "court_number" in response.body + assert "int" in response.body def test_update_booking_controller_sport_wrong_type(self): - booking_repo = BookingRepositoryMock() - usecase = UpdateBookingUsecase(booking_repo=booking_repo) - controller = UpdateBookingController(update_booking_use_case=usecase) + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) - request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": 123, - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] - }) + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": 123, + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) - response = controller(request) + response = controller(request) - assert response.status_code == 400 - assert response.body == "Field sport is not valid" + assert response.status_code == 400 + assert "sport" in response.body + assert "str" in response.body def test_update_booking_controller_materials_wrong_type(self): + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) + + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": "Raquete, Bola, Rede, Tenis" + }) + + response = controller(request) + + assert response.status_code == 400 + assert "materials" in response.body + assert "list" in response.body + + def test_update_booking_controller_only_booking_id(self): + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) + + original_booking = booking_repo.bookings[0] + booking_id = original_booking.booking_id + + request = HttpRequest(body={ + "booking_id": booking_id + }) + + response = controller(request) + + assert response.status_code == 200 + assert response.body['booking']['booking_id'] == booking_id + + def test_update_booking_controller_user_id_ignored(self): + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) + + original_booking = booking_repo.bookings[0] + original_user_id = original_booking.user_id + new_user_id = "novo-user-id-que-nao-deve-ser-usado" + + request = HttpRequest(body={ + "booking_id": original_booking.booking_id, + "start_date": original_booking.start_date, + "end_date": original_booking.end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'], + "user_id": new_user_id + }) + + response = controller(request) + + assert response.status_code == 200 + assert response.body['booking']['user_id'] == original_user_id + assert response.body['booking']['user_id'] != new_user_id + + def test_update_booking_controller_booking_not_found(self): + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) + + non_existent_booking_id = str(uuid.uuid4()) + + original_get_booking = booking_repo.get_booking + + def get_booking_mock(booking_id): + if booking_id == non_existent_booking_id: + return None + return original_get_booking(booking_id) + + booking_repo.get_booking = get_booking_mock + + request = HttpRequest(body={ + "booking_id": non_existent_booking_id, + "start_date": 1634576165000, + "end_date": 1634583365000, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + }) + + response = controller(request) + booking_repo.get_booking = original_get_booking + + assert response.status_code == 404 + assert "not found" in response.body.lower() + + + def test_update_booking_controller_partial_update(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) controller = UpdateBookingController(update_booking_use_case=usecase) - + + original_booking = booking_repo.bookings[0] + booking_id = original_booking.booking_id + original_court_number = original_booking.court_number + new_court_number = original_court_number + 1 + request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": "Raquete, Bola, Rede, Tenis" + "booking_id": booking_id, + "court_number": new_court_number }) - + response = controller(request) - - assert response.status_code == 400 - assert response.body == "Field materials is not valid" - - - + + assert response.status_code == 200 + assert response.body['booking']['court_number'] == new_court_number + assert response.body['booking']['start_date'] == original_booking.start_date + assert response.body['booking']['end_date'] == original_booking.end_date + assert response.body['booking']['sport'] == original_booking.sport.value + assert response.body['booking']['materials'] == original_booking.materials \ No newline at end of file diff --git a/tests/modules/update_booking/app/test_update_booking_usecase.py b/tests/modules/update_booking/app/test_update_booking_usecase.py index 20fbcbe..e47862a 100644 --- a/tests/modules/update_booking/app/test_update_booking_usecase.py +++ b/tests/modules/update_booking/app/test_update_booking_usecase.py @@ -135,41 +135,56 @@ def test_update_booking_usecase_none_booking_id(self): def test_update_booking_usecase_none_court_number(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) - - with pytest.raises(EntityError): - booking = usecase(booking_id=booking_repo.bookings[0].booking_id, - court_number=None, - start_date=1634576165000, - end_date=1634583365000, - sport=SPORT.TENNIS, - materials=['Raquete', 'Bola', 'Rede', 'Tenis'] - ) + + original_booking = booking_repo.bookings[0] + original_court_number = original_booking.court_number + + booking = usecase( + booking_id=original_booking.booking_id, + court_number=None, + start_date=1634576165000, + end_date=1634583365000, + sport=SPORT.TENNIS, + materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + ) + + assert booking.court_number == original_court_number def test_update_booking_usecase_none_start_date(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) - - with pytest.raises(EntityError): - booking = usecase(booking_id=booking_repo.bookings[0].booking_id, - court_number=2, - start_date=None, - end_date=1634583365000, - sport=SPORT.TENNIS, - materials=['Raquete', 'Bola', 'Rede', 'Tenis'] - ) + + original_booking = booking_repo.bookings[0] + original_start_date = original_booking.start_date + + booking = usecase( + booking_id=original_booking.booking_id, + court_number=2, + start_date=None, + end_date=1634583365000, + sport=SPORT.TENNIS, + materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + ) + + assert booking.start_date == original_start_date def test_update_booking_usecase_none_end_date(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) - - with pytest.raises(EntityError): - booking = usecase(booking_id=booking_repo.bookings[0].booking_id, - court_number=2, - start_date=1634576165000, - end_date=None, - sport=SPORT.TENNIS, - materials=['Raquete', 'Bola', 'Rede', 'Tenis'] - ) + + original_booking = booking_repo.bookings[0] + original_end_date = original_booking.end_date + + booking = usecase( + booking_id=original_booking.booking_id, + court_number=2, + start_date=1634576165000, + end_date=None, + sport=SPORT.TENNIS, + materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + ) + + assert booking.end_date == original_end_date def test_update_booking_usecase_order_dates_incorrect(self): booking_repo = BookingRepositoryMock() @@ -187,25 +202,55 @@ def test_update_booking_usecase_order_dates_incorrect(self): def test_update_booking_usecase_none_sport(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) - - with pytest.raises(EntityError): - booking = usecase(booking_id=booking_repo.bookings[0].booking_id, - court_number=2, - start_date=1634576165000, - end_date=1634583365000, - sport=None, - materials=['Raquete', 'Bola', 'Rede', 'Tenis'] - ) + + original_booking = booking_repo.bookings[0] + original_sport = original_booking.sport + + booking = usecase( + booking_id=original_booking.booking_id, + court_number=2, + start_date=1634576165000, + end_date=1634583365000, + sport=None, + materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + ) + + assert booking.sport == original_sport def test_update_booking_usecase_none_materials(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) + + original_booking = booking_repo.bookings[0] + original_materials = original_booking.materials + + booking = usecase( + booking_id=original_booking.booking_id, + court_number=2, + start_date=1634576165000, + end_date=1634583365000, + sport=SPORT.TENNIS, + materials=None + ) + + assert booking.materials == original_materials - with pytest.raises(EntityError): - booking = usecase(booking_id=booking_repo.bookings[0].booking_id, - court_number=2, - start_date=1634576165000, - end_date=1634583365000, - sport=SPORT.TENNIS, - materials=None - ) \ No newline at end of file + def test_update_booking_usecase_cannot_update_user_id(self): + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + + original_booking = booking_repo.bookings[0] + booking_id = original_booking.booking_id + original_user_id = original_booking.user_id + + booking = usecase( + booking_id=booking_id, + court_number=2, + start_date=1634576165000, + end_date=1634583365000, + sport=SPORT.TENNIS, + materials=['Raquete', 'Bola', 'Rede', 'Tenis'], + user_id="novo-user-id-que-nao-deve-ser-usado" + ) + + assert booking.user_id == original_user_id \ No newline at end of file From 255b5d91a6f61c76864079a12f782afe8b9fc5b3 Mon Sep 17 00:00:00 2001 From: lseixas Date: Mon, 7 Jul 2025 19:11:49 -0300 Subject: [PATCH 034/167] updating import reference to newer cdk version --- iac/stacks/lambda_stack.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index fb3463e..b3cde43 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -6,9 +6,8 @@ ) from constructs import Construct from aws_cdk.aws_apigateway import Resource, LambdaIntegration -from aws_cdk.aws_events import Rule, Schedule, EventField -from aws_cdk.aws_events_targets import LambdaFunction, RuleTargetInput - +from aws_cdk.aws_events import Rule, Schedule, EventField, RuleTargetInput +from aws_cdk.aws_events_targets import LambdaFunction class LambdaStack(Construct): functions_that_need_dynamo_permissions = [] From 3a3d550c7a3c6783f5b9510f41786218ff92d6ec Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Thu, 10 Jul 2025 23:33:51 -0300 Subject: [PATCH 035/167] fix: generalizar o endpoint da api de user --- src/modules/generate_report/app/user_api_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/generate_report/app/user_api_client.py b/src/modules/generate_report/app/user_api_client.py index da0080a..163e845 100644 --- a/src/modules/generate_report/app/user_api_client.py +++ b/src/modules/generate_report/app/user_api_client.py @@ -18,7 +18,7 @@ def retrieve_users(): api_url= os.environ.get("USER_API_URL") try: - response = requests.get(api_url) + response = requests.get(api_url + '/get-all-users') users = response.json().get("users") return users except: From 386532b05012ef6a1a2a96bce1d4077028e50d21 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Thu, 10 Jul 2025 23:36:34 -0300 Subject: [PATCH 036/167] =?UTF-8?q?feat:=20adicionar=20vari=C3=A1vel=20USE?= =?UTF-8?q?R=5FAPI=5FURL=20ao=20ambiente=20de=20implanta=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/CD.yml | 3 ++- iac/stacks/iac_stack.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index 8a5c558..bd48634 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -54,4 +54,5 @@ jobs: AWS_REGION: ${{ vars.AWS_REGION }} AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} STACK_NAME: ${{ env.STACK_NAME }} - GITHUB_REF_NAME: ${{ github.ref_name }} \ No newline at end of file + GITHUB_REF_NAME: ${{ github.ref_name }} + USER_API_URL: ${{ secrets.USER_API_URL }} \ No newline at end of file diff --git a/iac/stacks/iac_stack.py b/iac/stacks/iac_stack.py index a7a1918..c16845b 100644 --- a/iac/stacks/iac_stack.py +++ b/iac/stacks/iac_stack.py @@ -55,6 +55,7 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: "DYNAMO_PARTITION_KEY": "PK", "DYNAMO_SORT_KEY": "SK", "REGION": self.aws_region, + "USER_API_URL": os.environ.get("USER_API_URL") } From e3662dd9faa39f833f5461197c70419ef68b94c7 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Thu, 10 Jul 2025 23:33:51 -0300 Subject: [PATCH 037/167] fix: generalizar o endpoint da api de user --- src/modules/generate_report/app/user_api_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/generate_report/app/user_api_client.py b/src/modules/generate_report/app/user_api_client.py index da0080a..163e845 100644 --- a/src/modules/generate_report/app/user_api_client.py +++ b/src/modules/generate_report/app/user_api_client.py @@ -18,7 +18,7 @@ def retrieve_users(): api_url= os.environ.get("USER_API_URL") try: - response = requests.get(api_url) + response = requests.get(api_url + '/get-all-users') users = response.json().get("users") return users except: From 9377078ea7aa70e508f33a02dc330306a40d9e44 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Thu, 10 Jul 2025 23:36:34 -0300 Subject: [PATCH 038/167] =?UTF-8?q?feat:=20adicionar=20vari=C3=A1vel=20USE?= =?UTF-8?q?R=5FAPI=5FURL=20ao=20ambiente=20de=20implanta=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/CD.yml | 3 ++- iac/stacks/iac_stack.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index 8a5c558..bd48634 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -54,4 +54,5 @@ jobs: AWS_REGION: ${{ vars.AWS_REGION }} AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} STACK_NAME: ${{ env.STACK_NAME }} - GITHUB_REF_NAME: ${{ github.ref_name }} \ No newline at end of file + GITHUB_REF_NAME: ${{ github.ref_name }} + USER_API_URL: ${{ secrets.USER_API_URL }} \ No newline at end of file diff --git a/iac/stacks/iac_stack.py b/iac/stacks/iac_stack.py index a7a1918..c16845b 100644 --- a/iac/stacks/iac_stack.py +++ b/iac/stacks/iac_stack.py @@ -55,6 +55,7 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: "DYNAMO_PARTITION_KEY": "PK", "DYNAMO_SORT_KEY": "SK", "REGION": self.aws_region, + "USER_API_URL": os.environ.get("USER_API_URL") } From a71db3b17af76796af0860daa477a369369ce3c2 Mon Sep 17 00:00:00 2001 From: tokujiTO Date: Fri, 11 Jul 2025 17:30:00 -0300 Subject: [PATCH 039/167] feat: fix github action --- .github/workflows/CD.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index 4efd3a7..1d8c266 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -80,4 +80,5 @@ jobs: AWS_REGION: ${{ vars.AWS_REGION }} AWS_ACCOUNT_ID: ${{ env.AWS_ACCOUNT_ID }} STACK_NAME: ${{ env.STACK_NAME }} - GITHUB_REF_NAME: ${{ env.STAGE }} \ No newline at end of file + USER_API_URL: ${{ secrets.USER_API_URL }} + GITHUB_REF_NAME: ${{ env.STAGE }} From a887da29322b35c2034c5737514d663b287216ef Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Sat, 12 Jul 2025 13:26:13 -0700 Subject: [PATCH 040/167] modified user api client location for global access, added new functions to UAP, added respective tests --- .../app/generate_report_aggregator.py | 2 +- .../generate_report/app/user_api_client.py | 25 ------ src/shared/clients/__init__.py | 0 src/shared/clients/user_api_client.py | 81 +++++++++++++++++++ .../app/test_user_api_client.py | 27 ++++++- 5 files changed, 106 insertions(+), 29 deletions(-) delete mode 100644 src/modules/generate_report/app/user_api_client.py create mode 100644 src/shared/clients/__init__.py create mode 100644 src/shared/clients/user_api_client.py diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index 4e35277..e06c041 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -1,4 +1,4 @@ -from src.modules.generate_report.app.user_api_client import UserAPIClient +from src.shared.clients.user_api_client import UserAPIClient from src.shared.domain.entities.booking import Booking from .generate_report_extractor import GenerateReportExtractor from typing import List diff --git a/src/modules/generate_report/app/user_api_client.py b/src/modules/generate_report/app/user_api_client.py deleted file mode 100644 index 163e845..0000000 --- a/src/modules/generate_report/app/user_api_client.py +++ /dev/null @@ -1,25 +0,0 @@ -import json -import os -import requests - -from src.shared.environments import Environments - -class UserAPIClient: - - def __init__(self): - self.all_users = self.retrieve_users() - - def get_user_name(self, user_id): - user = next((user for user in self.all_users if user["user_id"] == user_id), None) - return user["name"] if user is not None else None - - @staticmethod - def retrieve_users(): - - api_url= os.environ.get("USER_API_URL") - try: - response = requests.get(api_url + '/get-all-users') - users = response.json().get("users") - return users - except: - raise Exception('Couldn\'t retrieve users') diff --git a/src/shared/clients/__init__.py b/src/shared/clients/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/shared/clients/user_api_client.py b/src/shared/clients/user_api_client.py new file mode 100644 index 0000000..913135d --- /dev/null +++ b/src/shared/clients/user_api_client.py @@ -0,0 +1,81 @@ +import json +import os +import requests + +from src.shared.environments import Environments + +class UserAPIClient: + + def __init__(self): + self.all_users = self.retrieve_users() + + def get_user_name(self, user_id): + user = next((user for user in self.all_users if user["user_id"] == user_id), None) + return user["name"] if user is not None else None + + def authenticate_user(self, token): + return self._auth_user(token=token) + + @staticmethod + def retrieve_users(): + + api_url= os.environ.get("USER_API_URL") + try: + response = requests.get(api_url + '/get-all-users') + users = response.json().get("users") + return users + except: + raise Exception('Couldn\'t retrieve users') + + #TODO adciionar os parametros nas request, testar se funciona mesmo + + @staticmethod + def _auth_user(token): + + #this will only get the user info if the user is already created in db, else it will delete the user shortly after + + api_url = os.environ.get("USER_API_URL") + + #untested funtion + def delete_user(token): + + try: + + headers = { + "Authorization": f"Bearer{token}" + } + + response = requests.delete(api_url + '/delete-user', headers=headers) + + return response.json().get("message") + + except: + + raise Exception('Could not delete user') + + try: + + headers = { + "Authorization": f"Bearer {token}" + } + + response = requests.get(api_url + '/auth-user', headers=headers) + + user = response.json().get("user") + + identifier = user.get("message", None) + + #TODO test this part + + if identifier == "the user was created successfully": + + #untested funtion + delete_user(token=token) + + raise Exception('User was not registered') + + return user + + except: + raise Exception('Could not authenticate user') + diff --git a/tests/modules/generate_report/app/test_user_api_client.py b/tests/modules/generate_report/app/test_user_api_client.py index 26133ad..ca05e67 100644 --- a/tests/modules/generate_report/app/test_user_api_client.py +++ b/tests/modules/generate_report/app/test_user_api_client.py @@ -1,13 +1,34 @@ import pytest -from src.modules.generate_report.app.user_api_client import UserAPIClient +from src.shared.clients.user_api_client import UserAPIClient class TestUserAPIClient: + + # to test this, you must declare in your .env the user mss endpoint as USER_API_URL without + # any route at the end (the user api client already adds the routing) - @pytest.mark.skip("Can't run test in gh actions") def test_get_user(self): user_client = UserAPIClient() user_name = user_client.get_user_name('1f25448b-3429-4c19-8287-d9e64f17bc3a') - assert user_name == 'GUSTAVO ALVES GOMES' \ No newline at end of file + assert user_name == 'GUSTAVO ALVES GOMES' + + def test_auth_user(self): + + #this test will only pass if user is already created in db, as method checks for this + + user_client = UserAPIClient() + # the token in the next line must be updated for testing, it is not last longing + # it must be a valid microsoft graph authentication token (jwt format) + + # you can get it via azure cli via the following prompts + # az login + # az account get-access-token --scope https://graph.microsoft.com/.default + user_token = "eyJ0eXAiOiJKV1QiLCJub25jZSI6Ii1abjloOFZOOEZuNVMxS0gyUnBmTFZJeExIbWVmUVpoaVRGd0ZwRXJ3MVEiLCJhbGciOiJSUzI1NiIsIng1dCI6Il9qTndqZVNudlRUSzhYRWRyNVFVUGtCUkxMbyIsImtpZCI6Il9qTndqZVNudlRUSzhYRWRyNVFVUGtCUkxMbyJ9.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9jNDllMTkzOS00YjUzLTQ3MzgtYmI2NC00MWZiMjk5MGU0MWMvIiwiaWF0IjoxNzUyMzQ4MjIxLCJuYmYiOjE3NTIzNDgyMjEsImV4cCI6MTc1MjQzNDkyMSwiYWNjdCI6MCwiYWNyIjoiMSIsImFpbyI6IkFVUUF1LzhaQUFBQXh4MnlPNFgySmp2S0VYMFpsbmNXS292RnI1WGxhRnlqUndCWU4wUkkzcEFLd3ZpSmdnK1ZpM09NSXQyTklseVNRVjZXQXQ0cHZWSUZzNWYzZWhDU1R3PT0iLCJhbXIiOlsicHdkIl0sImFwcF9kaXNwbGF5bmFtZSI6Ik1pY3Jvc29mdCBBenVyZSBDTEkiLCJhcHBpZCI6IjA0YjA3Nzk1LThkZGItNDYxYS1iYmVlLTAyZjllMWJmN2I0NiIsImFwcGlkYWNyIjoiMCIsImZhbWlseV9uYW1lIjoiTFVJWiBTRUlYQVMgSU9SSU8iLCJnaXZlbl9uYW1lIjoiTEVPTkFSRE8iLCJpZHR5cCI6InVzZXIiLCJpcGFkZHIiOiIxODkuMTIwLjcyLjU4IiwibmFtZSI6IkxFT05BUkRPIExVSVogU0VJWEFTIElPUklPIiwib2lkIjoiZDM1MWE5YjEtOTM3Zi00MjNjLWE5ZDEtOTkyOWI1Nzk1YmUxIiwib25wcmVtX3NpZCI6IlMtMS01LTIxLTEyNTEwOTIzMjUtMTAwNzM4MzU3OC05Mjk3MDEwMDAtNjQ2NTYiLCJwbGF0ZiI6IjUiLCJwdWlkIjoiMTAwMzIwMDI1NzkwRTY2MyIsInJoIjoiMS5BUThBT1JtZXhGTkxPRWU3WkVIN0taRGtIQU1BQUFBQUFBQUF3QUFBQUFBQUFBQVBBR3NQQUEuIiwic2NwIjoiQXBwbGljYXRpb24uUmVhZFdyaXRlLkFsbCBBcHBSb2xlQXNzaWdubWVudC5SZWFkV3JpdGUuQWxsIEF1ZGl0TG9nLlJlYWQuQWxsIERlbGVnYXRlZFBlcm1pc3Npb25HcmFudC5SZWFkV3JpdGUuQWxsIERpcmVjdG9yeS5BY2Nlc3NBc1VzZXIuQWxsIGVtYWlsIEdyb3VwLlJlYWRXcml0ZS5BbGwgb3BlbmlkIHByb2ZpbGUgVXNlci5SZWFkLkFsbCBVc2VyLlJlYWRXcml0ZS5BbGwiLCJzaWQiOiIwMDZjYWM2OS0wMzFjLWY5ZTktZTMyOC05MjlhMTJhN2E5Y2EiLCJzdWIiOiJmeG9TLVRTaGpjRHlDQmVId1N0enozQ0RmTTNJdXV3aTJYemYta1JncTFFIiwidGVuYW50X3JlZ2lvbl9zY29wZSI6IlNBIiwidGlkIjoiYzQ5ZTE5MzktNGI1My00NzM4LWJiNjQtNDFmYjI5OTBlNDFjIiwidW5pcXVlX25hbWUiOiIyMy4wMDg0Ny00QG1hdWEuYnIiLCJ1cG4iOiIyMy4wMDg0Ny00QG1hdWEuYnIiLCJ1dGkiOiJVNG5oQ0VSdGdVZU12RUlKUXRJaUFBIiwidmVyIjoiMS4wIiwid2lkcyI6WyJiNzlmYmY0ZC0zZWY5LTQ2ODktODE0My03NmIxOTRlODU1MDkiXSwieG1zX2NjIjpbIkNQMSJdLCJ4bXNfZnRkIjoiSnpLckRZeVpydU1FT3k0UHJRWW1MNUJ2WVNvTmp5bG5kRTFmVmZkSkJPa0JkWE56YjNWMGFDMWtjMjF6IiwieG1zX2lkcmVsIjoiMjAgMSIsInhtc19zc20iOiIxIiwieG1zX3N0Ijp7InN1YiI6ImoyeS05b0NleWdEeTJqVUI2QUZSTjluVDk0RVAxNWgtbDc1WFBaTHpjZnMifSwieG1zX3RjZHQiOjE0NDM0ODcxNTV9.ZJXmjXXXFX0PMiGexOEoJ-BiatTRaCeL0FBeoFbvUCaVDtCv2cRUE1yxO_82Rdhn3JTcjIb7uQ5GokkA19gM65D_aOKdelxJUP7ADlW-h5IInoPX_fISnZzpTF_gYWF0e4toGQP0RHCPuXOwrvPVJnMtRJvMf0rSuBgpvL2DQnLvFC5QMzlHRLkJamcCx3CzQ4hQ4SiRZU5BB1o8-TTFUK29hcLhPv-V0FsDPA2hcD8flTP70Ivvp1Ir17Q3U9Y-FS_MXmieYs21J6Sz77rNjwQJ2kVZ0XM70aMolR2g9tZ3In8ZQueLkzTTddBjPxaUda8He_cyftaoi6lK6rvpUA" + + user_client = UserAPIClient() + + user_info = user_client.authenticate_user(token=user_token) + + print(user_info) \ No newline at end of file From 51e65a17bfd2de7de008df92f52e8d1ea16a77ec Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Sat, 12 Jul 2025 18:42:09 -0300 Subject: [PATCH 041/167] added graph authorizer --- src/shared/authorizer/__init__.py | 0 src/shared/authorizer/graph_authorizer.py | 118 ++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 src/shared/authorizer/__init__.py create mode 100644 src/shared/authorizer/graph_authorizer.py diff --git a/src/shared/authorizer/__init__.py b/src/shared/authorizer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/shared/authorizer/graph_authorizer.py b/src/shared/authorizer/graph_authorizer.py new file mode 100644 index 0000000..e67435a --- /dev/null +++ b/src/shared/authorizer/graph_authorizer.py @@ -0,0 +1,118 @@ +import os +import re +import json +import urllib3 + +from src.shared.environments import Environments + + +def lambda_handler(event, context): + """ + This function is used to authorize the user to access the API Gateway. + It uses the Microsoft Graph API to fetch the user information and check if the user is from Maua. + + Args: + event (dict): The event data passed to the Lambda function. + context (object): The context object representing the current invocation. + + Returns: + dict: The response object containing the policy document. + """ + + try: + # Fetching the Microsoft Graph endpoint from the environment variables + GRAPH_MICROSOFT_ENDPOINT = os.environ.get("GRAPH_MICROSOFT_ENDPOINT", None) + if not GRAPH_MICROSOFT_ENDPOINT: + raise Exception("MS_GRAPH_ENDPOINT environment variable not set") + + # Creating a HTTP client + http = urllib3.PoolManager() + + # Extracting the token from the event data + token = event["authorizationToken"].replace("Bearer ", "") + + print(f"token: {token}") + print(f"graph_endpoint: {GRAPH_MICROSOFT_ENDPOINT}") + + # Fetching the user information from the Microsoft Graph API + graph_endpoint = GRAPH_MICROSOFT_ENDPOINT + methodArn = event["methodArn"] + headers = {"Authorization": f"Bearer {token}"} + response = http.request("GET", graph_endpoint, headers=headers) + + # Checking if the request was successful + if response.status != 200: + raise Exception("Failed to fetch user information") + + # Parsing the user data + user_data = json.loads(response.data.decode("utf-8")) + + print("CHECK BEFORE REGEX") + print(user_data) + + # Checking if the user is from Maua + email_regex = r"(^\d{2}\.\d{5}-\d@maua\.br$)|(^[a-zA-Z]+\.[a-zA-Z]+@maua\.br$)" # Regex to match the Maua email + if not re.match(email_regex, user_data.get("mail", "")): + return generate_policy("user", "Deny", methodArn) + + + # TODO -> implementar o método de get user, pode ser pelo e-mail ou pelo user_id, usando o Repositorio + + print("USER_ID: ", user_data.get("id", "did not find id")) + + user_repo = Environments.get_user_repo()() + user = user_repo.get_user(user_id=user_data.get("id")) + + print("CHECK PASSED REGEX AND GET USER") + + policy = generate_policy( + user_data.get("id", "user"), "Allow", methodArn, {"user": json.dumps(user_data)} + ) + + print(policy) + + return policy + + # Handling exceptions + except Exception as e: + print(f"Error: {e}") + methodArn = event["methodArn"] + return generate_policy("user", "Deny", methodArn) + + +def generate_policy(principal_id, effect, method_arn, context=None): + ''' + This function generates the policy document based on the principal ID, effect, method ARN, and context. + + Args: + principal_id (str): The principal ID. + effect (str): The effect (Allow or Deny). + method_arn (str): The method ARN. + context (dict): The context object. + + Returns: + dict: The policy document. + ''' + + # Generating the policy document + auth_response = {"principalId": principal_id} + + if effect: + policy_document = { + "Version": "2012-10-17", # Version of the policy + "Statement": [ + { + "Action": "execute-api:Invoke", # Action to allow + "Effect": effect, # Effect (Allow or Deny) + "Resource": method_arn, # Resource path + } + ], + } + auth_response["policyDocument"] = policy_document + + if context: + auth_response["context"] = context # Adding the context to the response + + print("PASSED AUTH RESPONSE") + + return auth_response \ No newline at end of file From 2ea43a27478ec3d05cfc1d166d96c11ed7254a56 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Sat, 12 Jul 2025 19:02:00 -0300 Subject: [PATCH 042/167] added pytest marksip to unrunnable tests, moved user client folder test --- tests/clients/__init__.py | 0 .../generate_report/app => clients}/test_user_api_client.py | 2 ++ 2 files changed, 2 insertions(+) create mode 100644 tests/clients/__init__.py rename tests/{modules/generate_report/app => clients}/test_user_api_client.py (96%) diff --git a/tests/clients/__init__.py b/tests/clients/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/modules/generate_report/app/test_user_api_client.py b/tests/clients/test_user_api_client.py similarity index 96% rename from tests/modules/generate_report/app/test_user_api_client.py rename to tests/clients/test_user_api_client.py index ca05e67..cc6e263 100644 --- a/tests/modules/generate_report/app/test_user_api_client.py +++ b/tests/clients/test_user_api_client.py @@ -7,6 +7,7 @@ class TestUserAPIClient: # to test this, you must declare in your .env the user mss endpoint as USER_API_URL without # any route at the end (the user api client already adds the routing) + @pytest.mark.skip("Can't run test in github actions") def test_get_user(self): user_client = UserAPIClient() @@ -14,6 +15,7 @@ def test_get_user(self): assert user_name == 'GUSTAVO ALVES GOMES' + @pytest.mark.skip("Can't run test in github actions") def test_auth_user(self): #this test will only pass if user is already created in db, as method checks for this From 9fb65b237b701359e00f92b4590700fe462a36d7 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Sat, 12 Jul 2025 23:58:55 -0300 Subject: [PATCH 043/167] improved minio building, refactored s3 manager, made it a client, refactored credentials in environments, removed generate report sender and trasnfered it to presenter, as integration looks for handlers in presenter ending files --- iac/local/minio/docker-compose-minio.yml | 34 +++++++---- .../app/generate_report_presenter.py | 60 +++++++++++++++++-- .../app/generate_report_sender.py | 57 ------------------ .../S3Manager.py => clients/s3_client.py} | 2 +- src/shared/environments.py | 4 +- ...r.py => test_generate_report_presenter.py} | 4 +- 6 files changed, 82 insertions(+), 79 deletions(-) delete mode 100644 src/modules/generate_report/app/generate_report_sender.py rename src/shared/{infra/repositories/util/S3Manager.py => clients/s3_client.py} (98%) rename tests/modules/generate_report/app/{test_generate_report_sender.py => test_generate_report_presenter.py} (90%) diff --git a/iac/local/minio/docker-compose-minio.yml b/iac/local/minio/docker-compose-minio.yml index b5081d1..fcf5ebc 100644 --- a/iac/local/minio/docker-compose-minio.yml +++ b/iac/local/minio/docker-compose-minio.yml @@ -1,15 +1,16 @@ -version: '3' +version: '3.8' # The top-level 'version' is obsolete but using a more modern one like 3.8 is fine services: minio: image: minio/minio:latest container_name: minio-reservation - ports: - - 9000:9000 - - 9001:9001 + # ✅ SET credentials for the MinIO server environment: - - MINIO_ROOT_USER=${CLIENT_ID} - - MINIO_ROOT_PASSWORD=${CLIENT_SECRET} + MINIO_ROOT_USER: root + MINIO_ROOT_PASSWORD: root1234 + ports: + - "9000:9000" + - "9001:9001" volumes: - minio-data:/data command: server /data --console-address :9001 @@ -19,11 +20,22 @@ services: depends_on: - minio entrypoint: > - /bin/sh -c " - /usr/bin/mc config host add --api s3v4 s3 http://minio:9000 ${CLIENT_ID} ${CLIENT_SECRET}; - /usr/bin/mc mb s3/bucket-test; - /usr/bin/mc policy set public s3/bucket-test; + /bin/sh -c " + # ✅ Make the script exit on any error + set -e; + + # Wait for MinIO to be ready + # Use the more modern 'mc alias set' and provide the credentials + /usr/bin/mc alias set s3 http://minio:9000 root root1234; + + # Create the bucket + /usr/bin/mc mb s3/bucket-test; + + # Set the policy + /usr/bin/mc policy set public s3/bucket-test; + + echo '✅ Bucket created successfully!'; " volumes: - minio-data: + minio-data: \ No newline at end of file diff --git a/src/modules/generate_report/app/generate_report_presenter.py b/src/modules/generate_report/app/generate_report_presenter.py index e02c936..a3db094 100644 --- a/src/modules/generate_report/app/generate_report_presenter.py +++ b/src/modules/generate_report/app/generate_report_presenter.py @@ -1,9 +1,57 @@ +import datetime +import time + +from src.shared.environments import Environments +from src.shared.clients.s3_client import s3_client + +from .generate_report_extractor import GenerateReportExtractor +from .generate_report_aggregator import GenerateReportAggregator +from .generate_report_transformer import GenerateReportTransformer + +repo = Environments.get_envs().get_booking_repo()() def lambda_handler(event, context): - """ - Lambda handler function for the generate_report module - """ - print("IM ALIVE!! LAMBDA TRIGGERED BY EVENTBRIDGE") - print('event: ', event) - print('context', context) \ No newline at end of file + extractor = GenerateReportExtractor(repo) + #"2025-04-03T15:00:00Z" date format + + current_date = datetime.datetime.now() + + year = current_date.year + month = current_date.month + year_start_date = datetime.datetime(year, 1, 1) + + start_date = int(time.mktime(year_start_date.timetuple())) * 1000 + final_date = int(time.mktime(current_date.timetuple())) * 1000 + + file_name = f"relatorio_gerado_em_{current_date.day}_{month}_{year}.xlsx" + file_path = f"relatorios/" + + extractor = GenerateReportExtractor(booking_repository=repo) + aggregator = GenerateReportAggregator(extractor=extractor) + transformer = GenerateReportTransformer(aggregator=aggregator) + report = transformer(start_date, final_date) + + if report: + + bucket_manager = s3_client() + + try: + + response = bucket_manager.upload_file(key=file_path + file_name, + file_type=".xlsx", + decode_string=report, + ) + + print("Report generated and uploaded successfully") + + return 1 + + except: + + raise Exception("Error uploading file to S3") + + + else: + + raise Exception("Error generating report") diff --git a/src/modules/generate_report/app/generate_report_sender.py b/src/modules/generate_report/app/generate_report_sender.py deleted file mode 100644 index 823c50c..0000000 --- a/src/modules/generate_report/app/generate_report_sender.py +++ /dev/null @@ -1,57 +0,0 @@ -import datetime -import time - -from src.shared.environments import Environments -from src.shared.infra.repositories.util.S3Manager import S3Manager - -from .generate_report_extractor import GenerateReportExtractor -from .generate_report_aggregator import GenerateReportAggregator -from .generate_report_transformer import GenerateReportTransformer - -repo = Environments.get_envs().get_booking_repo()() - - -def lambda_handler(event, context): - extractor = GenerateReportExtractor(repo) - #"2025-04-03T15:00:00Z" date format - - current_date = datetime.datetime.now() - - year = current_date.year - month = current_date.month - year_start_date = datetime.datetime(year, 1, 1) - - start_date = int(time.mktime(year_start_date.timetuple())) * 1000 - final_date = int(time.mktime(current_date.timetuple())) * 1000 - - file_name = f"relatorio_gerado_em_{current_date.day}_{month}_{year}.xlsx" - file_path = f"relatorios/" - - extractor = GenerateReportExtractor(booking_repository=repo) - aggregator = GenerateReportAggregator(extractor=extractor) - transformer = GenerateReportTransformer(aggregator=aggregator) - report = transformer(start_date, final_date) - - if report: - - bucket_manager = S3Manager() - - try: - - response = bucket_manager.upload_file(key=file_path + file_name, - file_type=".xlsx", - decode_string=report, - ) - - print("Report generated and uploaded successfully") - - return 1 - - except: - - raise Exception("Error uploading file to S3") - - - else: - - raise Exception("Error generating report") diff --git a/src/shared/infra/repositories/util/S3Manager.py b/src/shared/clients/s3_client.py similarity index 98% rename from src/shared/infra/repositories/util/S3Manager.py rename to src/shared/clients/s3_client.py index 318e02e..ee94e96 100644 --- a/src/shared/infra/repositories/util/S3Manager.py +++ b/src/shared/clients/s3_client.py @@ -3,7 +3,7 @@ from src.shared.environments import Environments -class S3Manager: +class s3_client: def __init__(self): self.__envs = Environments.get_envs() diff --git a/src/shared/environments.py b/src/shared/environments.py index ab28e2f..f3075bd 100644 --- a/src/shared/environments.py +++ b/src/shared/environments.py @@ -52,8 +52,8 @@ def load_envs(self): self.dynamo_partition_key = "PK" self.dynamo_sort_key = "SK" self.cloud_front_distribution_domain = "https://d3q9q9q9q9q9q9.cloudfront.net" - self.client_id = "local_client_id" - self.client_secret = "local_client_secret" + self.client_id = "root" #change to what is inside minio compose + self.client_secret = "root1234" #change to what is inside minio compose self.bucket_endpoint_url = "http://localhost:9000" else: diff --git a/tests/modules/generate_report/app/test_generate_report_sender.py b/tests/modules/generate_report/app/test_generate_report_presenter.py similarity index 90% rename from tests/modules/generate_report/app/test_generate_report_sender.py rename to tests/modules/generate_report/app/test_generate_report_presenter.py index ad84489..b506ad4 100644 --- a/tests/modules/generate_report/app/test_generate_report_sender.py +++ b/tests/modules/generate_report/app/test_generate_report_presenter.py @@ -2,14 +2,14 @@ from src.modules.generate_report.app.generate_report_aggregator import GenerateReportAggregator from src.modules.generate_report.app.generate_report_extractor import GenerateReportExtractor -from src.modules.generate_report.app.generate_report_sender import lambda_handler +from src.modules.generate_report.app.generate_report_presenter import lambda_handler from src.modules.generate_report.app.generate_report_transformer import GenerateReportTransformer from src.shared.infra.repositories.booking_repository_dynamo import BookingRepositoryDynamo class TestGenerateReportSender: - @pytest.mark.skip("Can't run test in gh actions") + pytest.mark.skip("Can't run test in github actions") #WONT WORK WITH CURRENT MOCK, ALL DATES ARE OUTDATED AND DO NOT MATCH WITH CURRENT YEAR From 30d0ee82679803156237e6e5d92a1d200a9ab96b Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Sun, 13 Jul 2025 00:08:01 -0300 Subject: [PATCH 044/167] =?UTF-8?q?added=20@=20to=20markskip=20?= =?UTF-8?q?=F0=9F=A6=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generate_report/app/test_generate_report_presenter.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/modules/generate_report/app/test_generate_report_presenter.py b/tests/modules/generate_report/app/test_generate_report_presenter.py index b506ad4..47c499b 100644 --- a/tests/modules/generate_report/app/test_generate_report_presenter.py +++ b/tests/modules/generate_report/app/test_generate_report_presenter.py @@ -7,13 +7,12 @@ from src.shared.infra.repositories.booking_repository_dynamo import BookingRepositoryDynamo -class TestGenerateReportSender: - - pytest.mark.skip("Can't run test in github actions") +class TestGenerateReportPresenter: #WONT WORK WITH CURRENT MOCK, ALL DATES ARE OUTDATED AND DO NOT MATCH WITH CURRENT YEAR - def test_generate_report_sender(self): + @pytest.mark.skip("Can't run test in github actions") + def test_generate_report_presenter(self): event_from_event_bridge = { "version": "0", From bfa44cfbc98a284f8880d5694e62bc1f474fb63d Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Mon, 14 Jul 2025 16:42:20 -0300 Subject: [PATCH 045/167] changed authorizer name, added new logic for validation in get-user route --- ...h_authorizer.py => user_mss_authorizer.py} | 30 +++++-------------- 1 file changed, 7 insertions(+), 23 deletions(-) rename src/shared/authorizer/{graph_authorizer.py => user_mss_authorizer.py} (71%) diff --git a/src/shared/authorizer/graph_authorizer.py b/src/shared/authorizer/user_mss_authorizer.py similarity index 71% rename from src/shared/authorizer/graph_authorizer.py rename to src/shared/authorizer/user_mss_authorizer.py index e67435a..9779615 100644 --- a/src/shared/authorizer/graph_authorizer.py +++ b/src/shared/authorizer/user_mss_authorizer.py @@ -20,10 +20,11 @@ def lambda_handler(event, context): """ try: - # Fetching the Microsoft Graph endpoint from the environment variables - GRAPH_MICROSOFT_ENDPOINT = os.environ.get("GRAPH_MICROSOFT_ENDPOINT", None) - if not GRAPH_MICROSOFT_ENDPOINT: - raise Exception("MS_GRAPH_ENDPOINT environment variable not set") + + # Fetch the User Mss enpoint from the environment variables + MSS_USER_API_ENDPOINT = os.environ.get("USER_API_URL") + if not MSS_USER_API_ENDPOINT: + raise Exception("MSS_USER_ENDPOINT environment variable not set") # Creating a HTTP client http = urllib3.PoolManager() @@ -32,13 +33,11 @@ def lambda_handler(event, context): token = event["authorizationToken"].replace("Bearer ", "") print(f"token: {token}") - print(f"graph_endpoint: {GRAPH_MICROSOFT_ENDPOINT}") # Fetching the user information from the Microsoft Graph API - graph_endpoint = GRAPH_MICROSOFT_ENDPOINT methodArn = event["methodArn"] headers = {"Authorization": f"Bearer {token}"} - response = http.request("GET", graph_endpoint, headers=headers) + response = http.request("GET", MSS_USER_API_ENDPOINT + "/get-user", headers=headers) # Checking if the request was successful if response.status != 200: @@ -49,22 +48,7 @@ def lambda_handler(event, context): print("CHECK BEFORE REGEX") print(user_data) - - # Checking if the user is from Maua - email_regex = r"(^\d{2}\.\d{5}-\d@maua\.br$)|(^[a-zA-Z]+\.[a-zA-Z]+@maua\.br$)" # Regex to match the Maua email - if not re.match(email_regex, user_data.get("mail", "")): - return generate_policy("user", "Deny", methodArn) - - - # TODO -> implementar o método de get user, pode ser pelo e-mail ou pelo user_id, usando o Repositorio - - print("USER_ID: ", user_data.get("id", "did not find id")) - - user_repo = Environments.get_user_repo()() - user = user_repo.get_user(user_id=user_data.get("id")) - - print("CHECK PASSED REGEX AND GET USER") - + policy = generate_policy( user_data.get("id", "user"), "Allow", methodArn, {"user": json.dumps(user_data)} ) From a387d0cc1dc1c2be91a1ef1ff062f2cadf03cb85 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Mon, 14 Jul 2025 16:46:58 -0300 Subject: [PATCH 046/167] added role validation login --- .../app/delete_court_controller.py | 5 +++++ .../app/delete_court_presenter.py | 20 +++++++++++++------ .../delete_court/app/delete_court_usecase.py | 7 +++++-- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/modules/delete_court/app/delete_court_controller.py b/src/modules/delete_court/app/delete_court_controller.py index 7902822..ebb5523 100644 --- a/src/modules/delete_court/app/delete_court_controller.py +++ b/src/modules/delete_court/app/delete_court_controller.py @@ -8,6 +8,7 @@ from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, Created, InternalServerError, NotFound from src.shared.domain.enums.status_enum import STATUS +from src.shared.clients.user_api_client import UserAPIClient class DeleteCourtController: @@ -19,6 +20,10 @@ def __call__(self, request: IRequest) -> IResponse: if request.data.get('number') is None: raise MissingParameters('number') + if request.data.get('user_from_authorizer') is None: + raise MissingParameters('user') + + user = request.data.get("user_from_authorizer") court = self.usecase(number=request.data.get('number')) viewmodel = DeleteCourtViewModel(court) diff --git a/src/modules/delete_court/app/delete_court_presenter.py b/src/modules/delete_court/app/delete_court_presenter.py index bd8d419..f267d49 100644 --- a/src/modules/delete_court/app/delete_court_presenter.py +++ b/src/modules/delete_court/app/delete_court_presenter.py @@ -1,15 +1,23 @@ from .delete_court_controller import DeleteCourtController from .delete_court_usecase import DeleteCourtUsecase -from src.shared.environments import Environments from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse +from src.shared.environments import Environments -repo = Environments.get_reservation_repo()() +repo = Environments.get_user_repo()() usecase = DeleteCourtUsecase(repo) controller = DeleteCourtController(usecase) -def lambda_handler(event, context): + +def delete_court_presenter(event, context): httpRequest = LambdaHttpRequest(data=event) - response = controller(request=httpRequest) + httpRequest.data['user_from_authorizer'] = event.get('requestContext', {}).get('authorizer', {}).get('user', None) + response = controller(httpRequest) httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) - - return httpResponse.toDict() \ No newline at end of file + + return httpResponse.toDict() + + +def lambda_handler(event, context): + response = delete_court_presenter(event, context) + + return response diff --git a/src/modules/delete_court/app/delete_court_usecase.py b/src/modules/delete_court/app/delete_court_usecase.py index e13d719..425b1e6 100644 --- a/src/modules/delete_court/app/delete_court_usecase.py +++ b/src/modules/delete_court/app/delete_court_usecase.py @@ -2,18 +2,21 @@ from src.shared.domain.enums.status_enum import STATUS from src.shared.helpers.errors.usecase_errors import DuplicatedItem from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.errors.usecase_errors import NoItemsFound, ForbiddenAction from src.shared.domain.repositories.reservation_repository_interface import IReservationRepository class DeleteCourtUsecase: def __init__(self, repo:IReservationRepository): self.repo = repo - def __call__(self, number: int): + def __call__(self, number: int, role: str): if not Court.validate_number(number): raise EntityError('number') + if role != "ADMIN": + raise ForbiddenAction() + court = self.repo.delete_court(number=number) if court is None: From 2b3004e377ebe557042374694f2ee877f41d600f Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Mon, 14 Jul 2025 17:07:13 -0300 Subject: [PATCH 047/167] fixed tests --- .../app/delete_court_controller.py | 2 +- .../app/delete_court_presenter.py | 2 +- .../delete_court/app/delete_court_usecase.py | 2 +- .../app/test_delete_court_controller.py | 50 +++++++++++++++++-- .../app/test_delete_court_presenter.py | 32 ++++++++++++ .../app/test_delete_court_usecase.py | 17 +++++-- .../app/test_delete_court_viewmodel.py | 2 +- 7 files changed, 93 insertions(+), 14 deletions(-) diff --git a/src/modules/delete_court/app/delete_court_controller.py b/src/modules/delete_court/app/delete_court_controller.py index ebb5523..73f1b6b 100644 --- a/src/modules/delete_court/app/delete_court_controller.py +++ b/src/modules/delete_court/app/delete_court_controller.py @@ -24,7 +24,7 @@ def __call__(self, request: IRequest) -> IResponse: raise MissingParameters('user') user = request.data.get("user_from_authorizer") - court = self.usecase(number=request.data.get('number')) + court = self.usecase(number=request.data.get('number'), role=user.get("role")) viewmodel = DeleteCourtViewModel(court) return OK(viewmodel.to_dict()) diff --git a/src/modules/delete_court/app/delete_court_presenter.py b/src/modules/delete_court/app/delete_court_presenter.py index f267d49..c069ceb 100644 --- a/src/modules/delete_court/app/delete_court_presenter.py +++ b/src/modules/delete_court/app/delete_court_presenter.py @@ -3,7 +3,7 @@ from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse from src.shared.environments import Environments -repo = Environments.get_user_repo()() +repo = Environments.get_reservation_repo()() usecase = DeleteCourtUsecase(repo) controller = DeleteCourtController(usecase) diff --git a/src/modules/delete_court/app/delete_court_usecase.py b/src/modules/delete_court/app/delete_court_usecase.py index 425b1e6..8904cc1 100644 --- a/src/modules/delete_court/app/delete_court_usecase.py +++ b/src/modules/delete_court/app/delete_court_usecase.py @@ -15,7 +15,7 @@ def __call__(self, number: int, role: str): raise EntityError('number') if role != "ADMIN": - raise ForbiddenAction() + raise ForbiddenAction("user, only admin can delete courts") court = self.repo.delete_court(number=number) diff --git a/tests/modules/delete_court/app/test_delete_court_controller.py b/tests/modules/delete_court/app/test_delete_court_controller.py index bdca3bf..fe9f7c7 100644 --- a/tests/modules/delete_court/app/test_delete_court_controller.py +++ b/tests/modules/delete_court/app/test_delete_court_controller.py @@ -9,7 +9,15 @@ def test_delete_court_controller(self): usecase = DeleteCourtUsecase(repo= repo) controller = DeleteCourtController(usecase=usecase) request = HttpRequest(body= { - "number": 2 + "number": 2, + "user_from_authorizer": { + "name": "Dummy", + "email": "admin@maua.br", + "user_id": "user_id", + "ra": None, + "role": "ADMIN", + "confirm_user": False + } }) response = controller(request) @@ -22,7 +30,15 @@ def test_delete_court_controller_missing_number(self): usecase = DeleteCourtUsecase(repo= repo) controller = DeleteCourtController(usecase=usecase) request = HttpRequest(body={ - "number": None + "number": None, + "user_from_authorizer": { + "name": "Dummy", + "email": "admin@maua.br", + "user_id": "user_id", + "ra": None, + "role": "ADMIN", + "confirm_user": False + } }) response = controller(request) @@ -34,7 +50,15 @@ def test_delete_court_controller_number_entity_error(self): usecase = DeleteCourtUsecase(repo= repo) controller = DeleteCourtController(usecase=usecase) request = HttpRequest(body={ - "number": 0 + "number": 0, + "user_from_authorizer": { + "name": "Dummy", + "email": "admin@maua.br", + "user_id": "user_id", + "ra": None, + "role": "ADMIN", + "confirm_user": False + } }) reponse = controller(request) @@ -46,7 +70,15 @@ def test_delete_court_controller_wrong_type_parameter(self): usecase = DeleteCourtUsecase(repo=repo) controller = DeleteCourtController(usecase=usecase) request = HttpRequest(body={ - "number": "wrong_type" + "number": "wrong_type", + "user_from_authorizer": { + "name": "Dummy", + "email": "admin@maua.br", + "user_id": "user_id", + "ra": None, + "role": "ADMIN", + "confirm_user": False + } }) response = controller(request) @@ -58,7 +90,15 @@ def test_delete_court_controller_not_found(self): usecase = DeleteCourtUsecase(repo=repo) controller = DeleteCourtController(usecase=usecase) request = HttpRequest(body={ - "number": 10 + "number": 10, + "user_from_authorizer": { + "name": "Dummy", + "email": "admin@maua.br", + "user_id": "user_id", + "ra": None, + "role": "ADMIN", + "confirm_user": False + } }) response = controller(request) diff --git a/tests/modules/delete_court/app/test_delete_court_presenter.py b/tests/modules/delete_court/app/test_delete_court_presenter.py index a14b441..9c43d39 100644 --- a/tests/modules/delete_court/app/test_delete_court_presenter.py +++ b/tests/modules/delete_court/app/test_delete_court_presenter.py @@ -25,6 +25,14 @@ def test_delete_court_presenter(self): "apiId": "", "authentication": None, "authorizer": { + "user": + { + "id": "dummy_id", + "email": "dumm_yemail", + "name": "dummy_name", + "ra": None, + "role": "ADMIN", + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -74,6 +82,14 @@ def test_delete_court_presenter_missing_number(self): "apiId": "", "authentication": None, "authorizer": { + "user": + { + "id": "dummy_id", + "email": "dumm_yemail", + "name": "dummy_name", + "ra": None, + "role": "ADMIN", + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -123,6 +139,14 @@ def test_delete_court_not_found(self): "apiId": "", "authentication": None, "authorizer": { + "user": + { + "id": "dummy_id", + "email": "dumm_yemail", + "name": "dummy_name", + "ra": None, + "role": "ADMIN", + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -172,6 +196,14 @@ def test_delete_court_wrong_type(self): "apiId": "", "authentication": None, "authorizer": { + "user": + { + "id": "dummy_id", + "email": "dumm_yemail", + "name": "dummy_name", + "ra": None, + "role": "ADMIN", + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", diff --git a/tests/modules/delete_court/app/test_delete_court_usecase.py b/tests/modules/delete_court/app/test_delete_court_usecase.py index a58d416..78c4eec 100644 --- a/tests/modules/delete_court/app/test_delete_court_usecase.py +++ b/tests/modules/delete_court/app/test_delete_court_usecase.py @@ -6,16 +6,23 @@ from src.shared.helpers.errors.domain_errors import EntityError from src.modules.delete_court.app.delete_court_usecase import DeleteCourtUsecase from src.shared.infra.repositories.reservation_repository_mock import ReservationRepositoryMock -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.errors.usecase_errors import NoItemsFound, ForbiddenAction from src.shared.domain.repositories.reservation_repository_interface import IReservationRepository class Test_DeleteCourtUsecase: + + def test_delete_court_usecase_forbidden(self): + repo = ReservationRepositoryMock() + usecase = DeleteCourtUsecase(repo=repo) + with pytest.raises(ForbiddenAction): + court = usecase(number=1, role="STUDENT") + def test_delete_court_usecase(self): repo = ReservationRepositoryMock() usecase = DeleteCourtUsecase(repo=repo) len_before = len(repo.courts) - court = usecase(number=1) + court = usecase(number=1, role="ADMIN") assert len(repo.courts) == len_before - 1 assert court.number == 1 @@ -23,16 +30,16 @@ def test_delete_court_usecase_no_items_found(self): repo = ReservationRepositoryMock() usecase = DeleteCourtUsecase(repo=repo) with pytest.raises(NoItemsFound): - court = usecase(number=10) + court = usecase(number=10, role="ADMIN") def test_delete_court_usecase_invalid_number(self): repo = ReservationRepositoryMock() usecase = DeleteCourtUsecase(repo=repo) with pytest.raises(EntityError): - usecase(number=-1) + usecase(number=-1, role="ADMIN") with pytest.raises(EntityError): - usecase(number=None) + usecase(number=None, role="ADMIN") \ No newline at end of file diff --git a/tests/modules/delete_court/app/test_delete_court_viewmodel.py b/tests/modules/delete_court/app/test_delete_court_viewmodel.py index 6abda91..a468098 100644 --- a/tests/modules/delete_court/app/test_delete_court_viewmodel.py +++ b/tests/modules/delete_court/app/test_delete_court_viewmodel.py @@ -8,7 +8,7 @@ class Test_DeleteCourtViewModel: def test_delete_court_viewmodel(self): repo = ReservationRepositoryMock() usecase = DeleteCourtUsecase(repo=repo) - court = usecase(number=repo.courts[0].number) + court = usecase(number=repo.courts[0].number, role="ADMIN") viewmodel = DeleteCourtViewModel(court=court).to_dict() expected = { From 0296e5865db91f2d5583ced48711becf327e3a51 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Mon, 14 Jul 2025 17:23:00 -0300 Subject: [PATCH 048/167] bringing changes from auth to test in aws console --- .../app/delete_court_controller.py | 7 +- .../app/delete_court_presenter.py | 18 +++- .../delete_court/app/delete_court_usecase.py | 7 +- src/shared/authorizer/user_mss_authorizer.py | 102 ++++++++++++++++++ .../app/test_delete_court_controller.py | 50 ++++++++- .../app/test_delete_court_presenter.py | 32 ++++++ .../app/test_delete_court_usecase.py | 17 ++- .../app/test_delete_court_viewmodel.py | 2 +- 8 files changed, 216 insertions(+), 19 deletions(-) create mode 100644 src/shared/authorizer/user_mss_authorizer.py diff --git a/src/modules/delete_court/app/delete_court_controller.py b/src/modules/delete_court/app/delete_court_controller.py index 7902822..73f1b6b 100644 --- a/src/modules/delete_court/app/delete_court_controller.py +++ b/src/modules/delete_court/app/delete_court_controller.py @@ -8,6 +8,7 @@ from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, Created, InternalServerError, NotFound from src.shared.domain.enums.status_enum import STATUS +from src.shared.clients.user_api_client import UserAPIClient class DeleteCourtController: @@ -19,7 +20,11 @@ def __call__(self, request: IRequest) -> IResponse: if request.data.get('number') is None: raise MissingParameters('number') - court = self.usecase(number=request.data.get('number')) + if request.data.get('user_from_authorizer') is None: + raise MissingParameters('user') + + user = request.data.get("user_from_authorizer") + court = self.usecase(number=request.data.get('number'), role=user.get("role")) viewmodel = DeleteCourtViewModel(court) return OK(viewmodel.to_dict()) diff --git a/src/modules/delete_court/app/delete_court_presenter.py b/src/modules/delete_court/app/delete_court_presenter.py index bd8d419..c069ceb 100644 --- a/src/modules/delete_court/app/delete_court_presenter.py +++ b/src/modules/delete_court/app/delete_court_presenter.py @@ -1,15 +1,23 @@ from .delete_court_controller import DeleteCourtController from .delete_court_usecase import DeleteCourtUsecase -from src.shared.environments import Environments from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse +from src.shared.environments import Environments repo = Environments.get_reservation_repo()() usecase = DeleteCourtUsecase(repo) controller = DeleteCourtController(usecase) -def lambda_handler(event, context): + +def delete_court_presenter(event, context): httpRequest = LambdaHttpRequest(data=event) - response = controller(request=httpRequest) + httpRequest.data['user_from_authorizer'] = event.get('requestContext', {}).get('authorizer', {}).get('user', None) + response = controller(httpRequest) httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) - - return httpResponse.toDict() \ No newline at end of file + + return httpResponse.toDict() + + +def lambda_handler(event, context): + response = delete_court_presenter(event, context) + + return response diff --git a/src/modules/delete_court/app/delete_court_usecase.py b/src/modules/delete_court/app/delete_court_usecase.py index e13d719..8904cc1 100644 --- a/src/modules/delete_court/app/delete_court_usecase.py +++ b/src/modules/delete_court/app/delete_court_usecase.py @@ -2,18 +2,21 @@ from src.shared.domain.enums.status_enum import STATUS from src.shared.helpers.errors.usecase_errors import DuplicatedItem from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.errors.usecase_errors import NoItemsFound, ForbiddenAction from src.shared.domain.repositories.reservation_repository_interface import IReservationRepository class DeleteCourtUsecase: def __init__(self, repo:IReservationRepository): self.repo = repo - def __call__(self, number: int): + def __call__(self, number: int, role: str): if not Court.validate_number(number): raise EntityError('number') + if role != "ADMIN": + raise ForbiddenAction("user, only admin can delete courts") + court = self.repo.delete_court(number=number) if court is None: diff --git a/src/shared/authorizer/user_mss_authorizer.py b/src/shared/authorizer/user_mss_authorizer.py new file mode 100644 index 0000000..9779615 --- /dev/null +++ b/src/shared/authorizer/user_mss_authorizer.py @@ -0,0 +1,102 @@ +import os +import re +import json +import urllib3 + +from src.shared.environments import Environments + + +def lambda_handler(event, context): + """ + This function is used to authorize the user to access the API Gateway. + It uses the Microsoft Graph API to fetch the user information and check if the user is from Maua. + + Args: + event (dict): The event data passed to the Lambda function. + context (object): The context object representing the current invocation. + + Returns: + dict: The response object containing the policy document. + """ + + try: + + # Fetch the User Mss enpoint from the environment variables + MSS_USER_API_ENDPOINT = os.environ.get("USER_API_URL") + if not MSS_USER_API_ENDPOINT: + raise Exception("MSS_USER_ENDPOINT environment variable not set") + + # Creating a HTTP client + http = urllib3.PoolManager() + + # Extracting the token from the event data + token = event["authorizationToken"].replace("Bearer ", "") + + print(f"token: {token}") + + # Fetching the user information from the Microsoft Graph API + methodArn = event["methodArn"] + headers = {"Authorization": f"Bearer {token}"} + response = http.request("GET", MSS_USER_API_ENDPOINT + "/get-user", headers=headers) + + # Checking if the request was successful + if response.status != 200: + raise Exception("Failed to fetch user information") + + # Parsing the user data + user_data = json.loads(response.data.decode("utf-8")) + + print("CHECK BEFORE REGEX") + print(user_data) + + policy = generate_policy( + user_data.get("id", "user"), "Allow", methodArn, {"user": json.dumps(user_data)} + ) + + print(policy) + + return policy + + # Handling exceptions + except Exception as e: + print(f"Error: {e}") + methodArn = event["methodArn"] + return generate_policy("user", "Deny", methodArn) + + +def generate_policy(principal_id, effect, method_arn, context=None): + ''' + This function generates the policy document based on the principal ID, effect, method ARN, and context. + + Args: + principal_id (str): The principal ID. + effect (str): The effect (Allow or Deny). + method_arn (str): The method ARN. + context (dict): The context object. + + Returns: + dict: The policy document. + ''' + + # Generating the policy document + auth_response = {"principalId": principal_id} + + if effect: + policy_document = { + "Version": "2012-10-17", # Version of the policy + "Statement": [ + { + "Action": "execute-api:Invoke", # Action to allow + "Effect": effect, # Effect (Allow or Deny) + "Resource": method_arn, # Resource path + } + ], + } + auth_response["policyDocument"] = policy_document + + if context: + auth_response["context"] = context # Adding the context to the response + + print("PASSED AUTH RESPONSE") + + return auth_response \ No newline at end of file diff --git a/tests/modules/delete_court/app/test_delete_court_controller.py b/tests/modules/delete_court/app/test_delete_court_controller.py index bdca3bf..fe9f7c7 100644 --- a/tests/modules/delete_court/app/test_delete_court_controller.py +++ b/tests/modules/delete_court/app/test_delete_court_controller.py @@ -9,7 +9,15 @@ def test_delete_court_controller(self): usecase = DeleteCourtUsecase(repo= repo) controller = DeleteCourtController(usecase=usecase) request = HttpRequest(body= { - "number": 2 + "number": 2, + "user_from_authorizer": { + "name": "Dummy", + "email": "admin@maua.br", + "user_id": "user_id", + "ra": None, + "role": "ADMIN", + "confirm_user": False + } }) response = controller(request) @@ -22,7 +30,15 @@ def test_delete_court_controller_missing_number(self): usecase = DeleteCourtUsecase(repo= repo) controller = DeleteCourtController(usecase=usecase) request = HttpRequest(body={ - "number": None + "number": None, + "user_from_authorizer": { + "name": "Dummy", + "email": "admin@maua.br", + "user_id": "user_id", + "ra": None, + "role": "ADMIN", + "confirm_user": False + } }) response = controller(request) @@ -34,7 +50,15 @@ def test_delete_court_controller_number_entity_error(self): usecase = DeleteCourtUsecase(repo= repo) controller = DeleteCourtController(usecase=usecase) request = HttpRequest(body={ - "number": 0 + "number": 0, + "user_from_authorizer": { + "name": "Dummy", + "email": "admin@maua.br", + "user_id": "user_id", + "ra": None, + "role": "ADMIN", + "confirm_user": False + } }) reponse = controller(request) @@ -46,7 +70,15 @@ def test_delete_court_controller_wrong_type_parameter(self): usecase = DeleteCourtUsecase(repo=repo) controller = DeleteCourtController(usecase=usecase) request = HttpRequest(body={ - "number": "wrong_type" + "number": "wrong_type", + "user_from_authorizer": { + "name": "Dummy", + "email": "admin@maua.br", + "user_id": "user_id", + "ra": None, + "role": "ADMIN", + "confirm_user": False + } }) response = controller(request) @@ -58,7 +90,15 @@ def test_delete_court_controller_not_found(self): usecase = DeleteCourtUsecase(repo=repo) controller = DeleteCourtController(usecase=usecase) request = HttpRequest(body={ - "number": 10 + "number": 10, + "user_from_authorizer": { + "name": "Dummy", + "email": "admin@maua.br", + "user_id": "user_id", + "ra": None, + "role": "ADMIN", + "confirm_user": False + } }) response = controller(request) diff --git a/tests/modules/delete_court/app/test_delete_court_presenter.py b/tests/modules/delete_court/app/test_delete_court_presenter.py index a14b441..9c43d39 100644 --- a/tests/modules/delete_court/app/test_delete_court_presenter.py +++ b/tests/modules/delete_court/app/test_delete_court_presenter.py @@ -25,6 +25,14 @@ def test_delete_court_presenter(self): "apiId": "", "authentication": None, "authorizer": { + "user": + { + "id": "dummy_id", + "email": "dumm_yemail", + "name": "dummy_name", + "ra": None, + "role": "ADMIN", + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -74,6 +82,14 @@ def test_delete_court_presenter_missing_number(self): "apiId": "", "authentication": None, "authorizer": { + "user": + { + "id": "dummy_id", + "email": "dumm_yemail", + "name": "dummy_name", + "ra": None, + "role": "ADMIN", + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -123,6 +139,14 @@ def test_delete_court_not_found(self): "apiId": "", "authentication": None, "authorizer": { + "user": + { + "id": "dummy_id", + "email": "dumm_yemail", + "name": "dummy_name", + "ra": None, + "role": "ADMIN", + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -172,6 +196,14 @@ def test_delete_court_wrong_type(self): "apiId": "", "authentication": None, "authorizer": { + "user": + { + "id": "dummy_id", + "email": "dumm_yemail", + "name": "dummy_name", + "ra": None, + "role": "ADMIN", + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", diff --git a/tests/modules/delete_court/app/test_delete_court_usecase.py b/tests/modules/delete_court/app/test_delete_court_usecase.py index a58d416..78c4eec 100644 --- a/tests/modules/delete_court/app/test_delete_court_usecase.py +++ b/tests/modules/delete_court/app/test_delete_court_usecase.py @@ -6,16 +6,23 @@ from src.shared.helpers.errors.domain_errors import EntityError from src.modules.delete_court.app.delete_court_usecase import DeleteCourtUsecase from src.shared.infra.repositories.reservation_repository_mock import ReservationRepositoryMock -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.errors.usecase_errors import NoItemsFound, ForbiddenAction from src.shared.domain.repositories.reservation_repository_interface import IReservationRepository class Test_DeleteCourtUsecase: + + def test_delete_court_usecase_forbidden(self): + repo = ReservationRepositoryMock() + usecase = DeleteCourtUsecase(repo=repo) + with pytest.raises(ForbiddenAction): + court = usecase(number=1, role="STUDENT") + def test_delete_court_usecase(self): repo = ReservationRepositoryMock() usecase = DeleteCourtUsecase(repo=repo) len_before = len(repo.courts) - court = usecase(number=1) + court = usecase(number=1, role="ADMIN") assert len(repo.courts) == len_before - 1 assert court.number == 1 @@ -23,16 +30,16 @@ def test_delete_court_usecase_no_items_found(self): repo = ReservationRepositoryMock() usecase = DeleteCourtUsecase(repo=repo) with pytest.raises(NoItemsFound): - court = usecase(number=10) + court = usecase(number=10, role="ADMIN") def test_delete_court_usecase_invalid_number(self): repo = ReservationRepositoryMock() usecase = DeleteCourtUsecase(repo=repo) with pytest.raises(EntityError): - usecase(number=-1) + usecase(number=-1, role="ADMIN") with pytest.raises(EntityError): - usecase(number=None) + usecase(number=None, role="ADMIN") \ No newline at end of file diff --git a/tests/modules/delete_court/app/test_delete_court_viewmodel.py b/tests/modules/delete_court/app/test_delete_court_viewmodel.py index 6abda91..a468098 100644 --- a/tests/modules/delete_court/app/test_delete_court_viewmodel.py +++ b/tests/modules/delete_court/app/test_delete_court_viewmodel.py @@ -8,7 +8,7 @@ class Test_DeleteCourtViewModel: def test_delete_court_viewmodel(self): repo = ReservationRepositoryMock() usecase = DeleteCourtUsecase(repo=repo) - court = usecase(number=repo.courts[0].number) + court = usecase(number=repo.courts[0].number, role="ADMIN") viewmodel = DeleteCourtViewModel(court=court).to_dict() expected = { From 1c1b62b199739f0d90973fa50b251fae2d15686c Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Tue, 15 Jul 2025 21:06:19 -0300 Subject: [PATCH 049/167] =?UTF-8?q?feat:=20implementar=20l=C3=B3gica=20par?= =?UTF-8?q?a=20receber=20informa=C3=A7=C3=B5es=20do=20usu=C3=A1rio=20e=20v?= =?UTF-8?q?alida=C3=A7=C3=A3o=20no=20delete=5Fbooking?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/delete_booking/app/delete_booking_controller.py | 3 +++ src/modules/delete_booking/app/delete_booking_presenter.py | 3 +++ src/modules/delete_booking/app/delete_booking_usecase.py | 2 ++ src/shared/domain/repositories/booking_repository_interface.py | 3 +++ 4 files changed, 11 insertions(+) diff --git a/src/modules/delete_booking/app/delete_booking_controller.py b/src/modules/delete_booking/app/delete_booking_controller.py index e4de475..fb91b07 100644 --- a/src/modules/delete_booking/app/delete_booking_controller.py +++ b/src/modules/delete_booking/app/delete_booking_controller.py @@ -15,6 +15,9 @@ def __init__(self, usecase: DeleteBookingUsecase): self.usecase = usecase def __call__(self, request: IRequest) -> IResponse: + + # TODO: Fazer a lógica de receber o token e buscar o usuário. Mandar as infos do usuário para o usecase + try: if request.data.get('booking_id') is None: raise MissingParameters('booking_id') diff --git a/src/modules/delete_booking/app/delete_booking_presenter.py b/src/modules/delete_booking/app/delete_booking_presenter.py index 5183e6f..582fa47 100644 --- a/src/modules/delete_booking/app/delete_booking_presenter.py +++ b/src/modules/delete_booking/app/delete_booking_presenter.py @@ -9,6 +9,9 @@ def lambda_handler(event, context): httpRequest = LambdaHttpRequest(data=event) + print(event) + print("PRINT DO EVENT TA AQUI") + httpRequest.data['user_from_authorizer'] = event.get('requestContext', {}).get('authorizer', {}).get('user', None) response = controller(request=httpRequest) httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) diff --git a/src/modules/delete_booking/app/delete_booking_usecase.py b/src/modules/delete_booking/app/delete_booking_usecase.py index 09f07ef..3ad59dc 100644 --- a/src/modules/delete_booking/app/delete_booking_usecase.py +++ b/src/modules/delete_booking/app/delete_booking_usecase.py @@ -11,6 +11,8 @@ def __init__(self, repo:IReservationRepository): def __call__(self, booking_id: int): + # TODO: receber as infos do usuário e ver se tem "role" e "email". + if not Booking.validate_booking_id(booking_id): raise EntityError('booking_id') diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index ebcb773..3d1cbab 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -35,6 +35,7 @@ def get_booking(self, booking_id: str) -> Optional[Booking]: ''' pass + # TODO: arrumar a lógica para receber as infos do usuário, validar se ele pode realizar a operação + enviar e-mail @abstractmethod def delete_booking(self, booking_id: int) -> Optional[Booking]: ''' @@ -56,3 +57,5 @@ def get_all_users(self) -> List[str]: Returns name users by user id ''' pass + + # TODO: método para enviar e-mail para o usuário From 1bd0e7e30be225e2ddf109922352a262aff16f17 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Fri, 18 Jul 2025 11:55:36 -0300 Subject: [PATCH 050/167] added auth login to create court --- .../app/create_court_controller.py | 7 +++- .../app/create_court_presenter.py | 1 + .../create_court/app/create_court_usecase.py | 7 +++- .../app/test_create_court_controller.py | 40 +++++++++++++++---- .../app/test_create_court_presenter.py | 6 +++ .../app/test_create_court_usecase.py | 8 ++-- 6 files changed, 54 insertions(+), 15 deletions(-) diff --git a/src/modules/create_court/app/create_court_controller.py b/src/modules/create_court/app/create_court_controller.py index 8ebc8ef..00b8b01 100644 --- a/src/modules/create_court/app/create_court_controller.py +++ b/src/modules/create_court/app/create_court_controller.py @@ -15,7 +15,7 @@ def __init__(self, usecase: CreateCourtUsecase): def __call__(self, request: IRequest): - try: + try: if request.data.get('number') is None: raise MissingParameters('number') @@ -39,11 +39,14 @@ def __call__(self, request: IRequest): if request.data.get('photo') is not None and type(request.data.get('photo')) is not str: raise WrongTypeParameter(fieldName= 'photo', fieldTypeExpected= str, fieldTypeReceived= type(request.data.get('photo'))) + user = request.data.get("user_from_authorizer") + court = self.usecase( number= request.data.get('number'), status= status, is_field= request.data.get('is_field'), - photo= request.data.get('photo') + photo= request.data.get('photo'), + role=user.get("role") ) viewmodel = CreateCourtViewmodel(court= court) diff --git a/src/modules/create_court/app/create_court_presenter.py b/src/modules/create_court/app/create_court_presenter.py index 88639b0..44afbd7 100644 --- a/src/modules/create_court/app/create_court_presenter.py +++ b/src/modules/create_court/app/create_court_presenter.py @@ -9,6 +9,7 @@ def lambda_handler(event, context): httpRequest = LambdaHttpRequest(data=event) + httpRequest.data['user_from_authorizer'] = event.get('requestContext', {}).get('authorizer', {}).get('user', None) response = controller(request=httpRequest) httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) diff --git a/src/modules/create_court/app/create_court_usecase.py b/src/modules/create_court/app/create_court_usecase.py index 35bb56b..9a9068c 100644 --- a/src/modules/create_court/app/create_court_usecase.py +++ b/src/modules/create_court/app/create_court_usecase.py @@ -1,17 +1,20 @@ from typing import Optional from src.shared.domain.entities.court import Court from src.shared.domain.enums.status_enum import STATUS -from src.shared.helpers.errors.usecase_errors import DuplicatedItem +from src.shared.helpers.errors.usecase_errors import DuplicatedItem, ForbiddenAction from src.shared.domain.repositories.reservation_repository_interface import IReservationRepository class CreateCourtUsecase: def __init__(self, repo: IReservationRepository): self.repo = repo - def __call__(self, number: int, status: STATUS, is_field: bool, photo: Optional[str] = None): + def __call__(self, number: int, status: STATUS, is_field: bool, role: str, photo: Optional[str] = None): if self.repo.get_court(number) is not None: raise DuplicatedItem('number') + + if role != "ADMIN": + raise ForbiddenAction("user, only admin can create courts") court = Court( number = number, diff --git a/tests/modules/create_court/app/test_create_court_controller.py b/tests/modules/create_court/app/test_create_court_controller.py index 5932464..df2de6a 100644 --- a/tests/modules/create_court/app/test_create_court_controller.py +++ b/tests/modules/create_court/app/test_create_court_controller.py @@ -12,7 +12,10 @@ def test_create_court_controller(self): "number": 7, "status": "AVAILABLE", "is_field": False, - "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/" + "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/", + "user_from_authorizer": { + "role": "ADMIN" + } }) response = controller(request) @@ -30,7 +33,10 @@ def test_create_court_controller_missing_number(self): request = HttpRequest(body={ "status": "AVAILABLE", "is_field": False, - "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/" + "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/", + "user_from_authorizer": { + "role": "ADMIN" + } }) response = controller(request) @@ -45,7 +51,10 @@ def test_create_court_controller_with_missing_status(self): request = HttpRequest(body={ "number": 7, "is_field": False, - "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/" + "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/", + "user_from_authorizer": { + "role": "ADMIN" + } }) response = controller(request) @@ -60,7 +69,10 @@ def test_create_court_controller_wrong_type_number(self): "number": "cavalo", "status": "AVAILABLE", "is_field": False, - "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/" + "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/", + "user_from_authorizer": { + "role": "ADMIN" + } }) reponse = controller(request) @@ -76,7 +88,10 @@ def test_create_court_controller_with_wrong_type_status(self): "number": 7, "status": 123, "is_field": False, - "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/" + "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/", + "user_from_authorizer": { + "role": "ADMIN" + } }) response = controller(request) @@ -91,7 +106,10 @@ def test_create_court_controllerwith_duplicated_item(self): "number": 1, "status": "AVAILABLE", "is_field": False, - "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/" + "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/", + "user_from_authorizer": { + "role": "ADMIN" + } }) response = controller(request) @@ -107,7 +125,10 @@ def test_create_court_controller_number_entity_error(self): "number": 0, "status": "AVAILABLE", "is_field": False, - "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/" + "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/", + "user_from_authorizer": { + "role": "ADMIN" + } }) reponse = controller(request) @@ -123,7 +144,10 @@ def test_create_court_controller_status_entity_error(self): "number": 7, "status": "INVALID", "is_field": False, - "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/" + "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/", + "user_from_authorizer": { + "role": "ADMIN" + } }) response = controller(request) diff --git a/tests/modules/create_court/app/test_create_court_presenter.py b/tests/modules/create_court/app/test_create_court_presenter.py index bf74fa5..3c3cf7d 100644 --- a/tests/modules/create_court/app/test_create_court_presenter.py +++ b/tests/modules/create_court/app/test_create_court_presenter.py @@ -25,6 +25,9 @@ def test_create_court_presenter(self): "apiId": "", "authentication": None, "authorizer": { + "user": { + "role":"ADMIN" + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -77,6 +80,9 @@ def test_create_court_presenter_missing_number(self): "apiId": "", "authentication": None, "authorizer": { + "user": { + "role":"ADMIN" + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", diff --git a/tests/modules/create_court/app/test_create_court_usecase.py b/tests/modules/create_court/app/test_create_court_usecase.py index f81659f..db5aec8 100644 --- a/tests/modules/create_court/app/test_create_court_usecase.py +++ b/tests/modules/create_court/app/test_create_court_usecase.py @@ -13,7 +13,8 @@ def test_create_court_usecase(self): number= 8, status= STATUS.AVAILABLE, is_field= False, - photo = "https://super.abril.com.br/mundo-estranho/os-poneis-sao-cavalos-anoes" + photo = "https://super.abril.com.br/mundo-estranho/os-poneis-sao-cavalos-anoes", + role="ADMIN" ) assert repo.courts[-1] == court @@ -28,7 +29,7 @@ def test_create_court_usecase_duplicated_item(self): usecase = CreateCourtUsecase(repo=repo) with pytest.raises(DuplicatedItem): - court = usecase(number= 2, status= STATUS.AVAILABLE, is_field= False, photo = None) + court = usecase(number= 2, status= STATUS.AVAILABLE, is_field= False, photo = None, role="ADMIN") def test_create_court_usecase_no_photo(self): repo = ReservationRepositoryMock() @@ -38,7 +39,8 @@ def test_create_court_usecase_no_photo(self): number= 7, status= STATUS.UNAVAILABLE, is_field = False, - photo = None + photo = None, + role="ADMIN" ) assert court.photo is None assert repo.courts[-1] == court From fe7ad42a2d44f8397798552986f4ec15bd85969e Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Fri, 18 Jul 2025 12:19:31 -0300 Subject: [PATCH 051/167] added auth logic to update_court, added forbidden action testing, added catching in controllers for forbidden action raises --- .../app/create_court_controller.py | 5 +- .../app/delete_court_controller.py | 5 +- .../app/update_court_controller.py | 10 +++- .../app/update_court_presenter.py | 1 + .../update_court/app/update_court_usecase.py | 6 ++- .../app/test_create_court_usecase.py | 16 ++++++- tests/modules/delete_court/__init__.py | 0 .../app/test_delete_court_usecase.py | 10 ++++ .../app/test_update_court_controller.py | 48 +++++++++++++++---- .../app/test_update_court_presenter.py | 27 +++++++++++ .../app/test_update_court_usecase.py | 27 +++++++++-- 11 files changed, 135 insertions(+), 20 deletions(-) create mode 100644 tests/modules/delete_court/__init__.py diff --git a/src/modules/create_court/app/create_court_controller.py b/src/modules/create_court/app/create_court_controller.py index 00b8b01..0f93da1 100644 --- a/src/modules/create_court/app/create_court_controller.py +++ b/src/modules/create_court/app/create_court_controller.py @@ -2,7 +2,7 @@ from .create_court_viewmodel import CreateCourtViewmodel from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.errors.usecase_errors import DuplicatedItem +from src.shared.helpers.errors.usecase_errors import DuplicatedItem, ForbiddenAction from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse from src.shared.helpers.external_interfaces.http_codes import BadRequest, Created, InternalServerError from src.shared.domain.enums.status_enum import STATUS @@ -65,6 +65,9 @@ def __call__(self, request: IRequest): except EntityError as err: return BadRequest(body=err.message) + except ForbiddenAction as err: + return BadRequest(body=err.message) + except Exception as err: return InternalServerError(body=err.args[0]) diff --git a/src/modules/delete_court/app/delete_court_controller.py b/src/modules/delete_court/app/delete_court_controller.py index 73f1b6b..f1573bd 100644 --- a/src/modules/delete_court/app/delete_court_controller.py +++ b/src/modules/delete_court/app/delete_court_controller.py @@ -4,7 +4,7 @@ from .delete_court_viewmodel import DeleteCourtViewModel from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.errors.usecase_errors import NoItemsFound, ForbiddenAction from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, Created, InternalServerError, NotFound from src.shared.domain.enums.status_enum import STATUS @@ -41,5 +41,8 @@ def __call__(self, request: IRequest) -> IResponse: except EntityError as err: return BadRequest(body=err.message) + except ForbiddenAction as err: + return BadRequest(body=err.message) + except Exception as err: return InternalServerError(body=err.args[0]) \ No newline at end of file diff --git a/src/modules/update_court/app/update_court_controller.py b/src/modules/update_court/app/update_court_controller.py index e6b8fb7..1a50614 100644 --- a/src/modules/update_court/app/update_court_controller.py +++ b/src/modules/update_court/app/update_court_controller.py @@ -2,7 +2,7 @@ from .update_court_usecase import UpdateCourtUsecase from .update_court_viewmodel import UpdateCourtViewmodel from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.errors.usecase_errors import NoItemsFound, ForbiddenAction from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.external_interfaces.external_interface import IRequest from src.shared.helpers.external_interfaces.http_codes import BadRequest, OK, InternalServerError, NotFound @@ -35,11 +35,14 @@ def __call__(self, request: IRequest): if type(photo_str) is not str: raise WrongTypeParameter(fieldName='photo', fieldTypeExpected=str, fieldTypeReceived=type(request.data.get('photo'))) + + user = request.data.get("user_from_authorizer") court = self.usecase( number=request.data.get('number'), status=STATUS[status_str] if status_str is not None else None, - photo=photo_str + photo=photo_str, + role=user.get("role") ) viewmodel = UpdateCourtViewmodel(court=court) @@ -57,6 +60,9 @@ def __call__(self, request: IRequest): except EntityError as err: return BadRequest(body=err.message) + + except ForbiddenAction as err: + return BadRequest(body=err.message) except Exception as err: return InternalServerError(body=err.args[0]) \ No newline at end of file diff --git a/src/modules/update_court/app/update_court_presenter.py b/src/modules/update_court/app/update_court_presenter.py index b0dfe9d..289ec26 100644 --- a/src/modules/update_court/app/update_court_presenter.py +++ b/src/modules/update_court/app/update_court_presenter.py @@ -10,6 +10,7 @@ def lambda_handler(event, context): httpRequest = LambdaHttpRequest(data=event) + httpRequest.data['user_from_authorizer'] = event.get('requestContext', {}).get('authorizer', {}).get('user', None) response = controller(request=httpRequest) httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) diff --git a/src/modules/update_court/app/update_court_usecase.py b/src/modules/update_court/app/update_court_usecase.py index b26bef4..b2220bc 100644 --- a/src/modules/update_court/app/update_court_usecase.py +++ b/src/modules/update_court/app/update_court_usecase.py @@ -2,7 +2,7 @@ from src.shared.domain.entities.court import Court from src.shared.domain.enums.status_enum import STATUS from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.errors.usecase_errors import NoItemsFound, ForbiddenAction from src.shared.domain.repositories.reservation_repository_interface import IReservationRepository @@ -12,6 +12,7 @@ def __init__(self, repo: IReservationRepository): def __call__(self, number: int, + role: str, status: Optional[STATUS] = None, photo: Optional[str] = None): @@ -24,6 +25,9 @@ def __call__(self, if self.repo.get_court(number) is None: raise NoItemsFound(f'number: {number}') + + if role != "ADMIN": + raise ForbiddenAction("user, only admin can update courts") court = self.repo.update_court(number=number, status=status, diff --git a/tests/modules/create_court/app/test_create_court_usecase.py b/tests/modules/create_court/app/test_create_court_usecase.py index db5aec8..70993b2 100644 --- a/tests/modules/create_court/app/test_create_court_usecase.py +++ b/tests/modules/create_court/app/test_create_court_usecase.py @@ -1,7 +1,7 @@ import pytest from src.modules.create_court.app.create_court_usecase import CreateCourtUsecase from src.shared.infra.repositories.reservation_repository_mock import ReservationRepositoryMock -from src.shared.helpers.errors.usecase_errors import DuplicatedItem +from src.shared.helpers.errors.usecase_errors import DuplicatedItem, ForbiddenAction from src.shared.domain.enums.status_enum import STATUS class TestCreateCourtUsecase: @@ -46,5 +46,19 @@ def test_create_court_usecase_no_photo(self): assert repo.courts[-1] == court assert court.number == 7 + def test_create_court_usecase_not_admin(self): + + repo = ReservationRepositoryMock() + Usecase = CreateCourtUsecase(repo=repo) + + with pytest.raises(ForbiddenAction): + court = Usecase( + number= 7, + status= STATUS.UNAVAILABLE, + is_field = False, + photo = None, + role="STUDENT" + ) + \ No newline at end of file diff --git a/tests/modules/delete_court/__init__.py b/tests/modules/delete_court/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/modules/delete_court/app/test_delete_court_usecase.py b/tests/modules/delete_court/app/test_delete_court_usecase.py index 78c4eec..e3e9b1b 100644 --- a/tests/modules/delete_court/app/test_delete_court_usecase.py +++ b/tests/modules/delete_court/app/test_delete_court_usecase.py @@ -41,5 +41,15 @@ def test_delete_court_usecase_invalid_number(self): with pytest.raises(EntityError): usecase(number=None, role="ADMIN") + + def test_delete_court_usecase_not_admin(self): + repo = ReservationRepositoryMock() + usecase = DeleteCourtUsecase(repo=repo) + + with pytest.raises(ForbiddenAction): + usecase(number=1, role="STUDENT") + + assert repo.get_court(1) != None + \ No newline at end of file diff --git a/tests/modules/update_court/app/test_update_court_controller.py b/tests/modules/update_court/app/test_update_court_controller.py index 118c53f..bd048be 100644 --- a/tests/modules/update_court/app/test_update_court_controller.py +++ b/tests/modules/update_court/app/test_update_court_controller.py @@ -14,7 +14,10 @@ def test_update_court_controller_two_params(self): request = HttpRequest(body={ "number": court_number, "status": "MAINTENANCE", - "photo": "https://www.linkedin.com/in/leonardo-iorio-b83360279/" + "photo": "https://www.linkedin.com/in/leonardo-iorio-b83360279/", + "user_from_authorizer": { + "role": "ADMIN" + } }) response = controller(request) @@ -34,6 +37,9 @@ def test_update_court_controller_only_status_param(self): request = HttpRequest(body={ "number": court_number, "status": "MAINTENANCE", + "user_from_authorizer": { + "role": "ADMIN" + } }) response = controller(request) @@ -52,7 +58,10 @@ def test_update_court_controller_only_photo_param(self): request = HttpRequest(body={ "number": court_number, - "photo": "photostr" + "photo": "photostr", + "user_from_authorizer": { + "role": "ADMIN" + } }) response = controller(request) @@ -71,7 +80,10 @@ def test_update_court_controller_missing_number(self): request = HttpRequest(body={ "status": "AVAILABLE", "is_field": False, - "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/" + "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/", + "user_from_authorizer": { + "role": "ADMIN" + } }) response = controller(request) @@ -87,7 +99,10 @@ def test_update_court_controller_wrong_type_number(self): "number": "cavalo", "status": "AVAILABLE", "is_field": False, - "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/" + "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/", + "user_from_authorizer": { + "role": "ADMIN" + } }) reponse = controller(request) @@ -104,7 +119,10 @@ def test_update_court_controller_with_wrong_type_status(self): "number": 7, "status": 123, "is_field": False, - "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/" + "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/", + "user_from_authorizer": { + "role": "ADMIN" + } }) response = controller(request) @@ -120,7 +138,10 @@ def test_update_court_controller_status_entity_error(self): "number": 7, "status": "INVALID", "is_field": False, - "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/" + "photo": "https://www.linkedin.com/in/vinicius-berti-a80354209/", + "user_from_authorizer": { + "role": "ADMIN" + } }) response = controller(request) @@ -136,7 +157,10 @@ def test_update_court_controller_photo_type_error(self): "number": 7, "status": "AVAILABLE", "is_field": False, - "photo": 1337 + "photo": 1337, + "user_from_authorizer": { + "role": "ADMIN" + } }) response = controller(request) @@ -152,7 +176,10 @@ def test_update_court_controller_number_not_found(self): "number": 9, "status": "AVAILABLE", "is_field": False, - "photo": "1234" + "photo": "1234", + "user_from_authorizer": { + "role": "ADMIN" + } }) response = controller(request) @@ -168,7 +195,10 @@ def test_update_court_controller_invalid_number(self): "number": -999, "status": "AVAILABLE", "is_field": False, - "photo": "1234" + "photo": "1234", + "user_from_authorizer": { + "role": "ADMIN" + } }) response = controller(request) diff --git a/tests/modules/update_court/app/test_update_court_presenter.py b/tests/modules/update_court/app/test_update_court_presenter.py index 6fa0f82..afe7c3f 100644 --- a/tests/modules/update_court/app/test_update_court_presenter.py +++ b/tests/modules/update_court/app/test_update_court_presenter.py @@ -25,6 +25,9 @@ def test_update_court_presenter_one_param(self): "apiId": "", "authentication": None, "authorizer": { + "user": { + "role": "ADMIN" + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -77,6 +80,9 @@ def test_update_court_presenter(self): "apiId": "", "authentication": None, "authorizer": { + "user": { + "role": "ADMIN" + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -130,6 +136,9 @@ def test_update_court_presenter_missing_number(self): "apiId": "", "authentication": None, "authorizer": { + "user": { + "role": "ADMIN" + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -179,6 +188,9 @@ def test_update_court_presenter_wrong_type_number(self): "apiId": "", "authentication": None, "authorizer": { + "user": { + "role": "ADMIN" + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -228,6 +240,9 @@ def test_update_court_presenter_wrong_type_status(self): "apiId": "", "authentication": None, "authorizer": { + "user": { + "role": "ADMIN" + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -278,6 +293,9 @@ def test_update_court_presenter_wrong_status_entity(self): "apiId": "", "authentication": None, "authorizer": { + "user": { + "role": "ADMIN" + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -327,6 +345,9 @@ def test_update_court_presenter_wrong_photo_type(self): "apiId": "", "authentication": None, "authorizer": { + "user": { + "role": "ADMIN" + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -376,6 +397,9 @@ def test_update_court_presenter_number_not_found(self): "apiId": "", "authentication": None, "authorizer": { + "user": { + "role": "ADMIN" + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -425,6 +449,9 @@ def test_update_court_presenter_invalid_number(self): "apiId": "", "authentication": None, "authorizer": { + "user": { + "role": "ADMIN" + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", diff --git a/tests/modules/update_court/app/test_update_court_usecase.py b/tests/modules/update_court/app/test_update_court_usecase.py index 4322ee6..4706b2a 100644 --- a/tests/modules/update_court/app/test_update_court_usecase.py +++ b/tests/modules/update_court/app/test_update_court_usecase.py @@ -2,7 +2,7 @@ from src.modules.update_court.app.update_court_usecase import UpdateCourtUsecase from src.shared.helpers.errors.domain_errors import EntityError from src.shared.infra.repositories.reservation_repository_mock import ReservationRepositoryMock -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.errors.usecase_errors import NoItemsFound, ForbiddenAction from src.shared.domain.enums.status_enum import STATUS @@ -16,7 +16,8 @@ def test_update_court_usecase(self): court = usecase( number=court_number, status=STATUS.MAINTENANCE, - photo="https://super.abril.com.br/mundo-estranho/os-poneis-sao-cavalos-anoes" + photo="https://super.abril.com.br/mundo-estranho/os-poneis-sao-cavalos-anoes", + role="ADMIN" ) assert repo.get_court(court_number).number == court.number @@ -32,7 +33,8 @@ def test_update_court_usecase_not_found_number(self): court = usecase( number=9, status=STATUS.MAINTENANCE, - photo="http://foto" + photo="http://foto", + role="ADMIN" ) def test_update_court_usecase_invalid_court_number(self): @@ -44,7 +46,8 @@ def test_update_court_usecase_invalid_court_number(self): court = usecase( number=-999, status=STATUS.MAINTENANCE, - photo="https://super.abril.com.br/mundo-estranho/os-poneis-sao-cavalos-anoes" + photo="https://super.abril.com.br/mundo-estranho/os-poneis-sao-cavalos-anoes", + role="ADMIN" ) def test_update_court_usecase_court_number_not_found(self): @@ -56,5 +59,19 @@ def test_update_court_usecase_court_number_not_found(self): court = usecase( number=9, status=STATUS.MAINTENANCE, - photo="https://super.abril.com.br/mundo-estranho/os-poneis-sao-cavalos-anoes" + photo="https://super.abril.com.br/mundo-estranho/os-poneis-sao-cavalos-anoes", + role="ADMIN" + ) + + def test_update_court_usecase_not_admin(self): + + repo = ReservationRepositoryMock() + usecase = UpdateCourtUsecase(repo=repo) + + with pytest.raises(ForbiddenAction): + court = usecase( + number=1, + status=STATUS.MAINTENANCE, + photo="https://super.abril.com.br/mundo-estranho/os-poneis-sao-cavalos-anoes", + role="STUDENT" ) From 71505dd042c15949b43257617db8b2180e40d795 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Fri, 18 Jul 2025 12:45:33 -0300 Subject: [PATCH 052/167] added authorizer functions and token to court routes --- iac/stacks/lambda_stack.py | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index b3cde43..bf452d2 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -3,6 +3,7 @@ from aws_cdk import ( aws_lambda as lambda_, NestedStack, Duration, + aws_apigateway as apigw ) from constructs import Construct from aws_cdk.aws_apigateway import Resource, LambdaIntegration @@ -77,6 +78,24 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment code=lambda_.Code.from_asset("./copied_shared"), compatible_runtimes=[lambda_.Runtime.PYTHON_3_9] ) + + authorizer_lambda = lambda_.Function( + self, "AuthorizerUserMssReservationApiLambda", + code=lambda_.Code.from_asset("../src/shared/authorizer"), + handler="user_mss_authorizer.lambda_handler", + runtime=lambda_.Runtime.PYTHON_3_9, + layers=[self.lambda_layer, self.lambda_power_tools], + environment=environment_variables, + timeout=Duration.seconds(15) + ) + + token_authorizer_lambda = apigw.TokenAuthorizer( + self, "TokenAuthorizerReservationApi", + handler=authorizer_lambda, + identity_source=apigw.IdentitySource.header("Authorization"), + authorizer_name="AuthorizerUserMssReservationMssAlertLambda", + results_cache_ttl=Duration.seconds(0) + ) self.create_booking = self.create_lambda_api_gateway_integration( module_name="create_booking", @@ -117,7 +136,8 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment module_name="create_court", method="POST", api_resource=api_gateway_resource, - environment_variables=environment_variables + environment_variables=environment_variables, + authorizer=token_authorizer_lambda ) self.get_court = self.create_lambda_api_gateway_integration( @@ -131,14 +151,16 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment module_name="update_court", method="PUT", api_resource=api_gateway_resource, - environment_variables=environment_variables + environment_variables=environment_variables, + authorizer=token_authorizer_lambda ) self.delete_court = self.create_lambda_api_gateway_integration( module_name="delete_court", method="DELETE", api_resource=api_gateway_resource, - environment_variables=environment_variables + environment_variables=environment_variables, + authorizer=token_authorizer_lambda ) self.get_all_courts = self.create_lambda_api_gateway_integration( From a475f375fe3b29b3a021cdb7b103895bbbd08c2c Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Fri, 18 Jul 2025 13:47:53 -0300 Subject: [PATCH 053/167] informative commit --- tests/clients/test_user_api_client.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/clients/test_user_api_client.py b/tests/clients/test_user_api_client.py index cc6e263..1d415e0 100644 --- a/tests/clients/test_user_api_client.py +++ b/tests/clients/test_user_api_client.py @@ -6,6 +6,7 @@ class TestUserAPIClient: # to test this, you must declare in your .env the user mss endpoint as USER_API_URL without # any route at the end (the user api client already adds the routing) + # ex: https://api-url/reservation-mss-user @pytest.mark.skip("Can't run test in github actions") def test_get_user(self): From 7e24417021a345c2b6bfc1c77c3345a5325f393e Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 18 Jul 2025 15:13:41 -0300 Subject: [PATCH 054/167] =?UTF-8?q?feat:=20adicionar=20l=C3=B3gica=20de=20?= =?UTF-8?q?valida=C3=A7=C3=A3o=20de=20usu=C3=A1rio=20na=20exclus=C3=A3o=20?= =?UTF-8?q?de=20reservas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/delete_booking_controller.py | 8 ++- .../app/delete_booking_usecase.py | 13 ++++- .../booking_repository_interface.py | 2 +- .../reservation_repository_interface.py | 4 +- .../repositories/booking_repository_mock.py | 23 +++++++-- .../app/test_delete_booking_controller.py | 35 +++++++++++-- .../app/test_delete_booking_presenter.py | 25 +++++++++- .../app/test_delete_booking_usecase.py | 50 +++++++++++++++++-- .../app/test_delete_booking_viewmodel.py | 7 ++- .../test_booking_repository_mock.py | 7 ++- 10 files changed, 153 insertions(+), 21 deletions(-) diff --git a/src/modules/delete_booking/app/delete_booking_controller.py b/src/modules/delete_booking/app/delete_booking_controller.py index fb91b07..03f5c80 100644 --- a/src/modules/delete_booking/app/delete_booking_controller.py +++ b/src/modules/delete_booking/app/delete_booking_controller.py @@ -19,9 +19,15 @@ def __call__(self, request: IRequest) -> IResponse: # TODO: Fazer a lógica de receber o token e buscar o usuário. Mandar as infos do usuário para o usecase try: + + if request.data.get('user_from_authorizer') is None: + raise MissingParameters('user authorizer') + + user = request.data.get('user_from_authorizer') + if request.data.get('booking_id') is None: raise MissingParameters('booking_id') - booking = self.usecase(booking_id=request.data.get('booking_id')) + booking = self.usecase(booking_id=request.data.get('booking_id'), user=user) viewmodel = DeleteBookingViewModel(booking) return OK(viewmodel.to_dict()) diff --git a/src/modules/delete_booking/app/delete_booking_usecase.py b/src/modules/delete_booking/app/delete_booking_usecase.py index 3ad59dc..6dedcd6 100644 --- a/src/modules/delete_booking/app/delete_booking_usecase.py +++ b/src/modules/delete_booking/app/delete_booking_usecase.py @@ -9,14 +9,23 @@ class DeleteBookingUsecase: def __init__(self, repo:IReservationRepository): self.repo = repo - def __call__(self, booking_id: int): + def __call__(self, booking_id: int, user): # TODO: receber as infos do usuário e ver se tem "role" e "email". + if user.get('user_id') is None: + raise EntityError('user id') + + if user.get('email') is None: + raise EntityError('user email') + + if user.get('role') is None: + raise EntityError('user role') + if not Booking.validate_booking_id(booking_id): raise EntityError('booking_id') - booking = self.repo.delete_booking(booking_id=booking_id) + booking = self.repo.delete_booking(booking_id=booking_id, user=user) if booking is None: raise NoItemsFound('booking') diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index 3d1cbab..f641824 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -37,7 +37,7 @@ def get_booking(self, booking_id: str) -> Optional[Booking]: # TODO: arrumar a lógica para receber as infos do usuário, validar se ele pode realizar a operação + enviar e-mail @abstractmethod - def delete_booking(self, booking_id: int) -> Optional[Booking]: + def delete_booking(self, booking_id: int, user) -> Optional[Booking]: ''' If booking exists, deletes it and returns it else returns None diff --git a/src/shared/domain/repositories/reservation_repository_interface.py b/src/shared/domain/repositories/reservation_repository_interface.py index 584f24f..4d30fe2 100644 --- a/src/shared/domain/repositories/reservation_repository_interface.py +++ b/src/shared/domain/repositories/reservation_repository_interface.py @@ -1,4 +1,6 @@ from abc import ABC, abstractmethod +from typing import Optional +from src.shared.domain.entities.booking import Booking from src.shared.domain.entities.court import Court from src.shared.domain.enums.status_enum import STATUS @@ -42,4 +44,4 @@ def get_all_courts(self): ''' Returns all courts ''' - pass + pass \ No newline at end of file diff --git a/src/shared/infra/repositories/booking_repository_mock.py b/src/shared/infra/repositories/booking_repository_mock.py index 5eb3a70..61c0d0d 100644 --- a/src/shared/infra/repositories/booking_repository_mock.py +++ b/src/shared/infra/repositories/booking_repository_mock.py @@ -2,6 +2,7 @@ from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT from src.shared.domain.repositories.booking_repository_interface import IBookingRepository +from src.shared.helpers.errors.usecase_errors import ForbiddenAction class BookingRepositoryMock(IBookingRepository): @@ -127,11 +128,27 @@ def get_booking(self, booking_id: str): return booking return None - def delete_booking(self, booking_id: str): + def delete_booking(self, booking_id: str, user): booking = self.get_booking(booking_id) + + user_role = user.get('role') + if booking is not None: - self.bookings.remove(booking) - return booking + + if user_role == 'ADMIN': + self.bookings.remove(booking) + return booking + + elif user_role == 'STUDENT': + + if booking.user_id == user.get('user_id'): + + self.bookings.remove(booking) + return booking + + else: + raise ForbiddenAction('user id') + return None def get_all_bookings(self) -> List[Booking]: diff --git a/tests/modules/delete_bookings/app/test_delete_booking_controller.py b/tests/modules/delete_bookings/app/test_delete_booking_controller.py index 399c28e..5ee112f 100644 --- a/tests/modules/delete_bookings/app/test_delete_booking_controller.py +++ b/tests/modules/delete_bookings/app/test_delete_booking_controller.py @@ -9,7 +9,12 @@ def test_delete_booking_controller(self): usecase = DeleteBookingUsecase(repo= repo) controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body= { - "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' + "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'email': 'user@email.com', + 'role': 'STUDENT' + } }) response = controller(request) @@ -21,7 +26,12 @@ def test_delete_booking_controller_missing_booking_id(self): usecase = DeleteBookingUsecase(repo= repo) controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body={ - "booking_id": None + "booking_id": None, + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'email': 'user@email.com', + 'role': 'STUDENT' + } }) response = controller(request) @@ -33,7 +43,12 @@ def test_delete_booking_controller_booking_id_entity_error(self): usecase = DeleteBookingUsecase(repo= repo) controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body={ - "booking_id": 0 + "booking_id": 0, + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'email': 'user@email.com', + 'role': 'STUDENT' + } }) reponse = controller(request) @@ -45,7 +60,12 @@ def test_delete_booking_controller_wrong_type_parameter(self): usecase = DeleteBookingUsecase(repo=repo) controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body={ - "booking_id": "wrong_type" + "booking_id": "wrong_type", + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'email': 'user@email.com', + 'role': 'STUDENT' + } }) response = controller(request) @@ -57,7 +77,12 @@ def test_delete_booking_controller_not_found(self): usecase = DeleteBookingUsecase(repo=repo) controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body={ - "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2926' + "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2926', + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'email': 'user@email.com', + 'role': 'STUDENT' + } }) response = controller(request) diff --git a/tests/modules/delete_bookings/app/test_delete_booking_presenter.py b/tests/modules/delete_bookings/app/test_delete_booking_presenter.py index 60812bd..ef2004e 100644 --- a/tests/modules/delete_bookings/app/test_delete_booking_presenter.py +++ b/tests/modules/delete_bookings/app/test_delete_booking_presenter.py @@ -25,6 +25,11 @@ def test_delete_booking_presenter(self): "apiId": "", "authentication": None, "authorizer": { + 'user': { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'email': 'user@email.com', + 'role': 'ADMIN' + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -41,13 +46,16 @@ def test_delete_booking_presenter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": '{"booking_id": "b1d3bebf-dc0d-4fc1-861c-506a40cc2925"}', + "body": { + "booking_id": "b1d3bebf-dc0d-4fc1-861c-506a40cc2925" + }, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None } response = lambda_handler(event, None) + print(response) assert response['statusCode'] == 200 assert json.loads(response['body'])['message'] == 'the booking was deleted' @@ -74,6 +82,11 @@ def test_delete_booking_presenter_missing_booking_id(self): "apiId": "", "authentication": None, "authorizer": { + 'user': { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'email': 'user@email.com', + 'role': 'ADMIN' + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -123,6 +136,11 @@ def test_delete_booking_not_found(self): "apiId": "", "authentication": None, "authorizer": { + 'user': { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'email': 'user@email.com', + 'role': 'ADMIN' + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -172,6 +190,11 @@ def test_delete_booking_wrong_type(self): "apiId": "", "authentication": None, "authorizer": { + 'user': { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'email': 'user@email.com', + 'role': 'ADMIN' + } }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", diff --git a/tests/modules/delete_bookings/app/test_delete_booking_usecase.py b/tests/modules/delete_bookings/app/test_delete_booking_usecase.py index 43d5d0d..9ab0e03 100644 --- a/tests/modules/delete_bookings/app/test_delete_booking_usecase.py +++ b/tests/modules/delete_bookings/app/test_delete_booking_usecase.py @@ -2,7 +2,7 @@ from typing import Any, Optional from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.status_enum import STATUS -from src.shared.helpers.errors.usecase_errors import DuplicatedItem +from src.shared.helpers.errors.usecase_errors import DuplicatedItem, ForbiddenAction from src.shared.helpers.errors.domain_errors import EntityError from src.modules.delete_booking.app.delete_booking_usecase import DeleteBookingUsecase from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock @@ -14,22 +14,62 @@ def test_delete_booking_usecase(self): repo = BookingRepositoryMock() usecase = DeleteBookingUsecase(repo=repo) len_before = len(repo.bookings) + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'email': 'user@email.com', + 'role': 'STUDENT' + } - booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925') + booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', user=user) assert len(repo.bookings) == len_before - 1 + def test_delete_booking_usecase_admin(self): + repo = BookingRepositoryMock() + usecase = DeleteBookingUsecase(repo=repo) + len_before = len(repo.bookings) + user = { + 'user_id': 'd351a9b1-937f-423c-a9d1-9929b5795be1', + 'email': 'user@email.com', + 'role': 'ADMIN' + } + + booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', user=user) + assert len(repo.bookings) == len_before - 1 + + def test_delete_booking_usecase_invalid_student(self): + repo = BookingRepositoryMock() + usecase = DeleteBookingUsecase(repo=repo) + user = { + 'user_id': 'd351a9b1-937f-423c-a9d1-9929b5795be1', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + + with pytest.raises(ForbiddenAction): + usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', user=user) + def test_delete_booking_usecase_no_items_found(self): repo = BookingRepositoryMock() usecase = DeleteBookingUsecase(repo=repo) + user = { + 'user_id': 'd351a9b1-937f-423c-a9d1-9929b5795be1', + 'email': 'user@email.com', + 'role': 'ADMIN' + } with pytest.raises(NoItemsFound): - booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2926') + booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2926', user = user) def test_delete_booking_usecase_invalid_booking_id(self): repo = BookingRepositoryMock() usecase = DeleteBookingUsecase(repo=repo) + user = { + 'user_id': 'd351a9b1-937f-423c-a9d1-9929b5795be1', + 'email': 'user@email.com', + 'role': 'ADMIN' + } with pytest.raises(EntityError): - usecase(booking_id=-1) + usecase(booking_id=-1, user=user) with pytest.raises(EntityError): - usecase(booking_id=None) \ No newline at end of file + usecase(booking_id=None,user=user) \ No newline at end of file diff --git a/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py b/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py index 171cf26..8e4844e 100644 --- a/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py +++ b/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py @@ -8,7 +8,12 @@ class Test_DeleteBookingViewModel: def test_delete_booking_viewmodel(self): repo = BookingRepositoryMock() usecase = DeleteBookingUsecase(repo=repo) - booking = usecase(booking_id=repo.bookings[0].booking_id) + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + booking = usecase(booking_id=repo.bookings[0].booking_id, user=user) viewmodel = DeleteBookingViewModel(booking=booking).to_dict() expected = { diff --git a/tests/shared/infra/repositories/test_booking_repository_mock.py b/tests/shared/infra/repositories/test_booking_repository_mock.py index a22fcd7..2cb4128 100644 --- a/tests/shared/infra/repositories/test_booking_repository_mock.py +++ b/tests/shared/infra/repositories/test_booking_repository_mock.py @@ -58,9 +58,14 @@ def test_get_all_bookings(self): def test_delete_booking(self): repo_mock = BookingRepositoryMock() booking_id = 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' + user = { + 'user_id': 'd351a9b1-937f-423c-a9d1-9929b5795be1', + 'email': 'user@email.com', + 'role': 'ADMIN' + } len_before = len(repo_mock.bookings) - deleted_booking = repo_mock.delete_booking(booking_id) + deleted_booking = repo_mock.delete_booking(booking_id, user) len_after = len(repo_mock.bookings) assert deleted_booking is not None From 4940a531a738c5c0e6ec12314187dd35f940a343 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 18 Jul 2025 15:28:06 -0300 Subject: [PATCH 055/167] =?UTF-8?q?refactor:=20remover=20coment=C3=A1rios?= =?UTF-8?q?=20TODO=20sobre=20l=C3=B3gica=20de=20usu=C3=A1rio=20e=20e-mail?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../delete_booking/app/delete_booking_controller.py | 2 -- src/modules/delete_booking/app/delete_booking_usecase.py | 3 --- .../domain/repositories/booking_repository_interface.py | 8 +++++++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/modules/delete_booking/app/delete_booking_controller.py b/src/modules/delete_booking/app/delete_booking_controller.py index 03f5c80..eb0d69b 100644 --- a/src/modules/delete_booking/app/delete_booking_controller.py +++ b/src/modules/delete_booking/app/delete_booking_controller.py @@ -16,8 +16,6 @@ def __init__(self, usecase: DeleteBookingUsecase): def __call__(self, request: IRequest) -> IResponse: - # TODO: Fazer a lógica de receber o token e buscar o usuário. Mandar as infos do usuário para o usecase - try: if request.data.get('user_from_authorizer') is None: diff --git a/src/modules/delete_booking/app/delete_booking_usecase.py b/src/modules/delete_booking/app/delete_booking_usecase.py index 6dedcd6..d63e097 100644 --- a/src/modules/delete_booking/app/delete_booking_usecase.py +++ b/src/modules/delete_booking/app/delete_booking_usecase.py @@ -10,9 +10,6 @@ def __init__(self, repo:IReservationRepository): self.repo = repo def __call__(self, booking_id: int, user): - - # TODO: receber as infos do usuário e ver se tem "role" e "email". - if user.get('user_id') is None: raise EntityError('user id') diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index f641824..c2e3a93 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -35,7 +35,7 @@ def get_booking(self, booking_id: str) -> Optional[Booking]: ''' pass - # TODO: arrumar a lógica para receber as infos do usuário, validar se ele pode realizar a operação + enviar e-mail + # TODO: arrumar a lógica para receber as infos do usuário enviar e-mail @abstractmethod def delete_booking(self, booking_id: int, user) -> Optional[Booking]: ''' @@ -59,3 +59,9 @@ def get_all_users(self) -> List[str]: pass # TODO: método para enviar e-mail para o usuário + @abstractmethod + def send_user_email(self, user): + ''' + Send user an e-mail + ''' + pass \ No newline at end of file From b35a499d285281e0ebc0f55a545c22bea41cd068 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 18 Jul 2025 16:11:14 -0300 Subject: [PATCH 056/167] =?UTF-8?q?refactor:=20comentar=20m=C3=A9todo=20se?= =?UTF-8?q?nd=5Fuser=5Femail=20no=20reposit=C3=B3rio=20de=20reservas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repositories/booking_repository_interface.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index e3420b8..b4563d7 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -64,9 +64,9 @@ def get_all_users(self) -> List[str]: pass # TODO: método para enviar e-mail para o usuário - @abstractmethod - def send_user_email(self, user): - ''' - Send user an e-mail - ''' - pass \ No newline at end of file + # @abstractmethod + # def send_user_email(self, user): + # ''' + # Send user an e-mail + # ''' + # pass \ No newline at end of file From edb1d2e42152d65586ab011a442a3f86b4206d04 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 21 Jul 2025 21:28:05 -0300 Subject: [PATCH 057/167] =?UTF-8?q?feat:=20adicionar=20l=C3=B3gica=20de=20?= =?UTF-8?q?valida=C3=A7=C3=A3o=20de=20usu=C3=A1rio=20na=20exclus=C3=A3o=20?= =?UTF-8?q?de=20reservas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repositories/booking_repository_dynamo.py | 29 +++++++++++++++---- .../test_booking_repository_dynamo.py | 22 ++++++++++++-- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index 2b5ad14..4199934 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -6,6 +6,7 @@ from src.shared.domain.enums.sport import SPORT from src.shared.domain.repositories.booking_repository_interface import IBookingRepository from src.shared.environments import Environments +from src.shared.helpers.errors.usecase_errors import ForbiddenAction from src.shared.infra.dto.booking_dynamo_dto import BookingDynamoDTO from src.shared.infra.external.dynamo.datasources.dynamo_datasource import DynamoDatasource @@ -84,14 +85,30 @@ def get_booking(self, booking_id: str) -> Optional[Booking]: return BookingDynamoDTO.from_dynamo(dynamo_object['Item']).to_entity() - def delete_booking(self, booking_id: str) -> Optional[Booking]: + def delete_booking(self, booking_id: str, user) -> Optional[Booking]: - delete_booking = self.dynamo.delete_item(partition_key=self.booking_partition_key_format(), - sort_key=self.booking_sort_key_format(booking_id)) - if "Attributes" not in delete_booking: + booking = self.get_booking(booking_id) + user_role = user.get('role') + user_id = user.get('user_id') + + if not booking: return None - return BookingDynamoDTO.from_dynamo(delete_booking['Attributes']).to_entity() + is_admin = user_role == 'ADMIN' + is_owner = user_role == 'STUDENT' and booking.user_id == user_id + + if is_admin or is_owner: + deleted = self.dynamo.delete_item( + partition_key=self.booking_partition_key_format(), + sort_key=self.booking_sort_key_format(booking_id) + ) + return BookingDynamoDTO.from_dynamo(deleted['Attributes']).to_entity() + + if user_role == 'STUDENT': + raise ForbiddenAction('user id') + + return None + def get_all_bookings(self) -> Optional[List[Booking]]: @@ -102,6 +119,8 @@ def get_all_bookings(self) -> Optional[List[Booking]]: if item.get('entity') == 'booking': all_bookings.append(BookingDynamoDTO.from_dynamo(item).to_entity()) + return all_bookings + def get_all_bookings_by_date_range(self, initial_date: int, final_date: int) -> Optional[List[Booking]]: all_bookings = [] diff --git a/tests/shared/infra/repositories/test_booking_repository_dynamo.py b/tests/shared/infra/repositories/test_booking_repository_dynamo.py index 17c338d..9bea994 100644 --- a/tests/shared/infra/repositories/test_booking_repository_dynamo.py +++ b/tests/shared/infra/repositories/test_booking_repository_dynamo.py @@ -12,8 +12,14 @@ def test_dynamo_get_all_bookings(self): mock_repo = BookingRepositoryMock() dynamo_bookings = dynamo_repo.get_all_bookings() mock_bookings = mock_repo.get_all_bookings() + + print( dynamo_bookings[0].start_date ) + assert len(dynamo_bookings) == len(mock_bookings) for d_booking, m_booking in zip(dynamo_bookings, mock_bookings): + + + assert d_booking.start_date == m_booking.start_date assert d_booking.end_date == m_booking.end_date assert d_booking.court_number == m_booking.court_number @@ -25,8 +31,13 @@ def test_dynamo_get_all_bookings(self): def test_dynamo_delete_booking(self): dynamo_repo = BookingRepositoryDynamo() mock_repo = BookingRepositoryMock() - booking = mock_repo.get_booking('b5d3bebf-dc0d-4fc1-861c-506a40cc2925') - deleted_booking = dynamo_repo.delete_booking(booking.booking_id) + user = { + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + booking = mock_repo.get_booking('b7d3bebf-dc0d-4fc1-861c-506a40cc2925') + deleted_booking = dynamo_repo.delete_booking(booking.booking_id, user) retrieved_booking = dynamo_repo.get_booking(booking.booking_id) assert retrieved_booking is None assert deleted_booking.booking_id == booking.booking_id @@ -34,7 +45,12 @@ def test_dynamo_delete_booking(self): @pytest.mark.skip("Can't run test in github actions") def test_dynamo_delete_booking_not_found(self): dynamo_repo = BookingRepositoryDynamo() - deleted_booking = dynamo_repo.delete_booking('bau3bebf-dc0d-4fc1-861c-506a40cc2997') + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + deleted_booking = dynamo_repo.delete_booking('b1d3bebf-dc0d-4fc1-861c-506a40cc2925', user) assert deleted_booking is None @pytest.mark.skip("Can't run test in github actions") From bf19bddad50702cfd057ab45b12f1536d8f7822c Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 21 Jul 2025 21:28:22 -0300 Subject: [PATCH 058/167] =?UTF-8?q?feat:=20adicionar=20fun=C3=A7=C3=A3o=20?= =?UTF-8?q?para=20compor=20e-mail=20de=20delete=20booking=20para=20o=20usu?= =?UTF-8?q?=C3=A1rio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../functions/compose_delete_booking_email.py | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/shared/helpers/functions/compose_delete_booking_email.py diff --git a/src/shared/helpers/functions/compose_delete_booking_email.py b/src/shared/helpers/functions/compose_delete_booking_email.py new file mode 100644 index 0000000..3cbb790 --- /dev/null +++ b/src/shared/helpers/functions/compose_delete_booking_email.py @@ -0,0 +1,51 @@ +def compose_deleted_user_email(user): + name = user.name.split(" ")[0] + + message = f""" + + + + + + + + + +
+ + + + +
+ MauaFood Logo +

Feedback Enviado!

+
+ + + + +
+
+

Obrigado, NOME USUÁRIO

Seu feedback foi enviado para nossa equipe analisar:

+

MENSAGEM

+

DATA

+
+
+ + + + +
+
+

Atenciosamente,

+

Equipe MauaFood🍟

+
+
+
+ + + """ + + message = message.format(name=name) + + return message \ No newline at end of file From 6f881028613fd5cc9d5a1b5728abacec8047f636 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 21 Jul 2025 21:49:05 -0300 Subject: [PATCH 059/167] =?UTF-8?q?feat:=20implementar=20envio=20de=20e-ma?= =?UTF-8?q?il=20para=20usu=C3=A1rio=20ao=20cancelar=20reserva?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/delete_booking_usecase.py | 3 ++ .../booking_repository_interface.py | 12 ++--- .../functions/compose_delete_booking_email.py | 3 +- .../repositories/booking_repository_dynamo.py | 47 +++++++++++++++++++ .../repositories/booking_repository_mock.py | 4 ++ 5 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/modules/delete_booking/app/delete_booking_usecase.py b/src/modules/delete_booking/app/delete_booking_usecase.py index d63e097..a82b5f0 100644 --- a/src/modules/delete_booking/app/delete_booking_usecase.py +++ b/src/modules/delete_booking/app/delete_booking_usecase.py @@ -12,6 +12,9 @@ def __init__(self, repo:IReservationRepository): def __call__(self, booking_id: int, user): if user.get('user_id') is None: raise EntityError('user id') + + if user.get('name') is None: + raise EntityError('user id') if user.get('email') is None: raise EntityError('user email') diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index b4563d7..d3a9061 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -64,9 +64,9 @@ def get_all_users(self) -> List[str]: pass # TODO: método para enviar e-mail para o usuário - # @abstractmethod - # def send_user_email(self, user): - # ''' - # Send user an e-mail - # ''' - # pass \ No newline at end of file + @abstractmethod + def send_user_email(self, user) -> bool: + ''' + Send user an e-mail + ''' + pass \ No newline at end of file diff --git a/src/shared/helpers/functions/compose_delete_booking_email.py b/src/shared/helpers/functions/compose_delete_booking_email.py index 3cbb790..2249e28 100644 --- a/src/shared/helpers/functions/compose_delete_booking_email.py +++ b/src/shared/helpers/functions/compose_delete_booking_email.py @@ -1,5 +1,6 @@ def compose_deleted_user_email(user): - name = user.name.split(" ")[0] + name = user.get('name') + email = user.get('email') message = f""" diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index 4199934..410c518 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -1,5 +1,7 @@ +import os from typing import Optional, List +import boto3 from boto3.dynamodb.conditions import Key from src.shared.domain.entities.booking import Booking @@ -7,6 +9,7 @@ from src.shared.domain.repositories.booking_repository_interface import IBookingRepository from src.shared.environments import Environments from src.shared.helpers.errors.usecase_errors import ForbiddenAction +from src.shared.helpers.functions.compose_delete_booking_email import compose_deleted_user_email from src.shared.infra.dto.booking_dynamo_dto import BookingDynamoDTO from src.shared.infra.external.dynamo.datasources.dynamo_datasource import DynamoDatasource @@ -102,6 +105,9 @@ def delete_booking(self, booking_id: str, user) -> Optional[Booking]: partition_key=self.booking_partition_key_format(), sort_key=self.booking_sort_key_format(booking_id) ) + + self.send_user_email(user) + return BookingDynamoDTO.from_dynamo(deleted['Attributes']).to_entity() if user_role == 'STUDENT': @@ -136,4 +142,45 @@ def get_all_bookings_by_date_range(self, initial_date: int, final_date: int) -> def get_all_users(self): return super().get_all_users() + + + def send_user_email(self, user) -> bool: + try: + + client_ses = boto3.client('ses', region_name=os.environ.get('AWS_REGION')) + email_to_send = compose_deleted_user_email(user) + + response = client_ses.send_email( + Destination={ + 'ToAddresses': [ + user.get('email'), + ], + 'BccAddresses': + [ + os.environ.get("HIDDEN_COPY") + ] + }, + Message={ + 'Body': { + 'Html': { + 'Charset': "UTF-8", + 'Data': email_to_send, + }, + }, + 'Subject': { + 'Charset': "UTF-8", + 'Data': 'Mauá Reservation - Reserva Cancelada', + }, + }, + Source=os.environ.get("FROM_EMAIL"), + ) + + print("ESSA É A MAGIA DO PRINT, AQUI ESTÁ A SUA RESPONSE -----> ", response) + + return True + except Exception as err: + print(err) + return False + + diff --git a/src/shared/infra/repositories/booking_repository_mock.py b/src/shared/infra/repositories/booking_repository_mock.py index 61c0d0d..6b713ae 100644 --- a/src/shared/infra/repositories/booking_repository_mock.py +++ b/src/shared/infra/repositories/booking_repository_mock.py @@ -166,4 +166,8 @@ def get_all_bookings_by_date_range(self, initial_date, final_date): def get_all_users(self) -> List[str]: users_id = list(set([booking.user_id for booking in self.bookings])) return users_id + + def send_user_email(self, user) -> bool: + print('ENVIAR E-MAIL PARA O USUÁRIO') + return True \ No newline at end of file From 59699cc46846f2f50dd590a4f947c6321db003a4 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 21 Jul 2025 21:54:45 -0300 Subject: [PATCH 060/167] =?UTF-8?q?feat:=20adicionar=20campo=20'name'=20ao?= =?UTF-8?q?=20usu=C3=A1rio=20nas=20classes=20de=20teste=20de=20exclus?= =?UTF-8?q?=C3=A3o=20de=20reservas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/test_delete_booking_controller.py | 30 +++++++++++-------- .../app/test_delete_booking_presenter.py | 12 +++++--- .../app/test_delete_booking_usecase.py | 21 ++++++++----- .../app/test_delete_booking_viewmodel.py | 1 + 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/tests/modules/delete_bookings/app/test_delete_booking_controller.py b/tests/modules/delete_bookings/app/test_delete_booking_controller.py index 5ee112f..b4fcf77 100644 --- a/tests/modules/delete_bookings/app/test_delete_booking_controller.py +++ b/tests/modules/delete_bookings/app/test_delete_booking_controller.py @@ -11,9 +11,10 @@ def test_delete_booking_controller(self): request = HttpRequest(body= { "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', "user_from_authorizer": { - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', - 'email': 'user@email.com', - 'role': 'STUDENT' + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' } }) @@ -45,9 +46,10 @@ def test_delete_booking_controller_booking_id_entity_error(self): request = HttpRequest(body={ "booking_id": 0, "user_from_authorizer": { - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', - 'email': 'user@email.com', - 'role': 'STUDENT' + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' } }) @@ -62,10 +64,11 @@ def test_delete_booking_controller_wrong_type_parameter(self): request = HttpRequest(body={ "booking_id": "wrong_type", "user_from_authorizer": { - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', - 'email': 'user@email.com', - 'role': 'STUDENT' - } + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } }) response = controller(request) @@ -79,9 +82,10 @@ def test_delete_booking_controller_not_found(self): request = HttpRequest(body={ "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2926', "user_from_authorizer": { - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', - 'email': 'user@email.com', - 'role': 'STUDENT' + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' } }) diff --git a/tests/modules/delete_bookings/app/test_delete_booking_presenter.py b/tests/modules/delete_bookings/app/test_delete_booking_presenter.py index ef2004e..7920309 100644 --- a/tests/modules/delete_bookings/app/test_delete_booking_presenter.py +++ b/tests/modules/delete_bookings/app/test_delete_booking_presenter.py @@ -27,8 +27,9 @@ def test_delete_booking_presenter(self): "authorizer": { 'user': { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', 'email': 'user@email.com', - 'role': 'ADMIN' + 'role': 'STUDENT' } }, "domainName": ".lambda-url.us-west-2.on.aws", @@ -84,8 +85,9 @@ def test_delete_booking_presenter_missing_booking_id(self): "authorizer": { 'user': { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', 'email': 'user@email.com', - 'role': 'ADMIN' + 'role': 'STUDENT' } }, "domainName": ".lambda-url.us-west-2.on.aws", @@ -138,8 +140,9 @@ def test_delete_booking_not_found(self): "authorizer": { 'user': { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', 'email': 'user@email.com', - 'role': 'ADMIN' + 'role': 'STUDENT' } }, "domainName": ".lambda-url.us-west-2.on.aws", @@ -192,8 +195,9 @@ def test_delete_booking_wrong_type(self): "authorizer": { 'user': { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', 'email': 'user@email.com', - 'role': 'ADMIN' + 'role': 'STUDENT' } }, "domainName": ".lambda-url.us-west-2.on.aws", diff --git a/tests/modules/delete_bookings/app/test_delete_booking_usecase.py b/tests/modules/delete_bookings/app/test_delete_booking_usecase.py index 9ab0e03..4778989 100644 --- a/tests/modules/delete_bookings/app/test_delete_booking_usecase.py +++ b/tests/modules/delete_bookings/app/test_delete_booking_usecase.py @@ -16,6 +16,7 @@ def test_delete_booking_usecase(self): len_before = len(repo.bookings) user = { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', 'email': 'user@email.com', 'role': 'STUDENT' } @@ -28,9 +29,10 @@ def test_delete_booking_usecase_admin(self): usecase = DeleteBookingUsecase(repo=repo) len_before = len(repo.bookings) user = { - 'user_id': 'd351a9b1-937f-423c-a9d1-9929b5795be1', + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', 'email': 'user@email.com', - 'role': 'ADMIN' + 'role': 'STUDENT' } booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', user=user) @@ -40,21 +42,23 @@ def test_delete_booking_usecase_invalid_student(self): repo = BookingRepositoryMock() usecase = DeleteBookingUsecase(repo=repo) user = { - 'user_id': 'd351a9b1-937f-423c-a9d1-9929b5795be1', + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', 'email': 'user@email.com', 'role': 'STUDENT' } with pytest.raises(ForbiddenAction): - usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', user=user) + usecase(booking_id='b2d3bebf-dc0d-4fc1-861c-506a40cc2925', user=user) def test_delete_booking_usecase_no_items_found(self): repo = BookingRepositoryMock() usecase = DeleteBookingUsecase(repo=repo) user = { - 'user_id': 'd351a9b1-937f-423c-a9d1-9929b5795be1', + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', 'email': 'user@email.com', - 'role': 'ADMIN' + 'role': 'STUDENT' } with pytest.raises(NoItemsFound): booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2926', user = user) @@ -63,9 +67,10 @@ def test_delete_booking_usecase_invalid_booking_id(self): repo = BookingRepositoryMock() usecase = DeleteBookingUsecase(repo=repo) user = { - 'user_id': 'd351a9b1-937f-423c-a9d1-9929b5795be1', + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', 'email': 'user@email.com', - 'role': 'ADMIN' + 'role': 'STUDENT' } with pytest.raises(EntityError): diff --git a/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py b/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py index 8e4844e..339d113 100644 --- a/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py +++ b/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py @@ -10,6 +10,7 @@ def test_delete_booking_viewmodel(self): usecase = DeleteBookingUsecase(repo=repo) user = { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', 'email': 'user@email.com', 'role': 'STUDENT' } From 37d684b873bd3daa0e02a27489e2e23103b7dfff Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 21 Jul 2025 21:59:52 -0300 Subject: [PATCH 061/167] =?UTF-8?q?feat:=20adicionar=20permiss=C3=B5es=20S?= =?UTF-8?q?ES=20para=20a=20fun=C3=A7=C3=A3o=20de=20exclus=C3=A3o=20de=20re?= =?UTF-8?q?servas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- iac/stacks/iac_stack.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/iac/stacks/iac_stack.py b/iac/stacks/iac_stack.py index c16845b..2089081 100644 --- a/iac/stacks/iac_stack.py +++ b/iac/stacks/iac_stack.py @@ -1,5 +1,5 @@ from aws_cdk import ( - Stack, + Stack, aws_iam ) from constructs import Construct from aws_cdk.aws_apigateway import RestApi, Cors @@ -69,4 +69,23 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: for function in self.lambda_stack.functions_that_need_s3_permissions: self.s3_bucket.bucket.grant_read_write(function) + ses_admin_policy = aws_iam.PolicyStatement( + effect=aws_iam.Effect.ALLOW, + actions=[ + "ses:*", + ], + resources=[ + "*" + ] + ) + + functions_that_need_ses_permissions = [ + self.lambda_stack.delete_booking + ] + + for f in functions_that_need_ses_permissions: + f.add_environment("HIDDEN_COPY", os.environ.get("HIDDEN_COPY")) + f.add_environment("FROM_EMAIL", os.environ.get("FROM_EMAIL")) + f.add_environment("REPLY_TO_EMAIL", os.environ.get("REPLY_TO_EMAIL")) + f.add_to_role_policy(ses_admin_policy) From 2deac318a638190a7b83f3413e94b60aaabb62d8 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Mon, 28 Jul 2025 20:34:32 -0300 Subject: [PATCH 062/167] removed lambda_power_tools from authorizer --- iac/stacks/lambda_stack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index bf452d2..72e2ba0 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -84,7 +84,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment code=lambda_.Code.from_asset("../src/shared/authorizer"), handler="user_mss_authorizer.lambda_handler", runtime=lambda_.Runtime.PYTHON_3_9, - layers=[self.lambda_layer, self.lambda_power_tools], + layers=[self.lambda_layer], environment=environment_variables, timeout=Duration.seconds(15) ) From 3c2db4a04c355fdc0da52b0dc225349a6035774b Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Mon, 28 Jul 2025 21:00:32 -0300 Subject: [PATCH 063/167] readding variables to CD --- .github/workflows/CD.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index 1d8c266..5153f70 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -80,5 +80,11 @@ jobs: AWS_REGION: ${{ vars.AWS_REGION }} AWS_ACCOUNT_ID: ${{ env.AWS_ACCOUNT_ID }} STACK_NAME: ${{ env.STACK_NAME }} - USER_API_URL: ${{ secrets.USER_API_URL }} - GITHUB_REF_NAME: ${{ env.STAGE }} + GITHUB_REF_NAME: ${{ github.ref_name }} + MSS_NAME: ${{ github.event.repository.name }} + S3_ASSETS_CDN: ${{ vars.S3_ASSETS_CDN }} + AUTH_DEV_SYSTEM_USERPOOL_ARN_DEV: ${{ secrets.AUTH_DEV_SYSTEM_USERPOOL_ARN_DEV }} + FROM_EMAIL: ${{ vars.FROM_EMAIL }} + HIDDEN_COPY: ${{ vars.HIDDEN_COPY }} + REPLY_TO_EMAIL: ${{ vars.REPLY_TO_EMAIL }} + GRAPH_MICROSOFT_ENDPOINT: ${{ secrets.GRAPH_MICROSOFT_ENDPOINT }} From e1018b6f9a90881f589714321501712ab45eff16 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Mon, 28 Jul 2025 21:06:26 -0300 Subject: [PATCH 064/167] added user api url to cd --- .github/workflows/CD.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index 5153f70..104038e 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -88,3 +88,4 @@ jobs: HIDDEN_COPY: ${{ vars.HIDDEN_COPY }} REPLY_TO_EMAIL: ${{ vars.REPLY_TO_EMAIL }} GRAPH_MICROSOFT_ENDPOINT: ${{ secrets.GRAPH_MICROSOFT_ENDPOINT }} + USER_API_URL: ${{ secrets.USER_API_URL }} From f2dada55074ef3dc384c4f09caedaaa22e03c43b Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 30 Jul 2025 12:09:00 -0300 Subject: [PATCH 065/167] reverting to old account for better debugging --- .github/workflows/CD.yml | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index 104038e..8fcdc20 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -23,18 +23,8 @@ jobs: - uses: actions/checkout@v2 - name: Determine AWS Account ID - run: | - if [[ "${{ github.ref_name }}" == "dev" ]]; then - echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_DEV }}" >> $GITHUB_ENV - elif [[ "${{ github.ref_name }}" == "fix/githubActions" ]]; then - echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_DEV }}" >> $GITHUB_ENV - elif [[ "${{ github.ref_name }}" == "homolog" ]]; then - echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_HOML }}" >> $GITHUB_ENV - elif [[ "${{ github.ref_name }}" == "prod" ]]; then - echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_PROD }}" >> $GITHUB_ENV - else - echo "Invalid branch name!" && exit 1 - fi + run: echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID }}" >> $GITHUB_ENV + - name: Setup AWS Credentials uses: aws-actions/configure-aws-credentials@v2 From 7955a0a8eafd811303f26222e0472e05b2100e3c Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 30 Jul 2025 12:17:17 -0300 Subject: [PATCH 066/167] shoving to sa-east-1 --- .github/workflows/CD.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index 8fcdc20..bb83732 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -29,7 +29,7 @@ jobs: - name: Setup AWS Credentials uses: aws-actions/configure-aws-credentials@v2 with: - aws-region: ${{ vars.AWS_REGION }} + aws-region: sa-east-1 role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/GithubActionsRole role-session-name: github-action @@ -67,7 +67,7 @@ jobs: cdk deploy --require-approval never env: - AWS_REGION: ${{ vars.AWS_REGION }} + AWS_REGION: sa-east-1 AWS_ACCOUNT_ID: ${{ env.AWS_ACCOUNT_ID }} STACK_NAME: ${{ env.STACK_NAME }} GITHUB_REF_NAME: ${{ github.ref_name }} From 35f206429e2b1bd39aff8807aa0f9475352e4a69 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 30 Jul 2025 12:38:30 -0300 Subject: [PATCH 067/167] uniquifying s3 bucket name as cant delete bucket in the new account --- iac/stacks/bucket_stack.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iac/stacks/bucket_stack.py b/iac/stacks/bucket_stack.py index df796f8..bf93cc0 100644 --- a/iac/stacks/bucket_stack.py +++ b/iac/stacks/bucket_stack.py @@ -6,6 +6,7 @@ ) from constructs import Construct import os +import uuid class BucketStack(Construct): @@ -25,7 +26,8 @@ def __init__(self, scope: Construct, **kwargs) -> None: self.bucket = s3.Bucket( self, f"BACK_S3_REPORT_BUCKET_{stage}", - bucket_name=f"{self.stack_name}-report-bucket{stage}".lower(), + # TODO remover isso quando voltar pra conta nova ou tentar deletar o bucket criado la com power user + bucket_name=f"{self.stack_name}-report-bucket{stage}-{uuid.uuid4()}".lower(), versioned=True, removal_policy=RemovalPolicy.DESTROY if not (stage == 'PROD') else RemovalPolicy.RETAIN, ) From 4458900a41d99a9c1457dc169631b8210c12b03f Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 30 Jul 2025 12:41:32 -0300 Subject: [PATCH 068/167] =?UTF-8?q?=F0=9F=A6=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- iac/stacks/bucket_stack.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iac/stacks/bucket_stack.py b/iac/stacks/bucket_stack.py index bf93cc0..7b83325 100644 --- a/iac/stacks/bucket_stack.py +++ b/iac/stacks/bucket_stack.py @@ -6,7 +6,7 @@ ) from constructs import Construct import os -import uuid +import random class BucketStack(Construct): @@ -27,7 +27,7 @@ def __init__(self, scope: Construct, **kwargs) -> None: self.bucket = s3.Bucket( self, f"BACK_S3_REPORT_BUCKET_{stage}", # TODO remover isso quando voltar pra conta nova ou tentar deletar o bucket criado la com power user - bucket_name=f"{self.stack_name}-report-bucket{stage}-{uuid.uuid4()}".lower(), + bucket_name=f"{self.stack_name}-report-bucket{stage}-{random.randint(1000,9999)}".lower(), versioned=True, removal_policy=RemovalPolicy.DESTROY if not (stage == 'PROD') else RemovalPolicy.RETAIN, ) From 16977ab35ea033ceb47c0abeeb0087cec5f6f528 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 30 Jul 2025 12:54:53 -0300 Subject: [PATCH 069/167] added some commnets, added authorizer to create_booking --- iac/stacks/lambda_stack.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index 72e2ba0..3a7a687 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -97,13 +97,16 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment results_cache_ttl=Duration.seconds(0) ) + #ready for auth self.create_booking = self.create_lambda_api_gateway_integration( module_name="create_booking", method="POST", api_resource=api_gateway_resource, - environment_variables=environment_variables + environment_variables=environment_variables, + authorizer=token_authorizer_lambda ) + #not ready for auth self.update_booking = self.create_lambda_api_gateway_integration( module_name="update_booking", method="PUT", @@ -111,6 +114,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment environment_variables=environment_variables ) + #not ready for auth AND not used? self.get_booking = self.create_lambda_api_gateway_integration( module_name="get_booking", method="POST", @@ -118,6 +122,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment environment_variables=environment_variables ) + #not ready for auth?? TODO Gasperi self.delete_booking = self.create_lambda_api_gateway_integration( module_name="delete_booking", method="DELETE", @@ -125,6 +130,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment environment_variables=environment_variables ) + #not ready and unused self.get_all_bookings = self.create_lambda_api_gateway_integration( module_name="get_all_bookings", method="GET", @@ -132,6 +138,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment environment_variables=environment_variables ) + #ready for auth self.create_court = self.create_lambda_api_gateway_integration( module_name="create_court", method="POST", @@ -140,6 +147,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment authorizer=token_authorizer_lambda ) + #not ready TODO self.get_court = self.create_lambda_api_gateway_integration( module_name="get_court", method="POST", @@ -147,6 +155,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment environment_variables=environment_variables ) + #ready self.update_court = self.create_lambda_api_gateway_integration( module_name="update_court", method="PUT", @@ -155,6 +164,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment authorizer=token_authorizer_lambda ) + #ready self.delete_court = self.create_lambda_api_gateway_integration( module_name="delete_court", method="DELETE", @@ -163,6 +173,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment authorizer=token_authorizer_lambda ) + #not ready? needed? self.get_all_courts = self.create_lambda_api_gateway_integration( module_name="get_all_courts", method="GET", @@ -170,6 +181,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment environment_variables=environment_variables ) + #yes self.health_check = self.create_lambda_api_gateway_integration( module_name="health_check", method="GET", @@ -177,6 +189,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment environment_variables=environment_variables ) + #does not need auth / not a route self.generate_report = self.create_lambda_event_bridge_integration( module_name="generate_report", cron_schedule=Schedule.cron(week_day="FRI", hour="18"), From 4de665509bbf6aba3bdaa276ed9e02c8bd689614 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 30 Jul 2025 13:05:17 -0300 Subject: [PATCH 070/167] fixing user endpoint --- src/shared/authorizer/user_mss_authorizer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/authorizer/user_mss_authorizer.py b/src/shared/authorizer/user_mss_authorizer.py index 9779615..f42a434 100644 --- a/src/shared/authorizer/user_mss_authorizer.py +++ b/src/shared/authorizer/user_mss_authorizer.py @@ -34,10 +34,10 @@ def lambda_handler(event, context): print(f"token: {token}") - # Fetching the user information from the Microsoft Graph API + # Fetching the user information from the user mss methodArn = event["methodArn"] headers = {"Authorization": f"Bearer {token}"} - response = http.request("GET", MSS_USER_API_ENDPOINT + "/get-user", headers=headers) + response = http.request("GET", MSS_USER_API_ENDPOINT + "/reservation-mss-user/get-user", headers=headers) # Checking if the request was successful if response.status != 200: From 2d83898f476fea8eb614b4172b2b54a257855862 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 30 Jul 2025 13:12:56 -0300 Subject: [PATCH 071/167] adjusting create booking controller to fetch for the right parameter name coming from user mss --- .../app/create_booking_controller.py | 2 +- .../app/test_create_booking_controller.py | 24 +++++++++---------- .../app/test_create_booking_presenter.py | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/modules/create_booking/app/create_booking_controller.py b/src/modules/create_booking/app/create_booking_controller.py index 8e737e9..b3dad81 100644 --- a/src/modules/create_booking/app/create_booking_controller.py +++ b/src/modules/create_booking/app/create_booking_controller.py @@ -29,7 +29,7 @@ def __call__(self, request: IRequest): end_date = request.data.get('end_date', None) court_number = request.data.get('court_number', None) sport = request.data.get('sport', None) - user_id = user_from_authorizer.get('id', None) + user_id = user_from_authorizer.get('user_id', None) materials = request.data.get('materials', None) try: diff --git a/tests/modules/create_booking/app/test_create_booking_controller.py b/tests/modules/create_booking/app/test_create_booking_controller.py index c349251..046104c 100644 --- a/tests/modules/create_booking/app/test_create_booking_controller.py +++ b/tests/modules/create_booking/app/test_create_booking_controller.py @@ -23,7 +23,7 @@ def test_create_booking_controller(self): "user_from_authorizer": { "displayName": 'Lebron James', "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' } } ) @@ -48,7 +48,7 @@ def test_create_booking_controller_missing_start_date(self): "user_from_authorizer": { "displayName": 'Lebron James', "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' } }) @@ -72,7 +72,7 @@ def test_create_booking_controller_wrong_type_start_date(self): "user_from_authorizer": { "displayName": 'Lebron James', "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' } }) @@ -95,7 +95,7 @@ def test_create_booking_controller_missing_end_date(self): "user_from_authorizer": { "displayName": 'Lebron James', "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' } }) @@ -119,7 +119,7 @@ def test_create_booking_controller_wrong_type_end_date(self): "user_from_authorizer": { "displayName": 'Lebron James', "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' } }) @@ -143,7 +143,7 @@ def test_create_booking_wrong_type_court_number(self): "user_from_authorizer": { "displayName": 'Lebron James', "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' } }) @@ -166,7 +166,7 @@ def test_create_booking_controller_missing_court_number(self): "user_from_authorizer": { "displayName": 'Lebron James', "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' } }) @@ -189,7 +189,7 @@ def test_create_booking_controller_missing_sport(self): "user_from_authorizer": { "displayName": 'Lebron James', "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' } }) @@ -213,7 +213,7 @@ def test_create_booking_controller_wrong_type_sport(self): "user_from_authorizer": { "displayName": 'Lebron James', "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' } }) @@ -236,7 +236,7 @@ def test_create_booking_controller_missing_materials(self): "user_from_authorizer": { "displayName": 'Lebron James', "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' } }) @@ -260,7 +260,7 @@ def test_create_booking_controller_wrong_type_materials(self): "user_from_authorizer": { "displayName": 'Lebron James', "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' } }) @@ -284,7 +284,7 @@ def test_create_booking_controller_wrong_type_inside_list(self): "user_from_authorizer": { "displayName": 'Lebron James', "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' } }) diff --git a/tests/modules/create_booking/app/test_create_booking_presenter.py b/tests/modules/create_booking/app/test_create_booking_presenter.py index 0a6ea41..bbec02c 100644 --- a/tests/modules/create_booking/app/test_create_booking_presenter.py +++ b/tests/modules/create_booking/app/test_create_booking_presenter.py @@ -31,7 +31,7 @@ def test_create_booking_presenter(self): "user": { "displayName": 'Lebron James', "mail": 'lbj@maua.br', - "id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' } }, "domainName": ".lambda-url.us-west-2.on.aws", From cccd31e8342c02069c786d8fa482afc3bd488311 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 30 Jul 2025 13:23:19 -0300 Subject: [PATCH 072/167] attempting to add more debug --- src/modules/create_booking/app/create_booking_presenter.py | 3 +++ src/modules/create_court/app/create_court_controller.py | 5 +++++ src/modules/create_court/app/create_court_presenter.py | 3 +++ 3 files changed, 11 insertions(+) diff --git a/src/modules/create_booking/app/create_booking_presenter.py b/src/modules/create_booking/app/create_booking_presenter.py index c67b811..eea23c0 100644 --- a/src/modules/create_booking/app/create_booking_presenter.py +++ b/src/modules/create_booking/app/create_booking_presenter.py @@ -8,6 +8,9 @@ controller = CreateBookingController(usecase) def lambda_handler(event, context): + + print(event) + httpRequest = LambdaHttpRequest(data=event) httpRequest.data['user_from_authorizer'] = event.get('requestContext', {}).get('authorizer', {}).get('user', None) response = controller(request=httpRequest) diff --git a/src/modules/create_court/app/create_court_controller.py b/src/modules/create_court/app/create_court_controller.py index 0f93da1..4203880 100644 --- a/src/modules/create_court/app/create_court_controller.py +++ b/src/modules/create_court/app/create_court_controller.py @@ -6,6 +6,7 @@ from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse from src.shared.helpers.external_interfaces.http_codes import BadRequest, Created, InternalServerError from src.shared.domain.enums.status_enum import STATUS +import json class CreateCourtController: @@ -41,6 +42,10 @@ def __call__(self, request: IRequest): user = request.data.get("user_from_authorizer") + if not isinstance(user, dict): + + user = json.loads(user) + court = self.usecase( number= request.data.get('number'), status= status, diff --git a/src/modules/create_court/app/create_court_presenter.py b/src/modules/create_court/app/create_court_presenter.py index 44afbd7..c6b63cb 100644 --- a/src/modules/create_court/app/create_court_presenter.py +++ b/src/modules/create_court/app/create_court_presenter.py @@ -8,6 +8,9 @@ controller = CreateCourtController(usecase) def lambda_handler(event, context): + + print(event) + httpRequest = LambdaHttpRequest(data=event) httpRequest.data['user_from_authorizer'] = event.get('requestContext', {}).get('authorizer', {}).get('user', None) response = controller(request=httpRequest) From cf914e2c6fab6610dbfc8d65357f43c605fae1d1 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 30 Jul 2025 13:39:45 -0300 Subject: [PATCH 073/167] fixing vent extraction --- .../create_booking/app/create_booking_presenter.py | 12 +++++++++--- .../app/test_create_booking_presenter.py | 11 ++++++----- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/modules/create_booking/app/create_booking_presenter.py b/src/modules/create_booking/app/create_booking_presenter.py index eea23c0..c0875c4 100644 --- a/src/modules/create_booking/app/create_booking_presenter.py +++ b/src/modules/create_booking/app/create_booking_presenter.py @@ -2,6 +2,7 @@ from .create_booking_usecase import CreateBookingUsecase from src.shared.environments import Environments from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse +import json repo = Environments.get_booking_repo()() usecase = CreateBookingUsecase(repo) @@ -9,10 +10,15 @@ def lambda_handler(event, context): - print(event) - httpRequest = LambdaHttpRequest(data=event) - httpRequest.data['user_from_authorizer'] = event.get('requestContext', {}).get('authorizer', {}).get('user', None) + + user_info_string = event.get('requestContext', {}).get('authorizer', {}).get('user') + + if user_info_string: + httpRequest.data['user_from_authorizer'] = json.loads(user_info_string).get('user') + else: + httpRequest.data['user_from_authorizer'] = None + response = controller(request=httpRequest) httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) diff --git a/tests/modules/create_booking/app/test_create_booking_presenter.py b/tests/modules/create_booking/app/test_create_booking_presenter.py index bbec02c..fbaab8e 100644 --- a/tests/modules/create_booking/app/test_create_booking_presenter.py +++ b/tests/modules/create_booking/app/test_create_booking_presenter.py @@ -28,11 +28,12 @@ def test_create_booking_presenter(self): "apiId": "", "authentication": None, "authorizer": { - "user": { - "displayName": 'Lebron James', - "mail": 'lbj@maua.br', - "user_id": 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - } + "user": json.dumps({ + "user": { + "user_id": "c8435c66-13a4-4641-9d54-773b4b8ccc98", + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", From 950bb3b686a30335a3a12098e7de79ef0846627f Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 30 Jul 2025 15:10:48 -0300 Subject: [PATCH 074/167] adding correct authorizer user catching, fixed tests --- .../app/create_court_presenter.py | 14 ++- .../app/delete_booking_presenter.py | 16 ++- .../app/delete_court_presenter.py | 21 ++-- .../app/update_court_presenter.py | 11 +- .../app/test_create_court_presenter.py | 18 ++- .../app/test_delete_booking_presenter.py | 60 ++++++---- .../app/test_delete_court_presenter.py | 68 +++++------ .../app/test_update_court_presenter.py | 108 +++++++++++++----- 8 files changed, 210 insertions(+), 106 deletions(-) diff --git a/src/modules/create_court/app/create_court_presenter.py b/src/modules/create_court/app/create_court_presenter.py index c6b63cb..746f31a 100644 --- a/src/modules/create_court/app/create_court_presenter.py +++ b/src/modules/create_court/app/create_court_presenter.py @@ -2,6 +2,7 @@ from .create_court_usecase import CreateCourtUsecase from src.shared.environments import Environments from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse +import json repo = Environments.get_reservation_repo()() usecase = CreateCourtUsecase(repo) @@ -9,11 +10,16 @@ def lambda_handler(event, context): - print(event) - httpRequest = LambdaHttpRequest(data=event) - httpRequest.data['user_from_authorizer'] = event.get('requestContext', {}).get('authorizer', {}).get('user', None) + + user_info_string = event.get('requestContext', {}).get('authorizer', {}).get('user') + + if user_info_string: + httpRequest.data['user_from_authorizer'] = json.loads(user_info_string).get('user') + else: + httpRequest.data['user_from_authorizer'] = None + response = controller(request=httpRequest) httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) - + return httpResponse.toDict() \ No newline at end of file diff --git a/src/modules/delete_booking/app/delete_booking_presenter.py b/src/modules/delete_booking/app/delete_booking_presenter.py index 582fa47..5974992 100644 --- a/src/modules/delete_booking/app/delete_booking_presenter.py +++ b/src/modules/delete_booking/app/delete_booking_presenter.py @@ -2,17 +2,27 @@ from .delete_booking_usecase import DeleteBookingUsecase from src.shared.environments import Environments from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse +import json repo = Environments.get_booking_repo()() usecase = DeleteBookingUsecase(repo) controller = DeleteBookingController(usecase) def lambda_handler(event, context): - httpRequest = LambdaHttpRequest(data=event) + print(event) print("PRINT DO EVENT TA AQUI") - httpRequest.data['user_from_authorizer'] = event.get('requestContext', {}).get('authorizer', {}).get('user', None) + + httpRequest = LambdaHttpRequest(data=event) + + user_info_string = event.get('requestContext', {}).get('authorizer', {}).get('user') + + if user_info_string: + httpRequest.data['user_from_authorizer'] = json.loads(user_info_string).get('user') + else: + httpRequest.data['user_from_authorizer'] = None + response = controller(request=httpRequest) httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) - + return httpResponse.toDict() \ No newline at end of file diff --git a/src/modules/delete_court/app/delete_court_presenter.py b/src/modules/delete_court/app/delete_court_presenter.py index c069ceb..c0aafa0 100644 --- a/src/modules/delete_court/app/delete_court_presenter.py +++ b/src/modules/delete_court/app/delete_court_presenter.py @@ -2,22 +2,25 @@ from .delete_court_usecase import DeleteCourtUsecase from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse from src.shared.environments import Environments +import json repo = Environments.get_reservation_repo()() usecase = DeleteCourtUsecase(repo) controller = DeleteCourtController(usecase) -def delete_court_presenter(event, context): +def lambda_handler(event, context): + httpRequest = LambdaHttpRequest(data=event) - httpRequest.data['user_from_authorizer'] = event.get('requestContext', {}).get('authorizer', {}).get('user', None) - response = controller(httpRequest) + + user_info_string = event.get('requestContext', {}).get('authorizer', {}).get('user') + + if user_info_string: + httpRequest.data['user_from_authorizer'] = json.loads(user_info_string).get('user') + else: + httpRequest.data['user_from_authorizer'] = None + + response = controller(request=httpRequest) httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) return httpResponse.toDict() - - -def lambda_handler(event, context): - response = delete_court_presenter(event, context) - - return response diff --git a/src/modules/update_court/app/update_court_presenter.py b/src/modules/update_court/app/update_court_presenter.py index 289ec26..38a4fae 100644 --- a/src/modules/update_court/app/update_court_presenter.py +++ b/src/modules/update_court/app/update_court_presenter.py @@ -2,6 +2,7 @@ from .update_court_usecase import UpdateCourtUsecase from src.shared.environments import Environments from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse +import json repo = Environments.get_reservation_repo()() usecase = UpdateCourtUsecase(repo) @@ -9,8 +10,16 @@ def lambda_handler(event, context): + httpRequest = LambdaHttpRequest(data=event) - httpRequest.data['user_from_authorizer'] = event.get('requestContext', {}).get('authorizer', {}).get('user', None) + + user_info_string = event.get('requestContext', {}).get('authorizer', {}).get('user') + + if user_info_string: + httpRequest.data['user_from_authorizer'] = json.loads(user_info_string).get('user') + else: + httpRequest.data['user_from_authorizer'] = None + response = controller(request=httpRequest) httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) diff --git a/tests/modules/create_court/app/test_create_court_presenter.py b/tests/modules/create_court/app/test_create_court_presenter.py index 3c3cf7d..eb05390 100644 --- a/tests/modules/create_court/app/test_create_court_presenter.py +++ b/tests/modules/create_court/app/test_create_court_presenter.py @@ -25,9 +25,12 @@ def test_create_court_presenter(self): "apiId": "", "authentication": None, "authorizer": { - "user": { - "role":"ADMIN" - } + "user": json.dumps({ + "user": { + "role": "ADMIN", + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -80,9 +83,12 @@ def test_create_court_presenter_missing_number(self): "apiId": "", "authentication": None, "authorizer": { - "user": { - "role":"ADMIN" - } + "user": json.dumps({ + "user": { + "role": "ADMIN", + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", diff --git a/tests/modules/delete_bookings/app/test_delete_booking_presenter.py b/tests/modules/delete_bookings/app/test_delete_booking_presenter.py index 7920309..a7d296a 100644 --- a/tests/modules/delete_bookings/app/test_delete_booking_presenter.py +++ b/tests/modules/delete_bookings/app/test_delete_booking_presenter.py @@ -25,12 +25,15 @@ def test_delete_booking_presenter(self): "apiId": "", "authentication": None, "authorizer": { - 'user': { - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', - 'name': 'Nome', - 'email': 'user@email.com', - 'role': 'STUDENT' - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -83,12 +86,15 @@ def test_delete_booking_presenter_missing_booking_id(self): "apiId": "", "authentication": None, "authorizer": { - 'user': { - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', - 'name': 'Nome', - 'email': 'user@email.com', - 'role': 'STUDENT' - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -138,12 +144,15 @@ def test_delete_booking_not_found(self): "apiId": "", "authentication": None, "authorizer": { - 'user': { - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', - 'name': 'Nome', - 'email': 'user@email.com', - 'role': 'STUDENT' - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -193,12 +202,15 @@ def test_delete_booking_wrong_type(self): "apiId": "", "authentication": None, "authorizer": { - 'user': { - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', - 'name': 'Nome', - 'email': 'user@email.com', - 'role': 'STUDENT' - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", diff --git a/tests/modules/delete_court/app/test_delete_court_presenter.py b/tests/modules/delete_court/app/test_delete_court_presenter.py index 9c43d39..e5c3111 100644 --- a/tests/modules/delete_court/app/test_delete_court_presenter.py +++ b/tests/modules/delete_court/app/test_delete_court_presenter.py @@ -25,14 +25,15 @@ def test_delete_court_presenter(self): "apiId": "", "authentication": None, "authorizer": { - "user": - { - "id": "dummy_id", - "email": "dumm_yemail", - "name": "dummy_name", - "ra": None, - "role": "ADMIN", - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'ADMIN' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -82,14 +83,15 @@ def test_delete_court_presenter_missing_number(self): "apiId": "", "authentication": None, "authorizer": { - "user": - { - "id": "dummy_id", - "email": "dumm_yemail", - "name": "dummy_name", - "ra": None, - "role": "ADMIN", - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'ADMIN' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -139,14 +141,15 @@ def test_delete_court_not_found(self): "apiId": "", "authentication": None, "authorizer": { - "user": - { - "id": "dummy_id", - "email": "dumm_yemail", - "name": "dummy_name", - "ra": None, - "role": "ADMIN", - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'ADMIN' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -196,14 +199,15 @@ def test_delete_court_wrong_type(self): "apiId": "", "authentication": None, "authorizer": { - "user": - { - "id": "dummy_id", - "email": "dumm_yemail", - "name": "dummy_name", - "ra": None, - "role": "ADMIN", - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'ADMIN' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", diff --git a/tests/modules/update_court/app/test_update_court_presenter.py b/tests/modules/update_court/app/test_update_court_presenter.py index afe7c3f..1ec1697 100644 --- a/tests/modules/update_court/app/test_update_court_presenter.py +++ b/tests/modules/update_court/app/test_update_court_presenter.py @@ -25,9 +25,15 @@ def test_update_court_presenter_one_param(self): "apiId": "", "authentication": None, "authorizer": { - "user": { - "role": "ADMIN" - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'ADMIN' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -80,9 +86,15 @@ def test_update_court_presenter(self): "apiId": "", "authentication": None, "authorizer": { - "user": { - "role": "ADMIN" - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'ADMIN' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -136,9 +148,15 @@ def test_update_court_presenter_missing_number(self): "apiId": "", "authentication": None, "authorizer": { - "user": { - "role": "ADMIN" - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'ADMIN' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -188,9 +206,15 @@ def test_update_court_presenter_wrong_type_number(self): "apiId": "", "authentication": None, "authorizer": { - "user": { - "role": "ADMIN" - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'ADMIN' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -240,9 +264,15 @@ def test_update_court_presenter_wrong_type_status(self): "apiId": "", "authentication": None, "authorizer": { - "user": { - "role": "ADMIN" - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'ADMIN' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -293,9 +323,15 @@ def test_update_court_presenter_wrong_status_entity(self): "apiId": "", "authentication": None, "authorizer": { - "user": { - "role": "ADMIN" - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'ADMIN' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -345,9 +381,15 @@ def test_update_court_presenter_wrong_photo_type(self): "apiId": "", "authentication": None, "authorizer": { - "user": { - "role": "ADMIN" - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'ADMIN' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -397,9 +439,15 @@ def test_update_court_presenter_number_not_found(self): "apiId": "", "authentication": None, "authorizer": { - "user": { - "role": "ADMIN" - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'ADMIN' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -449,9 +497,15 @@ def test_update_court_presenter_invalid_number(self): "apiId": "", "authentication": None, "authorizer": { - "user": { - "role": "ADMIN" - } + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'ADMIN' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", From 0db05ac978290cad479756da4344d428415e19dd Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 30 Jul 2025 15:14:41 -0300 Subject: [PATCH 075/167] fixing get all booking module name in lambda_stack --- iac/stacks/lambda_stack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index 3a7a687..c112f71 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -132,7 +132,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment #not ready and unused self.get_all_bookings = self.create_lambda_api_gateway_integration( - module_name="get_all_bookings", + module_name="get_all_booking", method="GET", api_resource=api_gateway_resource, environment_variables=environment_variables From 792e4b14e9a70b51e68ec046fa1c323a916c946e Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 30 Jul 2025 15:29:12 -0300 Subject: [PATCH 076/167] fixing entire get-all-bookings module names --- iac/stacks/lambda_stack.py | 2 +- ...l_booking_controller.py => get_all_bookings_controller.py} | 4 ++-- ...all_booking_presenter.py => get_all_bookings_presenter.py} | 4 ++-- ...get_all_booking_usecase.py => get_all_bookings_usecase.py} | 0 ...all_booking_viewmodel.py => get_all_bookings_viewmodel.py} | 0 .../get_all_bookings/app/test_get_all_bookings_controller.py | 4 ++-- .../get_all_bookings/app/test_get_all_bookings_presenter.py | 2 +- .../get_all_bookings/app/test_get_all_bookings_usecase.py | 2 +- .../get_all_bookings/app/test_get_all_bookings_viewmodel.py | 4 ++-- 9 files changed, 11 insertions(+), 11 deletions(-) rename src/modules/get_all_bookings/app/{get_all_booking_controller.py => get_all_bookings_controller.py} (87%) rename src/modules/get_all_bookings/app/{get_all_booking_presenter.py => get_all_bookings_presenter.py} (81%) rename src/modules/get_all_bookings/app/{get_all_booking_usecase.py => get_all_bookings_usecase.py} (100%) rename src/modules/get_all_bookings/app/{get_all_booking_viewmodel.py => get_all_bookings_viewmodel.py} (100%) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index c112f71..3a7a687 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -132,7 +132,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment #not ready and unused self.get_all_bookings = self.create_lambda_api_gateway_integration( - module_name="get_all_booking", + module_name="get_all_bookings", method="GET", api_resource=api_gateway_resource, environment_variables=environment_variables diff --git a/src/modules/get_all_bookings/app/get_all_booking_controller.py b/src/modules/get_all_bookings/app/get_all_bookings_controller.py similarity index 87% rename from src/modules/get_all_bookings/app/get_all_booking_controller.py rename to src/modules/get_all_bookings/app/get_all_bookings_controller.py index 5eceb5c..c8631df 100644 --- a/src/modules/get_all_bookings/app/get_all_booking_controller.py +++ b/src/modules/get_all_bookings/app/get_all_bookings_controller.py @@ -1,6 +1,6 @@ from typing import Any -from .get_all_booking_usecase import GetAllBookingsUsecase -from .get_all_booking_viewmodel import GetAllBookingViewModel +from .get_all_bookings_usecase import GetAllBookingsUsecase +from .get_all_bookings_viewmodel import GetAllBookingViewModel from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.external_interfaces.external_interface import IRequest diff --git a/src/modules/get_all_bookings/app/get_all_booking_presenter.py b/src/modules/get_all_bookings/app/get_all_bookings_presenter.py similarity index 81% rename from src/modules/get_all_bookings/app/get_all_booking_presenter.py rename to src/modules/get_all_bookings/app/get_all_bookings_presenter.py index 91dec82..b396c76 100644 --- a/src/modules/get_all_bookings/app/get_all_booking_presenter.py +++ b/src/modules/get_all_bookings/app/get_all_bookings_presenter.py @@ -1,5 +1,5 @@ -from .get_all_booking_controller import GetAllBookingsController -from .get_all_booking_usecase import GetAllBookingsUsecase +from .get_all_bookings_controller import GetAllBookingsController +from .get_all_bookings_usecase import GetAllBookingsUsecase from src.shared.environments import Environments from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse diff --git a/src/modules/get_all_bookings/app/get_all_booking_usecase.py b/src/modules/get_all_bookings/app/get_all_bookings_usecase.py similarity index 100% rename from src/modules/get_all_bookings/app/get_all_booking_usecase.py rename to src/modules/get_all_bookings/app/get_all_bookings_usecase.py diff --git a/src/modules/get_all_bookings/app/get_all_booking_viewmodel.py b/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py similarity index 100% rename from src/modules/get_all_bookings/app/get_all_booking_viewmodel.py rename to src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py diff --git a/tests/modules/get_all_bookings/app/test_get_all_bookings_controller.py b/tests/modules/get_all_bookings/app/test_get_all_bookings_controller.py index 5fed98e..d51e0d0 100644 --- a/tests/modules/get_all_bookings/app/test_get_all_bookings_controller.py +++ b/tests/modules/get_all_bookings/app/test_get_all_bookings_controller.py @@ -1,8 +1,8 @@ -from src.modules.get_all_bookings.app.get_all_booking_usecase import GetAllBookingsUsecase +from src.modules.get_all_bookings.app.get_all_bookings_usecase import GetAllBookingsUsecase from src.shared.helpers.external_interfaces.http_models import HttpRequest from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock from src.shared.domain.entities.booking import Booking -from src.modules.get_all_bookings.app.get_all_booking_controller import GetAllBookingsController +from src.modules.get_all_bookings.app.get_all_bookings_controller import GetAllBookingsController class Test_GetAllBookingsController: def test_get_all_bookings_controller(self): diff --git a/tests/modules/get_all_bookings/app/test_get_all_bookings_presenter.py b/tests/modules/get_all_bookings/app/test_get_all_bookings_presenter.py index 41298e8..ef2d463 100644 --- a/tests/modules/get_all_bookings/app/test_get_all_bookings_presenter.py +++ b/tests/modules/get_all_bookings/app/test_get_all_bookings_presenter.py @@ -1,5 +1,5 @@ import json -from src.modules.get_all_bookings.app.get_all_booking_presenter import lambda_handler +from src.modules.get_all_bookings.app.get_all_bookings_presenter import lambda_handler class TestGetAllBookingsPresenter: def test_lambda_handler(self): diff --git a/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py b/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py index ff93fab..17b0a56 100644 --- a/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py +++ b/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py @@ -1,4 +1,4 @@ -from src.modules.get_all_bookings.app.get_all_booking_usecase import GetAllBookingsUsecase +from src.modules.get_all_bookings.app.get_all_bookings_usecase import GetAllBookingsUsecase from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock from src.shared.domain.enums.sport import SPORT from src.shared.domain.entities.booking import Booking diff --git a/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py b/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py index 958341a..a4ca114 100644 --- a/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py +++ b/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py @@ -1,5 +1,5 @@ -from src.modules.get_all_bookings.app.get_all_booking_usecase import GetAllBookingsUsecase -from src.modules.get_all_bookings.app.get_all_booking_viewmodel import GetAllBookingViewModel +from src.modules.get_all_bookings.app.get_all_bookings_usecase import GetAllBookingsUsecase +from src.modules.get_all_bookings.app.get_all_bookings_viewmodel import GetAllBookingViewModel from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock from src.shared.domain.entities.booking import Booking From 404c34a71fff217624606b8dca725a9ff0f409bb Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 30 Jul 2025 17:10:34 -0300 Subject: [PATCH 077/167] fix: get_bookings de volta a vida --- iac/stacks/lambda_stack.py | 10 +- src/modules/get_bookings/__init__.py | 0 src/modules/get_bookings/app/__init__.py | 0 .../app/get_bookings_controller.py | 95 ++++++ .../app/get_bookings_presenter.py | 17 ++ .../get_bookings/app/get_bookings_usecase.py | 52 ++++ .../app/get_bookings_viewmodel.py | 15 + .../booking_repository_interface.py | 13 + .../repositories/booking_repository_mock.py | 34 ++- tests/modules/get_bookings/__init__.py | 0 tests/modules/get_bookings/app/__init__.py | 0 .../app/test_get_bookings_controller.py | 217 +++++++++++++ .../app/test_get_bookings_presenter.py | 289 ++++++++++++++++++ .../app/test_get_bookings_usecase.py | 26 ++ .../app/test_get_bookings_viewmodel.py | 26 ++ 15 files changed, 792 insertions(+), 2 deletions(-) create mode 100644 src/modules/get_bookings/__init__.py create mode 100644 src/modules/get_bookings/app/__init__.py create mode 100644 src/modules/get_bookings/app/get_bookings_controller.py create mode 100644 src/modules/get_bookings/app/get_bookings_presenter.py create mode 100644 src/modules/get_bookings/app/get_bookings_usecase.py create mode 100644 src/modules/get_bookings/app/get_bookings_viewmodel.py create mode 100644 tests/modules/get_bookings/__init__.py create mode 100644 tests/modules/get_bookings/app/__init__.py create mode 100644 tests/modules/get_bookings/app/test_get_bookings_controller.py create mode 100644 tests/modules/get_bookings/app/test_get_bookings_presenter.py create mode 100644 tests/modules/get_bookings/app/test_get_bookings_usecase.py create mode 100644 tests/modules/get_bookings/app/test_get_bookings_viewmodel.py diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index bf452d2..9c4a9c1 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -118,6 +118,13 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment environment_variables=environment_variables ) + self.get_bookings = self.create_lambda_api_gateway_integration( + module_name="get_bookings", + method="GET", + api_resource=api_gateway_resource, + environment_variables=environment_variables, + ) + self.delete_booking = self.create_lambda_api_gateway_integration( module_name="delete_booking", method="DELETE", @@ -193,7 +200,8 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment self.get_booking, self.update_booking, self.delete_booking, - self.get_all_bookings + self.get_all_bookings, + self.get_bookings ] self.functions_that_need_s3_permissions = [ diff --git a/src/modules/get_bookings/__init__.py b/src/modules/get_bookings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/get_bookings/app/__init__.py b/src/modules/get_bookings/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/get_bookings/app/get_bookings_controller.py b/src/modules/get_bookings/app/get_bookings_controller.py new file mode 100644 index 0000000..abae3b3 --- /dev/null +++ b/src/modules/get_bookings/app/get_bookings_controller.py @@ -0,0 +1,95 @@ +import json + +from .get_bookings_viewmodel import GetBookingsViewmodel +from .get_bookings_usecase import GetBookingsUseCase +from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter, EmptyQueryParameters, \ + AuthorizerError +from src.shared.helpers.errors.domain_errors import EntityError +from src.shared.helpers.errors.usecase_errors import NoItemsFound, DependantFilter +from src.shared.helpers.external_interfaces.external_interface import IRequest +from src.shared.helpers.external_interfaces.http_codes import BadRequest, OK, NotFound, InternalServerError + + +class GetBookingsController: + def __init__(self, usecase: GetBookingsUseCase): + self.usecase = usecase + + def __call__(self, request: IRequest): + try: + + booking_id = request.data.get('booking_id', None) + user_id = request.data.get('user_id', None) + sport = request.data.get('sport', None) + court_number = request.data.get('court_number', None) + end_date = request.data.get('end_date', None) + start_date = request.data.get('start_date', None) + + booking_id = booking_id if booking_id != "" else None + user_id = user_id if user_id != "" else None + sport = sport if sport != "" else None + court_number = court_number if court_number != "" else None + end_date = end_date if end_date != "" else None + start_date = start_date if start_date != "" else None + + if not booking_id and not user_id and not sport and not court_number and not end_date and not start_date: + raise EmptyQueryParameters( + 'At least one of the filters must be provided: booking_id, user_id, sport, court_number, end_date, start_date') + + if court_number is not None: + try: + court_number = int(court_number) + except ValueError: + raise WrongTypeParameter(fieldName='court_number', + fieldTypeExpected='int', + fieldTypeReceived=court_number) + + if end_date is not None: + try: + end_date = int(end_date) + except ValueError: + raise WrongTypeParameter(fieldName='end_date', + fieldTypeExpected='int', + fieldTypeReceived=end_date) + + if start_date is not None: + try: + start_date = int(start_date) + except ValueError: + raise WrongTypeParameter(fieldName='start_date', + fieldTypeExpected='int', + fieldTypeReceived=start_date) + + booking = self.usecase( + booking_id=booking_id, + user_id=user_id, + sport=sport, + court_number=court_number, + end_date=end_date, + start_date=start_date + ) + booking_viewmodel = GetBookingsViewmodel(booking) + return OK(booking_viewmodel.to_dict()) + + except AuthorizerError as err: + return BadRequest(body=err.message) + + except EmptyQueryParameters as err: + return BadRequest(body=err.message) + + except DependantFilter as err: + return BadRequest(body=err.message) + + except MissingParameters as err: + return BadRequest(body=err.message) + + except EntityError as err: + return BadRequest(body=err.message) + + except NoItemsFound as err: + return NotFound(body=err.message) + + except WrongTypeParameter as err: + return BadRequest(body=err.message) + + except Exception as err: + return InternalServerError(body=err.args[0]) \ No newline at end of file diff --git a/src/modules/get_bookings/app/get_bookings_presenter.py b/src/modules/get_bookings/app/get_bookings_presenter.py new file mode 100644 index 0000000..a44f717 --- /dev/null +++ b/src/modules/get_bookings/app/get_bookings_presenter.py @@ -0,0 +1,17 @@ +from .get_bookings_controller import GetBookingsController +from .get_bookings_usecase import GetBookingsUseCase +from src.shared.environments import Environments +from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse +from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock + +repo = Environments.get_booking_repo()() +usecase = GetBookingsUseCase(repo=repo) +controller = GetBookingsController(usecase=usecase) + + +def lambda_handler(event, context): + httpRequest = LambdaHttpRequest(data=event) + response = controller(request=httpRequest) + httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) + + return httpResponse.toDict() \ No newline at end of file diff --git a/src/modules/get_bookings/app/get_bookings_usecase.py b/src/modules/get_bookings/app/get_bookings_usecase.py new file mode 100644 index 0000000..57d099d --- /dev/null +++ b/src/modules/get_bookings/app/get_bookings_usecase.py @@ -0,0 +1,52 @@ +from typing import Optional + +from src.shared.domain.entities.booking import Booking +from src.shared.domain.enums.sport import SPORT +from src.shared.domain.repositories.booking_repository_interface import IBookingRepository +from src.shared.helpers.errors.domain_errors import EntityError +from src.shared.helpers.errors.usecase_errors import NoItemsFound, DependantFilter + +class GetBookingsUseCase: + repo: IBookingRepository + + def __init__(self, repo: IBookingRepository): + self.repo = repo + + def __call__(self, + booking_id: Optional[str] = None, + user_id: Optional[str] = None, + sport: Optional[str] = None, + court_number: Optional[int] = None, + end_date: Optional[int] = None, + start_date: Optional[int] = None): + + if booking_id: + if not Booking.validate_booking_id(booking_id): + raise EntityError('booking_id') + if user_id: + if not Booking.validate_user_id(user_id): + raise EntityError('user_id') + if sport: + if not Booking.validate_sport(SPORT(sport)): + raise EntityError('sport') + if court_number: + if not Booking.validate_court(court_number): + raise EntityError('court_number') + if end_date and start_date: + if not Booking.validate_dates(end_date, start_date): + raise EntityError('end_date or start_date') + + if (start_date and not end_date) or (end_date and not start_date): + raise DependantFilter('start_date and end_date') + + bookings = self.repo.get_bookings( + booking_id=booking_id if booking_id else None, + user_id=user_id if user_id else None, + sport=SPORT(sport) if sport else None, + court_number=court_number if court_number else None, + end_date=end_date if end_date else None, + start_date=start_date if start_date else None) + if bookings is None or bookings == []: + raise NoItemsFound('booking filters passed') + + return bookings \ No newline at end of file diff --git a/src/modules/get_bookings/app/get_bookings_viewmodel.py b/src/modules/get_bookings/app/get_bookings_viewmodel.py new file mode 100644 index 0000000..18e1b7c --- /dev/null +++ b/src/modules/get_bookings/app/get_bookings_viewmodel.py @@ -0,0 +1,15 @@ +from typing import List +from src.shared.domain.entities.booking import Booking + + +class GetBookingsViewmodel: + bookings: List[Booking] + + def __init__(self, bookings: list): + self.bookings = bookings + + def to_dict(self): + return { + 'bookings': [booking.to_dict() for booking in self.bookings], + 'message': 'the bookings were retrieved' + } \ No newline at end of file diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index d3a9061..e003c39 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -40,6 +40,19 @@ def get_booking(self, booking_id: str) -> Optional[Booking]: ''' pass + @abstractmethod + def get_bookings(self, + booking_id: Optional[str] = None, + user_id: Optional[str] = None, + sport: Optional[SPORT] = None, + court_number: Optional[int] = None, + end_date: Optional[int] = None, + start_date: Optional[int] = None) -> List[Optional[Booking]]: + ''' + If the booking exists, returns it, else returns None + ''' + pass + # TODO: arrumar a lógica para receber as infos do usuário enviar e-mail @abstractmethod def delete_booking(self, booking_id: int, user) -> Optional[Booking]: diff --git a/src/shared/infra/repositories/booking_repository_mock.py b/src/shared/infra/repositories/booking_repository_mock.py index 6b713ae..e64416c 100644 --- a/src/shared/infra/repositories/booking_repository_mock.py +++ b/src/shared/infra/repositories/booking_repository_mock.py @@ -1,4 +1,4 @@ -from typing import List +from typing import List, Optional from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT from src.shared.domain.repositories.booking_repository_interface import IBookingRepository @@ -127,6 +127,38 @@ def get_booking(self, booking_id: str): if booking.booking_id == booking_id: return booking return None + + def get_bookings(self, + booking_id: Optional[str] = None, + user_id: Optional[str] = None, + sport: Optional[str] = None, + court_number: Optional[int] = None, + end_date: Optional[int] = None, + start_date: Optional[int] = None) -> List[Optional[Booking]]: + + filters = locals().copy() + filters.pop('self') + filters.pop('end_date') + filters.pop('start_date') + + filters = {k: v for k, v in filters.items() if v is not None} + + bookings = [] + + for booking in self.bookings: + booking_dict = booking.__dict__ + if start_date and end_date: + if all( + booking_dict.get(key) == value for key, value in filters.items() + ) and booking.start_date >= start_date and booking.end_date <= end_date: + bookings.append(booking) + else: + if all( + booking_dict.get(key) == value for key, value in filters.items() + ): + bookings.append(booking) + + return bookings def delete_booking(self, booking_id: str, user): booking = self.get_booking(booking_id) diff --git a/tests/modules/get_bookings/__init__.py b/tests/modules/get_bookings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/modules/get_bookings/app/__init__.py b/tests/modules/get_bookings/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/modules/get_bookings/app/test_get_bookings_controller.py b/tests/modules/get_bookings/app/test_get_bookings_controller.py new file mode 100644 index 0000000..be8c438 --- /dev/null +++ b/tests/modules/get_bookings/app/test_get_bookings_controller.py @@ -0,0 +1,217 @@ +import pytest + +from src.modules.get_bookings.app.get_bookings_controller import GetBookingsController +from src.modules.get_bookings.app.get_bookings_usecase import GetBookingsUseCase +from src.shared.helpers.errors.usecase_errors import DependantFilter +from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock +from src.shared.helpers.external_interfaces.http_models import HttpRequest + +class TestGetBookingsController: + def setup_method(self): + repo = BookingRepositoryMock() + usecase = GetBookingsUseCase(repo=repo) + self.controller = GetBookingsController(usecase=usecase) + + def test_get_bookings_controller(self): + repo = BookingRepositoryMock() + usecase = GetBookingsUseCase(repo=repo) + controller = GetBookingsController(usecase=usecase) + request = HttpRequest(query_params={ + 'booking_id': 'b6d3bebf-dc0d-4fc1-861c-506a40cc2925', + 'user_id': "c8435c66-13a4-4641-9d54-773b4b8ccc98" + }) + response = controller(request) + + assert response.status_code == 200 + assert response.body['bookings'][0]['booking_id'] == 'b6d3bebf-dc0d-4fc1-861c-506a40cc2925' + assert response.body['bookings'][0]['start_date'] == 1634583600000 + assert response.body['bookings'][0]['end_date'] == 1634585400000 + assert response.body['bookings'][0]['court_number'] == 5 + assert response.body['bookings'][0]['sport'] == 'Futsal' + assert response.body['bookings'][0]['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + assert response.body['bookings'][0]['materials'] == ['Bola', 'Chuteira'] + + def test_get_bookings_controller_empty_query(self): + repo = BookingRepositoryMock() + usecase = GetBookingsUseCase(repo=repo) + controller = GetBookingsController(usecase=usecase) + request = HttpRequest(query_params={ + }) + response = controller(request) + + assert response.status_code == 400 + assert response.body == 'Empty query parameters: At least one of the filters must be provided: booking_id, user_id, sport, court_number, end_date, start_date' + + def test_get_bookings_controller_wrong_type_booking_id(self): + repo = BookingRepositoryMock() + usecase = GetBookingsUseCase(repo=repo) + controller = GetBookingsController(usecase=usecase) + request = HttpRequest(query_params={ + 'booking_id': '123', + }) + response = controller(request) + + assert response.status_code == 400 + assert "Field booking_id is not valid" in response.body + + def test_get_bookings_controller_booking_not_found(self): + repo = BookingRepositoryMock() + usecase = GetBookingsUseCase(repo=repo) + controller = GetBookingsController(usecase=usecase) + request = HttpRequest(query_params={ + 'booking_id': 'b2d3bebf-dc0d-4fc1-861c-506a40cc2943', + }) + + response = controller(request) + assert response.status_code == 404 + assert response.body == 'No items found for booking filters passed' + + def test_get_bookings_controller_sport(self): + repo = BookingRepositoryMock() + usecase = GetBookingsUseCase(repo=repo) + controller = GetBookingsController(usecase=usecase) + request = HttpRequest(query_params={ + 'sport': 'Tennis', + }) + response = controller(request) + + assert response.status_code == 200 + + for booking in response.body['bookings']: + assert booking['sport'] == 'Tennis' + + def test_get_bookings_controller_court_number(self): + repo = BookingRepositoryMock() + usecase = GetBookingsUseCase(repo=repo) + controller = GetBookingsController(usecase=usecase) + request = HttpRequest(query_params={ + 'court_number': '1', + }) + response = controller(request) + + assert response.status_code == 200 + + for booking in response.body['bookings']: + assert booking['court_number'] == 1 + + def test_get_bookings_controller_user_id(self): + repo = BookingRepositoryMock() + usecase = GetBookingsUseCase(repo=repo) + controller = GetBookingsController(usecase=usecase) + request = HttpRequest(query_params={ + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + }) + response = controller(request) + + assert response.status_code == 200 + + for booking in response.body['bookings']: + assert booking['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + + def test_get_bookings_controller_start_date_error(self): + + repo = BookingRepositoryMock() + usecase = GetBookingsUseCase(repo=repo) + controller = GetBookingsController(usecase=usecase) + request = HttpRequest(query_params={ + 'start_date': '1634563800000', + }) + response = controller(request) + + assert response.status_code == 400 + assert response.body == "Filters have to be provided together: start_date and end_date" + + def test_get_bookings_controller_end_date_error(self): + repo = BookingRepositoryMock() + usecase = GetBookingsUseCase(repo=repo) + controller = GetBookingsController(usecase=usecase) + request = HttpRequest(query_params={ + 'end_date': '1634567400000', + }) + response = controller(request) + + assert response.status_code == 400 + assert response.body == "Filters have to be provided together: start_date and end_date" + + def test_get_bookings_controller_start_date_end_date(self): + repo = BookingRepositoryMock() + usecase = GetBookingsUseCase(repo=repo) + controller = GetBookingsController(usecase=usecase) + request = HttpRequest(query_params={ + 'start_date': '1634563800000', + 'end_date': '16345674000000', + }) + response = controller(request) + + assert response.status_code == 200 + + for booking in response.body['bookings']: + assert booking['start_date'] >= 1634563800000 + assert booking['end_date'] <= 16345674000000 + + def test_get_bookings_controller_five_filters(self): + # booking_id + user_id + sport + court_number + date_range + start = '1634583600000' + end = '1634585400000' + request = HttpRequest(query_params={ + 'booking_id': 'b6d3bebf-dc0d-4fc1-861c-506a40cc2925', + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'sport': 'Futsal', + 'court_number': 5, + 'start_date': start, + 'end_date': end + }) + response = self.controller(request) + assert response.status_code == 200 + bookings = response.body['bookings'] + assert len(bookings) == 1 + b = bookings[0] + assert b['booking_id'] == 'b6d3bebf-dc0d-4fc1-861c-506a40cc2925' + assert b['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + assert b['sport'] == 'Futsal' + assert b['court_number'] == 5 + assert b['start_date'] >= int(start) and b['end_date'] <= int(end) + + def test_get_bookings_controller_four_filters(self): + # user_id + sport + court_number + date_range + start = '1634574600000' + end = '1634578200000' + request = HttpRequest(query_params={ + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'sport': 'Volleyball', + 'court_number': 4, + 'start_date': start, + 'end_date': end + }) + response = self.controller(request) + assert response.status_code == 200 + bookings = response.body['bookings'] + assert len(bookings) == 1 + b = bookings[0] + assert b['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + assert b['sport'] == 'Volleyball' + assert b['court_number'] == 4 + assert b['start_date'] >= int(start) and b['end_date'] <= int(end) + + def test_get_bookings_controller_three_filters(self): + # sport + court_number + user_id + request = HttpRequest(query_params={ + 'sport': 'Rugby', + 'court_number': 5, + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + }) + response = self.controller(request) + assert response.status_code == 200 + bookings = response.body['bookings'] + assert len(bookings) == 1 + b = bookings[0] + assert b['sport'] == 'Rugby' + assert b['court_number'] == 5 + assert b['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + + def test_get_bookings_user_id_not_valid(self): + request = HttpRequest(query_params={ + 'user_id': '1' + }) + response = self.controller(request) + assert response.status_code == 400 \ No newline at end of file diff --git a/tests/modules/get_bookings/app/test_get_bookings_presenter.py b/tests/modules/get_bookings/app/test_get_bookings_presenter.py new file mode 100644 index 0000000..080419c --- /dev/null +++ b/tests/modules/get_bookings/app/test_get_bookings_presenter.py @@ -0,0 +1,289 @@ +import json +from src.modules.get_bookings.app.get_bookings_presenter import lambda_handler +from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock + +class Test_GetBookingPresenter: + + def test_get_bookings_presenter(self): + event = { + "version": "2.0", + "routeKey": "$default", + "rawPath": "/my/path", + "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", + "cookies": [ + "cookie1", + "cookie2" + ], + "headers": { + "header1": "value1", + "header2": "value1,value2" + }, + "queryStringParameters": { + "booking_id": "b1d3bebf-dc0d-4fc1-861c-506a40cc2925", + "user_id": "", + "sport": "", + "court_number": "", + "end_date": "", + "start_date": "" + }, + "requestContext": { + "accountId": "123456789012", + "apiId": "", + "authentication": None, + "authorizer": { + "user": { + "id": "1f25448b-3429-4c19-8287-d9e64f17bc3a", + "displayName": "User", + "mail": "lbj@maua.br" + } + }, + "domainName": ".lambda-url.us-west-2.on.aws", + "domainPrefix": "", + "external_interfaces": { + "method": "POST", + "path": "/my/path", + "protocol": "HTTP/1.1", + "sourceIp": "123.123.123.123", + "userAgent": "agent" + }, + "requestId": "id", + "routeKey": "$default", + "stage": "$default", + "time": "12/Mar/2020:19:03:58 +0000", + "timeEpoch": 1583348638390 + }, + "body": {}, + "pathParameters": None, + "isBase64Encoded": None, + "stageVariables": None + } + + + response = lambda_handler(event, None) + assert response['statusCode'] == 200 + assert json.loads(response['body'])['message'] == 'the bookings were retrieved' + assert json.loads(response['body'])['bookings'][0]['booking_id'] == 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' + assert json.loads(response['body'])['bookings'][0]['start_date'] == 1634576165000 + assert json.loads(response['body'])['bookings'][0]['end_date'] == 1634583365000 + assert json.loads(response['body'])['bookings'][0]['court_number'] == 1 + assert json.loads(response['body'])['bookings'][0]['sport'] == 'Tennis' + assert json.loads(response['body'])['bookings'][0]['user_id'] == '1f25448b-3429-4c19-8287-d9e64f17bc3a' + assert json.loads(response['body'])['bookings'][0]['materials'] == ['Raquete', 'Bola', 'Rede', 'Tenis'] + + + def test_get_bookings_presenter_missing_parameters(self): + event = { + "version": "2.0", + "routeKey": "$default", + "rawPath": "/my/path", + "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", + "cookies": [ + "cookie1", + "cookie2" + ], + "headers": { + "header1": "value1", + "header2": "value1,value2" + }, + "queryStringParameters": { + "parameter1": "1" + }, + "requestContext": { + "accountId": "123456789012", + "apiId": "", + "authentication": None, + "authorizer": { + "user": { + "id": "c8435c66-13a4-4641-9d54-773b4b8ccc98", + "displayName": "User", + "mail": "lbj@maua.br" + } + }, + "domainName": ".lambda-url.us-west-2.on.aws", + "domainPrefix": "", + "external_interfaces": { + "method": "POST", + "path": "/my/path", + "protocol": "HTTP/1.1", + "sourceIp": "123.123.123.123", + "userAgent": "agent" + }, + "requestId": "id", + "routeKey": "$default", + "stage": "$default", + "time": "12/Mar/2020:19:03:58 +0000", + "timeEpoch": 1583348638390 + }, + "body": {}, + "pathParameters": None, + "isBase64Encoded": None, + "stageVariables": None + } + + response = lambda_handler(event, None) + assert response['statusCode'] == 400 + assert json.loads(response['body']) == 'Empty query parameters: At least one of the filters must be provided: booking_id, user_id, sport, court_number, end_date, start_date' + + def test_get_bookings_presenter_entity_error(self): + event = { + "version": "2.0", + "routeKey": "$default", + "rawPath": "/my/path", + "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", + "cookies": [ + "cookie1", + "cookie2" + ], + "headers": { + "header1": "value1", + "header2": "value1,value2" + }, + "queryStringParameters": { + "booking_id":'teste' + }, + "requestContext": { + "accountId": "123456789012", + "apiId": "", + "authentication": None, + "authorizer": { + "user": { + "id": "c8435c66-13a4-4641-9d54-773b4b8ccc98", + "displayName": "User", + "mail": "lbj@maua.br" + } + }, + "domainName": ".lambda-url.us-west-2.on.aws", + "domainPrefix": "", + "external_interfaces": { + "method": "POST", + "path": "/my/path", + "protocol": "HTTP/1.1", + "sourceIp": "123.123.123.123", + "userAgent": "agent" + }, + "requestId": "id", + "routeKey": "$default", + "stage": "$default", + "time": "12/Mar/2020:19:03:58 +0000", + "timeEpoch": 1583348638390 + }, + "body": {}, + "pathParameters": None, + "isBase64Encoded": None, + "stageVariables": None + } + + response = lambda_handler(event, None) + + assert response['statusCode'] == 400 + assert json.loads(response['body']) == 'Field booking_id is not valid' + + + def test_get_bookings_presenter_wrong_type_parameter(self): + event = { + "version": "2.0", + "routeKey": "$default", + "rawPath": "/my/path", + "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", + "cookies": [ + "cookie1", + "cookie2" + ], + "headers": { + "header1": "value1", + "header2": "value1,value2" + }, + "queryStringParameters": { + "booking_id": '10' + }, + "requestContext": { + "accountId": "123456789012", + "apiId": "", + "authentication": None, + "authorizer": { + "user": { + "id": "c8435c66-13a4-4641-9d54-773b4b8ccc98", + "displayName": "User", + "mail": "lbj@maua.br" + } + }, + "domainName": ".lambda-url.us-west-2.on.aws", + "domainPrefix": "", + "external_interfaces": { + "method": "POST", + "path": "/my/path", + "protocol": "HTTP/1.1", + "sourceIp": "123.123.123.123", + "userAgent": "agent" + }, + "requestId": "id", + "routeKey": "$default", + "stage": "$default", + "time": "12/Mar/2020:19:03:58 +0000", + "timeEpoch": 1583348638390 + }, + "body": {}, + "pathParameters": None, + "isBase64Encoded": None, + "stageVariables": None + } + + response = lambda_handler(event, None) + + assert response['statusCode'] == 400 + assert json.loads(response['body']) == 'Field booking_id is not valid' + + + def test_get_bookings_presenter_entity_not_found(self): + event = { + "version": "2.0", + "routeKey": "$default", + "rawPath": "/my/path", + "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", + "cookies": [ + "cookie1", + "cookie2" + ], + "headers": { + "header1": "value1", + "header2": "value1,value2" + }, + "queryStringParameters": { + "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2989' + }, + "requestContext": { + "accountId": "123456789012", + "apiId": "", + "authentication": None, + "authorizer": { + "user": { + "id": "c8435c66-13a4-4641-9d54-773b4b8ccc98", + "displayName": "User", + "mail": "lbj@maua.br" + } + }, + "domainName": ".lambda-url.us-west-2.on.aws", + "domainPrefix": "", + "external_interfaces": { + "method": "POST", + "path": "/my/path", + "protocol": "HTTP/1.1", + "sourceIp": "123.123.123.123", + "userAgent": "agent" + }, + "requestId": "id", + "routeKey": "$default", + "stage": "$default", + "time": "12/Mar/2020:19:03:58 +0000", + "timeEpoch": 1583348638390 + }, + "body": {}, + "pathParameters": None, + "isBase64Encoded": None, + "stageVariables": None + } + + response = lambda_handler(event, None) + + assert response['statusCode'] == 404 + assert json.loads(response['body']) == 'No items found for booking filters passed' diff --git a/tests/modules/get_bookings/app/test_get_bookings_usecase.py b/tests/modules/get_bookings/app/test_get_bookings_usecase.py new file mode 100644 index 0000000..de767b0 --- /dev/null +++ b/tests/modules/get_bookings/app/test_get_bookings_usecase.py @@ -0,0 +1,26 @@ +import pytest + +from src.modules.get_bookings.app.get_bookings_usecase import GetBookingsUseCase +from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock +from src.shared.helpers.errors.domain_errors import EntityError +from src.shared.helpers.errors.usecase_errors import NoItemsFound + +class TestGetBookingsUseCase: + def test_get_bookings_usecase(self): + repo = BookingRepositoryMock() + usecase = GetBookingsUseCase(repo=repo) + booking = repo.bookings[0].booking_id + response = usecase(booking) + assert response[0] == repo.bookings[0] + + def test_get_bookings_usecase_invalid_id(self): + with pytest.raises(EntityError): + repo = BookingRepositoryMock() + usecase = GetBookingsUseCase(repo = repo) + usecase('invalid_id') + + def test_get_bookings_usecase_no_items_found(self): + with pytest.raises(NoItemsFound): + repo = BookingRepositoryMock() + usecase = GetBookingsUseCase(repo = repo) + usecase('b3d3b3b3-dc0d-4fc1-861c-506a40cc2925') \ No newline at end of file diff --git a/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py b/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py new file mode 100644 index 0000000..c2ac5b5 --- /dev/null +++ b/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py @@ -0,0 +1,26 @@ +from src.modules.get_bookings.app.get_bookings_viewmodel import GetBookingsViewmodel +from src.modules.get_bookings.app.get_bookings_usecase import GetBookingsUseCase +from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock + +class Test_GetBookingsViewModel: + def test_get_bookings_viewmodel(self): + repo = BookingRepositoryMock() + usecase = GetBookingsUseCase(repo) + booking = usecase(booking_id=repo.bookings[0].booking_id) + + viewmodel = GetBookingsViewmodel(bookings=booking).to_dict() + + expected = { + 'bookings': [{ + 'start_date': 1634576165000, + 'end_date': 1634583365000, + 'court_number': 1, + 'sport': 'Tennis', + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', + 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] + }], + 'message': 'the bookings were retrieved' + } + + assert viewmodel == expected \ No newline at end of file From 0dfadf8460f160a9856b242f114c1202045397bc Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Tue, 5 Aug 2025 09:35:18 -0300 Subject: [PATCH 078/167] attemp 1 reverting changes, merging old commit with todays dev --- .gitignore | 2 +- iac/stacks/lambda_stack.py | 27 +- requirements-dev.txt | 5 +- .../app/delete_booking_controller.py | 18 +- .../app/generate_report_extractor.py | 21 -- .../app/generate_report_transformer.py | 28 -- .../app/get_all_bookings_usecase.py | 2 - .../app/get_all_courts_controller.py | 1 + .../app/get_all_courts_usecase.py | 2 - .../get_booking/app/get_booking_controller.py | 25 +- .../get_booking/app/get_booking_usecase.py | 16 +- .../app/get_bookings_controller.py | 2 +- .../app/get_bookings_presenter.py | 2 +- .../get_bookings/app/get_bookings_usecase.py | 2 +- .../app/get_bookings_viewmodel.py | 2 +- .../get_court/app/get_court_controller.py | 23 +- src/shared/clients/user_api_client.py | 12 +- .../booking_repository_interface.py | 5 +- src/shared/helpers/errors/domain_errors.py | 3 +- src/shared/helpers/errors/usecase_errors.py | 4 - .../repositories/booking_repository_dynamo.py | 36 ++- .../repositories/booking_repository_mock.py | 44 ++- .../reservation_repository_dynamo.py | 3 +- .../__init__.py | 0 .../app/__init__.py | 0 .../app/test_delete_booking_controller.py | 73 +++-- .../app/test_delete_booking_presenter.py | 32 +++ .../app/test_delete_booking_usecase.py | 25 +- .../app/test_delete_booking_viewmodel.py | 7 +- .../app}/__init__.py | 0 .../app/test_generate_report_aggregator.py | 22 -- .../app/test_generate_report_transformer.py | 37 --- .../app/test_get_all_bookings_usecase.py | 2 +- .../app => get_all_courts}/__init__.py | 0 .../app}/__init__.py | 0 .../app/test_get_all_courts_controller.py | 0 .../app/test_get_all_courts_presenter.py | 2 +- .../app/test_get_all_courts_usecase.py | 0 .../app/test_get_all_courts_viewmodel.py | 0 .../get_all_courts_usecase/app/__init__.py | 0 .../app/test_get_booking_controller.py | 40 +-- .../app/test_get_booking_presenter.py | 20 +- .../app/test_get_booking_viewmodel.py | 2 +- .../app/test_get_bookings_controller.py | 2 +- .../app/test_get_bookings_presenter.py | 4 +- .../app/test_get_bookings_viewmodel.py | 2 +- .../app/test_get_court_controller.py | 16 +- .../get_court/app/test_get_court_presenter.py | 16 +- .../test_booking_repository_dynamo.py | 253 ++++++++++++++++-- .../test_booking_repository_mock.py | 2 +- .../test_reservation_repository_dynamo.py | 7 +- 51 files changed, 528 insertions(+), 321 deletions(-) delete mode 100644 src/modules/generate_report/app/generate_report_extractor.py delete mode 100644 src/modules/generate_report/app/generate_report_transformer.py rename tests/modules/{delete_bookings => delete_booking}/__init__.py (100%) rename tests/modules/{delete_bookings => delete_booking}/app/__init__.py (100%) rename tests/modules/{delete_bookings => delete_booking}/app/test_delete_booking_controller.py (61%) rename tests/modules/{delete_bookings => delete_booking}/app/test_delete_booking_presenter.py (82%) rename tests/modules/{delete_bookings => delete_booking}/app/test_delete_booking_usecase.py (65%) rename tests/modules/{delete_bookings => delete_booking}/app/test_delete_booking_viewmodel.py (74%) rename tests/modules/{generate_report => delete_court/app}/__init__.py (100%) delete mode 100644 tests/modules/generate_report/app/test_generate_report_aggregator.py delete mode 100644 tests/modules/generate_report/app/test_generate_report_transformer.py rename tests/modules/{generate_report/app => get_all_courts}/__init__.py (100%) rename tests/modules/{get_all_courts_usecase => get_all_courts/app}/__init__.py (100%) rename tests/modules/{get_all_courts_usecase => get_all_courts}/app/test_get_all_courts_controller.py (100%) rename tests/modules/{get_all_courts_usecase => get_all_courts}/app/test_get_all_courts_presenter.py (95%) rename tests/modules/{get_all_courts_usecase => get_all_courts}/app/test_get_all_courts_usecase.py (100%) rename tests/modules/{get_all_courts_usecase => get_all_courts}/app/test_get_all_courts_viewmodel.py (100%) delete mode 100644 tests/modules/get_all_courts_usecase/app/__init__.py diff --git a/.gitignore b/.gitignore index 9d783f9..5e06bd6 100644 --- a/.gitignore +++ b/.gitignore @@ -135,5 +135,5 @@ dmypy.json /.idea/ iac/local/docker/dynamodb/shared-local-instance.db -# MACOS temp files + .DS_Store \ No newline at end of file diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index 58d5de5..45a3c1c 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -48,16 +48,11 @@ def create_lambda_event_bridge_integration(self, ) rule = Rule( - self, f"{module_name.title()}EventRuleForWeeklyUpload", + self, f"{module_name.title()}EventRule", schedule=cron_schedule ) - input_transformer = RuleTargetInput.from_object({ - "current_date": EventField.time, - "message": "weekly report trigger!" - }) - - rule.add_target(LambdaFunction(function, event=input_transformer)) + rule.add_target(LambdaFunction(function)) return function @@ -80,8 +75,8 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment ) authorizer_lambda = lambda_.Function( - self, "AuthorizerUserMssReservationApiLambda", - code=lambda_.Code.from_asset("../src/shared/authorizer"), + self, "GetUserAuthroizer", + code=lambda_.Code.from_asset("../src/shared/authorizer"), # TODO check if this matches current merge handler="user_mss_authorizer.lambda_handler", runtime=lambda_.Runtime.PYTHON_3_9, layers=[self.lambda_layer], @@ -90,10 +85,10 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment ) token_authorizer_lambda = apigw.TokenAuthorizer( - self, "TokenAuthorizerReservationApi", + self, "TokenAuthorizerReservationAlerts", handler=authorizer_lambda, identity_source=apigw.IdentitySource.header("Authorization"), - authorizer_name="AuthorizerUserMssReservationMssAlertLambda", + authorizer_name="GetUserAuthorizerForAlertsMss", results_cache_ttl=Duration.seconds(0) ) @@ -117,12 +112,11 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment #not ready for auth AND not used? self.get_booking = self.create_lambda_api_gateway_integration( module_name="get_booking", - method="POST", + method="GET", api_resource=api_gateway_resource, environment_variables=environment_variables ) - self.get_bookings = self.create_lambda_api_gateway_integration( module_name="get_bookings", method="GET", @@ -135,7 +129,8 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment module_name="delete_booking", method="DELETE", api_resource=api_gateway_resource, - environment_variables=environment_variables + environment_variables=environment_variables, + authorizer=self.token_authorizer_graph ) #not ready and unused @@ -158,7 +153,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment #not ready TODO self.get_court = self.create_lambda_api_gateway_integration( module_name="get_court", - method="POST", + method="GET", api_resource=api_gateway_resource, environment_variables=environment_variables ) @@ -200,7 +195,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment #does not need auth / not a route self.generate_report = self.create_lambda_event_bridge_integration( module_name="generate_report", - cron_schedule=Schedule.cron(week_day="FRI", hour="18"), + cron_schedule=Schedule.cron(minute="0", hour="18", week_day="FRI"), environment_variables=environment_variables ) diff --git a/requirements-dev.txt b/requirements-dev.txt index 44455a7..ab21f95 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,7 +3,4 @@ pytest-cov==4.0.0 boto3==1.24.88 python-dotenv==0.21.0 aws-lambda-powertools==2.9.0 -aws_xray_sdk==2.11.0 -pandas==2.2.3 -XlsxWriter==3.2.2 -requests==2.32.3 \ No newline at end of file +aws_xray_sdk==2.11.0 \ No newline at end of file diff --git a/src/modules/delete_booking/app/delete_booking_controller.py b/src/modules/delete_booking/app/delete_booking_controller.py index eb0d69b..c02e519 100644 --- a/src/modules/delete_booking/app/delete_booking_controller.py +++ b/src/modules/delete_booking/app/delete_booking_controller.py @@ -1,13 +1,13 @@ -from typing import Any -from src.shared.domain.entities.booking import Booking +import json + from .delete_booking_usecase import DeleteBookingUsecase from .delete_booking_viewmodel import DeleteBookingViewModel -from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter +from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter, AuthorizerError from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.errors.usecase_errors import NoItemsFound, ForbiddenAction from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse -from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, Created, InternalServerError, NotFound -from src.shared.domain.enums.sport import SPORT +from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, InternalServerError, NotFound, Forbidden + class DeleteBookingController: @@ -32,6 +32,12 @@ def __call__(self, request: IRequest) -> IResponse: except MissingParameters as err: return BadRequest(body=err.message) + + except ForbiddenAction as err: + return Forbidden(body=err.message) + + except AuthorizerError as err: + return InternalServerError(body=err.message) except WrongTypeParameter as err: return BadRequest(body=err.message) diff --git a/src/modules/generate_report/app/generate_report_extractor.py b/src/modules/generate_report/app/generate_report_extractor.py deleted file mode 100644 index eb8e0c1..0000000 --- a/src/modules/generate_report/app/generate_report_extractor.py +++ /dev/null @@ -1,21 +0,0 @@ -from src.shared.domain.repositories.booking_repository_interface import IBookingRepository -from src.shared.helpers.errors.usecase_errors import DynamoDBBaseError - - -class GenerateReportExtractor: - - def __init__(self, booking_repository: IBookingRepository): - self.booking_repository = booking_repository - - def __call__(self, initial_date, final_date): - - try: - #TODO fazer chamada get_all_users - #retornar booking, users - - bookings = self.booking_repository.get_all_bookings_by_date_range(initial_date, final_date) - - except: - raise DynamoDBBaseError("Error extracting bookings from dynamo") - - return bookings diff --git a/src/modules/generate_report/app/generate_report_transformer.py b/src/modules/generate_report/app/generate_report_transformer.py deleted file mode 100644 index 59adba0..0000000 --- a/src/modules/generate_report/app/generate_report_transformer.py +++ /dev/null @@ -1,28 +0,0 @@ -from .generate_report_aggregator import GenerateReportAggregator -import pandas as pd -import io - -class GenerateReportTransformer: - - def __init__(self, aggregator: GenerateReportAggregator): - self.aggregator = aggregator - - def __call__(self, initial_date, final_date): - - user_statistics, court_statistics, sports_statistics = self.aggregator(initial_date, final_date) - - df_users = pd.DataFrame.from_dict(user_statistics, orient="index") - df_courts = pd.DataFrame.from_dict(court_statistics, orient="index") - df_sports = pd.DataFrame.from_dict(sports_statistics, orient="index") - - output = io.BytesIO() - - with pd.ExcelWriter(output, engine="xlsxwriter") as writer: - df_users.to_excel(writer, sheet_name="Usuários") - df_courts.to_excel(writer, sheet_name="Quadras") - df_sports.to_excel(writer, sheet_name="Esportes") - - output.seek(0) - - return output - diff --git a/src/modules/get_all_bookings/app/get_all_bookings_usecase.py b/src/modules/get_all_bookings/app/get_all_bookings_usecase.py index fe4533e..70acd06 100644 --- a/src/modules/get_all_bookings/app/get_all_bookings_usecase.py +++ b/src/modules/get_all_bookings/app/get_all_bookings_usecase.py @@ -1,6 +1,4 @@ -from typing import Any from src.shared.domain.repositories.booking_repository_interface import IBookingRepository -from src.shared.domain.entities.booking import Booking class GetAllBookingsUsecase: def __init__(self, repo: IBookingRepository): diff --git a/src/modules/get_all_courts/app/get_all_courts_controller.py b/src/modules/get_all_courts/app/get_all_courts_controller.py index afeda0f..ef80113 100644 --- a/src/modules/get_all_courts/app/get_all_courts_controller.py +++ b/src/modules/get_all_courts/app/get_all_courts_controller.py @@ -17,6 +17,7 @@ def __call__(self, request: IRequest): courts = self.usecase() viewmodel = GetAllCourtsViewModel(courts).to_dict() return OK(viewmodel) + except EntityError as err: return BadRequest(body=err.message) diff --git a/src/modules/get_all_courts/app/get_all_courts_usecase.py b/src/modules/get_all_courts/app/get_all_courts_usecase.py index 4814e43..85f5943 100644 --- a/src/modules/get_all_courts/app/get_all_courts_usecase.py +++ b/src/modules/get_all_courts/app/get_all_courts_usecase.py @@ -1,6 +1,4 @@ -from typing import Any from src.shared.domain.repositories.reservation_repository_interface import IReservationRepository -from src.shared.domain.entities.court import Court class GetAllCourtsUsecase: def __init__(self, repo: IReservationRepository): diff --git a/src/modules/get_booking/app/get_booking_controller.py b/src/modules/get_booking/app/get_booking_controller.py index 3d9d0a2..2939634 100644 --- a/src/modules/get_booking/app/get_booking_controller.py +++ b/src/modules/get_booking/app/get_booking_controller.py @@ -1,6 +1,6 @@ from .get_booking_viewmodel import GetBookingViewmodel from .get_booking_usecase import GetBookingUseCase -from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter +from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter, EmptyQueryParameters from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.errors.usecase_errors import NoItemsFound from src.shared.helpers.external_interfaces.external_interface import IRequest @@ -13,25 +13,26 @@ def __init__(self, usecase: GetBookingUseCase): def __call__(self, request: IRequest): try: - if request.data.get('booking_id') is None: - raise MissingParameters('booking_id') - - booking_id = request.data.get('booking_id') + + booking_id = request.data.get('booking_id', None) if booking_id is not None: - if type(booking_id) is not str: - raise WrongTypeParameter( - 'booking_id', - 'str', - (type(booking_id)).__name__ - ) + if not isinstance(booking_id, str): + raise WrongTypeParameter('booking_id', + fieldTypeReceived=type(booking_id).__name__, + fieldTypeExpected='str') + else: + raise MissingParameters('booking_id') booking = self.usecase( - booking_id = request.data.get('booking_id') + booking_id=booking_id ) booking_viewmodel = GetBookingViewmodel(booking) return OK(booking_viewmodel.to_dict()) + except EmptyQueryParameters as err: + return BadRequest(body=err.message) + except MissingParameters as err: return BadRequest(body=err.message) diff --git a/src/modules/get_booking/app/get_booking_usecase.py b/src/modules/get_booking/app/get_booking_usecase.py index ecc32e8..c31b44b 100644 --- a/src/modules/get_booking/app/get_booking_usecase.py +++ b/src/modules/get_booking/app/get_booking_usecase.py @@ -1,7 +1,9 @@ +from typing import Optional + from src.shared.domain.entities.booking import Booking from src.shared.domain.repositories.booking_repository_interface import IBookingRepository from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.errors.usecase_errors import NoItemsFound, DependantFilter class GetBookingUseCase: repo: IBookingRepository @@ -9,11 +11,15 @@ class GetBookingUseCase: def __init__(self, repo: IBookingRepository): self.repo = repo - def __call__(self, booking_id: str): - if not Booking.validate_booking_id(booking_id=booking_id): + def __call__(self, + booking_id: str): + + if not Booking.validate_booking_id(booking_id): raise EntityError('booking_id') - - booking = self.repo.get_booking(booking_id=booking_id) + + booking = self.repo.get_booking( + booking_id=booking_id + ) if booking is None: raise NoItemsFound('booking_id') diff --git a/src/modules/get_bookings/app/get_bookings_controller.py b/src/modules/get_bookings/app/get_bookings_controller.py index abae3b3..5715e8d 100644 --- a/src/modules/get_bookings/app/get_bookings_controller.py +++ b/src/modules/get_bookings/app/get_bookings_controller.py @@ -92,4 +92,4 @@ def __call__(self, request: IRequest): return BadRequest(body=err.message) except Exception as err: - return InternalServerError(body=err.args[0]) \ No newline at end of file + return InternalServerError(body=err.args[0]) diff --git a/src/modules/get_bookings/app/get_bookings_presenter.py b/src/modules/get_bookings/app/get_bookings_presenter.py index a44f717..1815d57 100644 --- a/src/modules/get_bookings/app/get_bookings_presenter.py +++ b/src/modules/get_bookings/app/get_bookings_presenter.py @@ -14,4 +14,4 @@ def lambda_handler(event, context): response = controller(request=httpRequest) httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) - return httpResponse.toDict() \ No newline at end of file + return httpResponse.toDict() diff --git a/src/modules/get_bookings/app/get_bookings_usecase.py b/src/modules/get_bookings/app/get_bookings_usecase.py index 57d099d..614b675 100644 --- a/src/modules/get_bookings/app/get_bookings_usecase.py +++ b/src/modules/get_bookings/app/get_bookings_usecase.py @@ -49,4 +49,4 @@ def __call__(self, if bookings is None or bookings == []: raise NoItemsFound('booking filters passed') - return bookings \ No newline at end of file + return bookings diff --git a/src/modules/get_bookings/app/get_bookings_viewmodel.py b/src/modules/get_bookings/app/get_bookings_viewmodel.py index 18e1b7c..d8ad428 100644 --- a/src/modules/get_bookings/app/get_bookings_viewmodel.py +++ b/src/modules/get_bookings/app/get_bookings_viewmodel.py @@ -12,4 +12,4 @@ def to_dict(self): return { 'bookings': [booking.to_dict() for booking in self.bookings], 'message': 'the bookings were retrieved' - } \ No newline at end of file + } diff --git a/src/modules/get_court/app/get_court_controller.py b/src/modules/get_court/app/get_court_controller.py index ad2e675..35427bd 100644 --- a/src/modules/get_court/app/get_court_controller.py +++ b/src/modules/get_court/app/get_court_controller.py @@ -15,18 +15,21 @@ def __call__(self, request: IRequest): try: if request.data.get('number') is None: raise MissingParameters('number') - + number = request.data.get('number') if number is not None: - if type(number) is not int: + + try: + number = int(number) + + except ValueError: raise WrongTypeParameter('number', 'int', type(number).__name__) - - court = self.usecase( - number= request.data.get('number') - ) - court_viewmodel = GetCourtViewmodel(court= court) + court = self.usecase( + number=number + ) + court_viewmodel = GetCourtViewmodel(court=court) return OK(court_viewmodel.to_dict()) @@ -45,9 +48,3 @@ def __call__(self, request: IRequest): except Exception as err: return InternalServerError(body=err.args[0]) - - - - - - diff --git a/src/shared/clients/user_api_client.py b/src/shared/clients/user_api_client.py index 913135d..0ba2d41 100644 --- a/src/shared/clients/user_api_client.py +++ b/src/shared/clients/user_api_client.py @@ -21,7 +21,7 @@ def retrieve_users(): api_url= os.environ.get("USER_API_URL") try: - response = requests.get(api_url + '/get-all-users') + response = requests.get(api_url + '/reservation-mss-user/get-all-users') users = response.json().get("users") return users except: @@ -32,8 +32,14 @@ def retrieve_users(): @staticmethod def _auth_user(token): + ''' + UNUSED AND DEPRECATED DO NOT USE + ''' + #this will only get the user info if the user is already created in db, else it will delete the user shortly after + #UNUSED DO NOT USE THIS, ITS DEPRECATED + api_url = os.environ.get("USER_API_URL") #untested funtion @@ -45,7 +51,7 @@ def delete_user(token): "Authorization": f"Bearer{token}" } - response = requests.delete(api_url + '/delete-user', headers=headers) + response = requests.delete(api_url + 'reservation-mss-user/delete-user', headers=headers) return response.json().get("message") @@ -59,7 +65,7 @@ def delete_user(token): "Authorization": f"Bearer {token}" } - response = requests.get(api_url + '/auth-user', headers=headers) + response = requests.get(api_url + 'reservation-mss-user/auth-user', headers=headers) user = response.json().get("user") diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index e003c39..cc8df67 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -34,7 +34,8 @@ def update_booking(self, pass @abstractmethod - def get_booking(self, booking_id: str) -> Optional[Booking]: + def get_booking(self, + booking_id: str) -> Optional[Booking]: ''' If the booking exists, returns it, else returns None ''' @@ -82,4 +83,4 @@ def send_user_email(self, user) -> bool: ''' Send user an e-mail ''' - pass \ No newline at end of file + pass diff --git a/src/shared/helpers/errors/domain_errors.py b/src/shared/helpers/errors/domain_errors.py index 6b00235..305be4c 100644 --- a/src/shared/helpers/errors/domain_errors.py +++ b/src/shared/helpers/errors/domain_errors.py @@ -29,4 +29,5 @@ def message(self): class EntityParameterTimeError(BaseError): def __init__(self, start_Date: int, end_date: int): - super().__init__(f'Initial time {start_Date} must be less than or equal to end time {end_date}') \ No newline at end of file + super().__init__(f'Initial time {start_Date} must be less than or equal to end time {end_date}') + diff --git a/src/shared/helpers/errors/usecase_errors.py b/src/shared/helpers/errors/usecase_errors.py index 371c9c7..5609355 100644 --- a/src/shared/helpers/errors/usecase_errors.py +++ b/src/shared/helpers/errors/usecase_errors.py @@ -16,10 +16,6 @@ class DependantFilter(BaseError): def __init__(self, message: str): super().__init__(f'Filters have to be provided together: {message}') -class DynamoDBBaseError(BaseError): - def __init__(self, message: str): - super().__init__(f'Error extracting bookings from dynamo: {message}') - class InvalidSchedule(BaseError): def __init__(self): super().__init__('Court is already booked for the selected time slot or has to have 15 min tolerance') diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index 410c518..b515c89 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -66,7 +66,7 @@ def update_booking(self, "sport": sport.value if sport is not None else booking_to_update.sport.value, "materials": materials if materials is not None else booking_to_update.materials, "user_id": booking_to_update.user_id, - "booking_id": booking_to_update.booking_id + "booking_id": booking_to_update.booking_id, } resp = self.dynamo.update_item(update_dict=update_dict, @@ -78,6 +78,40 @@ def update_booking(self, return BookingDynamoDTO.from_dynamo(resp['Attributes']).to_entity() + def get_bookings(self, + booking_id: Optional[str] = None, + user_id: Optional[str] = None, + sport: Optional[SPORT] = None, + court_number: Optional[int] = None, + end_date: Optional[int] = None, + start_date: Optional[int] = None) -> List[Optional[Booking]]: + + filters = locals().copy() + filters.pop('self') + filters.pop('end_date') + filters.pop('start_date') + + filters = {k: v for k, v in filters.items() if v is not None} + + all_bookings = self.get_all_bookings() + + bookings = [] + + for booking in all_bookings: + booking_dict = booking.__dict__ + if start_date and end_date: + if all( + booking_dict.get(key) == value for key, value in filters.items() + ) and booking.start_date >= start_date and booking.end_date <= end_date: + bookings.append(booking) + else: + if all( + booking_dict.get(key) == value for key, value in filters.items() + ): + bookings.append(booking) + + return bookings + def get_booking(self, booking_id: str) -> Optional[Booking]: dynamo_object = self.dynamo.get_item(partition_key=self.booking_partition_key_format(), diff --git a/src/shared/infra/repositories/booking_repository_mock.py b/src/shared/infra/repositories/booking_repository_mock.py index e64416c..bb44017 100644 --- a/src/shared/infra/repositories/booking_repository_mock.py +++ b/src/shared/infra/repositories/booking_repository_mock.py @@ -15,7 +15,7 @@ def __init__(self): end_date=1634583365000, court_number=1, sport=SPORT.TENNIS, - user_id='1f25448b-3429-4c19-8287-d9e64f17bc3a', + user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Raquete', 'Bola', 'Rede', 'Tenis'] ), @@ -25,7 +25,7 @@ def __init__(self): end_date=1634567400000, court_number=2, sport=SPORT.FOOTBALL, - user_id='c07e0862-3c07-4227-ab0f-511a267cb7ff', + user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b2d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Bola', 'Chuteira'] ), @@ -35,7 +35,7 @@ def __init__(self): end_date=1634571000000, court_number=3, sport=SPORT.BASKETBALL, - user_id='d351a9b1-937f-423c-a9d1-9929b5795be1', + user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b3d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Bola'] ), @@ -122,7 +122,41 @@ def update_booking(self, return booking - def get_booking(self, booking_id: str): + def get_bookings(self, + booking_id: Optional[str] = None, + user_id: Optional[str] = None, + sport: Optional[str] = None, + court_number: Optional[int] = None, + end_date: Optional[int] = None, + start_date: Optional[int] = None) -> List[Optional[Booking]]: + + filters = locals().copy() + filters.pop('self') + filters.pop('end_date') + filters.pop('start_date') + + filters = {k: v for k, v in filters.items() if v is not None} + + bookings = [] + + for booking in self.bookings: + booking_dict = booking.__dict__ + if start_date and end_date: + if all( + booking_dict.get(key) == value for key, value in filters.items() + ) and booking.start_date >= start_date and booking.end_date <= end_date: + bookings.append(booking) + else: + if all( + booking_dict.get(key) == value for key, value in filters.items() + ): + bookings.append(booking) + + return bookings + + def get_booking(self, + booking_id: str) -> Optional[Booking]: + for booking in self.bookings: if booking.booking_id == booking_id: return booking @@ -202,4 +236,4 @@ def get_all_users(self) -> List[str]: def send_user_email(self, user) -> bool: print('ENVIAR E-MAIL PARA O USUÁRIO') - return True \ No newline at end of file + return True diff --git a/src/shared/infra/repositories/reservation_repository_dynamo.py b/src/shared/infra/repositories/reservation_repository_dynamo.py index 195d1c8..5a65f38 100644 --- a/src/shared/infra/repositories/reservation_repository_dynamo.py +++ b/src/shared/infra/repositories/reservation_repository_dynamo.py @@ -49,7 +49,8 @@ def get_all_courts(self) -> list[Court]: all_items = self.dynamo.get_all_items().get('Items') for item in all_items: - all_courts.append(CourtDynamoDTO.from_dynamo(item).to_entity()) + if item.get("entity") == "Court": + all_courts.append(CourtDynamoDTO.from_dynamo(item).to_entity()) return all_courts diff --git a/tests/modules/delete_bookings/__init__.py b/tests/modules/delete_booking/__init__.py similarity index 100% rename from tests/modules/delete_bookings/__init__.py rename to tests/modules/delete_booking/__init__.py diff --git a/tests/modules/delete_bookings/app/__init__.py b/tests/modules/delete_booking/app/__init__.py similarity index 100% rename from tests/modules/delete_bookings/app/__init__.py rename to tests/modules/delete_booking/app/__init__.py diff --git a/tests/modules/delete_bookings/app/test_delete_booking_controller.py b/tests/modules/delete_booking/app/test_delete_booking_controller.py similarity index 61% rename from tests/modules/delete_bookings/app/test_delete_booking_controller.py rename to tests/modules/delete_booking/app/test_delete_booking_controller.py index b4fcf77..69e384b 100644 --- a/tests/modules/delete_bookings/app/test_delete_booking_controller.py +++ b/tests/modules/delete_booking/app/test_delete_booking_controller.py @@ -3,10 +3,11 @@ from src.shared.helpers.external_interfaces.http_models import HttpRequest from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock + class TestDeleteBookingController: def test_delete_booking_controller(self): repo = BookingRepositoryMock() - usecase = DeleteBookingUsecase(repo= repo) + usecase = DeleteBookingUsecase(repo=repo) controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body= { "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', @@ -24,11 +25,12 @@ def test_delete_booking_controller(self): def test_delete_booking_controller_missing_booking_id(self): repo = BookingRepositoryMock() - usecase = DeleteBookingUsecase(repo= repo) + usecase = DeleteBookingUsecase(repo=repo) controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body={ - "booking_id": None, - "user_from_authorizer": { + "booking_id": None + }, headers={ + 'user_from_authorizer': { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', 'email': 'user@email.com', 'role': 'STUDENT' @@ -41,18 +43,19 @@ def test_delete_booking_controller_missing_booking_id(self): def test_delete_booking_controller_booking_id_entity_error(self): repo = BookingRepositoryMock() - usecase = DeleteBookingUsecase(repo= repo) + usecase = DeleteBookingUsecase(repo=repo) controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body={ - "booking_id": 0, - "user_from_authorizer": { - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', - 'name': 'Nome', - 'email': 'user@email.com', - 'role': 'STUDENT' + "booking_id": 0 + }, headers={ + 'user_from_authorizer': { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' } }) - + reponse = controller(request) assert reponse.status_code == 400 assert reponse.body == "Field booking_id is not valid" @@ -62,12 +65,13 @@ def test_delete_booking_controller_wrong_type_parameter(self): usecase = DeleteBookingUsecase(repo=repo) controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body={ - "booking_id": "wrong_type", - "user_from_authorizer": { - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', - 'name': 'Nome', - 'email': 'user@email.com', - 'role': 'STUDENT' + "booking_id": "not an id" + }, headers={ + 'user_from_authorizer': { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' } }) @@ -80,15 +84,34 @@ def test_delete_booking_controller_not_found(self): usecase = DeleteBookingUsecase(repo=repo) controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body={ - "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2926', - "user_from_authorizer": { - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', - 'name': 'Nome', - 'email': 'user@email.com', - 'role': 'STUDENT' + "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2926' + }, headers={ + 'user_from_authorizer': { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' } }) response = controller(request) assert response.status_code == 404 - assert response.body == "No items found for booking" \ No newline at end of file + assert response.body == "No items found for booking" + + def test_delete_bookings_controller_forbidden(self): + repo = BookingRepositoryMock() + usecase = DeleteBookingUsecase(repo=repo) + controller = DeleteBookingController(usecase=usecase) + request = HttpRequest(body={ + "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' + }, headers={ + 'user_from_authorizer': { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + }) + response = controller(request) + + assert response.status_code == 403 diff --git a/tests/modules/delete_bookings/app/test_delete_booking_presenter.py b/tests/modules/delete_booking/app/test_delete_booking_presenter.py similarity index 82% rename from tests/modules/delete_bookings/app/test_delete_booking_presenter.py rename to tests/modules/delete_booking/app/test_delete_booking_presenter.py index a7d296a..6a9b438 100644 --- a/tests/modules/delete_bookings/app/test_delete_booking_presenter.py +++ b/tests/modules/delete_booking/app/test_delete_booking_presenter.py @@ -25,6 +25,7 @@ def test_delete_booking_presenter(self): "apiId": "", "authentication": None, "authorizer": { +<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_presenter.py "user": json.dumps({ "user": { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', @@ -34,6 +35,13 @@ def test_delete_booking_presenter(self): }, "message": "the user was retrieved" }) +======= + 'user': { + 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'displayName': 'John Doe', + 'mail': 'JD@maua.br' + } +>>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_presenter.py }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -86,6 +94,7 @@ def test_delete_booking_presenter_missing_booking_id(self): "apiId": "", "authentication": None, "authorizer": { +<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_presenter.py "user": json.dumps({ "user": { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', @@ -95,6 +104,13 @@ def test_delete_booking_presenter_missing_booking_id(self): }, "message": "the user was retrieved" }) +======= + 'user': { + 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'displayName': 'John Doe', + 'mail': 'JD@maua.br' + } +>>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_presenter.py }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -144,6 +160,7 @@ def test_delete_booking_not_found(self): "apiId": "", "authentication": None, "authorizer": { +<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_presenter.py "user": json.dumps({ "user": { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', @@ -153,6 +170,13 @@ def test_delete_booking_not_found(self): }, "message": "the user was retrieved" }) +======= + 'user': { + 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'displayName': 'John Doe', + 'mail': 'JD@maua.br' + } +>>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_presenter.py }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -202,6 +226,7 @@ def test_delete_booking_wrong_type(self): "apiId": "", "authentication": None, "authorizer": { +<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_presenter.py "user": json.dumps({ "user": { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', @@ -211,6 +236,13 @@ def test_delete_booking_wrong_type(self): }, "message": "the user was retrieved" }) +======= + 'user': { + 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'displayName': 'John Doe', + 'mail': 'JD@maua.br' + } +>>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_presenter.py }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", diff --git a/tests/modules/delete_bookings/app/test_delete_booking_usecase.py b/tests/modules/delete_booking/app/test_delete_booking_usecase.py similarity index 65% rename from tests/modules/delete_bookings/app/test_delete_booking_usecase.py rename to tests/modules/delete_booking/app/test_delete_booking_usecase.py index 4778989..02727b5 100644 --- a/tests/modules/delete_bookings/app/test_delete_booking_usecase.py +++ b/tests/modules/delete_booking/app/test_delete_booking_usecase.py @@ -1,13 +1,15 @@ import pytest +<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_usecase.py from typing import Any, Optional from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.status_enum import STATUS from src.shared.helpers.errors.usecase_errors import DuplicatedItem, ForbiddenAction +======= +>>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_usecase.py from src.shared.helpers.errors.domain_errors import EntityError from src.modules.delete_booking.app.delete_booking_usecase import DeleteBookingUsecase from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock from src.shared.helpers.errors.usecase_errors import NoItemsFound -from src.shared.domain.repositories.booking_repository_interface import IBookingRepository class Test_DeleteBookingUsecase: def test_delete_booking_usecase(self): @@ -21,7 +23,12 @@ def test_delete_booking_usecase(self): 'role': 'STUDENT' } +<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_usecase.py booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', user=user) +======= + booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', + user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98') +>>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_usecase.py assert len(repo.bookings) == len_before - 1 def test_delete_booking_usecase_admin(self): @@ -61,7 +68,12 @@ def test_delete_booking_usecase_no_items_found(self): 'role': 'STUDENT' } with pytest.raises(NoItemsFound): +<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_usecase.py booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2926', user = user) +======= + booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2926', + user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98') +>>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_usecase.py def test_delete_booking_usecase_invalid_booking_id(self): repo = BookingRepositoryMock() @@ -74,7 +86,16 @@ def test_delete_booking_usecase_invalid_booking_id(self): } with pytest.raises(EntityError): +<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_usecase.py usecase(booking_id=-1, user=user) with pytest.raises(EntityError): - usecase(booking_id=None,user=user) \ No newline at end of file + usecase(booking_id=None,user=user) +======= + usecase(booking_id=-1, + user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98') + + with pytest.raises(EntityError): + usecase(booking_id=None, + user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98') +>>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_usecase.py diff --git a/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py b/tests/modules/delete_booking/app/test_delete_booking_viewmodel.py similarity index 74% rename from tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py rename to tests/modules/delete_booking/app/test_delete_booking_viewmodel.py index 339d113..e35d010 100644 --- a/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py +++ b/tests/modules/delete_booking/app/test_delete_booking_viewmodel.py @@ -8,6 +8,7 @@ class Test_DeleteBookingViewModel: def test_delete_booking_viewmodel(self): repo = BookingRepositoryMock() usecase = DeleteBookingUsecase(repo=repo) +<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py user = { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', 'name': 'Nome', @@ -15,6 +16,10 @@ def test_delete_booking_viewmodel(self): 'role': 'STUDENT' } booking = usecase(booking_id=repo.bookings[0].booking_id, user=user) +======= + booking = usecase(booking_id=repo.bookings[0].booking_id, + user_id=repo.bookings[0].user_id) +>>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_viewmodel.py viewmodel = DeleteBookingViewModel(booking=booking).to_dict() expected = { @@ -23,7 +28,7 @@ def test_delete_booking_viewmodel(self): 'end_date': 1634583365000, 'court_number': 1, 'sport': 'Tennis', - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] }, diff --git a/tests/modules/generate_report/__init__.py b/tests/modules/delete_court/app/__init__.py similarity index 100% rename from tests/modules/generate_report/__init__.py rename to tests/modules/delete_court/app/__init__.py diff --git a/tests/modules/generate_report/app/test_generate_report_aggregator.py b/tests/modules/generate_report/app/test_generate_report_aggregator.py deleted file mode 100644 index 6b2fcd3..0000000 --- a/tests/modules/generate_report/app/test_generate_report_aggregator.py +++ /dev/null @@ -1,22 +0,0 @@ -import pytest - -from src.modules.generate_report.app.generate_report_aggregator import GenerateReportAggregator -from src.modules.generate_report.app.generate_report_extractor import GenerateReportExtractor -from src.shared.infra.repositories.booking_repository_dynamo import BookingRepositoryDynamo - - -class TestGenerateReportAggregator: - - @pytest.mark.skip("Can't run test in gh actions") - def test_generate_report_aggregator(self): - - repo = BookingRepositoryDynamo() - - # Arrange - extractor = GenerateReportExtractor(booking_repository=repo) - aggregator = GenerateReportAggregator(extractor) - - # Act - result = aggregator(1577836800, 1767225600) - - print(result) \ No newline at end of file diff --git a/tests/modules/generate_report/app/test_generate_report_transformer.py b/tests/modules/generate_report/app/test_generate_report_transformer.py deleted file mode 100644 index 9a9e831..0000000 --- a/tests/modules/generate_report/app/test_generate_report_transformer.py +++ /dev/null @@ -1,37 +0,0 @@ -import platform -import subprocess -import pytest - -from src.modules.generate_report.app.generate_report_aggregator import GenerateReportAggregator -from src.modules.generate_report.app.generate_report_extractor import GenerateReportExtractor -from src.modules.generate_report.app.generate_report_transformer import GenerateReportTransformer -from src.shared.infra.repositories.booking_repository_dynamo import BookingRepositoryDynamo -import tempfile -import os - -class TestGenerateReportTransformer: - - @pytest.mark.skip("Can't run test in gh actions") - def test_generate_report_transformer(self): - - repo = BookingRepositoryDynamo() - extractor = GenerateReportExtractor(booking_repository=repo) - aggregator = GenerateReportAggregator(extractor=extractor) - - transformer = GenerateReportTransformer(aggregator=aggregator) - - output = transformer(1577836800, 1767225600) - - with tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") as tmp_file: - tmp_file.write(output.read()) - tmp_file_path = tmp_file.name - - # os.startfile(tmp_file_path) - - system = platform.system() - if system == 'Windows': - os.startfile(tmp_file_path) - elif system == 'Darwin': - subprocess.call(['open', tmp_file_path]) - else: - subprocess.call(['xdg-open', tmp_file_path]) \ No newline at end of file diff --git a/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py b/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py index 17b0a56..236704e 100644 --- a/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py +++ b/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py @@ -15,6 +15,6 @@ def test_get_all_bookings_usecase(self): assert bookings[0].start_date == 1634576165000 assert bookings[0].end_date == 1634583365000 assert bookings[0].sport == SPORT.TENNIS - assert bookings[0].user_id == '1f25448b-3429-4c19-8287-d9e64f17bc3a' + assert bookings[0].user_id == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' assert bookings[0].booking_id == 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' assert bookings[0].materials == ['Raquete', 'Bola', 'Rede', 'Tenis'] \ No newline at end of file diff --git a/tests/modules/generate_report/app/__init__.py b/tests/modules/get_all_courts/__init__.py similarity index 100% rename from tests/modules/generate_report/app/__init__.py rename to tests/modules/get_all_courts/__init__.py diff --git a/tests/modules/get_all_courts_usecase/__init__.py b/tests/modules/get_all_courts/app/__init__.py similarity index 100% rename from tests/modules/get_all_courts_usecase/__init__.py rename to tests/modules/get_all_courts/app/__init__.py diff --git a/tests/modules/get_all_courts_usecase/app/test_get_all_courts_controller.py b/tests/modules/get_all_courts/app/test_get_all_courts_controller.py similarity index 100% rename from tests/modules/get_all_courts_usecase/app/test_get_all_courts_controller.py rename to tests/modules/get_all_courts/app/test_get_all_courts_controller.py diff --git a/tests/modules/get_all_courts_usecase/app/test_get_all_courts_presenter.py b/tests/modules/get_all_courts/app/test_get_all_courts_presenter.py similarity index 95% rename from tests/modules/get_all_courts_usecase/app/test_get_all_courts_presenter.py rename to tests/modules/get_all_courts/app/test_get_all_courts_presenter.py index 61198b0..2f214f4 100644 --- a/tests/modules/get_all_courts_usecase/app/test_get_all_courts_presenter.py +++ b/tests/modules/get_all_courts/app/test_get_all_courts_presenter.py @@ -40,7 +40,7 @@ def test_lambda_handler(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": '{"number": 7, "status": "AVAILABLE", "is_field": false, "photo": "photo"}', + "body": None, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None diff --git a/tests/modules/get_all_courts_usecase/app/test_get_all_courts_usecase.py b/tests/modules/get_all_courts/app/test_get_all_courts_usecase.py similarity index 100% rename from tests/modules/get_all_courts_usecase/app/test_get_all_courts_usecase.py rename to tests/modules/get_all_courts/app/test_get_all_courts_usecase.py diff --git a/tests/modules/get_all_courts_usecase/app/test_get_all_courts_viewmodel.py b/tests/modules/get_all_courts/app/test_get_all_courts_viewmodel.py similarity index 100% rename from tests/modules/get_all_courts_usecase/app/test_get_all_courts_viewmodel.py rename to tests/modules/get_all_courts/app/test_get_all_courts_viewmodel.py diff --git a/tests/modules/get_all_courts_usecase/app/__init__.py b/tests/modules/get_all_courts_usecase/app/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/modules/get_booking/app/test_get_booking_controller.py b/tests/modules/get_booking/app/test_get_booking_controller.py index 3cdfc18..bc5fdc5 100644 --- a/tests/modules/get_booking/app/test_get_booking_controller.py +++ b/tests/modules/get_booking/app/test_get_booking_controller.py @@ -8,14 +8,8 @@ def test_get_booking_controller(self): repo = BookingRepositoryMock() usecase = GetBookingUseCase(repo=repo) controller = GetBookingController(usecase=usecase) - request = HttpRequest(body={ + request = HttpRequest(query_params={ 'booking_id': 'b2d3bebf-dc0d-4fc1-861c-506a40cc2925', - 'start_date': 1634563800000, - 'end_date': 1634567400000, - 'court_number': 2, - 'sport': 'FOOTBALL', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - }) response = controller(request) @@ -25,39 +19,26 @@ def test_get_booking_controller(self): assert response.body['booking']['end_date'] == 1634567400000 assert response.body['booking']['court_number'] == 2 assert response.body['booking']['sport'] == 'Football' - assert response.body['booking']['user_id'] == 'c07e0862-3c07-4227-ab0f-511a267cb7ff' + assert response.body['booking']['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' assert response.body['booking']['materials'] == ['Bola', 'Chuteira'] def test_get_booking_controller_missing_booking_id(self): repo = BookingRepositoryMock() usecase = GetBookingUseCase(repo=repo) controller = GetBookingController(usecase=usecase) - request = HttpRequest(body={ - 'start_date': 1634563800000, - 'end_date': 1634567400000, - 'court_number': 2, - 'sport': 'Football', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - + request = HttpRequest(query_params={ }) response = controller(request) assert response.status_code == 400 assert response.body == 'Field booking_id is missing' - def test_get_booking_controller_wrong_type_booking_id(self): repo = BookingRepositoryMock() usecase = GetBookingUseCase(repo=repo) controller = GetBookingController(usecase=usecase) - request = HttpRequest(body={ + request = HttpRequest(query_params={ 'booking_id': 123, - 'start_date': 1634563800000, - 'end_date': 1634567400000, - 'court_number': 2, - 'sport': 'Football', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - }) response = controller(request) @@ -71,21 +52,10 @@ def test_get_booking_controller_booking_not_found(self): repo = BookingRepositoryMock() usecase = GetBookingUseCase(repo=repo) controller = GetBookingController(usecase=usecase) - request = HttpRequest(body={ + request = HttpRequest(query_params={ 'booking_id': 'b2d3bebf-dc0d-4fc1-861c-506a40cc2943', - 'start_date': 1634563800000, - 'end_date': 1634567400000, - 'court_number': 2, - 'sport': 'Football', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98' - }) response = controller(request) assert response.status_code == 404 assert response.body == 'No items found for booking_id' - - - - - \ No newline at end of file diff --git a/tests/modules/get_booking/app/test_get_booking_presenter.py b/tests/modules/get_booking/app/test_get_booking_presenter.py index dcab6cb..d54a475 100644 --- a/tests/modules/get_booking/app/test_get_booking_presenter.py +++ b/tests/modules/get_booking/app/test_get_booking_presenter.py @@ -19,7 +19,7 @@ def test_get_booking_presenter(self): "header2": "value1,value2" }, "queryStringParameters": { - "parameter1": "1" + "booking_id": "b1d3bebf-dc0d-4fc1-861c-506a40cc2925" }, "requestContext": { "accountId": "123456789012", @@ -42,7 +42,7 @@ def test_get_booking_presenter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {"booking_id":'b1d3bebf-dc0d-4fc1-861c-506a40cc2925'}, + "body": {}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -57,7 +57,7 @@ def test_get_booking_presenter(self): assert json.loads(response['body'])['booking']['end_date'] == 1634583365000 assert json.loads(response['body'])['booking']['court_number'] == 1 assert json.loads(response['body'])['booking']['sport'] == 'Tennis' - assert json.loads(response['body'])['booking']['user_id'] == '1f25448b-3429-4c19-8287-d9e64f17bc3a' + assert json.loads(response['body'])['booking']['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' assert json.loads(response['body'])['booking']['materials'] == ['Raquete', 'Bola', 'Rede', 'Tenis'] @@ -107,7 +107,7 @@ def test_get_booking_presenter_missing_parameters(self): response = lambda_handler(event, None) assert response['statusCode'] == 400 - assert json.loads(response['body']) == 'Field booking_id is missing' + assert json.loads(response['body']) == "Field booking_id is missing" def test_get_booking_presenter_entity_error(self): event = { @@ -124,7 +124,7 @@ def test_get_booking_presenter_entity_error(self): "header2": "value1,value2" }, "queryStringParameters": { - "parameter1": "1" + "booking_id":'teste' }, "requestContext": { "accountId": "123456789012", @@ -147,7 +147,7 @@ def test_get_booking_presenter_entity_error(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {"booking_id":'teste'}, + "body": {}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -174,7 +174,7 @@ def test_get_booking_presenter_wrong_type_parameter(self): "header2": "value1,value2" }, "queryStringParameters": { - "parameter1": "1" + "booking_id":10 }, "requestContext": { "accountId": "123456789012", @@ -197,7 +197,7 @@ def test_get_booking_presenter_wrong_type_parameter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {"booking_id":10}, + "body": {}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -224,7 +224,7 @@ def test_get_booking_presenter_entity_not_found(self): "header2": "value1,value2" }, "queryStringParameters": { - "parameter1": "1" + "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2989' }, "requestContext": { "accountId": "123456789012", @@ -247,7 +247,7 @@ def test_get_booking_presenter_entity_not_found(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {"booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2989'}, + "body": {}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None diff --git a/tests/modules/get_booking/app/test_get_booking_viewmodel.py b/tests/modules/get_booking/app/test_get_booking_viewmodel.py index 6cec5ef..a3b80a6 100644 --- a/tests/modules/get_booking/app/test_get_booking_viewmodel.py +++ b/tests/modules/get_booking/app/test_get_booking_viewmodel.py @@ -16,7 +16,7 @@ def test_get_booking_viewmodel(self): 'end_date': 1634583365000, 'court_number': 1, 'sport': 'Tennis', - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] }, diff --git a/tests/modules/get_bookings/app/test_get_bookings_controller.py b/tests/modules/get_bookings/app/test_get_bookings_controller.py index be8c438..4f9f8b5 100644 --- a/tests/modules/get_bookings/app/test_get_bookings_controller.py +++ b/tests/modules/get_bookings/app/test_get_bookings_controller.py @@ -214,4 +214,4 @@ def test_get_bookings_user_id_not_valid(self): 'user_id': '1' }) response = self.controller(request) - assert response.status_code == 400 \ No newline at end of file + assert response.status_code == 400 diff --git a/tests/modules/get_bookings/app/test_get_bookings_presenter.py b/tests/modules/get_bookings/app/test_get_bookings_presenter.py index 080419c..c8307ed 100644 --- a/tests/modules/get_bookings/app/test_get_bookings_presenter.py +++ b/tests/modules/get_bookings/app/test_get_bookings_presenter.py @@ -2,7 +2,7 @@ from src.modules.get_bookings.app.get_bookings_presenter import lambda_handler from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock -class Test_GetBookingPresenter: +class TestGetBookingsPresenter: def test_get_bookings_presenter(self): event = { @@ -67,7 +67,7 @@ def test_get_bookings_presenter(self): assert json.loads(response['body'])['bookings'][0]['end_date'] == 1634583365000 assert json.loads(response['body'])['bookings'][0]['court_number'] == 1 assert json.loads(response['body'])['bookings'][0]['sport'] == 'Tennis' - assert json.loads(response['body'])['bookings'][0]['user_id'] == '1f25448b-3429-4c19-8287-d9e64f17bc3a' + assert json.loads(response['body'])['bookings'][0]['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' assert json.loads(response['body'])['bookings'][0]['materials'] == ['Raquete', 'Bola', 'Rede', 'Tenis'] diff --git a/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py b/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py index c2ac5b5..27bcd57 100644 --- a/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py +++ b/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py @@ -16,7 +16,7 @@ def test_get_bookings_viewmodel(self): 'end_date': 1634583365000, 'court_number': 1, 'sport': 'Tennis', - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] }], diff --git a/tests/modules/get_court/app/test_get_court_controller.py b/tests/modules/get_court/app/test_get_court_controller.py index 5a4a39a..62fe2ca 100644 --- a/tests/modules/get_court/app/test_get_court_controller.py +++ b/tests/modules/get_court/app/test_get_court_controller.py @@ -10,8 +10,8 @@ def test_get_court_controller(self): repo = ReservationRepositoryMock() usecase = GetCourtUsecase(repo=repo) controller = GetCourtController(usecase=usecase) - request = HttpRequest(body={ - "number": 2 + request = HttpRequest(query_params={ + "number": "2" }) response = controller(request) @@ -27,7 +27,7 @@ def test_get_court_controller_missing_number(self): repo = ReservationRepositoryMock() usecase = GetCourtUsecase(repo=repo) controller = GetCourtController(usecase=usecase) - request = HttpRequest(body={ + request = HttpRequest(query_params={ "status": "AVAILABLE", "is_field": False, "photo": "https://www.linkedin.com/in/giovanna-albuquerque-16917a245/" @@ -43,11 +43,8 @@ def test_get_court_controller_wrong_type_parameters(self): repo = ReservationRepositoryMock() usecase = GetCourtUsecase(repo=repo) controller = GetCourtController(usecase=usecase) - request = HttpRequest(body={ + request = HttpRequest(query_params={ "number": "cavalo", - "status": "AVAILABLE", - "is_field": False, - "photo": "https://www.linkedin.com/in/giovanna-albuquerque-16917a245/" }) response = controller(request) @@ -61,11 +58,8 @@ def test_get_court_controller_court_not_found(self): repo = ReservationRepositoryMock() usecase = GetCourtUsecase(repo=repo) controller = GetCourtController(usecase=usecase) - request = HttpRequest(body={ + request = HttpRequest(query_params={ "number": 10, - "status": "AVAILABLE", - "is_field": False, - "photo": "https://www.linkedin.com/in/giovanna-albuquerque-16917a245/" }) response = controller(request) diff --git a/tests/modules/get_court/app/test_get_court_presenter.py b/tests/modules/get_court/app/test_get_court_presenter.py index 46ee487..7f93dfb 100644 --- a/tests/modules/get_court/app/test_get_court_presenter.py +++ b/tests/modules/get_court/app/test_get_court_presenter.py @@ -19,7 +19,7 @@ def test_get_court_presenter(self): "header2": "value1,value2" }, "queryStringParameters": { - "parameter1": "1" + "number": "1" #tem que passar ja que no querry sempre vem como string }, "requestContext": { "accountId": "123456789012", @@ -42,7 +42,7 @@ def test_get_court_presenter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {"number":1}, + "body": {}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -117,7 +117,7 @@ def test_get_court_presenter_entity_error(self): "header2": "value1,value2" }, "queryStringParameters": { - "parameter1": "1" + "number": 15 }, "requestContext": { "accountId": "123456789012", @@ -140,7 +140,7 @@ def test_get_court_presenter_entity_error(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {"number": 15}, + "body": {}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -166,7 +166,7 @@ def test_get_court_presenter_wrong_type_parameter(self): "header2": "value1,value2" }, "queryStringParameters": { - "parameter1": "1" + "code": "1" }, "requestContext": { "accountId": "123456789012", @@ -189,7 +189,7 @@ def test_get_court_presenter_wrong_type_parameter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {"code": "1"}, + "body": {}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -216,7 +216,7 @@ def test_get_court_presenter_not_found(self): "header2": "value1,value2" }, "queryStringParameters": { - "parameter1": "1" + "number": 8 }, "requestContext": { "accountId": "123456789012", @@ -239,7 +239,7 @@ def test_get_court_presenter_not_found(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {"number": 8}, + "body": {}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None diff --git a/tests/shared/infra/repositories/test_booking_repository_dynamo.py b/tests/shared/infra/repositories/test_booking_repository_dynamo.py index 9bea994..c53f308 100644 --- a/tests/shared/infra/repositories/test_booking_repository_dynamo.py +++ b/tests/shared/infra/repositories/test_booking_repository_dynamo.py @@ -5,7 +5,7 @@ from src.shared.domain.entities.booking import Booking class TestBookingRepositoryDynamo: - + @pytest.mark.skip("Can't run test in github actions") def test_dynamo_get_all_bookings(self): dynamo_repo = BookingRepositoryDynamo() @@ -16,6 +16,25 @@ def test_dynamo_get_all_bookings(self): print( dynamo_bookings[0].start_date ) assert len(dynamo_bookings) == len(mock_bookings) + + + @pytest.mark.skip("Can't run test in github actions") + def test_dynamo_get_booking(self): + dynamo_repo = BookingRepositoryDynamo() + resp= dynamo_repo.get_booking('b1d3bebf-dc0d-4fc1-861c-506a40cc2925') + assert resp.booking_id == 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' + + + @pytest.mark.skip("Can't run test in github actions") + def test_dynamo_get_bookings_sport(self): + dynamo_repo = BookingRepositoryDynamo() + mock_repo = BookingRepositoryMock() + + dynamo_bookings = dynamo_repo.get_bookings(sport=SPORT.TENNIS.value) + mock_bookings = mock_repo.get_bookings(sport=SPORT.TENNIS.value) + + assert len(dynamo_bookings) == len(mock_bookings) + for d_booking, m_booking in zip(dynamo_bookings, mock_bookings): @@ -27,47 +46,202 @@ def test_dynamo_get_all_bookings(self): assert d_booking.user_id == m_booking.user_id assert d_booking.booking_id == m_booking.booking_id assert d_booking.materials == m_booking.materials - @pytest.mark.skip("Can't run test in github actions") - def test_dynamo_delete_booking(self): + + + @pytest.mark.skip("Can't run test in github actions") + def test_get_bookings_by_user_id(self): dynamo_repo = BookingRepositoryDynamo() mock_repo = BookingRepositoryMock() - user = { - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'email': 'user@email.com', - 'role': 'STUDENT' - } - booking = mock_repo.get_booking('b7d3bebf-dc0d-4fc1-861c-506a40cc2925') - deleted_booking = dynamo_repo.delete_booking(booking.booking_id, user) - retrieved_booking = dynamo_repo.get_booking(booking.booking_id) - assert retrieved_booking is None - assert deleted_booking.booking_id == booking.booking_id + + all_mock_bookings = mock_repo.get_all_bookings() + test_user_id = all_mock_bookings[0].user_id + + dynamo_bookings = dynamo_repo.get_bookings(user_id=test_user_id) + mock_bookings = mock_repo.get_bookings(user_id=test_user_id) + + assert len(dynamo_bookings) == len(mock_bookings) + + for booking in dynamo_bookings: + assert booking.user_id == test_user_id + + @pytest.mark.skip("Can't run test in github actions") + def test_get_bookings_by_court_number(self): + dynamo_repo = BookingRepositoryDynamo() + mock_repo = BookingRepositoryMock() + + for court_number in [1, 2, 3]: + dynamo_bookings = dynamo_repo.get_bookings(court_number=court_number) + mock_bookings = mock_repo.get_bookings(court_number=court_number) + + assert len(dynamo_bookings) == len(mock_bookings) + + for booking in dynamo_bookings: + assert booking.court_number == court_number + @pytest.mark.skip("Can't run test in github actions") - def test_dynamo_delete_booking_not_found(self): + def test_get_bookings_by_booking_id(self): dynamo_repo = BookingRepositoryDynamo() - user = { - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', - 'email': 'user@email.com', - 'role': 'STUDENT' - } - deleted_booking = dynamo_repo.delete_booking('b1d3bebf-dc0d-4fc1-861c-506a40cc2925', user) - assert deleted_booking is None + mock_repo = BookingRepositoryMock() + + test_booking_id = 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' + + dynamo_bookings = dynamo_repo.get_bookings(booking_id=test_booking_id) + mock_bookings = mock_repo.get_bookings(booking_id=test_booking_id) + + assert len(dynamo_bookings) == len(mock_bookings) + assert len(dynamo_bookings) == 1 + assert dynamo_bookings[0].booking_id == test_booking_id + @pytest.mark.skip("Can't run test in github actions") - def test_dynamo_get_booking(self): + def test_get_bookings_by_sport_and_court(self): dynamo_repo = BookingRepositoryDynamo() - resp= dynamo_repo.get_booking('b1d3bebf-dc0d-4fc1-861c-506a40cc2925') - assert resp.booking_id == 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' + mock_repo = BookingRepositoryMock() + + test_combinations = [ + (SPORT.TENNIS, 1), + (SPORT.FOOTBALL, 2), + (SPORT.BASKETBALL, 3) + ] + + for sport, court_number in test_combinations: + dynamo_bookings = dynamo_repo.get_bookings(sport=sport.value, court_number=court_number) + mock_bookings = mock_repo.get_bookings(sport=sport.value, court_number=court_number) + + assert len(dynamo_bookings) == len(mock_bookings) + + for booking in dynamo_bookings: + assert booking.sport == sport + assert booking.court_number == court_number + + + @pytest.mark.skip("Can't run test in github actions") + def test_get_bookings_by_sport_and_user(self): + dynamo_repo = BookingRepositoryDynamo() + mock_repo = BookingRepositoryMock() + + all_mock_bookings = mock_repo.get_all_bookings() + test_user_id = all_mock_bookings[0].user_id + + for sport in SPORT: + dynamo_bookings = dynamo_repo.get_bookings(sport=sport.value, user_id=test_user_id) + mock_bookings = mock_repo.get_bookings(sport=sport.value, user_id=test_user_id) + + assert len(dynamo_bookings) == len(mock_bookings) + + for booking in dynamo_bookings: + assert booking.sport == sport + assert booking.user_id == test_user_id + + + @pytest.mark.skip("Can't run test in github actions") + def test_get_bookings_by_user_and_court(self): + dynamo_repo = BookingRepositoryDynamo() + mock_repo = BookingRepositoryMock() + + all_mock_bookings = mock_repo.get_all_bookings() + test_user_id = all_mock_bookings[0].user_id + + for court_number in [1, 2, 3]: + dynamo_bookings = dynamo_repo.get_bookings(user_id=test_user_id, court_number=court_number) + mock_bookings = mock_repo.get_bookings(user_id=test_user_id, court_number=court_number) + + assert len(dynamo_bookings) == len(mock_bookings) + + for booking in dynamo_bookings: + assert booking.user_id == test_user_id + assert booking.court_number == court_number + + + @pytest.mark.skip("Can't run test in github actions") + def test_get_bookings_by_three_filters(self): + dynamo_repo = BookingRepositoryDynamo() + mock_repo = BookingRepositoryMock() + + all_mock_bookings = mock_repo.get_all_bookings() + test_user_id = all_mock_bookings[0].user_id + + test_combinations = [ + (SPORT.TENNIS, 1, test_user_id), + (SPORT.FOOTBALL, 2, test_user_id) + ] + + for sport, court_number, user_id in test_combinations: + dynamo_bookings = dynamo_repo.get_bookings( + sport=sport.value, + court_number=court_number, + user_id=user_id + ) + mock_bookings = mock_repo.get_bookings( + sport=sport.value, + court_number=court_number, + user_id=user_id + ) + + assert len(dynamo_bookings) == len(mock_bookings) + + for booking in dynamo_bookings: + assert booking.sport == sport + assert booking.court_number == court_number + assert booking.user_id == user_id + @pytest.mark.skip("Can't run test in github actions") + def test_get_bookings_by_date_range(self): + dynamo_repo = BookingRepositoryDynamo() + mock_repo = BookingRepositoryMock() + + start_date = 1634400000000 + end_date = 1634700000000 + + dynamo_bookings = dynamo_repo.get_bookings(start_date=start_date, end_date=end_date) + mock_bookings = mock_repo.get_bookings(start_date=start_date, end_date=end_date) + + assert len(dynamo_bookings) == len(mock_bookings) + + for booking in dynamo_bookings: + assert booking.start_date >= start_date + assert booking.end_date <= end_date + + + @pytest.mark.skip("Can't run test in github actions") + def test_get_bookings_by_sport_and_date_range(self): + dynamo_repo = BookingRepositoryDynamo() + mock_repo = BookingRepositoryMock() + + start_date = 1634400000000 + end_date = 1634700000000 + + for sport in SPORT: + dynamo_bookings = dynamo_repo.get_bookings( + sport=sport.value, + start_date=start_date, + end_date=end_date + ) + mock_bookings = mock_repo.get_bookings( + sport=sport.value, + start_date=start_date, + end_date=end_date + ) + + assert len(dynamo_bookings) == len(mock_bookings) + + for booking in dynamo_bookings: + assert booking.sport == sport + assert booking.start_date >= start_date + assert booking.end_date <= end_date + + + @pytest.mark.skip("Can't run test in github actions") def test_dynamo_update_booking(self): dynamo_repo = BookingRepositoryDynamo() booking_id = 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' updated_booking = dynamo_repo.update_booking( booking_id=booking_id, start_date=1234567890, - court_number=2, - sport=SPORT.TENNIS.value + court_number=2, + sport=SPORT.BASKETBALL ) @@ -75,8 +249,9 @@ def test_dynamo_update_booking(self): assert updated_booking.booking_id == booking_id assert updated_booking.start_date == 1234567890 assert updated_booking.court_number == 2 - assert updated_booking.sport == SPORT.TENNIS + assert updated_booking.sport == SPORT.BASKETBALL + @pytest.mark.skip("Can't run test in github actions") def test_dynamo_create_booking(self): dynamo_repo = BookingRepositoryDynamo() @@ -108,4 +283,26 @@ def test_dynamo_create_booking(self): assert retrieved_booking.sport == new_booking.sport assert retrieved_booking.user_id == new_booking.user_id assert retrieved_booking.booking_id == new_booking.booking_id - assert retrieved_booking.materials == new_booking.materials \ No newline at end of file + assert retrieved_booking.materials == new_booking.materials + + dynamo_repo.delete_booking(new_booking.booking_id) + + + @pytest.mark.skip("Can't run test in github actions") + def test_dynamo_delete_booking(self): + dynamo_repo = BookingRepositoryDynamo() + mock_repo = BookingRepositoryMock() + booking = mock_repo.get_booking('b5d3bebf-dc0d-4fc1-861c-506a40cc2925') + deleted_booking = dynamo_repo.delete_booking(booking.booking_id) + retrieved_booking = dynamo_repo.get_booking(booking.booking_id) + assert retrieved_booking is None + assert deleted_booking.booking_id == booking.booking_id + + + @pytest.mark.skip("Can't run test in github actions") + def test_dynamo_delete_booking_not_found(self): + dynamo_repo = BookingRepositoryDynamo() + deleted_booking = dynamo_repo.delete_booking('bau3bebf-dc0d-4fc1-861c-506a40cc2997') + assert deleted_booking is None + + diff --git a/tests/shared/infra/repositories/test_booking_repository_mock.py b/tests/shared/infra/repositories/test_booking_repository_mock.py index 2cb4128..6ba96ff 100644 --- a/tests/shared/infra/repositories/test_booking_repository_mock.py +++ b/tests/shared/infra/repositories/test_booking_repository_mock.py @@ -40,7 +40,7 @@ def test_get_booking(self): assert booking is not None assert booking.booking_id == booking_id - assert booking.user_id == '1f25448b-3429-4c19-8287-d9e64f17bc3a' + assert booking.user_id == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' assert booking.sport == SPORT.TENNIS assert booking.court_number == 1 assert booking.start_date == 1634576165000 diff --git a/tests/shared/infra/repositories/test_reservation_repository_dynamo.py b/tests/shared/infra/repositories/test_reservation_repository_dynamo.py index fe65af8..b486e55 100644 --- a/tests/shared/infra/repositories/test_reservation_repository_dynamo.py +++ b/tests/shared/infra/repositories/test_reservation_repository_dynamo.py @@ -10,6 +10,7 @@ class TestReservationRepositoryDynamo: + @pytest.mark.skip("Can't run test in github actions") def test_dynamo_delete_court(self): dynamo_repo = ReservationRepositoryDynamo() @@ -29,7 +30,7 @@ def test_dynamo_delete_court_not_found(self): @pytest.mark.skip("Can't run test in github actions") def test_update_court(self): repo = ReservationRepositoryDynamo() - resp = repo.update_court(number=3, new_photo="https://www.linkedin.com/in/giovanna-albuquerque-16917a245/") + resp = repo.update_court(number=3, photo="https://www.linkedin.com/in/giovanna-albuquerque-16917a245/") assert resp.number == 3 assert resp.photo == "https://www.linkedin.com/in/giovanna-albuquerque-16917a245/" @@ -61,6 +62,6 @@ def test_dynamo_create_court(self): new_court = Court(number=6, status=STATUS.MAINTENANCE, is_field=False, photo=None) size = len(dynamo_repo.get_all_courts()) - assert new_court == dynamo_repo.create_court(new_court) - assert dynamo_repo.get_court(6) == new_court + assert new_court.__dict__ == dynamo_repo.create_court(new_court).__dict__ + assert dynamo_repo.get_court(6).__dict__ == new_court.__dict__ From 3b6567114b01799c3ddb8912e019e6f57d60d144 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Tue, 5 Aug 2025 11:26:18 -0300 Subject: [PATCH 079/167] pre-merge checkpoint --- .gitignore | 2 +- iac/local/minio/docker-compose-minio.yml | 4 +- iac/stacks/lambda_stack.py | 24 ++++---- requirements-dev.txt | 5 +- .../app/delete_booking_controller.py | 18 ++---- .../app/delete_booking_usecase.py | 7 ++- .../app/generate_report_aggregator.py | 1 - .../app/generate_report_extractor.py | 20 +++++++ .../app/generate_report_sender.py | 57 +++++++++++++++++++ .../app/generate_report_transformer.py | 28 +++++++++ .../app/get_all_bookings_controller.py | 4 +- .../app/get_all_bookings_usecase.py | 2 + .../app/get_all_bookings_viewmodel.py | 2 +- .../app/get_all_courts_controller.py | 3 - .../get_booking/app/get_booking_controller.py | 25 ++++---- .../get_booking/app/get_booking_usecase.py | 16 ++---- .../get_court/app/get_court_controller.py | 24 ++++---- .../booking_repository_interface.py | 4 +- src/shared/helpers/errors/usecase_errors.py | 4 ++ .../repositories/booking_repository_dynamo.py | 4 +- .../repositories/booking_repository_mock.py | 42 ++------------ .../reservation_repository_dynamo.py | 1 - .../infra/repositories/util/S3Manager.py | 46 +++++++++++++++ .../__init__.py | 0 .../app/__init__.py | 0 .../app/test_delete_booking_controller.py | 7 +-- .../app/test_delete_booking_presenter.py | 32 ----------- .../app/test_delete_booking_usecase.py | 37 ++---------- .../app/test_delete_booking_viewmodel.py | 7 +-- tests/modules/generate_report/__init__.py | 0 tests/modules/generate_report/app/__init__.py | 0 .../app/test_generate_report_aggregator.py | 22 +++++++ .../app/test_generate_report_sender.py | 38 +++++++++++++ .../app/test_generate_report_transformer.py | 37 ++++++++++++ .../app/test_get_all_bookings_usecase.py | 4 +- .../app/test_get_all_bookings_viewmodel.py | 4 +- .../app/test_get_all_courts_presenter.py | 2 +- .../app/test_get_booking_controller.py | 4 +- .../app/test_get_booking_presenter.py | 15 ++--- .../app/test_get_booking_viewmodel.py | 2 +- .../app/test_get_bookings_presenter.py | 2 +- .../app/test_get_bookings_viewmodel.py | 2 +- .../get_court/app/test_get_court_presenter.py | 16 +++--- .../test_booking_repository_dynamo.py | 2 +- .../test_booking_repository_mock.py | 2 +- .../test_reservation_repository_dynamo.py | 8 +-- 46 files changed, 366 insertions(+), 220 deletions(-) create mode 100644 src/modules/generate_report/app/generate_report_extractor.py create mode 100644 src/modules/generate_report/app/generate_report_sender.py create mode 100644 src/modules/generate_report/app/generate_report_transformer.py create mode 100644 src/shared/infra/repositories/util/S3Manager.py rename tests/modules/{delete_booking => delete_bookings}/__init__.py (100%) rename tests/modules/{delete_booking => delete_bookings}/app/__init__.py (100%) rename tests/modules/{delete_booking => delete_bookings}/app/test_delete_booking_controller.py (97%) rename tests/modules/{delete_booking => delete_bookings}/app/test_delete_booking_presenter.py (82%) rename tests/modules/{delete_booking => delete_bookings}/app/test_delete_booking_usecase.py (61%) rename tests/modules/{delete_booking => delete_bookings}/app/test_delete_booking_viewmodel.py (74%) create mode 100644 tests/modules/generate_report/__init__.py create mode 100644 tests/modules/generate_report/app/__init__.py create mode 100644 tests/modules/generate_report/app/test_generate_report_aggregator.py create mode 100644 tests/modules/generate_report/app/test_generate_report_sender.py create mode 100644 tests/modules/generate_report/app/test_generate_report_transformer.py diff --git a/.gitignore b/.gitignore index 5e06bd6..9d783f9 100644 --- a/.gitignore +++ b/.gitignore @@ -135,5 +135,5 @@ dmypy.json /.idea/ iac/local/docker/dynamodb/shared-local-instance.db - +# MACOS temp files .DS_Store \ No newline at end of file diff --git a/iac/local/minio/docker-compose-minio.yml b/iac/local/minio/docker-compose-minio.yml index fcf5ebc..4a0b046 100644 --- a/iac/local/minio/docker-compose-minio.yml +++ b/iac/local/minio/docker-compose-minio.yml @@ -6,7 +6,7 @@ services: container_name: minio-reservation # ✅ SET credentials for the MinIO server environment: - MINIO_ROOT_USER: root + MINIO_ROOT_USER: root # If you change any credentials, you have to match it in environments MINIO_ROOT_PASSWORD: root1234 ports: - "9000:9000" @@ -38,4 +38,4 @@ services: " volumes: - minio-data: \ No newline at end of file + minio-data: diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index 45a3c1c..51ab6a3 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -48,11 +48,16 @@ def create_lambda_event_bridge_integration(self, ) rule = Rule( - self, f"{module_name.title()}EventRule", + self, f"{module_name.title()}EventRuleForWeeklyUpload", schedule=cron_schedule ) - rule.add_target(LambdaFunction(function)) + input_transformer = RuleTargetInput.from_object({ + "current_date": EventField.time, + "message": "weekly report trigger!" + }) + + rule.add_target(LambdaFunction(function, event=input_transformer)) return function @@ -75,8 +80,8 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment ) authorizer_lambda = lambda_.Function( - self, "GetUserAuthroizer", - code=lambda_.Code.from_asset("../src/shared/authorizer"), # TODO check if this matches current merge + self, "AuthorizerUserMssReservationApiLambda", + code=lambda_.Code.from_asset("../src/shared/authorizer"), handler="user_mss_authorizer.lambda_handler", runtime=lambda_.Runtime.PYTHON_3_9, layers=[self.lambda_layer], @@ -85,10 +90,10 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment ) token_authorizer_lambda = apigw.TokenAuthorizer( - self, "TokenAuthorizerReservationAlerts", + self, "TokenAuthorizerReservationApi", handler=authorizer_lambda, identity_source=apigw.IdentitySource.header("Authorization"), - authorizer_name="GetUserAuthorizerForAlertsMss", + authorizer_name="AuthorizerUserMssReservationMssAlertLambda", results_cache_ttl=Duration.seconds(0) ) @@ -124,16 +129,15 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment environment_variables=environment_variables, ) - #not ready for auth?? TODO Gasperi + #not ready for auth??TODO self.delete_booking = self.create_lambda_api_gateway_integration( module_name="delete_booking", method="DELETE", api_resource=api_gateway_resource, - environment_variables=environment_variables, - authorizer=self.token_authorizer_graph + environment_variables=environment_variables ) - #not ready and unused + #not auth and unused self.get_all_bookings = self.create_lambda_api_gateway_integration( module_name="get_all_bookings", method="GET", diff --git a/requirements-dev.txt b/requirements-dev.txt index ab21f95..44455a7 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,4 +3,7 @@ pytest-cov==4.0.0 boto3==1.24.88 python-dotenv==0.21.0 aws-lambda-powertools==2.9.0 -aws_xray_sdk==2.11.0 \ No newline at end of file +aws_xray_sdk==2.11.0 +pandas==2.2.3 +XlsxWriter==3.2.2 +requests==2.32.3 \ No newline at end of file diff --git a/src/modules/delete_booking/app/delete_booking_controller.py b/src/modules/delete_booking/app/delete_booking_controller.py index c02e519..eb0d69b 100644 --- a/src/modules/delete_booking/app/delete_booking_controller.py +++ b/src/modules/delete_booking/app/delete_booking_controller.py @@ -1,13 +1,13 @@ -import json - +from typing import Any +from src.shared.domain.entities.booking import Booking from .delete_booking_usecase import DeleteBookingUsecase from .delete_booking_viewmodel import DeleteBookingViewModel -from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter, AuthorizerError +from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.errors.usecase_errors import NoItemsFound, ForbiddenAction +from src.shared.helpers.errors.usecase_errors import NoItemsFound from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse -from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, InternalServerError, NotFound, Forbidden - +from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, Created, InternalServerError, NotFound +from src.shared.domain.enums.sport import SPORT class DeleteBookingController: @@ -32,12 +32,6 @@ def __call__(self, request: IRequest) -> IResponse: except MissingParameters as err: return BadRequest(body=err.message) - - except ForbiddenAction as err: - return Forbidden(body=err.message) - - except AuthorizerError as err: - return InternalServerError(body=err.message) except WrongTypeParameter as err: return BadRequest(body=err.message) diff --git a/src/modules/delete_booking/app/delete_booking_usecase.py b/src/modules/delete_booking/app/delete_booking_usecase.py index a82b5f0..18559e1 100644 --- a/src/modules/delete_booking/app/delete_booking_usecase.py +++ b/src/modules/delete_booking/app/delete_booking_usecase.py @@ -3,10 +3,10 @@ from src.shared.helpers.errors.usecase_errors import DuplicatedItem from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.errors.usecase_errors import NoItemsFound -from src.shared.domain.repositories.reservation_repository_interface import IReservationRepository +from src.shared.domain.repositories.booking_repository_interface import IBookingRepository class DeleteBookingUsecase: - def __init__(self, repo:IReservationRepository): + def __init__(self, repo:IBookingRepository): self.repo = repo def __call__(self, booking_id: int, user): @@ -27,6 +27,9 @@ def __call__(self, booking_id: int, user): booking = self.repo.delete_booking(booking_id=booking_id, user=user) + if booking is None: + raise NoItemsFound('booking') + if booking is None: raise NoItemsFound('booking') diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index e06c041..f899fba 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -1,5 +1,4 @@ from src.shared.clients.user_api_client import UserAPIClient -from src.shared.domain.entities.booking import Booking from .generate_report_extractor import GenerateReportExtractor from typing import List diff --git a/src/modules/generate_report/app/generate_report_extractor.py b/src/modules/generate_report/app/generate_report_extractor.py new file mode 100644 index 0000000..e0e732f --- /dev/null +++ b/src/modules/generate_report/app/generate_report_extractor.py @@ -0,0 +1,20 @@ +from src.shared.domain.repositories.booking_repository_interface import IBookingRepository +from src.shared.helpers.errors.usecase_errors import DynamoDBBaseError + + +class GenerateReportExtractor: + + def __init__(self, booking_repository: IBookingRepository): + self.booking_repository = booking_repository + + def __call__(self, initial_date, final_date): + + try: + + #TODO Add method to interface + bookings = self.booking_repository.get_all_bookings_by_date_range(initial_date, final_date) + + except: + raise DynamoDBBaseError("Error extracting bookings from dynamo") + + return bookings diff --git a/src/modules/generate_report/app/generate_report_sender.py b/src/modules/generate_report/app/generate_report_sender.py new file mode 100644 index 0000000..0844a2f --- /dev/null +++ b/src/modules/generate_report/app/generate_report_sender.py @@ -0,0 +1,57 @@ +# import datetime +# import time + +# from src.shared.environments import Environments +# from src.shared.infra.repositories.util.S3Manager import S3Manager + +# from .generate_report_extractor import GenerateReportExtractor +# from .generate_report_aggregator import GenerateReportAggregator +# from .generate_report_transformer import GenerateReportTransformer + +# repo = Environments.get_envs().get_booking_repo()() + + +# def lambda_handler(event, context): +# extractor = GenerateReportExtractor(repo) +# #"2025-04-03T15:00:00Z" date format + +# current_date = datetime.datetime.now() + +# year = current_date.year +# month = current_date.month +# year_start_date = datetime.datetime(year, 1, 1) + +# start_date = int(time.mktime(year_start_date.timetuple())) * 1000 +# final_date = int(time.mktime(current_date.timetuple())) * 1000 + +# file_name = f"relatorio_gerado_em_{current_date.day}_{month}_{year}.xlsx" +# file_path = f"relatorios/" + +# extractor = GenerateReportExtractor(booking_repository=repo) +# aggregator = GenerateReportAggregator(extractor=extractor) +# transformer = GenerateReportTransformer(aggregator=aggregator) +# report = transformer(start_date, final_date) + +# if report: + +# bucket_manager = S3Manager() + +# try: + +# response = bucket_manager.upload_file(key=file_path + file_name, +# file_type=".xlsx", +# decode_string=report, +# ) + +# print("Report generated and uploaded successfully") + +# return 1 + +# except: + +# raise Exception("Error uploading file to S3") + + +# else: + +# raise Exception("Error generating report") diff --git a/src/modules/generate_report/app/generate_report_transformer.py b/src/modules/generate_report/app/generate_report_transformer.py new file mode 100644 index 0000000..59adba0 --- /dev/null +++ b/src/modules/generate_report/app/generate_report_transformer.py @@ -0,0 +1,28 @@ +from .generate_report_aggregator import GenerateReportAggregator +import pandas as pd +import io + +class GenerateReportTransformer: + + def __init__(self, aggregator: GenerateReportAggregator): + self.aggregator = aggregator + + def __call__(self, initial_date, final_date): + + user_statistics, court_statistics, sports_statistics = self.aggregator(initial_date, final_date) + + df_users = pd.DataFrame.from_dict(user_statistics, orient="index") + df_courts = pd.DataFrame.from_dict(court_statistics, orient="index") + df_sports = pd.DataFrame.from_dict(sports_statistics, orient="index") + + output = io.BytesIO() + + with pd.ExcelWriter(output, engine="xlsxwriter") as writer: + df_users.to_excel(writer, sheet_name="Usuários") + df_courts.to_excel(writer, sheet_name="Quadras") + df_sports.to_excel(writer, sheet_name="Esportes") + + output.seek(0) + + return output + diff --git a/src/modules/get_all_bookings/app/get_all_bookings_controller.py b/src/modules/get_all_bookings/app/get_all_bookings_controller.py index c8631df..3caa8bc 100644 --- a/src/modules/get_all_bookings/app/get_all_bookings_controller.py +++ b/src/modules/get_all_bookings/app/get_all_bookings_controller.py @@ -1,6 +1,6 @@ from typing import Any from .get_all_bookings_usecase import GetAllBookingsUsecase -from .get_all_bookings_viewmodel import GetAllBookingViewModel +from .get_all_bookings_viewmodel import GetAllBookingsViewModel from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.external_interfaces.external_interface import IRequest @@ -15,7 +15,7 @@ def __init__(self, usecase: GetAllBookingsUsecase): def __call__(self, request: IRequest): try: bookings = self.usecase() - viewmodel = GetAllBookingViewModel(bookings).to_dict() + viewmodel = GetAllBookingsViewModel(bookings).to_dict() return OK(viewmodel) except EntityError as err: return BadRequest(body=err.message) diff --git a/src/modules/get_all_bookings/app/get_all_bookings_usecase.py b/src/modules/get_all_bookings/app/get_all_bookings_usecase.py index 70acd06..fe4533e 100644 --- a/src/modules/get_all_bookings/app/get_all_bookings_usecase.py +++ b/src/modules/get_all_bookings/app/get_all_bookings_usecase.py @@ -1,4 +1,6 @@ +from typing import Any from src.shared.domain.repositories.booking_repository_interface import IBookingRepository +from src.shared.domain.entities.booking import Booking class GetAllBookingsUsecase: def __init__(self, repo: IBookingRepository): diff --git a/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py b/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py index b693175..963e786 100644 --- a/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py +++ b/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py @@ -41,7 +41,7 @@ def to_dict(self): 'booking' : self.booking_viewmodel.to_dict() } -class GetAllBookingViewModel: +class GetAllBookingsViewModel: bookings: List[GetBookingViewModel] def __init__(self, bookings: list): diff --git a/src/modules/get_all_courts/app/get_all_courts_controller.py b/src/modules/get_all_courts/app/get_all_courts_controller.py index ef80113..e7d5ba9 100644 --- a/src/modules/get_all_courts/app/get_all_courts_controller.py +++ b/src/modules/get_all_courts/app/get_all_courts_controller.py @@ -1,7 +1,5 @@ -from typing import Any from .get_all_courts_usecase import GetAllCourtsUsecase from .get_all_courts_viewmodel import GetAllCourtsViewModel -from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.external_interfaces.external_interface import IRequest from src.shared.helpers.external_interfaces.http_codes import BadRequest, OK, InternalServerError @@ -17,7 +15,6 @@ def __call__(self, request: IRequest): courts = self.usecase() viewmodel = GetAllCourtsViewModel(courts).to_dict() return OK(viewmodel) - except EntityError as err: return BadRequest(body=err.message) diff --git a/src/modules/get_booking/app/get_booking_controller.py b/src/modules/get_booking/app/get_booking_controller.py index 2939634..3d9d0a2 100644 --- a/src/modules/get_booking/app/get_booking_controller.py +++ b/src/modules/get_booking/app/get_booking_controller.py @@ -1,6 +1,6 @@ from .get_booking_viewmodel import GetBookingViewmodel from .get_booking_usecase import GetBookingUseCase -from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter, EmptyQueryParameters +from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.errors.usecase_errors import NoItemsFound from src.shared.helpers.external_interfaces.external_interface import IRequest @@ -13,26 +13,25 @@ def __init__(self, usecase: GetBookingUseCase): def __call__(self, request: IRequest): try: - - booking_id = request.data.get('booking_id', None) + if request.data.get('booking_id') is None: + raise MissingParameters('booking_id') + + booking_id = request.data.get('booking_id') if booking_id is not None: - if not isinstance(booking_id, str): - raise WrongTypeParameter('booking_id', - fieldTypeReceived=type(booking_id).__name__, - fieldTypeExpected='str') - else: - raise MissingParameters('booking_id') + if type(booking_id) is not str: + raise WrongTypeParameter( + 'booking_id', + 'str', + (type(booking_id)).__name__ + ) booking = self.usecase( - booking_id=booking_id + booking_id = request.data.get('booking_id') ) booking_viewmodel = GetBookingViewmodel(booking) return OK(booking_viewmodel.to_dict()) - except EmptyQueryParameters as err: - return BadRequest(body=err.message) - except MissingParameters as err: return BadRequest(body=err.message) diff --git a/src/modules/get_booking/app/get_booking_usecase.py b/src/modules/get_booking/app/get_booking_usecase.py index c31b44b..ecc32e8 100644 --- a/src/modules/get_booking/app/get_booking_usecase.py +++ b/src/modules/get_booking/app/get_booking_usecase.py @@ -1,9 +1,7 @@ -from typing import Optional - from src.shared.domain.entities.booking import Booking from src.shared.domain.repositories.booking_repository_interface import IBookingRepository from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.errors.usecase_errors import NoItemsFound, DependantFilter +from src.shared.helpers.errors.usecase_errors import NoItemsFound class GetBookingUseCase: repo: IBookingRepository @@ -11,15 +9,11 @@ class GetBookingUseCase: def __init__(self, repo: IBookingRepository): self.repo = repo - def __call__(self, - booking_id: str): - - if not Booking.validate_booking_id(booking_id): + def __call__(self, booking_id: str): + if not Booking.validate_booking_id(booking_id=booking_id): raise EntityError('booking_id') - - booking = self.repo.get_booking( - booking_id=booking_id - ) + + booking = self.repo.get_booking(booking_id=booking_id) if booking is None: raise NoItemsFound('booking_id') diff --git a/src/modules/get_court/app/get_court_controller.py b/src/modules/get_court/app/get_court_controller.py index 35427bd..1dff4e4 100644 --- a/src/modules/get_court/app/get_court_controller.py +++ b/src/modules/get_court/app/get_court_controller.py @@ -15,21 +15,19 @@ def __call__(self, request: IRequest): try: if request.data.get('number') is None: raise MissingParameters('number') - + number = request.data.get('number') + #TODO ajustar para vir do query parameters if number is not None: - - try: - number = int(number) - - except ValueError: + if type(number) is not int: raise WrongTypeParameter('number', 'int', type(number).__name__) - court = self.usecase( - number=number - ) - court_viewmodel = GetCourtViewmodel(court=court) + + court = self.usecase( + number= request.data.get('number') + ) + court_viewmodel = GetCourtViewmodel(court= court) return OK(court_viewmodel.to_dict()) @@ -48,3 +46,9 @@ def __call__(self, request: IRequest): except Exception as err: return InternalServerError(body=err.args[0]) + + + + + + diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index cc8df67..83ac220 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -34,8 +34,7 @@ def update_booking(self, pass @abstractmethod - def get_booking(self, - booking_id: str) -> Optional[Booking]: + def get_booking(self, booking_id: str) -> Optional[Booking]: ''' If the booking exists, returns it, else returns None ''' @@ -84,3 +83,4 @@ def send_user_email(self, user) -> bool: Send user an e-mail ''' pass + \ No newline at end of file diff --git a/src/shared/helpers/errors/usecase_errors.py b/src/shared/helpers/errors/usecase_errors.py index 5609355..371c9c7 100644 --- a/src/shared/helpers/errors/usecase_errors.py +++ b/src/shared/helpers/errors/usecase_errors.py @@ -16,6 +16,10 @@ class DependantFilter(BaseError): def __init__(self, message: str): super().__init__(f'Filters have to be provided together: {message}') +class DynamoDBBaseError(BaseError): + def __init__(self, message: str): + super().__init__(f'Error extracting bookings from dynamo: {message}') + class InvalidSchedule(BaseError): def __init__(self): super().__init__('Court is already booked for the selected time slot or has to have 15 min tolerance') diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index b515c89..6c7e857 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -66,7 +66,7 @@ def update_booking(self, "sport": sport.value if sport is not None else booking_to_update.sport.value, "materials": materials if materials is not None else booking_to_update.materials, "user_id": booking_to_update.user_id, - "booking_id": booking_to_update.booking_id, + "booking_id": booking_to_update.booking_id } resp = self.dynamo.update_item(update_dict=update_dict, @@ -159,8 +159,6 @@ def get_all_bookings(self) -> Optional[List[Booking]]: if item.get('entity') == 'booking': all_bookings.append(BookingDynamoDTO.from_dynamo(item).to_entity()) - return all_bookings - def get_all_bookings_by_date_range(self, initial_date: int, final_date: int) -> Optional[List[Booking]]: all_bookings = [] diff --git a/src/shared/infra/repositories/booking_repository_mock.py b/src/shared/infra/repositories/booking_repository_mock.py index bb44017..77e0b65 100644 --- a/src/shared/infra/repositories/booking_repository_mock.py +++ b/src/shared/infra/repositories/booking_repository_mock.py @@ -15,7 +15,7 @@ def __init__(self): end_date=1634583365000, court_number=1, sport=SPORT.TENNIS, - user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', + user_id='1f25448b-3429-4c19-8287-d9e64f17bc3a', booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Raquete', 'Bola', 'Rede', 'Tenis'] ), @@ -25,7 +25,7 @@ def __init__(self): end_date=1634567400000, court_number=2, sport=SPORT.FOOTBALL, - user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', + user_id='c07e0862-3c07-4227-ab0f-511a267cb7ff', booking_id='b2d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Bola', 'Chuteira'] ), @@ -35,7 +35,7 @@ def __init__(self): end_date=1634571000000, court_number=3, sport=SPORT.BASKETBALL, - user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', + user_id='d351a9b1-937f-423c-a9d1-9929b5795be1', booking_id='b3d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Bola'] ), @@ -122,41 +122,7 @@ def update_booking(self, return booking - def get_bookings(self, - booking_id: Optional[str] = None, - user_id: Optional[str] = None, - sport: Optional[str] = None, - court_number: Optional[int] = None, - end_date: Optional[int] = None, - start_date: Optional[int] = None) -> List[Optional[Booking]]: - - filters = locals().copy() - filters.pop('self') - filters.pop('end_date') - filters.pop('start_date') - - filters = {k: v for k, v in filters.items() if v is not None} - - bookings = [] - - for booking in self.bookings: - booking_dict = booking.__dict__ - if start_date and end_date: - if all( - booking_dict.get(key) == value for key, value in filters.items() - ) and booking.start_date >= start_date and booking.end_date <= end_date: - bookings.append(booking) - else: - if all( - booking_dict.get(key) == value for key, value in filters.items() - ): - bookings.append(booking) - - return bookings - - def get_booking(self, - booking_id: str) -> Optional[Booking]: - + def get_booking(self, booking_id: str): for booking in self.bookings: if booking.booking_id == booking_id: return booking diff --git a/src/shared/infra/repositories/reservation_repository_dynamo.py b/src/shared/infra/repositories/reservation_repository_dynamo.py index 5a65f38..6f2422f 100644 --- a/src/shared/infra/repositories/reservation_repository_dynamo.py +++ b/src/shared/infra/repositories/reservation_repository_dynamo.py @@ -5,7 +5,6 @@ from typing import List, Optional from src.shared.infra.external.dynamo.datasources.dynamo_datasource import DynamoDatasource from src.shared.domain.enums.status_enum import STATUS -from boto3.dynamodb.conditions import Key class ReservationRepositoryDynamo(IReservationRepository): diff --git a/src/shared/infra/repositories/util/S3Manager.py b/src/shared/infra/repositories/util/S3Manager.py new file mode 100644 index 0000000..318e02e --- /dev/null +++ b/src/shared/infra/repositories/util/S3Manager.py @@ -0,0 +1,46 @@ +import boto3 + +from src.shared.environments import Environments + + +class S3Manager: + + def __init__(self): + self.__envs = Environments.get_envs() + stage = self.__envs.stage.value + if stage == "TEST": + self.s3 = boto3.client( + "s3", + aws_access_key_id=self.__envs.client_id, + aws_secret_access_key=self.__envs.client_secret, + endpoint_url=self.__envs.bucket_endpoint_url, + region_name=self.__envs.region, + config=boto3.session.Config(signature_version="s3v4"), + ) + else: + self.s3 = boto3.client("s3") + + def upload_file(self, key, file_type, decode_string): + + response = self.s3.put_object( + Bucket=self.__envs.s3_bucket_name, + Key=key, + Body=decode_string, + ContentType=file_type.replace(".", ""), + ) + + return { + 's3_response': response, + 'key': key + } + + def delete_file(self): + pass + def get_all_files(self): + pass + def get_file(self): + pass + def generate_presigned_url(self, expiration_time: int, object_name: str, method: str, content_type: str): + pass + + diff --git a/tests/modules/delete_booking/__init__.py b/tests/modules/delete_bookings/__init__.py similarity index 100% rename from tests/modules/delete_booking/__init__.py rename to tests/modules/delete_bookings/__init__.py diff --git a/tests/modules/delete_booking/app/__init__.py b/tests/modules/delete_bookings/app/__init__.py similarity index 100% rename from tests/modules/delete_booking/app/__init__.py rename to tests/modules/delete_bookings/app/__init__.py diff --git a/tests/modules/delete_booking/app/test_delete_booking_controller.py b/tests/modules/delete_bookings/app/test_delete_booking_controller.py similarity index 97% rename from tests/modules/delete_booking/app/test_delete_booking_controller.py rename to tests/modules/delete_bookings/app/test_delete_booking_controller.py index 69e384b..f4685bb 100644 --- a/tests/modules/delete_booking/app/test_delete_booking_controller.py +++ b/tests/modules/delete_bookings/app/test_delete_booking_controller.py @@ -3,7 +3,6 @@ from src.shared.helpers.external_interfaces.http_models import HttpRequest from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock - class TestDeleteBookingController: def test_delete_booking_controller(self): repo = BookingRepositoryMock() @@ -25,7 +24,7 @@ def test_delete_booking_controller(self): def test_delete_booking_controller_missing_booking_id(self): repo = BookingRepositoryMock() - usecase = DeleteBookingUsecase(repo=repo) + usecase = DeleteBookingUsecase(repo= repo) controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body={ "booking_id": None @@ -43,7 +42,7 @@ def test_delete_booking_controller_missing_booking_id(self): def test_delete_booking_controller_booking_id_entity_error(self): repo = BookingRepositoryMock() - usecase = DeleteBookingUsecase(repo=repo) + usecase = DeleteBookingUsecase(repo= repo) controller = DeleteBookingController(usecase=usecase) request = HttpRequest(body={ "booking_id": 0 @@ -55,7 +54,7 @@ def test_delete_booking_controller_booking_id_entity_error(self): 'role': 'STUDENT' } }) - + reponse = controller(request) assert reponse.status_code == 400 assert reponse.body == "Field booking_id is not valid" diff --git a/tests/modules/delete_booking/app/test_delete_booking_presenter.py b/tests/modules/delete_bookings/app/test_delete_booking_presenter.py similarity index 82% rename from tests/modules/delete_booking/app/test_delete_booking_presenter.py rename to tests/modules/delete_bookings/app/test_delete_booking_presenter.py index 6a9b438..a7d296a 100644 --- a/tests/modules/delete_booking/app/test_delete_booking_presenter.py +++ b/tests/modules/delete_bookings/app/test_delete_booking_presenter.py @@ -25,7 +25,6 @@ def test_delete_booking_presenter(self): "apiId": "", "authentication": None, "authorizer": { -<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_presenter.py "user": json.dumps({ "user": { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', @@ -35,13 +34,6 @@ def test_delete_booking_presenter(self): }, "message": "the user was retrieved" }) -======= - 'user': { - 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'displayName': 'John Doe', - 'mail': 'JD@maua.br' - } ->>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_presenter.py }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -94,7 +86,6 @@ def test_delete_booking_presenter_missing_booking_id(self): "apiId": "", "authentication": None, "authorizer": { -<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_presenter.py "user": json.dumps({ "user": { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', @@ -104,13 +95,6 @@ def test_delete_booking_presenter_missing_booking_id(self): }, "message": "the user was retrieved" }) -======= - 'user': { - 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'displayName': 'John Doe', - 'mail': 'JD@maua.br' - } ->>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_presenter.py }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -160,7 +144,6 @@ def test_delete_booking_not_found(self): "apiId": "", "authentication": None, "authorizer": { -<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_presenter.py "user": json.dumps({ "user": { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', @@ -170,13 +153,6 @@ def test_delete_booking_not_found(self): }, "message": "the user was retrieved" }) -======= - 'user': { - 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'displayName': 'John Doe', - 'mail': 'JD@maua.br' - } ->>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_presenter.py }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", @@ -226,7 +202,6 @@ def test_delete_booking_wrong_type(self): "apiId": "", "authentication": None, "authorizer": { -<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_presenter.py "user": json.dumps({ "user": { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', @@ -236,13 +211,6 @@ def test_delete_booking_wrong_type(self): }, "message": "the user was retrieved" }) -======= - 'user': { - 'id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'displayName': 'John Doe', - 'mail': 'JD@maua.br' - } ->>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_presenter.py }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", diff --git a/tests/modules/delete_booking/app/test_delete_booking_usecase.py b/tests/modules/delete_bookings/app/test_delete_booking_usecase.py similarity index 61% rename from tests/modules/delete_booking/app/test_delete_booking_usecase.py rename to tests/modules/delete_bookings/app/test_delete_booking_usecase.py index 02727b5..b750459 100644 --- a/tests/modules/delete_booking/app/test_delete_booking_usecase.py +++ b/tests/modules/delete_bookings/app/test_delete_booking_usecase.py @@ -1,15 +1,9 @@ import pytest -<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_usecase.py -from typing import Any, Optional -from src.shared.domain.entities.booking import Booking -from src.shared.domain.enums.status_enum import STATUS from src.shared.helpers.errors.usecase_errors import DuplicatedItem, ForbiddenAction -======= ->>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_usecase.py -from src.shared.helpers.errors.domain_errors import EntityError from src.modules.delete_booking.app.delete_booking_usecase import DeleteBookingUsecase from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.errors.domain_errors import EntityError class Test_DeleteBookingUsecase: def test_delete_booking_usecase(self): @@ -22,13 +16,10 @@ def test_delete_booking_usecase(self): 'email': 'user@email.com', 'role': 'STUDENT' } - -<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_usecase.py - booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', user=user) -======= + booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', - user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98') ->>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_usecase.py + user=user) + assert len(repo.bookings) == len_before - 1 def test_delete_booking_usecase_admin(self): @@ -68,13 +59,8 @@ def test_delete_booking_usecase_no_items_found(self): 'role': 'STUDENT' } with pytest.raises(NoItemsFound): -<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_usecase.py booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2926', user = user) -======= - booking = usecase(booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2926', - user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98') ->>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_usecase.py - + def test_delete_booking_usecase_invalid_booking_id(self): repo = BookingRepositoryMock() usecase = DeleteBookingUsecase(repo=repo) @@ -86,16 +72,5 @@ def test_delete_booking_usecase_invalid_booking_id(self): } with pytest.raises(EntityError): -<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_usecase.py usecase(booking_id=-1, user=user) - - with pytest.raises(EntityError): - usecase(booking_id=None,user=user) -======= - usecase(booking_id=-1, - user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98') - - with pytest.raises(EntityError): - usecase(booking_id=None, - user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98') ->>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_usecase.py + \ No newline at end of file diff --git a/tests/modules/delete_booking/app/test_delete_booking_viewmodel.py b/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py similarity index 74% rename from tests/modules/delete_booking/app/test_delete_booking_viewmodel.py rename to tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py index e35d010..339d113 100644 --- a/tests/modules/delete_booking/app/test_delete_booking_viewmodel.py +++ b/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py @@ -8,7 +8,6 @@ class Test_DeleteBookingViewModel: def test_delete_booking_viewmodel(self): repo = BookingRepositoryMock() usecase = DeleteBookingUsecase(repo=repo) -<<<<<<< HEAD:tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py user = { 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', 'name': 'Nome', @@ -16,10 +15,6 @@ def test_delete_booking_viewmodel(self): 'role': 'STUDENT' } booking = usecase(booking_id=repo.bookings[0].booking_id, user=user) -======= - booking = usecase(booking_id=repo.bookings[0].booking_id, - user_id=repo.bookings[0].user_id) ->>>>>>> parent of 86c13e0 (Merge pull request #20 from Maua-Dev/user-on-generate-report):tests/modules/delete_booking/app/test_delete_booking_viewmodel.py viewmodel = DeleteBookingViewModel(booking=booking).to_dict() expected = { @@ -28,7 +23,7 @@ def test_delete_booking_viewmodel(self): 'end_date': 1634583365000, 'court_number': 1, 'sport': 'Tennis', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] }, diff --git a/tests/modules/generate_report/__init__.py b/tests/modules/generate_report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/modules/generate_report/app/__init__.py b/tests/modules/generate_report/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/modules/generate_report/app/test_generate_report_aggregator.py b/tests/modules/generate_report/app/test_generate_report_aggregator.py new file mode 100644 index 0000000..6b2fcd3 --- /dev/null +++ b/tests/modules/generate_report/app/test_generate_report_aggregator.py @@ -0,0 +1,22 @@ +import pytest + +from src.modules.generate_report.app.generate_report_aggregator import GenerateReportAggregator +from src.modules.generate_report.app.generate_report_extractor import GenerateReportExtractor +from src.shared.infra.repositories.booking_repository_dynamo import BookingRepositoryDynamo + + +class TestGenerateReportAggregator: + + @pytest.mark.skip("Can't run test in gh actions") + def test_generate_report_aggregator(self): + + repo = BookingRepositoryDynamo() + + # Arrange + extractor = GenerateReportExtractor(booking_repository=repo) + aggregator = GenerateReportAggregator(extractor) + + # Act + result = aggregator(1577836800, 1767225600) + + print(result) \ No newline at end of file diff --git a/tests/modules/generate_report/app/test_generate_report_sender.py b/tests/modules/generate_report/app/test_generate_report_sender.py new file mode 100644 index 0000000..6c0d8ad --- /dev/null +++ b/tests/modules/generate_report/app/test_generate_report_sender.py @@ -0,0 +1,38 @@ +import pytest + +from src.modules.generate_report.app.generate_report_aggregator import GenerateReportAggregator +from src.modules.generate_report.app.generate_report_extractor import GenerateReportExtractor +from src.modules.generate_report.app.generate_report_presenter import lambda_handler +from src.modules.generate_report.app.generate_report_transformer import GenerateReportTransformer +from src.shared.infra.repositories.booking_repository_dynamo import BookingRepositoryDynamo + + +class TestGenerateReportPresenter: + + @pytest.mark.skip("Can't run test in gh actions") + + #WONT WORK WITH CURRENT MOCK, ALL DATES ARE OUTDATED AND DO NOT MATCH WITH CURRENT YEAR + + def test_generate_report_presenter(self): + + event_from_event_bridge = { + "version": "0", + "id": "12345678-1234-1234-1234-123456789012", + "detail-type": "EC2 Instance State-change Notification", + "source": "aws.ec2", + "account": "123456789012", + "time": "2023-11-11T12:00:00Z", + "region": "us-east-1", + "resources": [ + "arn:aws:ec2:us-east-1:123456789012:instance/i-1234567890abcdef0" + ], + "detail": { + "instance-id": "i-1234567890abcdef0", + "state": "running" + } + } + + sender = lambda_handler(event_from_event_bridge, None) + + #WONT WORK WITH CURRENT MOCK, ALL DATES ARE OUTDATED AND DO NOT MATCH WITH CURRENT YEAR + diff --git a/tests/modules/generate_report/app/test_generate_report_transformer.py b/tests/modules/generate_report/app/test_generate_report_transformer.py new file mode 100644 index 0000000..9a9e831 --- /dev/null +++ b/tests/modules/generate_report/app/test_generate_report_transformer.py @@ -0,0 +1,37 @@ +import platform +import subprocess +import pytest + +from src.modules.generate_report.app.generate_report_aggregator import GenerateReportAggregator +from src.modules.generate_report.app.generate_report_extractor import GenerateReportExtractor +from src.modules.generate_report.app.generate_report_transformer import GenerateReportTransformer +from src.shared.infra.repositories.booking_repository_dynamo import BookingRepositoryDynamo +import tempfile +import os + +class TestGenerateReportTransformer: + + @pytest.mark.skip("Can't run test in gh actions") + def test_generate_report_transformer(self): + + repo = BookingRepositoryDynamo() + extractor = GenerateReportExtractor(booking_repository=repo) + aggregator = GenerateReportAggregator(extractor=extractor) + + transformer = GenerateReportTransformer(aggregator=aggregator) + + output = transformer(1577836800, 1767225600) + + with tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") as tmp_file: + tmp_file.write(output.read()) + tmp_file_path = tmp_file.name + + # os.startfile(tmp_file_path) + + system = platform.system() + if system == 'Windows': + os.startfile(tmp_file_path) + elif system == 'Darwin': + subprocess.call(['open', tmp_file_path]) + else: + subprocess.call(['xdg-open', tmp_file_path]) \ No newline at end of file diff --git a/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py b/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py index 236704e..e9a8013 100644 --- a/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py +++ b/tests/modules/get_all_bookings/app/test_get_all_bookings_usecase.py @@ -4,7 +4,7 @@ from src.shared.domain.entities.booking import Booking import pytest -class Test_GetAllBookingsUsecase: +class TestGetAllBookingsUsecase: def test_get_all_bookings_usecase(self): repo = BookingRepositoryMock() usecase = GetAllBookingsUsecase(repo = repo) @@ -15,6 +15,6 @@ def test_get_all_bookings_usecase(self): assert bookings[0].start_date == 1634576165000 assert bookings[0].end_date == 1634583365000 assert bookings[0].sport == SPORT.TENNIS - assert bookings[0].user_id == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + assert bookings[0].user_id == '1f25448b-3429-4c19-8287-d9e64f17bc3a' assert bookings[0].booking_id == 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' assert bookings[0].materials == ['Raquete', 'Bola', 'Rede', 'Tenis'] \ No newline at end of file diff --git a/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py b/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py index a4ca114..ed9fc66 100644 --- a/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py +++ b/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py @@ -1,5 +1,5 @@ from src.modules.get_all_bookings.app.get_all_bookings_usecase import GetAllBookingsUsecase -from src.modules.get_all_bookings.app.get_all_bookings_viewmodel import GetAllBookingViewModel +from src.modules.get_all_bookings.app.get_all_bookings_viewmodel import GetAllBookingsViewModel from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock from src.shared.domain.entities.booking import Booking @@ -8,7 +8,7 @@ def test_get_all_bookings_viewmodel(self): repo = BookingRepositoryMock() usecase = GetAllBookingsUsecase(repo = repo) courts = usecase() - viewmodel = GetAllBookingViewModel(courts).to_dict() + viewmodel = GetAllBookingsViewModel(courts).to_dict() excepted = { 'courts': [ diff --git a/tests/modules/get_all_courts/app/test_get_all_courts_presenter.py b/tests/modules/get_all_courts/app/test_get_all_courts_presenter.py index 2f214f4..61198b0 100644 --- a/tests/modules/get_all_courts/app/test_get_all_courts_presenter.py +++ b/tests/modules/get_all_courts/app/test_get_all_courts_presenter.py @@ -40,7 +40,7 @@ def test_lambda_handler(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": None, + "body": '{"number": 7, "status": "AVAILABLE", "is_field": false, "photo": "photo"}', "pathParameters": None, "isBase64Encoded": None, "stageVariables": None diff --git a/tests/modules/get_booking/app/test_get_booking_controller.py b/tests/modules/get_booking/app/test_get_booking_controller.py index bc5fdc5..4e14d57 100644 --- a/tests/modules/get_booking/app/test_get_booking_controller.py +++ b/tests/modules/get_booking/app/test_get_booking_controller.py @@ -19,7 +19,7 @@ def test_get_booking_controller(self): assert response.body['booking']['end_date'] == 1634567400000 assert response.body['booking']['court_number'] == 2 assert response.body['booking']['sport'] == 'Football' - assert response.body['booking']['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + assert response.body['booking']['user_id'] == 'c07e0862-3c07-4227-ab0f-511a267cb7ff' assert response.body['booking']['materials'] == ['Bola', 'Chuteira'] def test_get_booking_controller_missing_booking_id(self): @@ -32,6 +32,7 @@ def test_get_booking_controller_missing_booking_id(self): assert response.status_code == 400 assert response.body == 'Field booking_id is missing' + def test_get_booking_controller_wrong_type_booking_id(self): repo = BookingRepositoryMock() @@ -59,3 +60,4 @@ def test_get_booking_controller_booking_not_found(self): response = controller(request) assert response.status_code == 404 assert response.body == 'No items found for booking_id' + \ No newline at end of file diff --git a/tests/modules/get_booking/app/test_get_booking_presenter.py b/tests/modules/get_booking/app/test_get_booking_presenter.py index d54a475..0c4b928 100644 --- a/tests/modules/get_booking/app/test_get_booking_presenter.py +++ b/tests/modules/get_booking/app/test_get_booking_presenter.py @@ -57,7 +57,7 @@ def test_get_booking_presenter(self): assert json.loads(response['body'])['booking']['end_date'] == 1634583365000 assert json.loads(response['body'])['booking']['court_number'] == 1 assert json.loads(response['body'])['booking']['sport'] == 'Tennis' - assert json.loads(response['body'])['booking']['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + assert json.loads(response['body'])['booking']['user_id'] == '1f25448b-3429-4c19-8287-d9e64f17bc3a' assert json.loads(response['body'])['booking']['materials'] == ['Raquete', 'Bola', 'Rede', 'Tenis'] @@ -76,7 +76,7 @@ def test_get_booking_presenter_missing_parameters(self): "header2": "value1,value2" }, "queryStringParameters": { - "parameter1": "1" + }, "requestContext": { "accountId": "123456789012", @@ -107,7 +107,7 @@ def test_get_booking_presenter_missing_parameters(self): response = lambda_handler(event, None) assert response['statusCode'] == 400 - assert json.loads(response['body']) == "Field booking_id is missing" + assert json.loads(response['body']) == 'Field booking_id is missing' def test_get_booking_presenter_entity_error(self): event = { @@ -257,11 +257,4 @@ def test_get_booking_presenter_entity_not_found(self): assert response['statusCode'] == 404 assert json.loads(response['body']) == 'No items found for booking_id' - - - - - - - - + \ No newline at end of file diff --git a/tests/modules/get_booking/app/test_get_booking_viewmodel.py b/tests/modules/get_booking/app/test_get_booking_viewmodel.py index a3b80a6..6cec5ef 100644 --- a/tests/modules/get_booking/app/test_get_booking_viewmodel.py +++ b/tests/modules/get_booking/app/test_get_booking_viewmodel.py @@ -16,7 +16,7 @@ def test_get_booking_viewmodel(self): 'end_date': 1634583365000, 'court_number': 1, 'sport': 'Tennis', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] }, diff --git a/tests/modules/get_bookings/app/test_get_bookings_presenter.py b/tests/modules/get_bookings/app/test_get_bookings_presenter.py index c8307ed..3ba24be 100644 --- a/tests/modules/get_bookings/app/test_get_bookings_presenter.py +++ b/tests/modules/get_bookings/app/test_get_bookings_presenter.py @@ -67,7 +67,7 @@ def test_get_bookings_presenter(self): assert json.loads(response['body'])['bookings'][0]['end_date'] == 1634583365000 assert json.loads(response['body'])['bookings'][0]['court_number'] == 1 assert json.loads(response['body'])['bookings'][0]['sport'] == 'Tennis' - assert json.loads(response['body'])['bookings'][0]['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + assert json.loads(response['body'])['bookings'][0]['user_id'] == '1f25448b-3429-4c19-8287-d9e64f17bc3a' assert json.loads(response['body'])['bookings'][0]['materials'] == ['Raquete', 'Bola', 'Rede', 'Tenis'] diff --git a/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py b/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py index 27bcd57..c2ac5b5 100644 --- a/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py +++ b/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py @@ -16,7 +16,7 @@ def test_get_bookings_viewmodel(self): 'end_date': 1634583365000, 'court_number': 1, 'sport': 'Tennis', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] }], diff --git a/tests/modules/get_court/app/test_get_court_presenter.py b/tests/modules/get_court/app/test_get_court_presenter.py index 7f93dfb..46ee487 100644 --- a/tests/modules/get_court/app/test_get_court_presenter.py +++ b/tests/modules/get_court/app/test_get_court_presenter.py @@ -19,7 +19,7 @@ def test_get_court_presenter(self): "header2": "value1,value2" }, "queryStringParameters": { - "number": "1" #tem que passar ja que no querry sempre vem como string + "parameter1": "1" }, "requestContext": { "accountId": "123456789012", @@ -42,7 +42,7 @@ def test_get_court_presenter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {}, + "body": {"number":1}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -117,7 +117,7 @@ def test_get_court_presenter_entity_error(self): "header2": "value1,value2" }, "queryStringParameters": { - "number": 15 + "parameter1": "1" }, "requestContext": { "accountId": "123456789012", @@ -140,7 +140,7 @@ def test_get_court_presenter_entity_error(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {}, + "body": {"number": 15}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -166,7 +166,7 @@ def test_get_court_presenter_wrong_type_parameter(self): "header2": "value1,value2" }, "queryStringParameters": { - "code": "1" + "parameter1": "1" }, "requestContext": { "accountId": "123456789012", @@ -189,7 +189,7 @@ def test_get_court_presenter_wrong_type_parameter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {}, + "body": {"code": "1"}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -216,7 +216,7 @@ def test_get_court_presenter_not_found(self): "header2": "value1,value2" }, "queryStringParameters": { - "number": 8 + "parameter1": "1" }, "requestContext": { "accountId": "123456789012", @@ -239,7 +239,7 @@ def test_get_court_presenter_not_found(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {}, + "body": {"number": 8}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None diff --git a/tests/shared/infra/repositories/test_booking_repository_dynamo.py b/tests/shared/infra/repositories/test_booking_repository_dynamo.py index c53f308..1a2a31d 100644 --- a/tests/shared/infra/repositories/test_booking_repository_dynamo.py +++ b/tests/shared/infra/repositories/test_booking_repository_dynamo.py @@ -5,7 +5,7 @@ from src.shared.domain.entities.booking import Booking class TestBookingRepositoryDynamo: - + @pytest.mark.skip("Can't run test in github actions") def test_dynamo_get_all_bookings(self): dynamo_repo = BookingRepositoryDynamo() diff --git a/tests/shared/infra/repositories/test_booking_repository_mock.py b/tests/shared/infra/repositories/test_booking_repository_mock.py index 6ba96ff..2cb4128 100644 --- a/tests/shared/infra/repositories/test_booking_repository_mock.py +++ b/tests/shared/infra/repositories/test_booking_repository_mock.py @@ -40,7 +40,7 @@ def test_get_booking(self): assert booking is not None assert booking.booking_id == booking_id - assert booking.user_id == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + assert booking.user_id == '1f25448b-3429-4c19-8287-d9e64f17bc3a' assert booking.sport == SPORT.TENNIS assert booking.court_number == 1 assert booking.start_date == 1634576165000 diff --git a/tests/shared/infra/repositories/test_reservation_repository_dynamo.py b/tests/shared/infra/repositories/test_reservation_repository_dynamo.py index b486e55..e465106 100644 --- a/tests/shared/infra/repositories/test_reservation_repository_dynamo.py +++ b/tests/shared/infra/repositories/test_reservation_repository_dynamo.py @@ -10,7 +10,7 @@ class TestReservationRepositoryDynamo: - + @pytest.mark.skip("Can't run test in github actions") def test_dynamo_delete_court(self): dynamo_repo = ReservationRepositoryDynamo() @@ -30,7 +30,7 @@ def test_dynamo_delete_court_not_found(self): @pytest.mark.skip("Can't run test in github actions") def test_update_court(self): repo = ReservationRepositoryDynamo() - resp = repo.update_court(number=3, photo="https://www.linkedin.com/in/giovanna-albuquerque-16917a245/") + resp = repo.update_court(number=3, new_photo="https://www.linkedin.com/in/giovanna-albuquerque-16917a245/") assert resp.number == 3 assert resp.photo == "https://www.linkedin.com/in/giovanna-albuquerque-16917a245/" @@ -62,6 +62,6 @@ def test_dynamo_create_court(self): new_court = Court(number=6, status=STATUS.MAINTENANCE, is_field=False, photo=None) size = len(dynamo_repo.get_all_courts()) - assert new_court.__dict__ == dynamo_repo.create_court(new_court).__dict__ - assert dynamo_repo.get_court(6).__dict__ == new_court.__dict__ + assert new_court == dynamo_repo.create_court(new_court) + assert dynamo_repo.get_court(6) == new_court From 7e465899cece15e2e44403e722367df8e021b467 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Tue, 5 Aug 2025 11:43:49 -0300 Subject: [PATCH 080/167] fixing tests --- .../delete_booking/app/delete_booking_controller.py | 7 +++++-- src/modules/get_court/app/get_court_controller.py | 7 ++++--- .../{delete_bookings => delete_booking}/__init__.py | 0 .../{delete_bookings => delete_booking}/app/__init__.py | 0 .../app/test_delete_booking_controller.py | 2 +- .../app/test_delete_booking_presenter.py | 0 .../app/test_delete_booking_usecase.py | 0 .../app/test_delete_booking_viewmodel.py | 0 8 files changed, 10 insertions(+), 6 deletions(-) rename tests/modules/{delete_bookings => delete_booking}/__init__.py (100%) rename tests/modules/{delete_bookings => delete_booking}/app/__init__.py (100%) rename tests/modules/{delete_bookings => delete_booking}/app/test_delete_booking_controller.py (98%) rename tests/modules/{delete_bookings => delete_booking}/app/test_delete_booking_presenter.py (100%) rename tests/modules/{delete_bookings => delete_booking}/app/test_delete_booking_usecase.py (100%) rename tests/modules/{delete_bookings => delete_booking}/app/test_delete_booking_viewmodel.py (100%) diff --git a/src/modules/delete_booking/app/delete_booking_controller.py b/src/modules/delete_booking/app/delete_booking_controller.py index eb0d69b..7315569 100644 --- a/src/modules/delete_booking/app/delete_booking_controller.py +++ b/src/modules/delete_booking/app/delete_booking_controller.py @@ -4,9 +4,9 @@ from .delete_booking_viewmodel import DeleteBookingViewModel from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.errors.usecase_errors import NoItemsFound, ForbiddenAction from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse -from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, Created, InternalServerError, NotFound +from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, Created, InternalServerError, NotFound, Forbidden from src.shared.domain.enums.sport import SPORT class DeleteBookingController: @@ -42,5 +42,8 @@ def __call__(self, request: IRequest) -> IResponse: except EntityError as err: return BadRequest(body=err.message) + except ForbiddenAction as err: + return Forbidden(body=err.message) + except Exception as err: return InternalServerError(body=err.args[0]) \ No newline at end of file diff --git a/src/modules/get_court/app/get_court_controller.py b/src/modules/get_court/app/get_court_controller.py index 1dff4e4..ec8d652 100644 --- a/src/modules/get_court/app/get_court_controller.py +++ b/src/modules/get_court/app/get_court_controller.py @@ -18,14 +18,15 @@ def __call__(self, request: IRequest): number = request.data.get('number') - #TODO ajustar para vir do query parameters if number is not None: - if type(number) is not int: + try: + number = int(number) + except ValueError: raise WrongTypeParameter('number', 'int', type(number).__name__) court = self.usecase( - number= request.data.get('number') + number=number ) court_viewmodel = GetCourtViewmodel(court= court) diff --git a/tests/modules/delete_bookings/__init__.py b/tests/modules/delete_booking/__init__.py similarity index 100% rename from tests/modules/delete_bookings/__init__.py rename to tests/modules/delete_booking/__init__.py diff --git a/tests/modules/delete_bookings/app/__init__.py b/tests/modules/delete_booking/app/__init__.py similarity index 100% rename from tests/modules/delete_bookings/app/__init__.py rename to tests/modules/delete_booking/app/__init__.py diff --git a/tests/modules/delete_bookings/app/test_delete_booking_controller.py b/tests/modules/delete_booking/app/test_delete_booking_controller.py similarity index 98% rename from tests/modules/delete_bookings/app/test_delete_booking_controller.py rename to tests/modules/delete_booking/app/test_delete_booking_controller.py index f4685bb..e25446c 100644 --- a/tests/modules/delete_bookings/app/test_delete_booking_controller.py +++ b/tests/modules/delete_booking/app/test_delete_booking_controller.py @@ -105,7 +105,7 @@ def test_delete_bookings_controller_forbidden(self): "booking_id": 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925' }, headers={ 'user_from_authorizer': { - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'user_id': '2f25448b-3429-4c19-8287-d9e64f17bc3a', 'name': 'Nome', 'email': 'user@email.com', 'role': 'STUDENT' diff --git a/tests/modules/delete_bookings/app/test_delete_booking_presenter.py b/tests/modules/delete_booking/app/test_delete_booking_presenter.py similarity index 100% rename from tests/modules/delete_bookings/app/test_delete_booking_presenter.py rename to tests/modules/delete_booking/app/test_delete_booking_presenter.py diff --git a/tests/modules/delete_bookings/app/test_delete_booking_usecase.py b/tests/modules/delete_booking/app/test_delete_booking_usecase.py similarity index 100% rename from tests/modules/delete_bookings/app/test_delete_booking_usecase.py rename to tests/modules/delete_booking/app/test_delete_booking_usecase.py diff --git a/tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py b/tests/modules/delete_booking/app/test_delete_booking_viewmodel.py similarity index 100% rename from tests/modules/delete_bookings/app/test_delete_booking_viewmodel.py rename to tests/modules/delete_booking/app/test_delete_booking_viewmodel.py From e99a1f5b57784c46466c0264cbab26969b167fc3 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Thu, 7 Aug 2025 12:13:33 -0300 Subject: [PATCH 081/167] removing unused imports --- src/modules/delete_court/app/delete_court_controller.py | 6 +----- src/modules/delete_court/app/delete_court_usecase.py | 2 -- src/shared/authorizer/user_mss_authorizer.py | 1 - 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/modules/delete_court/app/delete_court_controller.py b/src/modules/delete_court/app/delete_court_controller.py index f1573bd..591959f 100644 --- a/src/modules/delete_court/app/delete_court_controller.py +++ b/src/modules/delete_court/app/delete_court_controller.py @@ -1,14 +1,10 @@ -from typing import Any -from src.shared.domain.entities.court import Court from .delete_court_usecase import DeleteCourtUsecase from .delete_court_viewmodel import DeleteCourtViewModel from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.errors.usecase_errors import NoItemsFound, ForbiddenAction from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse -from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, Created, InternalServerError, NotFound -from src.shared.domain.enums.status_enum import STATUS -from src.shared.clients.user_api_client import UserAPIClient +from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, InternalServerError, NotFound class DeleteCourtController: diff --git a/src/modules/delete_court/app/delete_court_usecase.py b/src/modules/delete_court/app/delete_court_usecase.py index 8904cc1..2bb34e8 100644 --- a/src/modules/delete_court/app/delete_court_usecase.py +++ b/src/modules/delete_court/app/delete_court_usecase.py @@ -1,6 +1,4 @@ from src.shared.domain.entities.court import Court -from src.shared.domain.enums.status_enum import STATUS -from src.shared.helpers.errors.usecase_errors import DuplicatedItem from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.errors.usecase_errors import NoItemsFound, ForbiddenAction from src.shared.domain.repositories.reservation_repository_interface import IReservationRepository diff --git a/src/shared/authorizer/user_mss_authorizer.py b/src/shared/authorizer/user_mss_authorizer.py index f42a434..cb376ce 100644 --- a/src/shared/authorizer/user_mss_authorizer.py +++ b/src/shared/authorizer/user_mss_authorizer.py @@ -1,5 +1,4 @@ import os -import re import json import urllib3 From a7e8b21c1eddb7e6b537da93c07f6820067681d5 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Thu, 7 Aug 2025 12:14:05 -0300 Subject: [PATCH 082/167] refactoring adjust layer script to fetch new lambda dependencies --- iac/adjust_layer_directory.py | 76 ++++++++++++++++++++--------------- iac/app.py | 2 +- iac/requirements-layer.txt | 3 ++ iac/stacks/lambda_stack.py | 2 +- requirements-dev.txt | 1 + 5 files changed, 49 insertions(+), 35 deletions(-) create mode 100644 iac/requirements-layer.txt diff --git a/iac/adjust_layer_directory.py b/iac/adjust_layer_directory.py index 5232368..0f8ee52 100644 --- a/iac/adjust_layer_directory.py +++ b/iac/adjust_layer_directory.py @@ -1,37 +1,47 @@ import os import shutil -from pathlib import Path -import sys - -IAC_DIRECTORY_NAME = "iac" -SOURCE_DIRECTORY_NAME = "src" -LAMBDA_LAYER_PREFIX = os.path.join("python", "src") - - -def adjust_layer_directory(shared_dir_name: str, destination: str): - # Get the root directory of the source directory - root_directory = Path(__file__).parent.parent - iac_directory = os.path.join(root_directory, IAC_DIRECTORY_NAME) - - print(f"Root directory: {root_directory}") - print(f"Root direcotry files: {os.listdir(root_directory)}") - print(f"IaC directory: {iac_directory}") - print(f"IaC directory files: {os.listdir(iac_directory)}") - - - # Get the destination and source directory - destination_directory = os.path.join(root_directory, IAC_DIRECTORY_NAME, destination) - source_directory = os.path.join(root_directory, SOURCE_DIRECTORY_NAME, shared_dir_name) - - # Delete the destination directory if it exists - if os.path.exists(destination_directory): - shutil.rmtree(destination_directory) - - # Copy the source directory to the destination directory - shutil.copytree(source_directory, os.path.join(destination_directory, LAMBDA_LAYER_PREFIX, shared_dir_name)) - print( - f"Copying files from {source_directory} to {os.path.join(destination_directory, LAMBDA_LAYER_PREFIX, shared_dir_name)}") - +import subprocess + +# --- Configurações --- +# Define os nomes e caminhos principais que o script vai usar. +# Isso facilita a manutenção se um dia os nomes das pastas mudarem. +BUILD_DIRECTORY = "build" +PYTHON_TOP_LEVEL_DIR = os.path.join(BUILD_DIRECTORY, "python") +SHARED_CODE_SOURCE = "src/shared" +REQUIREMENTS_FILE = "requirements-layer.txt" + +def adjust_layer_directory(): + """ + Prepara um diretório 'build' para uma Lambda Layer do AWS CDK. + + A função junta o código local compartilhado e as dependências externas (pip) + na estrutura de pastas que a Lambda espera (/python). + """ + + # Garante que o build seja sempre limpo, removendo qualquer artefato antigo. + if os.path.exists(BUILD_DIRECTORY): + shutil.rmtree(BUILD_DIRECTORY) + + # Cria a estrutura de pastas 'build/python/src/'. + # Isso é necessário para que os imports 'from src.shared...' funcionem na Lambda. + shared_code_intermediate_dir = os.path.join(PYTHON_TOP_LEVEL_DIR, "src") + os.makedirs(shared_code_intermediate_dir) + + # Copia o código compartilhado (de 'src/shared') para dentro da estrutura da Layer. + # O resultado final será 'build/python/src/shared'. + shared_code_dest = os.path.join(shared_code_intermediate_dir, os.path.basename(SHARED_CODE_SOURCE)) + shutil.copytree(SHARED_CODE_SOURCE, shared_code_dest) + + # Se o arquivo de dependências existir, instala todas as bibliotecas. + if os.path.exists(REQUIREMENTS_FILE): + # Instala os pacotes diretamente na pasta 'build/python'. + # Isso permite que a Lambda importe as bibliotecas de forma padrão (ex: import requests). + subprocess.check_call( + ["pip", "install", "-r", REQUIREMENTS_FILE, "-t", PYTHON_TOP_LEVEL_DIR, "--no-cache-dir"] + ) + else: + # Apenas um aviso caso o arquivo não seja encontrado. + print(f"Aviso: Arquivo '{REQUIREMENTS_FILE}' não encontrado. Nenhuma dependência externa será instalada.") if __name__ == '__main__': - adjust_layer_directory(shared_dir_name="shared", destination="copied_shared") \ No newline at end of file + adjust_layer_directory() \ No newline at end of file diff --git a/iac/app.py b/iac/app.py index edebb46..6e19da3 100644 --- a/iac/app.py +++ b/iac/app.py @@ -10,7 +10,7 @@ print("Starting the CDK") print("Adjusting the layer directory") -adjust_layer_directory(shared_dir_name="shared", destination="copied_shared") +adjust_layer_directory() print("Finished adjusting the layer directory") diff --git a/iac/requirements-layer.txt b/iac/requirements-layer.txt new file mode 100644 index 0000000..e32f01f --- /dev/null +++ b/iac/requirements-layer.txt @@ -0,0 +1,3 @@ +pandas==2.2.3 +XlsxWriter==3.2.2 +requests==2.32.3 \ No newline at end of file diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index 51ab6a3..5f4acfb 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -75,7 +75,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment super().__init__(scope, f"{self.stack_name}_LambdaStack_{stage}") self.lambda_layer = lambda_.LayerVersion(self, f"{self.stack_name}_Lambda_Layer_{stage}", - code=lambda_.Code.from_asset("./copied_shared"), + code=lambda_.Code.from_asset("./build"), compatible_runtimes=[lambda_.Runtime.PYTHON_3_9] ) diff --git a/requirements-dev.txt b/requirements-dev.txt index 44455a7..2a9eb03 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,6 +4,7 @@ boto3==1.24.88 python-dotenv==0.21.0 aws-lambda-powertools==2.9.0 aws_xray_sdk==2.11.0 + pandas==2.2.3 XlsxWriter==3.2.2 requests==2.32.3 \ No newline at end of file From 891dda2ae80b0b54d9d6249b9c47f40f0590a7b7 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Thu, 7 Aug 2025 12:18:09 -0300 Subject: [PATCH 083/167] adjusting relative import from new script --- iac/adjust_layer_directory.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/iac/adjust_layer_directory.py b/iac/adjust_layer_directory.py index 0f8ee52..9bd5344 100644 --- a/iac/adjust_layer_directory.py +++ b/iac/adjust_layer_directory.py @@ -1,14 +1,19 @@ import os import shutil import subprocess +from pathlib import Path # Importe a biblioteca pathlib # --- Configurações --- -# Define os nomes e caminhos principais que o script vai usar. -# Isso facilita a manutenção se um dia os nomes das pastas mudarem. BUILD_DIRECTORY = "build" PYTHON_TOP_LEVEL_DIR = os.path.join(BUILD_DIRECTORY, "python") -SHARED_CODE_SOURCE = "src/shared" -REQUIREMENTS_FILE = "requirements-layer.txt" +REQUIREMENTS_FILE = "requirements-layers.txt" + +# --- CONSTRUÇÃO CORRETA DO CAMINHO --- +# Pega o diretório do projeto (a raiz 'reservation_api') subindo um nível a partir do script atual. +PROJECT_ROOT = Path(__file__).parent.parent +# Agora, constrói o caminho para 'src/shared' a partir da raiz do projeto. +SHARED_CODE_SOURCE = os.path.join(PROJECT_ROOT, "src", "shared") + def adjust_layer_directory(): """ @@ -29,19 +34,24 @@ def adjust_layer_directory(): # Copia o código compartilhado (de 'src/shared') para dentro da estrutura da Layer. # O resultado final será 'build/python/src/shared'. + print(f"Copiando código de: {SHARED_CODE_SOURCE}") # Adicionado para debug shared_code_dest = os.path.join(shared_code_intermediate_dir, os.path.basename(SHARED_CODE_SOURCE)) shutil.copytree(SHARED_CODE_SOURCE, shared_code_dest) # Se o arquivo de dependências existir, instala todas as bibliotecas. - if os.path.exists(REQUIREMENTS_FILE): + # O arquivo de requirements também precisa ser lido a partir da raiz. + requirements_path = os.path.join(PROJECT_ROOT, REQUIREMENTS_FILE) + if os.path.exists(requirements_path): # Instala os pacotes diretamente na pasta 'build/python'. # Isso permite que a Lambda importe as bibliotecas de forma padrão (ex: import requests). subprocess.check_call( - ["pip", "install", "-r", REQUIREMENTS_FILE, "-t", PYTHON_TOP_LEVEL_DIR, "--no-cache-dir"] + ["pip", "install", "-r", requirements_path, "-t", PYTHON_TOP_LEVEL_DIR, "--no-cache-dir"] ) else: # Apenas um aviso caso o arquivo não seja encontrado. - print(f"Aviso: Arquivo '{REQUIREMENTS_FILE}' não encontrado. Nenhuma dependência externa será instalada.") + print(f"Aviso: Arquivo '{requirements_path}' não encontrado. Nenhuma dependência externa será instalada.") + +# Ponto de entrada do script. if __name__ == '__main__': adjust_layer_directory() \ No newline at end of file From f5df94aa0a15f12ae55da05d15f90bb368803c40 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Thu, 7 Aug 2025 12:21:40 -0300 Subject: [PATCH 084/167] adjusting requirements name --- iac/adjust_layer_directory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iac/adjust_layer_directory.py b/iac/adjust_layer_directory.py index 9bd5344..61845b2 100644 --- a/iac/adjust_layer_directory.py +++ b/iac/adjust_layer_directory.py @@ -6,7 +6,7 @@ # --- Configurações --- BUILD_DIRECTORY = "build" PYTHON_TOP_LEVEL_DIR = os.path.join(BUILD_DIRECTORY, "python") -REQUIREMENTS_FILE = "requirements-layers.txt" +REQUIREMENTS_FILE = "requirements-layer.txt" # --- CONSTRUÇÃO CORRETA DO CAMINHO --- # Pega o diretório do projeto (a raiz 'reservation_api') subindo um nível a partir do script atual. From 60feb52059cdb04bc3f8fc273a19961746af83af Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Thu, 7 Aug 2025 12:23:27 -0300 Subject: [PATCH 085/167] changing requirements directory --- iac/requirements-layer.txt => requirements-layer.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename iac/requirements-layer.txt => requirements-layer.txt (100%) diff --git a/iac/requirements-layer.txt b/requirements-layer.txt similarity index 100% rename from iac/requirements-layer.txt rename to requirements-layer.txt From 6795bc681a8289eb988561274a0a678b322a4005 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Thu, 7 Aug 2025 12:28:30 -0300 Subject: [PATCH 086/167] fixing urllib3 version as boto3 requires older one --- requirements-layer.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/requirements-layer.txt b/requirements-layer.txt index e32f01f..d6f5bfe 100644 --- a/requirements-layer.txt +++ b/requirements-layer.txt @@ -1,3 +1,7 @@ +#boto3 compatibility +urllib3<1.27 + +#lambda needs pandas==2.2.3 XlsxWriter==3.2.2 requests==2.32.3 \ No newline at end of file From 385684abc8929b2ffcfae51df3bf3e176c7f1c46 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Thu, 7 Aug 2025 12:43:48 -0300 Subject: [PATCH 087/167] fixing delete court --- .../app/delete_court_controller.py | 20 ++++++++++++++----- .../app/test_delete_court_controller.py | 2 +- .../app/test_delete_court_presenter.py | 16 +++++++-------- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/modules/delete_court/app/delete_court_controller.py b/src/modules/delete_court/app/delete_court_controller.py index 591959f..bed8620 100644 --- a/src/modules/delete_court/app/delete_court_controller.py +++ b/src/modules/delete_court/app/delete_court_controller.py @@ -13,14 +13,24 @@ def __init__(self, usecase: DeleteCourtUsecase): def __call__(self, request: IRequest) -> IResponse: try: - if request.data.get('number') is None: - raise MissingParameters('number') - if request.data.get('user_from_authorizer') is None: + user = request.data.get("user_from_authorizer") + number = request.data.get("number") + + if user is None: raise MissingParameters('user') - user = request.data.get("user_from_authorizer") - court = self.usecase(number=request.data.get('number'), role=user.get("role")) + if number is not None: + try: + number = int(number) + except ValueError: + raise WrongTypeParameter(fieldName="number", + fieldTypeExpected="int", + fieldTypeReceived=type(number).__name__) + else: + raise MissingParameters("number") + + court = self.usecase(number=number, role=user.get("role")) viewmodel = DeleteCourtViewModel(court) return OK(viewmodel.to_dict()) diff --git a/tests/modules/delete_court/app/test_delete_court_controller.py b/tests/modules/delete_court/app/test_delete_court_controller.py index fe9f7c7..c59da3b 100644 --- a/tests/modules/delete_court/app/test_delete_court_controller.py +++ b/tests/modules/delete_court/app/test_delete_court_controller.py @@ -83,7 +83,7 @@ def test_delete_court_controller_wrong_type_parameter(self): response = controller(request) assert response.status_code == 400 - assert response.body == "Field number is not valid" + assert "Field number isn't in the right type" in response.body def test_delete_court_controller_not_found(self): repo = ReservationRepositoryMock() diff --git a/tests/modules/delete_court/app/test_delete_court_presenter.py b/tests/modules/delete_court/app/test_delete_court_presenter.py index e5c3111..e9aa872 100644 --- a/tests/modules/delete_court/app/test_delete_court_presenter.py +++ b/tests/modules/delete_court/app/test_delete_court_presenter.py @@ -18,7 +18,7 @@ def test_delete_court_presenter(self): "header2": "value1,value2" }, "queryStringParameters": { - "parameter1": "1" + "number": "1" }, "requestContext": { "accountId": "123456789012", @@ -50,7 +50,7 @@ def test_delete_court_presenter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": '{"number": 1}', + "body": {}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -108,7 +108,7 @@ def test_delete_court_presenter_missing_number(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": '{}', + "body": {}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -134,7 +134,7 @@ def test_delete_court_not_found(self): "header2": "value1,value2" }, "queryStringParameters": { - "parameter1": "1" + "number": "10" }, "requestContext": { "accountId": "123456789012", @@ -166,7 +166,7 @@ def test_delete_court_not_found(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": '{"number": 10}', + "body": {}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -192,7 +192,7 @@ def test_delete_court_wrong_type(self): "header2": "value1,value2" }, "queryStringParameters": { - "parameter1": "1" + "number": "wrong_type" }, "requestContext": { "accountId": "123456789012", @@ -224,7 +224,7 @@ def test_delete_court_wrong_type(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": '{"number": "wrong_type"}', + "body": {}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -233,4 +233,4 @@ def test_delete_court_wrong_type(self): response = lambda_handler(event, None) assert response['statusCode'] == 400 - assert json.loads(response['body']) == 'Field number is not valid' \ No newline at end of file + assert "Field number isn't in the right type" in json.loads(response['body']) \ No newline at end of file From f0f1a130dbdad33002e853f67e5eb8b07be1d924 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Thu, 7 Aug 2025 12:57:15 -0300 Subject: [PATCH 088/167] attempting to fix none value somewhere in the dto --- src/shared/infra/dto/booking_dynamo_dto.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/infra/dto/booking_dynamo_dto.py b/src/shared/infra/dto/booking_dynamo_dto.py index b8a0bd0..6f59019 100644 --- a/src/shared/infra/dto/booking_dynamo_dto.py +++ b/src/shared/infra/dto/booking_dynamo_dto.py @@ -49,7 +49,7 @@ def to_dynamo(self) -> dict: "sport": self.sport.value, "user_id": self.user_id, "booking_id": self.booking_id, - "materials": self.materials + "materials": self.materials or [] } booking_without_none_values = {k: v for k, v in data.items() if v is not None} @@ -68,7 +68,7 @@ def from_dynamo(booking_data: dict) -> "BookingDynamoDTO": sport = SPORT(booking_data["sport"]), user_id = booking_data["user_id"], booking_id = booking_data["booking_id"], - materials = booking_data["materials"] + materials = booking_data.get("materials") or [] ) def to_entity(self) -> Booking: From 3b5095ff6710d2d54d269c700fdc8e70b28b184b Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Thu, 7 Aug 2025 13:01:07 -0300 Subject: [PATCH 089/167] adding redundance to get all dynamo methods --- src/shared/infra/repositories/booking_repository_dynamo.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index 6c7e857..8c75783 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -153,16 +153,18 @@ def delete_booking(self, booking_id: str, user) -> Optional[Booking]: def get_all_bookings(self) -> Optional[List[Booking]]: all_bookings = [] - all_items = self.dynamo.get_all_items().get('Items') + all_items = self.dynamo.get_all_items().get('Items') or [] for item in all_items: if item.get('entity') == 'booking': all_bookings.append(BookingDynamoDTO.from_dynamo(item).to_entity()) + + return all_bookings def get_all_bookings_by_date_range(self, initial_date: int, final_date: int) -> Optional[List[Booking]]: all_bookings = [] - all_items = self.dynamo.get_all_items().get('Items') + all_items = self.dynamo.get_all_items().get('Items') or [] for item in all_items: if item.get('entity') == 'booking': From e1a6623f8f5534d8ae943d6e2b13f954ee9d97a7 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Thu, 7 Aug 2025 17:27:09 -0300 Subject: [PATCH 090/167] added token authorizer to delete booking --- iac/stacks/lambda_stack.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index 5f4acfb..a69738e 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -134,7 +134,8 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment module_name="delete_booking", method="DELETE", api_resource=api_gateway_resource, - environment_variables=environment_variables + environment_variables=environment_variables, + authorizer=token_authorizer_lambda ) #not auth and unused From 2ce2d00d75bd3f67e698e16fd0b37bc362eda2d2 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 8 Aug 2025 18:30:46 -0300 Subject: [PATCH 091/167] feat(update-booking): integrating user validation --- .../app/update_booking_controller.py | 16 +- .../app/update_booking_presenter.py | 9 + .../app/update_booking_usecase.py | 14 +- .../app/test_update_booking_controller.py | 225 +++++++++++++----- .../app/test_update_booking_presenter.py | 9 + .../app/test_update_booking_usecase.py | 177 ++++++++++++-- 6 files changed, 364 insertions(+), 86 deletions(-) diff --git a/src/modules/update_booking/app/update_booking_controller.py b/src/modules/update_booking/app/update_booking_controller.py index ecdd232..448f1ae 100644 --- a/src/modules/update_booking/app/update_booking_controller.py +++ b/src/modules/update_booking/app/update_booking_controller.py @@ -4,8 +4,8 @@ from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse -from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, InternalServerError, NotFound -from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.external_interfaces.http_codes import OK, BadRequest, Forbidden, InternalServerError, NotFound +from src.shared.helpers.errors.usecase_errors import ForbiddenAction, NoItemsFound class UpdateBookingController: def __init__(self, update_booking_use_case: UpdateBookingUsecase): @@ -16,14 +16,17 @@ def __call__(self, request: IRequest) -> IResponse: if request.data.get('booking_id') is None: raise MissingParameters('booking_id') + if request.data.get('user_from_authorizer') is None: + raise MissingParameters('user authorizer') + booking_id = request.data.get('booking_id') start_date = request.data.get('start_date') end_date = request.data.get('end_date') court_number = request.data.get('court_number') sport_value = request.data.get('sport') materials = request.data.get('materials') - - + user = request.data.get('user_from_authorizer') + if not isinstance(booking_id, str): raise WrongTypeParameter('booking_id', 'str', type(booking_id).__name__) @@ -49,9 +52,11 @@ def __call__(self, request: IRequest) -> IResponse: if materials is not None and not isinstance(materials, list): raise WrongTypeParameter('materials', 'list', type(materials).__name__) + booking = self.UpdateBookingUsecase( booking_id=booking_id, + user=user, start_date=start_date, end_date=end_date, court_number=court_number, @@ -75,5 +80,8 @@ def __call__(self, request: IRequest) -> IResponse: except NoItemsFound as err: return NotFound(body=f"Booking not found: {err.message}") + except ForbiddenAction as err: + return Forbidden(body=err.message) + except Exception as err: return InternalServerError(body=err.args[0]) \ No newline at end of file diff --git a/src/modules/update_booking/app/update_booking_presenter.py b/src/modules/update_booking/app/update_booking_presenter.py index 19b0404..17fd9d3 100644 --- a/src/modules/update_booking/app/update_booking_presenter.py +++ b/src/modules/update_booking/app/update_booking_presenter.py @@ -1,3 +1,4 @@ +import json from .update_booking_controller import UpdateBookingController from .update_booking_usecase import UpdateBookingUsecase from src.shared.environments import Environments @@ -10,6 +11,14 @@ def lambda_handler(event, context): httpRequest = LambdaHttpRequest(data=event) + + user_info_string = event.get('requestContext', {}).get('authorizer', {}).get('user') + + if user_info_string: + httpRequest.data['user_from_authorizer'] = json.loads(user_info_string).get('user') + else: + httpRequest.data['user_from_authorizer'] = None + response = controller(request=httpRequest) httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) diff --git a/src/modules/update_booking/app/update_booking_usecase.py b/src/modules/update_booking/app/update_booking_usecase.py index e039294..35fd7ce 100644 --- a/src/modules/update_booking/app/update_booking_usecase.py +++ b/src/modules/update_booking/app/update_booking_usecase.py @@ -3,7 +3,7 @@ from src.shared.domain.enums.sport import SPORT from src.shared.domain.repositories.booking_repository_interface import IBookingRepository from src.shared.helpers.errors.domain_errors import EntityError, EntityParameterOrderDatesError -from src.shared.helpers.errors.usecase_errors import NoItemsFound, InvalidSchedule +from src.shared.helpers.errors.usecase_errors import ForbiddenAction, NoItemsFound, InvalidSchedule class UpdateBookingUsecase: def __init__(self, booking_repo: IBookingRepository): @@ -11,12 +11,16 @@ def __init__(self, booking_repo: IBookingRepository): def __call__(self, booking_id: str, + user: dict, start_date: int = None, end_date: int = None, court_number: int = None, sport: SPORT = None, materials: List[str] = None, - user_id: str = None): + new_user_id: str = None): + + user_id = user.get('user_id') + user_role = user.get('role') if Booking.validate_booking_id(booking_id) is False: raise EntityError('booking_id') @@ -25,6 +29,11 @@ def __call__(self, if existing_booking is None: raise NoItemsFound('booking') + if user_role != 'ADMIN': + + booking_user_id = existing_booking.user_id + if booking_user_id != user_id: + raise ForbiddenAction('user id') start_date = start_date if start_date is not None else existing_booking.start_date end_date = end_date if end_date is not None else existing_booking.end_date @@ -32,7 +41,6 @@ def __call__(self, sport = sport if sport is not None else existing_booking.sport materials = materials if materials is not None else existing_booking.materials - if Booking.validate_dates(start_date, end_date) is False: raise EntityError("date") diff --git a/tests/modules/update_booking/app/test_update_booking_controller.py b/tests/modules/update_booking/app/test_update_booking_controller.py index 02f02d2..fd19080 100644 --- a/tests/modules/update_booking/app/test_update_booking_controller.py +++ b/tests/modules/update_booking/app/test_update_booking_controller.py @@ -14,12 +14,18 @@ def test_update_booking_controller(self): controller = UpdateBookingController(update_booking_use_case=usecase) request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'], + "user_from_authorizer": { + 'user_id': 'qualquer-id', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'ADMIN' + } }) response = controller(request) @@ -27,17 +33,51 @@ def test_update_booking_controller(self): assert response.status_code == 200 assert response.body['message'] == "the booking was retrieved" + + def test_update_booking_controller_with_invalid_user_id(self): + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + controller = UpdateBookingController(update_booking_use_case=usecase) + + request = HttpRequest(body={ + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'], + "user_from_authorizer": { + 'user_id': 'invalid', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + }) + + response = controller(request) + + assert response.status_code == 403 + assert response.body == "That action is forbidden for this user id" + + def test_update_booking_controller_booking_id_missing(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) controller = UpdateBookingController(update_booking_use_case=usecase) request = HttpRequest(body={ - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'], + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + }) response = controller(request) @@ -51,12 +91,19 @@ def test_update_booking_controller_booking_id_wrong_type(self): controller = UpdateBookingController(update_booking_use_case=usecase) request = HttpRequest(body={ - "booking_id": 123, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + "booking_id": 123, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'], + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + }) response = controller(request) @@ -71,12 +118,18 @@ def test_update_booking_controller_start_date_wrong_type(self): controller = UpdateBookingController(update_booking_use_case=usecase) request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": "123", - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": "123", + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'], + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } }) response = controller(request) @@ -91,12 +144,18 @@ def test_update_booking_controller_end_date_wrong_type(self): controller = UpdateBookingController(update_booking_use_case=usecase) request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": "123", - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": "123", + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'], + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } }) response = controller(request) @@ -111,12 +170,18 @@ def test_update_booking_controller_court_number_wrong_type(self): controller = UpdateBookingController(update_booking_use_case=usecase) request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": "1", - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": "1", + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'], + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } }) response = controller(request) @@ -131,12 +196,18 @@ def test_update_booking_controller_sport_wrong_type(self): controller = UpdateBookingController(update_booking_use_case=usecase) request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": 123, - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": 123, + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'], + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } }) response = controller(request) @@ -151,12 +222,18 @@ def test_update_booking_controller_materials_wrong_type(self): controller = UpdateBookingController(update_booking_use_case=usecase) request = HttpRequest(body={ - "booking_id": booking_repo.bookings[0].booking_id, - "start_date": booking_repo.bookings[0].start_date, - "end_date": booking_repo.bookings[0].end_date, - "court_number": 1, - "sport": "Tennis", - "materials": "Raquete, Bola, Rede, Tenis" + "booking_id": booking_repo.bookings[0].booking_id, + "start_date": booking_repo.bookings[0].start_date, + "end_date": booking_repo.bookings[0].end_date, + "court_number": 1, + "sport": "Tennis", + "materials": "Raquete, Bola, Rede, Tenis", + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } }) response = controller(request) @@ -174,7 +251,13 @@ def test_update_booking_controller_only_booking_id(self): booking_id = original_booking.booking_id request = HttpRequest(body={ - "booking_id": booking_id + "booking_id": booking_id, + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } }) response = controller(request) @@ -192,13 +275,19 @@ def test_update_booking_controller_user_id_ignored(self): new_user_id = "novo-user-id-que-nao-deve-ser-usado" request = HttpRequest(body={ - "booking_id": original_booking.booking_id, - "start_date": original_booking.start_date, - "end_date": original_booking.end_date, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'], - "user_id": new_user_id + "booking_id": original_booking.booking_id, + "start_date": original_booking.start_date, + "end_date": original_booking.end_date, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'], + "user_id": new_user_id, + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } }) response = controller(request) @@ -224,12 +313,18 @@ def get_booking_mock(booking_id): booking_repo.get_booking = get_booking_mock request = HttpRequest(body={ - "booking_id": non_existent_booking_id, - "start_date": 1634576165000, - "end_date": 1634583365000, - "court_number": 1, - "sport": "Tennis", - "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'] + "booking_id": non_existent_booking_id, + "start_date": 1634576165000, + "end_date": 1634583365000, + "court_number": 1, + "sport": "Tennis", + "materials": ['Raquete', 'Bola', 'Rede', 'Tenis'], + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } }) response = controller(request) @@ -251,7 +346,13 @@ def test_update_booking_controller_partial_update(self): request = HttpRequest(body={ "booking_id": booking_id, - "court_number": new_court_number + "court_number": new_court_number, + "user_from_authorizer": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } }) response = controller(request) diff --git a/tests/modules/update_booking/app/test_update_booking_presenter.py b/tests/modules/update_booking/app/test_update_booking_presenter.py index 9887f18..6fe8ca3 100644 --- a/tests/modules/update_booking/app/test_update_booking_presenter.py +++ b/tests/modules/update_booking/app/test_update_booking_presenter.py @@ -26,6 +26,15 @@ def test_lambda_handler(self): "apiId": "", "authentication": None, "authorizer": { + "user": json.dumps({ + "user": { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + }, + "message": "the user was retrieved" + }) }, "domainName": ".lambda-url.us-west-2.on.aws", "domainPrefix": "", diff --git a/tests/modules/update_booking/app/test_update_booking_usecase.py b/tests/modules/update_booking/app/test_update_booking_usecase.py index e47862a..f853693 100644 --- a/tests/modules/update_booking/app/test_update_booking_usecase.py +++ b/tests/modules/update_booking/app/test_update_booking_usecase.py @@ -3,7 +3,7 @@ from src.modules.update_booking.app.update_booking_usecase import UpdateBookingUsecase from src.shared.domain.enums.sport import SPORT from src.shared.helpers.errors.domain_errors import EntityError, EntityParameterOrderDatesError, EntityParameterTimeError -from src.shared.helpers.errors.usecase_errors import InvalidSchedule +from src.shared.helpers.errors.usecase_errors import ForbiddenAction, InvalidSchedule from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock @@ -14,7 +14,15 @@ def test_update_booking_usecase(self): booking_id = booking_repo.bookings[0].booking_id + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + booking = usecase(booking_id=booking_id, + user=user, court_number=2, start_date=1634576165000, end_date=1634583365000, @@ -29,6 +37,29 @@ def test_update_booking_usecase(self): assert booking_repo.bookings[0].sport == booking.sport assert booking_repo.bookings[0].materials == booking.materials + def test_update_booking_usecase_with_invalid_user_id(self): + booking_repo = BookingRepositoryMock() + usecase = UpdateBookingUsecase(booking_repo=booking_repo) + + booking_id = booking_repo.bookings[0].booking_id + + user = { + 'user_id': 'c07e0862-3c07-4227-ab0f-511a267cb7ff', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + + with pytest.raises(ForbiddenAction): + usecase(booking_id=booking_id, + user=user, + court_number=2, + start_date=1634576165000, + end_date=1634583365000, + sport=SPORT.TENNIS, + materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + ) + def test_update_booking_usecase_invalid_schedule_overlap(self): with pytest.raises(InvalidSchedule) as e: @@ -38,7 +69,15 @@ def test_update_booking_usecase_invalid_schedule_overlap(self): booking_id = booking_repo.bookings[0].booking_id + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + booking = usecase(booking_id=booking_id, + user=user, court_number=3, start_date=1634569200000, end_date=1634570000000, @@ -57,7 +96,15 @@ def test_update_booking_usecase_invalid_schedule_15min_intolerance(self): booking_id = booking_repo.bookings[0].booking_id + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + booking = usecase(booking_id=booking_id, + user=user, court_number=3, start_date=1634571899999, end_date=1734571000000, @@ -71,8 +118,16 @@ def test_update_booking_usecase_invalid_booking_id(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + with pytest.raises(EntityError): booking = usecase(booking_id=111, + user=user, court_number=2, start_date=1634576165000, end_date=1634583365000, @@ -84,8 +139,16 @@ def test_update_booking_usecase_invalid_dates(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + with pytest.raises(EntityError): booking = usecase(booking_id=booking_repo.bookings[0].booking_id, + user=user, court_number=2, start_date="1634583365000", end_date="1634576165000", @@ -97,8 +160,16 @@ def test_update_booking_usecase_invalid_sport(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + with pytest.raises(EntityError): - booking = usecase(booking_id=booking_repo.bookings[0].booking_id, + booking = usecase(booking_id=booking_repo.bookings[0].booking_id, + user=user, court_number=2, start_date=1634576165000, end_date=1634583365000, @@ -110,8 +181,16 @@ def test_update_booking_usecase_invalid_materials(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + with pytest.raises(EntityError): - booking = usecase(booking_id=booking_repo.bookings[0].booking_id, + booking = usecase(booking_id=booking_repo.bookings[0].booking_id, + user=user, court_number=2, start_date=1634576165000, end_date=1634583365000, @@ -123,8 +202,16 @@ def test_update_booking_usecase_none_booking_id(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + with pytest.raises(EntityError): - booking = usecase(booking_id=None, + booking = usecase(booking_id=None, + user=user, court_number=2, start_date=1634576165000, end_date=1634583365000, @@ -135,12 +222,20 @@ def test_update_booking_usecase_none_booking_id(self): def test_update_booking_usecase_none_court_number(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) - + + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + original_booking = booking_repo.bookings[0] original_court_number = original_booking.court_number booking = usecase( - booking_id=original_booking.booking_id, + booking_id=original_booking.booking_id, + user=user, court_number=None, start_date=1634576165000, end_date=1634583365000, @@ -156,9 +251,17 @@ def test_update_booking_usecase_none_start_date(self): original_booking = booking_repo.bookings[0] original_start_date = original_booking.start_date - + + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + booking = usecase( - booking_id=original_booking.booking_id, + booking_id=original_booking.booking_id, + user=user, court_number=2, start_date=None, end_date=1634583365000, @@ -171,12 +274,20 @@ def test_update_booking_usecase_none_start_date(self): def test_update_booking_usecase_none_end_date(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) - + + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + original_booking = booking_repo.bookings[0] original_end_date = original_booking.end_date booking = usecase( - booking_id=original_booking.booking_id, + booking_id=original_booking.booking_id, + user=user, court_number=2, start_date=1634576165000, end_date=None, @@ -190,8 +301,16 @@ def test_update_booking_usecase_order_dates_incorrect(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + with pytest.raises(EntityParameterOrderDatesError): - booking = usecase(booking_id=booking_repo.bookings[0].booking_id, + booking = usecase(booking_id=booking_repo.bookings[0].booking_id, + user=user, court_number=2, start_date=1634583365000, end_date=1634576165000, @@ -202,12 +321,20 @@ def test_update_booking_usecase_order_dates_incorrect(self): def test_update_booking_usecase_none_sport(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) - + + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + original_booking = booking_repo.bookings[0] original_sport = original_booking.sport booking = usecase( - booking_id=original_booking.booking_id, + booking_id=original_booking.booking_id, + user=user, court_number=2, start_date=1634576165000, end_date=1634583365000, @@ -220,12 +347,20 @@ def test_update_booking_usecase_none_sport(self): def test_update_booking_usecase_none_materials(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) - + + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + original_booking = booking_repo.bookings[0] original_materials = original_booking.materials booking = usecase( - booking_id=original_booking.booking_id, + booking_id=original_booking.booking_id, + user=user, court_number=2, start_date=1634576165000, end_date=1634583365000, @@ -239,18 +374,26 @@ def test_update_booking_usecase_cannot_update_user_id(self): booking_repo = BookingRepositoryMock() usecase = UpdateBookingUsecase(booking_repo=booking_repo) + user = { + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'name': 'Nome', + 'email': 'user@email.com', + 'role': 'STUDENT' + } + original_booking = booking_repo.bookings[0] booking_id = original_booking.booking_id original_user_id = original_booking.user_id booking = usecase( - booking_id=booking_id, + booking_id=booking_id, + user=user, court_number=2, start_date=1634576165000, end_date=1634583365000, sport=SPORT.TENNIS, materials=['Raquete', 'Bola', 'Rede', 'Tenis'], - user_id="novo-user-id-que-nao-deve-ser-usado" + new_user_id="novo-user-id-que-nao-deve-ser-usado" ) assert booking.user_id == original_user_id \ No newline at end of file From 7a4625472aa0bef5b8d7d1c9252f0fe883db5c95 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Tue, 12 Aug 2025 09:47:16 -0300 Subject: [PATCH 092/167] adding dynamo permission to generate report --- iac/stacks/lambda_stack.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index a69738e..f21a883 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -215,7 +215,8 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment self.update_booking, self.delete_booking, self.get_all_bookings, - self.get_bookings + self.get_bookings, + self.generate_report ] self.functions_that_need_s3_permissions = [ From 6ddbe446384dd8c1917d0354a85ad7cb774ed193 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Tue, 12 Aug 2025 11:29:36 -0300 Subject: [PATCH 093/167] updating to new account again --- .github/workflows/CD.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index bb83732..dc284cc 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -22,9 +22,17 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Determine AWS Account ID - run: echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID }}" >> $GITHUB_ENV - + - name: Set AWS Account ID + run: | + if [[ "${{ github.ref_name }}" == "dev" ]]; then + echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_DEV }}" >> $GITHUB_ENV + elif [[ "${{ github.ref_name }}" == "homolog" ]]; then + echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_HOMOLOG }}" >> $GITHUB_ENV + elif [[ "${{ github.ref_name }}" == "prod" ]]; then + echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_PROD }}" >> $GITHUB_ENV + else + echo "Invalid branch name!" && exit 1 + fi - name: Setup AWS Credentials uses: aws-actions/configure-aws-credentials@v2 From 473c9623e30ed0e7ec015fce465c6fbfb2942ab4 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Tue, 12 Aug 2025 11:32:17 -0300 Subject: [PATCH 094/167] fixing region --- .github/workflows/CD.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index dc284cc..a284f7d 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -37,7 +37,7 @@ jobs: - name: Setup AWS Credentials uses: aws-actions/configure-aws-credentials@v2 with: - aws-region: sa-east-1 + aws-region: ${{ env.AWS_REGION }} role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/GithubActionsRole role-session-name: github-action From 70a1df45115c0d669d629d815a9728bc303b6649 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Tue, 12 Aug 2025 11:32:54 -0300 Subject: [PATCH 095/167] fixing region again --- .github/workflows/CD.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index a284f7d..d583cf5 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -37,7 +37,7 @@ jobs: - name: Setup AWS Credentials uses: aws-actions/configure-aws-credentials@v2 with: - aws-region: ${{ env.AWS_REGION }} + aws-region: ${{ vars.AWS_REGION }} role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/GithubActionsRole role-session-name: github-action From 2d630bb1ef7c922504ef53fefd99bc7344f0e34b Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Tue, 12 Aug 2025 11:42:39 -0300 Subject: [PATCH 096/167] =?UTF-8?q?updating=20aws=20region=20=F0=9F=A6=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/CD.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index d583cf5..32134df 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -75,7 +75,7 @@ jobs: cdk deploy --require-approval never env: - AWS_REGION: sa-east-1 + AWS_REGION: ${{ vars.AWS_REGION }} AWS_ACCOUNT_ID: ${{ env.AWS_ACCOUNT_ID }} STACK_NAME: ${{ env.STACK_NAME }} GITHUB_REF_NAME: ${{ github.ref_name }} From d216abf13b81a5143c7dba63485eeeff6e716b64 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Tue, 12 Aug 2025 11:52:39 -0300 Subject: [PATCH 097/167] improved s3 upload method to debug tf is wrong --- src/shared/clients/s3_client.py | 44 ++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/src/shared/clients/s3_client.py b/src/shared/clients/s3_client.py index ee94e96..0d2dbf9 100644 --- a/src/shared/clients/s3_client.py +++ b/src/shared/clients/s3_client.py @@ -21,18 +21,40 @@ def __init__(self): self.s3 = boto3.client("s3") def upload_file(self, key, file_type, decode_string): - - response = self.s3.put_object( - Bucket=self.__envs.s3_bucket_name, - Key=key, - Body=decode_string, - ContentType=file_type.replace(".", ""), - ) - - return { - 's3_response': response, - 'key': key + print(f"DEBUG upload_file - key: {key}") + print(f"DEBUG upload_file - file_type: {file_type}") + print(f"DEBUG upload_file - decode_string type: {type(decode_string)}") + print(f"DEBUG upload_file - decode_string length: {len(decode_string)}") + + # Content type correto para Excel + content_types = { + '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + '.xls': 'application/vnd.ms-excel', } + + content_type = content_types.get(file_type, 'application/octet-stream') + print(f"DEBUG upload_file - content_type: {content_type}") + + try: + print("DEBUG upload_file - Chamando s3.put_object...") + response = self.s3.put_object( + Bucket=self.__envs.s3_bucket_name, + Key=key, + Body=decode_string, # Este deve ser bytes + ContentType=content_type, + ) + print("DEBUG upload_file - put_object executado com sucesso") + + return { + 's3_response': response, + 'key': key + } + + except Exception as e: + print(f"DEBUG upload_file - ERRO no put_object: {str(e)}") + print(f"DEBUG upload_file - Tipo do erro: {type(e)}") + print(f"DEBUG upload_file - Bucket: {self.__envs.s3_bucket_name}") + raise e def delete_file(self): pass From f98b5954476555597d1385a4da46ebbc5ad6521e Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Tue, 12 Aug 2025 11:53:38 -0300 Subject: [PATCH 098/167] passing the report bytes, not the object --- src/modules/generate_report/app/generate_report_presenter.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/generate_report/app/generate_report_presenter.py b/src/modules/generate_report/app/generate_report_presenter.py index a3db094..537187c 100644 --- a/src/modules/generate_report/app/generate_report_presenter.py +++ b/src/modules/generate_report/app/generate_report_presenter.py @@ -37,6 +37,8 @@ def lambda_handler(event, context): bucket_manager = s3_client() try: + + report = report.getvalue() response = bucket_manager.upload_file(key=file_path + file_name, file_type=".xlsx", From f0886de866ed4b40bd548e30bb119a3d36e671c8 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Tue, 12 Aug 2025 12:09:23 -0300 Subject: [PATCH 099/167] adding bucket name to environment variables at iac_stack --- iac/stacks/iac_stack.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iac/stacks/iac_stack.py b/iac/stacks/iac_stack.py index 2089081..79b5779 100644 --- a/iac/stacks/iac_stack.py +++ b/iac/stacks/iac_stack.py @@ -55,7 +55,8 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: "DYNAMO_PARTITION_KEY": "PK", "DYNAMO_SORT_KEY": "SK", "REGION": self.aws_region, - "USER_API_URL": os.environ.get("USER_API_URL") + "USER_API_URL": os.environ.get("USER_API_URL"), + "S3_BUCKET_NAME": self.s3_bucket.bucket.bucket_name, } From 2c3602a3963de0c3d690858789d0bcd6c0591212 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 13 Aug 2025 22:16:38 -0300 Subject: [PATCH 100/167] fix(update-booking): add user authorizer on lambda --- iac/stacks/lambda_stack.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index a69738e..9146049 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -111,7 +111,8 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment module_name="update_booking", method="PUT", api_resource=api_gateway_resource, - environment_variables=environment_variables + environment_variables=environment_variables, + authorizer=token_authorizer_lambda ) #not ready for auth AND not used? From db3d674917470c83e832f54a49b7211a6ddab2eb Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 27 Aug 2025 12:24:38 -0300 Subject: [PATCH 101/167] added new module, added module to lambda stack, created new erros for module, added minimal test --- iac/stacks/lambda_stack.py | 10 ++++- .../get_all_admin_bookings/__init__.py | 0 .../get_all_admin_bookings/app/__init__.py | 0 .../app/get_all_admin_bookings_controller.py | 37 +++++++++++++++++ .../app/get_all_admin_bookings_presenter.py | 25 ++++++++++++ .../app/get_all_admin_bookings_usecase.py | 40 +++++++++++++++++++ .../app/get_all_admin_bookings_viewmodel.py | 21 ++++++++++ src/shared/helpers/errors/usecase_errors.py | 9 +++++ .../get_all_admin_bookings/__init__.py | 0 .../get_all_admin_bookings/app/__init__.py | 0 .../test_get_all_admin_bookings_controller.py | 14 +++++++ 11 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 src/modules/get_all_admin_bookings/__init__.py create mode 100644 src/modules/get_all_admin_bookings/app/__init__.py create mode 100644 src/modules/get_all_admin_bookings/app/get_all_admin_bookings_controller.py create mode 100644 src/modules/get_all_admin_bookings/app/get_all_admin_bookings_presenter.py create mode 100644 src/modules/get_all_admin_bookings/app/get_all_admin_bookings_usecase.py create mode 100644 src/modules/get_all_admin_bookings/app/get_all_admin_bookings_viewmodel.py create mode 100644 tests/modules/get_all_admin_bookings/__init__.py create mode 100644 tests/modules/get_all_admin_bookings/app/__init__.py create mode 100644 tests/modules/get_all_admin_bookings/app/test_get_all_admin_bookings_controller.py diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index f21a883..2ff1e72 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -203,6 +203,13 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment cron_schedule=Schedule.cron(minute="0", hour="18", week_day="FRI"), environment_variables=environment_variables ) + + self.get_all_admin_bookings = self.create_lambda_api_gateway_integration( + module_name="get_all_admin_bookings", + method="GET", + api_resource=api_gateway_resource, + environment_variables=environment_variables + ) self.functions_that_need_dynamo_permissions = [ self.create_court, @@ -216,7 +223,8 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment self.delete_booking, self.get_all_bookings, self.get_bookings, - self.generate_report + self.generate_report, + self.get_all_admin_bookings ] self.functions_that_need_s3_permissions = [ diff --git a/src/modules/get_all_admin_bookings/__init__.py b/src/modules/get_all_admin_bookings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/get_all_admin_bookings/app/__init__.py b/src/modules/get_all_admin_bookings/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_controller.py b/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_controller.py new file mode 100644 index 0000000..9692885 --- /dev/null +++ b/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_controller.py @@ -0,0 +1,37 @@ +from .get_all_admin_bookings_usecase import GetAllAdminBookingsUsecase +from .get_all_admin_bookings_viewmodel import GetAllAdminBookingsViewmodel +from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse +from src.shared.helpers.external_interfaces.http_codes import * +from src.shared.helpers.errors.domain_errors import * +from src.shared.helpers.errors.usecase_errors import * + + + +class GetAllAdminBookingsController: + + def __init__(self, usecase: GetAllAdminBookingsUsecase): + + self.usecase = usecase + + def __call__(self, request: IRequest) -> IResponse: + + try: + + response = self.usecase() + + return OK(GetAllAdminBookingsViewmodel(bookings=response).to_dict()) + + except EntityError as err: + return BadRequest(body=err.message) + + except NoItemsFound as err: + return BadRequest(body=err.message) + + except NoAdminFound as err: + return BadRequest(body=err.message) + + except NoAdminBookingsFound as err: + return BadRequest(body=err.message) + + except Exception as err: + return InternalServerError(body=err.args[0]) \ No newline at end of file diff --git a/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_presenter.py b/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_presenter.py new file mode 100644 index 0000000..4adf9c4 --- /dev/null +++ b/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_presenter.py @@ -0,0 +1,25 @@ +import json +from .get_all_admin_bookings_controller import GetAllAdminBookingsController +from .get_all_admin_bookings_usecase import GetAllAdminBookingsUsecase +from src.shared.environments import Environments +from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse + + +repo = Environments.get_booking_repo()() +usecase = GetAllAdminBookingsUsecase(repo) +controller = GetAllAdminBookingsController(usecase) + +def lambda_handler(event, context): + httpRequest = LambdaHttpRequest(data=event) + + user_info_string = event.get('requestContext', {}).get('authorizer', {}).get('user') + + if user_info_string: + httpRequest.data['user_from_authorizer'] = json.loads(user_info_string).get('user') + else: + httpRequest.data['user_from_authorizer'] = None + + response = controller(request=httpRequest) + httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) + + return httpResponse.toDict() \ No newline at end of file diff --git a/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_usecase.py b/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_usecase.py new file mode 100644 index 0000000..d76f450 --- /dev/null +++ b/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_usecase.py @@ -0,0 +1,40 @@ +from src.shared.domain.repositories.booking_repository_interface import IBookingRepository +from src.shared.clients.user_api_client import UserAPIClient +from src.shared.helpers.errors.usecase_errors import * + +class GetAllAdminBookingsUsecase: + + def __init__(self, repo: IBookingRepository): + + self.repo = repo + self.user_client = UserAPIClient() + + def __call__(self): + + all_users = self.user_client.all_users + admin_user = None + + for item in all_users: + + if item.get("role") == "ADMIN" and item.get("email") == "dev@maua.br": + + admin_user = item + + if admin_user == None: + + raise NoAdminFound() + + all_bookings = self.repo.get_all_bookings() + admin_bookings = [] + + for item in all_bookings: + + if item.user_id == admin_user.get("user_id", None): + + admin_bookings.append(item) + + if not admin_bookings: + + raise NoAdminBookingsFound() + + return admin_bookings \ No newline at end of file diff --git a/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_viewmodel.py b/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_viewmodel.py new file mode 100644 index 0000000..55de6f3 --- /dev/null +++ b/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_viewmodel.py @@ -0,0 +1,21 @@ +from typing import List +from src.shared.domain.entities.booking import Booking + + +class GetAllAdminBookingsViewmodel: + + bookings: List[Booking] + + def __init__(self, bookings: List[Booking]): + + self.bookings = bookings + + def to_dict(self): + + return { + "bookings": [ + {k: v for k, v in booking.to_dict().items() if k != 'user_id'} + for booking in self.bookings + ], + "message": "Admin bookings retreived" + } \ No newline at end of file diff --git a/src/shared/helpers/errors/usecase_errors.py b/src/shared/helpers/errors/usecase_errors.py index 371c9c7..1c17218 100644 --- a/src/shared/helpers/errors/usecase_errors.py +++ b/src/shared/helpers/errors/usecase_errors.py @@ -24,3 +24,12 @@ class InvalidSchedule(BaseError): def __init__(self): super().__init__('Court is already booked for the selected time slot or has to have 15 min tolerance') +class NoAdminFound(BaseError): + + def __init__(self): + super().__init__("No user with role admin was found in user mss") + +class NoAdminBookingsFound(BaseError): + + def __init__(self): + super().__init__("Admin does not have any bookings") diff --git a/tests/modules/get_all_admin_bookings/__init__.py b/tests/modules/get_all_admin_bookings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/modules/get_all_admin_bookings/app/__init__.py b/tests/modules/get_all_admin_bookings/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/modules/get_all_admin_bookings/app/test_get_all_admin_bookings_controller.py b/tests/modules/get_all_admin_bookings/app/test_get_all_admin_bookings_controller.py new file mode 100644 index 0000000..879fe79 --- /dev/null +++ b/tests/modules/get_all_admin_bookings/app/test_get_all_admin_bookings_controller.py @@ -0,0 +1,14 @@ +from src.modules.get_all_admin_bookings.app.get_all_admin_bookings_controller import GetAllAdminBookingsController +from src.modules.get_all_admin_bookings.app.get_all_admin_bookings_usecase import GetAllAdminBookingsUsecase +from src.shared.helpers.external_interfaces.http_models import HttpRequest +from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock + +class TestGetAllAdminBookingsController: + + def test_get_all_admin_bookings_controller(self): + + repo = BookingRepositoryMock() + usecase = GetAllAdminBookingsUsecase(repo = repo) + controller = GetAllAdminBookingsController(usecase=usecase) + request = HttpRequest() + response = controller(request) \ No newline at end of file From 2f47ad1629e95ce9607efd3c7243d3b1801b2546 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 27 Aug 2025 12:29:10 -0300 Subject: [PATCH 102/167] markskip to test that needs endpoint --- .../app/test_get_all_admin_bookings_controller.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/modules/get_all_admin_bookings/app/test_get_all_admin_bookings_controller.py b/tests/modules/get_all_admin_bookings/app/test_get_all_admin_bookings_controller.py index 879fe79..04c3281 100644 --- a/tests/modules/get_all_admin_bookings/app/test_get_all_admin_bookings_controller.py +++ b/tests/modules/get_all_admin_bookings/app/test_get_all_admin_bookings_controller.py @@ -2,9 +2,11 @@ from src.modules.get_all_admin_bookings.app.get_all_admin_bookings_usecase import GetAllAdminBookingsUsecase from src.shared.helpers.external_interfaces.http_models import HttpRequest from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock +import pytest class TestGetAllAdminBookingsController: + @pytest.mark.skip("needs user endpoint url to urn") def test_get_all_admin_bookings_controller(self): repo = BookingRepositoryMock() From 86c4987a41c255b400f3e44f0218a70efe6f086b Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 27 Aug 2025 12:33:20 -0300 Subject: [PATCH 103/167] added authorizer to update_booking --- iac/stacks/lambda_stack.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index 2ff1e72..393d506 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -106,12 +106,13 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment authorizer=token_authorizer_lambda ) - #not ready for auth + #ready for auth self.update_booking = self.create_lambda_api_gateway_integration( module_name="update_booking", method="PUT", api_resource=api_gateway_resource, - environment_variables=environment_variables + environment_variables=environment_variables, + authorizer=token_authorizer_lambda ) #not ready for auth AND not used? From d7ea9ff335de2cd2b7f895026616ce86a9ee9ac7 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 27 Aug 2025 13:33:47 -0300 Subject: [PATCH 104/167] dummy commit to update secret deploy --- src/shared/authorizer/user_mss_authorizer.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/shared/authorizer/user_mss_authorizer.py b/src/shared/authorizer/user_mss_authorizer.py index cb376ce..b250dc1 100644 --- a/src/shared/authorizer/user_mss_authorizer.py +++ b/src/shared/authorizer/user_mss_authorizer.py @@ -31,8 +31,6 @@ def lambda_handler(event, context): # Extracting the token from the event data token = event["authorizationToken"].replace("Bearer ", "") - print(f"token: {token}") - # Fetching the user information from the user mss methodArn = event["methodArn"] headers = {"Authorization": f"Bearer {token}"} From 1db58251e47f93eebc1aa8046e880f2acb5bbfe7 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Wed, 27 Aug 2025 13:35:20 -0300 Subject: [PATCH 105/167] removing unused secret --- .github/workflows/CD.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index 32134df..b33ab12 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -85,5 +85,4 @@ jobs: FROM_EMAIL: ${{ vars.FROM_EMAIL }} HIDDEN_COPY: ${{ vars.HIDDEN_COPY }} REPLY_TO_EMAIL: ${{ vars.REPLY_TO_EMAIL }} - GRAPH_MICROSOFT_ENDPOINT: ${{ secrets.GRAPH_MICROSOFT_ENDPOINT }} USER_API_URL: ${{ secrets.USER_API_URL }} From 0e3d26dd2497209a0c527e32df3ef1c85f3a9941 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 27 Aug 2025 21:24:18 -0300 Subject: [PATCH 106/167] chore: criando diretorio da rota --- src/modules/get_all_bookings_grouped_by_role/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/modules/get_all_bookings_grouped_by_role/__init__.py diff --git a/src/modules/get_all_bookings_grouped_by_role/__init__.py b/src/modules/get_all_bookings_grouped_by_role/__init__.py new file mode 100644 index 0000000..e69de29 From d8b09fab08543191cf31a3acc12f2570ee6a20f7 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 27 Aug 2025 21:24:28 -0300 Subject: [PATCH 107/167] feat: usecase da rota feito --- ...et_all_bookings_grouped_by_role_usecase.py | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_usecase.py diff --git a/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_usecase.py b/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_usecase.py new file mode 100644 index 0000000..1f1ca92 --- /dev/null +++ b/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_usecase.py @@ -0,0 +1,41 @@ +from src.shared.clients.user_api_client import UserAPIClient +from src.shared.domain.repositories.booking_repository_interface import IBookingRepository +from src.shared.helpers.errors.usecase_errors import NoItemsFound + + +class GetAllBookingsGroupedByRoleUsecase: + + def __init__(self, repo: IBookingRepository): + self.repo = repo + self.user_client = UserAPIClient() + + def __call__(self): + all_users = self.user_client.all_users + + all_bookings = self.repo.get_all_bookings() + + if all_bookings is None: + raise NoItemsFound('all_bookings') + + all_bookings_by_role = { + 'UNKNOWN': [] + } + + for user in all_users: + + user_role = user.get('role', None) + user_id = user.get('user_id', None) + + if user_role is not None: + + if user_role not in all_bookings_by_role: + all_bookings_by_role[user_role] = [] + + user_bookings = [booking for booking in all_bookings if booking.user_id == user_id] + + all_bookings_by_role[user_role if user_role is not None else 'UNKNOWN'].extend(user_bookings) + + return all_bookings_by_role + + + \ No newline at end of file From 692c386be404749ede20777919144f9ac5d851c9 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 27 Aug 2025 23:21:57 -0300 Subject: [PATCH 108/167] chore: adicionando diretorio de testes da rota --- tests/modules/get_all_bookings_grouped_by_role/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/modules/get_all_bookings_grouped_by_role/__init__.py diff --git a/tests/modules/get_all_bookings_grouped_by_role/__init__.py b/tests/modules/get_all_bookings_grouped_by_role/__init__.py new file mode 100644 index 0000000..e69de29 From 98cbe0d44029ec35583fc79d21052213e388b129 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 27 Aug 2025 23:23:10 -0300 Subject: [PATCH 109/167] fix: retirando user_id dos bookings retornados --- .../app/get_all_bookings_grouped_by_role_usecase.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_usecase.py b/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_usecase.py index 1f1ca92..e9f5eab 100644 --- a/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_usecase.py +++ b/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_usecase.py @@ -31,7 +31,11 @@ def __call__(self): if user_role not in all_bookings_by_role: all_bookings_by_role[user_role] = [] - user_bookings = [booking for booking in all_bookings if booking.user_id == user_id] + user_bookings = [ + {k: v for k, v in booking.to_dict().items() if k != 'user_id'} + for booking in all_bookings + if booking.user_id == user_id + ] all_bookings_by_role[user_role if user_role is not None else 'UNKNOWN'].extend(user_bookings) From b5677904417378e3ebd205472428026c23db2023 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 27 Aug 2025 23:23:18 -0300 Subject: [PATCH 110/167] feat: viewmodel da rota --- ...get_all_bookings_grouped_by_role_viewmodel.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_viewmodel.py diff --git a/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_viewmodel.py b/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_viewmodel.py new file mode 100644 index 0000000..521480a --- /dev/null +++ b/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_viewmodel.py @@ -0,0 +1,16 @@ +from typing import Dict, List +from src.shared.domain.entities.booking import Booking + + +class GetAllBookingsGroupedByRoleViewmodel: + + def __init__(self, all_bookings_by_role: Dict[str, List[Booking]]): + + self.all_bookings_by_role = all_bookings_by_role + + def to_dict(self): + + return { + 'bookings': self.all_bookings_by_role, + 'message': "The bookings grouped by roles were retrieved." + } \ No newline at end of file From b37a70a773a3f3f0726fcdfc9bfaafa4ce23a282 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 27 Aug 2025 23:23:27 -0300 Subject: [PATCH 111/167] feat: controller da rota --- ...all_bookings_grouped_by_role_controller.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_controller.py diff --git a/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_controller.py b/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_controller.py new file mode 100644 index 0000000..d2dc308 --- /dev/null +++ b/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_controller.py @@ -0,0 +1,25 @@ +from src.modules.get_all_bookings_grouped_by_role.app.get_all_bookings_grouped_by_role_usecase import GetAllBookingsGroupedByRoleUsecase +from src.modules.get_all_bookings_grouped_by_role.app.get_all_bookings_grouped_by_role_viewmodel import GetAllBookingsGroupedByRoleViewmodel +from src.shared.helpers.errors.usecase_errors import NoItemsFound +from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse +from src.shared.helpers.external_interfaces.http_codes import OK, InternalServerError, NotFound + + +class GetAllBookingsGroupedByRoleController: + + def __init__(self, usecase: GetAllBookingsGroupedByRoleUsecase): + + self.usecase = usecase + + def __call__(self, request: IRequest) -> IResponse: + + try: + + response = self.usecase() + + return OK(GetAllBookingsGroupedByRoleViewmodel(response).to_dict()) + + except NoItemsFound as err: + return NotFound(body=err.message) + except Exception as err: + return InternalServerError(body=err.args[0]) \ No newline at end of file From d458619350601f1822c53d594142052828107930 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 27 Aug 2025 23:23:35 -0300 Subject: [PATCH 112/167] feat: presenter da rota --- ..._all_bookings_grouped_by_role_presenter.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_presenter.py diff --git a/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_presenter.py b/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_presenter.py new file mode 100644 index 0000000..a6230ac --- /dev/null +++ b/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_presenter.py @@ -0,0 +1,25 @@ +import json +from src.modules.get_all_bookings_grouped_by_role.app.get_all_bookings_grouped_by_role_controller import GetAllBookingsGroupedByRoleController +from src.modules.get_all_bookings_grouped_by_role.app.get_all_bookings_grouped_by_role_usecase import GetAllBookingsGroupedByRoleUsecase +from src.shared.environments import Environments +from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse + + +repo = Environments.get_booking_repo()() +usecase = GetAllBookingsGroupedByRoleUsecase(repo) +controller = GetAllBookingsGroupedByRoleController(usecase) + +def lambda_handler(event, context): + httpRequest = LambdaHttpRequest(data=event) + + user_info_string = event.get('requestContext', {}).get('authorizer', {}).get('user') + + if user_info_string: + httpRequest.data['user_from_authorizer'] = json.loads(user_info_string).get('user') + else: + httpRequest.data['user_from_authorizer'] = None + + response = controller(request=httpRequest) + httpResponse = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers) + + return httpResponse.toDict() \ No newline at end of file From 71a08a1fe1e5ba224e0f0ab558594234bd5b638e Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 27 Aug 2025 23:23:52 -0300 Subject: [PATCH 113/167] feat: integracao com o lambda --- iac/stacks/lambda_stack.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index 393d506..92e9ba3 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -212,6 +212,13 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment environment_variables=environment_variables ) + self.get_all_bookings_grouped_by_role = self.create_lambda_api_gateway_integration( + module_name="get_all_bookings_grouped_by_role", + method="GET", + api_resource=api_gateway_resource, + environment_variables=environment_variables + ) + self.functions_that_need_dynamo_permissions = [ self.create_court, self.get_court, @@ -225,7 +232,8 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment self.get_all_bookings, self.get_bookings, self.generate_report, - self.get_all_admin_bookings + self.get_all_admin_bookings, + self.get_all_bookings_grouped_by_role ] self.functions_that_need_s3_permissions = [ From ded1c682e7b87cc3505592e222a4980cb570fa3f Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 27 Aug 2025 23:39:11 -0300 Subject: [PATCH 114/167] fix: imports dando erro --- .../app/get_all_bookings_grouped_by_role_controller.py | 4 ++-- .../app/get_all_bookings_grouped_by_role_presenter.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_controller.py b/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_controller.py index d2dc308..8d04e22 100644 --- a/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_controller.py +++ b/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_controller.py @@ -1,5 +1,5 @@ -from src.modules.get_all_bookings_grouped_by_role.app.get_all_bookings_grouped_by_role_usecase import GetAllBookingsGroupedByRoleUsecase -from src.modules.get_all_bookings_grouped_by_role.app.get_all_bookings_grouped_by_role_viewmodel import GetAllBookingsGroupedByRoleViewmodel +from .get_all_bookings_grouped_by_role_usecase import GetAllBookingsGroupedByRoleUsecase +from .get_all_bookings_grouped_by_role_viewmodel import GetAllBookingsGroupedByRoleViewmodel from src.shared.helpers.errors.usecase_errors import NoItemsFound from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse from src.shared.helpers.external_interfaces.http_codes import OK, InternalServerError, NotFound diff --git a/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_presenter.py b/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_presenter.py index a6230ac..7d0fa41 100644 --- a/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_presenter.py +++ b/src/modules/get_all_bookings_grouped_by_role/app/get_all_bookings_grouped_by_role_presenter.py @@ -1,6 +1,6 @@ import json -from src.modules.get_all_bookings_grouped_by_role.app.get_all_bookings_grouped_by_role_controller import GetAllBookingsGroupedByRoleController -from src.modules.get_all_bookings_grouped_by_role.app.get_all_bookings_grouped_by_role_usecase import GetAllBookingsGroupedByRoleUsecase +from .get_all_bookings_grouped_by_role_controller import GetAllBookingsGroupedByRoleController +from .get_all_bookings_grouped_by_role_usecase import GetAllBookingsGroupedByRoleUsecase from src.shared.environments import Environments from src.shared.helpers.external_interfaces.http_lambda_requests import LambdaHttpRequest, LambdaHttpResponse From 6fa4238134194a7ed1b1469b10771b9fa8087df0 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Sat, 30 Aug 2025 11:29:22 -0300 Subject: [PATCH 115/167] removed user-id from all get routes --- .../app/get_all_admin_bookings_viewmodel.py | 2 +- .../get_all_bookings/app/get_all_bookings_viewmodel.py | 3 --- src/modules/get_booking/app/get_booking_viewmodel.py | 3 --- src/modules/get_bookings/app/get_bookings_viewmodel.py | 5 ++++- .../get_booking/app/test_get_booking_controller.py | 1 - .../modules/get_booking/app/test_get_booking_presenter.py | 1 - .../modules/get_booking/app/test_get_booking_viewmodel.py | 1 - .../get_bookings/app/test_get_bookings_controller.py | 8 ++------ .../get_bookings/app/test_get_bookings_presenter.py | 1 - .../get_bookings/app/test_get_bookings_viewmodel.py | 1 - 10 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_viewmodel.py b/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_viewmodel.py index 55de6f3..b16af11 100644 --- a/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_viewmodel.py +++ b/src/modules/get_all_admin_bookings/app/get_all_admin_bookings_viewmodel.py @@ -14,7 +14,7 @@ def to_dict(self): return { "bookings": [ - {k: v for k, v in booking.to_dict().items() if k != 'user_id'} + {k: v for k, v in booking.to_dict().items() if k != 'user_id' or k != 'booking_id'} for booking in self.bookings ], "message": "Admin bookings retreived" diff --git a/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py b/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py index 963e786..871209e 100644 --- a/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py +++ b/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py @@ -7,7 +7,6 @@ class BookingViewModel: end_date: int court_number: int sport: SPORT - user_id: str booking_id: str materials: List[str] @@ -16,7 +15,6 @@ def __init__(self, booking: Booking): self.end_date = booking.end_date self.court_number = booking.court_number self.sport = booking.sport - self.user_id = booking.user_id self.booking_id = booking.booking_id self.materials = booking.materials @@ -26,7 +24,6 @@ def to_dict(self): 'end_date': self.end_date, 'court_number': self.court_number, 'sport': self.sport.value, - 'user_id': self.user_id, 'booking_id': self.booking_id, 'materials': self.materials } diff --git a/src/modules/get_booking/app/get_booking_viewmodel.py b/src/modules/get_booking/app/get_booking_viewmodel.py index 484e7d5..7d5383c 100644 --- a/src/modules/get_booking/app/get_booking_viewmodel.py +++ b/src/modules/get_booking/app/get_booking_viewmodel.py @@ -6,7 +6,6 @@ class BookingViewmodel: end_date: int court_number: int sport: SPORT - user_id: str booking_id: str materials: list @@ -15,7 +14,6 @@ def __init__(self, booking: Booking): self.end_date = booking.end_date self.court_number = booking.court_number self.sport = booking.sport - self.user_id = booking.user_id self.booking_id = booking.booking_id self.materials = booking.materials @@ -25,7 +23,6 @@ def to_dict(self): 'end_date': self.end_date, 'court_number': self.court_number, 'sport': self.sport.value, - 'user_id': self.user_id, 'booking_id': self.booking_id, 'materials': self.materials } diff --git a/src/modules/get_bookings/app/get_bookings_viewmodel.py b/src/modules/get_bookings/app/get_bookings_viewmodel.py index d8ad428..fefc788 100644 --- a/src/modules/get_bookings/app/get_bookings_viewmodel.py +++ b/src/modules/get_bookings/app/get_bookings_viewmodel.py @@ -10,6 +10,9 @@ def __init__(self, bookings: list): def to_dict(self): return { - 'bookings': [booking.to_dict() for booking in self.bookings], + 'bookings': [ + {k: v for k, v in booking.to_dict().items() if k != 'user_id'} + for booking in self.bookings + ], 'message': 'the bookings were retrieved' } diff --git a/tests/modules/get_booking/app/test_get_booking_controller.py b/tests/modules/get_booking/app/test_get_booking_controller.py index 4e14d57..ef6a1d2 100644 --- a/tests/modules/get_booking/app/test_get_booking_controller.py +++ b/tests/modules/get_booking/app/test_get_booking_controller.py @@ -19,7 +19,6 @@ def test_get_booking_controller(self): assert response.body['booking']['end_date'] == 1634567400000 assert response.body['booking']['court_number'] == 2 assert response.body['booking']['sport'] == 'Football' - assert response.body['booking']['user_id'] == 'c07e0862-3c07-4227-ab0f-511a267cb7ff' assert response.body['booking']['materials'] == ['Bola', 'Chuteira'] def test_get_booking_controller_missing_booking_id(self): diff --git a/tests/modules/get_booking/app/test_get_booking_presenter.py b/tests/modules/get_booking/app/test_get_booking_presenter.py index 0c4b928..eb2f0aa 100644 --- a/tests/modules/get_booking/app/test_get_booking_presenter.py +++ b/tests/modules/get_booking/app/test_get_booking_presenter.py @@ -57,7 +57,6 @@ def test_get_booking_presenter(self): assert json.loads(response['body'])['booking']['end_date'] == 1634583365000 assert json.loads(response['body'])['booking']['court_number'] == 1 assert json.loads(response['body'])['booking']['sport'] == 'Tennis' - assert json.loads(response['body'])['booking']['user_id'] == '1f25448b-3429-4c19-8287-d9e64f17bc3a' assert json.loads(response['body'])['booking']['materials'] == ['Raquete', 'Bola', 'Rede', 'Tenis'] diff --git a/tests/modules/get_booking/app/test_get_booking_viewmodel.py b/tests/modules/get_booking/app/test_get_booking_viewmodel.py index 6cec5ef..a481248 100644 --- a/tests/modules/get_booking/app/test_get_booking_viewmodel.py +++ b/tests/modules/get_booking/app/test_get_booking_viewmodel.py @@ -16,7 +16,6 @@ def test_get_booking_viewmodel(self): 'end_date': 1634583365000, 'court_number': 1, 'sport': 'Tennis', - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] }, diff --git a/tests/modules/get_bookings/app/test_get_bookings_controller.py b/tests/modules/get_bookings/app/test_get_bookings_controller.py index 4f9f8b5..629422e 100644 --- a/tests/modules/get_bookings/app/test_get_bookings_controller.py +++ b/tests/modules/get_bookings/app/test_get_bookings_controller.py @@ -28,7 +28,6 @@ def test_get_bookings_controller(self): assert response.body['bookings'][0]['end_date'] == 1634585400000 assert response.body['bookings'][0]['court_number'] == 5 assert response.body['bookings'][0]['sport'] == 'Futsal' - assert response.body['bookings'][0]['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' assert response.body['bookings'][0]['materials'] == ['Bola', 'Chuteira'] def test_get_bookings_controller_empty_query(self): @@ -105,8 +104,8 @@ def test_get_bookings_controller_user_id(self): assert response.status_code == 200 - for booking in response.body['bookings']: - assert booking['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' + # for booking in response.body['bookings']: + # assert booking['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' def test_get_bookings_controller_start_date_error(self): @@ -167,7 +166,6 @@ def test_get_bookings_controller_five_filters(self): assert len(bookings) == 1 b = bookings[0] assert b['booking_id'] == 'b6d3bebf-dc0d-4fc1-861c-506a40cc2925' - assert b['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' assert b['sport'] == 'Futsal' assert b['court_number'] == 5 assert b['start_date'] >= int(start) and b['end_date'] <= int(end) @@ -188,7 +186,6 @@ def test_get_bookings_controller_four_filters(self): bookings = response.body['bookings'] assert len(bookings) == 1 b = bookings[0] - assert b['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' assert b['sport'] == 'Volleyball' assert b['court_number'] == 4 assert b['start_date'] >= int(start) and b['end_date'] <= int(end) @@ -207,7 +204,6 @@ def test_get_bookings_controller_three_filters(self): b = bookings[0] assert b['sport'] == 'Rugby' assert b['court_number'] == 5 - assert b['user_id'] == 'c8435c66-13a4-4641-9d54-773b4b8ccc98' def test_get_bookings_user_id_not_valid(self): request = HttpRequest(query_params={ diff --git a/tests/modules/get_bookings/app/test_get_bookings_presenter.py b/tests/modules/get_bookings/app/test_get_bookings_presenter.py index 3ba24be..9831335 100644 --- a/tests/modules/get_bookings/app/test_get_bookings_presenter.py +++ b/tests/modules/get_bookings/app/test_get_bookings_presenter.py @@ -67,7 +67,6 @@ def test_get_bookings_presenter(self): assert json.loads(response['body'])['bookings'][0]['end_date'] == 1634583365000 assert json.loads(response['body'])['bookings'][0]['court_number'] == 1 assert json.loads(response['body'])['bookings'][0]['sport'] == 'Tennis' - assert json.loads(response['body'])['bookings'][0]['user_id'] == '1f25448b-3429-4c19-8287-d9e64f17bc3a' assert json.loads(response['body'])['bookings'][0]['materials'] == ['Raquete', 'Bola', 'Rede', 'Tenis'] diff --git a/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py b/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py index c2ac5b5..b5bc7a6 100644 --- a/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py +++ b/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py @@ -16,7 +16,6 @@ def test_get_bookings_viewmodel(self): 'end_date': 1634583365000, 'court_number': 1, 'sport': 'Tennis', - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] }], From e6b4e9c01e439887f07d10062fb9f364ced6f02a Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Sat, 6 Sep 2025 00:19:24 -0300 Subject: [PATCH 116/167] fixing homl name --- .github/workflows/CD.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index b33ab12..e941ee6 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -27,7 +27,7 @@ jobs: if [[ "${{ github.ref_name }}" == "dev" ]]; then echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_DEV }}" >> $GITHUB_ENV elif [[ "${{ github.ref_name }}" == "homolog" ]]; then - echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_HOMOLOG }}" >> $GITHUB_ENV + echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_HOML }}" >> $GITHUB_ENV elif [[ "${{ github.ref_name }}" == "prod" ]]; then echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_PROD }}" >> $GITHUB_ENV else From 34e0073ad7864a8c8bde0a5cf8d98ced19f7e5bc Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 10 Sep 2025 20:00:22 -0300 Subject: [PATCH 117/167] feat(entity): adicionando o parametro type em booking --- src/shared/domain/entities/booking.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/shared/domain/entities/booking.py b/src/shared/domain/entities/booking.py index d9c78f0..27ceefa 100644 --- a/src/shared/domain/entities/booking.py +++ b/src/shared/domain/entities/booking.py @@ -3,6 +3,7 @@ from typing import Optional, List from src.shared.domain.entities.court import Court from src.shared.domain.enums.sport import SPORT +from src.shared.domain.enums.type import TYPE from src.shared.helpers.errors.domain_errors import EntityError, EntityParameterOrderDatesError class Booking(abc.ABC): @@ -13,9 +14,10 @@ class Booking(abc.ABC): user_id: str booking_id: str materials: List[str] + booking_type: TYPE - def __init__(self, start_date: int, end_date: int, court_number: int, sport: SPORT, user_id: str, booking_id: str, materials: List[str]): + def __init__(self, start_date: int, end_date: int, court_number: int, sport: SPORT, user_id: str, booking_id: str, materials: List[str], booking_type: TYPE): if not Booking.validate_dates(start_date, end_date): raise EntityError("dates") self.start_date = start_date @@ -44,6 +46,10 @@ def __init__(self, start_date: int, end_date: int, court_number: int, sport: SPO raise EntityError("materials") self.materials = materials + if not Booking.validate_type(booking_type): + raise EntityError("type") + self.booking_type = booking_type + @staticmethod def validate_dates(start_date: int, end_date: int) -> bool: @@ -95,6 +101,12 @@ def validate_materials(materials: List[str]) -> bool: return False return True + @staticmethod + def validate_type(booking_type: TYPE) -> bool: + if not isinstance(booking_type, TYPE): + return False + return True + def to_dict(self): return { "start_date": self.start_date, @@ -103,7 +115,8 @@ def to_dict(self): "sport": self.sport.value, "user_id": self.user_id, "booking_id": self.booking_id, - "materials": self.materials + "materials": self.materials, + "type": self.booking_type.value } def __eq__(self, other): From 04d72469224baad5c280e86b9495b4a9dc5c36ad Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 10 Sep 2025 20:00:49 -0300 Subject: [PATCH 118/167] feat(enum): TYPE --- src/shared/domain/enums/type.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/shared/domain/enums/type.py diff --git a/src/shared/domain/enums/type.py b/src/shared/domain/enums/type.py new file mode 100644 index 0000000..7b87051 --- /dev/null +++ b/src/shared/domain/enums/type.py @@ -0,0 +1,6 @@ +from enum import Enum + +class TYPE(Enum): + MAINTENCE = 'maintence' + TRAINING = 'training' + COMMON = 'common' From 17776eb958ff1b4bd92939d3177665a67dea62db Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 10 Sep 2025 20:03:43 -0300 Subject: [PATCH 119/167] test(entity): implementa testes unitarios para a entidade --- tests/shared/domain/entities/test_booking.py | 70 +++++++++++++++----- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/tests/shared/domain/entities/test_booking.py b/tests/shared/domain/entities/test_booking.py index d508dae..6eb56a8 100644 --- a/tests/shared/domain/entities/test_booking.py +++ b/tests/shared/domain/entities/test_booking.py @@ -2,6 +2,7 @@ from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT +from src.shared.domain.enums.type import TYPE from src.shared.helpers.errors.domain_errors import EntityError, EntityParameterOrderDatesError @@ -16,7 +17,8 @@ def test_booking(self): sport= SPORT.FOOTBALL, user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - materials= ["ball"] + materials= ["ball"], + booking_type=TYPE.TRAINING ) assert type(booking) == Booking @@ -27,6 +29,7 @@ def test_booking(self): assert booking.user_id == "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5" assert booking.booking_id == "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1" assert booking.materials == ["ball"] + assert booking.booking_type.value == 'training' def test_order_dates_incorrect(self): with pytest.raises(EntityParameterOrderDatesError): @@ -37,7 +40,8 @@ def test_order_dates_incorrect(self): sport= SPORT.FOOTBALL, user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - materials= ["ball"] + materials= ["ball"], + booking_type=TYPE.TRAINING ) def test_invalid_dates(self): @@ -49,7 +53,8 @@ def test_invalid_dates(self): sport= SPORT.FOOTBALL, user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - materials= ["ball"] + materials= ["ball"], + booking_type=TYPE.TRAINING ) def test_invalid_court_number(self): @@ -61,7 +66,8 @@ def test_invalid_court_number(self): sport= SPORT.FOOTBALL, user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - materials= ["ball"] + materials= ["ball"], + booking_type=TYPE.TRAINING ) def test_invalid_sport(self): @@ -73,7 +79,8 @@ def test_invalid_sport(self): sport= "football", user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - materials= ["ball"] + materials= ["ball"], + booking_type=TYPE.TRAINING ) def test_invalid_user_id(self): @@ -85,7 +92,8 @@ def test_invalid_user_id(self): sport= SPORT.FOOTBALL, user_id= "123", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - materials= ["ball"] + materials= ["ball"], + booking_type=TYPE.TRAINING ) def test_invalid_booking_id(self): @@ -97,7 +105,8 @@ def test_invalid_booking_id(self): sport= SPORT.FOOTBALL, user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "123", - materials= ["ball"] + materials= ["ball"], + booking_type=TYPE.TRAINING ) def test_invalid_materials(self): @@ -109,7 +118,8 @@ def test_invalid_materials(self): sport= SPORT.FOOTBALL, user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - materials= "ball" + materials= "ball", + booking_type=TYPE.TRAINING ) def test_invalid_materials2(self): @@ -121,7 +131,8 @@ def test_invalid_materials2(self): sport= SPORT.FOOTBALL, user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - materials= [1] + materials= [1], + booking_type=TYPE.TRAINING ) def test_invalid_materials3(self): @@ -133,7 +144,8 @@ def test_invalid_materials3(self): sport= SPORT.FOOTBALL, user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - materials= ["ball", 2] + materials= ["ball", 2], + booking_type=TYPE.TRAINING ) def test_booking_none_dates(self): @@ -145,7 +157,8 @@ def test_booking_none_dates(self): sport= SPORT.FOOTBALL, user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - materials= ["ball"] + materials= ["ball"], + booking_type=TYPE.TRAINING ) def test_booking_none_court_number(self): @@ -157,7 +170,8 @@ def test_booking_none_court_number(self): sport= SPORT.FOOTBALL, user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - materials= ["ball"] + materials= ["ball"], + booking_type=TYPE.TRAINING ) def test_booking_none_sport(self): @@ -169,7 +183,8 @@ def test_booking_none_sport(self): sport= None, user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - materials= ["ball"] + materials= ["ball"], + booking_type=TYPE.TRAINING ) def test_booking_none_user_id(self): @@ -181,7 +196,8 @@ def test_booking_none_user_id(self): sport= SPORT.FOOTBALL, user_id= None, booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - materials= ["ball"] + materials= ["ball"], + booking_type=TYPE.TRAINING ) def test_booking_none_booking_id(self): @@ -193,7 +209,8 @@ def test_booking_none_booking_id(self): sport= SPORT.FOOTBALL, user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= None, - materials= ["ball"] + materials= ["ball"], + booking_type=TYPE.TRAINING ) def test_booking_none_materials(self): @@ -205,9 +222,24 @@ def test_booking_none_materials(self): sport= SPORT.FOOTBALL, user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - materials= None + materials= None, + booking_type=TYPE.TRAINING ) + def test_booking_with_invalid_type(self): + + with pytest.raises(EntityError): + Booking( + start_date= 1738940138, + end_date= 1838940138, + court_number= 1, + sport= SPORT.FOOTBALL, + user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", + booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", + materials= ["ball"], + booking_type='invalid' + ) + def test_booking_to_dict(self): booking = Booking( @@ -217,7 +249,8 @@ def test_booking_to_dict(self): sport= SPORT.FOOTBALL, user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - materials= ["ball"] + materials= ["ball"], + booking_type=TYPE.MAINTENCE ) expected = { @@ -227,7 +260,8 @@ def test_booking_to_dict(self): "sport": "Football", "user_id": "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", "booking_id": "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", - "materials": ["ball"] + "materials": ["ball"], + "type": TYPE.MAINTENCE.value } assert booking.to_dict() == expected \ No newline at end of file From 40f4e927ccc7bd4e5e9d9cf824845980a7603e36 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 10 Sep 2025 21:45:47 -0300 Subject: [PATCH 120/167] fix(domain): adicionando um NA no sport e melhorando a criacao de um booking --- src/shared/domain/entities/booking.py | 4 ++++ src/shared/domain/enums/sport.py | 1 + src/shared/domain/enums/type.py | 6 +++--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/shared/domain/entities/booking.py b/src/shared/domain/entities/booking.py index 27ceefa..84c459c 100644 --- a/src/shared/domain/entities/booking.py +++ b/src/shared/domain/entities/booking.py @@ -48,6 +48,10 @@ def __init__(self, start_date: int, end_date: int, court_number: int, sport: SPO if not Booking.validate_type(booking_type): raise EntityError("type") + + if booking_type == TYPE.MAINTENCE and self.sport != SPORT.NA: + raise EntityError("sport") + self.booking_type = booking_type diff --git a/src/shared/domain/enums/sport.py b/src/shared/domain/enums/sport.py index cabb69e..a37480d 100644 --- a/src/shared/domain/enums/sport.py +++ b/src/shared/domain/enums/sport.py @@ -10,3 +10,4 @@ class SPORT(Enum): RUGBY = "Rugby" PING_PONG = "Ping Pong" BEACH_TENNIS = "Beach Tennis" + NA = "NA" diff --git a/src/shared/domain/enums/type.py b/src/shared/domain/enums/type.py index 7b87051..870971e 100644 --- a/src/shared/domain/enums/type.py +++ b/src/shared/domain/enums/type.py @@ -1,6 +1,6 @@ from enum import Enum class TYPE(Enum): - MAINTENCE = 'maintence' - TRAINING = 'training' - COMMON = 'common' + MAINTENCE = 'Maintence' + TRAINING = 'Training' + COMMON = 'Common' From e4a096d9fb13d4db4c98ac09fc8205a93150a7d0 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 10 Sep 2025 21:46:11 -0300 Subject: [PATCH 121/167] test(entity): testes da entidade booking --- tests/shared/domain/entities/test_booking.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/shared/domain/entities/test_booking.py b/tests/shared/domain/entities/test_booking.py index 6eb56a8..9f3160d 100644 --- a/tests/shared/domain/entities/test_booking.py +++ b/tests/shared/domain/entities/test_booking.py @@ -29,7 +29,7 @@ def test_booking(self): assert booking.user_id == "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5" assert booking.booking_id == "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1" assert booking.materials == ["ball"] - assert booking.booking_type.value == 'training' + assert booking.booking_type.value == 'Training' def test_order_dates_incorrect(self): with pytest.raises(EntityParameterOrderDatesError): @@ -239,6 +239,20 @@ def test_booking_with_invalid_type(self): materials= ["ball"], booking_type='invalid' ) + + def test_booking_with_maintance_invalid_sport(self): + + with pytest.raises(EntityError): + Booking( + start_date= 1738940138, + end_date= 1838940138, + court_number= 1, + sport= SPORT.TENNIS, + user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", + booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", + materials= ["ball"], + booking_type=TYPE.MAINTENCE + ) def test_booking_to_dict(self): @@ -246,7 +260,7 @@ def test_booking_to_dict(self): start_date= 1738940138, end_date= 1838940138, court_number= 1, - sport= SPORT.FOOTBALL, + sport= SPORT.NA, user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= ["ball"], @@ -257,7 +271,7 @@ def test_booking_to_dict(self): "start_date": 1738940138, "end_date": 1838940138, "court_number": 1, - "sport": "Football", + "sport": "NA", "user_id": "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", "booking_id": "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", "materials": ["ball"], From c07353cfcec1a78b54d029496e2563b7387f7fa3 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 10 Sep 2025 21:46:29 -0300 Subject: [PATCH 122/167] test(repo): testes do mock do booking --- .../shared/infra/repositories/test_booking_repository_mock.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/shared/infra/repositories/test_booking_repository_mock.py b/tests/shared/infra/repositories/test_booking_repository_mock.py index 2cb4128..9b82bdb 100644 --- a/tests/shared/infra/repositories/test_booking_repository_mock.py +++ b/tests/shared/infra/repositories/test_booking_repository_mock.py @@ -1,3 +1,4 @@ +from src.shared.domain.enums.type import TYPE from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock from src.shared.domain.enums.sport import SPORT from src.shared.domain.entities.booking import Booking @@ -6,7 +7,7 @@ class TestBookingRepositoryMock: def test_create_booking(self): repo_mock = BookingRepositoryMock() - new_booking = Booking(start_date=1634576165000, end_date=1634583365000, court_number=1,sport=SPORT.TENNIS, user_id='c8435c66-13a4-4641-9d54-773b4b8ccd09', booking_id='c2d3bebf-dc0d-4fc1-861c-506a40cc2036', materials=['Raquete', 'Bola', 'Rede', 'Tenis']) + new_booking = Booking(start_date=1634576165000, end_date=1634583365000, court_number=1,sport=SPORT.TENNIS, user_id='c8435c66-13a4-4641-9d54-773b4b8ccd09', booking_id='c2d3bebf-dc0d-4fc1-861c-506a40cc2036', materials=['Raquete', 'Bola', 'Rede', 'Tenis'], booking_type=TYPE.TRAINING) len_before = len(repo_mock.bookings) response = repo_mock.create_booking(new_booking) From 29495febeba9d3e1f057f4c22bb5968ffe97b588 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 10 Sep 2025 21:47:21 -0300 Subject: [PATCH 123/167] test(repo): testes do repositorio mock --- .../repositories/booking_repository_mock.py | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/shared/infra/repositories/booking_repository_mock.py b/src/shared/infra/repositories/booking_repository_mock.py index 77e0b65..5d3bf79 100644 --- a/src/shared/infra/repositories/booking_repository_mock.py +++ b/src/shared/infra/repositories/booking_repository_mock.py @@ -1,6 +1,7 @@ from typing import List, Optional from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT +from src.shared.domain.enums.type import TYPE from src.shared.domain.repositories.booking_repository_interface import IBookingRepository from src.shared.helpers.errors.usecase_errors import ForbiddenAction @@ -17,7 +18,8 @@ def __init__(self): sport=SPORT.TENNIS, user_id='1f25448b-3429-4c19-8287-d9e64f17bc3a', booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', - materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + materials=['Raquete', 'Bola', 'Rede', 'Tenis'], + booking_type=TYPE.TRAINING ), Booking( @@ -27,7 +29,8 @@ def __init__(self): sport=SPORT.FOOTBALL, user_id='c07e0862-3c07-4227-ab0f-511a267cb7ff', booking_id='b2d3bebf-dc0d-4fc1-861c-506a40cc2925', - materials=['Bola', 'Chuteira'] + materials=['Bola', 'Chuteira'], + booking_type=TYPE.TRAINING ), Booking( @@ -37,7 +40,8 @@ def __init__(self): sport=SPORT.BASKETBALL, user_id='d351a9b1-937f-423c-a9d1-9929b5795be1', booking_id='b3d3bebf-dc0d-4fc1-861c-506a40cc2925', - materials=['Bola'] + materials=['Bola'], + booking_type=TYPE.COMMON ), Booking( @@ -47,7 +51,8 @@ def __init__(self): sport=SPORT.VOLLEYBALL, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b4d3bebf-dc0d-4fc1-861c-506a40cc2925', - materials=['Bola', 'Rede'] + materials=['Bola', 'Rede'], + booking_type=TYPE.COMMON ), Booking( @@ -57,7 +62,8 @@ def __init__(self): sport=SPORT.HANDBALL, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b5d3bebf-dc0d-4fc1-861c-506a40cc2925', - materials=['Bola'] + materials=['Bola'], + booking_type=TYPE.TRAINING ), Booking( @@ -67,7 +73,8 @@ def __init__(self): sport=SPORT.FUTSAL, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b6d3bebf-dc0d-4fc1-861c-506a40cc2925', - materials=['Bola', 'Chuteira'] + materials=['Bola', 'Chuteira'], + booking_type=TYPE.TRAINING ), Booking( @@ -77,7 +84,8 @@ def __init__(self): sport=SPORT.RUGBY, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b7d3bebf-dc0d-4fc1-861c-506a40cc2925', - materials=['Bola', 'Tenis', 'Capacete'] + materials=['Bola', 'Tenis', 'Capacete'], + booking_type=TYPE.TRAINING ), Booking( @@ -87,7 +95,8 @@ def __init__(self): sport=SPORT.PING_PONG, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b8d3bebf-dc0d-4fc1-861c-506a40cc2925', - materials=['Raquete', 'Bola'] + materials=['Raquete', 'Bola'], + booking_type=TYPE.TRAINING ), ] From ed24b509f0a1390e4e939f84a2867e6232d2a7d6 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 10 Sep 2025 21:47:54 -0300 Subject: [PATCH 124/167] feat(modules): adicionando novo campo nas rotas --- .../create_booking/app/create_booking_controller.py | 13 ++++++++++++- .../create_booking/app/create_booking_usecase.py | 8 ++++++-- .../create_booking/app/create_booking_viewmodel.py | 4 +++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/modules/create_booking/app/create_booking_controller.py b/src/modules/create_booking/app/create_booking_controller.py index b3dad81..5902b30 100644 --- a/src/modules/create_booking/app/create_booking_controller.py +++ b/src/modules/create_booking/app/create_booking_controller.py @@ -1,5 +1,7 @@ import json +from src.shared.domain.enums.type import TYPE + from .create_booking_usecase import CreateBookingUsecase from .create_booking_viewmodel import CreateBookingViewmodel from src.shared.helpers.errors.controller_errors import MissingParameters, WrongTypeParameter, AuthorizerError @@ -31,6 +33,7 @@ def __call__(self, request: IRequest): sport = request.data.get('sport', None) user_id = user_from_authorizer.get('user_id', None) materials = request.data.get('materials', None) + booking_type = request.data.get('type', None) try: @@ -75,6 +78,13 @@ def __call__(self, request: IRequest): raise WrongTypeParameter(fieldName='materials', fieldTypeExpected='list', fieldTypeReceived=type(materials).__name__) + + if booking_type is None: + raise MissingParameters('type') + if not isinstance(booking_type, str): + raise WrongTypeParameter(fieldName='type', + fieldTypeExpected='str', + fieldTypeReceived=type(booking_type).__name__) booking = self.create_booking_use_case( start_date=start_date, @@ -82,7 +92,8 @@ def __call__(self, request: IRequest): court_number=court_number, sport=sport, user_id=user_id, - materials=materials + materials=materials, + booking_type=TYPE(booking_type) ) viewmodel = CreateBookingViewmodel(booking=booking) diff --git a/src/modules/create_booking/app/create_booking_usecase.py b/src/modules/create_booking/app/create_booking_usecase.py index 0d2bdf7..167a279 100644 --- a/src/modules/create_booking/app/create_booking_usecase.py +++ b/src/modules/create_booking/app/create_booking_usecase.py @@ -3,6 +3,7 @@ from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT +from src.shared.domain.enums.type import TYPE from src.shared.domain.repositories.booking_repository_interface import IBookingRepository from src.shared.helpers.errors.usecase_errors import DuplicatedItem, InvalidSchedule @@ -15,6 +16,7 @@ class CreateBookingUsecase: user_id: str booking_id: str materials: List[str] + booking_type: TYPE def __init__(self, repo: IBookingRepository): self.repo = repo @@ -25,7 +27,8 @@ def __call__(self, court_number: int, sport: str, user_id: str, - materials: List[str] + materials: List[str], + booking_type: TYPE ) -> Booking: booking_id = str(uuid.uuid4()) @@ -60,7 +63,8 @@ def __call__(self, self.sport, user_id, booking_id, - materials)) + materials, + booking_type)) return resp diff --git a/src/modules/create_booking/app/create_booking_viewmodel.py b/src/modules/create_booking/app/create_booking_viewmodel.py index b91e23a..83cada4 100644 --- a/src/modules/create_booking/app/create_booking_viewmodel.py +++ b/src/modules/create_booking/app/create_booking_viewmodel.py @@ -21,6 +21,7 @@ def __init__(self, booking): self.user_id = booking.user_id self.booking_id = booking.booking_id self.materials = booking.materials + self.booking_type = booking.booking_type def to_dict(self): @@ -32,7 +33,8 @@ def to_dict(self): "sport": self.sport.value, "user_id": self.user_id, "booking_id": self.booking_id, - "materials": self.materials + "materials": self.materials, + "type": self.booking_type.value }, "message": "Booking created successfully" } From efc2b662c0eccde97cd8cbfbcbedcca985e937b4 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 10 Sep 2025 21:48:17 -0300 Subject: [PATCH 125/167] test(modules): testando novo campo na rota create_booking --- .../app/test_create_booking_controller.py | 6 +++-- .../app/test_create_booking_presenter.py | 2 +- .../app/test_create_booking_usecase.py | 26 +++++++++++++------ .../app/test_create_booking_viewmodel.py | 7 +++-- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/tests/modules/create_booking/app/test_create_booking_controller.py b/tests/modules/create_booking/app/test_create_booking_controller.py index 046104c..610992c 100644 --- a/tests/modules/create_booking/app/test_create_booking_controller.py +++ b/tests/modules/create_booking/app/test_create_booking_controller.py @@ -17,7 +17,8 @@ def test_create_booking_controller(self): "end_date": 1630003600, "court_number": 1, "sport": "Tennis", - "materials": ["racket", "balls"] + "materials": ["racket", "balls"], + "type": "Training" }, headers={ "user_from_authorizer": { @@ -279,7 +280,8 @@ def test_create_booking_controller_wrong_type_inside_list(self): "end_date": 1630003600, "court_number": 1, "sport": "Tennis", - "materials": ["racket", 1] + "materials": ["racket", 1], + "type": 'Common' }, headers={ "user_from_authorizer": { "displayName": 'Lebron James', diff --git a/tests/modules/create_booking/app/test_create_booking_presenter.py b/tests/modules/create_booking/app/test_create_booking_presenter.py index fbaab8e..495b807 100644 --- a/tests/modules/create_booking/app/test_create_booking_presenter.py +++ b/tests/modules/create_booking/app/test_create_booking_presenter.py @@ -50,7 +50,7 @@ def test_create_booking_presenter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": '{"start_date": 1610617200, "end_date": 1610620800, "court_number": 1, "sport": "Tennis", "materials": ["ball", "racket"]}', + "body": {'start_date': 1610617200, 'end_date': 1610620800, 'court_number': 1, 'sport': 'Tennis', 'materials': ['ball', 'racket'], 'type': 'Common'}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None diff --git a/tests/modules/create_booking/app/test_create_booking_usecase.py b/tests/modules/create_booking/app/test_create_booking_usecase.py index 3d79879..143608f 100644 --- a/tests/modules/create_booking/app/test_create_booking_usecase.py +++ b/tests/modules/create_booking/app/test_create_booking_usecase.py @@ -3,6 +3,7 @@ from src.modules.create_booking.app.create_booking_usecase import CreateBookingUsecase from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT +from src.shared.domain.enums.type import TYPE from src.shared.helpers.errors.usecase_errors import InvalidSchedule from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock @@ -18,7 +19,8 @@ def test_create_booking_usecase(self): sport=SPORT.TENNIS, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=['Raquete', 'Bola', 'Rede', 'Tenis'], - booking_id='c8435c66-13a4-4641-9d54-773b4b8ccc98' + booking_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', + booking_type=TYPE.TRAINING ) booking_repository = BookingRepositoryMock() @@ -31,7 +33,8 @@ def test_create_booking_usecase(self): court_number=1, sport="Tennis", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', - materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + materials=['Raquete', 'Bola', 'Rede', 'Tenis'], + booking_type=TYPE.TRAINING ) assert response is not None @@ -41,6 +44,7 @@ def test_create_booking_usecase(self): assert response.sport == booking.sport assert response.user_id == booking.user_id assert response.booking_id != booking.booking_id + assert response.booking_type == booking.booking_type def test_create_booking_usecase_invalid_sport(self): @@ -56,7 +60,8 @@ def test_create_booking_usecase_invalid_sport(self): court_number=1, sport="Invalid sport but string", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', - materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + materials=['Raquete', 'Bola', 'Rede', 'Tenis'], + booking_type=TYPE.TRAINING ) def test_create_booking_usecase_invalid_materials(self): @@ -73,7 +78,8 @@ def test_create_booking_usecase_invalid_materials(self): court_number=1, sport="Tennis", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', - materials=[1, 2, 3] + materials=[1, 2, 3], + booking_type=TYPE.TRAINING ) def test_create_booking_usecase_invalid_schedule_overlap(self): @@ -90,7 +96,8 @@ def test_create_booking_usecase_invalid_schedule_overlap(self): court_number=1, sport="Tennis", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', - materials=["colete"] + materials=["colete"], + booking_type=TYPE.TRAINING ) assert e.value == "Court is already booked for the selected time slot or has to have 15 min tolerance" @@ -112,7 +119,8 @@ def test_create_booking_usecase_invalid_schedule_15min(self): sport=SPORT.FUTSAL, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=['Bola', 'Chuteira'], - booking_id='ddd35c66-13a4-4641-9d54-773b4b8ccc98' + booking_id='ddd35c66-13a4-4641-9d54-773b4b8ccc98', + booking_type=TYPE.TRAINING ) ) @@ -122,7 +130,8 @@ def test_create_booking_usecase_invalid_schedule_15min(self): court_number=5, sport=SPORT.FUTSAL, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', - materials=['Bola', 'Chuteira'] + materials=['Bola', 'Chuteira'], + booking_type=TYPE.TRAINING ) assert e.value == "Court is already booked for the selected time slot or has to have 15 min tolerance" @@ -136,7 +145,8 @@ def test_create_booking_usecase_invalid_schedule_15min(self): court_number=5, sport=SPORT.FUTSAL, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', - materials=['Bola', 'Chuteira'] + materials=['Bola', 'Chuteira'], + booking_type=TYPE.TRAINING ) assert e2.value == "Court is already booked for the selected time slot or has to have 15 min tolerance" diff --git a/tests/modules/create_booking/app/test_create_booking_viewmodel.py b/tests/modules/create_booking/app/test_create_booking_viewmodel.py index 9783677..aee1cb4 100644 --- a/tests/modules/create_booking/app/test_create_booking_viewmodel.py +++ b/tests/modules/create_booking/app/test_create_booking_viewmodel.py @@ -1,6 +1,7 @@ from src.modules.create_booking.app.create_booking_viewmodel import CreateBookingViewmodel from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT +from src.shared.domain.enums.type import TYPE class TestCreateBookingViewmodel: @@ -14,7 +15,8 @@ def test_create_booking_viewmodel(self): sport=SPORT.TENNIS, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', - materials=['Raquete', 'Bola', 'Rede', 'Tenis'] + materials=['Raquete', 'Bola', 'Rede', 'Tenis'], + booking_type=TYPE.TRAINING ) expected = { @@ -25,7 +27,8 @@ def test_create_booking_viewmodel(self): "sport": "Tennis", "user_id": "c8435c66-13a4-4641-9d54-773b4b8ccc98", "booking_id": "b1d3bebf-dc0d-4fc1-861c-506a40cc2925", - "materials": ["Raquete", "Bola", "Rede", "Tenis"] + "materials": ["Raquete", "Bola", "Rede", "Tenis"], + "type": 'Training' }, "message": "Booking created successfully" } From 168e202bd98ce3476b82965ac44b374615123b41 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 15 Sep 2025 19:07:31 -0300 Subject: [PATCH 126/167] refat(booking): refatoramento geral: - rotas que utilizavam a entidade booking - DTO - interface, mock e repositorio dynamo --- .../app/create_booking_controller.py | 4 +- .../app/create_booking_usecase.py | 6 +- .../app/delete_booking_viewmodel.py | 4 +- .../app/get_all_bookings_viewmodel.py | 4 +- .../get_booking/app/get_booking_viewmodel.py | 4 +- .../app/get_bookings_controller.py | 5 +- .../get_bookings/app/get_bookings_usecase.py | 11 +- .../app/update_booking_controller.py | 15 +- .../app/update_booking_usecase.py | 11 +- .../app/update_booking_viewmodel.py | 10 +- src/shared/domain/entities/booking.py | 14 +- src/shared/domain/enums/type.py | 2 +- .../booking_repository_interface.py | 9 +- src/shared/infra/dto/booking_dynamo_dto.py | 19 ++- .../repositories/booking_repository_dynamo.py | 12 +- .../repositories/booking_repository_mock.py | 27 ++-- .../app/test_create_booking_usecase.py | 18 +-- .../app/test_create_booking_viewmodel.py | 4 +- .../app/test_delete_booking_viewmodel.py | 3 +- .../app/test_get_all_bookings_viewmodel.py | 135 ++++++++++++------ .../app/test_get_booking_viewmodel.py | 3 +- .../app/test_get_bookings_viewmodel.py | 3 +- .../app/test_update_booking_viewmodel.py | 7 +- tests/shared/domain/entities/test_booking.py | 40 +++--- .../test_booking_repository_mock.py | 4 +- 25 files changed, 239 insertions(+), 135 deletions(-) diff --git a/src/modules/create_booking/app/create_booking_controller.py b/src/modules/create_booking/app/create_booking_controller.py index 5902b30..4d99dd3 100644 --- a/src/modules/create_booking/app/create_booking_controller.py +++ b/src/modules/create_booking/app/create_booking_controller.py @@ -1,6 +1,6 @@ import json -from src.shared.domain.enums.type import TYPE +from src.shared.domain.enums.type import BOOKING_TYPE from .create_booking_usecase import CreateBookingUsecase from .create_booking_viewmodel import CreateBookingViewmodel @@ -93,7 +93,7 @@ def __call__(self, request: IRequest): sport=sport, user_id=user_id, materials=materials, - booking_type=TYPE(booking_type) + booking_type=BOOKING_TYPE(booking_type) ) viewmodel = CreateBookingViewmodel(booking=booking) diff --git a/src/modules/create_booking/app/create_booking_usecase.py b/src/modules/create_booking/app/create_booking_usecase.py index 167a279..6933cd8 100644 --- a/src/modules/create_booking/app/create_booking_usecase.py +++ b/src/modules/create_booking/app/create_booking_usecase.py @@ -3,7 +3,7 @@ from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT -from src.shared.domain.enums.type import TYPE +from src.shared.domain.enums.type import BOOKING_TYPE from src.shared.domain.repositories.booking_repository_interface import IBookingRepository from src.shared.helpers.errors.usecase_errors import DuplicatedItem, InvalidSchedule @@ -16,7 +16,7 @@ class CreateBookingUsecase: user_id: str booking_id: str materials: List[str] - booking_type: TYPE + booking_type: BOOKING_TYPE def __init__(self, repo: IBookingRepository): self.repo = repo @@ -28,7 +28,7 @@ def __call__(self, sport: str, user_id: str, materials: List[str], - booking_type: TYPE + booking_type: BOOKING_TYPE ) -> Booking: booking_id = str(uuid.uuid4()) diff --git a/src/modules/delete_booking/app/delete_booking_viewmodel.py b/src/modules/delete_booking/app/delete_booking_viewmodel.py index eddbcd4..309192c 100644 --- a/src/modules/delete_booking/app/delete_booking_viewmodel.py +++ b/src/modules/delete_booking/app/delete_booking_viewmodel.py @@ -20,6 +20,7 @@ def __init__(self, booking: Booking): self.user_id = booking.user_id self.booking_id = booking.booking_id self.materials = booking.materials + self.booking_type = booking.booking_type def to_dict(self): return { @@ -29,7 +30,8 @@ def to_dict(self): 'sport': self.sport.value, 'user_id': self.user_id, 'booking_id': self.booking_id, - 'materials': self.materials + 'materials': self.materials, + 'type': self.booking_type.value } class DeleteBookingViewModel: diff --git a/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py b/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py index 963e786..b111a79 100644 --- a/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py +++ b/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py @@ -19,6 +19,7 @@ def __init__(self, booking: Booking): self.user_id = booking.user_id self.booking_id = booking.booking_id self.materials = booking.materials + self.booking_type = booking.booking_type def to_dict(self): return { @@ -28,7 +29,8 @@ def to_dict(self): 'sport': self.sport.value, 'user_id': self.user_id, 'booking_id': self.booking_id, - 'materials': self.materials + 'materials': self.materials, + "type": self.booking_type.value } class GetBookingViewModel: booking: Booking diff --git a/src/modules/get_booking/app/get_booking_viewmodel.py b/src/modules/get_booking/app/get_booking_viewmodel.py index 484e7d5..6a5969b 100644 --- a/src/modules/get_booking/app/get_booking_viewmodel.py +++ b/src/modules/get_booking/app/get_booking_viewmodel.py @@ -18,6 +18,7 @@ def __init__(self, booking: Booking): self.user_id = booking.user_id self.booking_id = booking.booking_id self.materials = booking.materials + self.booking_type = booking.booking_type def to_dict(self): return { @@ -27,7 +28,8 @@ def to_dict(self): 'sport': self.sport.value, 'user_id': self.user_id, 'booking_id': self.booking_id, - 'materials': self.materials + 'materials': self.materials, + "type": self.booking_type.value } class GetBookingViewmodel: diff --git a/src/modules/get_bookings/app/get_bookings_controller.py b/src/modules/get_bookings/app/get_bookings_controller.py index 5715e8d..371a18b 100644 --- a/src/modules/get_bookings/app/get_bookings_controller.py +++ b/src/modules/get_bookings/app/get_bookings_controller.py @@ -23,6 +23,7 @@ def __call__(self, request: IRequest): court_number = request.data.get('court_number', None) end_date = request.data.get('end_date', None) start_date = request.data.get('start_date', None) + booking_type = request.data.get('type', None) booking_id = booking_id if booking_id != "" else None user_id = user_id if user_id != "" else None @@ -30,6 +31,7 @@ def __call__(self, request: IRequest): court_number = court_number if court_number != "" else None end_date = end_date if end_date != "" else None start_date = start_date if start_date != "" else None + booking_type = booking_type if booking_type != "" else None if not booking_id and not user_id and not sport and not court_number and not end_date and not start_date: raise EmptyQueryParameters( @@ -65,7 +67,8 @@ def __call__(self, request: IRequest): sport=sport, court_number=court_number, end_date=end_date, - start_date=start_date + start_date=start_date, + booking_type=booking_type ) booking_viewmodel = GetBookingsViewmodel(booking) return OK(booking_viewmodel.to_dict()) diff --git a/src/modules/get_bookings/app/get_bookings_usecase.py b/src/modules/get_bookings/app/get_bookings_usecase.py index 614b675..8b1e0bf 100644 --- a/src/modules/get_bookings/app/get_bookings_usecase.py +++ b/src/modules/get_bookings/app/get_bookings_usecase.py @@ -2,6 +2,7 @@ from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT +from src.shared.domain.enums.type import BOOKING_TYPE from src.shared.domain.repositories.booking_repository_interface import IBookingRepository from src.shared.helpers.errors.domain_errors import EntityError from src.shared.helpers.errors.usecase_errors import NoItemsFound, DependantFilter @@ -18,7 +19,8 @@ def __call__(self, sport: Optional[str] = None, court_number: Optional[int] = None, end_date: Optional[int] = None, - start_date: Optional[int] = None): + start_date: Optional[int] = None, + booking_type: Optional[str] = None): if booking_id: if not Booking.validate_booking_id(booking_id): @@ -39,13 +41,18 @@ def __call__(self, if (start_date and not end_date) or (end_date and not start_date): raise DependantFilter('start_date and end_date') + if booking_type: + if not Booking.validate_booking_type(BOOKING_TYPE(booking_type)): + raise EntityError('type') + bookings = self.repo.get_bookings( booking_id=booking_id if booking_id else None, user_id=user_id if user_id else None, sport=SPORT(sport) if sport else None, court_number=court_number if court_number else None, end_date=end_date if end_date else None, - start_date=start_date if start_date else None) + start_date=start_date if start_date else None, + booking_type=booking_type) if bookings is None or bookings == []: raise NoItemsFound('booking filters passed') diff --git a/src/modules/update_booking/app/update_booking_controller.py b/src/modules/update_booking/app/update_booking_controller.py index 448f1ae..1ccdf8d 100644 --- a/src/modules/update_booking/app/update_booking_controller.py +++ b/src/modules/update_booking/app/update_booking_controller.py @@ -1,3 +1,4 @@ +from src.shared.domain.enums.type import BOOKING_TYPE from .update_booking_usecase import UpdateBookingUsecase from .update_booking_viewmodel import UpdateBookingViewmodel from src.shared.domain.enums.sport import SPORT @@ -25,6 +26,7 @@ def __call__(self, request: IRequest) -> IResponse: court_number = request.data.get('court_number') sport_value = request.data.get('sport') materials = request.data.get('materials') + booking_type = request.data.get('type') user = request.data.get('user_from_authorizer') if not isinstance(booking_id, str): @@ -48,7 +50,15 @@ def __call__(self, request: IRequest) -> IResponse: raise EntityError('sport') sport = SPORT(sport_value) - + + if booking_type is not None: + if not isinstance(booking_type, str): + raise WrongTypeParameter('type', 'str', type(booking_type).__name__) + if booking_type not in [type.value for type in BOOKING_TYPE]: + raise EntityError('type') + + booking_type = BOOKING_TYPE(booking_type) + if materials is not None and not isinstance(materials, list): raise WrongTypeParameter('materials', 'list', type(materials).__name__) @@ -61,7 +71,8 @@ def __call__(self, request: IRequest) -> IResponse: end_date=end_date, court_number=court_number, sport=sport, - materials=materials + materials=materials, + booking_type=booking_type ) viewmodel = UpdateBookingViewmodel(booking=booking) diff --git a/src/modules/update_booking/app/update_booking_usecase.py b/src/modules/update_booking/app/update_booking_usecase.py index 35fd7ce..1a5cfda 100644 --- a/src/modules/update_booking/app/update_booking_usecase.py +++ b/src/modules/update_booking/app/update_booking_usecase.py @@ -1,6 +1,7 @@ from typing import List from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT +from src.shared.domain.enums.type import BOOKING_TYPE from src.shared.domain.repositories.booking_repository_interface import IBookingRepository from src.shared.helpers.errors.domain_errors import EntityError, EntityParameterOrderDatesError from src.shared.helpers.errors.usecase_errors import ForbiddenAction, NoItemsFound, InvalidSchedule @@ -17,7 +18,8 @@ def __call__(self, court_number: int = None, sport: SPORT = None, materials: List[str] = None, - new_user_id: str = None): + new_user_id: str = None, + booking_type: BOOKING_TYPE = None): user_id = user.get('user_id') user_role = user.get('role') @@ -40,6 +42,7 @@ def __call__(self, court_number = court_number if court_number is not None else existing_booking.court_number sport = sport if sport is not None else existing_booking.sport materials = materials if materials is not None else existing_booking.materials + booking_type = booking_type if booking_type is not None else existing_booking.booking_type if Booking.validate_dates(start_date, end_date) is False: raise EntityError("date") @@ -56,6 +59,9 @@ def __call__(self, if Booking.validate_materials(materials) is False: raise EntityError("materials") + if Booking.validate_booking_type(booking_type) is False: + raise EntityError("type") + all_bookings = self.booking_repo.get_all_bookings() for booking in all_bookings: @@ -77,7 +83,8 @@ def __call__(self, end_date=end_date, court_number=court_number, sport=sport, - materials=materials + materials=materials, + booking_type=booking_type ) if booking.user_id != existing_booking.user_id: diff --git a/src/modules/update_booking/app/update_booking_viewmodel.py b/src/modules/update_booking/app/update_booking_viewmodel.py index e86874a..137a88c 100644 --- a/src/modules/update_booking/app/update_booking_viewmodel.py +++ b/src/modules/update_booking/app/update_booking_viewmodel.py @@ -4,13 +4,6 @@ class BookingViewmodel: - start_date: int - end_date: int - court_number: int - sport: SPORT - user_id: str - booking_id: str - materials: List[str] def __init__(self, booking: Booking): self.booking = booking @@ -23,7 +16,8 @@ def to_dict(self) -> Booking: 'sport': self.booking.sport.value, 'user_id': self.booking.user_id, 'booking_id': self.booking.booking_id, - 'materials': self.booking.materials + 'materials': self.booking.materials, + 'type': self.booking.booking_type.value } class UpdateBookingViewmodel: diff --git a/src/shared/domain/entities/booking.py b/src/shared/domain/entities/booking.py index 84c459c..d517c67 100644 --- a/src/shared/domain/entities/booking.py +++ b/src/shared/domain/entities/booking.py @@ -3,7 +3,7 @@ from typing import Optional, List from src.shared.domain.entities.court import Court from src.shared.domain.enums.sport import SPORT -from src.shared.domain.enums.type import TYPE +from src.shared.domain.enums.type import BOOKING_TYPE from src.shared.helpers.errors.domain_errors import EntityError, EntityParameterOrderDatesError class Booking(abc.ABC): @@ -14,10 +14,10 @@ class Booking(abc.ABC): user_id: str booking_id: str materials: List[str] - booking_type: TYPE + booking_type: BOOKING_TYPE - def __init__(self, start_date: int, end_date: int, court_number: int, sport: SPORT, user_id: str, booking_id: str, materials: List[str], booking_type: TYPE): + def __init__(self, start_date: int, end_date: int, court_number: int, sport: SPORT, user_id: str, booking_id: str, materials: List[str], booking_type: BOOKING_TYPE): if not Booking.validate_dates(start_date, end_date): raise EntityError("dates") self.start_date = start_date @@ -46,10 +46,10 @@ def __init__(self, start_date: int, end_date: int, court_number: int, sport: SPO raise EntityError("materials") self.materials = materials - if not Booking.validate_type(booking_type): + if not Booking.validate_booking_type(booking_type): raise EntityError("type") - if booking_type == TYPE.MAINTENCE and self.sport != SPORT.NA: + if booking_type == BOOKING_TYPE.MAINTENCE and self.sport != SPORT.NA: raise EntityError("sport") self.booking_type = booking_type @@ -106,8 +106,8 @@ def validate_materials(materials: List[str]) -> bool: return True @staticmethod - def validate_type(booking_type: TYPE) -> bool: - if not isinstance(booking_type, TYPE): + def validate_booking_type(booking_type: BOOKING_TYPE) -> bool: + if not isinstance(booking_type, BOOKING_TYPE): return False return True diff --git a/src/shared/domain/enums/type.py b/src/shared/domain/enums/type.py index 870971e..ef8b9e9 100644 --- a/src/shared/domain/enums/type.py +++ b/src/shared/domain/enums/type.py @@ -1,6 +1,6 @@ from enum import Enum -class TYPE(Enum): +class BOOKING_TYPE(Enum): MAINTENCE = 'Maintence' TRAINING = 'Training' COMMON = 'Common' diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index 83ac220..180d63e 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -4,6 +4,7 @@ from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT +from src.shared.domain.enums.type import BOOKING_TYPE class IBookingRepository(ABC): @@ -25,7 +26,8 @@ def update_booking(self, end_date: int = None, court_number: int = None, sport: SPORT = None, - materials: List[str] = None) -> Optional[Booking]: + materials: List[str] = None, + booking_type: BOOKING_TYPE = None) -> Optional[Booking]: ''' If booking exists, updates it and returns it @@ -44,10 +46,11 @@ def get_booking(self, booking_id: str) -> Optional[Booking]: def get_bookings(self, booking_id: Optional[str] = None, user_id: Optional[str] = None, - sport: Optional[SPORT] = None, + sport: Optional[str] = None, court_number: Optional[int] = None, end_date: Optional[int] = None, - start_date: Optional[int] = None) -> List[Optional[Booking]]: + start_date: Optional[int] = None, + booking_type: Optional[str] = None) -> List[Optional[Booking]]: ''' If the booking exists, returns it, else returns None ''' diff --git a/src/shared/infra/dto/booking_dynamo_dto.py b/src/shared/infra/dto/booking_dynamo_dto.py index 6f59019..01bb8a8 100644 --- a/src/shared/infra/dto/booking_dynamo_dto.py +++ b/src/shared/infra/dto/booking_dynamo_dto.py @@ -2,6 +2,7 @@ from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT +from src.shared.domain.enums.type import BOOKING_TYPE class BookingDynamoDTO: @@ -12,8 +13,9 @@ class BookingDynamoDTO: user_id: str booking_id: str materials: List[str] + booking_type: BOOKING_TYPE - def __init__(self, start_date: int, end_date: int, court_number: int, sport: SPORT, user_id: str, booking_id: str, materials: List[str]): + def __init__(self, start_date: int, end_date: int, court_number: int, sport: SPORT, user_id: str, booking_id: str, materials: List[str], booking_type: BOOKING_TYPE): self.start_date = start_date self.end_date = end_date self.court_number = court_number @@ -21,6 +23,7 @@ def __init__(self, start_date: int, end_date: int, court_number: int, sport: SPO self.user_id = user_id self.booking_id = booking_id self.materials = materials + self.booking_type = booking_type @staticmethod def from_entity(booking: Booking) -> 'BookingDynamoDTO': @@ -34,7 +37,8 @@ def from_entity(booking: Booking) -> 'BookingDynamoDTO': sport = booking.sport, user_id = booking.user_id, booking_id = booking.booking_id, - materials = booking.materials + materials = booking.materials, + booking_type= booking.booking_type ) def to_dynamo(self) -> dict: @@ -49,7 +53,8 @@ def to_dynamo(self) -> dict: "sport": self.sport.value, "user_id": self.user_id, "booking_id": self.booking_id, - "materials": self.materials or [] + "materials": self.materials or [], + "booking_type": self.booking_type.value } booking_without_none_values = {k: v for k, v in data.items() if v is not None} @@ -68,7 +73,8 @@ def from_dynamo(booking_data: dict) -> "BookingDynamoDTO": sport = SPORT(booking_data["sport"]), user_id = booking_data["user_id"], booking_id = booking_data["booking_id"], - materials = booking_data.get("materials") or [] + materials = booking_data.get("materials") or [], + booking_type= booking_data["booking_type"] ) def to_entity(self) -> Booking: @@ -82,11 +88,12 @@ def to_entity(self) -> Booking: sport=self.sport, user_id=self.user_id, booking_id=self.booking_id, - materials=self.materials + materials=self.materials, + booking_type=self.booking_type ) def __repr__(self): - return f"BookingDynamoDTO(start_date={self.start_date}, end_date={self.end_date}, court_number={self.court_number}, sport={self.sport}, user_id={self.user_id}, booking_id={self.booking_id}, materials={self.materials})" + return f"BookingDynamoDTO(start_date={self.start_date}, end_date={self.end_date}, court_number={self.court_number}, sport={self.sport.value}, user_id={self.user_id}, booking_id={self.booking_id}, materials={self.materials}, booking_type={self.booking_type.value})" def __eq__(self, other): return self.__dict__ == other.__dict__ diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index 8c75783..1bb422e 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -6,6 +6,7 @@ from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT +from src.shared.domain.enums.type import BOOKING_TYPE from src.shared.domain.repositories.booking_repository_interface import IBookingRepository from src.shared.environments import Environments from src.shared.helpers.errors.usecase_errors import ForbiddenAction @@ -52,7 +53,8 @@ def update_booking(self, end_date: int = None, court_number: int = None, sport: SPORT = None, - materials: List[str] = None) -> Optional[Booking]: + materials: List[str] = None, + booking_type: BOOKING_TYPE = None) -> Optional[Booking]: booking_to_update = self.get_booking(booking_id) @@ -66,7 +68,8 @@ def update_booking(self, "sport": sport.value if sport is not None else booking_to_update.sport.value, "materials": materials if materials is not None else booking_to_update.materials, "user_id": booking_to_update.user_id, - "booking_id": booking_to_update.booking_id + "booking_id": booking_to_update.booking_id, + "booking_type": booking_type.value if booking_type is not None else booking_to_update.booking_type.value } resp = self.dynamo.update_item(update_dict=update_dict, @@ -81,10 +84,11 @@ def update_booking(self, def get_bookings(self, booking_id: Optional[str] = None, user_id: Optional[str] = None, - sport: Optional[SPORT] = None, + sport: Optional[str] = None, court_number: Optional[int] = None, end_date: Optional[int] = None, - start_date: Optional[int] = None) -> List[Optional[Booking]]: + start_date: Optional[int] = None, + booking_type: Optional[str] = None) -> List[Optional[Booking]]: filters = locals().copy() filters.pop('self') diff --git a/src/shared/infra/repositories/booking_repository_mock.py b/src/shared/infra/repositories/booking_repository_mock.py index 5d3bf79..1f75237 100644 --- a/src/shared/infra/repositories/booking_repository_mock.py +++ b/src/shared/infra/repositories/booking_repository_mock.py @@ -1,7 +1,7 @@ from typing import List, Optional from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT -from src.shared.domain.enums.type import TYPE +from src.shared.domain.enums.type import BOOKING_TYPE from src.shared.domain.repositories.booking_repository_interface import IBookingRepository from src.shared.helpers.errors.usecase_errors import ForbiddenAction @@ -19,7 +19,7 @@ def __init__(self): user_id='1f25448b-3429-4c19-8287-d9e64f17bc3a', booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Raquete', 'Bola', 'Rede', 'Tenis'], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ), Booking( @@ -30,7 +30,7 @@ def __init__(self): user_id='c07e0862-3c07-4227-ab0f-511a267cb7ff', booking_id='b2d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Bola', 'Chuteira'], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ), Booking( @@ -41,7 +41,7 @@ def __init__(self): user_id='d351a9b1-937f-423c-a9d1-9929b5795be1', booking_id='b3d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Bola'], - booking_type=TYPE.COMMON + booking_type=BOOKING_TYPE.COMMON ), Booking( @@ -52,7 +52,7 @@ def __init__(self): user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b4d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Bola', 'Rede'], - booking_type=TYPE.COMMON + booking_type=BOOKING_TYPE.COMMON ), Booking( @@ -63,7 +63,7 @@ def __init__(self): user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b5d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Bola'], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ), Booking( @@ -74,7 +74,7 @@ def __init__(self): user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b6d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Bola', 'Chuteira'], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ), Booking( @@ -85,7 +85,7 @@ def __init__(self): user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b7d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Bola', 'Tenis', 'Capacete'], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ), Booking( @@ -96,7 +96,7 @@ def __init__(self): user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b8d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Raquete', 'Bola'], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ), ] @@ -110,7 +110,8 @@ def update_booking(self, end_date: int = None, court_number: int = None, sport: SPORT = None, - materials: List[str] = None + materials: List[str] = None, + booking_type: BOOKING_TYPE = None ) -> Booking: booking = self.get_booking(booking_id) @@ -128,7 +129,8 @@ def update_booking(self, booking.sport = sport if materials is not None: booking.materials = materials - + if booking_type is not None: + booking.booking_type = booking_type return booking def get_booking(self, booking_id: str): @@ -143,7 +145,8 @@ def get_bookings(self, sport: Optional[str] = None, court_number: Optional[int] = None, end_date: Optional[int] = None, - start_date: Optional[int] = None) -> List[Optional[Booking]]: + start_date: Optional[int] = None, + booking_type: Optional[str] = None) -> List[Optional[Booking]]: filters = locals().copy() filters.pop('self') diff --git a/tests/modules/create_booking/app/test_create_booking_usecase.py b/tests/modules/create_booking/app/test_create_booking_usecase.py index 143608f..80254ea 100644 --- a/tests/modules/create_booking/app/test_create_booking_usecase.py +++ b/tests/modules/create_booking/app/test_create_booking_usecase.py @@ -3,7 +3,7 @@ from src.modules.create_booking.app.create_booking_usecase import CreateBookingUsecase from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT -from src.shared.domain.enums.type import TYPE +from src.shared.domain.enums.type import BOOKING_TYPE from src.shared.helpers.errors.usecase_errors import InvalidSchedule from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock @@ -20,7 +20,7 @@ def test_create_booking_usecase(self): user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=['Raquete', 'Bola', 'Rede', 'Tenis'], booking_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) booking_repository = BookingRepositoryMock() @@ -34,7 +34,7 @@ def test_create_booking_usecase(self): sport="Tennis", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=['Raquete', 'Bola', 'Rede', 'Tenis'], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) assert response is not None @@ -61,7 +61,7 @@ def test_create_booking_usecase_invalid_sport(self): sport="Invalid sport but string", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=['Raquete', 'Bola', 'Rede', 'Tenis'], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_create_booking_usecase_invalid_materials(self): @@ -79,7 +79,7 @@ def test_create_booking_usecase_invalid_materials(self): sport="Tennis", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=[1, 2, 3], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_create_booking_usecase_invalid_schedule_overlap(self): @@ -97,7 +97,7 @@ def test_create_booking_usecase_invalid_schedule_overlap(self): sport="Tennis", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=["colete"], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) assert e.value == "Court is already booked for the selected time slot or has to have 15 min tolerance" @@ -120,7 +120,7 @@ def test_create_booking_usecase_invalid_schedule_15min(self): user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=['Bola', 'Chuteira'], booking_id='ddd35c66-13a4-4641-9d54-773b4b8ccc98', - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) ) @@ -131,7 +131,7 @@ def test_create_booking_usecase_invalid_schedule_15min(self): sport=SPORT.FUTSAL, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=['Bola', 'Chuteira'], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) assert e.value == "Court is already booked for the selected time slot or has to have 15 min tolerance" @@ -146,7 +146,7 @@ def test_create_booking_usecase_invalid_schedule_15min(self): sport=SPORT.FUTSAL, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=['Bola', 'Chuteira'], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) assert e2.value == "Court is already booked for the selected time slot or has to have 15 min tolerance" diff --git a/tests/modules/create_booking/app/test_create_booking_viewmodel.py b/tests/modules/create_booking/app/test_create_booking_viewmodel.py index aee1cb4..ceb50b0 100644 --- a/tests/modules/create_booking/app/test_create_booking_viewmodel.py +++ b/tests/modules/create_booking/app/test_create_booking_viewmodel.py @@ -1,7 +1,7 @@ from src.modules.create_booking.app.create_booking_viewmodel import CreateBookingViewmodel from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT -from src.shared.domain.enums.type import TYPE +from src.shared.domain.enums.type import BOOKING_TYPE class TestCreateBookingViewmodel: @@ -16,7 +16,7 @@ def test_create_booking_viewmodel(self): user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', materials=['Raquete', 'Bola', 'Rede', 'Tenis'], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) expected = { diff --git a/tests/modules/delete_booking/app/test_delete_booking_viewmodel.py b/tests/modules/delete_booking/app/test_delete_booking_viewmodel.py index 339d113..fe074a8 100644 --- a/tests/modules/delete_booking/app/test_delete_booking_viewmodel.py +++ b/tests/modules/delete_booking/app/test_delete_booking_viewmodel.py @@ -25,7 +25,8 @@ def test_delete_booking_viewmodel(self): 'sport': 'Tennis', 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', - 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] + 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'], + "type": 'Training' }, 'message': 'the booking was deleted' } diff --git a/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py b/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py index ed9fc66..db930bc 100644 --- a/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py +++ b/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py @@ -7,57 +7,110 @@ class Test_GetAllBookingsViewmodel: def test_get_all_bookings_viewmodel(self): repo = BookingRepositoryMock() usecase = GetAllBookingsUsecase(repo = repo) - courts = usecase() - viewmodel = GetAllBookingsViewModel(courts).to_dict() + bookings = usecase() + viewmodel = GetAllBookingsViewModel(bookings).to_dict() - excepted = { - 'courts': [ - { - 'start_date': 1634576165000, - 'end_date': 1634583365000, - 'court_number': 1, - 'sport': 'TENNIS', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', - 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] + expected = { + 'bookings': [ + { + 'booking': { + 'start_date': 1634576165000, + 'end_date': 1634583365000, + 'court_number': 1, + 'sport': 'Tennis', + 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', + 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', + 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'], + 'type': 'Training' + } + }, + { + 'booking': { + 'start_date': 1634563800000, + 'end_date': 1634567400000, + 'court_number': 2, + 'sport': 'Football', + 'user_id': 'c07e0862-3c07-4227-ab0f-511a267cb7ff', + 'booking_id': 'b2d3bebf-dc0d-4fc1-861c-506a40cc2925', + 'materials': ['Bola', 'Chuteira'], + 'type': 'Training' + } + }, + { + 'booking': { + 'start_date': 1634569200000, + 'end_date': 1634571000000, + 'court_number': 3, + 'sport': 'Basketball', + 'user_id': 'd351a9b1-937f-423c-a9d1-9929b5795be1', + 'booking_id': 'b3d3bebf-dc0d-4fc1-861c-506a40cc2925', + 'materials': ['Bola'], + 'type': 'Common' + } + }, + { + 'booking': { + 'start_date': 1634574600000, + 'end_date': 1634578200000, + 'court_number': 4, + 'sport': 'Volleyball', + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'booking_id': 'b4d3bebf-dc0d-4fc1-861c-506a40cc2925', + 'materials': ['Bola', 'Rede'], + 'type': 'Common' + } }, { - 'start_date': 1634563800000, - 'end_date': 1634567400000, - 'court_number': 2, - 'sport': 'FOOTBALL', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'booking_id': 'b2d3bebf-dc0d-4fc1-861c-506a40cc2925', - 'materials': ['Bola', 'Chuteira'] + 'booking': { + 'start_date': 1634580000000, + 'end_date': 1634581800000, + 'court_number': 5, + 'sport': 'Handball', + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'booking_id': 'b5d3bebf-dc0d-4fc1-861c-506a40cc2925', + 'materials': ['Bola'], + 'type': 'Training' + } }, { - 'start_date': 1634569200000, - 'end_date': 1634571000000, - 'court_number': 3, - 'sport': 'BASKETBALL', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'booking_id': 'b3d3bebf-dc0d-4fc1-861c-506a40cc2925', - 'materials': ['Bola'] + 'booking': { + 'start_date': 1634583600000, + 'end_date': 1634585400000, + 'court_number': 5, + 'sport': 'Futsal', + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'booking_id': 'b6d3bebf-dc0d-4fc1-861c-506a40cc2925', + 'materials': ['Bola', 'Chuteira'], + 'type': 'Training' + } }, { - 'start_date': 1634574600000, - 'end_date': 1634578200000, - 'court_number': 4, - 'sport': 'VOLLEYBALL', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'booking_id': 'b4d3bebf-dc0d-4fc1-861c-506a40cc2925', - 'materials': ['Bola', 'Rede'] + 'booking': { + 'start_date': 1634587200000, + 'end_date': 1634589000000, + 'court_number': 5, + 'sport': 'Rugby', + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'booking_id': 'b7d3bebf-dc0d-4fc1-861c-506a40cc2925', + 'materials': ['Bola', 'Tenis', 'Capacete'], + 'type': 'Training' + } }, { - 'start_date': 1634580000000, - 'end_date': 1634581800000, - 'court_number': 5, - 'sport': 'HANDBALL', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', - 'booking_id': 'b5d3bebf-dc0d-4fc1-861c-506a40cc2925', - 'materials': ['Bola'] + 'booking': { + 'start_date': 1634590800000, + 'end_date': 1634592600000, + 'court_number': 5, + 'sport': 'Ping Pong', + 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', + 'booking_id': 'b8d3bebf-dc0d-4fc1-861c-506a40cc2925', + 'materials': ['Raquete', 'Bola'], + 'type': 'Training' + } } ], 'message': 'the bookings were retrieved' + } + - } \ No newline at end of file + assert viewmodel == expected diff --git a/tests/modules/get_booking/app/test_get_booking_viewmodel.py b/tests/modules/get_booking/app/test_get_booking_viewmodel.py index 6cec5ef..e3360ca 100644 --- a/tests/modules/get_booking/app/test_get_booking_viewmodel.py +++ b/tests/modules/get_booking/app/test_get_booking_viewmodel.py @@ -18,7 +18,8 @@ def test_get_booking_viewmodel(self): 'sport': 'Tennis', 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', - 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] + 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'], + 'type': 'Training' }, 'message': 'the booking was retrieved' } diff --git a/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py b/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py index c2ac5b5..f45da46 100644 --- a/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py +++ b/tests/modules/get_bookings/app/test_get_bookings_viewmodel.py @@ -18,7 +18,8 @@ def test_get_bookings_viewmodel(self): 'sport': 'Tennis', 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', - 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'] + 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'], + 'type': 'Training' }], 'message': 'the bookings were retrieved' } diff --git a/tests/modules/update_booking/app/test_update_booking_viewmodel.py b/tests/modules/update_booking/app/test_update_booking_viewmodel.py index 6e9e708..1458306 100644 --- a/tests/modules/update_booking/app/test_update_booking_viewmodel.py +++ b/tests/modules/update_booking/app/test_update_booking_viewmodel.py @@ -1,6 +1,7 @@ from src.modules.update_booking.app.update_booking_viewmodel import UpdateBookingViewmodel from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT +from src.shared.domain.enums.type import BOOKING_TYPE class Test_UpdateBookingViewmodel: @@ -12,7 +13,8 @@ def test_update_booking_view_model(self): sport=SPORT.FOOTBALL, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', booking_id='b1d3bebf-dc0d-4fc1-861c-506a40cc2925', - materials=['Bola']) + materials=['Bola'], + booking_type=BOOKING_TYPE.TRAINING) viewmodel = UpdateBookingViewmodel(booking=booking).to_dict() @@ -24,7 +26,8 @@ def test_update_booking_view_model(self): 'sport': 'Football', 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', - 'materials': ['Bola'] + 'materials': ['Bola'], + 'type': 'Training' }, 'message': 'the booking was retrieved' } diff --git a/tests/shared/domain/entities/test_booking.py b/tests/shared/domain/entities/test_booking.py index 9f3160d..dc7e366 100644 --- a/tests/shared/domain/entities/test_booking.py +++ b/tests/shared/domain/entities/test_booking.py @@ -2,7 +2,7 @@ from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT -from src.shared.domain.enums.type import TYPE +from src.shared.domain.enums.type import BOOKING_TYPE from src.shared.helpers.errors.domain_errors import EntityError, EntityParameterOrderDatesError @@ -18,7 +18,7 @@ def test_booking(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= ["ball"], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) assert type(booking) == Booking @@ -41,7 +41,7 @@ def test_order_dates_incorrect(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= ["ball"], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_invalid_dates(self): @@ -54,7 +54,7 @@ def test_invalid_dates(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= ["ball"], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_invalid_court_number(self): @@ -67,7 +67,7 @@ def test_invalid_court_number(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= ["ball"], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_invalid_sport(self): @@ -80,7 +80,7 @@ def test_invalid_sport(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= ["ball"], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_invalid_user_id(self): @@ -93,7 +93,7 @@ def test_invalid_user_id(self): user_id= "123", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= ["ball"], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_invalid_booking_id(self): @@ -106,7 +106,7 @@ def test_invalid_booking_id(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "123", materials= ["ball"], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_invalid_materials(self): @@ -119,7 +119,7 @@ def test_invalid_materials(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= "ball", - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_invalid_materials2(self): @@ -132,7 +132,7 @@ def test_invalid_materials2(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= [1], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_invalid_materials3(self): @@ -145,7 +145,7 @@ def test_invalid_materials3(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= ["ball", 2], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_booking_none_dates(self): @@ -158,7 +158,7 @@ def test_booking_none_dates(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= ["ball"], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_booking_none_court_number(self): @@ -171,7 +171,7 @@ def test_booking_none_court_number(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= ["ball"], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_booking_none_sport(self): @@ -184,7 +184,7 @@ def test_booking_none_sport(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= ["ball"], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_booking_none_user_id(self): @@ -197,7 +197,7 @@ def test_booking_none_user_id(self): user_id= None, booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= ["ball"], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_booking_none_booking_id(self): @@ -210,7 +210,7 @@ def test_booking_none_booking_id(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= None, materials= ["ball"], - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_booking_none_materials(self): @@ -223,7 +223,7 @@ def test_booking_none_materials(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= None, - booking_type=TYPE.TRAINING + booking_type=BOOKING_TYPE.TRAINING ) def test_booking_with_invalid_type(self): @@ -251,7 +251,7 @@ def test_booking_with_maintance_invalid_sport(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= ["ball"], - booking_type=TYPE.MAINTENCE + booking_type=BOOKING_TYPE.MAINTENCE ) def test_booking_to_dict(self): @@ -264,7 +264,7 @@ def test_booking_to_dict(self): user_id= "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", booking_id= "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", materials= ["ball"], - booking_type=TYPE.MAINTENCE + booking_type=BOOKING_TYPE.MAINTENCE ) expected = { @@ -275,7 +275,7 @@ def test_booking_to_dict(self): "user_id": "d3b07384-d9a1-4e8a-b3ef-4f1d2a87c6f5", "booking_id": "a1f5e2c3-7d8b-4c9e-b012-34f6a789d0e1", "materials": ["ball"], - "type": TYPE.MAINTENCE.value + "type": BOOKING_TYPE.MAINTENCE.value } assert booking.to_dict() == expected \ No newline at end of file diff --git a/tests/shared/infra/repositories/test_booking_repository_mock.py b/tests/shared/infra/repositories/test_booking_repository_mock.py index 9b82bdb..8039bc2 100644 --- a/tests/shared/infra/repositories/test_booking_repository_mock.py +++ b/tests/shared/infra/repositories/test_booking_repository_mock.py @@ -1,4 +1,4 @@ -from src.shared.domain.enums.type import TYPE +from src.shared.domain.enums.type import BOOKING_TYPE from src.shared.infra.repositories.booking_repository_mock import BookingRepositoryMock from src.shared.domain.enums.sport import SPORT from src.shared.domain.entities.booking import Booking @@ -7,7 +7,7 @@ class TestBookingRepositoryMock: def test_create_booking(self): repo_mock = BookingRepositoryMock() - new_booking = Booking(start_date=1634576165000, end_date=1634583365000, court_number=1,sport=SPORT.TENNIS, user_id='c8435c66-13a4-4641-9d54-773b4b8ccd09', booking_id='c2d3bebf-dc0d-4fc1-861c-506a40cc2036', materials=['Raquete', 'Bola', 'Rede', 'Tenis'], booking_type=TYPE.TRAINING) + new_booking = Booking(start_date=1634576165000, end_date=1634583365000, court_number=1,sport=SPORT.TENNIS, user_id='c8435c66-13a4-4641-9d54-773b4b8ccd09', booking_id='c2d3bebf-dc0d-4fc1-861c-506a40cc2036', materials=['Raquete', 'Bola', 'Rede', 'Tenis'], booking_type=BOOKING_TYPE.TRAINING) len_before = len(repo_mock.bookings) response = repo_mock.create_booking(new_booking) From 44504e51d6bd3879aae8e7298053f9ae00d9d110 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 15 Sep 2025 19:26:47 -0300 Subject: [PATCH 127/167] fix()get_all_bookigs): remove user_id from mock tests --- .../app/test_get_all_bookings_viewmodel.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py b/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py index db930bc..5967770 100644 --- a/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py +++ b/tests/modules/get_all_bookings/app/test_get_all_bookings_viewmodel.py @@ -18,7 +18,6 @@ def test_get_all_bookings_viewmodel(self): 'end_date': 1634583365000, 'court_number': 1, 'sport': 'Tennis', - 'user_id': '1f25448b-3429-4c19-8287-d9e64f17bc3a', 'booking_id': 'b1d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Raquete', 'Bola', 'Rede', 'Tenis'], 'type': 'Training' @@ -30,7 +29,6 @@ def test_get_all_bookings_viewmodel(self): 'end_date': 1634567400000, 'court_number': 2, 'sport': 'Football', - 'user_id': 'c07e0862-3c07-4227-ab0f-511a267cb7ff', 'booking_id': 'b2d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Bola', 'Chuteira'], 'type': 'Training' @@ -42,7 +40,6 @@ def test_get_all_bookings_viewmodel(self): 'end_date': 1634571000000, 'court_number': 3, 'sport': 'Basketball', - 'user_id': 'd351a9b1-937f-423c-a9d1-9929b5795be1', 'booking_id': 'b3d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Bola'], 'type': 'Common' @@ -54,7 +51,6 @@ def test_get_all_bookings_viewmodel(self): 'end_date': 1634578200000, 'court_number': 4, 'sport': 'Volleyball', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', 'booking_id': 'b4d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Bola', 'Rede'], 'type': 'Common' @@ -66,7 +62,6 @@ def test_get_all_bookings_viewmodel(self): 'end_date': 1634581800000, 'court_number': 5, 'sport': 'Handball', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', 'booking_id': 'b5d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Bola'], 'type': 'Training' @@ -78,7 +73,6 @@ def test_get_all_bookings_viewmodel(self): 'end_date': 1634585400000, 'court_number': 5, 'sport': 'Futsal', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', 'booking_id': 'b6d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Bola', 'Chuteira'], 'type': 'Training' @@ -90,7 +84,6 @@ def test_get_all_bookings_viewmodel(self): 'end_date': 1634589000000, 'court_number': 5, 'sport': 'Rugby', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', 'booking_id': 'b7d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Bola', 'Tenis', 'Capacete'], 'type': 'Training' @@ -102,7 +95,6 @@ def test_get_all_bookings_viewmodel(self): 'end_date': 1634592600000, 'court_number': 5, 'sport': 'Ping Pong', - 'user_id': 'c8435c66-13a4-4641-9d54-773b4b8ccc98', 'booking_id': 'b8d3bebf-dc0d-4fc1-861c-506a40cc2925', 'materials': ['Raquete', 'Bola'], 'type': 'Training' From c67fd824098e264b5084516409494d1d6232e6de Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 15 Sep 2025 20:25:25 -0300 Subject: [PATCH 128/167] fix(DTO): tentando corrigir o DTO --- src/shared/infra/dto/booking_dynamo_dto.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/infra/dto/booking_dynamo_dto.py b/src/shared/infra/dto/booking_dynamo_dto.py index 01bb8a8..7304242 100644 --- a/src/shared/infra/dto/booking_dynamo_dto.py +++ b/src/shared/infra/dto/booking_dynamo_dto.py @@ -74,7 +74,7 @@ def from_dynamo(booking_data: dict) -> "BookingDynamoDTO": user_id = booking_data["user_id"], booking_id = booking_data["booking_id"], materials = booking_data.get("materials") or [], - booking_type= booking_data["booking_type"] + booking_type= BOOKING_TYPE(booking_data["booking_type"]) ) def to_entity(self) -> Booking: From 1f96c4c535d6cd28973b49bbf43439067940c2ec Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 15 Sep 2025 20:47:58 -0300 Subject: [PATCH 129/167] fix(booking): corrigindo erros de viewmodel --- src/modules/create_booking/app/create_booking_viewmodel.py | 2 ++ src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py | 2 ++ src/modules/update_booking/app/update_booking_controller.py | 1 + 3 files changed, 5 insertions(+) diff --git a/src/modules/create_booking/app/create_booking_viewmodel.py b/src/modules/create_booking/app/create_booking_viewmodel.py index 83cada4..19675b4 100644 --- a/src/modules/create_booking/app/create_booking_viewmodel.py +++ b/src/modules/create_booking/app/create_booking_viewmodel.py @@ -1,6 +1,7 @@ from typing import List from src.shared.domain.enums.sport import SPORT +from src.shared.domain.enums.type import BOOKING_TYPE class CreateBookingViewmodel: @@ -12,6 +13,7 @@ class CreateBookingViewmodel: user_id: str booking_id: str materials: List[str] + booking_type: BOOKING_TYPE def __init__(self, booking): self.start_date = booking.start_date diff --git a/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py b/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py index fc5259e..ee8d77f 100644 --- a/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py +++ b/src/modules/get_all_bookings/app/get_all_bookings_viewmodel.py @@ -1,5 +1,6 @@ from src.shared.domain.entities.booking import Booking from src.shared.domain.enums.sport import SPORT +from src.shared.domain.enums.type import BOOKING_TYPE from typing import List class BookingViewModel: @@ -9,6 +10,7 @@ class BookingViewModel: sport: SPORT booking_id: str materials: List[str] + booking_type: BOOKING_TYPE def __init__(self, booking: Booking): self.start_date = booking.start_date diff --git a/src/modules/update_booking/app/update_booking_controller.py b/src/modules/update_booking/app/update_booking_controller.py index 1ccdf8d..62e07a4 100644 --- a/src/modules/update_booking/app/update_booking_controller.py +++ b/src/modules/update_booking/app/update_booking_controller.py @@ -51,6 +51,7 @@ def __call__(self, request: IRequest) -> IResponse: sport = SPORT(sport_value) + if booking_type is not None: if not isinstance(booking_type, str): raise WrongTypeParameter('type', 'str', type(booking_type).__name__) From 78a778a000ae5795fe274db78cbe9ccbe4e97bd5 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Tue, 16 Sep 2025 15:41:16 -0300 Subject: [PATCH 130/167] fix: provavel problema no DTO --- .../create_booking/app/create_booking_controller.py | 2 +- src/modules/create_booking/app/create_booking_usecase.py | 9 +++++++-- src/shared/infra/dto/booking_dynamo_dto.py | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/modules/create_booking/app/create_booking_controller.py b/src/modules/create_booking/app/create_booking_controller.py index 4d99dd3..798ee6b 100644 --- a/src/modules/create_booking/app/create_booking_controller.py +++ b/src/modules/create_booking/app/create_booking_controller.py @@ -93,7 +93,7 @@ def __call__(self, request: IRequest): sport=sport, user_id=user_id, materials=materials, - booking_type=BOOKING_TYPE(booking_type) + booking_type=booking_type ) viewmodel = CreateBookingViewmodel(booking=booking) diff --git a/src/modules/create_booking/app/create_booking_usecase.py b/src/modules/create_booking/app/create_booking_usecase.py index 6933cd8..a795713 100644 --- a/src/modules/create_booking/app/create_booking_usecase.py +++ b/src/modules/create_booking/app/create_booking_usecase.py @@ -28,7 +28,7 @@ def __call__(self, sport: str, user_id: str, materials: List[str], - booking_type: BOOKING_TYPE + booking_type: str ) -> Booking: booking_id = str(uuid.uuid4()) @@ -44,6 +44,11 @@ def __call__(self, for material in materials: if not isinstance(material, str): raise ValueError("Invalid material type") + + if booking_type not in [type.value for type in BOOKING_TYPE]: + raise ValueError("Invalid type enum value") + + self.booking_type = BOOKING_TYPE(booking_type) all_bookings = self.repo.get_all_bookings() @@ -64,7 +69,7 @@ def __call__(self, user_id, booking_id, materials, - booking_type)) + self.booking_type)) return resp diff --git a/src/shared/infra/dto/booking_dynamo_dto.py b/src/shared/infra/dto/booking_dynamo_dto.py index 7304242..3121b3f 100644 --- a/src/shared/infra/dto/booking_dynamo_dto.py +++ b/src/shared/infra/dto/booking_dynamo_dto.py @@ -74,7 +74,7 @@ def from_dynamo(booking_data: dict) -> "BookingDynamoDTO": user_id = booking_data["user_id"], booking_id = booking_data["booking_id"], materials = booking_data.get("materials") or [], - booking_type= BOOKING_TYPE(booking_data["booking_type"]) + booking_type= BOOKING_TYPE(booking_data.get("booking_type", None)) if booking_data.get("booking_type", None) is not None else 'Undefined' ) def to_entity(self) -> Booking: From ae377a38dca84117d3cea32f0c307fd051a42597 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Tue, 16 Sep 2025 15:43:18 -0300 Subject: [PATCH 131/167] =?UTF-8?q?fix(enums):=20adicionando=20o=20tipo=20?= =?UTF-8?q?UNDEFINED=20para=20bookings=20j=C3=A1=20existentes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/domain/enums/type.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shared/domain/enums/type.py b/src/shared/domain/enums/type.py index ef8b9e9..d1fc9d1 100644 --- a/src/shared/domain/enums/type.py +++ b/src/shared/domain/enums/type.py @@ -4,3 +4,4 @@ class BOOKING_TYPE(Enum): MAINTENCE = 'Maintence' TRAINING = 'Training' COMMON = 'Common' + UNDEFINED = 'Undefined' From cf76b107d5a6355629e3ba7ee800acdd172257be Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Tue, 16 Sep 2025 15:57:07 -0300 Subject: [PATCH 132/167] fix(create-booking): arrumando os testes do usecase --- .../app/test_create_booking_presenter.py | 6 +++--- .../app/test_create_booking_usecase.py | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/modules/create_booking/app/test_create_booking_presenter.py b/tests/modules/create_booking/app/test_create_booking_presenter.py index 495b807..b236058 100644 --- a/tests/modules/create_booking/app/test_create_booking_presenter.py +++ b/tests/modules/create_booking/app/test_create_booking_presenter.py @@ -50,7 +50,7 @@ def test_create_booking_presenter(self): "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, - "body": {'start_date': 1610617200, 'end_date': 1610620800, 'court_number': 1, 'sport': 'Tennis', 'materials': ['ball', 'racket'], 'type': 'Common'}, + "body": {'start_date': 1610617200, 'end_date': 1610620800, 'court_number': 1, 'sport': 'Tennis', 'materials': ['ball', 'racket'], 'type': 'Training'}, "pathParameters": None, "isBase64Encoded": None, "stageVariables": None @@ -59,5 +59,5 @@ def test_create_booking_presenter(self): response = lambda_handler(event, None) print(response) - assert response['statusCode'] == 201 - assert json.loads(response['body'])['message'] == 'Booking created successfully' \ No newline at end of file + assert json.loads(response['body'])['message'] == 'Booking created successfully' + assert response['statusCode'] == 201 \ No newline at end of file diff --git a/tests/modules/create_booking/app/test_create_booking_usecase.py b/tests/modules/create_booking/app/test_create_booking_usecase.py index 80254ea..84caa90 100644 --- a/tests/modules/create_booking/app/test_create_booking_usecase.py +++ b/tests/modules/create_booking/app/test_create_booking_usecase.py @@ -34,7 +34,7 @@ def test_create_booking_usecase(self): sport="Tennis", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=['Raquete', 'Bola', 'Rede', 'Tenis'], - booking_type=BOOKING_TYPE.TRAINING + booking_type='Training' ) assert response is not None @@ -61,7 +61,7 @@ def test_create_booking_usecase_invalid_sport(self): sport="Invalid sport but string", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=['Raquete', 'Bola', 'Rede', 'Tenis'], - booking_type=BOOKING_TYPE.TRAINING + booking_type='Training' ) def test_create_booking_usecase_invalid_materials(self): @@ -79,7 +79,7 @@ def test_create_booking_usecase_invalid_materials(self): sport="Tennis", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=[1, 2, 3], - booking_type=BOOKING_TYPE.TRAINING + booking_type='Training' ) def test_create_booking_usecase_invalid_schedule_overlap(self): @@ -97,7 +97,7 @@ def test_create_booking_usecase_invalid_schedule_overlap(self): sport="Tennis", user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=["colete"], - booking_type=BOOKING_TYPE.TRAINING + booking_type='Training' ) assert e.value == "Court is already booked for the selected time slot or has to have 15 min tolerance" @@ -131,7 +131,7 @@ def test_create_booking_usecase_invalid_schedule_15min(self): sport=SPORT.FUTSAL, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=['Bola', 'Chuteira'], - booking_type=BOOKING_TYPE.TRAINING + booking_type='Training' ) assert e.value == "Court is already booked for the selected time slot or has to have 15 min tolerance" @@ -146,7 +146,7 @@ def test_create_booking_usecase_invalid_schedule_15min(self): sport=SPORT.FUTSAL, user_id='c8435c66-13a4-4641-9d54-773b4b8ccc98', materials=['Bola', 'Chuteira'], - booking_type=BOOKING_TYPE.TRAINING + booking_type='Training' ) assert e2.value == "Court is already booked for the selected time slot or has to have 15 min tolerance" From 81e6371f583c3d7b9a8f588fc675b761fd1819a8 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Tue, 16 Sep 2025 16:06:37 -0300 Subject: [PATCH 133/167] fix(DTO): Retorna UNDEFINED caso o booking ja exista --- src/shared/infra/dto/booking_dynamo_dto.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/infra/dto/booking_dynamo_dto.py b/src/shared/infra/dto/booking_dynamo_dto.py index 3121b3f..38ad9fb 100644 --- a/src/shared/infra/dto/booking_dynamo_dto.py +++ b/src/shared/infra/dto/booking_dynamo_dto.py @@ -74,7 +74,7 @@ def from_dynamo(booking_data: dict) -> "BookingDynamoDTO": user_id = booking_data["user_id"], booking_id = booking_data["booking_id"], materials = booking_data.get("materials") or [], - booking_type= BOOKING_TYPE(booking_data.get("booking_type", None)) if booking_data.get("booking_type", None) is not None else 'Undefined' + booking_type= BOOKING_TYPE(booking_data.get("booking_type", None)) if booking_data.get("booking_type", None) is not None else BOOKING_TYPE.UNDEFINED ) def to_entity(self) -> Booking: From 9af553a17ca565e4d324b4cc23c7d70f3e426e92 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 17 Sep 2025 17:10:08 -0300 Subject: [PATCH 134/167] fix(get-bookings): arrumando alguns pontos para ver se a rota funciona com o atributo booking_type --- src/modules/get_bookings/app/get_bookings_controller.py | 4 ++-- src/modules/get_bookings/app/get_bookings_usecase.py | 2 +- .../domain/repositories/booking_repository_interface.py | 5 +++-- src/shared/infra/repositories/booking_repository_dynamo.py | 5 +++-- .../modules/get_bookings/app/test_get_bookings_controller.py | 2 +- .../modules/get_bookings/app/test_get_bookings_presenter.py | 2 +- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/modules/get_bookings/app/get_bookings_controller.py b/src/modules/get_bookings/app/get_bookings_controller.py index 371a18b..10e7781 100644 --- a/src/modules/get_bookings/app/get_bookings_controller.py +++ b/src/modules/get_bookings/app/get_bookings_controller.py @@ -33,9 +33,9 @@ def __call__(self, request: IRequest): start_date = start_date if start_date != "" else None booking_type = booking_type if booking_type != "" else None - if not booking_id and not user_id and not sport and not court_number and not end_date and not start_date: + if not booking_id and not user_id and not sport and not court_number and not end_date and not start_date and not booking_type: raise EmptyQueryParameters( - 'At least one of the filters must be provided: booking_id, user_id, sport, court_number, end_date, start_date') + 'At least one of the filters must be provided: booking_id, user_id, sport, court_number, end_date, start_date, type') if court_number is not None: try: diff --git a/src/modules/get_bookings/app/get_bookings_usecase.py b/src/modules/get_bookings/app/get_bookings_usecase.py index 8b1e0bf..1290fda 100644 --- a/src/modules/get_bookings/app/get_bookings_usecase.py +++ b/src/modules/get_bookings/app/get_bookings_usecase.py @@ -52,7 +52,7 @@ def __call__(self, court_number=court_number if court_number else None, end_date=end_date if end_date else None, start_date=start_date if start_date else None, - booking_type=booking_type) + booking_type=BOOKING_TYPE(booking_type) if booking_type else None) if bookings is None or bookings == []: raise NoItemsFound('booking filters passed') diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index 180d63e..efa69a2 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -48,9 +48,10 @@ def get_bookings(self, user_id: Optional[str] = None, sport: Optional[str] = None, court_number: Optional[int] = None, + booking_type: Optional[str] = None, end_date: Optional[int] = None, - start_date: Optional[int] = None, - booking_type: Optional[str] = None) -> List[Optional[Booking]]: + start_date: Optional[int] = None + ) -> List[Optional[Booking]]: ''' If the booking exists, returns it, else returns None ''' diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index 1bb422e..c64b450 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -86,9 +86,10 @@ def get_bookings(self, user_id: Optional[str] = None, sport: Optional[str] = None, court_number: Optional[int] = None, + booking_type: Optional[str] = None, end_date: Optional[int] = None, - start_date: Optional[int] = None, - booking_type: Optional[str] = None) -> List[Optional[Booking]]: + start_date: Optional[int] = None + ) -> List[Optional[Booking]]: filters = locals().copy() filters.pop('self') diff --git a/tests/modules/get_bookings/app/test_get_bookings_controller.py b/tests/modules/get_bookings/app/test_get_bookings_controller.py index 629422e..8ccfa41 100644 --- a/tests/modules/get_bookings/app/test_get_bookings_controller.py +++ b/tests/modules/get_bookings/app/test_get_bookings_controller.py @@ -39,7 +39,7 @@ def test_get_bookings_controller_empty_query(self): response = controller(request) assert response.status_code == 400 - assert response.body == 'Empty query parameters: At least one of the filters must be provided: booking_id, user_id, sport, court_number, end_date, start_date' + assert response.body == 'Empty query parameters: At least one of the filters must be provided: booking_id, user_id, sport, court_number, end_date, start_date, type' def test_get_bookings_controller_wrong_type_booking_id(self): repo = BookingRepositoryMock() diff --git a/tests/modules/get_bookings/app/test_get_bookings_presenter.py b/tests/modules/get_bookings/app/test_get_bookings_presenter.py index 9831335..c58e4d7 100644 --- a/tests/modules/get_bookings/app/test_get_bookings_presenter.py +++ b/tests/modules/get_bookings/app/test_get_bookings_presenter.py @@ -121,7 +121,7 @@ def test_get_bookings_presenter_missing_parameters(self): response = lambda_handler(event, None) assert response['statusCode'] == 400 - assert json.loads(response['body']) == 'Empty query parameters: At least one of the filters must be provided: booking_id, user_id, sport, court_number, end_date, start_date' + assert json.loads(response['body']) == 'Empty query parameters: At least one of the filters must be provided: booking_id, user_id, sport, court_number, end_date, start_date, type' def test_get_bookings_presenter_entity_error(self): event = { From 4b1850257dd1184ed64dd3a80edd2cf19e382347 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 1 Oct 2025 20:06:54 -0300 Subject: [PATCH 135/167] fix(delete-booking): ajustando logica de envio de e-mail --- .../booking_repository_interface.py | 2 +- .../functions/compose_delete_booking_email.py | 291 +++++++++++++++--- .../repositories/booking_repository_dynamo.py | 8 +- 3 files changed, 253 insertions(+), 48 deletions(-) diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index efa69a2..af654db 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -82,7 +82,7 @@ def get_all_users(self) -> List[str]: # TODO: método para enviar e-mail para o usuário @abstractmethod - def send_user_email(self, user) -> bool: + def send_user_email(self, user, deleted_booking: Booking) -> bool: ''' Send user an e-mail ''' diff --git a/src/shared/helpers/functions/compose_delete_booking_email.py b/src/shared/helpers/functions/compose_delete_booking_email.py index 2249e28..90ee501 100644 --- a/src/shared/helpers/functions/compose_delete_booking_email.py +++ b/src/shared/helpers/functions/compose_delete_booking_email.py @@ -1,49 +1,256 @@ -def compose_deleted_user_email(user): +from datetime import datetime +from src.shared.domain.entities.booking import Booking + + +def compose_deleted_user_email(user, deleted_booking: Booking): name = user.get('name') email = user.get('email') + data_hora_inicio = datetime.fromtimestamp(deleted_booking.start_date/1000) + data_hora_fim = datetime.fromtimestamp(deleted_booking.end_date/1000) message = f""" - - - - - - - - - -
- - - - -
- MauaFood Logo -

Feedback Enviado!

-
- - - - -
-
-

Obrigado, NOME USUÁRIO

Seu feedback foi enviado para nossa equipe analisar:

-

MENSAGEM

-

DATA

-
-
- - - - -
-
-

Atenciosamente,

-

Equipe MauaFood🍟

-
-
-
- + + + + + + Reserva Cancelada + + + +
+
+

Reserva Cancelada!

+
+ + Quadra + +
+
Olá {name},
+ +
Lamentamos informar que sua reserva:
+ +
+
+ Quadra: + {deleted_booking.court_number} +
+
+ Data: + {data_hora_inicio.strftime("%d/%m/%Y")} +
+
+ Horário: + {data_hora_inicio.strftime("%H:%M")} - {data_hora_fim.strftime("%H:%M")} +
+
+ +
foi cancelada!!
+ +
+ + +
+ """ diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index c64b450..0e8244f 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -145,7 +145,7 @@ def delete_booking(self, booking_id: str, user) -> Optional[Booking]: sort_key=self.booking_sort_key_format(booking_id) ) - self.send_user_email(user) + self.send_user_email(user, deleted) return BookingDynamoDTO.from_dynamo(deleted['Attributes']).to_entity() @@ -183,11 +183,11 @@ def get_all_users(self): return super().get_all_users() - def send_user_email(self, user) -> bool: + def send_user_email(self, user, deleted_booking: Booking) -> bool: try: client_ses = boto3.client('ses', region_name=os.environ.get('AWS_REGION')) - email_to_send = compose_deleted_user_email(user) + email_to_send = compose_deleted_user_email(user, deleted_booking) response = client_ses.send_email( Destination={ @@ -214,8 +214,6 @@ def send_user_email(self, user) -> bool: Source=os.environ.get("FROM_EMAIL"), ) - print("ESSA É A MAGIA DO PRINT, AQUI ESTÁ A SUA RESPONSE -----> ", response) - return True except Exception as err: print(err) From 871829465b5d6d5a6b75e4b6fa3f7eb63c43ea97 Mon Sep 17 00:00:00 2001 From: Leonardo Luiz Seixas Iorio Date: Sat, 4 Oct 2025 16:16:28 -0300 Subject: [PATCH 136/167] fixing bucket name, adding cfn distribution --- iac/stacks/bucket_stack.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/iac/stacks/bucket_stack.py b/iac/stacks/bucket_stack.py index 7b83325..6f97846 100644 --- a/iac/stacks/bucket_stack.py +++ b/iac/stacks/bucket_stack.py @@ -1,12 +1,12 @@ from aws_cdk import ( aws_s3 as s3, + aws_cloudfront as cloudfront, + aws_cloudfront_origins as origins, aws_iam as iam, RemovalPolicy, - Stack, ) from constructs import Construct import os -import random class BucketStack(Construct): @@ -27,7 +27,17 @@ def __init__(self, scope: Construct, **kwargs) -> None: self.bucket = s3.Bucket( self, f"BACK_S3_REPORT_BUCKET_{stage}", # TODO remover isso quando voltar pra conta nova ou tentar deletar o bucket criado la com power user - bucket_name=f"{self.stack_name}-report-bucket{stage}-{random.randint(1000,9999)}".lower(), + bucket_name=f"{self.stack_name}-report-bucket-{stage}".lower(), versioned=True, removal_policy=RemovalPolicy.DESTROY if not (stage == 'PROD') else RemovalPolicy.RETAIN, + block_public_access=s3.BlockPublicAccess.BLOCK_ALL + ) + + self.distribution = cloudfront.Distribution( + self, f"ReportBucketDistribution{stage}", + default_behavior=cloudfront.BehaviorOptions( + origin=origins.S3Origin(self.bucket), + viewer_protocol_policy=cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + ), + default_root_object=None # não obrigatório, mas evita erro se não tiver index.html ) From 1093e5400aa985623cfd805e28913f45e3855328 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 6 Oct 2025 21:02:32 -0300 Subject: [PATCH 137/167] fix(delete-booking): ajustando as variaveis de ambiente com o endereco de email correto --- iac/stacks/iac_stack.py | 2 ++ src/shared/environments.py | 4 ++++ src/shared/infra/repositories/booking_repository_dynamo.py | 6 ++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/iac/stacks/iac_stack.py b/iac/stacks/iac_stack.py index 79b5779..105cdc0 100644 --- a/iac/stacks/iac_stack.py +++ b/iac/stacks/iac_stack.py @@ -57,6 +57,8 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: "REGION": self.aws_region, "USER_API_URL": os.environ.get("USER_API_URL"), "S3_BUCKET_NAME": self.s3_bucket.bucket.bucket_name, + "FROM_EMAIL": os.environ.get("FROM_EMAIL"), + "HIDDEN_COPY": os.environ.get("HIDDEN_COPY") } diff --git a/src/shared/environments.py b/src/shared/environments.py index f3075bd..2dd4c46 100644 --- a/src/shared/environments.py +++ b/src/shared/environments.py @@ -31,6 +31,8 @@ class Environments: dynamo_sort_key: str cloud_front_distribution_domain: str mss_name: str + from_email: str + hidden_copy: str def _configure_local(self): from dotenv import load_dotenv @@ -64,6 +66,8 @@ def load_envs(self): self.dynamo_partition_key = os.environ.get("DYNAMO_PARTITION_KEY") self.dynamo_sort_key = os.environ.get("DYNAMO_SORT_KEY") self.cloud_front_distribution_domain = os.environ.get("CLOUD_FRONT_DISTRIBUTION_DOMAIN") + self.from_email = os.environ.get("FROM_EMAIL") + self.hidden_copy = os.environ.get("HIDDEN_COPY") # @staticmethod # def get_user_repo() -> IUserRepository: diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index 0e8244f..21013d3 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -196,7 +196,7 @@ def send_user_email(self, user, deleted_booking: Booking) -> bool: ], 'BccAddresses': [ - os.environ.get("HIDDEN_COPY") + Environments.hidden_copy ] }, Message={ @@ -211,9 +211,11 @@ def send_user_email(self, user, deleted_booking: Booking) -> bool: 'Data': 'Mauá Reservation - Reserva Cancelada', }, }, - Source=os.environ.get("FROM_EMAIL"), + Source = Environments.from_email, ) + + return True except Exception as err: print(err) From 7cbf26d89d8734e9b847300ca1302eadce926017 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 6 Oct 2025 21:17:54 -0300 Subject: [PATCH 138/167] fix(delete-booking): arrumando maneira de acesso as variaveis de ambiente do endereco --- src/shared/infra/repositories/booking_repository_dynamo.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index 21013d3..e34b3c6 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -196,7 +196,7 @@ def send_user_email(self, user, deleted_booking: Booking) -> bool: ], 'BccAddresses': [ - Environments.hidden_copy + Environments.get_envs().hidden_copy ] }, Message={ @@ -211,10 +211,10 @@ def send_user_email(self, user, deleted_booking: Booking) -> bool: 'Data': 'Mauá Reservation - Reserva Cancelada', }, }, - Source = Environments.from_email, + Source = Environments.get_envs().from_email, ) - + print('endereco de envio -> ' + Environments.get_envs().from_email) return True except Exception as err: From 866a40e82a96854ec9f836f20ac84c41cee43fff Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 6 Oct 2025 22:10:51 -0300 Subject: [PATCH 139/167] fix(delete_booking): tentando entender o problema --- .../delete_booking/app/delete_booking_presenter.py | 3 --- .../infra/repositories/booking_repository_dynamo.py | 8 +++++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/modules/delete_booking/app/delete_booking_presenter.py b/src/modules/delete_booking/app/delete_booking_presenter.py index 5974992..72a5648 100644 --- a/src/modules/delete_booking/app/delete_booking_presenter.py +++ b/src/modules/delete_booking/app/delete_booking_presenter.py @@ -10,9 +10,6 @@ def lambda_handler(event, context): - print(event) - print("PRINT DO EVENT TA AQUI") - httpRequest = LambdaHttpRequest(data=event) user_info_string = event.get('requestContext', {}).get('authorizer', {}).get('user') diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index e34b3c6..143d032 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -145,8 +145,12 @@ def delete_booking(self, booking_id: str, user) -> Optional[Booking]: sort_key=self.booking_sort_key_format(booking_id) ) + print(1) + self.send_user_email(user, deleted) + print(2) + return BookingDynamoDTO.from_dynamo(deleted['Attributes']).to_entity() if user_role == 'STUDENT': @@ -186,6 +190,8 @@ def get_all_users(self): def send_user_email(self, user, deleted_booking: Booking) -> bool: try: + print(3) + client_ses = boto3.client('ses', region_name=os.environ.get('AWS_REGION')) email_to_send = compose_deleted_user_email(user, deleted_booking) @@ -214,7 +220,7 @@ def send_user_email(self, user, deleted_booking: Booking) -> bool: Source = Environments.get_envs().from_email, ) - print('endereco de envio -> ' + Environments.get_envs().from_email) + print('4 endereco de envio -> ' + Environments.get_envs().from_email) return True except Exception as err: From acd67457a6aff10000616d3e51067559f723da6c Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 6 Oct 2025 22:23:52 -0300 Subject: [PATCH 140/167] fix(delete-booking): tentando entender o problema --- .../infra/repositories/booking_repository_dynamo.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index 143d032..8306a1f 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -190,11 +190,18 @@ def get_all_users(self): def send_user_email(self, user, deleted_booking: Booking) -> bool: try: - print(3) + print('3 ' + Environments.get_envs().from_email) + print('4 ' + Environments.get_envs().hidden_copy) + print('5 ' + user.get('email')) client_ses = boto3.client('ses', region_name=os.environ.get('AWS_REGION')) + + print('6 cliente aberto com sucesso') + email_to_send = compose_deleted_user_email(user, deleted_booking) + print('7 mensagem email criada -> ' + email_to_send) + response = client_ses.send_email( Destination={ 'ToAddresses': [ @@ -220,7 +227,7 @@ def send_user_email(self, user, deleted_booking: Booking) -> bool: Source = Environments.get_envs().from_email, ) - print('4 endereco de envio -> ' + Environments.get_envs().from_email) + print('EMAIL ENVIADO') return True except Exception as err: From 0483290e1942c8747bb989e4beafc2d6766eef96 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 6 Oct 2025 22:33:46 -0300 Subject: [PATCH 141/167] feat(delete_booking): provavel erro na passagem da resposta do dynamo --- .../repositories/booking_repository_dynamo.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index 8306a1f..1abb083 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -145,13 +145,11 @@ def delete_booking(self, booking_id: str, user) -> Optional[Booking]: sort_key=self.booking_sort_key_format(booking_id) ) - print(1) + deleted_booking = BookingDynamoDTO.from_dynamo(deleted['Attributes']).to_entity() - self.send_user_email(user, deleted) + self.send_user_email(user, deleted_booking) - print(2) - - return BookingDynamoDTO.from_dynamo(deleted['Attributes']).to_entity() + return deleted_booking if user_role == 'STUDENT': raise ForbiddenAction('user id') @@ -190,14 +188,8 @@ def get_all_users(self): def send_user_email(self, user, deleted_booking: Booking) -> bool: try: - print('3 ' + Environments.get_envs().from_email) - print('4 ' + Environments.get_envs().hidden_copy) - print('5 ' + user.get('email')) - client_ses = boto3.client('ses', region_name=os.environ.get('AWS_REGION')) - print('6 cliente aberto com sucesso') - email_to_send = compose_deleted_user_email(user, deleted_booking) print('7 mensagem email criada -> ' + email_to_send) From c2b46db6266b7186c33cf12e8fdd5a0d20529b8c Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 6 Oct 2025 22:43:52 -0300 Subject: [PATCH 142/167] fix(compose-email): provavel erro no format --- src/shared/helpers/functions/compose_delete_booking_email.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/shared/helpers/functions/compose_delete_booking_email.py b/src/shared/helpers/functions/compose_delete_booking_email.py index 90ee501..d46984f 100644 --- a/src/shared/helpers/functions/compose_delete_booking_email.py +++ b/src/shared/helpers/functions/compose_delete_booking_email.py @@ -254,6 +254,4 @@ def compose_deleted_user_email(user, deleted_booking: Booking): """ - message = message.format(name=name) - return message \ No newline at end of file From 7c99dd1fdcce6ad3d775e41ec4996498441f5c7c Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Wed, 8 Oct 2025 22:03:04 -0300 Subject: [PATCH 143/167] fix(generate-report): corrigindo possiveis problemas na geracao do relatorio --- .../generate_report/app/generate_report_presenter.py | 1 - .../domain/repositories/booking_repository_interface.py | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/modules/generate_report/app/generate_report_presenter.py b/src/modules/generate_report/app/generate_report_presenter.py index 537187c..06f7eed 100644 --- a/src/modules/generate_report/app/generate_report_presenter.py +++ b/src/modules/generate_report/app/generate_report_presenter.py @@ -12,7 +12,6 @@ def lambda_handler(event, context): - extractor = GenerateReportExtractor(repo) #"2025-04-03T15:00:00Z" date format current_date = datetime.datetime.now() diff --git a/src/shared/domain/repositories/booking_repository_interface.py b/src/shared/domain/repositories/booking_repository_interface.py index af654db..cc1a199 100644 --- a/src/shared/domain/repositories/booking_repository_interface.py +++ b/src/shared/domain/repositories/booking_repository_interface.py @@ -73,6 +73,13 @@ def get_all_bookings(self): ''' pass + @abstractmethod + def get_all_bookings_by_date_range(self, initial_date: int, final_date: int) -> Optional[List[Booking]]: + ''' + Returns all bookings, filtered by date range + ''' + pass + @abstractmethod def get_all_users(self) -> List[str]: ''' From cc4ac1dd7acbb52939a8d28be0af782ecb3b663e Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Thu, 9 Oct 2025 16:52:26 -0300 Subject: [PATCH 144/167] fix(generate-report): adicionando prints para debuggar o problema --- .../generate_report/app/generate_report_aggregator.py | 6 ++++++ .../generate_report/app/generate_report_transformer.py | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index f899fba..5615e78 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -16,6 +16,7 @@ def __call__(self, initial_date, final_date): #trocar os bookings por users #dps instalar as dependencias do requirements-dev.txt + users_statistics = {} @@ -116,4 +117,9 @@ def __call__(self, initial_date, final_date): #sport_statistics logic + print(f"Users: {len(users_statistics)}") + print(f"Courts: {len(court_statistics)}") + print(f"Sports: {len(sport_statistics)}") + print(f"Sample user data: {list(users_statistics.items())[:1]}") + return users_statistics, court_statistics, sport_statistics diff --git a/src/modules/generate_report/app/generate_report_transformer.py b/src/modules/generate_report/app/generate_report_transformer.py index 59adba0..3a46ef0 100644 --- a/src/modules/generate_report/app/generate_report_transformer.py +++ b/src/modules/generate_report/app/generate_report_transformer.py @@ -15,13 +15,18 @@ def __call__(self, initial_date, final_date): df_courts = pd.DataFrame.from_dict(court_statistics, orient="index") df_sports = pd.DataFrame.from_dict(sports_statistics, orient="index") + + print(f"DF Users shape: {df_users.shape}") + print(f"DF Courts shape: {df_courts.shape}") + print(f"DF Sports shape: {df_sports.shape}") + output = io.BytesIO() with pd.ExcelWriter(output, engine="xlsxwriter") as writer: df_users.to_excel(writer, sheet_name="Usuários") df_courts.to_excel(writer, sheet_name="Quadras") df_sports.to_excel(writer, sheet_name="Esportes") - + writer.close() output.seek(0) return output From 8e12cee708d49fcc54d08430779f95ae391c90f6 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Thu, 9 Oct 2025 17:11:43 -0300 Subject: [PATCH 145/167] fix(generate-report): provavel erro na manipulacao da data --- .../generate_report/app/generate_report_aggregator.py | 6 ++++-- src/shared/infra/repositories/booking_repository_dynamo.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index 5615e78..f0aed86 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -1,4 +1,5 @@ from src.shared.clients.user_api_client import UserAPIClient +from src.shared.domain.entities.booking import Booking from .generate_report_extractor import GenerateReportExtractor from typing import List @@ -15,14 +16,15 @@ def __call__(self, initial_date, final_date): #fazer logica aqui #trocar os bookings por users #dps instalar as dependencias do requirements-dev.txt - - users_statistics = {} user_api_client = UserAPIClient() for booking in bookings: + + print(booking.to_dict) + if booking.user_id not in users_statistics: user_name = user_api_client.get_user_name(booking.user_id) key = user_name if user_name is not None else booking.user_id diff --git a/src/shared/infra/repositories/booking_repository_dynamo.py b/src/shared/infra/repositories/booking_repository_dynamo.py index 1abb083..b811e5e 100644 --- a/src/shared/infra/repositories/booking_repository_dynamo.py +++ b/src/shared/infra/repositories/booking_repository_dynamo.py @@ -176,7 +176,7 @@ def get_all_bookings_by_date_range(self, initial_date: int, final_date: int) -> for item in all_items: if item.get('entity') == 'booking': booking = BookingDynamoDTO.from_dynamo(item).to_entity() - if initial_date <= booking.start_date/1000 <= final_date: + if initial_date <= booking.start_date <= final_date: all_bookings.append(booking) return all_bookings From 8430ed8fbb3cf7bcdd523127f54dcb632f9b4b2d Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Thu, 9 Oct 2025 17:26:46 -0300 Subject: [PATCH 146/167] fix(generate-report): court number inexistente no dicionario de estatisticas --- src/modules/generate_report/app/generate_report_aggregator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index f0aed86..b6eabd9 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -23,7 +23,7 @@ def __call__(self, initial_date, final_date): for booking in bookings: - print(booking.to_dict) + print(booking.to_dict()) if booking.user_id not in users_statistics: user_name = user_api_client.get_user_name(booking.user_id) @@ -43,6 +43,7 @@ def __call__(self, initial_date, final_date): 3: 0, 4: 0, 5: 0, + 6: 0, "tempo_em_quadra": 0 } From 76d9943660f66d46ebd802a0c5f131833102b7e1 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Thu, 9 Oct 2025 17:33:31 -0300 Subject: [PATCH 147/167] fix(generate-report): erro de key nos esportes novos --- .../generate_report/app/generate_report_aggregator.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index b6eabd9..4a4680d 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -38,6 +38,8 @@ def __call__(self, initial_date, final_date): "Futsal": 0, "Rugby": 0, "Ping Pong": 0, + "Beach Tennis": 0, + "NA": 0, 1: 0, 2: 0, 3: 0, @@ -72,7 +74,9 @@ def __call__(self, initial_date, final_date): "Handball": 0, "Futsal": 0, "Rugby": 0, - "Ping Pong": 0 + "Ping Pong": 0, + "Beach Tennis": 0, + "NA": 0 } sport_column = booking.sport.value @@ -104,6 +108,7 @@ def __call__(self, initial_date, final_date): "quadra 3": 0, "quadra 4": 0, "quadra 5": 0, + "quadra 6": 0, "Tempo Total Praticado": 0, } From d1dde62cf2215f473a9bbf4d4649fcc9c2247b1f Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Thu, 9 Oct 2025 17:47:46 -0300 Subject: [PATCH 148/167] fix(generate-report): ajustando identacao das estatisticas de user --- .../generate_report/app/generate_report_aggregator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index 4a4680d..e2d8e3a 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -51,10 +51,10 @@ def __call__(self, initial_date, final_date): - users_statistics[key]["reservas_feitas"] += 1 - users_statistics[key][booking.sport.value] += 1 - users_statistics[key][booking.court_number] += 1 - users_statistics[key]["tempo_em_quadra"] += booking.end_date - booking.start_date + users_statistics[key]["reservas_feitas"] += 1 + users_statistics[key][booking.sport.value] += 1 + users_statistics[key][booking.court_number] += 1 + users_statistics[key]["tempo_em_quadra"] += booking.end_date - booking.start_date #court statistics logic From 74f1771a0b42d5fc04f40a5ae4607ac187c01704 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Thu, 9 Oct 2025 18:17:35 -0300 Subject: [PATCH 149/167] fix(generate-report): erro na validacao da existencia da key no dicionario de estatisticas --- .../app/generate_report_aggregator.py | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index e2d8e3a..8b79798 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -13,21 +13,17 @@ def __call__(self, initial_date, final_date): bookings = self.extractor(initial_date, final_date) - #fazer logica aqui - #trocar os bookings por users - #dps instalar as dependencias do requirements-dev.txt - users_statistics = {} user_api_client = UserAPIClient() for booking in bookings: - print(booking.to_dict()) + user_name = user_api_client.get_user_name(booking.user_id) + key = user_name if user_name is not None else booking.user_id + + if key not in users_statistics: - if booking.user_id not in users_statistics: - user_name = user_api_client.get_user_name(booking.user_id) - key = user_name if user_name is not None else booking.user_id users_statistics[key] = { "reservas_feitas": 0, "Tennis": 0, @@ -50,11 +46,10 @@ def __call__(self, initial_date, final_date): } - - users_statistics[key]["reservas_feitas"] += 1 - users_statistics[key][booking.sport.value] += 1 - users_statistics[key][booking.court_number] += 1 - users_statistics[key]["tempo_em_quadra"] += booking.end_date - booking.start_date + users_statistics[key]["reservas_feitas"] += 1 + users_statistics[key][booking.sport.value] += 1 + users_statistics[key][booking.court_number] += 1 + users_statistics[key]["tempo_em_quadra"] += (booking.end_date - booking.start_date) / (1000 * 60 * 60) #court statistics logic @@ -125,9 +120,4 @@ def __call__(self, initial_date, final_date): #sport_statistics logic - print(f"Users: {len(users_statistics)}") - print(f"Courts: {len(court_statistics)}") - print(f"Sports: {len(sport_statistics)}") - print(f"Sample user data: {list(users_statistics.items())[:1]}") - return users_statistics, court_statistics, sport_statistics From 9b4a500a17c2bb7dffe7227a5228d2f039641591 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 13 Oct 2025 20:09:18 -0300 Subject: [PATCH 150/167] =?UTF-8?q?fix(compose-email):=20ajuste=20no=20hor?= =?UTF-8?q?=C3=A1rio=20da=20reserva=20para=20GMT-03?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/helpers/functions/compose_delete_booking_email.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/helpers/functions/compose_delete_booking_email.py b/src/shared/helpers/functions/compose_delete_booking_email.py index d46984f..1d618ea 100644 --- a/src/shared/helpers/functions/compose_delete_booking_email.py +++ b/src/shared/helpers/functions/compose_delete_booking_email.py @@ -5,8 +5,8 @@ def compose_deleted_user_email(user, deleted_booking: Booking): name = user.get('name') email = user.get('email') - data_hora_inicio = datetime.fromtimestamp(deleted_booking.start_date/1000) - data_hora_fim = datetime.fromtimestamp(deleted_booking.end_date/1000) + data_hora_inicio = datetime.fromtimestamp((deleted_booking.start_date - 3 * 60 * 60 * 1000)/1000) + data_hora_fim = datetime.fromtimestamp((deleted_booking.end_date - 3 * 60 * 60 * 1000)/1000) message = f""" From 48ed8171a824506db2371339f00a1398503ed5c1 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Mon, 13 Oct 2025 20:38:03 -0300 Subject: [PATCH 151/167] fix(bucket-stack): alterando nome do bucket para ficar generico --- iac/stacks/bucket_stack.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iac/stacks/bucket_stack.py b/iac/stacks/bucket_stack.py index 6f97846..2e28d8d 100644 --- a/iac/stacks/bucket_stack.py +++ b/iac/stacks/bucket_stack.py @@ -25,16 +25,16 @@ def __init__(self, scope: Construct, **kwargs) -> None: stage = 'DEV' self.bucket = s3.Bucket( - self, f"BACK_S3_REPORT_BUCKET_{stage}", + self, f"RESERVATION_BACK_S3_BUCKET_{stage}", # TODO remover isso quando voltar pra conta nova ou tentar deletar o bucket criado la com power user - bucket_name=f"{self.stack_name}-report-bucket-{stage}".lower(), + bucket_name=f"{self.stack_name}-bucket-{stage}".lower(), versioned=True, removal_policy=RemovalPolicy.DESTROY if not (stage == 'PROD') else RemovalPolicy.RETAIN, block_public_access=s3.BlockPublicAccess.BLOCK_ALL ) self.distribution = cloudfront.Distribution( - self, f"ReportBucketDistribution{stage}", + self, f"ReservationBucketDistribution{stage}", default_behavior=cloudfront.BehaviorOptions( origin=origins.S3Origin(self.bucket), viewer_protocol_policy=cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, From f70b44175fac610b15102a6d0c5e3467e3ea74da Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Thu, 16 Oct 2025 18:02:59 -0300 Subject: [PATCH 152/167] fix(compose-email): adicionando imagens ao e-mail de cancelamento --- src/shared/environments.py | 2 ++ .../functions/compose_delete_booking_email.py | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/shared/environments.py b/src/shared/environments.py index 2dd4c46..bfe295c 100644 --- a/src/shared/environments.py +++ b/src/shared/environments.py @@ -33,6 +33,7 @@ class Environments: mss_name: str from_email: str hidden_copy: str + s3_assets: str def _configure_local(self): from dotenv import load_dotenv @@ -68,6 +69,7 @@ def load_envs(self): self.cloud_front_distribution_domain = os.environ.get("CLOUD_FRONT_DISTRIBUTION_DOMAIN") self.from_email = os.environ.get("FROM_EMAIL") self.hidden_copy = os.environ.get("HIDDEN_COPY") + self.s3_assets = os.environ.get("S3_ASSETS_CDN") # @staticmethod # def get_user_repo() -> IUserRepository: diff --git a/src/shared/helpers/functions/compose_delete_booking_email.py b/src/shared/helpers/functions/compose_delete_booking_email.py index 1d618ea..59c2e21 100644 --- a/src/shared/helpers/functions/compose_delete_booking_email.py +++ b/src/shared/helpers/functions/compose_delete_booking_email.py @@ -1,6 +1,6 @@ from datetime import datetime from src.shared.domain.entities.booking import Booking - +from src.shared.environments import Environments def compose_deleted_user_email(user, deleted_booking: Booking): name = user.get('name') @@ -8,6 +8,8 @@ def compose_deleted_user_email(user, deleted_booking: Booking): data_hora_inicio = datetime.fromtimestamp((deleted_booking.start_date - 3 * 60 * 60 * 1000)/1000) data_hora_fim = datetime.fromtimestamp((deleted_booking.end_date - 3 * 60 * 60 * 1000)/1000) + s3_assets_endpoint = Environments.get_envs().s3_assets + '/assets' + message = f""" @@ -213,7 +215,7 @@ def compose_deleted_user_email(user, deleted_booking: Booking):

Reserva Cancelada!

- Quadra + Quadra
Olá {name},
@@ -237,10 +239,17 @@ def compose_deleted_user_email(user, deleted_booking: Booking):
foi cancelada!!
+
Motivo: CEAF / Chuva / Evento
+
+
Infelizmente sua reserva foi cancelada, por motivos de manutenção, condições climáticas, ou exceções. Dúvidas? Entre em contato pelo nosso e-mail ceaf@maua.br
+
+ +
+ -
foi cancelada!!
+
foi CANCELADA
-
Motivo: CEAF / Chuva / Evento
Infelizmente sua reserva foi cancelada, por motivos de manutenção, condições climáticas, ou exceções. Dúvidas? Entre em contato pelo nosso e-mail ceaf@maua.br
From d4dc0f22458c5726671d9ae274946b307434cdb6 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 17 Oct 2025 18:22:31 -0300 Subject: [PATCH 155/167] feat(sports-enum): adicionando esportes solicitados --- .../generate_report/app/generate_report_aggregator.py | 5 ++++- src/shared/domain/enums/sport.py | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index 8b79798..7f5ae08 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -33,8 +33,10 @@ def __call__(self, initial_date, final_date): "Handball": 0, "Futsal": 0, "Rugby": 0, - "Ping Pong": 0, + "Tênis de Mesa": 0, "Beach Tennis": 0, + "Natação": 0, + "Corrida": 0, "NA": 0, 1: 0, 2: 0, @@ -42,6 +44,7 @@ def __call__(self, initial_date, final_date): 4: 0, 5: 0, 6: 0, + 7: 0, "tempo_em_quadra": 0 } diff --git a/src/shared/domain/enums/sport.py b/src/shared/domain/enums/sport.py index a37480d..225599f 100644 --- a/src/shared/domain/enums/sport.py +++ b/src/shared/domain/enums/sport.py @@ -8,6 +8,8 @@ class SPORT(Enum): HANDBALL = "Handball" FUTSAL = "Futsal" RUGBY = "Rugby" - PING_PONG = "Ping Pong" + TENIS_DE_MESA = "Tênis de Mesa" BEACH_TENNIS = "Beach Tennis" + NATACAO = "Natação" + CORRIDA = "Corrida" NA = "NA" From d0ced7c50794880ddbdd5ef4b4490c24533f7d5a Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 17 Oct 2025 18:23:50 -0300 Subject: [PATCH 156/167] fix(sports-enum): nao deu para alterar para tenis de mesa --- src/modules/generate_report/app/generate_report_aggregator.py | 2 +- src/shared/domain/enums/sport.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index 7f5ae08..c0eef1c 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -33,7 +33,7 @@ def __call__(self, initial_date, final_date): "Handball": 0, "Futsal": 0, "Rugby": 0, - "Tênis de Mesa": 0, + "Ping Pong": 0, "Beach Tennis": 0, "Natação": 0, "Corrida": 0, diff --git a/src/shared/domain/enums/sport.py b/src/shared/domain/enums/sport.py index 225599f..c43f8e4 100644 --- a/src/shared/domain/enums/sport.py +++ b/src/shared/domain/enums/sport.py @@ -8,7 +8,7 @@ class SPORT(Enum): HANDBALL = "Handball" FUTSAL = "Futsal" RUGBY = "Rugby" - TENIS_DE_MESA = "Tênis de Mesa" + PING_PONG= "Ping Pong" BEACH_TENNIS = "Beach Tennis" NATACAO = "Natação" CORRIDA = "Corrida" From 35ace1ac6afc7a6ed2fe68ac6eb134f0500df077 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 17 Oct 2025 18:42:26 -0300 Subject: [PATCH 157/167] fix(sport-enum): arrumando o esporte natacao --- src/modules/generate_report/app/generate_report_aggregator.py | 1 + src/shared/domain/enums/sport.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index c0eef1c..c704c45 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -107,6 +107,7 @@ def __call__(self, initial_date, final_date): "quadra 4": 0, "quadra 5": 0, "quadra 6": 0, + "quadra 7": 0, "Tempo Total Praticado": 0, } diff --git a/src/shared/domain/enums/sport.py b/src/shared/domain/enums/sport.py index c43f8e4..a0ef3ff 100644 --- a/src/shared/domain/enums/sport.py +++ b/src/shared/domain/enums/sport.py @@ -10,6 +10,6 @@ class SPORT(Enum): RUGBY = "Rugby" PING_PONG= "Ping Pong" BEACH_TENNIS = "Beach Tennis" - NATACAO = "Natação" + NATACAO = "Natacao" CORRIDA = "Corrida" NA = "NA" From b0f4a68befaa6914893e0c9d23c78bb3d37f2b3a Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 17 Oct 2025 19:21:02 -0300 Subject: [PATCH 158/167] fix(generate-report): adicionando a quadra 0 --- src/modules/generate_report/app/generate_report_aggregator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index c704c45..6dfbb66 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -38,6 +38,7 @@ def __call__(self, initial_date, final_date): "Natação": 0, "Corrida": 0, "NA": 0, + 0: 0, 1: 0, 2: 0, 3: 0, From c3e276d61bc62c1c1f82114d8aac152bc27671c5 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 17 Oct 2025 21:44:06 -0300 Subject: [PATCH 159/167] fix(lambda-stack): python 3.9 -> 13.3 --- iac/stacks/lambda_stack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index 92e9ba3..8dc798f 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -19,7 +19,7 @@ def create_lambda_api_gateway_integration(self, module_name: str, method: str, a self, module_name.title(), code=lambda_.Code.from_asset(f"../src/modules/{module_name}"), handler=f"app.{module_name}_presenter.lambda_handler", - runtime=lambda_.Runtime.PYTHON_3_9, + runtime=lambda_.Runtime.PYTHON_13_3, layers=[self.lambda_layer], environment=environment_variables, timeout=Duration.seconds(15) From f2a12e71d10f5abb8d0fa7de03dd7f4d5ce07804 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 17 Oct 2025 21:45:20 -0300 Subject: [PATCH 160/167] fix(CD): mudanca de versao python para 13.3 --- .github/workflows/CD.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index e941ee6..4da84e2 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -60,7 +60,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: "3.9" + python-version: "13.3" - name: Installing Dependencies run: | From aa9cdbcbbb905113ffde0157ae250974925b6469 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 17 Oct 2025 21:48:58 -0300 Subject: [PATCH 161/167] fix(python): 3.9 -> 3.13 --- .github/workflows/CD.yml | 2 +- iac/stacks/lambda_stack.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index 4da84e2..c59b314 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -60,7 +60,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: "13.3" + python-version: "3.13" - name: Installing Dependencies run: | diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index 8dc798f..c50c794 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -19,7 +19,7 @@ def create_lambda_api_gateway_integration(self, module_name: str, method: str, a self, module_name.title(), code=lambda_.Code.from_asset(f"../src/modules/{module_name}"), handler=f"app.{module_name}_presenter.lambda_handler", - runtime=lambda_.Runtime.PYTHON_13_3, + runtime=lambda_.Runtime.PYTHON_3_13, layers=[self.lambda_layer], environment=environment_variables, timeout=Duration.seconds(15) From ad7935ac66e1971b4940fe1c6920a8d1d7f0a5b0 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 17 Oct 2025 21:53:28 -0300 Subject: [PATCH 162/167] =?UTF-8?q?fix(lambda-stack):=20versao=20atual=20d?= =?UTF-8?q?o=20lambda=20n=C3=A3o=20tem=20o=20enum=20atualizado=20das=20ver?= =?UTF-8?q?soes=20do=20python?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- iac/stacks/lambda_stack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index c50c794..c9a1d3f 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -19,7 +19,7 @@ def create_lambda_api_gateway_integration(self, module_name: str, method: str, a self, module_name.title(), code=lambda_.Code.from_asset(f"../src/modules/{module_name}"), handler=f"app.{module_name}_presenter.lambda_handler", - runtime=lambda_.Runtime.PYTHON_3_13, + runtime=lambda_.Runtime("python3.13"), layers=[self.lambda_layer], environment=environment_variables, timeout=Duration.seconds(15) From 0a7f9ca830f635da5a97077ce181a1df86a6b8c7 Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 17 Oct 2025 21:56:27 -0300 Subject: [PATCH 163/167] fix(lambda-stack): ajustando python layers --- iac/stacks/lambda_stack.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index c9a1d3f..293e6dd 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -41,7 +41,7 @@ def create_lambda_event_bridge_integration(self, module_name.title(), code=lambda_.Code.from_asset(f"../src/modules/{module_name}"), handler=f"app.{module_name}_presenter.lambda_handler", - runtime=lambda_.Runtime.PYTHON_3_9, + runtime=lambda_.Runtime("python3.13"), layers=[self.lambda_layer], environment=environment_variables, timeout=Duration.seconds(15) @@ -76,14 +76,14 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment self.lambda_layer = lambda_.LayerVersion(self, f"{self.stack_name}_Lambda_Layer_{stage}", code=lambda_.Code.from_asset("./build"), - compatible_runtimes=[lambda_.Runtime.PYTHON_3_9] + compatible_runtimes=[lambda_.Runtime("python3.13")] ) authorizer_lambda = lambda_.Function( self, "AuthorizerUserMssReservationApiLambda", code=lambda_.Code.from_asset("../src/shared/authorizer"), handler="user_mss_authorizer.lambda_handler", - runtime=lambda_.Runtime.PYTHON_3_9, + runtime=lambda_.Runtime("python3.13"), layers=[self.lambda_layer], environment=environment_variables, timeout=Duration.seconds(15) From 47c2670530bb7474ac273b479ca39492c71570ce Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Sat, 18 Oct 2025 16:12:23 -0300 Subject: [PATCH 164/167] fix(generate-report): adicionando nome de usuario nas outras estatisticas --- .../generate_report/app/generate_report_aggregator.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/modules/generate_report/app/generate_report_aggregator.py b/src/modules/generate_report/app/generate_report_aggregator.py index 6dfbb66..6d1dee8 100644 --- a/src/modules/generate_report/app/generate_report_aggregator.py +++ b/src/modules/generate_report/app/generate_report_aggregator.py @@ -60,6 +60,7 @@ def __call__(self, initial_date, final_date): court_statistics = {} for booking in bookings: + user_name = user_api_client.get_user_name(booking.user_id) court_key = booking.court_number if court_key not in court_statistics: @@ -82,7 +83,7 @@ def __call__(self, initial_date, final_date): if sport_column not in court_statistics[court_key]: court_statistics[court_key][sport_column] = 0 - user_column = f"user_{booking.user_id}" + user_column = user_name if user_column not in court_statistics[court_key]: court_statistics[court_key][user_column] = 0 @@ -97,7 +98,7 @@ def __call__(self, initial_date, final_date): for booking in bookings: sport_key = booking.sport.value - + user_name = user_api_client.get_user_name(booking.user_id) # Se ainda não existir, inicializa if sport_key not in sport_statistics: sport_statistics[sport_key] = { @@ -117,7 +118,7 @@ def __call__(self, initial_date, final_date): sport_statistics[sport_key][f"quadra {booking.court_number}"] += 1 sport_statistics[sport_key]["Tempo Total Praticado"] += (booking.end_date - booking.start_date) - user_column = f"Usuário: {booking.user_id}" + user_column = user_name if user_column not in sport_statistics[sport_key]: sport_statistics[sport_key][user_column] = 0 From bd5b9e980b7f963a59e7d474d0d857151b930602 Mon Sep 17 00:00:00 2001 From: veloy25 Date: Fri, 24 Oct 2025 16:59:51 -0300 Subject: [PATCH 165/167] fix(delete-booking): alteracao no corpo do e-mail --- .../functions/compose_delete_booking_email.py | 402 +++++++++--------- 1 file changed, 201 insertions(+), 201 deletions(-) diff --git a/src/shared/helpers/functions/compose_delete_booking_email.py b/src/shared/helpers/functions/compose_delete_booking_email.py index 81f422f..c31f7b2 100644 --- a/src/shared/helpers/functions/compose_delete_booking_email.py +++ b/src/shared/helpers/functions/compose_delete_booking_email.py @@ -11,211 +11,211 @@ def compose_deleted_user_email(user, deleted_booking: Booking): s3_assets_endpoint = Environments.get_envs().s3_assets + '/assets' message = f""" - - - - - - Reserva Cancelada - - - + + + + + + Reserva Cancelada + + +

Reserva Cancelada!

- Quadra + Quadra
Olá {name},
@@ -259,7 +259,7 @@ def compose_deleted_user_email(user, deleted_booking: Booking):
- + """ return message \ No newline at end of file From 60fe5f592c0fac3c5ce46ea31bd42007b984101d Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 24 Oct 2025 17:33:48 -0300 Subject: [PATCH 166/167] fix(compose-email): alterando corpo do email --- .../functions/compose_delete_booking_email.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/shared/helpers/functions/compose_delete_booking_email.py b/src/shared/helpers/functions/compose_delete_booking_email.py index c31f7b2..6054eaf 100644 --- a/src/shared/helpers/functions/compose_delete_booking_email.py +++ b/src/shared/helpers/functions/compose_delete_booking_email.py @@ -214,9 +214,9 @@ def compose_deleted_user_email(user, deleted_booking: Booking):

Reserva Cancelada!

- - Quadra - +
+ Quadra +
Olá {name},
@@ -245,9 +245,7 @@ def compose_deleted_user_email(user, deleted_booking: Booking):
- - - + + + + From 7af1cfb08de655968455499c1594c4ae8e8f5e5a Mon Sep 17 00:00:00 2001 From: Victor Gasperi Date: Fri, 7 Nov 2025 11:15:29 -0300 Subject: [PATCH 167/167] fix(generate-report): ajustando horario das 18h para as 11:30h --- iac/stacks/lambda_stack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iac/stacks/lambda_stack.py b/iac/stacks/lambda_stack.py index 293e6dd..dbf1138 100644 --- a/iac/stacks/lambda_stack.py +++ b/iac/stacks/lambda_stack.py @@ -201,7 +201,7 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment #does not need auth / not a route self.generate_report = self.create_lambda_event_bridge_integration( module_name="generate_report", - cron_schedule=Schedule.cron(minute="0", hour="18", week_day="FRI"), + cron_schedule=Schedule.cron(minute="30", hour="11", week_day="FRI"), environment_variables=environment_variables )