diff --git a/README.md b/README.md index adf465b..18119da 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,8 @@ No matter which deployment option you chose you must setup some environment vari | `HTTP_HOST` | The address the application tries to attach to, leave this empty to listen on all interfaces, leave this empty if you are using Docker | No | `0.0.0.0` | `192.168.1.5` | | `HTTP_PORT` | The port the application listens on, change this if needed if you run the application locally, leave this empty if you are using Docker | No | `8742` | `1234` | +Ensure to quote your environment variables. Without quotes your password might not be read properly if it contains symbols such as `<`, `&` or `;`. + ### Deployment options You can run this app in three simple ways. I prefer the third option. Depending on the deployment option you chose @@ -60,11 +62,11 @@ you can ignore some environment variables (e.g. `HTTP_HOST` and `HTTP_PORT`). - You *can* (not must) specify a different port than the default (`8742`) with `-p 1234:8742`. - Example: ```bash - docker run - -e BRING_USERNAME="myuser@myemailprovider.com" - -e BRING_PASSWORD="my super secret password" - -e BRING_LIST_NAME="My shopping list with spaces" - -p 1234:8742 + docker run \ + -e BRING_USERNAME="myuser@myemailprovider.com" \ + -e BRING_PASSWORD="my super secret password" \ + -e BRING_LIST_NAME="My shopping list with spaces" \ + -p 1234:8742 \ ghcr.io/felixschndr/mealie-bring-api:latest ``` diff --git a/assets/.env.example b/assets/.env.example index 67581ab..c559093 100644 --- a/assets/.env.example +++ b/assets/.env.example @@ -1,8 +1,8 @@ # Take a look at the README for an explanation of the environment variables -BRING_USERNAME=myuser@myemailprovider.com -BRING_PASSWORD=mysupersecretpassword -BRING_LIST_NAME=My list has some spaces in it -IGNORED_INGREDIENTS=Pepper,Salt +BRING_USERNAME="myuser@myemailprovider.com" +BRING_PASSWORD="mysupersecretpassword" +BRING_LIST_NAME="My list has some spaces in it" +IGNORED_INGREDIENTS="Pepper,Salt" LOG_LEVEL=INFO HTTP_HOST=0.0.0.0 HTTP_PORT=8742 diff --git a/source/bring_handler.py b/source/bring_handler.py index 3a6ba46..119f908 100644 --- a/source/bring_handler.py +++ b/source/bring_handler.py @@ -55,13 +55,11 @@ def determine_list_uuid(self) -> str: break if not bring_list_uuid: - self.log.critical( - f"Could not find a bring list with the name {self.list_name}" - ) + self.log.critical(f'Can not find a list with the name "{self.list_name}"') sys.exit(1) self.log.info( - f"Found the bring list {self.list_name} (UUID: {bring_list_uuid})" + f'Found the list with the name "{self.list_name}" (UUID: {bring_list_uuid})' ) return bring_list_uuid diff --git a/source/ingredient.py b/source/ingredient.py index 6e58623..25b0558 100644 --- a/source/ingredient.py +++ b/source/ingredient.py @@ -1,13 +1,24 @@ +from typing import Optional + from errors import IgnoredIngredient +from logger_mixin import LoggerMixin +NO_INGREDIENT_NAME_ERROR = "There is an ingredient with no name, it will be ignored!" -class Ingredient: +class Ingredient(LoggerMixin): def __init__( - self, ingredient_input: dict, ignored_ingredients: list[str] + self, + ingredient_input: dict, + ignored_ingredients: list[str], + enable_amount: bool, ): + super().__init__() + self.ingredient_input = ingredient_input self.ignored_ingredients = ignored_ingredients + self.enable_amount = enable_amount + self.food = None self.specification = "" @@ -19,34 +30,71 @@ def __repr__(self): return self.food def parse_input(self) -> None: - try: - _ = self.ingredient_input["food"] - except KeyError: - # Happens if there is an empty ingredient (i.e. added one ingredient but did not fill it out) - raise ValueError("There is an ingredient with no name, it will be ignored!") - if self.ingredient_input["disableAmount"]: - self._parse_input_with_no_ingredient_amounts() - else: + self.log.debug(f"Parsing {self.ingredient_input}") + + if self.enable_amount: self._parse_input_with_ingredient_amounts() + else: + self._parse_input_with_no_ingredient_amounts() + + self.log.debug(f"Parsed ingredient: {self}") def _parse_input_with_no_ingredient_amounts(self) -> None: - self.food = self.ingredient_input["display"] + note = self.ingredient_input["note"] + if not note: + raise ValueError(NO_INGREDIENT_NAME_ERROR) + self.food = note def _parse_input_with_ingredient_amounts(self) -> None: + if not self.ingredient_input["food"]: + # Happens if there is an empty ingredient (i.e., added one ingredient but did not fill it out) + raise ValueError(NO_INGREDIENT_NAME_ERROR) food_name = self.ingredient_input["food"]["name"] + food_plural_name = self.ingredient_input["food"]["pluralName"] + quantity = int(self.ingredient_input["quantity"] or 0) + unit = self.ingredient_input["unit"] + note = self.ingredient_input["note"] + + # Ignored check # if food_name.lower() in self.ignored_ingredients: raise IgnoredIngredient(f"Found ignored ingredient {food_name}") + + self._set_food(food_name, food_plural_name, quantity) + self._set_quantity(quantity) + self._set_seperator(quantity, unit) + self._set_unit(quantity, unit) + self._set_note(note) + + def _set_food(self, food_name: str, food_plural_name: str, quantity: int) -> None: + if quantity and quantity > 1 and food_plural_name: + self.food = food_plural_name + return + self.food = food_name - quantity = self.ingredient_input.get("quantity", None) + def _set_quantity(self, quantity: int) -> None: if quantity: self.specification += str(quantity) - unit = self.ingredient_input.get("unit", None) - if unit: - self.specification += unit.get("abbreviation", unit["name"]) + def _set_seperator(self, quantity: int, unit: Optional[dict]): + if quantity and unit: + self.specification += " " + + def _set_unit(self, quantity: int, unit: Optional[dict]): + if not unit: + return + + unit_name = unit["name"] + unit_abbreviation = unit["abbreviation"] + unit_plural_name = unit["pluralName"] + if unit_abbreviation: + self.specification += unit_abbreviation + elif unit_plural_name and quantity and quantity > 1: + self.specification += unit_plural_name + elif unit_name: + self.specification += unit_name - note = self.ingredient_input.get("note", None) + def _set_note(self, note: str): if note: self.specification += f" ({note})" diff --git a/source/main.py b/source/main.py index dfe4d18..f937593 100644 --- a/source/main.py +++ b/source/main.py @@ -19,25 +19,29 @@ def webhook_handler(): data = request.get_json(force=True) - recipe_name = data["name"] - logger.log.info(f'Received recipe "{recipe_name}" from "{request.origin}"') + logger.log.info(f'Received recipe "{data["name"]}" from "{request.origin}"') - if data["settings"]["disableAmount"]: + enable_amount = not data["settings"]["disableAmount"] + if enable_amount: + logger.log.debug("This recipe has its ingredient amount enabled") + else: logger.log.warning( - "This recipe has its ingredient amount this disabled. Its ingredients will not be checked whether they are supposed to be ignored." + "This recipe has its ingredient amount this disabled --> Its ingredients will not be checked whether they are supposed to be ignored" ) for ingredient in data["recipeIngredient"]: try: - ingredient = Ingredient(ingredient, bring_handler.ignored_ingredients) + parsed_ingredient = Ingredient( + ingredient, bring_handler.ignored_ingredients, enable_amount + ) except ValueError as e: - logging.warning(e) + logger.log.warning(e) continue except IgnoredIngredient as e: - logging.debug(e) + logger.log.debug(e) continue - bring_handler.add_item_to_list(ingredient) + bring_handler.add_item_to_list(parsed_ingredient) logger.log.info("Added all ingredients to Bring") bring_handler.notify_users_about_changes_in_list()