Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
feat: TT-293 add CLI functionality in order to manage entities data i…
…n the database
  • Loading branch information
jcalarcon98 committed Jul 21, 2021
commit 1dd858317492ad23bc423359f952285aa51ccc55
27 changes: 27 additions & 0 deletions cosmosdb_emulator/cli.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/sh
COMMAND=$@
API_CONTAINER_NAME="time-tracker-backend_api"
TIME_TRACKER_CLI_URL="cosmosdb_emulator/time_tracker_cli"
TIME_TRACKER_CLI="python3 $COMMAND"
DEFAULT_SCRIPT_NAME='main.py'
FIRST_ARG=$1

if [ "$FIRST_ARG" != "$DEFAULT_SCRIPT_NAME" ]; then
echo "Do not forget that the file name is $DEFAULT_SCRIPT_NAME and needs to be sent as first parameter"
echo "For example: ./cli.sh main.py"
exit 0
fi

DATABASE_EMULATOR_KEY="C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
DATABASE_ENV_KEY=$DATABASE_MASTER_KEY

if [ "$DATABASE_EMULATOR_KEY" != "$DATABASE_ENV_KEY" ]; then
echo "You are trying to run this CLI in a non-development environment. We can not proceed with this action"
exit 0
fi

execute(){
docker exec -ti $API_CONTAINER_NAME sh -c "cd $TIME_TRACKER_CLI_URL && $TIME_TRACKER_CLI"
}

execute
30 changes: 30 additions & 0 deletions cosmosdb_emulator/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/sh

until curl -ksf "${DATABASE_ACCOUNT_URI}/_explorer/emulator.pem" -o 'cosmosdb_emulator/emulatorcert.crt'; do
echo "Waiting for Cosmosdb to start..."
sleep 10
done

echo "Development environment check..."
DATABASE_EMULATOR_KEY="C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
DATABASE_ENV_KEY=$DATABASE_MASTER_KEY

if [ "$DATABASE_EMULATOR_KEY" != "$DATABASE_ENV_KEY" ]; then
echo "You are trying to build an environment different from the development, this can have negative effects."
exit 0
fi
echo "GREAT! You are on development environment"

echo "Container cosmosemulator started."

echo "Importing SSL..."
cp cosmosdb_emulator/emulatorcert.crt /usr/local/share/ca-certificates/
cp cosmosdb_emulator/emulatorcert.crt /usr/share/ca-certificates/
update-ca-certificates --fresh
echo "Importing Containers..."
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/
python3 ./cosmosdb_emulator/init_emulator_db.py
echo "Installation succeed!!"

echo "Starting Flask!!"
flask run
63 changes: 63 additions & 0 deletions cosmosdb_emulator/init_emulator_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from azure.cosmos import exceptions, CosmosClient, PartitionKey
import os, sys

sys.path.append("/usr/src/app")

DATABASE_ACCOUNT_URI = os.environ.get('DATABASE_ACCOUNT_URI')
DATABASE_MASTER_KEY = os.environ.get('DATABASE_MASTER_KEY')
DATABASE_NAME = os.environ.get('DATABASE_NAME')

client = CosmosClient(DATABASE_ACCOUNT_URI, DATABASE_MASTER_KEY)
database = client.create_database_if_not_exists(id=DATABASE_NAME)

print("Creating TimeTracker initial initial database schema...")

try:
print('- Project')
from time_tracker_api.projects.projects_model import (
container_definition as project_definition,
)

database.create_container_if_not_exists(**project_definition)

print('- Project type')
from time_tracker_api.project_types.project_types_model import (
container_definition as project_type_definition,
)

database.create_container_if_not_exists(**project_type_definition)

print('- Activity')
from time_tracker_api.activities.activities_model import (
container_definition as activity_definition,
)

database.create_container_if_not_exists(**activity_definition)

print('- Customer')
from time_tracker_api.customers.customers_model import (
container_definition as customer_definition,
)

