Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
vabene1111 committed Oct 8, 2024
2 parents 1bfe5bb + cae26e7 commit 4c0ace1
Show file tree
Hide file tree
Showing 27 changed files with 511 additions and 423 deletions.
16 changes: 6 additions & 10 deletions cookbook/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,11 @@ def ready(self):
import cookbook.signals # noqa

if not settings.DISABLE_EXTERNAL_CONNECTORS:
try:
from cookbook.connectors.connector_manager import ConnectorManager # Needs to be here to prevent loading race condition of oauth2 modules in models.py
handler = ConnectorManager()
post_save.connect(handler, dispatch_uid="connector_manager")
post_delete.connect(handler, dispatch_uid="connector_manager")
except Exception as e:
traceback.print_exc()
print('Failed to initialize connectors')
pass
from cookbook.connectors.connector_manager import ConnectorManager # Needs to be here to prevent loading race condition of oauth2 modules in models.py
handler = ConnectorManager()
post_save.connect(handler, dispatch_uid="post_save-connector_manager")
post_delete.connect(handler, dispatch_uid="post_delete-connector_manager")

# if not settings.DISABLE_TREE_FIX_STARTUP:
# # when starting up run fix_tree to:
# # a) make sure that nodes are sorted when switching between sort modes
Expand All @@ -45,4 +41,4 @@ def ready(self):
# except Exception:
# if DEBUG:
# traceback.print_exc()
# pass # dont break startup just because fix could not run, need to investigate cases when this happens
# pass # dont break startup just because fix could not run, need to investigate cases when this happens
12 changes: 11 additions & 1 deletion cookbook/connectors/connector_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ class Work:
actionType: ActionType


class Singleton(type):
_instances = {}

def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]


# The way ConnectionManager works is as follows:
# 1. On init, it starts a worker & creates a queue for 'Work'
# 2. Then any time its called, it verifies the type of action (create/update/delete) and if the item is of interest, pushes the Work (non-blocking) to the queue.
Expand All @@ -39,7 +48,8 @@ class Work:
# 3.2 If work is of type REGISTERED_CLASSES, it asynchronously fires of all connectors and wait for them to finish (runtime should depend on the 'slowest' connector)
# 4. Work is marked as consumed, and next entry of the queue is consumed.
# Each 'Work' is processed in sequential by the worker, so the throughput is about [workers * the slowest connector]
class ConnectorManager:
# The Singleton class is used for ConnectorManager to have a self-reference and so Python does not garbage collect it
class ConnectorManager(metaclass=Singleton):
_logger: Logger
_queue: queue.Queue
_listening_to_classes = REGISTERED_CLASSES | ConnectorConfig
Expand Down
22 changes: 13 additions & 9 deletions cookbook/connectors/homeassistant.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from typing import Dict, Tuple
from urllib.parse import urljoin

from aiohttp import ClientError, request
from aiohttp import request, ClientResponseError

from cookbook.connectors.connector import Connector
from cookbook.models import ShoppingListEntry, ConnectorConfig, Space
Expand All @@ -13,6 +13,8 @@ class HomeAssistant(Connector):
_config: ConnectorConfig
_logger: Logger

_required_foreign_keys = ("food", "unit", "created_by")

