initial commit

This commit is contained in:
2022-12-20 21:26:47 +01:00
commit 2962a6db69
722 changed files with 63886 additions and 0 deletions

View File

@@ -0,0 +1,121 @@
"""Register_commands."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from homeassistant.components import websocket_api
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
import voluptuous as vol
from ..const import DOMAIN
from .critical import hacs_critical_acknowledge, hacs_critical_list
from .repositories import (
hacs_repositories_add,
hacs_repositories_clear_new,
hacs_repositories_list,
hacs_repositories_remove,
hacs_repositories_removed,
)
from .repository import (
hacs_repository_beta,
hacs_repository_download,
hacs_repository_ignore,
hacs_repository_info,
hacs_repository_refresh,
hacs_repository_release_notes,
hacs_repository_remove,
hacs_repository_state,
hacs_repository_version,
)
if TYPE_CHECKING:
from ..base import HacsBase
@callback
def async_register_websocket_commands(hass: HomeAssistant) -> None:
"""Register_commands."""
websocket_api.async_register_command(hass, hacs_info)
websocket_api.async_register_command(hass, hacs_subscribe)
websocket_api.async_register_command(hass, hacs_repository_info)
websocket_api.async_register_command(hass, hacs_repository_download)
websocket_api.async_register_command(hass, hacs_repository_ignore)
websocket_api.async_register_command(hass, hacs_repository_state)
websocket_api.async_register_command(hass, hacs_repository_version)
websocket_api.async_register_command(hass, hacs_repository_beta)
websocket_api.async_register_command(hass, hacs_repository_refresh)
websocket_api.async_register_command(hass, hacs_repository_release_notes)
websocket_api.async_register_command(hass, hacs_repository_remove)
websocket_api.async_register_command(hass, hacs_critical_acknowledge)
websocket_api.async_register_command(hass, hacs_critical_list)
websocket_api.async_register_command(hass, hacs_repositories_list)
websocket_api.async_register_command(hass, hacs_repositories_add)
websocket_api.async_register_command(hass, hacs_repositories_clear_new)
websocket_api.async_register_command(hass, hacs_repositories_removed)
websocket_api.async_register_command(hass, hacs_repositories_remove)
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/subscribe",
vol.Required("signal"): str,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_subscribe(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict,
) -> None:
"""Handle websocket subscriptions."""
@callback
def forward_messages(data: dict | None = None):
"""Forward events to websocket."""
connection.send_message(websocket_api.event_message(msg["id"], data))
connection.subscriptions[msg["id"]] = async_dispatcher_connect(
hass,
msg["signal"],
forward_messages,
)
connection.send_message(websocket_api.result_message(msg["id"]))
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/info",
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_info(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""Return information about HACS."""
hacs: HacsBase = hass.data.get(DOMAIN)
connection.send_message(
websocket_api.result_message(
msg["id"],
{
"categories": hacs.common.categories,
"country": hacs.configuration.country,
"debug": hacs.configuration.debug,
"dev": hacs.configuration.dev,
"disabled_reason": hacs.system.disabled_reason,
"experimental": hacs.configuration.experimental,
"has_pending_tasks": hacs.queue.has_pending_tasks,
"lovelace_mode": hacs.core.lovelace_mode,
"stage": hacs.stage,
"startup": hacs.status.startup,
"version": hacs.version,
},
)
)

View File

@@ -0,0 +1,56 @@
"""Register info websocket commands."""
from __future__ import annotations
from typing import Any
from homeassistant.components import websocket_api
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
import voluptuous as vol
from ..utils.store import async_load_from_store, async_save_to_store
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/critical/list",
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_critical_list(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
):
"""List critical repositories."""
connection.send_message(
websocket_api.result_message(
msg["id"],
(await async_load_from_store(hass, "critical") or []),
)
)
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/critical/acknowledge",
vol.Optional("repository"): cv.string,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_critical_acknowledge(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
):
"""Acknowledge critical repository."""
repository = msg["repository"]
critical = await async_load_from_store(hass, "critical")
for repo in critical:
if repository == repo["repository"]:
repo["acknowledged"] = True
await async_save_to_store(hass, "critical", critical)
connection.send_message(websocket_api.result_message(msg["id"], critical))

View File