database.create_container_if_not_exists(**customer_definition)

print('- Time entry')
from time_tracker_api.time_entries.time_entries_model import (
container_definition as time_entry_definition,
)

database.create_container_if_not_exists(**time_entry_definition)

print('- Technology')
from time_tracker_api.technologies.technologies_model import (
container_definition as technologies_definition,
)

database.create_container_if_not_exists(**technologies_definition)
except exceptions.CosmosResourceExistsError as e:
print(
"Unexpected error while creating initial database schema: %s"
% e.message
)

print("Done!")
109 changes: 109 additions & 0 deletions cosmosdb_emulator/time_tracker_cli/data_target/cosmos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import os

from azure.cosmos import CosmosClient
from azure.cosmos.exceptions import CosmosResourceExistsError

from cosmosdb_emulator.time_tracker_cli.data_target.data_target import (
DataTarget,
)
from cosmosdb_emulator.time_tracker_cli.enums.entites import (
TimeTrackerEntities,
)
from cosmosdb_emulator.time_tracker_cli.utils.activity import get_activity_json
from cosmosdb_emulator.time_tracker_cli.utils.customer import get_customer_json
from cosmosdb_emulator.time_tracker_cli.utils.project import get_project_json
from cosmosdb_emulator.time_tracker_cli.utils.project_type import (
get_project_type_json,
)
from cosmosdb_emulator.time_tracker_cli.utils.time_entry import get_entry_json

from time_tracker_api.customers.customers_model import (
container_definition as customer_definition,
)
from time_tracker_api.project_types.project_types_model import (
container_definition as project_type_definition,
)
from time_tracker_api.projects.projects_model import (
container_definition as project_definition,
)
from time_tracker_api.activities.activities_model import (
container_definition as activity_definition,
)
from time_tracker_api.time_entries.time_entries_model import (
container_definition as time_entry_definition,
)

DATABASE_ACCOUNT_URI = os.environ.get('DATABASE_ACCOUNT_URI')
DATABASE_MASTER_KEY = os.environ.get('DATABASE_MASTER_KEY')
DATABASE_NAME = os.environ.get('DATABASE_NAME')


class CosmosDataTarget(DataTarget):
def __init__(self):
self.cosmos_client = CosmosClient(
DATABASE_ACCOUNT_URI, DATABASE_MASTER_KEY
)
self.database = self.cosmos_client.create_database_if_not_exists(
DATABASE_NAME
)

@staticmethod
def get_container_definition_by_entity_name(container_name: str) -> dict:
containers_definition = {
TimeTrackerEntities.CUSTOMER.value: customer_definition,
TimeTrackerEntities.PROJECT_TYPE.value: project_type_definition,
TimeTrackerEntities.PROJECT.value: project_definition,
TimeTrackerEntities.ACTIVITY.value: activity_definition,
TimeTrackerEntities.TIME_ENTRY.value: time_entry_definition,
}

return containers_definition.get(container_name)

@staticmethod
def get_json_method_entity_name(entity_name):
available_json = {
TimeTrackerEntities.CUSTOMER.value: get_customer_json,
TimeTrackerEntities.PROJECT_TYPE.value: get_project_type_json,
TimeTrackerEntities.PROJECT.value: get_project_json,
TimeTrackerEntities.ACTIVITY.value: get_activity_json,
TimeTrackerEntities.TIME_ENTRY.value: get_entry_json,
}

return available_json.get(entity_name)

def delete(self, entities: dict):
for entity in entities:
entity_container_definition = (
CosmosDataTarget.get_container_definition_by_entity_name(
entity
)
)
entity_container_id = entity_container_definition.get('id')
self.database.create_container_if_not_exists(
**entity_container_definition
)
self.database.delete_container(entity_container_id)

