From 94589fb6a0d9ae86843f024e2ca9767f2fb5c95b Mon Sep 17 00:00:00 2001 From: VineetBala-AOT Date: Mon, 15 Jan 2024 13:22:12 -0800 Subject: [PATCH] Fixing linting issue on timeline widget --- met-api/sample.env | 2 + .../constants/timeline_event_status.py | 2 +- met-api/src/met_api/models/widget_timeline.py | 16 +---- .../src/met_api/schemas/widget_timeline.py | 5 +- .../services/widget_timeline_service.py | 60 ++++++++++++++----- met-api/tests/conftest.py | 14 +++-- .../unit/api/test_engagement_membership.py | 1 - met-api/tests/unit/api/test_survey.py | 3 +- met-api/tests/unit/api/test_widget.py | 2 +- met-api/tests/unit/services/test_widget.py | 4 +- 10 files changed, 66 insertions(+), 43 deletions(-) diff --git a/met-api/sample.env b/met-api/sample.env index 90a2b1d60..8dc1aa73f 100644 --- a/met-api/sample.env +++ b/met-api/sample.env @@ -124,6 +124,8 @@ DATABASE_TEST_NAME= DATABASE_TEST_HOST= DATABASE_TEST_PORT= +KEYCLOAK_TEST_BASE_URL="http://localhost:8081" + # Docker database settings # If unset, uses the same settings as the main database DATABASE_DOCKER_USERNAME= diff --git a/met-api/src/met_api/constants/timeline_event_status.py b/met-api/src/met_api/constants/timeline_event_status.py index 20a52e107..43ecc6dbd 100644 --- a/met-api/src/met_api/constants/timeline_event_status.py +++ b/met-api/src/met_api/constants/timeline_event_status.py @@ -7,4 +7,4 @@ class TimelineEventStatus(IntEnum): Pending = 1 InProgress = 2 - Completed = 3 \ No newline at end of file + Completed = 3 diff --git a/met-api/src/met_api/models/widget_timeline.py b/met-api/src/met_api/models/widget_timeline.py index 68a007793..18cb732be 100755 --- a/met-api/src/met_api/models/widget_timeline.py +++ b/met-api/src/met_api/models/widget_timeline.py @@ -3,13 +3,12 @@ Manages the timeline widget """ from __future__ import annotations -from typing import Optional from sqlalchemy.sql.schema import ForeignKey from met_api.models.timeline_event import TimelineEvent -from met_api.services.timeline_event_service import TimelineEventService from .base_model import BaseModel from .db import db + class WidgetTimeline(BaseModel): # pylint: disable=too-few-public-methods, too-many-instance-attributes """Definition of the Timeline entity.""" @@ -30,16 +29,3 @@ def get_timeline(cls, timeline_id) -> list[WidgetTimeline]: .filter(WidgetTimeline.widget_id == timeline_id) \ .all() return widget_timeline - - @classmethod - def update_timeline(cls, timeline_id, timeline_data: dict) -> Optional[WidgetTimeline or None]: - """Update timeline.""" - TimelineEvent.delete_event(timeline_id) - widget_timeline: WidgetTimeline = WidgetTimeline.query.get(timeline_id) - if widget_timeline: - widget_timeline.title = timeline_data.get('title') - widget_timeline.description = timeline_data.get('description') - for event in timeline_data.get('events', []): - TimelineEventService.create_timeline_event(timeline_id, event) - widget_timeline.save() - return widget_timeline diff --git a/met-api/src/met_api/schemas/widget_timeline.py b/met-api/src/met_api/schemas/widget_timeline.py index 52ae8f133..7eeac83bc 100644 --- a/met-api/src/met_api/schemas/widget_timeline.py +++ b/met-api/src/met_api/schemas/widget_timeline.py @@ -19,7 +19,9 @@ from marshmallow import Schema from marshmallow_sqlalchemy.fields import Nested + class TimelineEventSchema(Schema): # pylint: disable=too-many-ancestors, too-few-public-methods + """This is the schema for the timeline event model.""" class Meta: # pylint: disable=too-few-public-methods """All of the fields in the Timeline Event schema.""" @@ -29,11 +31,12 @@ class Meta: # pylint: disable=too-few-public-methods class WidgetTimelineSchema(Schema): # pylint: disable=too-many-ancestors, too-few-public-methods + """This is the schema for the widget timeline model.""" class Meta: # pylint: disable=too-few-public-methods """All of the fields in the Widget Timeline schema.""" model = WidgetTimelineModel fields = ('id', 'engagement_id', 'widget_id', 'title', 'description', 'events') - + events = Nested(TimelineEventSchema, many=True) diff --git a/met-api/src/met_api/services/widget_timeline_service.py b/met-api/src/met_api/services/widget_timeline_service.py index 5cd436012..73aafbd3b 100644 --- a/met-api/src/met_api/services/widget_timeline_service.py +++ b/met-api/src/met_api/services/widget_timeline_service.py @@ -1,8 +1,13 @@ """Service for Widget Timeline management.""" +from http import HTTPStatus +from typing import Optional + from met_api.constants.membership_type import MembershipType +from met_api.exceptions.business_exception import BusinessException from met_api.models.widget_timeline import WidgetTimeline as WidgetTimelineModel from met_api.models.timeline_event import TimelineEvent as TimelineEventModel from met_api.services import authorization +from met_api.services.timeline_event_service import TimelineEventService from met_api.utils.roles import Role @@ -28,23 +33,48 @@ def create_timeline(widget_id: int, timeline_details: dict): return widget_timeline @staticmethod - def update_timeline(widget_id: int, timeline_id: int, timeline_data: dict): + def update_timeline(widget_id: int, timeline_id: int, timeline_data: dict) -> Optional[WidgetTimelineModel]: """Update timeline widget.""" - events = timeline_data.get("events") + events = timeline_data.get('events') first_event = events[0] + + WidgetTimelineService._check_update_timeline_auth(first_event) + widget_timeline: WidgetTimelineModel = WidgetTimelineModel.find_by_id(timeline_id) - authorization.check_auth(one_of_roles=(MembershipType.TEAM_MEMBER.name, - Role.EDIT_ENGAGEMENT.value), engagement_id=first_event.get('engagement_id')) + if not widget_timeline: - raise KeyError('Timeline widget not found') + raise BusinessException( + error='Timeline widget not found', + status_code=HTTPStatus.BAD_REQUEST) if widget_timeline.widget_id != widget_id: - raise ValueError('Invalid widget ID') + raise BusinessException( + error='Invalid widget ID', + status_code=HTTPStatus.BAD_REQUEST) if widget_timeline.id != timeline_id: - raise ValueError('Invalid timeline ID') + raise BusinessException( + error='Invalid timeline ID', + status_code=HTTPStatus.BAD_REQUEST) + + WidgetTimelineService._update_widget_timeline(widget_timeline, timeline_data) + + return widget_timeline - return WidgetTimelineModel.update_timeline(timeline_id, timeline_data) + @staticmethod + def _check_update_timeline_auth(first_event): + eng_id = first_event.get('engagement_id') + authorization.check_auth(one_of_roles=(MembershipType.TEAM_MEMBER.name, + Role.EDIT_ENGAGEMENT.value), engagement_id=eng_id) + + @staticmethod + def _update_widget_timeline(widget_timeline: WidgetTimelineModel, timeline_data: dict): + widget_timeline.title = timeline_data.get('title') + widget_timeline.description = timeline_data.get('description') + TimelineEventModel.delete_event(widget_timeline.id) + for event in timeline_data.get('events', []): + TimelineEventService.create_timeline_event(widget_timeline.id, event) + widget_timeline.save() @staticmethod def _create_timeline_model(widget_id: int, timeline_data: dict): @@ -56,13 +86,13 @@ def _create_timeline_model(widget_id: int, timeline_data: dict): for event in timeline_data.get('events', []): timeline_model.events.append( TimelineEventModel( - widget_id = widget_id, - engagement_id = event.get('engagement_id'), - timeline_id = event.get('timeline_id'), - description = event.get('description'), - time = event.get('time'), - position = event.get('position'), - status = event.get('status'), + widget_id=widget_id, + engagement_id=event.get('engagement_id'), + timeline_id=event.get('timeline_id'), + description=event.get('description'), + time=event.get('time'), + position=event.get('position'), + status=event.get('status'), ) ) timeline_model.flush() diff --git a/met-api/tests/conftest.py b/met-api/tests/conftest.py index 04b01da49..ef113f611 100644 --- a/met-api/tests/conftest.py +++ b/met-api/tests/conftest.py @@ -23,7 +23,7 @@ from met_api import create_app, setup_jwt_manager from met_api.auth import jwt as _jwt from met_api.models import db as _db -from tests.utilities.factory_utils import factory_staff_user_model, set_global_tenant +from tests.utilities.factory_utils import factory_staff_user_model from tests.utilities.factory_scenarios import TestJwtClaims, TestUserInfo @@ -177,42 +177,46 @@ def auth_mock(monkeypatch): # Fixture for setting up user and claims for an admin user @pytest.fixture def setup_admin_user_and_claims(jwt): + """Set up a user with the staff admin role.""" staff_info = dict(TestUserInfo.user_staff_1) user = factory_staff_user_model(user_info=staff_info) claims = copy.deepcopy(TestJwtClaims.staff_admin_role.value) claims['sub'] = str(user.external_id) - + return user, claims # Fixture for setting up user and claims for a reviewer @pytest.fixture def setup_reviewer_and_claims(jwt): + """Set up a user with the reviewer role.""" staff_info = dict(TestUserInfo.user_staff_1) user = factory_staff_user_model(user_info=staff_info) claims = copy.deepcopy(TestJwtClaims.reviewer_role.value) claims['sub'] = str(user.external_id) - + return user, claims # Fixture for setting up user and claims for an team member @pytest.fixture def setup_team_member_and_claims(jwt): + """Set up a user with the team member role.""" staff_info = dict(TestUserInfo.user_staff_1) user = factory_staff_user_model(user_info=staff_info) claims = copy.deepcopy(TestJwtClaims.team_member_role.value) claims['sub'] = str(user.external_id) - + return user, claims # Fixture for setting up user and claims for a user with no role @pytest.fixture def setup_unprivileged_user_and_claims(jwt): + """Set up a user with the no role.""" staff_info = dict(TestUserInfo.user_staff_1) user = factory_staff_user_model(user_info=staff_info) claims = copy.deepcopy(TestJwtClaims.no_role.value) claims['sub'] = str(user.external_id) - + return user, claims diff --git a/met-api/tests/unit/api/test_engagement_membership.py b/met-api/tests/unit/api/test_engagement_membership.py index 7edbf28c6..6b5805485 100644 --- a/met-api/tests/unit/api/test_engagement_membership.py +++ b/met-api/tests/unit/api/test_engagement_membership.py @@ -9,7 +9,6 @@ from met_api.constants.membership_type import MembershipType from met_api.utils.enums import ContentType, KeycloakGroupName, MembershipStatus -from tests.utilities.factory_scenarios import TestJwtClaims from tests.utilities.factory_utils import ( factory_auth_header, factory_engagement_model, factory_membership_model, factory_staff_user_model) diff --git a/met-api/tests/unit/api/test_survey.py b/met-api/tests/unit/api/test_survey.py index 527628e70..de1b0b33e 100644 --- a/met-api/tests/unit/api/test_survey.py +++ b/met-api/tests/unit/api/test_survey.py @@ -32,7 +32,7 @@ from tests.utilities.factory_scenarios import TestJwtClaims, TestSurveyInfo, TestTenantInfo, TestUserInfo from tests.utilities.factory_utils import ( factory_auth_header, factory_engagement_model, factory_membership_model, factory_staff_user_model, - factory_survey_model, factory_tenant_model, set_global_tenant) + factory_survey_model, set_global_tenant) surveys_url = '/api/surveys/' @@ -74,7 +74,6 @@ def test_create_survey_with_tenant(client, jwt, session, # Create a tenant tenant_data = TestTenantInfo.tenant2 - tenant_model = factory_tenant_model(tenant_data) tenant2_short_name = tenant_data['short_name'] tenant_2 = TenantModel.find_by_short_name(tenant2_short_name) # Verify that the tenant was created successfully diff --git a/met-api/tests/unit/api/test_widget.py b/met-api/tests/unit/api/test_widget.py index 31463db45..c4098e60f 100644 --- a/met-api/tests/unit/api/test_widget.py +++ b/met-api/tests/unit/api/test_widget.py @@ -23,7 +23,7 @@ from met_api.constants.widget import WidgetType from met_api.utils.enums import ContentType -from tests.utilities.factory_scenarios import TestJwtClaims, TestWidgetInfo, TestWidgetItemInfo +from tests.utilities.factory_scenarios import TestWidgetInfo, TestWidgetItemInfo from tests.utilities.factory_utils import factory_auth_header, factory_engagement_model, factory_widget_model diff --git a/met-api/tests/unit/services/test_widget.py b/met-api/tests/unit/services/test_widget.py index db4df2e90..286f41b29 100644 --- a/met-api/tests/unit/services/test_widget.py +++ b/met-api/tests/unit/services/test_widget.py @@ -23,8 +23,8 @@ from met_api.services.widget_service import WidgetService from tests.utilities.factory_scenarios import TestJwtClaims, TestUserInfo, TestWidgetInfo, TestWidgetItemInfo from tests.utilities.factory_utils import ( - factory_engagement_model, factory_widget_item_model, factory_widget_model, patch_token_info, - factory_staff_user_model) + factory_engagement_model, factory_staff_user_model, factory_widget_item_model, factory_widget_model, + patch_token_info) fake = Faker()