Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 2 additions & 1 deletion tests/activities/activities_namespace_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

valid_activity_data = {
"name": fake.company(),
"description": fake.paragraph()
"description": fake.paragraph(),
"tenant_id": fake.uuid4()
}

fake_activity = ({
Expand Down
5 changes: 4 additions & 1 deletion tests/projects/projects_namespace_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
valid_project_data = {
"name": fake.company(),
"description": fake.paragraph(),
"type": fake.word(PROJECT_TYPE.valid_type_values()),
'customer_id': fake.uuid4(),
'tenant_id': fake.uuid4(),
'project_type_id': fake.uuid4()
}

fake_project = ({
"id": fake.random_int(1, 9999)
}).update(valid_project_data)
Expand Down
7 changes: 4 additions & 3 deletions tests/time_entries/time_entries_namespace_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
fake = Faker()

valid_time_entry_input = {
"project_id": fake.random_int(1, 9999),
"activity_id": fake.random_int(1, 9999),
"technologies": fake.words(3, ['java', 'javascript', 'python', 'azure'], unique=True),
"project_id": fake.uuid4(),
"activity_id": fake.uuid4(),
"description": fake.paragraph(nb_sentences=2),
"start_date": fake.iso8601(end_datetime=None),
"end_date": fake.iso8601(end_datetime=None),
"owner_id": fake.uuid4(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The model in LucidCharts has this field as owner only. @EliuX should we change the PR or update the LucidCharts diagram?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

"tenant_id": fake.uuid4()
}
fake_time_entry = ({
"id": fake.random_int(1, 9999),
Expand Down
6 changes: 4 additions & 2 deletions time_tracker_api/activities/activities_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ def create_dao() -> ActivityDao:
from time_tracker_api.sql_repository import db
from time_tracker_api.sql_repository import SQLCRUDDao, AuditedSQLModel

class ActivitySQLModel(db.Model, AuditedSQLModel):
class ActivitySQLModel(db.Model):
__tablename__ = 'activity'
id = db.Column(db.Integer, primary_key=True)
id = db.Column(db.String, primary_key=True)
name = db.Column(db.String(50), unique=True, nullable=False)
description = db.Column(db.String(250), unique=False, nullable=False)
deleted = db.Column(db.String, default=None)
tenant_id = db.Column(db.String, nullable=False)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's change all id fields that are supposed to be UUID to the right type. The use of String was actually a workaround.


def __repr__(self):
return '<Activity %r>' % self.name
Expand Down
10 changes: 8 additions & 2 deletions time_tracker_api/activities/activities_namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
description='Comments about the activity',
example=faker.paragraph(),
),
'tenant_id': fields.String(
required=True,
title='Identifier of Tenant',
description='Tenant this activity belongs to',
example=faker.uuid4(),
)
})

activity_response_fields = {
Expand All @@ -32,8 +38,8 @@
required=True,
title='Identifier',
description='The unique identifier',
example=faker.random_int(1, 9999),
)
example=faker.uuid4(),
),
}
activity_response_fields.update(audit_fields)

Expand Down
10 changes: 10 additions & 0 deletions time_tracker_api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@