@@ -0,0 +1,211 @@
"""Register info websocket commands."""
from __future__ import annotations
import sys
from typing import TYPE_CHECKING, Any
from homeassistant.components import websocket_api
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
import voluptuous as vol
from custom_components.hacs.utils import regex
from ..const import DOMAIN
from ..enums import HacsDispatchEvent
if TYPE_CHECKING:
from ..base import HacsBase
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/repositories/list",
vol.Optional("categories"): [str],
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_repositories_list(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
):
"""List repositories."""
hacs: HacsBase = hass.data.get(DOMAIN)
connection.send_message(
websocket_api.result_message(
msg["id"],
[
{
"authors": repo.data.authors,
"available_version": repo.display_available_version,
"installed_version": repo.display_installed_version,
"config_flow": repo.data.config_flow,
"can_download": repo.can_download,
"category": repo.data.category,
"country": repo.repository_manifest.country,
"custom": not hacs.repositories.is_default(str(repo.data.id)),
"description": repo.data.description,
"domain": repo.data.domain,
"downloads": repo.data.downloads,
"file_name": repo.data.file_name,
"full_name": repo.data.full_name,
"hide": repo.data.hide,
"homeassistant": repo.repository_manifest.homeassistant,
"id": repo.data.id,
"installed": repo.data.installed,
"last_updated": repo.data.last_updated,
"local_path": repo.content.path.local,
"name": repo.display_name,
"new": repo.data.new,
"pending_upgrade": repo.pending_update,
"stars": repo.data.stargazers_count,
"state": repo.state,
"status": repo.display_status,
"topics": repo.data.topics,
}
for repo in hacs.repositories.list_all
if repo.data.category in (msg.get("categories") or hacs.common.categories)
and not repo.ignored_by_country_configuration
],
)
)
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/repositories/clear_new",
vol.Optional("categories"): cv.ensure_list,
vol.Optional("repository"): cv.string,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_repositories_clear_new(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""Clear new repositories for spesific categories."""
hacs: HacsBase = hass.data.get(DOMAIN)
if repo := msg.get("repository"):
repository = hacs.repositories.get_by_id(repo)
repository.data.new = False
else:
for repo in hacs.repositories.list_all:
if repo.data.new and repo.data.category in msg.get("categories", []):
hacs.log.debug(
"Clearing new flag from '%s'",
repo.data.full_name,
)
repo.data.new = False
hacs.async_dispatch(HacsDispatchEvent.REPOSITORY, {})
await hacs.data.async_write()
connection.send_message(websocket_api.result_message(msg["id"]))
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/repositories/removed",
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_repositories_removed(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
):
"""Get information about removed repositories."""
hacs: HacsBase = hass.data.get(DOMAIN)
content = []
for repo in hacs.repositories.list_removed:
if repo.repository not in hacs.common.ignored_repositories:
content.append(repo.to_json())
connection.send_message(websocket_api.result_message(msg["id"], content))
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/repositories/add",
vol.Required("repository"): cv.string,
vol.Required("category"): vol.Lower,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_repositories_add(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
):
"""Add custom repositoriy."""
hacs: HacsBase = hass.data.get(DOMAIN)
repository = regex.extract_repository_from_url(msg["repository"])
category = msg["category"]
if repository is None:
return
if repository in hacs.common.skip:
hacs.common.skip.remove(repository)
if renamed := hacs.common.renamed_repositories.get(repository):
repository = renamed
if not hacs.repositories.get_by_full_name(repository):
try:
await hacs.async_register_repository(
repository_full_name=repository,
category=category,
)
except BaseException as exception: # lgtm [py/catch-base-exception] pylint: disable=broad-except
hacs.async_dispatch(
HacsDispatchEvent.ERROR,
{
"action": "add_repository",
"exception": str(sys.exc_info()[0].__name__),
"message": str(exception),
},
)
else:
hacs.async_dispatch(
HacsDispatchEvent.ERROR,
{
"action": "add_repository",
"message": f"Repository '{repository}' exists in the store.",
},
)
connection.send_message(websocket_api.result_message(msg["id"], {}))
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/repositories/remove",
vol.Required("repository"): cv.string,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_repositories_remove(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
):
"""Remove custom repositoriy."""
hacs: HacsBase = hass.data.get(DOMAIN)
hacs.log.warning(connection.context)
hacs.log.warning(msg)
repository = hacs.repositories.get_by_id(msg["repository"])
repository.remove()
await hacs.data.async_write()
connection.send_message(websocket_api.result_message(msg["id"], {}))

View File

@@ -0,0 +1,305 @@
"""Register info websocket commands."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from homeassistant.components import websocket_api
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
import voluptuous as vol
from ..const import DOMAIN
from ..enums import HacsDispatchEvent
from ..utils.version import version_left_higher_then_right
if TYPE_CHECKING:
from ..base import HacsBase
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/repository/info",
vol.Required("repository_id"): str,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_repository_info(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""Return information about a repository."""
hacs: HacsBase = hass.data.get(DOMAIN)
repository = hacs.repositories.get_by_id(msg["repository_id"])
if repository is None:
connection.send_error(msg["id"], "repository_not_found", "Repository not found")
return
if not repository.updated_info:
await repository.update_repository(ignore_issues=True, force=True)
repository.updated_info = True
if repository.data.new:
repository.data.new = False
await hacs.data.async_write()
connection.send_message(
websocket_api.result_message(
msg["id"],
{
"additional_info": repository.additional_info,
"authors": repository.data.authors,
"available_version": repository.display_available_version,
"beta": repository.data.show_beta,
"can_download": repository.can_download,
"category": repository.data.category,
"config_flow": repository.data.config_flow,
"country": repository.repository_manifest.country,
"custom": not hacs.repositories.is_default(str(repository.data.id)),
"default_branch": repository.data.default_branch,
"description": repository.data.description,
"domain": repository.data.domain,
"downloads": repository.data.downloads,
"file_name": repository.data.file_name,
"full_name": repository.data.full_name,
"hide_default_branch": repository.repository_manifest.hide_default_branch,
"homeassistant": repository.repository_manifest.homeassistant,
"id": repository.data.id,
"installed_version": repository.display_installed_version,
"installed": repository.data.installed,
"issues": repository.data.open_issues,
"last_updated": repository.data.last_updated,
"local_path": repository.content.path.local,
"name": repository.display_name,
"new": False,
"pending_upgrade": repository.pending_update,
"releases": repository.data.published_tags,
"ref": repository.ref,
"selected_tag": repository.data.selected_tag,
"stars": repository.data.stargazers_count,
"state": repository.state,
"status": repository.display_status,
"topics": repository.data.topics,
"version_or_commit": repository.display_version_or_commit,
},
)
)
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/repository/ignore",
vol.Required("repository"): str,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_repository_ignore(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
):
"""Ignore a repository."""
hacs: HacsBase = hass.data.get(DOMAIN)
repository = hacs.repositories.get_by_id(msg["repository"])
hacs.common.ignored_repositories.append(repository.data.full_name)
await hacs.data.async_write()
connection.send_message(websocket_api.result_message(msg["id"]))
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/repository/state",
vol.Required("repository"): cv.string,
vol.Required("state"): cv.string,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_repository_state(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
):
"""Set the state of a repository"""
hacs: HacsBase = hass.data.get(DOMAIN)
repository = hacs.repositories.get_by_id(msg["repository"])
repository.state = msg["state"]
await hacs.data.async_write()
connection.send_message(websocket_api.result_message(msg["id"], {}))
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/repository/version",
vol.Required("repository"): cv.string,
vol.Required("version"): cv.string,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_repository_version(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
):
"""Set the version of a repository"""
hacs: HacsBase = hass.data.get(DOMAIN)
repository = hacs.repositories.get_by_id(msg["repository"])
if msg["version"] == repository.data.default_branch:
repository.data.selected_tag = None
else:
repository.data.selected_tag = msg["version"]
await repository.update_repository(force=True)
repository.state = None
await hacs.data.async_write()
connection.send_message(websocket_api.result_message(msg["id"], {}))
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/repository/beta",
vol.Required("repository"): cv.string,
vol.Required("show_beta"): cv.boolean,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_repository_beta(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
):
"""Show or hide beta versions of a repository"""
hacs: HacsBase = hass.data.get(DOMAIN)
repository = hacs.repositories.get_by_id(msg["repository"])
repository.data.show_beta = msg["show_beta"]
await repository.update_repository(force=True)
repository.state = None
await hacs.data.async_write()
connection.send_message(websocket_api.result_message(msg["id"], {}))
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/repository/download",
vol.Required("repository"): cv.string,
vol.Optional("version"): cv.string,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_repository_download(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
):
"""Set the version of a repository"""
hacs: HacsBase = hass.data.get(DOMAIN)
repository = hacs.repositories.get_by_id(msg["repository"])
was_installed = repository.data.installed
if version := msg.get("version"):
repository.data.selected_tag = version
await repository.update_repository(force=True)
await repository.async_install()
repository.state = None
if not was_installed:
hacs.async_dispatch(HacsDispatchEvent.RELOAD, {"force": True})
await hacs.async_recreate_entities()
await hacs.data.async_write()
connection.send_message(websocket_api.result_message(msg["id"], {}))
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/repository/remove",
vol.Required("repository"): cv.string,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_repository_remove(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
):
"""Remove a repository."""
hacs: HacsBase = hass.data.get(DOMAIN)
repository = hacs.repositories.get_by_id(msg["repository"])
repository.data.new = False
await repository.update_repository(ignore_issues=True, force=True)
await repository.uninstall()
await hacs.data.async_write()
connection.send_message(websocket_api.result_message(msg["id"], {}))
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/repository/refresh",
vol.Required("repository"): cv.string,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_repository_refresh(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
):
"""Refresh a repository."""
hacs: HacsBase = hass.data.get(DOMAIN)
repository = hacs.repositories.get_by_id(msg["repository"])
await repository.update_repository(ignore_issues=True, force=True)
await hacs.data.async_write()
connection.send_message(websocket_api.result_message(msg["id"], {}))
@websocket_api.websocket_command(
{
vol.Required("type"): "hacs/repository/release_notes",
vol.Required("repository"): cv.string,
}
)
@websocket_api.require_admin
@websocket_api.async_response
async def hacs_repository_release_notes(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
):
"""Return release notes."""
hacs: HacsBase = hass.data.get(DOMAIN)
repository = hacs.repositories.get_by_id(msg["repository"])
connection.send_message(
websocket_api.result_message(
msg["id"],
[
{
"name": x.name,
"body": x.body,
"tag": x.tag_name,
}
for x in repository.releases.objects
if not repository.data.installed_version
or version_left_higher_then_right(x.tag_name, repository.data.installed_version)
],
)
)