Skip to content

Commit 21811b3

Browse files
author
EliuX
committed
Implement the api ns for time entries
1 parent 777f677 commit 21811b3

File tree

12 files changed

+155
-86
lines changed

12 files changed

+155
-86
lines changed

requirements/prod.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ Flask-Script==2.0.6
2323

2424
# SQL database (MS SQL)
2525
pyodbc==4.0.30
26+
SQLAlchemy==1.3.15
27+
SQLAlchemy-Utils==0.36.3
2628
flask_sqlalchemy==2.4.1
2729

2830
# Handling requests

tests/resources.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33

44
class PersonSQLModel(db.Model, AuditedSQLModel):
5-
__tablename__ = 'tests'
5+
__tablename__ = 'test'
66
id = db.Column(db.Integer, primary_key=True)
77
name = db.Column(db.String(80), unique=False, nullable=False)
88
email = db.Column(db.String(120), unique=True, nullable=False)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from time_tracker_api.database import CRUDDao
2+
3+
4+
class ActivitiesDao(CRUDDao):
5+
pass
6+
7+
8+
def create_dao() -> ActivitiesDao:
9+
from time_tracker_api.sql_repository import db
10+
from time_tracker_api.sql_repository import SQLCRUDDao, AuditedSQLModel, SQLModel
11+
12+
class ActivitySQLModel(db.Model, SQLModel, AuditedSQLModel):
13+
__tablename__ = 'activity'
14+
id = db.Column(db.Integer, primary_key=True)
15+
16+
class ActivitiesSQLDao(SQLCRUDDao):
17+
def __init__(self):
18+
SQLCRUDDao.__init__(self, ActivitySQLModel)
19+
20+
return ActivitiesSQLDao()

time_tracker_api/activities/activities_namespace.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from faker import Faker
22
from flask_restplus import fields, Resource, Namespace
33

4+
from time_tracker_api.activities.activities_model import create_dao
45
from time_tracker_api.api import audit_fields
56

67
faker = Faker()
@@ -40,6 +41,8 @@
4041
activity_response_fields
4142
)
4243

44+
activities_dao = create_dao()
45+
4346

4447
@ns.route('')
4548
class Activities(Resource):

time_tracker_api/api.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from faker import Faker
55
from flask import current_app as app
66
from flask_restplus import Api, fields
7+
from flask_restplus.fields import Raw, to_marshallable_type, MarshallingError
8+
from werkzeug.exceptions import Conflict
79

810
faker = Faker()
911

@@ -63,7 +65,7 @@
6365
def handle_db_integrity_error(e):
6466
"""Handles errors related to data consistency"""
6567
if e.code == 'gkpj':
66-
return {'message': 'It already exists.'}, 409
68+
return {'message': 'It already exists or references data that does not exist.'}, 409
6769
else:
6870
return {'message': 'Data integrity issues.'}, 409
6971

time_tracker_api/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class ProductionConfig(Config):
3535

3636

3737
class AzureConfig(SQLConfig):
38-
pass
38+
DATABASE_URI = os.environ.get('SQLAZURECONNSTR_DATABASE_URI')
3939

4040

4141
class AzureDevelopmentConfig(DevelopmentConfig, AzureConfig):

time_tracker_api/database.py

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,23 +46,7 @@ def __call__(self, *args, **kwargs):
4646

4747

4848
class DatabaseModel:
49-
def to_dto(self):
50-
return self
51-
52-
53-
def convert_result_to_dto(f):
54-
def convert_if_necessary(result):
55-
if hasattr(result, 'to_dto'):
56-
return result.to_dto()
57-
elif issubclass(type(result), list):
58-
return list(map(convert_if_necessary, result))
59-
return result
60-
61-
def to_dto(*args, **kw):
62-
result = f(*args, **kw)
63-
return convert_if_necessary(result)
64-
65-
return to_dto
49+
pass
6650

6751

6852
seeder: Seeder = None

time_tracker_api/projects/projects_model.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import enum
22

3-
from flask import Flask
4-
53
from time_tracker_api.database import CRUDDao
64

75

@@ -18,12 +16,12 @@ class ProjectDao(CRUDDao):
1816
pass
1917

2018

21-
def create_dao(app: Flask) -> ProjectDao:
19+
def create_dao() -> ProjectDao:
2220
from time_tracker_api.sql_repository import db
2321
from time_tracker_api.sql_repository import SQLCRUDDao, AuditedSQLModel, SQLModel
2422

2523
class ProjectSQLModel(db.Model, SQLModel, AuditedSQLModel):
26-
__tablename__ = 'projects'
24+
__tablename__ = 'project'
2725
id = db.Column(db.Integer, primary_key=True)
2826
name = db.Column(db.String(50), unique=True, nullable=False)
2927
description = db.Column(db.String(250), unique=False, nullable=False)

