Skip to content

Commit 3767cda

Browse files
authored
feat : add project type and customer models (#68)
Fixes #67
1 parent 51091f5 commit 3767cda

File tree

5 files changed

+288
-0
lines changed

5 files changed

+288
-0
lines changed

time_tracker_api/api.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@
3636

3737
api.add_namespace(time_entries_namespace.ns)
3838

39+
from time_tracker_api.project_types import project_types_namespace
40+
41+
api.add_namespace(project_types_namespace.ns)
42+
43+
from time_tracker_api.customers import customers_namespace
44+
45+
api.add_namespace(customers_namespace.ns)
46+
3947
"""
4048
Error handlers
4149
"""
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from time_tracker_api.database import CRUDDao
2+
3+
4+
class CustomerDao(CRUDDao):
5+
pass
6+
7+
8+
def create_dao() -> CustomerDao:
9+
from time_tracker_api.sql_repository import db
10+
from time_tracker_api.database import COMMENTS_MAX_LENGTH
11+
from time_tracker_api.sql_repository import SQLCRUDDao
12+
from sqlalchemy_utils import UUIDType
13+
import uuid
14+
15+
class CustomerSQLModel(db.Model):
16+
__tablename__ = 'customer'
17+
id = db.Column(UUIDType(binary=False), primary_key=True, default=uuid.uuid4)
18+
name = db.Column(db.String(50), unique=True, nullable=False)
19+
description = db.Column(db.String(COMMENTS_MAX_LENGTH), unique=False, nullable=False)
20+
deleted = db.Column(UUIDType(binary=False), default=uuid.uuid4)
21+
tenant_id = db.Column(UUIDType(binary=False), default=uuid.uuid4)
22+
23+
def __repr__(self):
24+
return '<Customer %r>' % self.name
25+
26+
def __str___(self):
27+
return "the customer \"%s\"" % self.name
28+
29+
class CustomerSQLDao(SQLCRUDDao):
30+
def __init__(self):
31+
SQLCRUDDao.__init__(self, CustomerSQLModel)
32+
33+
return CustomerSQLDao()
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
from faker import Faker
2+
from flask_restplus import Namespace, Resource, fields
3+
from flask_restplus._http import HTTPStatus
4+
5+
from time_tracker_api.api import audit_fields
6+
from time_tracker_api.customers.customers_model import create_dao
7+
8+
faker = Faker()
9+
10+
ns = Namespace('customers', description='API for customers')
11+
12+
# Customer Model
13+
customer_input = ns.model('CustomerInput', {
14+
'name': fields.String(
15+
required=True,
16+
title='Name',
17+
max_length=50,
18+
description='Name of the customer',
19+
example=faker.company(),
20+
),
21+
'description': fields.String(
22+
title='Description',
23+
max_length=250,
24+
description='Description about the customer',
25+
example=faker.paragraph(),
26+
),
27+
'tenant_id': fields.String(
28+
required=True,
29+
title='Identifier of Tenant',
30+
description='Tenant this customer belongs to',
31+
example=faker.uuid4(),
32+
),
33+
})
34+
35+
customer_response_fields = {
36+
'id': fields.String(
37+
readOnly=True,
38+
required=True,
39+
title='Identifier',
40+
description='The unique identifier',
41+
example=faker.uuid4(),
42+
)
43+
}
44+
customer_response_fields.update(audit_fields)
45+
46+
customer = ns.inherit(
47+
'Customer',
48+
customer_input,
49+
customer_response_fields
50+
)
51+
52+
customer_dao = create_dao()
53+
54+
55+
@ns.route('')
56+
class Customers(Resource):
57+
@ns.doc('list_customers')
58+
@ns.marshal_list_with(customer)
59+
def get(self):
60+
"""List all customers"""
61+
return customer_dao.get_all()
62+
63+
@ns.doc('create_customer')
64+
@ns.response(HTTPStatus.CONFLICT, 'This customer already exists')
65+
@ns.response(HTTPStatus.BAD_REQUEST, 'Invalid format or structure '
66+
'of the attributes of the customer')
67+
@ns.expect(customer_input)
68+
@ns.marshal_with(customer, code=HTTPStatus.CREATED)
69+
def post(self):
70+
"""Create a customer"""
71+
return customer_dao.create(ns.payload), HTTPStatus.CREATED
72+
73+
74+
@ns.route('/<string:id>')
75+
@ns.response(HTTPStatus.NOT_FOUND, 'This customer does not exist')
76+
@ns.response(HTTPStatus.UNPROCESSABLE_ENTITY, 'The data has an invalid format')
77+
@ns.param('id', 'The customer identifier')
78+
class Customer(Resource):
79+
@ns.doc('get_customer')
80+
@ns.response(HTTPStatus.UNPROCESSABLE_ENTITY, 'The id has an invalid format')
81+
@ns.marshal_with(customer)
82+
def get(self, id):
83+
"""Get a customer"""
84+
return customer_dao.get(id)
85+
86+
@ns.doc('update_customer')
87+
@ns.response(HTTPStatus.BAD_REQUEST, 'Invalid format or structure '
88+
'of the attributes of the customer')
89+
@ns.response(HTTPStatus.CONFLICT, 'A customer already exists with this new data')
90+
@ns.expect(customer_input)
91+
@ns.marshal_with(customer)
92+
def put(self, id):
93+
"""Update a customer"""
94+
return customer_dao.update(id, ns.payload)
95+
96+
@ns.doc('delete_customer')
97+
@ns.response(HTTPStatus.NO_CONTENT, 'Customer successfully deleted')
98+
def delete(self, id):
99+
"""Delete a customer"""
100+
customer_dao.delete(id)
101+
return None, HTTPStatus.NO_CONTENT
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from time_tracker_api.database import CRUDDao
2+
3+
4+
class ProjectTypeDao(CRUDDao):
5+
pass
6+
7+
8+
def create_dao() -> ProjectTypeDao:
9+
from time_tracker_api.sql_repository import db
10+
from time_tracker_api.database import COMMENTS_MAX_LENGTH
11+
from time_tracker_api.sql_repository import SQLCRUDDao
12+
from sqlalchemy_utils import UUIDType
13+
import uuid
14+
15+
class ProjectTypeSQLModel(db.Model):
16+
__tablename__ = 'project_type'
17+
id = db.Column(UUIDType(binary=False), primary_key=True, default=uuid.uuid4)
18+
name = db.Column(db.String(50), unique=True, nullable=False)
19+
description = db.Column(db.String(COMMENTS_MAX_LENGTH), unique=False, nullable=False)
20+
parent_id = db.Column(UUIDType(binary=False), default=uuid.uuid4)
21+
customer_id = db.Column(UUIDType(binary=False), default=uuid.uuid4)
22+
deleted = db.Column(UUIDType(binary=False), default=uuid.uuid4)
23+
tenant_id = db.Column(UUIDType(binary=False), default=uuid.uuid4)
24+
25+
def __repr__(self):
26+
return '<ProjectType %r>' % self.name
27+
28+
def __str___(self):
29+
return "the project type \"%s\"" % self.name
30+
31+
class ProjectTypeSQLDao(SQLCRUDDao):
32+
def __init__(self):
33+
SQLCRUDDao.__init__(self, ProjectTypeSQLModel)
34+
35+
return ProjectTypeSQLDao()
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
from faker import Faker
2+
from flask_restplus import Namespace, Resource, fields
3+
from flask_restplus._http import HTTPStatus
4+
5+
from time_tracker_api.api import audit_fields
6+
from time_tracker_api.project_types.project_types_model import create_dao
7+
8+
faker = Faker()
9+
10+
ns = Namespace('project-types', description='API for project types')
11+
12+
# ProjectType Model
13+
project_type_input = ns.model('ProjectTypeInput', {
14+
'name': fields.String(
15+
required=True,
16+
title='Name',
17+
max_length=50,
18+
description='Name of the project type',
19+
example=faker.company(),
20+
),
21+
'description': fields.String(
22+
title='Description',
23+
max_length=250,
24+
description='Description about the project type',
25+
example=faker.paragraph(),
26+
),
27+
'customer_id': fields.String(
28+
title='Identifier of the Customer',
29+
description='Customer this project type belongs to',
30+
example=faker.uuid4(),
31+
),
32+
'tenant_id': fields.String(
33+
required=True,
34+
title='Identifier of Tenant',
35+
description='Tenant this project type belongs to',
36+
example=faker.uuid4(),
37+
),
38+
'parent_id': fields.String(
39+
title='Identifier of Parent of the project type',
40+
description='Defines a self reference of the model ProjectType',
41+
example=faker.uuid4(),
42+
)
43+
})
44+
45+
project_type_response_fields = {
46+
'id': fields.String(
47+
readOnly=True,
48+
required=True,
49+
title='Identifier',
50+
description='The unique identifier',
51+
example=faker.uuid4(),
52+
)
53+
}
54+
project_type_response_fields.update(audit_fields)
55+
56+
project_type = ns.inherit(
57+
'ProjectType',
58+
project_type_input,
59+
project_type_response_fields
60+
)
61+
62+
project_type_dao = create_dao()
63+
64+
65+
@ns.route('')
66+
class ProjectTypes(Resource):
67+
@ns.doc('list_project_types')
68+
@ns.marshal_list_with(project_type)
69+
def get(self):
70+
"""List all project types"""
71+
return project_type_dao.get_all()
72+
73+
@ns.doc('create_project_type')
74+
@ns.response(HTTPStatus.CONFLICT, 'This project type already exists')
75+
@ns.response(HTTPStatus.BAD_REQUEST, 'Invalid format or structure '
76+
'of the attributes of the project type')
77+
@ns.expect(project_type_input)
78+
@ns.marshal_with(project_type, code=HTTPStatus.CREATED)
79+
def post(self):
80+
"""Create a project type"""
81+
return project_type_dao.create(ns.payload), HTTPStatus.CREATED
82+
83+
84+
@ns.route('/<string:id>')
85+
@ns.response(HTTPStatus.NOT_FOUND, 'This project type does not exist')
86+
@ns.response(HTTPStatus.UNPROCESSABLE_ENTITY, 'The data has an invalid format')
87+
@ns.param('id', 'The project type identifier')
88+
class ProjectType(Resource):
89+
@ns.doc('get_project_type')
90+
@ns.response(HTTPStatus.UNPROCESSABLE_ENTITY, 'The id has an invalid format')
91+
@ns.marshal_with(project_type)
92+
def get(self, id):
93+
"""Get a project type"""
94+
return project_type_dao.get(id)
95+
96+
@ns.doc('update_project_type')
97+
@ns.response(HTTPStatus.BAD_REQUEST, 'Invalid format or structure '
98+
'of the attributes of the project type')
99+
@ns.response(HTTPStatus.CONFLICT, 'A project type already exists with this new data')
100+
@ns.expect(project_type_input)
101+
@ns.marshal_with(project_type)
102+
def put(self, id):
103+
"""Update a project type"""
104+
return project_type_dao.update(id, ns.payload)
105+
106+
@ns.doc('delete_project_type')
107+
@ns.response(HTTPStatus.NO_CONTENT, 'Project Type successfully deleted')
108+
def delete(self, id):
109+
"""Delete a project type"""
110+
project_type_dao.delete(id)
111+
return None, HTTPStatus.NO_CONTENT

0 commit comments

Comments
 (0)