Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Every failure returns the same shape, with the status code carrying the meaning:
- [Menus](#menus)
- [Shopping List](#shopping-list)
- [Pantry](#pantry)
- [Aisles](#aisles)
- [Search & Stats](#search--stats)
- [Realtime](#realtime)
- [Sync](#sync)
Expand Down Expand Up @@ -1012,6 +1013,160 @@ Response:
]
```

## Aisles

Reads and changes `aisle.conf`, which groups the shopping list by store aisle: an `[aisle]` line, then one ingredient per line with its other names after `|`. Changes edit only the lines concerned, so comments and blank lines elsewhere in the file are kept. Each response carries the file's `revision`; send it back with a change and the change is refused with `409` if the file has been changed since, along with the current `revision`. Leave it out to apply the change regardless. Changes need the `shopper` role when sign-in is on.

### `GET /api/aisles`

Read the aisles

Aisles in file order, which is the order the shopping list uses. Each ingredient's first name is the one the shopping list shows; the others are merged into it. `warnings` lists the lines the parser skipped, such as a name listed twice. Without an aisle file, `configured` is `false`, `path` and `revision` are `null` and `aisles` is empty. The response below is trimmed to two of the seed's eight aisles and a few ingredients each.

Response:

```json
{
"configured": true,
"path": "/path/to/recipes/config/aisle.conf",
"revision": "edbf1fd2579f964e",
"aisles": [
{
"name": "fruit and veg",
"ingredients": [
{ "names": ["apples"] },
{ "names": ["avocado", "avocados"] }
]
},
{
"name": "milk and dairy",
"ingredients": [
{ "names": ["milk"] },
{ "names": ["butter"] }
]
}
],
"warnings": []
}
```

### `POST /api/aisles`

Create an aisle file

Creates an empty `config/aisle.conf` in the recipe directory and answers `201` with the same shape as `GET /api/aisles`. `409` if an aisle file already exists, wherever it was found.

### `POST /api/aisles/changes`

Change the aisles

A change is named by `action`; the other fields depend on it. `add_aisle` (`name`, optional `position`, counted from 0; last when omitted), `rename_aisle` (`name`, `new_name`), `remove_aisle` (`name`; its ingredients go with it), `move_aisle` (`name`, `position`), `add_ingredient` (`aisle`, `names`), `update_ingredient` (`name`, `names`, optional `aisle` to move it), `remove_ingredient` (`name`), `add_names` (`name`, `names`: more names for that ingredient, ones it has skipped) and `merge_ingredients` (`names`, one per ingredient, and `main`: the one name the shopping list will show; the result keeps the place, aisle and comment of the ingredient `main` came from). An ingredient is found by any of its names, ignoring case. Send one change with its fields beside `revision`, or several as `changes`, a list: they are applied in order and written together, or not at all, and an error names the change that failed (`Change 4: …`). Answers with the aisles as `GET /api/aisles` does. `400` for a name the file cannot hold (empty, or containing `|` or `//`) or one already used — ingredient names ignoring case, as the shopping list matches them; `404` for an aisle or ingredient that does not exist, or when there is no aisle file; `409` for a stale `revision`.

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `action` | body | `string` | yes | `add_aisle`, `rename_aisle`, `remove_aisle`, `move_aisle`, `add_ingredient`, `update_ingredient`, `remove_ingredient`, `add_names` or `merge_ingredients`. Not given when sending `changes`. |
| `changes` | body | `object[]` | no | Several changes, each with its own `action`, made together. |
| `revision` | body | `string` | no | The `revision` the change was made against. |
| `name` | body | `string` | no | The aisle, or any one of the ingredient's names. |
| `names` | body | `string[]` | no | An ingredient's names, the one to show first; for `merge_ingredients`, one name of each ingredient to group. |
| `main` | body | `string` | no | For `merge_ingredients`: the name the grouped ingredient goes by. |
| `aisle` | body | `string` | no | The aisle to put it in. |
| `new_name` | body | `string` | no | For `rename_aisle`. |
| `position` | body | `integer` | no | Where the aisle goes among the aisles, from 0. |

Request body:

```json
{
"revision": "edbf1fd2579f964e",
"changes": [
{ "action": "add_aisle", "name": "snacks" },
{ "action": "add_ingredient", "aisle": "snacks", "names": ["almonds"] },
{ "action": "add_names", "name": "butter", "names": ["Butter"] },
{ "action": "add_ingredient", "aisle": "snacks", "names": ["Butter"] }
]
}
```

Response:

```json
{
"error": "Change 4: \"Butter\" is already in the \"milk and dairy\" aisle"
}
```

### `GET /api/aisles/raw`

Read the aisle file as text

The file exactly as written, with its `revision`. `404` when there is no aisle file. The `content` below is cut short.

Response:

```json
{
"path": "/path/to/recipes/config/aisle.conf",
"content": "[fruit and veg]\napples\nbananas\ngrapes\n",
"revision": "edbf1fd2579f964e"
}
```

### `PUT /api/aisles/raw`

Replace the aisle file

Writes `content` as the whole file once the aisle parser accepts it, and answers as `GET /api/aisles` does. Otherwise `400` naming the line, and the file is left alone.

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `content` | body | `string` | yes | The new file. |
| `revision` | body | `string` | no | The `revision` the text was edited from. |

Request body:

```json
{
"content": "[a]\nx\n[b]\nx\n"
}
```

Response:

```json
{
"error": "Line 4: Duplicate ingredient: 'x'"
}
```

### `GET /api/aisles/uncategorized`

Ingredients without an aisle

The ingredients the recipes and menus use that no aisle names — what `cook doctor aisle` reports — with the files using each. `link` is what follows `/recipe/` in that file's page address. Scans the whole collection, so it takes longer than the other reads. The response below is trimmed to two of the seed's eleven.

Response:

```json
{
"total_recipes": 14,
"ingredients": [
{
"name": "San Marzano tomato sauce",
"recipes": [
{ "path": "Neapolitan Pizza.cook", "link": "Neapolitan Pizza" }
]
},
{
"name": "almonds",
"recipes": [
{ "path": "Weekly Plan.menu", "link": "Weekly Plan.menu" }
]
}
]
}
```

## Search & Stats

Collection-wide queries.
Expand Down
63 changes: 63 additions & 0 deletions locales/de-DE/aisles.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Gänge
aisles-title = Gänge
aisles-manage = Gänge verwalten
aisles-back-to-list = Einkaufsliste
aisles-intro = Die Einkaufsliste gruppiert Zutaten nach diesen Gängen, in dieser Reihenfolge. Der fett gedruckte Hauptname einer Zutat ist der, den die Liste zeigt; ihre weiteren Namen werden darin zusammengefasst.
aisles-no-config = Noch keine Gang-Datei
aisles-no-config-help = Ohne sie landet jede Zutat der Einkaufsliste unter „other“.
aisles-create = aisle.conf anlegen
aisles-warnings = Einige Zeilen der Gang-Datei wurden übersprungen:
aisles-tab-aisles = Gänge
aisles-tab-uncategorized = Ohne Gang
aisles-tab-text = Text
aisles-empty = Noch keine Gänge. Füge unten einen hinzu.
aisles-empty-aisle = Keine Zutaten in diesem Gang
aisles-aisle-name = Name des Gangs
aisles-add-aisle = Gang hinzufügen
aisles-rename = Gang umbenennen
aisles-move-up = Nach oben
aisles-move-down = Nach unten
aisles-remove-aisle = Gang entfernen
aisles-remove-aisle-confirm = Den Gang „%s“ und seine %n Zutaten entfernen?
aisles-edit = Bearbeiten
aisles-remove = Entfernen
aisles-remove-ingredient-confirm = „%s“ aus den Gängen entfernen?
aisles-save = Speichern
aisles-cancel = Abbrechen
aisles-add = Hinzufügen
aisles-add-ingredient = Zutat hinzufügen
aisles-ingredient-placeholder = z. B. Frühlingszwiebel | Lauchzwiebel
aisles-move-to = Gang
aisles-choose-aisle = Gang wählen…
aisles-assign = Gang zuordnen…
aisles-conflict = Die Gang-Datei wurde anderswo geändert; die Seite zeigt jetzt ihre neue Fassung. Bitte versuche es erneut.
aisles-failed = Die Änderung konnte nicht gespeichert werden
aisles-uncategorized-intro = Zutaten deiner Rezepte, die in keinem Gang stehen. Auf der Einkaufsliste erscheinen sie unter „other“.
aisles-uncategorized-loading = Rezepte werden durchsucht…
aisles-uncategorized-none = Jede Zutat deiner Rezepte hat einen Gang.
aisles-used-in = Verwendet in
aisles-text-intro = Bearbeite die Datei direkt: ein Gang pro Zeile [Name], darunter eine Zutat pro Zeile, weitere Namen nach |. Alles nach // ist ein Kommentar.
aisles-text-save = Datei speichern
aisles-text-saved = Gespeichert
aisles-text-conflict = Die Gang-Datei wurde anderswo geändert, während du bearbeitet hast. Dein Text bleibt erhalten; speichere erneut, um jene Änderung damit zu ersetzen.
aisles-new-aisle = + Neuer Gang…
aisles-new-aisle-prompt = Name des neuen Gangs:
aisles-select = Auswählen
aisles-select-done = Fertig
aisles-select-help = Wähle Zutaten aus, um sie zu einer zusammenzufassen oder gemeinsam zu verschieben.
aisles-selected = %n ausgewählt
aisles-group = Zusammenfassen…
aisles-group-help = Welchen Namen soll die Einkaufsliste zeigen? Die anderen werden darin zusammengefasst.
aisles-group-confirm = Zusammenfassen
aisles-move = Verschieben
aisles-clear = Auswahl aufheben
aisles-main-name = Hauptname
aisles-make-main = Zum Hauptnamen machen
aisles-remove-name = Diesen Namen entfernen
aisles-add-name = Weiteren Namen hinzufügen
aisles-filter = Zutaten filtern
aisles-select-all = Alle angezeigten auswählen
aisles-add-to-aisle = Zum Gang hinzufügen
aisles-add-as-names = Oder als weitere Namen hinzufügen von
aisles-choose-ingredient = Zutat…
aisles-move-to-aisle = In Gang verschieben
63 changes: 63 additions & 0 deletions locales/en-US/aisles.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Aisles
aisles-title = Aisles
aisles-manage = Manage aisles
aisles-back-to-list = Shopping list
aisles-intro = The shopping list groups ingredients by these aisles, in this order. An ingredient's main name, in bold, is the one the list shows; its other names are merged into it.
aisles-no-config = No aisle file yet
aisles-no-config-help = Without one, every ingredient on the shopping list lands under "other".
aisles-create = Create aisle.conf
aisles-warnings = Some lines of the aisle file were skipped:
aisles-tab-aisles = Aisles
aisles-tab-uncategorized = Uncategorized
aisles-tab-text = Text
aisles-empty = No aisles yet. Add one below.
aisles-empty-aisle = No ingredients in this aisle
aisles-aisle-name = Aisle name
aisles-add-aisle = Add aisle
aisles-rename = Rename aisle
aisles-move-up = Move up
aisles-move-down = Move down
aisles-remove-aisle = Remove aisle
aisles-remove-aisle-confirm = Remove the aisle "%s" and its %n ingredients?
aisles-edit = Edit
aisles-remove = Remove
aisles-remove-ingredient-confirm = Remove "%s" from the aisles?
aisles-save = Save
aisles-cancel = Cancel
aisles-add = Add
aisles-add-ingredient = Add ingredient
aisles-ingredient-placeholder = e.g. spring onion | scallion
aisles-move-to = Aisle
aisles-choose-aisle = Choose an aisle…
aisles-assign = Assign aisle…
aisles-conflict = The aisle file was changed elsewhere, so the page now shows its new version. Please try again.
aisles-failed = Could not save the change
aisles-uncategorized-intro = Ingredients your recipes use that no aisle lists. On the shopping list they appear under "other".
aisles-uncategorized-loading = Scanning recipes…
aisles-uncategorized-none = Every ingredient in your recipes has an aisle.
aisles-used-in = Used in
aisles-text-intro = Edit the file directly: an aisle per [name] line, then one ingredient per line with its other names after |. Anything after // is a comment.
aisles-text-save = Save file
aisles-text-saved = Saved
aisles-text-conflict = The aisle file was changed elsewhere while you were editing. Your text is kept; save again to replace that change with it.
aisles-new-aisle = + New aisle…
aisles-new-aisle-prompt = Name of the new aisle:
aisles-select = Select
aisles-select-done = Done
aisles-select-help = Pick ingredients to group them into one, or to move them together.
aisles-selected = %n selected
aisles-group = Group…
aisles-group-help = Which name should the shopping list show? The others are merged into it.
aisles-group-confirm = Group
aisles-move = Move
aisles-clear = Clear
aisles-main-name = main name
aisles-make-main = Make this the main name
aisles-remove-name = Remove this name
aisles-add-name = Add another name
aisles-filter = Filter ingredients
aisles-select-all = Select all shown
aisles-add-to-aisle = Add to aisle
aisles-add-as-names = Or add as other names of
aisles-choose-ingredient = Ingredient…
aisles-move-to-aisle = Move to aisle
63 changes: 63 additions & 0 deletions locales/es-ES/aisles.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Pasillos
aisles-title = Pasillos
aisles-manage = Gestionar pasillos
aisles-back-to-list = Lista de la compra
aisles-intro = La lista de la compra agrupa los ingredientes por estos pasillos, en este orden. El nombre principal de un ingrediente, en negrita, es el que muestra la lista; sus otros nombres se unen a él.
aisles-no-config = Aún no hay archivo de pasillos
aisles-no-config-help = Sin él, todos los ingredientes de la lista de la compra acaban en «other».
aisles-create = Crear aisle.conf
aisles-warnings = Se omitieron algunas líneas del archivo de pasillos:
aisles-tab-aisles = Pasillos
aisles-tab-uncategorized = Sin pasillo
aisles-tab-text = Texto
aisles-empty = Aún no hay pasillos. Añade uno abajo.
aisles-empty-aisle = No hay ingredientes en este pasillo
aisles-aisle-name = Nombre del pasillo
aisles-add-aisle = Añadir pasillo
aisles-rename = Renombrar pasillo
aisles-move-up = Subir
aisles-move-down = Bajar
aisles-remove-aisle = Eliminar pasillo
aisles-remove-aisle-confirm = ¿Eliminar el pasillo «%s» y sus %n ingredientes?
aisles-edit = Editar
aisles-remove = Eliminar
aisles-remove-ingredient-confirm = ¿Quitar «%s» de los pasillos?
aisles-save = Guardar
aisles-cancel = Cancelar
aisles-add = Añadir
aisles-add-ingredient = Añadir ingrediente
aisles-ingredient-placeholder = p. ej. cebolleta | cebolla tierna
aisles-move-to = Pasillo
aisles-choose-aisle = Elige un pasillo…
aisles-assign = Asignar pasillo…
aisles-conflict = El archivo de pasillos se cambió en otro lugar, así que la página muestra ahora su nueva versión. Inténtalo de nuevo.
aisles-failed = No se pudo guardar el cambio
aisles-uncategorized-intro = Ingredientes de tus recetas que ningún pasillo incluye. En la lista de la compra aparecen bajo «other».
aisles-uncategorized-loading = Analizando recetas…
aisles-uncategorized-none = Todos los ingredientes de tus recetas tienen pasillo.
aisles-used-in = Usado en
aisles-text-intro = Edita el archivo directamente: un pasillo por línea [nombre] y debajo un ingrediente por línea, con sus otros nombres tras |. Todo lo que sigue a // es un comentario.
aisles-text-save = Guardar archivo
aisles-text-saved = Guardado
aisles-text-conflict = El archivo de pasillos se cambió en otro lugar mientras editabas. Tu texto se conserva; guarda de nuevo para reemplazar ese cambio con él.
aisles-new-aisle = + Nuevo pasillo…
aisles-new-aisle-prompt = Nombre del nuevo pasillo:
aisles-select = Seleccionar
aisles-select-done = Listo
aisles-select-help = Elige ingredientes para agruparlos en uno solo o para moverlos juntos.
aisles-selected = %n seleccionados
aisles-group = Agrupar…
aisles-group-help = ¿Qué nombre debe mostrar la lista de la compra? Los demás se unen a él.
aisles-group-confirm = Agrupar
aisles-move = Mover
aisles-clear = Quitar selección
aisles-main-name = nombre principal
aisles-make-main = Convertir en nombre principal
aisles-remove-name = Quitar este nombre
aisles-add-name = Añadir otro nombre
aisles-filter = Filtrar ingredientes
aisles-select-all = Seleccionar todos los mostrados
aisles-add-to-aisle = Añadir al pasillo
aisles-add-as-names = O añadir como otros nombres de
aisles-choose-ingredient = Ingrediente…
aisles-move-to-aisle = Mover al pasillo
Loading
Loading