def __init__(self, config: ConnectorConfig):
if not config.token or not config.url or not config.todo_entity:
raise ValueError("config for HomeAssistantConnector in incomplete")
Expand All @@ -38,18 +40,20 @@ async def on_shopping_list_entry_created(self, space: Space, shopping_list_entry

item, description = _format_shopping_list_entry(shopping_list_entry)

self._logger.debug(f"adding {item=}")
self._logger.debug(f"adding {item=} with {description=} to {self._config.todo_entity}")

data = {
"entity_id": self._config.todo_entity,
"item": item,
"description": description,
}

if self._config.supports_description_field:
data["description"] = description

try:
await self.homeassistant_api_call("POST", "services/todo/add_item", data)
except ClientError as err:
self._logger.warning(f"received an exception from the api: {err=}, {type(err)=}")
except ClientResponseError as err:
self._logger.warning(f"received an exception from the api: {err.request_info.url=}, {err.request_info.method=}, {err.status=}, {err.message=}, {type(err)=}")

async def on_shopping_list_entry_updated(self, space: Space, shopping_list_entry: ShoppingListEntry) -> None:
if not self._config.on_shopping_list_entry_updated_enabled:
Expand All @@ -60,14 +64,14 @@ async def on_shopping_list_entry_deleted(self, space: Space, shopping_list_entry
if not self._config.on_shopping_list_entry_deleted_enabled:
return

if not hasattr(shopping_list_entry._state.fields_cache, "food"):
if not all(k in shopping_list_entry._state.fields_cache for k in self._required_foreign_keys):
# Sometimes the food foreign key is not loaded, and we cant load it from an async process
self._logger.debug("required property was not present in ShoppingListEntry")
return

item, _ = _format_shopping_list_entry(shopping_list_entry)

self._logger.debug(f"removing {item=}")
self._logger.debug(f"removing {item=} from {self._config.todo_entity}")

data = {
"entity_id": self._config.todo_entity,
Expand All @@ -76,9 +80,9 @@ async def on_shopping_list_entry_deleted(self, space: Space, shopping_list_entry

try:
await self.homeassistant_api_call("POST", "services/todo/remove_item", data)
except ClientError as err:
except ClientResponseError as err:
# This error will always trigger if the item is not present/found
self._logger.debug(f"received an exception from the api: {err=}, {type(err)=}")
self._logger.debug(f"received an exception from the api: {err.request_info.url=}, {err.request_info.method=}, {err.status=}, {err.message=}, {type(err)=}")

async def close(self) -> None:
pass
Expand Down
8 changes: 7 additions & 1 deletion cookbook/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,12 @@ class ConnectorConfigForm(forms.ModelForm):
required=False,
)

supports_description_field = forms.BooleanField(
help_text="Does the connector todo entity support the description field",
initial=True,
required=False,
)

update_token = forms.CharField(
widget=forms.TextInput(attrs={'autocomplete': 'update-token', 'type': 'password'}),
required=False,
Expand All @@ -198,7 +204,7 @@ class Meta:

fields = (
'name', 'type', 'enabled', 'on_shopping_list_entry_created_enabled', 'on_shopping_list_entry_updated_enabled',
'on_shopping_list_entry_deleted_enabled', 'url', 'todo_entity',
'on_shopping_list_entry_deleted_enabled', 'supports_description_field', 'url', 'todo_entity',
)

help_texts = {
Expand Down
4 changes: 3 additions & 1 deletion cookbook/helper/recipe_url_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ def get_from_scraper(scrape, request):
source_url = scrape.url
except Exception:
pass
if source_url:
if source_url == "https://urlnotfound.none" or not source_url:
recipe_json['source_url'] = ''
else:
recipe_json['source_url'] = source_url
try:
keywords.append(source_url.replace('http://', '').replace('https://', '').split('/')[0])
Expand Down
49 changes: 20 additions & 29 deletions cookbook/locale/de/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-08-01 15:04+0200\n"
"PO-Revision-Date: 2024-07-31 13:05+0000\n"
"Last-Translator: vabene1111 <[email protected]>\n"
"Language-Team: German <http://translate.tandoor.dev/projects/tandoor/recipes-"
"backend/de/>\n"
"PO-Revision-Date: 2024-09-27 13:58+0000\n"
"Last-Translator: supaeasy <[email protected]>\n"
"Language-Team: German <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/de/>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
Expand Down Expand Up @@ -478,7 +478,7 @@ msgstr "Essensplan"
#: .\cookbook\models.py:456 .\cookbook\templates\base.html:122
#: .\cookbook\views\views.py:459
msgid "Books"
msgstr "Bücher"
msgstr "Kochbücher"

#: .\cookbook\models.py:457 .\cookbook\templates\base.html:118
#: .\cookbook\views\views.py:460
Expand Down Expand Up @@ -542,10 +542,8 @@ msgid "Instruction Replace"
msgstr "Anleitung ersetzen"

#: .\cookbook\models.py:1472
#, fuzzy
#| msgid "New Unit"
msgid "Never Unit"
msgstr "Neue Einheit"
msgstr "Nie Einheit"

#: .\cookbook\models.py:1473
msgid "Transpose Words"
Expand Down Expand Up @@ -2143,7 +2141,7 @@ msgstr ""

#: .\cookbook\templates\system.html:86
msgid "Allowed Hosts"
msgstr ""
msgstr "Erlaubte Hosts"

#: .\cookbook\templates\system.html:90
msgid ""
Expand All @@ -2153,6 +2151,11 @@ msgid ""
"this.\n"
" "
msgstr ""
"\n"
" Die erlaubten Hosts sind so konfiguriert, dass sie jeden Host "
"erlauben. Das mag in einigen Fällen in Ordnung sein, sollte aber im "
"Regelfall vermieden werden. Bitte lies in der Dokumentation dazu nach.\n"
" "

#: .\cookbook\templates\system.html:97
msgid "Database"
Expand Down Expand Up @@ -2504,16 +2507,12 @@ msgid "Filter for entries with the given recipe"
msgstr "Filter für Einträge mit dem angegebenen Rezept"

#: .\cookbook\views\api.py:1292
#, fuzzy
#| msgid ""
#| "Returns the shopping list entry with a primary key of id. Multiple "
#| "values allowed."
msgid ""
"Return the Automations matching the automation type. Multiple values "
"allowed."
msgstr ""
"Zeigt denjenigen Eintrag auf der Einkaufliste mit der angegebenen ID. Kann "
"mehrfach angegeben werden."
"Zeigt Automationen, die dem Automationstyp entsprechen. Kann mehrfach "
"angegeben werden."

#: .\cookbook\views\api.py:1415
msgid "Nothing to do."
Expand Down Expand Up @@ -2582,10 +2581,8 @@ msgstr ""
"Monitor verwendet wird."

#: .\cookbook\views\delete.py:135
#, fuzzy
#| msgid "Storage Backend"
msgid "Connectors Config Backend"
msgstr "Speicherquelle"
msgstr "Backendkonfiguration für Konnektoren"

#: .\cookbook\views\delete.py:157
msgid "Invite Link"
Expand Down Expand Up @@ -2644,10 +2641,8 @@ msgid "Shopping List"
msgstr "Einkaufsliste"

#: .\cookbook\views\lists.py:77 .\cookbook\views\new.py:98
#, fuzzy
#| msgid "Storage Backend"
msgid "Connector Config Backend"
msgstr "Speicherquelle"
msgstr "Backendkonfiguration für Konnektoren"

#: .\cookbook\views\lists.py:91
msgid "Invite Links"
Expand Down Expand Up @@ -2743,7 +2738,7 @@ msgstr "Sie verwenden PostgreSQL %(v1)s. PostgreSQL %(v2)s wird empfohlen"

#: .\cookbook\views\views.py:313
msgid "Unable to determine PostgreSQL version."
msgstr ""
msgstr "PostgreSQL version konnte nicht erkannt werden."

#: .\cookbook\views\views.py:317
msgid ""
Expand All @@ -2755,18 +2750,14 @@ msgstr ""
"PostgreSQL-Datenbanken funktionieren."

#: .\cookbook\views\views.py:360
#, fuzzy
#| msgid ""
#| "The setup page can only be used to create the first user! If you have "
#| "forgotten your superuser credentials please consult the django "
#| "documentation on how to reset passwords."
msgid ""
"The setup page can only be used to create the first "
"user! If you have forgotten your superuser credentials "
"please consult the django documentation on how to reset passwords."
msgstr ""
"Die Setup-Seite kann nur für den ersten Nutzer verwendet werden. Zum "
"Zurücksetzen von Passwörtern bitte der Django-Dokumentation folgen."
"Die Setup-Seite kann nur für den ersten Nutzer verwendet "
"werden. Falls du die Superuser Logindaten vergessen "
"hast, folge bitte der Django-Dokumentation um Passwörter zurückzusetzen."

#: .\cookbook\views\views.py:369
msgid "Passwords dont match!"
Expand Down
14 changes: 7 additions & 7 deletions cookbook/locale/el/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-08-01 15:04+0200\n"
"PO-Revision-Date: 2023-08-21 09:19+0000\n"
"Last-Translator: Theodoros Grammenos <teogramm@outlook.com>\n"
"Language-Team: Greek <http://translate.tandoor.dev/projects/tandoor/recipes-"
"backend/el/>\n"
"PO-Revision-Date: 2024-09-23 21:58+0000\n"
"Last-Translator: Emmker <emmker@gmail.com>\n"
"Language-Team: Greek <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/el/>\n"
"Language: el\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.15\n"
"X-Generator: Weblate 5.6.2\n"

#: .\cookbook\forms.py:45
msgid ""
Expand All @@ -33,7 +33,7 @@ msgstr "Όνομα"

#: .\cookbook\forms.py:62 .\cookbook\forms.py:246 .\cookbook\views\lists.py:103
msgid "Keywords"
msgstr "Λέξεις κλειδιά"
msgstr "Λέξεις Κλειδιά"

#: .\cookbook\forms.py:62
msgid "Preparation time in minutes"
Expand Down Expand Up @@ -98,7 +98,7 @@ msgstr ""

#: .\cookbook\forms.py:205
msgid "http://homeassistant.local:8123/api for example"
msgstr ""
msgstr "http://homeassistant.local:8123/api για παράδειγμα"

#: .\cookbook\forms.py:222 .\cookbook\views\edit.py:117
msgid "Storage"
Expand Down
Loading

0 comments on commit 4c0ace1

Please sign in to comment.