Add create_habit action to Habitica integration (#139673)

pull/139798/head^2
Manu 2025-03-04 22:43:49 +01:00 committed by GitHub
parent 1456d9d800
commit 50ba93042b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 180 additions and 16 deletions

View File

@ -62,6 +62,7 @@ SERVICE_TRANSFORMATION = "transformation"
SERVICE_UPDATE_REWARD = "update_reward"
SERVICE_CREATE_REWARD = "create_reward"
SERVICE_UPDATE_HABIT = "update_habit"
SERVICE_CREATE_HABIT = "create_habit"
DEVELOPER_ID = "4c4ca53f-c059-4ffa-966e-9d29dd405daf"
X_CLIENT = f"{DEVELOPER_ID} - {APPLICATION_NAME} {__version__}"

View File

@ -237,6 +237,12 @@
"tag_options": "mdi:tag",
"developer_options": "mdi:test-tube"
}
},
"create_habit": {
"service": "mdi:contrast-box",
"sections": {
"developer_options": "mdi:test-tube"
}
}
}
}

View File

@ -66,6 +66,7 @@ from .const import (
SERVICE_API_CALL,
SERVICE_CANCEL_QUEST,
SERVICE_CAST_SKILL,
SERVICE_CREATE_HABIT,
SERVICE_CREATE_REWARD,
SERVICE_GET_TASKS,
SERVICE_LEAVE_QUEST,
@ -190,6 +191,7 @@ SERVICE_TASK_TYPE_MAP = {
SERVICE_UPDATE_REWARD: TaskType.REWARD,
SERVICE_CREATE_REWARD: TaskType.REWARD,
SERVICE_UPDATE_HABIT: TaskType.HABIT,
SERVICE_CREATE_HABIT: TaskType.HABIT,
}
@ -596,7 +598,7 @@ def async_setup_services(hass: HomeAssistant) -> None: # noqa: C901
data = Task()
if not is_update:
data["type"] = TaskType.REWARD
data["type"] = SERVICE_TASK_TYPE_MAP[call.service]
if (text := call.data.get(ATTR_RENAME)) or (text := call.data.get(ATTR_NAME)):
data["text"] = text
@ -733,6 +735,13 @@ def async_setup_services(hass: HomeAssistant) -> None: # noqa: C901
schema=SERVICE_CREATE_TASK_SCHEMA,
supports_response=SupportsResponse.ONLY,
)
hass.services.async_register(
DOMAIN,
SERVICE_CREATE_HABIT,
create_or_update_task,
schema=SERVICE_CREATE_TASK_SCHEMA,
supports_response=SupportsResponse.ONLY,
)
hass.services.async_register(
DOMAIN,
SERVICE_API_CALL,

View File

@ -183,7 +183,7 @@ update_reward:
create_reward:
fields:
config_entry: *config_entry
name:
name: &name
required: true
selector:
text:
@ -199,7 +199,7 @@ update_habit:
task: *task
rename: *rename
notes: *notes
up_down:
up_down: &up_down
required: false
selector:
select:
@ -210,7 +210,7 @@ update_habit:
label: ""
multiple: true
mode: list
priority:
priority: &priority
required: false
selector:
select:
@ -221,7 +221,7 @@ update_habit:
- "hard"
mode: dropdown
translation_key: "priority"
frequency:
frequency: &frequency
required: false
selector:
select:
@ -252,3 +252,13 @@ update_habit:
unit_of_measurement: ""
mode: box
alias: *alias
create_habit:
fields:
config_entry: *config_entry
name: *name
notes: *notes
up_down: *up_down
priority: *priority
frequency: *frequency
tag: *tag
developer_options: *developer_options

View File

@ -11,9 +11,9 @@
"config_entry_description": "Select the Habitica account to update a task.",
"task_description": "The name (or task ID) of the task you want to update.",
"rename_name": "Rename",
"rename_description": "The new title for the Habitica task.",
"notes_name": "Update notes",
"notes_description": "The new notes for the Habitica task.",
"rename_description": "The title for the Habitica task.",
"notes_name": "Notes",
"notes_description": "The notes for the Habitica task.",
"tag_name": "Add tags",
"tag_description": "Add tags to the Habitica task. If a tag does not already exist, a new one will be created.",
"remove_tag_name": "Remove tags",
@ -25,7 +25,13 @@
"tag_options_name": "Tags",
"tag_options_description": "Add or remove tags from a task.",
"name_description": "The title for the Habitica task.",
"cost_name": "Cost"
"cost_name": "Cost",
"difficulty_name": "Difficulty",
"difficulty_description": "The difficulty of the task.",
"frequency_name": "Counter reset",
"frequency_description": "The frequency at which the habit's counter resets: daily at the start of a new day, weekly after Sunday night, or monthly at the beginning of a new month.",
"up_down_name": "Rewards or losses",
"up_down_description": "Whether the habit is good and rewarding (positive), bad and penalizing (negative), or both."
},
"config": {
"abort": {
@ -793,16 +799,16 @@
"description": "[%key:component::habitica::common::alias_description%]"
},
"priority": {
"name": "Difficulty",
"description": "Update the difficulty of a task."
"name": "[%key:component::habitica::common::difficulty_name%]",
"description": "[%key:component::habitica::common::difficulty_description%]"
},
"frequency": {
"name": "Counter reset",
"description": "Update when a habit's counter resets: daily resets at the start of a new day, weekly after Sunday night, and monthly at the beginning of a new month."
"name": "[%key:component::habitica::common::frequency_name%]",
"description": "[%key:component::habitica::common::frequency_description%]"
},
"up_down": {
"name": "Rewards or losses",
"description": "Update if the habit is good and rewarding (positive), bad and penalizing (negative), or both."
"name": "[%key:component::habitica::common::up_down_name%]",
"description": "[%key:component::habitica::common::up_down_description%]"
},
"counter_up": {
"name": "Adjust positive counter",
@ -823,6 +829,50 @@
"description": "[%key:component::habitica::common::developer_options_description%]"
}
}
},
"create_habit": {
"name": "Create habit",
"description": "Adds a new habit.",
"fields": {
"config_entry": {
"name": "[%key:component::habitica::common::config_entry_name%]",
"description": "Select the Habitica account to create a habit."
},
"name": {
"name": "[%key:component::habitica::common::task_name%]",
"description": "[%key:component::habitica::common::name_description%]"
},
"notes": {
"name": "[%key:component::habitica::common::notes_name%]",
"description": "[%key:component::habitica::common::notes_description%]"
},
"tag": {
"name": "[%key:component::habitica::common::tag_name%]",
"description": "[%key:component::habitica::common::tag_description%]"
},
"alias": {
"name": "[%key:component::habitica::common::alias_name%]",
"description": "[%key:component::habitica::common::alias_description%]"
},
"priority": {
"name": "[%key:component::habitica::common::difficulty_name%]",
"description": "[%key:component::habitica::common::difficulty_description%]"
},
"frequency": {
"name": "[%key:component::habitica::common::frequency_name%]",
"description": "[%key:component::habitica::common::frequency_description%]"
},
"up_down": {
"name": "[%key:component::habitica::common::up_down_name%]",
"description": "[%key:component::habitica::common::up_down_description%]"
}
},
"sections": {
"developer_options": {
"name": "[%key:component::habitica::common::developer_options_name%]",
"description": "[%key:component::habitica::common::developer_options_description%]"
}
}
}
},
"selector": {

View File

@ -42,6 +42,7 @@ from homeassistant.components.habitica.const import (
SERVICE_ACCEPT_QUEST,
SERVICE_CANCEL_QUEST,
SERVICE_CAST_SKILL,
SERVICE_CREATE_HABIT,
SERVICE_CREATE_REWARD,
SERVICE_GET_TASKS,
SERVICE_LEAVE_QUEST,
@ -986,6 +987,10 @@ async def test_update_task_exceptions(
),
],
)
@pytest.mark.parametrize(
"service",
[SERVICE_CREATE_REWARD, SERVICE_CREATE_HABIT],
)
@pytest.mark.usefixtures("habitica")
async def test_create_task_exceptions(
hass: HomeAssistant,
@ -994,6 +999,7 @@ async def test_create_task_exceptions(
exception: Exception,
expected_exception: Exception,
exception_msg: str,
service: str,
) -> None:
"""Test Habitica task create action exceptions."""
@ -1001,7 +1007,7 @@ async def test_create_task_exceptions(
with pytest.raises(expected_exception, match=exception_msg):
await hass.services.async_call(
DOMAIN,
SERVICE_CREATE_REWARD,
service,
service_data={
ATTR_CONFIG_ENTRY: config_entry.entry_id,
ATTR_NAME: "TITLE",
@ -1230,6 +1236,88 @@ async def test_update_habit(
habitica.update_task.assert_awaited_with(UUID(task_id), call_args)
@pytest.mark.parametrize(
("service_data", "call_args"),
[
(
{
ATTR_NAME: "TITLE",
},
Task(type=TaskType.HABIT, text="TITLE"),
),
(
{
ATTR_NAME: "TITLE",
ATTR_NOTES: "NOTES",
},
Task(type=TaskType.HABIT, text="TITLE", notes="NOTES"),
),
(
{
ATTR_NAME: "TITLE",
ATTR_UP_DOWN: [""],
},
Task(type=TaskType.HABIT, text="TITLE", up=False, down=False),
),
(
{
ATTR_NAME: "TITLE",
ATTR_UP_DOWN: ["up"],
},
Task(type=TaskType.HABIT, text="TITLE", up=True, down=False),
),
(
{
ATTR_NAME: "TITLE",
ATTR_UP_DOWN: ["down"],
},
Task(type=TaskType.HABIT, text="TITLE", up=False, down=True),
),
(
{
ATTR_NAME: "TITLE",
ATTR_PRIORITY: "trivial",
},
Task(type=TaskType.HABIT, text="TITLE", priority=TaskPriority.TRIVIAL),
),
(
{
ATTR_NAME: "TITLE",
ATTR_FREQUENCY: "daily",
},
Task(type=TaskType.HABIT, text="TITLE", frequency=Frequency.DAILY),
),
(
{
ATTR_NAME: "TITLE",
ATTR_ALIAS: "ALIAS",
},
Task(type=TaskType.HABIT, text="TITLE", alias="ALIAS"),
),
],
)
async def test_create_habit(
hass: HomeAssistant,
config_entry: MockConfigEntry,
habitica: AsyncMock,
service_data: dict[str, Any],
call_args: Task,
) -> None:
"""Test Habitica create_habit action."""
await hass.services.async_call(
DOMAIN,
SERVICE_CREATE_HABIT,
service_data={
ATTR_CONFIG_ENTRY: config_entry.entry_id,
**service_data,
},
return_response=True,
blocking=True,
)
habitica.create_task.assert_awaited_with(call_args)
async def test_tags(
hass: HomeAssistant,
config_entry: MockConfigEntry,