Skip to content

Commit d0ff617

Browse files
Transmission Service validation and fixes (home-assistant#155554)
1 parent 8e49956 commit d0ff617

File tree

3 files changed

+55
-32
lines changed

3 files changed

+55
-32
lines changed

homeassistant/components/transmission/services.py

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
from functools import partial
44
import logging
5+
from typing import cast
56

67
import voluptuous as vol
78

89
from homeassistant.config_entries import ConfigEntryState
910
from homeassistant.const import CONF_ID
1011
from homeassistant.core import HomeAssistant, ServiceCall, callback
11-
from homeassistant.exceptions import HomeAssistantError
12+
from homeassistant.exceptions import ServiceValidationError
1213
from homeassistant.helpers import config_validation as cv, selector
1314

1415
from .const import (
@@ -23,7 +24,7 @@
2324
SERVICE_START_TORRENT,
2425
SERVICE_STOP_TORRENT,
2526
)
26-
from .coordinator import TransmissionConfigEntry, TransmissionDataUpdateCoordinator
27+
from .coordinator import TransmissionDataUpdateCoordinator
2728

2829
_LOGGER = logging.getLogger(__name__)
2930

@@ -67,63 +68,68 @@
6768

6869

6970
def _get_coordinator_from_service_data(
70-
hass: HomeAssistant, entry_id: str
71+
call: ServiceCall,
7172
) -> TransmissionDataUpdateCoordinator:
7273
"""Return coordinator for entry id."""
73-
entry: TransmissionConfigEntry | None = hass.config_entries.async_get_entry(
74-
entry_id
75-
)
76-
if entry is None or entry.state is not ConfigEntryState.LOADED:
77-
raise HomeAssistantError(f"Config entry {entry_id} is not found or not loaded")
78-
return entry.runtime_data
74+
config_entry_id: str = call.data[CONF_ENTRY_ID]
75+
if not (entry := call.hass.config_entries.async_get_entry(config_entry_id)):
76+
raise ServiceValidationError(
77+
translation_domain=DOMAIN,
78+
translation_key="integration_not_found",
79+
translation_placeholders={"target": DOMAIN},
80+
)
81+
if entry.state is not ConfigEntryState.LOADED:
82+
raise ServiceValidationError(
83+
translation_domain=DOMAIN,
84+
translation_key="not_loaded",
85+
translation_placeholders={"target": entry.title},
86+
)
87+
return cast(TransmissionDataUpdateCoordinator, entry.runtime_data)
7988

8089

8190
async def _async_add_torrent(service: ServiceCall) -> None:
8291
"""Add new torrent to download."""
83-
entry_id: str = service.data[CONF_ENTRY_ID]
84-
coordinator = _get_coordinator_from_service_data(service.hass, entry_id)
92+
coordinator = _get_coordinator_from_service_data(service)
8593
torrent: str = service.data[ATTR_TORRENT]
8694
download_path: str | None = service.data.get(ATTR_DOWNLOAD_PATH)
87-
if torrent.startswith(
88-
("http", "ftp:", "magnet:")
89-
) or service.hass.config.is_allowed_path(torrent):
90-
if download_path:
91-
await service.hass.async_add_executor_job(
92-
partial(
93-
coordinator.api.add_torrent, torrent, download_dir=download_path
94-
)
95-
)
96-
else:
97-
await service.hass.async_add_executor_job(
98-
coordinator.api.add_torrent, torrent
99-
)
100-
await coordinator.async_request_refresh()
95+
96+
if not (
97+
torrent.startswith(("http", "ftp:", "magnet:"))
98+
or service.hass.config.is_allowed_path(torrent)
99+
):
100+
raise ServiceValidationError(
101+
translation_domain=DOMAIN,
102+
translation_key="could_not_add_torrent",
103+
)
104+
105+
if download_path:
106+
await service.hass.async_add_executor_job(
107+
partial(coordinator.api.add_torrent, torrent, download_dir=download_path)
108+
)
101109
else:
102-
_LOGGER.warning("Could not add torrent: unsupported type or no permission")
110+
await service.hass.async_add_executor_job(coordinator.api.add_torrent, torrent)
111+
await coordinator.async_request_refresh()
103112

104113

105114
async def _async_start_torrent(service: ServiceCall) -> None:
106115
"""Start torrent."""
107-
entry_id: str = service.data[CONF_ENTRY_ID]
108-
coordinator = _get_coordinator_from_service_data(service.hass, entry_id)
116+
coordinator = _get_coordinator_from_service_data(service)
109117
torrent_id = service.data[CONF_ID]
110118
await service.hass.async_add_executor_job(coordinator.api.start_torrent, torrent_id)
111119
await coordinator.async_request_refresh()
112120

113121

114122
async def _async_stop_torrent(service: ServiceCall) -> None:
115123
"""Stop torrent."""
116-
entry_id: str = service.data[CONF_ENTRY_ID]
117-
coordinator = _get_coordinator_from_service_data(service.hass, entry_id)
124+
coordinator = _get_coordinator_from_service_data(service)
118125
torrent_id = service.data[CONF_ID]
119126
await service.hass.async_add_executor_job(coordinator.api.stop_torrent, torrent_id)
120127
await coordinator.async_request_refresh()
121128

122129

123130
async def _async_remove_torrent(service: ServiceCall) -> None:
124131
"""Remove torrent."""
125-
entry_id: str = service.data[CONF_ENTRY_ID]
126-
coordinator = _get_coordinator_from_service_data(service.hass, entry_id)
132+
coordinator = _get_coordinator_from_service_data(service)
127133
torrent_id = service.data[CONF_ID]
128134
delete_data = service.data[ATTR_DELETE_DATA]
129135
await service.hass.async_add_executor_job(

homeassistant/components/transmission/services.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
add_torrent:
22
fields:
33
entry_id:
4+
required: true
45
selector:
56
config_entry:
67
integration: transmission
@@ -18,6 +19,7 @@ add_torrent:
1819
remove_torrent:
1920
fields:
2021
entry_id:
22+
required: true
2123
selector:
2224
config_entry:
2325
integration: transmission
@@ -27,24 +29,28 @@ remove_torrent:
2729
selector:
2830
text:
2931
delete_data:
32+
required: true
3033
default: false
3134
selector:
3235
boolean:
3336

3437
start_torrent:
3538
fields:
3639
entry_id:
40+
required: true
3741
selector:
3842
config_entry:
3943
integration: transmission
4044
id:
45+
required: true
4146
example: 123
4247
selector:
4348
text:
4449

4550
stop_torrent:
4651
fields:
4752
entry_id:
53+
required: true
4854
selector:
4955
config_entry:
5056
integration: transmission

homeassistant/components/transmission/strings.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,17 @@
8787
}
8888
}
8989
},
90+
"exceptions": {
91+
"could_not_add_torrent": {
92+
"message": "Could not add torrent: unsupported type or no permission."
93+
},
94+
"integration_not_found": {
95+
"message": "Integration \"{target}\" not found in registry."
96+
},
97+
"not_loaded": {
98+
"message": "{target} is not loaded."
99+
}
100+
},
90101
"options": {
91102
"step": {
92103
"init": {

0 commit comments

Comments
 (0)