Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Endpoints for task comments #1171

Merged
merged 23 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9827495
feat: taskcomment model added
varun2948 Jan 17, 2024
9c54907
feat: crud task comment
varun2948 Jan 17, 2024
d1142a9
feat: task comment crud api route added
varun2948 Jan 17, 2024
df2141c
feat: task comment schema added
varun2948 Jan 17, 2024
5f423eb
Merge branch 'development' of github.com:hotosm/fmtm into feature/tas…
varun2948 Jan 17, 2024
931004a
Merge branch 'development' of github.com:hotosm/fmtm into feature/tas…
varun2948 Feb 5, 2024
bc41b8a
fix: removed use of dictionary to object
varun2948 Feb 5, 2024
e646b4a
fix: change row name by id with task_comment_id
varun2948 Feb 6, 2024
9142cc9
fix: renamed comment_task_id_to_id
varun2948 Feb 6, 2024
fd540d0
feat: migration add-task-comment
varun2948 Feb 6, 2024
89f0b7f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 6, 2024
45845a6
renamed task_comment index
varun2948 Feb 6, 2024
af88180
Merge branch 'development' of github.com:hotosm/fmtm into feature/tas…
varun2948 Feb 6, 2024
3033ca1
Merge branch 'feature/task_comment' of github.com:hotosm/fmtm into fe…
varun2948 Feb 6, 2024
5f0b92e
fix: removed new table migration for taskcomment
varun2948 Feb 11, 2024
42384b7
feat: used task_history table to get task_comment and add task_comment
varun2948 Feb 11, 2024
5b50d0c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 11, 2024
0fa3184
fix: linting issue
varun2948 Feb 12, 2024
9936669
Merge branch 'feature/task_comment' of github.com:hotosm/fmtm into fe…
varun2948 Feb 12, 2024
908f3ac
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 12, 2024
8a5f26b
Merge branch 'development' into feature/task_comment
spwoodcock Feb 13, 2024
5a950f8
refactor: improve sql, use query params, fix linting errors
spwoodcock Feb 13, 2024
85d6ad2
refactor: minor code cleanup bundled in merge
spwoodcock Feb 13, 2024
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
26 changes: 26 additions & 0 deletions src/backend/app/db/db_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,32 @@ class DbTaskHistory(Base):
)


class TaskComment(Base):
varun2948 marked this conversation as resolved.
Show resolved Hide resolved
"""Represents a comment associated with a task."""

__tablename__ = "task_comment"

id = Column(Integer, primary_key=True)
task_id = Column(Integer, nullable=False)
project_id = Column(Integer, ForeignKey("projects.id"), index=True)
comment_text = Column(String)
commented_by = Column(
BigInteger,
ForeignKey("users.id", name="fk_users"),
index=True,
nullable=False,
)
created_at = Column(DateTime, nullable=False, default=timestamp)

__table_args__ = (
ForeignKeyConstraint(
[task_id, project_id], ["tasks.id", "tasks.project_id"], name="fk_tasks"
),
Index("idx_task_comment_composite", "task_id", "project_id"),
{},
)


class DbTask(Base):
"""Describes an individual mapping Task."""

Expand Down
3 changes: 1 addition & 2 deletions src/backend/app/db/postgis_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,6 @@ def parse_and_filter_geojson(
geojson_str: str, filter: bool = True
) -> Optional[geojson.FeatureCollection]:
"""Parse geojson string and filter out incomaptible geometries."""
log.debug("Parsing geojson string")
geojson_parsed = geojson.loads(geojson_str)
if isinstance(geojson_parsed, geojson.FeatureCollection):
log.debug("Already in FeatureCollection format, skipping reparse")
Expand All @@ -255,7 +254,7 @@ def parse_and_filter_geojson(
log.debug("Converting Feature to FeatureCollection")
featcol = geojson.FeatureCollection(features=[geojson_parsed])
else:
log.debug("Converting geometry to FeatureCollection")
log.debug("Converting Geometry to FeatureCollection")
featcol = geojson.FeatureCollection(
features=[geojson.Feature(geometry=geojson_parsed)]
)
Expand Down
3 changes: 0 additions & 3 deletions src/backend/app/projects/project_crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,6 @@ def remove_z_dimension(coord):
meters=meters,
)
for index, poly in enumerate(tasks["features"]):
log.debug(poly)
db_task = db_models.DbTask(
project_id=project_id,
outline=wkblib.dumps(shape(poly["geometry"]), hex=True),
Expand All @@ -607,8 +606,6 @@ def remove_z_dimension(coord):
)
db.add(db_task)
db.commit()

# FIXME: write to tasks table
return True


Expand Down
98 changes: 98 additions & 0 deletions src/backend/app/tasks/tasks_crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from sqlalchemy.orm import Session
from sqlalchemy.sql import text

