From 656d0696bb55a028d87f56e50ddb7cc41767988b Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Fri, 22 Dec 2023 09:49:41 -0800 Subject: [PATCH] Add support for re-ordering Google Tasks (#104769) * Add reorder and task ordering * Remove un-needed js id code * Revert dead code deletion * Remove reverted test and dead logger * Update comment name --- homeassistant/components/google_tasks/api.py | 15 ++++ homeassistant/components/google_tasks/todo.py | 8 ++ .../google_tasks/snapshots/test_todo.ambr | 50 ++++++++++++ tests/components/google_tasks/test_todo.py | 81 +++++++++++++++++++ 4 files changed, 154 insertions(+) diff --git a/homeassistant/components/google_tasks/api.py b/homeassistant/components/google_tasks/api.py index 5dd7156702f..2658fdedc59 100644 --- a/homeassistant/components/google_tasks/api.py +++ b/homeassistant/components/google_tasks/api.py @@ -126,6 +126,21 @@ class AsyncConfigEntryAuth: ) await self._execute(batch) + async def move( + self, + task_list_id: str, + task_id: str, + previous: str | None, + ) -> None: + """Move a task resource to a specific position within the task list.""" + service = await self._get_service() + cmd: HttpRequest = service.tasks().move( + tasklist=task_list_id, + task=task_id, + previous=previous, + ) + await self._execute(cmd) + async def _execute(self, request: HttpRequest | BatchHttpRequest) -> Any: try: result = await self._hass.async_add_executor_job(request.execute) diff --git a/homeassistant/components/google_tasks/todo.py b/homeassistant/components/google_tasks/todo.py index 130c0d2cc01..cf3f84e9a0d 100644 --- a/homeassistant/components/google_tasks/todo.py +++ b/homeassistant/components/google_tasks/todo.py @@ -91,6 +91,7 @@ class GoogleTaskTodoListEntity( TodoListEntityFeature.CREATE_TODO_ITEM | TodoListEntityFeature.UPDATE_TODO_ITEM | TodoListEntityFeature.DELETE_TODO_ITEM + | TodoListEntityFeature.MOVE_TODO_ITEM | TodoListEntityFeature.SET_DUE_DATE_ON_ITEM | TodoListEntityFeature.SET_DESCRIPTION_ON_ITEM ) @@ -138,6 +139,13 @@ class GoogleTaskTodoListEntity( await self.coordinator.api.delete(self._task_list_id, uids) await self.coordinator.async_refresh() + async def async_move_todo_item( + self, uid: str, previous_uid: str | None = None + ) -> None: + """Re-order a To-do item.""" + await self.coordinator.api.move(self._task_list_id, uid, previous=previous_uid) + await self.coordinator.async_refresh() + def _order_tasks(tasks: list[dict[str, Any]]) -> list[dict[str, Any]]: """Order the task items response. diff --git a/tests/components/google_tasks/snapshots/test_todo.ambr b/tests/components/google_tasks/snapshots/test_todo.ambr index 7d6eb920593..e30739551f3 100644 --- a/tests/components/google_tasks/snapshots/test_todo.ambr +++ b/tests/components/google_tasks/snapshots/test_todo.ambr @@ -32,6 +32,56 @@ 'POST', ) # --- +# name: test_move_todo_item[api_responses0] + list([ + dict({ + 'status': 'needs_action', + 'summary': 'Water', + 'uid': 'some-task-id-1', + }), + dict({ + 'status': 'needs_action', + 'summary': 'Milk', + 'uid': 'some-task-id-2', + }), + dict({ + 'status': 'needs_action', + 'summary': 'Cheese', + 'uid': 'some-task-id-3', + }), + ]) +# --- +# name: test_move_todo_item[api_responses0].1 + tuple( + 'https://tasks.googleapis.com/tasks/v1/lists/task-list-id-1/tasks/some-task-id-3/move?previous=some-task-id-1&alt=json', + 'POST', + ) +# --- +# name: test_move_todo_item[api_responses0].2 + None +# --- +# name: test_move_todo_item[api_responses0].3 + list([ + dict({ + 'status': 'needs_action', + 'summary': 'Water', + 'uid': 'some-task-id-1', + }), + dict({ + 'status': 'needs_action', + 'summary': 'Cheese', + 'uid': 'some-task-id-3', + }), + dict({ + 'status': 'needs_action', + 'summary': 'Milk', + 'uid': 'some-task-id-2', + }), + ]) +# --- +# name: test_move_todo_item[api_responses0].4 + None +# --- # name: test_parent_child_ordering[api_responses0] list([ dict({ diff --git a/tests/components/google_tasks/test_todo.py b/tests/components/google_tasks/test_todo.py index 3329f89c1ca..bf9a3f03df0 100644 --- a/tests/components/google_tasks/test_todo.py +++ b/tests/components/google_tasks/test_todo.py @@ -74,6 +74,29 @@ LIST_TASKS_RESPONSE_MULTIPLE = { }, ], } +LIST_TASKS_RESPONSE_REORDER = { + "items": [ + { + "id": "some-task-id-2", + "title": "Milk", + "status": "needsAction", + "position": "00000000000000000002", + }, + { + "id": "some-task-id-1", + "title": "Water", + "status": "needsAction", + "position": "00000000000000000001", + }, + # Task 3 moved after task 1 + { + "id": "some-task-id-3", + "title": "Cheese", + "status": "needsAction", + "position": "000000000000000000011", + }, + ], +} # API responses when testing update methods UPDATE_API_RESPONSES = [ @@ -793,6 +816,64 @@ async def test_parent_child_ordering( assert items == snapshot +@pytest.mark.parametrize( + "api_responses", + [ + [ + LIST_TASK_LIST_RESPONSE, + LIST_TASKS_RESPONSE_MULTIPLE, + EMPTY_RESPONSE, # move + LIST_TASKS_RESPONSE_REORDER, # refresh after move + ] + ], +) +async def test_move_todo_item( + hass: HomeAssistant, + setup_credentials: None, + integration_setup: Callable[[], Awaitable[bool]], + ws_get_items: Callable[[], Awaitable[dict[str, str]]], + hass_ws_client: WebSocketGenerator, + mock_http_response: Any, + snapshot: SnapshotAssertion, +) -> None: + """Test for re-ordering a To-do Item.""" + + assert await integration_setup() + + state = hass.states.get(ENTITY_ID) + assert state + assert state.state == "3" + + items = await ws_get_items() + assert items == snapshot + + # Move to second in the list + client = await hass_ws_client() + data = { + "id": id, + "type": "todo/item/move", + "entity_id": ENTITY_ID, + "uid": "some-task-id-3", + "previous_uid": "some-task-id-1", + } + await client.send_json_auto_id(data) + resp = await client.receive_json() + assert resp.get("success") + + assert len(mock_http_response.call_args_list) == 4 + call = mock_http_response.call_args_list[2] + assert call + assert call.args == snapshot + assert call.kwargs.get("body") == snapshot + + state = hass.states.get(ENTITY_ID) + assert state + assert state.state == "3" + + items = await ws_get_items() + assert items == snapshot + + @pytest.mark.parametrize( "api_responses", [