Skip to content

Commit af1b9ee

Browse files
varun2948pre-commit-ci[bot]spwoodcock
authored
feat: endpoints for task comments (#1171)
* feat: taskcomment model added * feat: crud task comment * feat: task comment crud api route added * feat: task comment schema added * fix: removed use of dictionary to object * fix: change row name by id with task_comment_id * fix: renamed comment_task_id_to_id * feat: migration add-task-comment * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * renamed task_comment index * fix: removed new table migration for taskcomment * feat: used task_history table to get task_comment and add task_comment Using task_history table maintained action row as COMMENT and added comment * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix: linting issue * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * refactor: improve sql, use query params, fix linting errors * refactor: minor code cleanup bundled in merge --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: spwoodcock <sam.woodcock@protonmail.com>
1 parent c88355e commit af1b9ee

File tree

6 files changed

+193
-6
lines changed

6 files changed

+193
-6
lines changed

src/backend/app/db/db_models.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,32 @@ class DbTaskHistory(Base):
392392
)
393393

394394

395+
class TaskComment(Base):
396+
"""Represents a comment associated with a task."""
397+
398+
__tablename__ = "task_comment"
399+
400+
id = Column(Integer, primary_key=True)
401+
task_id = Column(Integer, nullable=False)
402+
project_id = Column(Integer, ForeignKey("projects.id"), index=True)
403+
comment_text = Column(String)
404+
commented_by = Column(
405+
BigInteger,
406+
ForeignKey("users.id", name="fk_users"),
407+
index=True,
408+
nullable=False,
409+
)
410+
created_at = Column(DateTime, nullable=False, default=timestamp)
411+
412+
__table_args__ = (
413+
ForeignKeyConstraint(
414+
[task_id, project_id], ["tasks.id", "tasks.project_id"], name="fk_tasks"
415+
),
416+
Index("idx_task_comment_composite", "task_id", "project_id"),
417+
{},
418+
)
419+
420+
395421
class DbTask(Base):
396422
"""Describes an individual mapping Task."""
397423

src/backend/app/db/postgis_utils.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,6 @@ def parse_and_filter_geojson(
246246
geojson_str: str, filter: bool = True
247247
) -> Optional[geojson.FeatureCollection]:
248248
"""Parse geojson string and filter out incomaptible geometries."""
249-
log.debug("Parsing geojson string")
250249
geojson_parsed = geojson.loads(geojson_str)
251250
if isinstance(geojson_parsed, geojson.FeatureCollection):
252251
log.debug("Already in FeatureCollection format, skipping reparse")
@@ -255,7 +254,7 @@ def parse_and_filter_geojson(
255254
log.debug("Converting Feature to FeatureCollection")
256255
featcol = geojson.FeatureCollection(features=[geojson_parsed])
257256
else:
258-
log.debug("Converting geometry to FeatureCollection")
257+
log.debug("Converting Geometry to FeatureCollection")
259258
featcol = geojson.FeatureCollection(
260259
features=[geojson.Feature(geometry=geojson_parsed)]
261260
)

src/backend/app/projects/project_crud.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,6 @@ def remove_z_dimension(coord):
594594
meters=meters,
595595
)
596596
for index, poly in enumerate(tasks["features"]):
597-
log.debug(poly)
598597
db_task = db_models.DbTask(
599598
project_id=project_id,
600599
outline=wkblib.dumps(shape(poly["geometry"]), hex=True),
@@ -607,8 +606,6 @@ def remove_z_dimension(coord):
607606
)
608607
db.add(db_task)
609608
db.commit()
610-
611-
# FIXME: write to tasks table
612609
return True
613610

614611

src/backend/app/tasks/tasks_crud.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from sqlalchemy.orm import Session
3030
from sqlalchemy.sql import text
3131