# Common models structure
audit_fields = {
'deleted': fields.String(
readOnly=True,
required=True,
title='Last event Identifier',
description='Last event over this resource',
example=faker.uuid4(),
),
}
"""
'created_at': fields.Date(
readOnly=True,
title='Created',
Expand Down Expand Up @@ -41,6 +50,7 @@
example='anonymous',
),
}
"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not leave commented content


# APIs
from time_tracker_api.projects import projects_namespace
Expand Down
10 changes: 6 additions & 4 deletions time_tracker_api/projects/projects_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ def create_dao() -> ProjectDao:
from time_tracker_api.database import COMMENTS_MAX_LENGTH
from time_tracker_api.sql_repository import SQLCRUDDao, AuditedSQLModel

class ProjectSQLModel(db.Model, AuditedSQLModel):
class ProjectSQLModel(db.Model):
__tablename__ = 'project'
id = db.Column(db.Integer, primary_key=True)
id = db.Column(db.String, primary_key=True)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whenever you see a String that is related to a UUID, you should probably set a max number of characters, like 64 maybe.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also SQL Alchemy has multiple ways of generating UUID content and you need to do it for the attribute id.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that you are sure that such UUID works, you should probably change a bit the SQL Repository tests so that the model uses a UUID as primary key and verify that such id is actually being generated.

name = db.Column(db.String(50), unique=True, nullable=False)
description = db.Column(db.String(COMMENTS_MAX_LENGTH), unique=False, nullable=False)
type = db.Column(db.String(10), nullable=False)
active = db.Column(db.Boolean, default=True)
project_type_id = db.Column(db.String, default=None)
customer_id = db.Column(db.String, nullable=False)
deleted = db.Column(db.String, default=None)
tenant_id = db.Column(db.String, nullable=False)

def __repr__(self):
return '<Project %r>' % self.name
Expand Down
29 changes: 16 additions & 13 deletions time_tracker_api/projects/projects_namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,23 @@
description='Description about the project',
example=faker.paragraph(),
),
'type': fields.String(
required=False,
title='Type',
max_length=10,
description='If it is `Costumer`, `Training` or other type',
enum=PROJECT_TYPE.valid_type_values(),
example=faker.word(PROJECT_TYPE.valid_type_values()),
'customer_id': fields.String(
required=True,
title='Identifier of the Customer',
description='Customer this project belongs to',
example=faker.uuid4(),
),
'active': fields.Boolean(
title='Is active?',
description='Whether the project is active or not',
default=True,
example=faker.boolean(),
'tenant_id': fields.String(
required=True,
title='Identifier of Tenant',
description='Tenant this project belongs to',
example=faker.uuid4(),
),
'project_type_id': fields.String(
title='Identifier of Project type',
description='Type of the project. Used for grouping',
example=faker.uuid4(),
)
})

project_response_fields = {
Expand All @@ -46,7 +49,7 @@
required=True,
title='Identifier',
description='The unique identifier',
example=faker.random_int(1, 9999),
example=faker.uuid4(),
)
}
project_response_fields.update(audit_fields)
Expand Down
12 changes: 8 additions & 4 deletions time_tracker_api/time_entries/time_entries_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,23 @@ def create_dao() -> TimeEntriesDao:
from time_tracker_api.database import COMMENTS_MAX_LENGTH
from time_tracker_api.sql_repository import SQLCRUDDao, AuditedSQLModel

class TimeEntrySQLModel(db.Model, AuditedSQLModel):
class TimeEntrySQLModel(db.Model):
__tablename__ = 'time_entry'
id = db.Column(db.Integer, primary_key=True)
id = db.Column(db.String, primary_key=True)
description = db.Column(db.String(COMMENTS_MAX_LENGTH))
start_date = db.Column(db.DateTime, server_default=db.func.now())
end_date = db.Column(db.DateTime)
project_id = db.Column(db.Integer,
project_id = db.Column(db.String,
db.ForeignKey('project.id'),
nullable=False)
activity_id = db.Column(db.Integer,
activity_id = db.Column(db.String,
db.ForeignKey('activity.id'),
nullable=False)
technologies = db.Column(ScalarListType())
uri = db.Column(db.String(500))
owner_id = db.Column(db.String, nullable=False)
deleted = db.Column(db.String, default=None)
tenant_id = db.Column(db.String, nullable=False)

@property
def running(self):
Expand Down
43 changes: 26 additions & 17 deletions time_tracker_api/time_entries/time_entries_namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,17 @@

# TimeEntry Model
time_entry_input = ns.model('TimeEntryInput', {
'project_id': fields.Integer(
'project_id': fields.String(
required=True,
title='Project',
description='The id of the selected project',
example=faker.random_int(1, 9999),
example=faker.uuid4(),
),
'activity_id': fields.Integer(
'activity_id': fields.String(
required=True,
title='Activity',
description='The id of the selected activity',
example=faker.random_int(1, 9999),
),
'technologies': fields.List(
fields.String(
required=True,
title='Technologies',
description='Technology names used in this time-entry',
),
example=faker.words(
3,
['java', 'elixir', 'python', 'docker'],
unique=True
)
example=faker.uuid4(),
),
'description': fields.String(
title='Comments',
Expand All @@ -54,14 +43,34 @@
description='When the user ended doing this activity',
example=faker.iso8601(end_datetime=None),
),
'uri': fields.String(
title='Uniform Resource identifier',
description='Either identifier or locator',
example=faker.words(
1,
['http://example.com/mypage.html', '/some/page.html']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would specify something like a Jira ticket, e.g. TT-124 or a the URL of a Github issue, e.g. #51. Something like that, so this makes sense to the user.

),
),
'owner_id': fields.String(
required=True,
title='Owner of time entry',
description='User who owns the time entry',
example=faker.uuid4(),
),
'tenant_id': fields.String(
required=True,
title='Identifier of Tenant',
description='Tenant this project belongs to',
example=faker.uuid4(),
),
})

time_entry_response_fields = {
'id': fields.String(
readOnly=True,
title='Identifier',
description='The unique identifier',
example=faker.random_int(1, 9999),
example=faker.uuid4(),
),
'running': fields.Boolean(
readOnly=True,
Expand Down