Skip to content

Commit

Permalink
Merge pull request #211 from hotosm/feat/unlock-task-if-locked
Browse files Browse the repository at this point in the history
Feat: add task reset feature for drone operators
  • Loading branch information
nrjadkry authored Sep 10, 2024
2 parents 4c300fc + fc7c826 commit 23d5d81
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/backend/app/models/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ class EventType(str, Enum):
- ``split`` -- Set the state *unlocked done* then generate additional subdivided task areas.
- ``assign`` -- For a requester user to assign a task to another user. Set the state *locked for mapping* passing in the required user id.
- ``comment`` -- Keep the state the same, but simply add a comment.
- ``unlock`` -- Unlock a task state by unlocking it if it's locked.
Note that ``task_id`` must be specified in the endpoint too.
"""
Expand All @@ -175,3 +176,4 @@ class EventType(str, Enum):
SPLIT = "split"
ASSIGN = "assign"
COMMENT = "comment"
UNLOCK = "unlock"
38 changes: 38 additions & 0 deletions src/backend/app/tasks/task_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,41 @@ async def request_mapping(
)
result = await cur.fetchone()
return result


async def get_task_state(
db: Connection, project_id: uuid.UUID, task_id: uuid.UUID
) -> dict:
"""
Retrieve the latest state of a task by querying the task_events table.
Args:
db (Connection): The database connection.
project_id (uuid.UUID): The project ID.
task_id (uuid.UUID): The task ID.
Returns:
dict: A dictionary containing the task's state and associated metadata.
"""
try:
async with db.cursor(row_factory=dict_row) as cur:
await cur.execute(
"""
SELECT state, user_id, created_at, comment
FROM task_events
WHERE project_id = %(project_id)s AND task_id = %(task_id)s
ORDER BY created_at DESC
LIMIT 1;
""",
{
"project_id": str(project_id),
"task_id": str(task_id),
},
)
result = await cur.fetchone()
return result
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"An error occurred while retrieving the task state: {str(e)}",
)
32 changes: 32 additions & 0 deletions src/backend/app/tasks/task_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,4 +368,36 @@ async def new_event(
State.UNFLYABLE_TASK,
)

case EventType.UNLOCK:
# Fetch the task state
current_task_state = await task_logic.get_task_state(
db, project_id, task_id
)

state = current_task_state.get("state")
locked_user_id = current_task_state.get("user_id")

# Determine error conditions
if state != State.LOCKED_FOR_MAPPING.name:
raise HTTPException(
status_code=400,
detail="Task state does not match expected state for unlock operation.",
)
if user_id != locked_user_id:
raise HTTPException(
status_code=403,
detail="You cannot unlock this task as it is locked by another user.",
)

# Proceed with unlocking the task
return await task_logic.update_task_state(
db,
project_id,
task_id,
user_id,
f"Task has been unlock by user {user_data.name}.",
State.LOCKED_FOR_MAPPING,
State.UNLOCKED_TO_MAP,
)

return True

0 comments on commit 23d5d81

Please sign in to comment.