32+
from app.auth.osm import AuthUser
3233
from app.central import central_crud
3334
from app.db import database, db_models
3435
from app.models.enums import (
@@ -315,6 +316,103 @@ async def edit_task_boundary(db: Session, task_id: int, boundary: str):
315316
return True
316317

317318

319+
async def get_task_comments(db: Session, project_id: int, task_id: int):
320+
"""Get a list of tasks id for a project."""
321+
query = text(
322+
"""
323+
SELECT
324+
task_history.id, task_history.task_id, users.username,
325+
task_history.action_text, task_history.action_date
326+
FROM
327+
task_history
328+
LEFT JOIN
329+
users ON task_history.user_id = users.id
330+
WHERE
331+
project_id = :project_id
332+
AND task_id = :task_id
333+
AND action = 'COMMENT'
334+
"""
335+
)
336+
337+
params = {"project_id": project_id, "task_id": task_id}
338+
339+
result = db.execute(query, params)
340+
341+
# Convert the result to a list of dictionaries
342+
result_dict_list = [
343+
{
344+
"id": row[0],
345+
"task_id": row[1],
346+
"commented_by": row[2],
347+
"comment": row[3],
348+
"created_at": row[4],
349+
}
350+
for row in result.fetchall()
351+
]
352+
353+
return result_dict_list
354+
355+
356+
async def add_task_comments(
357+
db: Session, comment: tasks_schemas.TaskCommentBase, user_data: AuthUser
358+
):
359+
"""Add a comment to a task.
360+
361+
Parameters:
362+
- db: SQLAlchemy database session
363+
- comment: TaskCommentBase instance containing the comment details
364+
- user_data: AuthUser instance containing the user details
365+
366+
Returns:
367+
- Dictionary with the details of the added comment
368+
"""
369+
currentdate = datetime.now()
370+
# Construct the query to insert the comment and retrieve inserted comment details
371+
query = text(
372+
"""
373+
INSERT INTO task_history (
374+
project_id, task_id, action, action_text,
375+
action_date, user_id
376+
)
377+
VALUES (
378+
:project_id, :task_id, 'COMMENT', :comment_text,
379+
:current_date, :user_id
380+
)
381+
RETURNING
382+
task_history.id,
383+
task_history.task_id,
384+
(SELECT username FROM users WHERE id = task_history.user_id) AS user_id,
385+
task_history.action_text,
386+
task_history.action_date;
387+
"""
388+
)
389+
390+
# Define a dictionary with the parameter values
391+
params = {
392+
"project_id": comment.project_id,
393+
"task_id": comment.task_id,
394+
"comment_text": comment.comment,
395+
"current_date": currentdate,
396+
"user_id": user_data.id,
397+
}
398+
399+
# Execute the query with the named parameters and commit the transaction
400+
result = db.execute(query, params)
401+
db.commit()
402+
403+
# Fetch the first row of the query result
404+
row = result.fetchone()
405+
406+
# Return the details of the added comment as a dictionary
407+
return {
408+
"id": row[0],
409+
"task_id": row[1],
410+
"commented_by": row[2],
411+
"comment": row[3],
412+
"created_at": row[4],
413+
}
414+
415+
318416
async def update_task_history(
319417
tasks: List[tasks_schemas.Task], db: Session = Depends(database.get_db)
320418
):

src/backend/app/tasks/tasks_routes.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from sqlalchemy.orm import Session
2626
from sqlalchemy.sql import text
2727

28-
from app.auth.osm import AuthUser
28+
from app.auth.osm import AuthUser, login_required
2929
from app.auth.roles import get_uid, mapper, project_admin
3030
from app.central import central_crud
3131
from app.db import database
@@ -196,6 +196,47 @@ async def task_features_count(
196196
return data
197197

198198

199+
@router.get("/task-comments/", response_model=list[tasks_schemas.TaskCommentResponse])
200+
async def task_comments(
201+
project_id: int,
202+
task_id: int,
203+
db: Session = Depends(database.get_db),
204+
):
205+
"""Retrieve a list of task comments for a specific project and task.
206+
207+
Args:
208+
project_id (int): The ID of the project.
209+
task_id (int): The ID of the task.
210+
db (Session, optional): The database session.
211+
212+
Returns:
213+
List[tasks_schemas.TaskCommentResponse]: A list of task comments.
214+
"""
215+
task_comment_list = await tasks_crud.get_task_comments(db, project_id, task_id)
216+
217+
return task_comment_list
218+
219+
220+
@router.post("/task-comments/", response_model=tasks_schemas.TaskCommentResponse)
221+
async def add_task_comments(
222+
comment: tasks_schemas.TaskCommentRequest,
223+
db: Session = Depends(database.get_db),
224+
user_data: AuthUser = Depends(login_required),
225+
):
226+
"""Create a new task comment.
227+
228+
Parameters:
229+
comment (TaskCommentRequest): The task comment to be created.
230+
db (Session): The database session.
231+
user_data (AuthUser): The authenticated user.
232+
233+
Returns:
234+
TaskCommentResponse: The created task comment.
235+
"""
236+
task_comment_list = await tasks_crud.add_task_comments(db, comment, user_data)
237+
return task_comment_list
238+
239+
199240
@router.get("/activity/", response_model=List[tasks_schemas.TaskHistoryCount])
200241
async def task_activity(
201242
project_id: int, days: int = 10, db: Session = Depends(database.get_db)

src/backend/app/tasks/tasks_schemas.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,32 @@ def decrypt_password(self, value: str) -> Optional[str]:
133133
return decrypt_value(value)
134134

135135

136+
class TaskCommentResponse(BaseModel):
137+
"""Task mapping history."""
138+
139+
id: int
140+
task_id: int
141+
comment: Optional[str] = None
142+
commented_by: str
143+
created_at: datetime
144+
145+
146+
class TaskCommentBase(BaseModel):
147+
"""Task mapping history."""
148+
149+
comment: str
150+
commented_by: str
151+
created_at: datetime
152+
153+
154+
class TaskCommentRequest(BaseModel):
155+
"""Task mapping history."""
156+
157+
task_id: int
158+
project_id: int
159+
comment: str
160+
161+
136162
class ReadTask(Task):
137163
"""Task details plus updated task history."""
138164

0 commit comments

Comments
 (0)