from app.auth.osm import AuthUser
from app.central import central_crud
from app.db import database, db_models
from app.models.enums import (
Expand Down Expand Up @@ -315,6 +316,103 @@ async def edit_task_boundary(db: Session, task_id: int, boundary: str):
return True


async def get_task_comments(db: Session, project_id: int, task_id: int):
"""Get a list of tasks id for a project."""
query = text(
"""
SELECT
task_history.id, task_history.task_id, users.username,
task_history.action_text, task_history.action_date
FROM
task_history
LEFT JOIN
users ON task_history.user_id = users.id
WHERE
project_id = :project_id
AND task_id = :task_id
AND action = 'COMMENT'
"""
)

params = {"project_id": project_id, "task_id": task_id}

result = db.execute(query, params)

# Convert the result to a list of dictionaries
result_dict_list = [
{
"id": row[0],
"task_id": row[1],
"commented_by": row[2],
"comment": row[3],
"created_at": row[4],
}
for row in result.fetchall()
]

return result_dict_list


async def add_task_comments(
db: Session, comment: tasks_schemas.TaskCommentBase, user_data: AuthUser
):
"""Add a comment to a task.

Parameters:
- db: SQLAlchemy database session
- comment: TaskCommentBase instance containing the comment details
- user_data: AuthUser instance containing the user details

Returns:
- Dictionary with the details of the added comment
"""
currentdate = datetime.now()
# Construct the query to insert the comment and retrieve inserted comment details
query = text(
"""
INSERT INTO task_history (
project_id, task_id, action, action_text,
action_date, user_id
)
VALUES (
:project_id, :task_id, 'COMMENT', :comment_text,
:current_date, :user_id
)
RETURNING
task_history.id,
task_history.task_id,
(SELECT username FROM users WHERE id = task_history.user_id) AS user_id,
task_history.action_text,
task_history.action_date;
"""
)

# Define a dictionary with the parameter values
params = {
"project_id": comment.project_id,
"task_id": comment.task_id,
"comment_text": comment.comment,
"current_date": currentdate,
"user_id": user_data.id,
}

# Execute the query with the named parameters and commit the transaction
result = db.execute(query, params)
db.commit()

# Fetch the first row of the query result
row = result.fetchone()

# Return the details of the added comment as a dictionary
return {
"id": row[0],
"task_id": row[1],
"commented_by": row[2],
"comment": row[3],
"created_at": row[4],
}


async def update_task_history(
tasks: List[tasks_schemas.Task], db: Session = Depends(database.get_db)
):
Expand Down
43 changes: 42 additions & 1 deletion src/backend/app/tasks/tasks_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from sqlalchemy.orm import Session
from sqlalchemy.sql import text

from app.auth.osm import AuthUser
from app.auth.osm import AuthUser, login_required
from app.auth.roles import get_uid, mapper, project_admin
from app.central import central_crud
from app.db import database
Expand Down Expand Up @@ -196,6 +196,47 @@ async def task_features_count(
return data


@router.get("/task-comments/", response_model=list[tasks_schemas.TaskCommentResponse])
async def task_comments(
project_id: int,
task_id: int,
db: Session = Depends(database.get_db),
):
"""Retrieve a list of task comments for a specific project and task.

Args:
project_id (int): The ID of the project.
task_id (int): The ID of the task.
db (Session, optional): The database session.

Returns:
List[tasks_schemas.TaskCommentResponse]: A list of task comments.
"""
task_comment_list = await tasks_crud.get_task_comments(db, project_id, task_id)

return task_comment_list


@router.post("/task-comments/", response_model=tasks_schemas.TaskCommentResponse)
async def add_task_comments(
comment: tasks_schemas.TaskCommentRequest,
db: Session = Depends(database.get_db),
user_data: AuthUser = Depends(login_required),
):
"""Create a new task comment.

Parameters:
comment (TaskCommentRequest): The task comment to be created.
db (Session): The database session.
user_data (AuthUser): The authenticated user.

Returns:
TaskCommentResponse: The created task comment.
"""
task_comment_list = await tasks_crud.add_task_comments(db, comment, user_data)
return task_comment_list


@router.get("/activity/", response_model=List[tasks_schemas.TaskHistoryCount])
async def task_activity(
project_id: int, days: int = 10, db: Session = Depends(database.get_db)
Expand Down
26 changes: 26 additions & 0 deletions src/backend/app/tasks/tasks_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,32 @@ def decrypt_password(self, value: str) -> Optional[str]:
return decrypt_value(value)


class TaskCommentResponse(BaseModel):
"""Task mapping history."""

id: int
task_id: int
comment: Optional[str] = None
commented_by: str
created_at: datetime


class TaskCommentBase(BaseModel):
"""Task mapping history."""

comment: str
commented_by: str
created_at: datetime


class TaskCommentRequest(BaseModel):
"""Task mapping history."""

task_id: int
project_id: int
comment: str


class ReadTask(Task):
"""Task details plus updated task history."""

Expand Down
Loading