Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 7 additions & 14 deletions commons/data_access_layer/cosmos_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand All @@ -242,8 +233,7 @@ def find_all(
]
params.extend(self.generate_params(conditions))
params.extend(custom_params)
result = self.container.query_items(
query="""
query_str = """
SELECT * FROM c
WHERE c.{partition_key_attribute}=@partition_key_value
{conditions_clause}
Expand All @@ -261,7 +251,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,
Expand Down
2 changes: 1 addition & 1 deletion commons/data_access_layer/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
15 changes: 12 additions & 3 deletions time_tracker_api/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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

Expand All @@ -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:
Expand All @@ -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):
Expand Down
6 changes: 5 additions & 1 deletion time_tracker_api/projects/projects_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
10 changes: 10 additions & 0 deletions time_tracker_api/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@

iss_claim_pattern = re.compile(r"(.*).b2clogin.com/(?P<tenant_id>%s)" % UUID_REGEX)

roles = {
"admin": {"name": "time-tracker-admin"},
"client": {"name": "client-role"}
}


def current_user_id() -> str:
oid_claim = get_token_json().get("oid")
Expand All @@ -38,6 +43,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:
Expand Down
51 changes: 35 additions & 16 deletions time_tracker_api/time_entries/time_entries_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 '<Time Entry %r>' % self.start_date # pragma: no cover

Expand Down Expand Up @@ -116,21 +125,31 @@ def find_all(
conditions: dict = {},
date_range: dict = {},
):
custom_sql_conditions = []
custom_sql_conditions.append(
self.create_sql_date_range_filter(date_range)
)
custom_sql_conditions = [self.create_sql_date_range_filter(date_range)]

custom_params = self.generate_params(date_range)
if event_context.is_admin:
conditions.pop("owner_id")
# TODO should be removed when implementing a role-based permission module ↑

return CosmosDBRepository.find_all(
custom_params = self.generate_params(date_range)
time_entries = CosmosDBRepository.find_all(
self,
event_context=event_context,
conditions=conditions,
custom_sql_conditions=custom_sql_conditions,
custom_params=custom_params,
)

if time_entries:
projects_id = [project.project_id for project in time_entries]
p_ids = str(tuple(projects_id)).replace(",", "") if len(projects_id) == 1 else str(tuple(projects_id))
custom_conditions = "c.id IN {}".format(p_ids)
# TODO this must be refactored to be used from the utils module ↑
project_dao = projects_model.create_dao()
projects = project_dao.get_all(custom_sql_conditions=[custom_conditions])
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)

Expand Down Expand Up @@ -282,19 +301,12 @@ def checks_owner_and_is_not_started(cls, data: dict):
"The specified time entry is already running",
)

def get_all(self, conditions: dict = {}) -> list:
def get_all(self, conditions: dict = None, **kwargs) -> list:
event_ctx = self.create_event_context("read-many")
conditions.update({"owner_id": event_ctx.user_id})

date_range = self.handle_date_filter_args(args=conditions)
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
return self.repository.find_all(event_ctx, conditions=conditions, date_range=date_range)

def get(self, id):
event_ctx = self.create_event_context("read")
Expand Down Expand Up @@ -366,19 +378,26 @@ def get_worked_time(self, conditions: dict = {}):

@staticmethod
def handle_date_filter_args(args: dict) -> dict:
date_range = None
if 'month' and 'year' in args:
month = int(args.get("month"))
year = int(args.get("year"))
args.pop('month')
args.pop('year')
elif "start_date" and "end_date" in args:
date_range = args.copy()
if "owner_id" in date_range:
date_range.pop("owner_id")
args.pop("start_date")
args.pop("end_date")
elif 'month' in args:
month = int(args.get("month"))
year = get_current_year()
args.pop('month')
else:
month = get_current_month()
year = get_current_year()
return get_date_range_of_month(year, month)
return date_range if date_range else get_date_range_of_month(year, month)


def create_dao() -> TimeEntriesDao:
Expand Down
15 changes: 15 additions & 0 deletions time_tracker_api/time_entries/time_entries_namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,21 @@
location='args',
)

attributes_filter.add_argument(
'start_date',
required=False,
store_missing=False,
help="(Filter) Start to filter by",
location='args',
)
attributes_filter.add_argument(
'end_date',
required=False,
store_missing=False,
help="(Filter) End time to filter by",
location='args',
)


@ns.route('')
class TimeEntries(Resource):
Expand Down