From abb02bd8f1af03075b1ead35cc3354fcfe119a2f Mon Sep 17 00:00:00 2001 From: fabidick22 Date: Thu, 7 May 2020 15:54:47 -0500 Subject: [PATCH 001/309] fix: Pass arguments to the find_all() function --- commons/data_access_layer/cosmos_db.py | 4 ++-- time_tracker_api/database.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/commons/data_access_layer/cosmos_db.py b/commons/data_access_layer/cosmos_db.py index 10bc685d..29a8a00d 100644 --- a/commons/data_access_layer/cosmos_db.py +++ b/commons/data_access_layer/cosmos_db.py @@ -255,9 +255,9 @@ class CosmosDBDao(CRUDDao): def __init__(self, repository: CosmosDBRepository): self.repository = repository - def get_all(self, conditions: dict = {}) -> list: + def get_all(self, conditions: dict = {}, **kwargs) -> list: event_ctx = self.create_event_context("read-many") - return self.repository.find_all(event_ctx, conditions=conditions) + return self.repository.find_all(event_ctx, conditions=conditions, **kwargs) def get(self, id): event_ctx = self.create_event_context("read") diff --git a/time_tracker_api/database.py b/time_tracker_api/database.py index 467f7900..1405f908 100644 --- a/time_tracker_api/database.py +++ b/time_tracker_api/database.py @@ -16,7 +16,7 @@ class CRUDDao(abc.ABC): @abc.abstractmethod - def get_all(self, conditions: dict): + def get_all(self, conditions: dict, **kwargs): raise NotImplementedError # pragma: no cover @abc.abstractmethod From 979e1035f27b2bb670b796d4766329444760c894 Mon Sep 17 00:00:00 2001 From: fabidick22 Date: Thu, 7 May 2020 15:58:08 -0500 Subject: [PATCH 002/309] fix: Refactor the project module #121 --- time_tracker_api/projects/projects_model.py | 34 +++++++++++++++------ 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/time_tracker_api/projects/projects_model.py b/time_tracker_api/projects/projects_model.py index 9374bbc9..300aa859 100644 --- a/time_tracker_api/projects/projects_model.py +++ b/time_tracker_api/projects/projects_model.py @@ -1,9 +1,8 @@ from dataclasses import dataclass - from azure.cosmos import PartitionKey - from commons.data_access_layer.cosmos_db import CosmosDBModel, CosmosDBDao, CosmosDBRepository from time_tracker_api.database import CRUDDao, APICosmosDBDao +from time_tracker_api.customers.customers_model import create_dao as customers_create_dao class ProjectDao(CRUDDao): @@ -41,12 +40,29 @@ def __str___(self): return "the project \"%s\"" % self.name # pragma: no cover -def create_dao() -> ProjectDao: - repository = CosmosDBRepository.from_definition(container_definition, - mapper=ProjectCosmosDBModel) +class ProjectCosmosDBRepository(CosmosDBRepository): + def __init__(self): + CosmosDBRepository.__init__(self, container_id=container_definition['id'], + partition_key_attribute='tenant_id', + mapper=ProjectCosmosDBModel) + + +class ProjectCosmosDBDao(APICosmosDBDao, ProjectDao): + def __init__(self, repository): + CosmosDBDao.__init__(self, repository) - class ProjectCosmosDBDao(APICosmosDBDao, ProjectDao): - def __init__(self): - CosmosDBDao.__init__(self, repository) + def get_all(self, conditions: dict = None, **kwargs) -> list: + event_ctx = self.create_event_context("read-many") + customer_dao = customers_create_dao() + customers = customer_dao.get_all(visible_only=False) + projects = self.repository.find_all(event_ctx, **kwargs) + for project in projects: + print(project.__dict__) + + return projects + + +def create_dao() -> ProjectDao: + repository = ProjectCosmosDBRepository() - return ProjectCosmosDBDao() + return ProjectCosmosDBDao(repository) From 59e8efb9b578b1f01344565fc7bc35d7c0014b27 Mon Sep 17 00:00:00 2001 From: Dickson Armijos Date: Mon, 11 May 2020 15:55:25 -0500 Subject: [PATCH 003/309] fix: Warning about mutable default argument #121 --- commons/data_access_layer/cosmos_db.py | 7 ++++--- time_tracker_api/database.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/commons/data_access_layer/cosmos_db.py b/commons/data_access_layer/cosmos_db.py index 29a8a00d..ff08fa2e 100644 --- a/commons/data_access_layer/cosmos_db.py +++ b/commons/data_access_layer/cosmos_db.py @@ -60,7 +60,7 @@ def delete_container(self, container_id: str): cosmos_helper: CosmosDBFacade = None -class CosmosDBModel(): +class CosmosDBModel: def __init__(self, data): names = set([f.name for f in dataclasses.fields(self)]) for k, v in data.items(): @@ -124,7 +124,7 @@ def create_custom_sql_conditions(custom_sql_conditions: List[str]) -> str: return '' @staticmethod - def generate_params(conditions: dict) -> dict: + def generate_params(conditions: dict) -> list: result = [] for k, v in conditions.items(): result.append({ @@ -255,7 +255,8 @@ class CosmosDBDao(CRUDDao): def __init__(self, repository: CosmosDBRepository): self.repository = repository - def get_all(self, conditions: dict = {}, **kwargs) -> list: + def get_all(self, conditions: dict = None, **kwargs) -> list: + conditions = conditions if conditions else {} event_ctx = self.create_event_context("read-many") return self.repository.find_all(event_ctx, conditions=conditions, **kwargs) diff --git a/time_tracker_api/database.py b/time_tracker_api/database.py index 1405f908..5da1ab18 100644 --- a/time_tracker_api/database.py +++ b/time_tracker_api/database.py @@ -16,7 +16,7 @@ class CRUDDao(abc.ABC): @abc.abstractmethod - def get_all(self, conditions: dict, **kwargs): + def get_all(self, conditions: dict = None, **kwargs): raise NotImplementedError # pragma: no cover @abc.abstractmethod From cd201833e4b4642c14fc749055b02470e51f7332 Mon Sep 17 00:00:00 2001 From: Dickson Armijos Date: Mon, 11 May 2020 16:26:12 -0500 Subject: [PATCH 004/309] fix: Filter projects by active customers #121 --- time_tracker_api/projects/projects_model.py | 27 ++++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/time_tracker_api/projects/projects_model.py b/time_tracker_api/projects/projects_model.py index 300aa859..d7faf48c 100644 --- a/time_tracker_api/projects/projects_model.py +++ b/time_tracker_api/projects/projects_model.py @@ -3,6 +3,7 @@ from commons.data_access_layer.cosmos_db import CosmosDBModel, CosmosDBDao, CosmosDBRepository from time_tracker_api.database import CRUDDao, APICosmosDBDao from time_tracker_api.customers.customers_model import create_dao as customers_create_dao +from time_tracker_api.customers.customers_model import CustomerCosmosDBModel class ProjectDao(CRUDDao): @@ -33,6 +34,12 @@ class ProjectCosmosDBModel(CosmosDBModel): def __init__(self, data): super(ProjectCosmosDBModel, self).__init__(data) # pragma: no cover + def __contains__(self, item): + if type(item) is CustomerCosmosDBModel: + return True if item.id == self.customer_id else False + else: + raise NotImplementedError + def __repr__(self): return '' % self.name # pragma: no cover @@ -52,14 +59,26 @@ def __init__(self, repository): CosmosDBDao.__init__(self, repository) def get_all(self, conditions: dict = None, **kwargs) -> list: + """ + Get all the projects an active client has + :param (dict) conditions: Conditions for querying the database + :param (dict) kwargs: Pass arguments + :return (list): ProjectCosmosDBModel object list + """ event_ctx = self.create_event_context("read-many") customer_dao = customers_create_dao() - customers = customer_dao.get_all(visible_only=False) + customers = customer_dao.get_all() projects = self.repository.find_all(event_ctx, **kwargs) - for project in projects: - print(project.__dict__) + active_projects = [] - return projects + for project in projects: + find = False + for customer in customers: + if customer in project: + find = True + if find: + active_projects.append(project) + return active_projects def create_dao() -> ProjectDao: From 071710416195116fc348de2b5c40ebded69b4ba3 Mon Sep 17 00:00:00 2001 From: Dickson Armijos Date: Mon, 11 May 2020 17:05:54 -0500 Subject: [PATCH 005/309] fix: Remove unnecessary variables (close #121) --- time_tracker_api/projects/projects_model.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/time_tracker_api/projects/projects_model.py b/time_tracker_api/projects/projects_model.py index d7faf48c..bca5213c 100644 --- a/time_tracker_api/projects/projects_model.py +++ b/time_tracker_api/projects/projects_model.py @@ -72,12 +72,10 @@ def get_all(self, conditions: dict = None, **kwargs) -> list: active_projects = [] for project in projects: - find = False for customer in customers: if customer in project: - find = True - if find: - active_projects.append(project) + active_projects.append(project) + break return active_projects From 5c87f0e59b3f3c2d37df18c940da84834c9860fb Mon Sep 17 00:00:00 2001 From: Dickson Armijos Date: Tue, 12 May 2020 13:31:48 -0500 Subject: [PATCH 006/309] fix: Refactor query #121 --- time_tracker_api/projects/projects_model.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/time_tracker_api/projects/projects_model.py b/time_tracker_api/projects/projects_model.py index bca5213c..3128fbee 100644 --- a/time_tracker_api/projects/projects_model.py +++ b/time_tracker_api/projects/projects_model.py @@ -68,15 +68,11 @@ def get_all(self, conditions: dict = None, **kwargs) -> list: event_ctx = self.create_event_context("read-many") customer_dao = customers_create_dao() customers = customer_dao.get_all() - projects = self.repository.find_all(event_ctx, **kwargs) - active_projects = [] - - for project in projects: - for customer in customers: - if customer in project: - active_projects.append(project) - break - return active_projects + + customers_id = [customer.id for customer in customers] + conditions = conditions if conditions else {} + custom_condition = "c.customer_id IN {}".format(str(tuple(customers_id))) + return self.repository.find_all(event_ctx, conditions, custom_sql_conditions=[custom_condition], **kwargs) def create_dao() -> ProjectDao: From c26459bd1f6a9255f94c624daa8c7af9f76c852b Mon Sep 17 00:00:00 2001 From: roberto Date: Tue, 12 May 2020 14:44:24 -0500 Subject: [PATCH 007/309] feat(time-entries): include project name in time-entries response --- .../time_entries/custom_modules/utils.py | 5 ++++ .../time_entries/time_entries_model.py | 29 ++++++++++++++++++- .../time_entries/time_entries_namespace.py | 7 +++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 time_tracker_api/time_entries/custom_modules/utils.py diff --git a/time_tracker_api/time_entries/custom_modules/utils.py b/time_tracker_api/time_entries/custom_modules/utils.py new file mode 100644 index 00000000..6ae79c1c --- /dev/null +++ b/time_tracker_api/time_entries/custom_modules/utils.py @@ -0,0 +1,5 @@ +def add_project_name_to_time_entries(time_entries, projects): + for time_entry in time_entries: + for project in projects: + if time_entry.project_id == project.id: + setattr(time_entry, 'project_name', project.name) diff --git a/time_tracker_api/time_entries/time_entries_model.py b/time_tracker_api/time_entries/time_entries_model.py index 955b5984..be27d23a 100644 --- a/time_tracker_api/time_entries/time_entries_model.py +++ b/time_tracker_api/time_entries/time_entries_model.py @@ -1,6 +1,7 @@ import abc from dataclasses import dataclass, field from typing import List, Callable +from flask import jsonify from azure.cosmos import PartitionKey from flask_restplus._http import HTTPStatus @@ -18,6 +19,10 @@ from commons.data_access_layer.database import EventContext from time_tracker_api.time_entries.custom_modules import worked_time +from time_tracker_api.time_entries.custom_modules.utils import ( + add_project_name_to_time_entries, +) +from time_tracker_api.projects import projects_model from time_tracker_api.database import CRUDDao, APICosmosDBDao from time_tracker_api.security import current_user_id @@ -106,6 +111,24 @@ def create_sql_date_range_filter(date_range: dict) -> str: else: return '' + def find( + self, + id: str, + event_context: EventContext, + peeker: 'function' = None, + visible_only=True, + mapper: Callable = None, + ): + time_entry = CosmosDBRepository.find( + self, id, event_context, peeker, visible_only, mapper, + ) + + project_dao = projects_model.create_dao() + project = project_dao.get(time_entry.project_id) + setattr(time_entry, 'project_name', project.name) + + return time_entry + def find_all( self, event_context: EventContext, @@ -119,7 +142,7 @@ def find_all( custom_params = self.generate_params(date_range) - return CosmosDBRepository.find_all( + time_entries = CosmosDBRepository.find_all( self, event_context=event_context, conditions=conditions, @@ -127,6 +150,10 @@ def find_all( custom_params=custom_params, ) + projects = project_dao.get_all() + add_project_name_to_time_entries(time_entries, projects) + return time_entries + def on_create(self, new_item_data: dict, event_context: EventContext): CosmosDBRepository.on_create(self, new_item_data, event_context) diff --git a/time_tracker_api/time_entries/time_entries_namespace.py b/time_tracker_api/time_entries/time_entries_namespace.py index df9f70c7..9455413e 100644 --- a/time_tracker_api/time_entries/time_entries_namespace.py +++ b/time_tracker_api/time_entries/time_entries_namespace.py @@ -115,6 +115,13 @@ description='User who owns the time entry', example=faker.uuid4(), ), + 'project_name': fields.String( + required=True, + title='Project Name', + max_length=50, + description='Name of the project where time-entry was registered', + example=faker.word(['mobile app', 'web app']), + ), } time_entry_response_fields.update(common_fields) From 4ed62890488f95219f183e7ebdf8326feb4ee1b6 Mon Sep 17 00:00:00 2001 From: semantic-release Date: Wed, 13 May 2020 02:23:46 +0000 Subject: [PATCH 008/309] 0.11.2 Automatically generated by python-semantic-release --- time_tracker_api/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/time_tracker_api/version.py b/time_tracker_api/version.py index ae4865cf..2b3823f1 100644 --- a/time_tracker_api/version.py +++ b/time_tracker_api/version.py @@ -1 +1 @@ -__version__ = '0.11.1' +__version__ = '0.11.2' From 3a95d9c0e522002502a6c18b1c9375331f7efa4b Mon Sep 17 00:00:00 2001 From: semantic-release Date: Wed, 13 May 2020 23:12:15 +0000 Subject: [PATCH 009/309] 0.12.0 Automatically generated by python-semantic-release --- time_tracker_api/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/time_tracker_api/version.py b/time_tracker_api/version.py index 2b3823f1..2c7bffbf 100644 --- a/time_tracker_api/version.py +++ b/time_tracker_api/version.py @@ -1 +1 @@ -__version__ = '0.11.2' +__version__ = '0.12.0' From b1fd60216ef577b718d08acef6a55e06c1b8e83c Mon Sep 17 00:00:00 2001 From: roberto Date: Thu, 14 May 2020 10:38:43 -0500 Subject: [PATCH 010/309] fix(time-entries): :bug: add instantiation of project_dao --- time_tracker_api/time_entries/time_entries_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/time_tracker_api/time_entries/time_entries_model.py b/time_tracker_api/time_entries/time_entries_model.py index be27d23a..dd13e609 100644 --- a/time_tracker_api/time_entries/time_entries_model.py +++ b/time_tracker_api/time_entries/time_entries_model.py @@ -1,7 +1,6 @@ import abc from dataclasses import dataclass, field from typing import List, Callable -from flask import jsonify from azure.cosmos import PartitionKey from flask_restplus._http import HTTPStatus @@ -150,6 +149,7 @@ def find_all( custom_params=custom_params, ) + project_dao = projects_model.create_dao() projects = project_dao.get_all() add_project_name_to_time_entries(time_entries, projects) return time_entries From 65adf5d5138a3e7f56685731a3ef8d3c26edbc79 Mon Sep 17 00:00:00 2001 From: semantic-release Date: Thu, 14 May 2020 16:10:57 +0000 Subject: [PATCH 011/309] 0.12.1 Automatically generated by python-semantic-release --- time_tracker_api/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/time_tracker_api/version.py b/time_tracker_api/version.py index 2c7bffbf..f8d90954 100644 --- a/time_tracker_api/version.py +++ b/time_tracker_api/version.py @@ -1 +1 @@ -__version__ = '0.12.0' +__version__ = '0.12.1' From f14734cc1f82d880fd9ba509641949e30f05c5b8 Mon Sep 17 00:00:00 2001 From: roberto Date: Thu, 14 May 2020 11:15:30 -0500 Subject: [PATCH 012/309] refactor(type-hints): :recycle: add Callable as type hint of functions --- commons/data_access_layer/cosmos_db.py | 17 +++++++++++------ .../time_entries/time_entries_model.py | 4 ++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/commons/data_access_layer/cosmos_db.py b/commons/data_access_layer/cosmos_db.py index b29e8e7c..cf6aa337 100644 --- a/commons/data_access_layer/cosmos_db.py +++ b/commons/data_access_layer/cosmos_db.py @@ -210,7 +210,7 @@ def find( self, id: str, event_context: EventContext, - peeker: 'function' = None, + peeker: Callable = None, visible_only=True, mapper: Callable = None, ): @@ -275,7 +275,7 @@ def partial_update( id: str, changes: dict, event_context: EventContext, - peeker: 'function' = None, + peeker: Callable = None, visible_only=True, mapper: Callable = None, ): @@ -305,7 +305,7 @@ def delete( self, id: str, event_context: EventContext, - peeker: 'function' = None, + peeker: Callable = None, mapper: Callable = None, ): return self.partial_update( @@ -348,7 +348,9 @@ def __init__(self, repository: CosmosDBRepository): def get_all(self, conditions: dict = None, **kwargs) -> list: conditions = conditions if conditions else {} event_ctx = self.create_event_context("read-many") - return self.repository.find_all(event_ctx, conditions=conditions, **kwargs) + return self.repository.find_all( + event_ctx, conditions=conditions, **kwargs + ) def get(self, id): event_ctx = self.create_event_context("read") @@ -406,6 +408,7 @@ def generate_uuid4() -> str: def get_last_day_of_month(year: int, month: int) -> int: from calendar import monthrange + return monthrange(year=year, month=month)[1] @@ -419,7 +422,9 @@ def get_current_month() -> int: def get_date_range_of_month(year: int, month: int) -> Dict[str, str]: first_day_of_month = 1 - start_date = datetime(year=year, month=month, day=first_day_of_month,tzinfo=timezone.utc) + start_date = datetime( + year=year, month=month, day=first_day_of_month, tzinfo=timezone.utc + ) last_day_of_month = get_last_day_of_month(year=year, month=month) end_date = datetime( @@ -430,7 +435,7 @@ def get_date_range_of_month(year: int, month: int) -> Dict[str, str]: minute=59, second=59, microsecond=999999, - tzinfo=timezone.utc + tzinfo=timezone.utc, ) return { diff --git a/time_tracker_api/time_entries/time_entries_model.py b/time_tracker_api/time_entries/time_entries_model.py index be27d23a..aaea297a 100644 --- a/time_tracker_api/time_entries/time_entries_model.py +++ b/time_tracker_api/time_entries/time_entries_model.py @@ -1,7 +1,6 @@ import abc from dataclasses import dataclass, field from typing import List, Callable -from flask import jsonify from azure.cosmos import PartitionKey from flask_restplus._http import HTTPStatus @@ -115,7 +114,7 @@ def find( self, id: str, event_context: EventContext, - peeker: 'function' = None, + peeker: Callable = None, visible_only=True, mapper: Callable = None, ): @@ -150,6 +149,7 @@ def find_all( custom_params=custom_params, ) + project_dao = projects_model.create_dao() projects = project_dao.get_all() add_project_name_to_time_entries(time_entries, projects) return time_entries From d94fde7df17d4e3b9faa94f73e5e52da80319ff5 Mon Sep 17 00:00:00 2001 From: Dickson Armijos Date: Thu, 14 May 2020 13:38:25 -0500 Subject: [PATCH 013/309] fix: role-based control #122 --- commons/data_access_layer/database.py | 2 +- time_tracker_api/database.py | 15 ++++++++++++--- time_tracker_api/security.py | 12 ++++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/commons/data_access_layer/database.py b/commons/data_access_layer/database.py index c1497b82..aa895339 100644 --- a/commons/data_access_layer/database.py +++ b/commons/data_access_layer/database.py @@ -33,7 +33,7 @@ def delete(self, id): raise NotImplementedError # pragma: no cover -class EventContext(): +class EventContext: def __init__(self, container_id: str, action: str, description: str = None, user_id: str = None, tenant_id: str = None, session_id: str = None, app_id: str = None): diff --git a/time_tracker_api/database.py b/time_tracker_api/database.py index 467f7900..280cc66e 100644 --- a/time_tracker_api/database.py +++ b/time_tracker_api/database.py @@ -11,7 +11,7 @@ from commons.data_access_layer.cosmos_db import CosmosDBDao from commons.data_access_layer.database import EventContext -from time_tracker_api.security import current_user_id, current_user_tenant_id +from time_tracker_api.security import current_user_id, current_user_tenant_id, current_role_user, roles class CRUDDao(abc.ABC): @@ -37,10 +37,11 @@ def delete(self, id): class ApiEventContext(EventContext): - def __init__(self, container_id: str, action: str, description: str = None, - user_id: str = None, tenant_id: str = None, session_id: str = None): + def __init__(self, container_id: str, action: str, description: str = None, user_id: str = None, + tenant_id: str = None, session_id: str = None, user_role: str = None): super(ApiEventContext, self).__init__(container_id, action, description) self._user_id = user_id + self._user_role = user_role self._tenant_id = tenant_id self._session_id = session_id @@ -50,6 +51,10 @@ def user_id(self) -> str: self._user_id = current_user_id() return self._user_id + @property + def user_role(self) -> str: + return self._user_role if self._user_role else current_role_user() + @property def tenant_id(self) -> str: if self._tenant_id is None: @@ -60,6 +65,10 @@ def tenant_id(self) -> str: def session_id(self) -> str: return self._session_id + @property + def is_admin(self): + return True if self.user_role == roles.get("admin").get("name") else False + class APICosmosDBDao(CosmosDBDao): def create_event_context(self, action: str = None, description: str = None): diff --git a/time_tracker_api/security.py b/time_tracker_api/security.py index b5919a1d..3f6643d1 100644 --- a/time_tracker_api/security.py +++ b/time_tracker_api/security.py @@ -29,6 +29,13 @@ iss_claim_pattern = re.compile(r"(.*).b2clogin.com/(?P%s)" % UUID_REGEX) +default_role = frozenset({"client-role"}) + +roles = { + "admin": {"name": "time-tracker-admin"}, + "client": {"name": "client-role"} +} + def current_user_id() -> str: oid_claim = get_token_json().get("oid") @@ -38,6 +45,11 @@ def current_user_id() -> str: return oid_claim +def current_role_user() -> str: + role_user = get_token_json().get("extension_role", None) + return role_user if role_user else roles.get("client").get("name") + + def current_user_tenant_id() -> str: iss_claim = get_token_json().get("iss") if iss_claim is None: From aae2fac4e61a8af151cf25a7be165f33144ca0d3 Mon Sep 17 00:00:00 2001 From: roberto Date: Thu, 14 May 2020 18:58:07 -0500 Subject: [PATCH 014/309] fix(time-entries): :ambulance: move logic of project names to time-entries DAO to keep compatibility with repository level functions --- .../time_entries/time_entries_model.py | 39 +++++++------------ 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/time_tracker_api/time_entries/time_entries_model.py b/time_tracker_api/time_entries/time_entries_model.py index aaea297a..ec73281a 100644 --- a/time_tracker_api/time_entries/time_entries_model.py +++ b/time_tracker_api/time_entries/time_entries_model.py @@ -110,24 +110,6 @@ def create_sql_date_range_filter(date_range: dict) -> str: else: return '' - def find( - self, - id: str, - event_context: EventContext, - peeker: Callable = None, - visible_only=True, - mapper: Callable = None, - ): - time_entry = CosmosDBRepository.find( - self, id, event_context, peeker, visible_only, mapper, - ) - - project_dao = projects_model.create_dao() - project = project_dao.get(time_entry.project_id) - setattr(time_entry, 'project_name', project.name) - - return time_entry - def find_all( self, event_context: EventContext, @@ -141,7 +123,7 @@ def find_all( custom_params = self.generate_params(date_range) - time_entries = CosmosDBRepository.find_all( + return CosmosDBRepository.find_all( self, event_context=event_context, conditions=conditions, @@ -149,11 +131,6 @@ def find_all( custom_params=custom_params, ) - project_dao = projects_model.create_dao() - projects = project_dao.get_all() - add_project_name_to_time_entries(time_entries, projects) - return time_entries - def on_create(self, new_item_data: dict, event_context: EventContext): CosmosDBRepository.on_create(self, new_item_data, event_context) @@ -310,16 +287,26 @@ def get_all(self, conditions: dict = {}) -> list: conditions.update({"owner_id": event_ctx.user_id}) date_range = self.handle_date_filter_args(args=conditions) - return self.repository.find_all( + time_entries = self.repository.find_all( event_ctx, conditions=conditions, date_range=date_range ) + project_dao = projects_model.create_dao() + projects = project_dao.get_all() + add_project_name_to_time_entries(time_entries, projects) + return time_entries + def get(self, id): event_ctx = self.create_event_context("read") - return self.repository.find( + time_entry = self.repository.find( id, event_ctx, peeker=self.check_whether_current_user_owns_item ) + project_dao = projects_model.create_dao() + project = project_dao.get(time_entry.project_id) + setattr(time_entry, 'project_name', project.name) + return time_entry + def create(self, data: dict): event_ctx = self.create_event_context("create") data['owner_id'] = event_ctx.user_id From bc12d5df95ac77ede9bc7e76f736c097eefad669 Mon Sep 17 00:00:00 2001 From: roberto Date: Thu, 14 May 2020 20:28:36 -0500 Subject: [PATCH 015/309] test(time-entries): :white_check_mark: update tests to meet changes in DAO --- .../time_entries_namespace_test.py | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/tests/time_tracker_api/time_entries/time_entries_namespace_test.py b/tests/time_tracker_api/time_entries/time_entries_namespace_test.py index 68d7c7c0..a29dbc98 100644 --- a/tests/time_tracker_api/time_entries/time_entries_namespace_test.py +++ b/tests/time_tracker_api/time_entries/time_entries_namespace_test.py @@ -146,8 +146,8 @@ def test_list_all_time_entries( time_entries_dao, ) - repository_find_all_mock = mocker.patch.object( - time_entries_dao.repository, 'find_all', return_value=[] + dao_get_all_mock = mocker.patch.object( + time_entries_dao, 'get_all', return_value=[] ) response = client.get( @@ -156,7 +156,7 @@ def test_list_all_time_entries( assert HTTPStatus.OK == response.status_code assert [] == json.loads(response.data) - repository_find_all_mock.assert_called_once() + dao_get_all_mock.assert_called_once() def test_get_time_entry_should_succeed_with_valid_id( @@ -166,8 +166,8 @@ def test_get_time_entry_should_succeed_with_valid_id( time_entries_dao, ) - repository_find_mock = mocker.patch.object( - time_entries_dao.repository, 'find', return_value=fake_time_entry + dao_get_mock = mocker.patch.object( + time_entries_dao, 'get', return_value={} ) valid_id = fake.random_int(1, 9999) @@ -179,9 +179,7 @@ def test_get_time_entry_should_succeed_with_valid_id( assert HTTPStatus.OK == response.status_code fake_time_entry == json.loads(response.data) - repository_find_mock.assert_called_once_with( - str(valid_id), ANY, peeker=ANY - ) + dao_get_mock.assert_called_once_with(str(valid_id)) def test_get_time_entry_should_response_with_unprocessable_entity_for_invalid_id_format( @@ -614,20 +612,15 @@ def test_find_all_is_called_with_generated_dates( time_entries_dao, ) - repository_find_all_mock = mocker.patch.object( - time_entries_dao.repository, 'find_all', return_value=[] + dao_get_all_mock = mocker.patch.object( + time_entries_dao, 'get_all', return_value=[] ) response = client.get(url, headers=valid_header, follow_redirects=True) - date_range = get_date_range_of_month(year, month) - conditions = {'owner_id': owner_id} - assert HTTPStatus.OK == response.status_code assert json.loads(response.data) is not None - repository_find_all_mock.assert_called_once_with( - ANY, conditions=conditions, date_range=date_range - ) + dao_get_all_mock.assert_called_once() def test_summary_is_called_with_date_range_from_worked_time_module( From 56af879776c6d7a76f72466eefa5079390959be0 Mon Sep 17 00:00:00 2001 From: semantic-release Date: Fri, 15 May 2020 13:37:18 +0000 Subject: [PATCH 016/309] 0.12.2 Automatically generated by python-semantic-release --- time_tracker_api/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/time_tracker_api/version.py b/time_tracker_api/version.py index f8d90954..92a60bdf 100644 --- a/time_tracker_api/version.py +++ b/time_tracker_api/version.py @@ -1 +1 @@ -__version__ = '0.12.1' +__version__ = '0.12.2' From ceb6ced2bdbc2e16f55e81c7e1e9891c94257b51 Mon Sep 17 00:00:00 2001 From: Dickson Armijos Date: Mon, 18 May 2020 16:55:53 -0500 Subject: [PATCH 017/309] fix: Update time-entries model #122 --- commons/data_access_layer/cosmos_db.py | 22 ++++------ time_tracker_api/projects/projects_model.py | 6 ++- .../time_entries/time_entries_model.py | 44 +++++++++++++------ .../time_entries/time_entries_namespace.py | 15 +++++++ 4 files changed, 59 insertions(+), 28 deletions(-) diff --git a/commons/data_access_layer/cosmos_db.py b/commons/data_access_layer/cosmos_db.py index b29e8e7c..396390d7 100644 --- a/commons/data_access_layer/cosmos_db.py +++ b/commons/data_access_layer/cosmos_db.py @@ -222,17 +222,8 @@ def find( function_mapper = self.get_mapper_or_dict(mapper) return function_mapper(self.check_visibility(found_item, visible_only)) - def find_all( - self, - event_context: EventContext, - conditions: dict = {}, - custom_sql_conditions: List[str] = [], - custom_params: dict = {}, - max_count=None, - offset=0, - visible_only=True, - mapper: Callable = None, - ): + def find_all(self, event_context: EventContext, conditions: dict = {}, custom_sql_conditions: List[str] = [], + custom_params: dict = {}, max_count=None, offset=0, visible_only=True, mapper: Callable = None): partition_key_value = self.find_partition_key_value(event_context) max_count = self.get_page_size_or(max_count) params = [ @@ -242,8 +233,8 @@ def find_all( ] params.extend(self.generate_params(conditions)) params.extend(custom_params) - result = self.container.query_items( - query=""" + print("before query") + query_str = """ SELECT * FROM c WHERE c.{partition_key_attribute}=@partition_key_value {conditions_clause} @@ -261,7 +252,10 @@ def find_all( custom_sql_conditions ), order_clause=self.create_sql_order_clause(), - ), + ) + + result = self.container.query_items( + query=query_str, parameters=params, partition_key=partition_key_value, max_item_count=max_count, diff --git a/time_tracker_api/projects/projects_model.py b/time_tracker_api/projects/projects_model.py index 447e5c1a..3c4a3aac 100644 --- a/time_tracker_api/projects/projects_model.py +++ b/time_tracker_api/projects/projects_model.py @@ -73,7 +73,11 @@ def get_all(self, conditions: dict = None, **kwargs) -> list: customers_id = [customer.id for customer in customers] conditions = conditions if conditions else {} custom_condition = "c.customer_id IN {}".format(str(tuple(customers_id))) - return self.repository.find_all(event_ctx, conditions, custom_sql_conditions=[custom_condition], **kwargs) + if "custom_sql_conditions" in kwargs: + kwargs["custom_sql_conditions"].append(custom_condition) + else: + kwargs["custom_sql_conditions"] = [custom_condition] + return self.repository.find_all(event_ctx, conditions, **kwargs) def create_dao() -> ProjectDao: diff --git a/time_tracker_api/time_entries/time_entries_model.py b/time_tracker_api/time_entries/time_entries_model.py index dd13e609..24978277 100644 --- a/time_tracker_api/time_entries/time_entries_model.py +++ b/time_tracker_api/time_entries/time_entries_model.py @@ -21,6 +21,7 @@ from time_tracker_api.time_entries.custom_modules.utils import ( add_project_name_to_time_entries, ) +from time_tracker_api.projects.projects_model import ProjectCosmosDBModel, create_dao as project_create_dao from time_tracker_api.projects import projects_model from time_tracker_api.database import CRUDDao, APICosmosDBDao from time_tracker_api.security import current_user_id @@ -74,6 +75,14 @@ def __init__(self, data): # pragma: no cover def running(self): return self.end_date is None + def __add__(self, other): + if type(other) is ProjectCosmosDBModel: + time_entry = self.__class__ + time_entry.project_id = other.__dict__ + return time_entry + else: + raise NotImplementedError + def __repr__(self): return '