Skip to content
Closed
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
5 changes: 5 additions & 0 deletions V2/azure_time_tracker/.funcignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.git*
.vscode
local.settings.json
test
.venv
130 changes: 130 additions & 0 deletions V2/azure_time_tracker/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don’t work, or not
# install all needed dependencies.
#Pipfile.lock

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# Azure Functions artifacts
bin
obj
appsettings.json
local.settings.json
.python_packages
48 changes: 48 additions & 0 deletions V2/azure_time_tracker/activities/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from time_tracker.source.daos.activities_json_dao import ActivitiesJsonDao
from time_tracker.source.services.activity_service import ActivityService
from time_tracker.source import use_cases

import logging
import json
import azure.functions as func


JSON_PATH = 'V2/azure_time_tracker/time_tracker/source/activities_data.json'


def main(req: func.HttpRequest) -> func.HttpResponse:
logging.info(
'Python HTTP trigger function processed a request to get an activity.'
)
activity_id = req.route_params.get('id')
status_code = 200

if activity_id:
activity_use_case = use_cases.GetActivityUseCase(
create_activity_service(JSON_PATH)
)
activity = activity_use_case.get_activity_by_id(activity_id)
if activity:
response = json.dumps(activity.__dict__)
else:
response = b'Not Found'
status_code = 404
else:
activities_use_case = use_cases.GetActivitiesUseCase(
create_activity_service(JSON_PATH)
)
response = json.dumps(
[
activity.__dict__
for activity in activities_use_case.get_activities()
]
)

return func.HttpResponse(
body=response, status_code=status_code, mimetype="application/json"
)


def create_activity_service(path: str):
activity_json = ActivitiesJsonDao(path)
return ActivityService(activity_json)
18 changes: 18 additions & 0 deletions V2/azure_time_tracker/activities/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [ "get" ],
"route": "activities/{id:?}"
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
15 changes: 15 additions & 0 deletions V2/azure_time_tracker/host.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[2.*, 3.0.0)"
}
}
4 changes: 4 additions & 0 deletions V2/azure_time_tracker/proxies.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "http://json.schemastore.org/proxies",
"proxies": {}
}
5 changes: 5 additions & 0 deletions V2/azure_time_tracker/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# DO NOT include azure-functions-worker in this file
# The Python Worker is managed by Azure Functions platform
# Manually managing azure-functions-worker may cause unexpected issues

azure-functions
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from V2.source.dtos.activity import Activity
from time_tracker.source.dtos.activity import Activity
import abc
import typing

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from V2.source.daos.activities_dao import ActivitiesDao
from V2.source.dtos.activity import Activity
from time_tracker.source.daos.activities_dao import ActivitiesDao
from time_tracker.source.dtos.activity import Activity
import dataclasses
import json
import typing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@ def create_app(test_config=None):
if test_config is not None:
app.config.from_mapping(test_config)

activities_namespace = Namespace('activities', description='Endpoint for activities')
activities_namespace = Namespace(
'activities', description='Endpoint for activities'
)
activities_namespace.route('/')(activities_endpoints.Activities)
activities_namespace.route('/<string:activity_id>')(activities_endpoints.Activity)
activities_namespace.route('/<string:activity_id>')(
activities_endpoints.Activity
)

api.add_namespace(activities_namespace)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from V2.source.daos.activities_json_dao import ActivitiesJsonDao
from V2.source.services.activity_service import ActivityService
from V2.source import use_cases
from time_tracker.source.daos.activities_json_dao import ActivitiesJsonDao
from time_tracker.source.services.activity_service import ActivityService
from time_tracker.source import use_cases
from flask_restplus import Resource
from http import HTTPStatus

JSON_PATH = './V2/source/activities_data.json'
JSON_PATH = 'V2/azure_time_tracker/time_tracker/source/activities_data.json'


class Activities(Resource):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from V2.source.daos.activities_dao import ActivitiesDao
from V2.source.dtos.activity import Activity
from time_tracker.source.daos.activities_dao import ActivitiesDao
from time_tracker.source.dtos.activity import Activity
import typing


Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from V2.source.services.activity_service import ActivityService
from V2.source.dtos.activity import Activity
from time_tracker.source.services.activity_service import ActivityService
from time_tracker.source.dtos.activity import Activity
import typing


Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from V2.source.services.activity_service import ActivityService
from V2.source.dtos.activity import Activity
from time_tracker.source.services.activity_service import ActivityService
from time_tracker.source.dtos.activity import Activity


class GetActivityUseCase:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
from V2.source.entry_points.flask_api import create_app
import json
import pytest
import typing
from flask.testing import FlaskClient
from http import HTTPStatus
from faker import Faker
import shutil


@pytest.fixture
def client():
app = create_app({'TESTING': True})
with app.test_client() as client:
yield client


@pytest.fixture
def activities_json(tmpdir_factory):
temporary_directory = tmpdir_factory.mktemp("tmp")
Expand Down Expand Up @@ -54,33 +42,3 @@ def activities_json(tmpdir_factory):

yield activities_json
shutil.rmtree(temporary_directory)


def test_test__activity_endpoint__returns_all_activities(
client: FlaskClient, activities_json: typing.List[dict]
):
response = client.get("/activities/")
json_data = json.loads(response.data)

assert response.status_code == HTTPStatus.OK
assert json_data == activities_json


def test__activity_endpoint__returns_an_activity__when_activity_matches_its_id(
client: FlaskClient, activities_json: typing.List[dict]
):
response = client.get("/activities/%s" % activities_json[0]['id'])
json_data = json.loads(response.data)

assert response.status_code == HTTPStatus.OK
assert json_data == activities_json[0]


def test__activity_endpoint__returns_a_not_found_status__when_no_activity_matches_its_id(
client: FlaskClient,
):
response = client.get("/activities/%s" % Faker().uuid4())
json_data = json.loads(response.data)

assert response.status_code == HTTPStatus.NOT_FOUND
assert json_data['message'] == 'Activity not found'
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from activities import main
import azure.functions as func
import json
import typing


def test__activity_azure_endpoint__returns_all_activities(
activities_json: typing.List[dict],
):
req = func.HttpRequest(method='GET', body=None, url='/api/activities')

response = main(req)
activities_json_data = response.get_body().decode("utf-8")

assert response.status_code == 200
assert activities_json_data == json.dumps(activities_json)


def test__activity_azure_endpoint__returns_an_activity__when_activity_matches_its_id(
activities_json: typing.List[dict],
):
req = func.HttpRequest(
method='GET',
body=None,
url='/api/activities/',
route_params={"id": activities_json[0]['id']},
)

response = main(req)
activitiy_json_data = response.get_body().decode("utf-8")

assert response.status_code == 200
assert activitiy_json_data == json.dumps(activities_json[0])
Loading