time_tracker_api/projects/projects_namespace.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from faker import Faker
22
from flask_restplus import Namespace, Resource, fields
3+
from flask_restplus._http import HTTPStatus
34

4-
from time_tracker_api import flask_app
55
from time_tracker_api.api import audit_fields
66
from time_tracker_api.projects.projects_model import PROJECT_TYPE, create_dao
77

@@ -57,51 +57,51 @@
5757
project_response_fields
5858
)
5959

60-
project_dao = create_dao(flask_app)
60+
project_dao = create_dao()
6161

6262

6363
@ns.route('')
6464
class Projects(Resource):
6565
@ns.doc('list_projects')
66-
@ns.marshal_list_with(project, code=200)
66+
@ns.marshal_list_with(project)
6767
def get(self):
6868
"""List all projects"""
69-
return project_dao.get_all(), 200
69+
return project_dao.get_all()
7070

7171
@ns.doc('create_project')
72-
@ns.response(409, 'This project already exists')
73-
@ns.response(400, 'Bad request')
72+
@ns.response(HTTPStatus.CONFLICT, 'This project already exists')
73+
@ns.response(HTTPStatus.BAD_REQUEST, 'Invalid format or structure '
74+
'of the attributes of the project')
7475
@ns.expect(project_input)
75-
@ns.marshal_with(project, code=201)
76+
@ns.marshal_with(project, code=HTTPStatus.CREATED)
7677
def post(self):
7778
"""Create a project"""
78-
return project_dao.create(ns.payload), 201
79+
return project_dao.create(ns.payload)
7980

8081

8182
@ns.route('/<string:id>')
82-
@ns.response(404, 'Project not found')
83+
@ns.response(HTTPStatus.NOT_FOUND, 'This project does not exist')
84+
@ns.response(HTTPStatus.UNPROCESSABLE_ENTITY, 'The data has an invalid format')
8385
@ns.param('id', 'The project identifier')
8486
class Project(Resource):
8587
@ns.doc('get_project')
86-
@ns.response(422, 'The id has an invalid format')
88+
@ns.response(HTTPStatus.UNPROCESSABLE_ENTITY, 'The id has an invalid format')
8789
@ns.marshal_with(project)
8890
def get(self, id):
8991
"""Get a project"""
9092
return project_dao.get(id)
9193

9294
@ns.doc('update_project')
93-
@ns.response(422, 'The data has an invalid format.')
94-
@ns.response(409, 'This project already exists')
95+
@ns.response(HTTPStatus.CONFLICT, 'A project already exists with this new data')
9596
@ns.expect(project_input)
9697
@ns.marshal_with(project)
9798
def put(self, id):
9899
"""Update a project"""
99100
return project_dao.update(id, ns.payload)
100101

101102
@ns.doc('delete_project')
102-
@ns.response(204, 'Project deleted successfully')
103-
@ns.response(422, 'The id has an invalid format')
103+
@ns.response(HTTPStatus.NO_CONTENT, 'Project successfully deleted')
104104
def delete(self, id):
105105
"""Delete a project"""
106106
project_dao.delete(id)
107-
return None, 204
107+
return None, HTTPStatus.NO_CONTENT

time_tracker_api/sql_repository.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
from flask import Flask
44
from flask_sqlalchemy import SQLAlchemy
55

6-
from time_tracker_api.database import CRUDDao, Seeder, DatabaseModel, convert_result_to_dto
6+
from time_tracker_api.database import CRUDDao, Seeder, DatabaseModel
77
from time_tracker_api.security import current_user_id
88

9+
LIST_SEPARATOR_CHAR = ";"
10+
11+
912
db: SQLAlchemy = None
1013
SQLModel = None
1114
AuditedSQLModel = None
@@ -27,12 +30,7 @@ def init_app(app: Flask) -> None:
2730
db = SQLAlchemy(app)
2831

2932
global SQLModel
30-
31-
class SQLModelClass(DatabaseModel):
32-
def to_dto(self):
33-
return self
34-
35-
SQLModel = SQLModelClass
33+
SQLModel = DatabaseModel
3634

3735
global AuditedSQLModel
3836

@@ -85,19 +83,15 @@ class SQLCRUDDao(CRUDDao):
8583
def __init__(self, model: type):
8684
self.repository = SQLRepository(model)
8785

88-
@convert_result_to_dto
8986
def get_all(self) -> list:
9087
return self.repository.find_all()
9188

92-
@convert_result_to_dto
9389
def get(self, id):
9490
return self.repository.find(id)
9591

96-
@convert_result_to_dto
9792
def create(self, element: dict):
9893
return self.repository.create(element)
9994

100-
@convert_result_to_dto
10195
def update(self, id, data: dict):
10296
return self.repository.update(id, data)
10397

0 commit comments

Comments
 (0)