def save(self, entities: dict):
for entity in entities:
entity_container_definition = (
CosmosDataTarget.get_container_definition_by_entity_name(
entity
)
)
entities_list = entities.get(entity)
entity_container = self.database.create_container_if_not_exists(
**entity_container_definition
)

for element in entities_list:
get_json_entity = CosmosDataTarget.get_json_method_entity_name(
entity
)
json_entity = get_json_entity(element)
try:
entity_container.create_item(body=json_entity)
except CosmosResourceExistsError:
print(
f'The {entity} entity with the ID ({element.id}) already exists, so it has not been created.'
)
11 changes: 11 additions & 0 deletions cosmosdb_emulator/time_tracker_cli/data_target/data_target.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from abc import ABC, abstractmethod


class DataTarget(ABC):
@abstractmethod
def save(self, entities: dict):
pass

@abstractmethod
def delete(self, entities: set):
pass
12 changes: 12 additions & 0 deletions cosmosdb_emulator/time_tracker_cli/enums/entites.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from enum import Enum


class TimeTrackerEntities(Enum):
def __str__(self):
return str(self.value)

CUSTOMER = 'Customers'
PROJECT = 'Projects'
PROJECT_TYPE = 'Project-Types'
ACTIVITY = 'Activities'
TIME_ENTRY = 'Time-entries'
29 changes: 29 additions & 0 deletions cosmosdb_emulator/time_tracker_cli/factories/activity_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from typing import NamedTuple

from factory import Factory, Faker

from cosmosdb_emulator.time_tracker_cli.providers.common import CommonProvider
from cosmosdb_emulator.time_tracker_cli.utils.common import (
get_time_tracker_tenant_id,
)

Faker.add_provider(CommonProvider)


class Activity(NamedTuple):
id: str
name: str
description: str
status: str
tenant_id: str


class ActivityFactory(Factory):
class Meta:
model = Activity

id = Faker('uuid4')
name = Faker('job')
description = Faker('sentence', nb_words=6)
status = Faker('status')
tenant_id = get_time_tracker_tenant_id()
24 changes: 24 additions & 0 deletions cosmosdb_emulator/time_tracker_cli/factories/customer_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from typing import NamedTuple

from factory import Factory, Faker

from cosmosdb_emulator.time_tracker_cli.utils.common import (
get_time_tracker_tenant_id,
)


class Customer(NamedTuple):
id: str
name: str
description: str
tenant_id: str


class CustomerFactory(Factory):
class Meta:
model = Customer

id = Faker('uuid4')
name = Faker('company')
description = Faker('sentence', nb_words=10)
tenant_id = get_time_tracker_tenant_id()
30 changes: 30 additions & 0 deletions cosmosdb_emulator/time_tracker_cli/factories/project_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from typing import NamedTuple

from factory import Factory, Faker

from cosmosdb_emulator.time_tracker_cli.utils.common import (
get_time_tracker_tenant_id,
)


class Project(NamedTuple):
id: str
name: str
description: str
project_type_id: int
customer_id: str
tenant_id: str


class ProjectFactory(Factory):
class Meta:
model = Project

def __init__(self, project_type_id, customer_id):
self.project_type_id = project_type_id
self.customer_id = customer_id

id = Faker('uuid4')
name = Faker('name')
description = Faker('sentence', nb_words=10)
tenant_id = get_time_tracker_tenant_id()
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from typing import NamedTuple

from factory import Factory, Faker

from cosmosdb_emulator.time_tracker_cli.utils.common import (
get_time_tracker_tenant_id,
)


class ProjectType(NamedTuple):
id: str
name: str
description: str
customer_id: str
tenant_id: str


class ProjectTypeFactory(Factory):
class Meta:
model = ProjectType

def __init__(self, customer_id):
self.customer_id = customer_id

id = Faker('uuid4')
name = Faker('name')
description = Faker('sentence', nb_words=10)
tenant_id = get_time_tracker_tenant_id()
Loading