Merge branch 'mealie-recipes:mealie-next' into mealie-next

This commit is contained in:
Julian van der Horst 2024-11-04 13:17:15 +01:00 committed by GitHub
commit 562a8be696
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 385 additions and 277 deletions

View file

@ -15,8 +15,30 @@ jobs:
- name: Checkout 🛎
uses: actions/checkout@v4
- name: Update pre-commit Hooks
uses: vrslev/pre-commit-autoupdate@v1.0.0
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Set PY
shell: bash
run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
- name: Cache
uses: actions/cache@v4
with:
path: |
~/.cache/pre-commit
~/.cache/pip
key: pre-commit-${{ env.PY }}-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Install pre-commit
shell: bash
run: pip install -U pre-commit
- name: Run `pre-commit autoupdate`
shell: bash
run: pre-commit autoupdate --color=always
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6

View file

@ -12,7 +12,7 @@ repos:
exclude: ^tests/data/
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.7.0
rev: v0.7.1
hooks:
- id: ruff
- id: ruff-format

View file

@ -5,6 +5,7 @@ vars:
GREETING: Hello, World!
env:
DEFAULT_GROUP: Home
DEFAULT_HOUSEHOLD: Family
PRODUCTION: false
API_PORT: 9000
API_DOCS: True

View file

@ -9,6 +9,7 @@
| PUID | 911 | UserID permissions between host OS and container |
| PGID | 911 | GroupID permissions between host OS and container |
| DEFAULT_GROUP | Home | The default group for users |
| DEFAULT_HOUSEHOLD | Family | The default household for users in each group |
| BASE_URL | http://localhost:8080 | Used for Notifications |
| TOKEN_TIME | 48 | The time in hours that a login/auth token is valid |
| API_PORT | 9000 | The port exposed by backend API. **Do not change this if you're running in Docker** |

View file

@ -31,7 +31,7 @@ To deploy mealie on your local network, it is highly recommended to use Docker t
We've gone through a few versions of Mealie v1 deployment targets. We have settled on a single container deployment, and we've begun publishing the nightly container on github containers. If you're looking to move from the old nightly (split containers _or_ the omni image) to the new nightly, there are a few things you need to do:
1. Take a backup just in case!
2. Replace the image for the API container with `ghcr.io/mealie-recipes/mealie:v2.0.0`
2. Replace the image for the API container with `ghcr.io/mealie-recipes/mealie:v2.1.0`
3. Take the external port from the frontend container and set that as the port mapped to port `9000` on the new container. The frontend is now served on port 9000 from the new container, so it will need to be mapped for you to have access.
4. Restart the container
@ -65,7 +65,7 @@ After you've decided setup the files it's important to set a few ENV variables t
- [x] You've configured the relevant ENV variables for your database selection in the `docker-compose.yaml` files.
- [x] You've configured the [SMTP server settings](./backend-config.md#email) (used for invitations, password resets, etc). You can setup a [google app password](https://support.google.com/accounts/answer/185833?hl=en) if you want to send email via gmail.
- [x] You've set the [`BASE_URL`](./backend-config.md#general) variable.
- [x] You've set the `DEFAULT_EMAIL` and `DEFAULT_GROUP` variable.
- [x] You've set the `DEFAULT_EMAIL`, `DEFAULT_GROUP`, and `DEFAULT_HOUSEHOLD` variables.
## Step 4: Startup

View file

@ -7,7 +7,7 @@ PostgreSQL might be considered if you need to support many concurrent users. In
```yaml
services:
mealie:
image: ghcr.io/mealie-recipes/mealie:v2.0.0 # (3)
image: ghcr.io/mealie-recipes/mealie:v2.1.0 # (3)
container_name: mealie
restart: always
ports:

View file

@ -11,7 +11,7 @@ SQLite is a popular, open source, self-contained, zero-configuration database th
```yaml
services:
mealie:
image: ghcr.io/mealie-recipes/mealie:v2.0.0 # (3)
image: ghcr.io/mealie-recipes/mealie:v2.1.0 # (3)
container_name: mealie
restart: always
ports:

View file

@ -205,23 +205,14 @@ export default defineComponent({
const route = useRoute();
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
const router = useRouter();
function navigateRandom() {
if (props.recipes.length > 0) {
const recipe = props.recipes[Math.floor(Math.random() * props.recipes.length)];
if (recipe.slug !== undefined) {
router.push(`/g/${groupSlug.value}/r/${recipe.slug}`);
}
}
}
const page = ref(1);
const perPage = 32;
const hasMore = ref(true);
const ready = ref(false);
const loading = ref(false);
const { fetchMore } = useLazyRecipes(isOwnGroup.value ? null : groupSlug.value);
const { fetchMore, getRandom } = useLazyRecipes(isOwnGroup.value ? null : groupSlug.value);
const router = useRouter();
const queryFilter = computed(() => {
const orderBy = props.query?.orderBy || preferences.value.orderBy;
@ -383,6 +374,15 @@ export default defineComponent({
}, useAsyncKey());
}
async function navigateRandom() {
const recipe = await getRandom(props.query, queryFilter.value);
if (!recipe?.slug) {
return;
}
router.push(`/g/${groupSlug.value}/r/${recipe.slug}`);
}
function toggleMobileCards() {
preferences.value.useMobileCards = !preferences.value.useMobileCards;
}

View file

@ -98,7 +98,7 @@
<tr v-for="(value, key) in recipe.nutrition" :key="key">
<template v-if="value">
<td>{{ labels[key].label }}</td>
<td>{{ value || '-' }}</td>
<td>{{ value ? (labels[key].suffix ? `${value} ${labels[key].suffix}` : value) : '-' }}</td>
</template>
</tr>
</tbody>
@ -322,10 +322,32 @@ li {
}
.nutrition-table {
width: 25%;
max-width: 80%;
border-collapse: collapse;
}
.nutrition-table th,
.nutrition-table td {
padding: 6px 10px;
text-align: left;
vertical-align: top;
font-size: 14px;
}
.nutrition-table th {
font-weight: bold;
padding-bottom: 10px;
}
.nutrition-table td:first-child {
width: 70%;
font-weight: bold;
}
.nutrition-table td:last-child {
width: 30%;
text-align: right;
}
.nutrition-table td {
padding: 2px;
text-align: left;

View file

@ -97,8 +97,8 @@ export default defineComponent({
},
});
const numerator = ref<number>(parseFloat(props.basicYieldNum.toFixed(3)) ?? 1);
const denominator = parseFloat(props.basicYieldNum.toFixed(32)) ?? 1;
const numerator = ref<number>(props.basicYieldNum != null ? parseFloat(props.basicYieldNum.toFixed(3)) : 1);
const denominator = props.basicYieldNum != null ? parseFloat(props.basicYieldNum.toFixed(32)) : 1;
const numberParsed = !!props.basicYieldNum;
watch(() => numerator.value, () => {

View file

@ -54,7 +54,7 @@ export function useParsedIngredientText(ingredient: RecipeIngredient, disableAmo
// casting to number is required as sometimes quantity is a string
if (quantity && Number(quantity) !== 0) {
if (unit && !unit.fraction) {
returnQty = (quantity * scale).toString();
returnQty = Number((quantity * scale).toPrecision(3)).toString();
} else {
const fraction = frac(quantity * scale, 10, true);
if (fraction[0] !== undefined && fraction[0] > 0) {

View file

@ -8,6 +8,32 @@ import { RecipeSearchQuery } from "~/lib/api/user/recipes/recipe";
export const allRecipes = ref<Recipe[]>([]);
export const recentRecipes = ref<Recipe[]>([]);
function getParams(
orderBy: string | null = null,
orderDirection = "desc",
query: RecipeSearchQuery | null = null,
queryFilter: string | null = null
) {
return {
orderBy,
orderDirection,
paginationSeed: query?._searchSeed, // propagate searchSeed to stabilize random order pagination
searchSeed: query?._searchSeed, // unused, but pass it along for completeness of data
search: query?.search,
cookbook: query?.cookbook,
households: query?.households,
categories: query?.categories,
requireAllCategories: query?.requireAllCategories,
tags: query?.tags,
requireAllTags: query?.requireAllTags,
tools: query?.tools,
requireAllTools: query?.requireAllTools,
foods: query?.foods,
requireAllFoods: query?.requireAllFoods,
queryFilter,
};
};
export const useLazyRecipes = function (publicGroupSlug: string | null = null) {
const router = useRouter();
@ -25,24 +51,11 @@ export const useLazyRecipes = function (publicGroupSlug: string | null = null) {
queryFilter: string | null = null,
) {
const { data, error } = await api.recipes.getAll(page, perPage, {
orderBy,
orderDirection,
paginationSeed: query?._searchSeed, // propagate searchSeed to stabilize random order pagination
searchSeed: query?._searchSeed, // unused, but pass it along for completeness of data
search: query?.search,
cookbook: query?.cookbook,
households: query?.households,
categories: query?.categories,
requireAllCategories: query?.requireAllCategories,
tags: query?.tags,
requireAllTags: query?.requireAllTags,
tools: query?.tools,
requireAllTools: query?.requireAllTools,
foods: query?.foods,
requireAllFoods: query?.requireAllFoods,
queryFilter,
});
const { data, error } = await api.recipes.getAll(
page,
perPage,
getParams(orderBy, orderDirection, query, queryFilter),
);
if (error?.response?.status === 404) {
router.push("/login");
@ -74,6 +87,13 @@ export const useLazyRecipes = function (publicGroupSlug: string | null = null) {
recipes.value = val;
}
async function getRandom(query: RecipeSearchQuery | null = null, queryFilter: string | null = null) {
const { data } = await api.recipes.getAll(1, 1, getParams("random", "desc", query, queryFilter));
if (data?.items.length) {
return data.items[0];
}
}
return {
recipes,
fetchMore,
@ -81,6 +101,7 @@ export const useLazyRecipes = function (publicGroupSlug: string | null = null) {
assignSorted,
removeRecipe,
replaceRecipes,
getRandom,
};
};

View file

@ -14,7 +14,7 @@
"development": "פיתוח",
"docs": "תיעוד",
"download-log": "הורדת לוגים",
"download-recipe-json": JSON האחרון שנקרא",
"download-recipe-json": -JSON האחרון שנקרא",
"github": "גיטהאב",
"log-lines": "שורות לוג",
"not-demo": "לא בהדגמה",
@ -54,7 +54,7 @@
"apprise-url": "קישור להודעה",
"database": "מסד נתונים",
"delete-event": "מחיקת אירוע",
"event-delete-confirmation": "האם את/ה בטוח/ה שברצונך למחוק את האירוע?",
"event-delete-confirmation": "למחוק את האירוע?",
"event-deleted": "אירוע נמחק",
"event-updated": "האירוע עודכן",
"new-notification-form-description": "Mקשךןק עושה שימוש בספריה בשם Apprise לשליחת התראות. Apprise מציעה אפשרויות רבות עבור התראות לבעלי שירותים. פנה לאתר הWiki של Apprise להסבר מלא על יצירת לינקים לשירות שלך.",
@ -88,7 +88,7 @@
"close": "סגירה",
"confirm": "אישור",
"confirm-how-does-everything-look": "איך הכל נראה?",
"confirm-delete-generic": "האם את/ה בטוח/ה שברצונך למחוק את זה?",
"confirm-delete-generic": "למחוק את זה?",
"copied_message": "הועתק!",
"create": "יצירה",
"created": "נוצר",
@ -189,7 +189,7 @@
"menu": "תפריט",
"a-name-is-required": "נדרש שם",
"delete-with-name": "מחיקת {name}",
"confirm-delete-generic-with-name": "האם את/ה בטוח/ה שברצונך למחוק את {name}?",
"confirm-delete-generic-with-name": "למחוק את {name}?",
"confirm-delete-own-admin-account": "אזהרה! אתה עומד למחוק את חשבון המנהל שלך. פעולה זו לא ניתנת לביטול ותמחק לחלוטין את החשבון שלך. האם להמשיך?",
"organizer": "מארגן",
"transfer": "העברה",
@ -211,7 +211,7 @@
"created-on-date": "נוצר ב-{0}",
"unsaved-changes": "יש שינויים שלא נשמרו. לצאת לפני שמירה? אשר לשמירה, בטל למחיקת שינויים.",
"clipboard-copy-failure": "כשלון בהעתקה ללוח ההדבקה.",
"confirm-delete-generic-items": "האם אתה בטוח שברצונך למחוק את הפריטים הנבחרים?",
"confirm-delete-generic-items": "למחוק את הפריטים שנבחרו?",
"organizers": "מארגנים",
"caution": "זהירות",
"show-advanced": "הצג הגדרות מתקדמות",
@ -220,7 +220,7 @@
"date-updated": "תאריך עדכון"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "האם את/ה בטוח/ה שברצונך למחוק את <b>{groupName}<b/>?",
"are-you-sure-you-want-to-delete-the-group": "למחוק את <b>{groupName}<b/>?",
"cannot-delete-default-group": "לא ניתן למחוק את קבוצת ברירת המחדל",
"cannot-delete-group-with-users": "לא ניתן למחוק קבוצה עם משתמשים",
"confirm-group-deletion": "אשר/י מחיקת קבוצה",
@ -322,7 +322,7 @@
"mealplan-updated": "תכנית ארוחה עודכנה",
"mealplan-households-description": "אם לא נבחר משק בית, ניתן להוסיף מתכונים מכל משק בית",
"any-category": "כל קטגוריה",
"any-tag": "כל תג",
"any-tag": "כל תגית",
"any-household": "כל משק בית",
"no-meal-plan-defined-yet": "עדיין לא הוגדרה תכנית ארוחה",
"no-meal-planned-for-today": "לא מתוכננת ארוחה להיום",
@ -377,7 +377,7 @@
},
"nextcloud": {
"description": "ייבא מידע מספר המתכונים ב- Nextcould",
"description-long": "ייבוא מתכונים מ- Nextcould יכול להתבצע בקובץ zip שמכיל את המידע מ- Nextcloud. ראה את דוגמת מבנה התיקיות למטה כדי לוודא שניתן לייבא את המתכון.",
"description-long": "ייבוא מתכונים מ-Nextcould יכול להתבצע בקובץ zip שמכיל את המידע. המבנה צריך להתאים לתיקייה לדוגמא למטה כדי להבטיח שניתן לייבא את המתכון.",
"title": "ספר בישול של Nextcloud"
},
"copymethat": {
@ -400,8 +400,8 @@
"recipe-data-migrations-explanation": "ניתן לייבא מתכונים מאפליקציות תומכות אחרות אל Mealie. זו דרך מעולה להתחיל במילי.",
"coming-from-another-application-or-an-even-older-version-of-mealie": "הגעת מתוכנה אחרת או גרסה ישנה יותר של Mealie? מומלץ לבדוק מיגרציות ולראות אם ניתן לייבא את המידע שלך.",
"choose-migration-type": "בחר סוג מיגרציה",
"tag-all-recipes": "תייג את כל המתכונים עם תגית {tag-name}",
"nextcloud-text": "ייבוא מתכונים מ- Nextcould יכול להתבצע בקובץ zip שמכיל את המידע מ- Nextcloud. ראה את דוגמת מבנה התיקיות למטה כדי לוודא שניתן לייבא את המתכון.",
"tag-all-recipes": "תיוג את כל המתכונים עם תגית {tag-name}",
"nextcloud-text": "ייבוא מתכונים מ-Nextcould יכול להתבצע בקובץ zip שמכיל את המידע. המבנה צריך להתאים לתיקייה לדוגמא למטה כדי להבטיח שניתן לייבא את המתכון.",
"chowdown-text": "Mealie תומכת באופן טבעי בפורמט Chowdown. יש להוריד את רפוזיטורי הקוד כ-zip ולהעלות אותו כאן.",
"recipe-1": "מתכון 1",
"recipe-2": "מתכון 2",
@ -470,7 +470,7 @@
"comment-action": "הערה",
"comment": "הערה",
"comments": "הערות",
"delete-confirmation": "האם את/ה בטוח/ה שברצונך למחוק את המתכון הזה?",
"delete-confirmation": "למחוק את המתכון הזה?",
"delete-recipe": "מחיקת מתכון",
"description": "תיאור",
"disable-amount": "ביטול כמויות מרכיבים",
@ -607,7 +607,7 @@
"should-translate-description": "תרגום המתכון לשפה שלי",
"please-wait-image-procesing": "נה להמתין, התמונה עוברת עיבוץ. זה יכול לקחת זמן.",
"bulk-url-import": "ייבוא מספר לינקים",
"debug-scraper": "סורק דיבוג",
"debug-scraper": "סורק לניפוי שגיאות",
"create-a-recipe-by-providing-the-name-all-recipes-must-have-unique-names": "יצירת מתכון באמצעות שם. כל שמות המתכונים צריכים להיות שונים.",
"new-recipe-names-must-be-unique": "שם מתכון חדש חייב להיות ייחודי",
"scrape-recipe": "קריאת מתכון",
@ -616,7 +616,7 @@
"scrape-recipe-suggest-bulk-importer": "נסה את יכולת קריאת רשימה",
"scrape-recipe-have-raw-html-or-json-data": "יש לך מידע גולמי ב-HTML או JSON?",
"scrape-recipe-you-can-import-from-raw-data-directly": "ניתן לייבא ישירות ממידע גולמי",
"import-original-keywords-as-tags": "ייבא שמות מפתח מקוריות כתגיות",
"import-original-keywords-as-tags": "ייבוא שמות מפתח מקוריות כתגיות",
"stay-in-edit-mode": "השאר במצב עריכה",
"import-from-zip": "ייבא מקובץ",
"import-from-zip-description": "ייבוא מתכון בודד שיוצא ממילי אחרת.",
@ -634,11 +634,11 @@
"bulk-import-process-has-started": "ייבוא קבוצה התחיל",
"bulk-import-process-has-failed": "יבוא קבוצתי נכשל",
"report-deletion-failed": "מחיקת דוח נכשלה",
"recipe-debugger": "דיבאגר למתכון",
"recipe-debugger-description": "ניתן להדביק פה קישור למתכון שברצונך לדבג. הכתובת תיסרק ע\"י סורק המתכונים והתוצאות יוצגו. אם לא חוזרות תוצאות, האתר לא נתמך ע\"י Mealie או ספריית הסריקה.",
"recipe-debugger": "מנפה שגיאות למתכון",
"recipe-debugger-description": "ניתן להדביק פה קישור למתכון שברצונך לנפות שגיאות עבורו. הכתובת תיסרק ע\"י סורק המתכונים והתוצאות יוצגו. אם לא חוזרות תוצאות, האתר לא נתמך ע\"י Mealie או ספריית הסריקה.",
"use-openai": "השתמש ב-OpenAI",
"recipe-debugger-use-openai-description": "ניתן להשתמש ב-OpenAI כדי לפענח את התוצאות במקום להסתמך על ספריית הסריקה. כאשר מייצרים מתכון באמצעות כתובת, זה נעשה אוטומטית אם ספריית הסריקה נכשלת, אך ניתן לבדוק זאת ידנית כאן.",
"debug": "דיבאג",
"debug": "ניפוי שגיאות",
"tree-view": "תצוגת עץ",
"recipe-yield": "תשואת מתכון",
"unit": "יחידה",
@ -701,7 +701,7 @@
"import-summary": "ייבא תקציר",
"partial-backup": "גיבוי חלקי",
"unable-to-delete-backup": "לא ניתן למחוק גיבוי.",
"experimental-description": "Backups are total snapshots of the database and data directory of the site. This includes all data and cannot be set to exclude subsets of data. You can think of this as a snapshot of Mealie at a specific time. These serve as a database agnostic way to export and import data, or back up the site to an external location.",
"experimental-description": "גיבויים הם תמונת מצב של מסד הנתונים ותיקיית המידע של האתר. זה כולל את כל המידע ולא ניתן להוריד חלק מהמידע. ניתן להתייחס אליהם כתמונת מצב של Mealie בזמן מסוים. הגיבויים הם דרך לייבוא ולייצוא מידע ללא תלות במסד הנתונים עצמו, או לגיבוי האתר למיקום חיצוני.",
"backup-restore": "גיבוי / שחזור",
"back-restore-description": "שחזור מגיבוי זה ידרוס את המידע הקיים במסד הנתונים ובספריות האתר ויחליף אותם בזה הקיים בגיבוי. {cannot-be-undone} אם השחזור יצליח, המשתמש ינותק מהמערכת.",
"cannot-be-undone": "פעולה זו לא בלתי הפיכה - השתמש בזהירות.",
@ -809,7 +809,7 @@
"email-configured": "דואר אלקטרוני הוגדר",
"email-test-results": "תוצאות בדיקת דואר אלקטרוני",
"ready": "מוכן",
"not-ready": "לא מוכן - בדוק משתני סביבה",
"not-ready": "לא מוכן - נא לבדוק משתני סביבה",
"succeeded": "הצליח",
"failed": "נכשל",
"general-about": "מידע כללי",
@ -823,16 +823,16 @@
"server-side-base-url-error-text": "'כתובת בסיס' היא עדיין הערך ברירת המחדל בשרת ה- API. הדבר יגרום לבעיות עם קישורי התראות בשרת עבור אימייל וכו'.",
"server-side-base-url-success-text": "קישור צד שרת אינו תואם לברירת המחדל",
"ldap-ready": "LDAP מוכן",
"ldap-ready-error-text": "לא כל ערכי ה- LDAP מוגדרים. ניתן להתעלם אם אינך משתמשת באימות LDAP.",
"ldap-ready-success-text": "כל משתני ה- LDAP הנחוצים מוגדרים.",
"ldap-ready-error-text": "לא כל הערכים הנחוצים ל-LDAP מוגדרים. ניתן להתעלם אם לא נעשה שימוש באימות LDAP.",
"ldap-ready-success-text": "כל המשתנים הנחוצים ל-LDAP מוגדרים.",
"build": "בניה",
"recipe-scraper-version": "גרסת סורק המתכונים",
"oidc-ready": "OIDC Ready",
"oidc-ready-error-text": "Not all OIDC Values are configured. This can be ignored if you are not using OIDC Authentication.",
"oidc-ready-success-text": "Required OIDC variables are all set.",
"openai-ready": "OpenAI Ready",
"openai-ready-error-text": "Not all OpenAI Values are configured. This can be ignored if you are not using OpenAI features.",
"openai-ready-success-text": "Required OpenAI variables are all set."
"oidc-ready": "OIDC מוכן",
"oidc-ready-error-text": "לא כל הערכים הנחוצים ל-OIDC מוגדרים. ניתן להתעלם אם לא נעשה שימוש באימות OIDC.",
"oidc-ready-success-text": "כל המשתנים הנחוצים ל-OIDC מוגדרים.",
"openai-ready": "OpenAI מוכן",
"openai-ready-error-text": "לא כל הערכים הנחוצים ל-OpenAI מוגדרים. ניתן להתעלם אם לא נעשה שימוש ב-OpenAI.",
"openai-ready-success-text": "כל המשתנים הנחוצים ל-OpenAI מוגדרים."
},
"shopping-list": {
"all-lists": "כל הרשימות",
@ -850,7 +850,7 @@
"linked-item-warning": "האובייקט הזה מקושר לאחד או יותר מתכונים. שינוי היחידות או האוכל יוביל לתוצאות בלתי צפויות בהוספה או הסרת מתכונים מהרשימה.",
"toggle-food": "הצג/הסתר אוכל",
"manage-labels": "ניהול תוויות",
"are-you-sure-you-want-to-delete-this-item": "האם אתה בטוח שברצונך למחוק פריט זה?",
"are-you-sure-you-want-to-delete-this-item": "למחוק פריט זה?",
"copy-as-text": "העתק כטקסט",
"copy-as-markdown": "העתק כ-Markdown",
"delete-checked": "מחק מסומנים",
@ -862,11 +862,11 @@
"items-checked-count": "לא נבחרו פריטים|פריט אחד נבחר|{count} פריטים נבחרו",
"no-label": "ללא תווית",
"completed-on": "הושלם ב- {date}",
"you-are-offline": "You are offline",
"you-are-offline-description": "Not all features are available while offline. You can still add, modify, and remove items, but you will not be able to sync your changes to the server until you are back online.",
"are-you-sure-you-want-to-check-all-items": "Are you sure you want to check all items?",
"are-you-sure-you-want-to-uncheck-all-items": "Are you sure you want to uncheck all items?",
"are-you-sure-you-want-to-delete-checked-items": "Are you sure you want to delete all checked items?"
"you-are-offline": "במצב לא מקוון",
"you-are-offline-description": "חלק מהיכולות אינן זמינות במצב לא מקוון. עדיין ניתן להוסיף, לשנות, ולהוריד פריטים, אך לא ניתן לסנכרן את השינויים שלך לשרת עד לחידוש החיבור.",
"are-you-sure-you-want-to-check-all-items": "לסמן את כל הפריטים?",
"are-you-sure-you-want-to-uncheck-all-items": "לבטל את סימון כל הפריטים?",
"are-you-sure-you-want-to-delete-checked-items": "למחוק את כל הפריטים המסומנים?"
},
"sidebar": {
"all-recipes": "כל המתכונים",
@ -909,7 +909,7 @@
"tag-updated": "תגית עודכנה",
"tags": "תגיות",
"untagged-count": "לא מתוייג {count}",
"create-a-tag": "צור תגית",
"create-a-tag": "יצירת תגית",
"tag-name": "שם תגית",
"tag": "תגית"
},
@ -925,8 +925,8 @@
},
"user": {
"admin": "אדמין",
"are-you-sure-you-want-to-delete-the-link": "האם את/ה בטוח/ה שברצונך למחוק את הלינק <b>{link}<b/>?",
"are-you-sure-you-want-to-delete-the-user": "האם את/ה בטוח/ה שברצונך למחוק את המשתמש <b>{activeName} ID: {activeId}<b/>?",
"are-you-sure-you-want-to-delete-the-link": "למחוק את הלינק <b>{link}<b/>?",
"are-you-sure-you-want-to-delete-the-user": "למחוק את המשתמש <b>{activeName} מזהה: {activeId}<b/>?",
"auth-method": "שיטת אימות",
"confirm-link-deletion": "אשר מחיקת לינק",
"confirm-password": "אימות סיסמה",
@ -1016,7 +1016,7 @@
"user-can-organize-group-data": "משתמש יכול לשנות מידע של קבוצה",
"enable-advanced-features": "אפשר אפשרויות מתקדמות",
"it-looks-like-this-is-your-first-time-logging-in": "נראה שזו ההתחברות הראשונה שלך.",
"dont-want-to-see-this-anymore-be-sure-to-change-your-email": "לא רוצה לראות את זה יותר? דאג לשנות את המייל של בהגדרות המשתמש!",
"dont-want-to-see-this-anymore-be-sure-to-change-your-email": "לא רוצה לראות את זה יותר? ניתן לשנות את המייל שלך בהגדרות המשתמש!",
"forgot-password": "שכחתי סיסמא",
"forgot-password-text": "נא לספק כתובת דוא\"ל. אנו נשלח לך הודעת דוא\"ל לצורך איפוס הסיסמה שלך.",
"changes-reflected-immediately": "שינויים למשתמש זה ישתקפו מיידית."
@ -1077,8 +1077,8 @@
},
"recipes": {
"purge-exports": "נקה ייצואים",
"are-you-sure-you-want-to-delete-all-export-data": "האם אתה בטוח שאתה רוצה למחוק נתוני הייצוא?",
"confirm-delete-recipes": "האם אתה בטוח שאתה רוצה למחוק את המתכונים הבאים? פעולה זו בלתי הפיכה.",
"are-you-sure-you-want-to-delete-all-export-data": "למחוק את כל נתוני הייצוא?",
"confirm-delete-recipes": "למחוק את המתכונים שנבחרו? פעולה זו בלתי הפיכה.",
"the-following-recipes-selected-length-will-be-exported": "המתכונים הבאים ({0}) ייוצאו.",
"settings-chosen-explanation": "הגדרות שנבחרו מלבד האפשרויות הנעולות, יופעלו על כל המתכונים שנבחרו.",
"selected-length-recipe-s-settings-will-be-updated": "הגדרות של {count} מתכונים יעודכנו.",
@ -1097,10 +1097,10 @@
"source-unit-will-be-deleted": "יחידת המקור תמחק"
},
"recipe-actions": {
"recipe-actions-data": "Recipe Actions Data",
"new-recipe-action": "New Recipe Action",
"edit-recipe-action": "Edit Recipe Action",
"action-type": "Action Type"
"recipe-actions-data": "מידע על הפעולות במתכון",
"new-recipe-action": "פעולת-מתכון חדשה",
"edit-recipe-action": "עריכת פעולת-מתכון",
"action-type": "סוג פעולה"
},
"create-alias": "יצירת שם נרדף",
"manage-aliases": "נהל שמות נרדפים",
@ -1118,9 +1118,9 @@
"category-data": "נתוני קטגוריה"
},
"tags": {
"new-tag": "טאג חדש",
"edit-tag": "ערוך טאג",
"tag-data": "נתוני טאגים"
"new-tag": "תגית חדשה",
"edit-tag": "עריכת תגית",
"tag-data": "נתוני תגיות"
},
"tools": {
"new-tool": "כלי חדש",
@ -1261,54 +1261,54 @@
"setup": {
"first-time-setup": "הגדרה ראשונית",
"welcome-to-mealie-get-started": "ברוכים הבאים ל-Mealie! בואו נתחיל",
"already-set-up-bring-to-homepage": "I'm already set up, just bring me to the homepage",
"common-settings-for-new-sites": "Here are some common settings for new sites",
"setup-complete": "Setup Complete!",
"here-are-a-few-things-to-help-you-get-started": "Here are a few things to help you get started with Mealie",
"restore-from-v1-backup": "Have a backup from a previous instance of Mealie v1? You can restore it here.",
"manage-profile-or-get-invite-link": "Manage your own profile, or grab an invite link to share with others."
"already-set-up-bring-to-homepage": "כבר הגדרתי הכל, תעבירו אותי לעמוד הבית",
"common-settings-for-new-sites": "הגדרות נפוצות לאתרים חדשים יופיעו כאן",
"setup-complete": "ההגדרה הושלמה!",
"here-are-a-few-things-to-help-you-get-started": "כמה דברים שיעזרו לך להתחיל להשתמש ב-Mealie",
"restore-from-v1-backup": "יש לך גיבוי משרת Mealie v1? ניתן לשחזר אותו כאן.",
"manage-profile-or-get-invite-link": "ניתן לנהל את הפרופיל שלך, או לשתף את לינק ההזמנה לאחרים."
},
"debug-openai-services": "Debug OpenAI Services",
"debug-openai-services-description": "Use this page to debug OpenAI services. You can test your OpenAI connection and see the results here. If you have image services enabled, you can also provide an image.",
"run-test": "Run Test",
"test-results": "Test Results",
"group-delete-note": "Groups with users or households cannot be deleted",
"household-delete-note": "Households with users cannot be deleted"
"debug-openai-services": "ניפוי שגיאות לשירותי OpenAI",
"debug-openai-services-description": "עמוד זה ישמש לניפוי שגיאות בשירותי OpenAI. ניתן לבדוק חיבור ל-OpenAI ולראות את התוצאות כאן. אם איפשרת את שירותי התמונה, ניתן גם לספק תמונה.",
"run-test": "הרצת בדיקה",
"test-results": "תוצאות הבדיקה",
"group-delete-note": "לא ניתן למחוק קבוצות עם משתמשים או משקי בית",
"household-delete-note": "לא ניתן למחוק משקי בית עם משתמשים"
},
"profile": {
"welcome-user": "👋 Welcome, {0}!",
"welcome-user": "👋 שלום, {0}!",
"description": "ניהול פרופיל, מתכונים והגדרות קבוצה.",
"get-invite-link": "קבלת קישור להזמנה",
"get-public-link": "כתובת פומבית",
"account-summary": "פירוט משתמש",
"account-summary-description": "Here's a summary of your group's information.",
"account-summary-description": "הנה סיכום המידע של הקבוצה שלך.",
"group-statistics": "נתונים סטטיסטיים של קבוצה",
"group-statistics-description": "סטטיסטיקות על הקבוצה שלך.",
"household-statistics": "Household Statistics",
"household-statistics-description": "Your Household Statistics provide some insight how you're using Mealie.",
"household-statistics": "סטטיסטיקות משק הבית",
"household-statistics-description": "סטטיסטיקות משק הבית שלך מספקות תובנות לאיך אתם משתמשים ב-Mealie.",
"storage-capacity": "מקום אחסון",
"storage-capacity-description": "מקום האחסון מחושב ע\"י סיכום התמונות והקבצים שהעלת.",
"personal": "אישי",
"personal-description": "These are settings that are personal to you. Changes here won't affect other users.",
"personal-description": "הגדרות אלה אישיות עבורך. שינויים לא ישפיעו על משתמשים אחרים.",
"user-settings": "הגדרות משתמש",
"user-settings-description": "Manage your preferences, change your password, and update your email.",
"api-tokens-description": "Manage your API Tokens for access from external applications.",
"user-settings-description": "ניהול ההעדפות שלך, שינוי סיסמא, ועדכון כתובת מייל.",
"api-tokens-description": "ניהול אסימוני API יאפשר גישה ליישומים חיצוניים.",
"group-description": "פריטים אלו שותפו עם קבוצתך. עריכתם תבצע שינוי עבור כל הקבוצה!",
"group-settings": "הגדרות קבוצה",
"group-settings-description": "Manage your common group settings, like privacy settings.",
"household-description": "These items are shared within your household. Editing one of them will change it for the whole household!",
"household-settings": "Household Settings",
"household-settings-description": "Manage your household settings, like mealplan and privacy settings.",
"group-settings-description": "ניהול הגדרות הקבוצות שלך, כגון הגדרות פרטיות.",
"household-description": "פריטים אלה משותפים עם משק הבית שלך. עריכה תשנה אותם עבור משק הבית כולו!",
"household-settings": "הגדרות משק הבית",
"household-settings-description": "ניהול הגדרות משק הבית שלך, כגון תכנון ארוחות והגדרות פרטיות.",
"cookbooks-description": "נהל אוסף של מתכונים וצור עבורם עמודים.",
"members": "חברים",
"members-description": "See who's in your household and manage their permissions.",
"members-description": "צפייה בחברי משק הביתה שלך ובהרשאות שלהם.",
"webhooks-description": "הגדר webhooks אשר יופעלו בימים בהם יש לך תוכניות ארוחות.",
"notifiers": "מתריעים",
"notifiers-description": "הגדרת הודעות דואל והודעות בדחיפה אשר יופעלו עם אירועים ספציפיים.",
"manage-data": "נהל נתונים",
"manage-data-description": "Manage your Mealie data; Foods, Units, Categories, Tags and more.",
"manage-data-description": "ניהול המידע שלך ב-Mealie; אוכל, יחידות מידה, קטגוריות, תגיות ועוד.",
"data-migrations": "ניוד נתונים",
"data-migrations-description": "Migrate your existing data from other applications like Nextcloud Recipes and Chowdown.",
"data-migrations-description": "העברת המידע שלך מאפליקציות אחרות כגון Nextcloud Recipes ו-Chowdown.",
"email-sent": "דוא\"ל נשלח",
"error-sending-email": "שגיאה בשליחת דוא\"ל",
"personal-information": "פרטים אישיים",
@ -1326,7 +1326,7 @@
},
"cookbook": {
"cookbooks": "ספרי בישול",
"description": "Cookbooks are another way to organize recipes by creating cross sections of recipes, organizers, and other filters. Creating a cookbook will add an entry to the side-bar and all the recipes with the filters chosen will be displayed in the cookbook.",
"description": "ספרי בישול הם דרך נוספת לסידור מתכונים על ידי חיתוך של מתכונים, מארגנים, ומסננים נוספים. יצירת ספר בישול תוסיף רשומה לתפריט הצדדי וכל המתכונים שעונים לסינון יוצגו באופן אוטומטי.",
"public-cookbook": "ספר בישול פומבי",
"public-cookbook-description": "ספרי בישול ניתנים לשיתוף עם משתמשים מחוץ ל-Mealie ויופיעו בתוך עמוד הקבוצות.",
"filter-options": "אפשרויות סינון",
@ -1336,31 +1336,31 @@
"require-all-tools": "זקוק לכל הכלים",
"cookbook-name": "שם ספר בישול",
"cookbook-with-name": "ספר בישול {0}",
"household-cookbook-name": "{0} Cookbook {1}",
"household-cookbook-name": "{0} ספר בישול {1}",
"create-a-cookbook": "צור ספר בישול חדש",
"cookbook": "ספר בישול"
},
"query-filter": {
"logical-operators": {
"and": "AND",
"or": "OR"
"and": "וגם",
"or": "או"
},
"relational-operators": {
"equals": "equals",
"does-not-equal": "does not equal",
"is-greater-than": "is greater than",
"is-greater-than-or-equal-to": "is greater than or equal to",
"is-less-than": "is less than",
"is-less-than-or-equal-to": "is less than or equal to"
"equals": "שווה",
"does-not-equal": "לא שווה",
"is-greater-than": "גדול מ-",
"is-greater-than-or-equal-to": "גדול או שווה ל-",
"is-less-than": "קטן מ-",
"is-less-than-or-equal-to": "קטן או שווה ל-"
},
"relational-keywords": {
"is": "is",
"is-not": "is not",
"is-one-of": "is one of",
"is-not-one-of": "is not one of",
"contains-all-of": "contains all of",
"is-like": "is like",
"is-not-like": "is not like"
"is": "זהה ל-",
"is-not": "לא זהה ל-",
"is-one-of": "אחד מ-",
"is-not-one-of": "לא אחד מ-",
"contains-all-of": "מכיל הכל מתוך",
"is-like": "דומה ל-",
"is-not-like": "לא דומה לא-"
}
}
}

View file

@ -182,7 +182,7 @@
"date": "日付",
"id": "Id",
"owner": "所有者",
"change-owner": "Change Owner",
"change-owner": "所有者の変更",
"date-added": "追加日",
"none": "なし",
"run": "実行",
@ -214,10 +214,10 @@
"confirm-delete-generic-items": "次のアイテムを本当に削除しますか?",
"organizers": "収納",
"caution": "注意",
"show-advanced": "Show Advanced",
"add-field": "Add Field",
"date-created": "Date Created",
"date-updated": "Date Updated"
"show-advanced": "詳細を表示",
"add-field": "フィールドを追加",
"date-created": "作成日",
"date-updated": "更新日"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "<b>{groupName}<b/> を削除しますか?",
@ -356,7 +356,7 @@
"for-type-meal-types": "{0} の食事の種類",
"meal-plan-rules": "食事プランのルール",
"new-rule": "新しいルール",
"meal-plan-rules-description": "You can create rules for auto selecting recipes for your meal plans. These rules are used by the server to determine the random pool of recipes to select from when creating meal plans. Note that if rules have the same day/type constraints then the rule filters will be merged. In practice, it's unnecessary to create duplicate rules, but it's possible to do so.",
"meal-plan-rules-description": "食事プランのレシピを自動選択するためのルールを作成できます。これらのルールは、食事プランを作成するときに選択するレシピのランダムプールを決定するためにサーバーによって使用されます。ルールに同じ日/タイプの制約がある場合は、ルールフィルターが結合されることに注意してください。実際には、重複したルールを作成する必要はありませんが、重複して作成することは可能です。",
"new-rule-description": "食事プランの新しいルールを作成する場合は、特定の曜日および/または特定の種類の食事に適用されるルールを制限できます。 すべての日またはすべての食事タイプにルールを適用するには、その日または食事タイプのすべての可能な値に適用されるルールを \"すべて\" に設定できます。",
"recipe-rules": "レシピのルール",
"applies-to-all-days": "すべての日に適用",
@ -1272,8 +1272,8 @@
"debug-openai-services-description": "このページを使用して、OpenAIサービスをデバッグします。ここでOpenAI接続をテストし、結果を確認できます。画像サービスが有効になっている場合は、画像を提供することもできます。",
"run-test": "テスト実行",
"test-results": "テスト結果",
"group-delete-note": "Groups with users or households cannot be deleted",
"household-delete-note": "Households with users cannot be deleted"
"group-delete-note": "ユーザーまたは世帯を含むグループは削除できません",
"household-delete-note": "ユーザーがいる世帯は削除できません"
},
"profile": {
"welcome-user": "👋 ようこそ, {0}!",
@ -1326,7 +1326,7 @@
},
"cookbook": {
"cookbooks": "料理本",
"description": "Cookbooks are another way to organize recipes by creating cross sections of recipes, organizers, and other filters. Creating a cookbook will add an entry to the side-bar and all the recipes with the filters chosen will be displayed in the cookbook.",
"description": "料理本は、レシピのクロスセクション、オーガナイザー、その他のフィルターを作成してレシピを整理するもう 1 つの方法です。料理本を作成するとサイドバーにエントリが追加され、選択したフィルターが適用されたすべてのレシピが料理本に表示されます。",
"public-cookbook": "公開料理本",
"public-cookbook-description": "公開料理本は非Mealieユーザーと共有でき、グループページに表示されます。",
"filter-options": "フィルタオプション",
@ -1346,21 +1346,21 @@
"or": "OR"
},
"relational-operators": {
"equals": "equals",
"does-not-equal": "does not equal",
"is-greater-than": "is greater than",
"is-greater-than-or-equal-to": "is greater than or equal to",
"is-less-than": "is less than",
"is-less-than-or-equal-to": "is less than or equal to"
"equals": "等しい",
"does-not-equal": "等しくない",
"is-greater-than": "より大きい",
"is-greater-than-or-equal-to": "以上",
"is-less-than": "より小さい",
"is-less-than-or-equal-to": "以下"
},
"relational-keywords": {
"is": "is",
"is-not": "is not",
"is-one-of": "is one of",
"is-not-one-of": "is not one of",
"contains-all-of": "contains all of",
"is-like": "is like",
"is-not-like": "is not like"
"is": "",
"is-not": "ではない",
"is-one-of": "のうちの1つです",
"is-not-one-of": "のひとつではない",
"contains-all-of": "すべてを含む",
"is-like": "次のようなものです",
"is-not-like": "というわけではありません"
}
}
}

View file

@ -61,7 +61,7 @@
"new-version": "새로운 버전 사용 가능",
"notification": "알림",
"refresh": "새로고침",
"scheduled": "Scheduled",
"scheduled": "예약됨",
"something-went-wrong": "문제가 발생했습니다!",
"subscribed-events": "구독한 이벤트",
"test-message-sent": "테스트 메시지가 전송됐습니다.",
@ -76,7 +76,7 @@
"when-a-user-in-your-group-creates-a-new-mealplan": "When a user in your group creates a new mealplan",
"shopping-list-events": "Shopping List Events",
"cookbook-events": "Cookbook Events",
"tag-events": "Tag Events",
"tag-events": "Tag 이벤트",
"category-events": "Category Events",
"when-a-new-user-joins-your-group": "When a new user joins your group",
"recipe-events": "Recipe Events"
@ -118,7 +118,7 @@
"json": "JSON",
"keyword": "키워드",
"link-copied": "링크 복사됨",
"loading": "Loading",
"loading": "불러오는 중",
"loading-events": "이벤트를 불러오는 중",
"loading-recipe": "레시피 로딩 중...",
"loading-ocr-data": "Loading OCR data...",
@ -146,49 +146,49 @@
"save": "저장",
"settings": "설정",
"share": "공유",
"show-all": "Show All",
"show-all": "모두 보기",
"shuffle": "섞기",
"sort": "정렬",
"sort-ascending": "Sort Ascending",
"sort-descending": "Sort Descending",
"sort-ascending": "오름차순 정렬",
"sort-descending": "내림차순으로 정렬",
"sort-alphabetically": "알파벳순",
"status": "상태",
"subject": "제목",
"submit": "제출",
"success-count": "성공: {count}",
"sunday": "일요일",
"system": "System",
"templates": "Templates:",
"test": "Test",
"themes": "Themes",
"system": "시스템",
"templates": "템플릿:",
"test": "테스트",
"themes": "테마",
"thursday": "목요일",
"title": "Title",
"token": "Token",
"title": "제목",
"token": "토큰",
"tuesday": "화요일",
"type": "Type",
"update": "Update",
"updated": "Updated",
"upload": "Upload",
"update": "업데이트",
"updated": "업데이트됨",
"upload": "업로드",
"url": "URL",
"view": "View",
"wednesday": "수요일",
"yes": "Yes",
"foods": "Foods",
"yes": "",
"foods": "음식",
"units": "Units",
"back": "Back",
"next": "Next",
"start": "Start",
"back": "뒤로",
"next": "다음",
"start": "시작",
"toggle-view": "Toggle View",
"date": "Date",
"date": "날짜",
"id": "Id",
"owner": "작성자",
"change-owner": "Change Owner",
"date-added": "Date Added",
"date-added": "추가된 날짜",
"none": "없음",
"run": "실행",
"menu": "메뉴",
"a-name-is-required": "이름은 필수 항목 입니다.",
"delete-with-name": "Delete {name}",
"delete-with-name": "{name} 삭제",
"confirm-delete-generic-with-name": "Are you sure you want to delete this {name}?",
"confirm-delete-own-admin-account": "Please note that you are trying to delete your own admin account! This action cannot be undone and will permanently delete your account?",
"organizer": "Organizer",

View file

@ -1278,7 +1278,7 @@
"profile": {
"welcome-user": "👋 Välkommen, {0}!",
"description": "Hantera dina profil, recept och gruppinställningar.",
"get-invite-link": " inbjudningslänk",
"get-invite-link": "Skapa inbjudningslänk",
"get-public-link": "Få offentlig länk",
"account-summary": "Kontosammanfattning",
"account-summary-description": "Här är en sammanfattning av din grupps information.",

View file

@ -1,6 +1,6 @@
{
"name": "mealie",
"version": "2.0.0",
"version": "2.1.0",
"private": true,
"scripts": {
"dev": "nuxt",

View file

@ -323,7 +323,7 @@ export default defineComponent({
// we explicitly set booleans to false since forms don't POST unchecked boxes
const createTarget = ref<CreateIngredientUnit>({
name: "",
fraction: false,
fraction: true,
useAbbreviation: false,
});

View file

@ -13,7 +13,7 @@
"no-recipes-match-your-rules": "규칙과 일치하는 Recipe가 없습니다"
},
"user": {
"user-updated": "User updated",
"user-updated": "사용자 업데이트됨",
"password-updated": "비밀번호가 변경되었습니다",
"invalid-current-password": "현재 비밀번호가 잘못되었습니다",
"ldap-update-password-unavailable": "사용자가 LDAP으로 제어되기 때문에 비밀번호를 변경할 수 없습니다"
@ -22,11 +22,11 @@
"report-deleted": "Report가 삭제됐습니다"
},
"exceptions": {
"permission_denied": "You do not have permission to perform this action",
"no-entry-found": "The requested resource was not found",
"permission_denied": "이 작업을 수행할 권한이 없습니다.",
"no-entry-found": "요청한 페이지를 찾을 수 없습니다. 주소를 정확히 입력했는지 확인해보세요.",
"integrity-error": "Database integrity error",
"username-conflict-error": "This username is already taken",
"email-conflict-error": "This email is already in use"
"username-conflict-error": "이미 사용 중인 사용자 이름입니다.",
"email-conflict-error": "이 이메일은 이미 사용중입니다"
},
"notifications": {
"generic-created": "{name} was created",
@ -48,23 +48,23 @@
"emails": {
"password": {
"subject": "Mealie Forgot Password",
"header_text": "Forgot Password",
"message_top": "You have requested to reset your password.",
"message_bottom": "Please click the button above to reset your password.",
"button_text": "Reset Password"
"header_text": "비밀번호를 분실",
"message_top": "비밀번호 재설정을 요청하셨습니다",
"message_bottom": "비밀번호를 변경하려면 아래 버튼을 클릭하십시오.",
"button_text": "비밀번호 재설정"
},
"invitation": {
"subject": "Invitation to join Mealie",
"header_text": "You're Invited!",
"header_text": "귀하는 초대되었습니다!",
"message_top": "You have been invited to join Mealie.",
"message_bottom": "Please click the button above to accept the invitation.",
"button_text": "Accept Invitation"
"button_text": "초대 수락"
},
"test": {
"subject": "Mealie Test Email",
"header_text": "Test Email",
"message_top": "This is a test email.",
"message_bottom": "Please click the button above to test the email.",
"header_text": "테스트 이메일",
"message_top": "이것은 테스트용 이메일입니다.",
"message_bottom": "비밀번호를 변경하려면 아래 버튼을 클릭하십시오.",
"button_text": "Open Mealie"
}
}

View file

@ -543,7 +543,7 @@
},
"scallion": {
"name": "salladslök",
"plural_name": "scallions"
"plural_name": "salladslökar"
},
"seafood": {
"name": "fisk och skaldjur"
@ -556,7 +556,7 @@
},
"shallot": {
"name": "schalottenlök",
"plural_name": "shallots"
"plural_name": "schalottenlökar"
},
"skate": {
"name": "skate"
@ -585,11 +585,11 @@
},
"spring-onion": {
"name": "vårlök",
"plural_name": "spring onions"
"plural_name": "vårlökar"
},
"squash": {
"name": "squash",
"plural_name": "squashes"
"plural_name": "squash"
},
"squash-family": {
"name": "squash-familj"
@ -612,7 +612,7 @@
},
"sweet-potato": {
"name": "sötpotatis",
"plural_name": "sweet potatoes"
"plural_name": "sötpotatisar"
},
"sweetcorn": {
"name": "sockermajs",
@ -633,7 +633,7 @@
},
"tomato": {
"name": "tomat",
"plural_name": "tomatoes"
"plural_name": "tomater"
},
"trout": {
"name": "öring"
@ -650,7 +650,7 @@
},
"turnip": {
"name": "majrova",
"plural_name": "turnips"
"plural_name": "majrovor"
},
"unrefined-sugar": {
"name": "råsocker"
@ -666,11 +666,11 @@
},
"watermelon": {
"name": "vattenmelon",
"plural_name": "watermelons"
"plural_name": "vattenmeloner"
},
"white-mushroom": {
"name": "schampinjon",
"plural_name": "white mushrooms"
"plural_name": "champinjoner"
},
"white-sugar": {
"name": "strösocker"
@ -687,6 +687,6 @@
},
"zucchini": {
"name": "zucchini",
"plural_name": "zucchinis"
"plural_name": "zucchinins"
}
}

View file

@ -14,7 +14,7 @@ def main():
logger = root_logger.get_logger()
with session_context() as session:
repos = AllRepositories(session)
repos = AllRepositories(session, group_id=None, household_id=None)
user = repos.users.get_one(confirmed, "email")

View file

@ -14,7 +14,7 @@ def main():
logger = root_logger.get_logger()
with session_context() as session:
repos = AllRepositories(session)
repos = AllRepositories(session, group_id=None, household_id=None)
user_service = UserService(repos)
locked_users = user_service.get_locked_users()

View file

@ -1,13 +1,15 @@
import datetime
import os
import uuid
from logging import Logger
from os import path
from pathlib import Path
from textwrap import dedent
from typing import Any
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
from sqlalchemy import ForeignKey, ForeignKeyConstraint, MetaData, Table, create_engine, insert, text
from sqlalchemy import Connection, ForeignKey, ForeignKeyConstraint, MetaData, Table, create_engine, insert, text
from sqlalchemy.engine import base
from sqlalchemy.orm import sessionmaker
@ -21,6 +23,36 @@ from mealie.services._base_service import BaseService
PROJECT_DIR = Path(__file__).parent.parent.parent.parent
class ForeignKeyDisabler:
def __init__(self, connection: Connection, dialect_name: str, *, logger: Logger | None = None):
self.connection = connection
self.is_postgres = dialect_name == "postgresql"
self.logger = logger
self._initial_fk_state: str | None = None
def __enter__(self):
if self.is_postgres:
self._initial_fk_state = self.connection.execute(text("SHOW session_replication_role;")).scalar()
self.connection.execute(text("SET session_replication_role = 'replica';"))
else:
self._initial_fk_state = self.connection.execute(text("PRAGMA foreign_keys;")).scalar()
self.connection.execute(text("PRAGMA foreign_keys = OFF;"))
def __exit__(self, exc_type, exc_val, exc_tb):
try:
if self.is_postgres:
initial_state = self._initial_fk_state or "origin"
self.connection.execute(text(f"SET session_replication_role = '{initial_state}';"))
else:
initial_state = self._initial_fk_state or "ON"
self.connection.execute(text(f"PRAGMA foreign_keys = {initial_state};"))
except Exception:
if self.logger:
self.logger.exception("Error when re-enabling foreign keys")
raise
class AlchemyExporter(BaseService):
connection_str: str
engine: base.Engine
@ -175,40 +207,42 @@ class AlchemyExporter(BaseService):
del db_dump["alembic_version"]
"""Restores all data from dictionary into the database"""
with self.engine.begin() as connection:
data = self.convert_types(db_dump)
with ForeignKeyDisabler(connection, self.engine.dialect.name, logger=self.logger):
data = self.convert_types(db_dump)
self.meta.reflect(bind=self.engine)
for table_name, rows in data.items():
if not rows:
continue
table = self.meta.tables[table_name]
rows = self.clean_rows(db_dump, table, rows)
self.meta.reflect(bind=self.engine)
for table_name, rows in data.items():
if not rows:
continue
table = self.meta.tables[table_name]
rows = self.clean_rows(db_dump, table, rows)
connection.execute(table.delete())
connection.execute(insert(table), rows)
if self.engine.dialect.name == "postgresql":
# Restore postgres sequence numbers
connection.execute(
text(
"""
SELECT SETVAL('api_extras_id_seq', (SELECT MAX(id) FROM api_extras));
SELECT SETVAL('group_meal_plans_id_seq', (SELECT MAX(id) FROM group_meal_plans));
SELECT SETVAL('ingredient_food_extras_id_seq', (SELECT MAX(id) FROM ingredient_food_extras));
SELECT SETVAL('invite_tokens_id_seq', (SELECT MAX(id) FROM invite_tokens));
SELECT SETVAL('long_live_tokens_id_seq', (SELECT MAX(id) FROM long_live_tokens));
SELECT SETVAL('notes_id_seq', (SELECT MAX(id) FROM notes));
SELECT SETVAL('password_reset_tokens_id_seq', (SELECT MAX(id) FROM password_reset_tokens));
SELECT SETVAL('recipe_assets_id_seq', (SELECT MAX(id) FROM recipe_assets));
SELECT SETVAL('recipe_ingredient_ref_link_id_seq', (SELECT MAX(id) FROM recipe_ingredient_ref_link));
SELECT SETVAL('recipe_nutrition_id_seq', (SELECT MAX(id) FROM recipe_nutrition));
SELECT SETVAL('recipe_settings_id_seq', (SELECT MAX(id) FROM recipe_settings));
SELECT SETVAL('recipes_ingredients_id_seq', (SELECT MAX(id) FROM recipes_ingredients));
SELECT SETVAL('server_tasks_id_seq', (SELECT MAX(id) FROM server_tasks));
SELECT SETVAL('shopping_list_extras_id_seq', (SELECT MAX(id) FROM shopping_list_extras));
SELECT SETVAL('shopping_list_item_extras_id_seq', (SELECT MAX(id) FROM shopping_list_item_extras));
"""
connection.execute(table.delete())
connection.execute(insert(table), rows)
if self.engine.dialect.name == "postgresql":
# Restore postgres sequence numbers
sequences = [
("api_extras_id_seq", "api_extras"),
("group_meal_plans_id_seq", "group_meal_plans"),
("ingredient_food_extras_id_seq", "ingredient_food_extras"),
("invite_tokens_id_seq", "invite_tokens"),
("long_live_tokens_id_seq", "long_live_tokens"),
("notes_id_seq", "notes"),
("password_reset_tokens_id_seq", "password_reset_tokens"),
("recipe_assets_id_seq", "recipe_assets"),
("recipe_ingredient_ref_link_id_seq", "recipe_ingredient_ref_link"),
("recipe_nutrition_id_seq", "recipe_nutrition"),
("recipe_settings_id_seq", "recipe_settings"),
("recipes_ingredients_id_seq", "recipes_ingredients"),
("server_tasks_id_seq", "server_tasks"),
("shopping_list_extras_id_seq", "shopping_list_extras"),
("shopping_list_item_extras_id_seq", "shopping_list_item_extras"),
]
sql = "\n".join(
[f"SELECT SETVAL('{seq}', (SELECT MAX(id) FROM {table}));" for seq, table in sequences]
)
)
connection.execute(text(dedent(sql)))
# Re-init database to finish migrations
init_db.main()

70
poetry.lock generated
View file

@ -627,13 +627,13 @@ cli = ["requests"]
[[package]]
name = "fastapi"
version = "0.115.3"
version = "0.115.4"
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
optional = false
python-versions = ">=3.8"
files = [
{file = "fastapi-0.115.3-py3-none-any.whl", hash = "sha256:8035e8f9a2b0aa89cea03b6c77721178ed5358e1aea4cd8570d9466895c0638c"},
{file = "fastapi-0.115.3.tar.gz", hash = "sha256:c091c6a35599c036d676fa24bd4a6e19fa30058d93d950216cdc672881f6f7db"},
{file = "fastapi-0.115.4-py3-none-any.whl", hash = "sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742"},
{file = "fastapi-0.115.4.tar.gz", hash = "sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349"},
]
[package.dependencies]
@ -1464,13 +1464,13 @@ pyyaml = ">=5.1"
[[package]]
name = "mkdocs-material"
version = "9.5.42"
version = "9.5.43"
description = "Documentation that simply works"
optional = false
python-versions = ">=3.8"
files = [
{file = "mkdocs_material-9.5.42-py3-none-any.whl", hash = "sha256:452a7c5d21284b373f36b981a2cbebfff59263feebeede1bc28652e9c5bbe316"},
{file = "mkdocs_material-9.5.42.tar.gz", hash = "sha256:92779b5e9b5934540c574c11647131d217dc540dce72b05feeda088c8eb1b8f2"},
{file = "mkdocs_material-9.5.43-py3-none-any.whl", hash = "sha256:4aae0664c456fd12837a3192e0225c17960ba8bf55d7f0a7daef7e4b0b914a34"},
{file = "mkdocs_material-9.5.43.tar.gz", hash = "sha256:83be7ff30b65a1e4930dfa4ab911e75780a3afc9583d162692e434581cb46979"},
]
[package.dependencies]
@ -1598,13 +1598,13 @@ signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"]
[[package]]
name = "openai"
version = "1.52.2"
version = "1.53.0"
description = "The official Python library for the openai API"
optional = false
python-versions = ">=3.7.1"
files = [
{file = "openai-1.52.2-py3-none-any.whl", hash = "sha256:57e9e37bc407f39bb6ec3a27d7e8fb9728b2779936daa1fcf95df17d3edfaccc"},
{file = "openai-1.52.2.tar.gz", hash = "sha256:87b7d0f69d85f5641678d414b7ee3082363647a5c66a462ed7f3ccb59582da0d"},
{file = "openai-1.53.0-py3-none-any.whl", hash = "sha256:20f408c32fc5cb66e60c6882c994cdca580a5648e10045cd840734194f033418"},
{file = "openai-1.53.0.tar.gz", hash = "sha256:be2c4e77721b166cce8130e544178b7d579f751b4b074ffbaade3854b6f85ec5"},
]
[package.dependencies]
@ -2174,13 +2174,13 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
[[package]]
name = "pydantic-settings"
version = "2.6.0"
version = "2.6.1"
description = "Settings management using Pydantic"
optional = false
python-versions = ">=3.8"
files = [
{file = "pydantic_settings-2.6.0-py3-none-any.whl", hash = "sha256:4a819166f119b74d7f8c765196b165f95cc7487ce58ea27dec8a5a26be0970e0"},
{file = "pydantic_settings-2.6.0.tar.gz", hash = "sha256:44a1804abffac9e6a30372bb45f6cafab945ef5af25e66b1c634c01dd39e0188"},
{file = "pydantic_settings-2.6.1-py3-none-any.whl", hash = "sha256:7fb0637c786a558d3103436278a7c4f1cfd29ba8973238a50c5bb9a55387da87"},
{file = "pydantic_settings-2.6.1.tar.gz", hash = "sha256:e0f92546d8a9923cb8941689abf85d6601a8c19a23e97a34b2964a2e3f813ca0"},
]
[package.dependencies]
@ -2413,13 +2413,13 @@ pyasn1_modules = ">=0.1.5"
[[package]]
name = "python-multipart"
version = "0.0.12"
version = "0.0.17"
description = "A streaming multipart parser for Python"
optional = false
python-versions = ">=3.8"
files = [
{file = "python_multipart-0.0.12-py3-none-any.whl", hash = "sha256:43dcf96cf65888a9cd3423544dd0d75ac10f7aa0c3c28a175bbcd00c9ce1aebf"},
{file = "python_multipart-0.0.12.tar.gz", hash = "sha256:045e1f98d719c1ce085ed7f7e1ef9d8ccc8c02ba02b5566d5f7521410ced58cb"},
{file = "python_multipart-0.0.17-py3-none-any.whl", hash = "sha256:15dc4f487e0a9476cc1201261188ee0940165cffc94429b6fc565c4d3045cb5d"},
{file = "python_multipart-0.0.17.tar.gz", hash = "sha256:41330d831cae6e2f22902704ead2826ea038d0419530eadff3ea80175aec5538"},
]
[[package]]
@ -2815,29 +2815,29 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"]
[[package]]
name = "ruff"
version = "0.7.1"
version = "0.7.2"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
{file = "ruff-0.7.1-py3-none-linux_armv6l.whl", hash = "sha256:cb1bc5ed9403daa7da05475d615739cc0212e861b7306f314379d958592aaa89"},
{file = "ruff-0.7.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:27c1c52a8d199a257ff1e5582d078eab7145129aa02721815ca8fa4f9612dc35"},
{file = "ruff-0.7.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:588a34e1ef2ea55b4ddfec26bbe76bc866e92523d8c6cdec5e8aceefeff02d99"},
{file = "ruff-0.7.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94fc32f9cdf72dc75c451e5f072758b118ab8100727168a3df58502b43a599ca"},
{file = "ruff-0.7.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:985818742b833bffa543a84d1cc11b5e6871de1b4e0ac3060a59a2bae3969250"},
{file = "ruff-0.7.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32f1e8a192e261366c702c5fb2ece9f68d26625f198a25c408861c16dc2dea9c"},
{file = "ruff-0.7.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:699085bf05819588551b11751eff33e9ca58b1b86a6843e1b082a7de40da1565"},
{file = "ruff-0.7.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:344cc2b0814047dc8c3a8ff2cd1f3d808bb23c6658db830d25147339d9bf9ea7"},
{file = "ruff-0.7.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4316bbf69d5a859cc937890c7ac7a6551252b6a01b1d2c97e8fc96e45a7c8b4a"},
{file = "ruff-0.7.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79d3af9dca4c56043e738a4d6dd1e9444b6d6c10598ac52d146e331eb155a8ad"},
{file = "ruff-0.7.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c5c121b46abde94a505175524e51891f829414e093cd8326d6e741ecfc0a9112"},
{file = "ruff-0.7.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8422104078324ea250886954e48f1373a8fe7de59283d747c3a7eca050b4e378"},
{file = "ruff-0.7.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:56aad830af8a9db644e80098fe4984a948e2b6fc2e73891538f43bbe478461b8"},
{file = "ruff-0.7.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:658304f02f68d3a83c998ad8bf91f9b4f53e93e5412b8f2388359d55869727fd"},
{file = "ruff-0.7.1-py3-none-win32.whl", hash = "sha256:b517a2011333eb7ce2d402652ecaa0ac1a30c114fbbd55c6b8ee466a7f600ee9"},
{file = "ruff-0.7.1-py3-none-win_amd64.whl", hash = "sha256:f38c41fcde1728736b4eb2b18850f6d1e3eedd9678c914dede554a70d5241307"},
{file = "ruff-0.7.1-py3-none-win_arm64.whl", hash = "sha256:19aa200ec824c0f36d0c9114c8ec0087082021732979a359d6f3c390a6ff2a37"},
{file = "ruff-0.7.1.tar.gz", hash = "sha256:9d8a41d4aa2dad1575adb98a82870cf5db5f76b2938cf2206c22c940034a36f4"},
{file = "ruff-0.7.2-py3-none-linux_armv6l.whl", hash = "sha256:b73f873b5f52092e63ed540adefc3c36f1f803790ecf2590e1df8bf0a9f72cb8"},
{file = "ruff-0.7.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5b813ef26db1015953daf476202585512afd6a6862a02cde63f3bafb53d0b2d4"},
{file = "ruff-0.7.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:853277dbd9675810c6826dad7a428d52a11760744508340e66bf46f8be9701d9"},
{file = "ruff-0.7.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21aae53ab1490a52bf4e3bf520c10ce120987b047c494cacf4edad0ba0888da2"},
{file = "ruff-0.7.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ccc7e0fc6e0cb3168443eeadb6445285abaae75142ee22b2b72c27d790ab60ba"},
{file = "ruff-0.7.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd77877a4e43b3a98e5ef4715ba3862105e299af0c48942cc6d51ba3d97dc859"},
{file = "ruff-0.7.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e00163fb897d35523c70d71a46fbaa43bf7bf9af0f4534c53ea5b96b2e03397b"},
{file = "ruff-0.7.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3c54b538633482dc342e9b634d91168fe8cc56b30a4b4f99287f4e339103e88"},
{file = "ruff-0.7.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b792468e9804a204be221b14257566669d1db5c00d6bb335996e5cd7004ba80"},
{file = "ruff-0.7.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dba53ed84ac19ae4bfb4ea4bf0172550a2285fa27fbb13e3746f04c80f7fa088"},
{file = "ruff-0.7.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b19fafe261bf741bca2764c14cbb4ee1819b67adb63ebc2db6401dcd652e3748"},
{file = "ruff-0.7.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:28bd8220f4d8f79d590db9e2f6a0674f75ddbc3847277dd44ac1f8d30684b828"},
{file = "ruff-0.7.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9fd67094e77efbea932e62b5d2483006154794040abb3a5072e659096415ae1e"},
{file = "ruff-0.7.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:576305393998b7bd6c46018f8104ea3a9cb3fa7908c21d8580e3274a3b04b691"},
{file = "ruff-0.7.2-py3-none-win32.whl", hash = "sha256:fa993cfc9f0ff11187e82de874dfc3611df80852540331bc85c75809c93253a8"},
{file = "ruff-0.7.2-py3-none-win_amd64.whl", hash = "sha256:dd8800cbe0254e06b8fec585e97554047fb82c894973f7ff18558eee33d1cb88"},
{file = "ruff-0.7.2-py3-none-win_arm64.whl", hash = "sha256:bb8368cd45bba3f57bb29cbb8d64b4a33f8415d0149d2655c5c8539452ce7760"},
{file = "ruff-0.7.2.tar.gz", hash = "sha256:2b14e77293380e475b4e3a7a368e14549288ed2931fce259a6f99978669e844f"},
]
[[package]]
@ -3416,4 +3416,4 @@ pgsql = ["psycopg2-binary"]
[metadata]
lock-version = "2.0"
python-versions = "^3.10"
content-hash = "455f4f29104e6614f7ff7e899cf2d63302cd84dd693b59ee17d48ca05fd39543"
content-hash = "956580fac81cd8b933caf4e05d9578a1c5f50c815c5e57b6e8a8b7c8bd4761d3"

View file

@ -3,7 +3,7 @@ authors = ["Hayden <hay-kot@pm.me>"]
description = "A Recipe Manager"
license = "AGPL"
name = "mealie"
version = "2.0.0"
version = "2.1.0"
[tool.poetry.scripts]
start = "mealie.app:main"
@ -31,7 +31,7 @@ python = "^3.10"
python-dateutil = "^2.8.2"
python-dotenv = "^1.0.0"
python-ldap = "^3.3.1"
python-multipart = "^0.0.12"
python-multipart = "^0.0.17"
python-slugify = "^8.0.0"
recipe-scrapers = "^15.0.0"
requests = "^2.31.0"

View file

@ -16,15 +16,18 @@ backup_version_44e8d670719d_3 = CWD / "backups/backup-version-44e8d670719d-3.zip
backup_version_44e8d670719d_4 = CWD / "backups/backup-version-44e8d670719d-4.zip"
"""44e8d670719d: add extras to shopping lists, list items, and ingredient foods"""
backup_version_ba1e4a6cfe99_1 = CWD / "backups/backup-version-ba1e4a6cfe99-1.zip"
"""ba1e4a6cfe99: added plural names and alias tables for foods and units"""
backup_version_bcfdad6b7355_1 = CWD / "backups/backup-version-bcfdad6b7355-1.zip"
"""bcfdad6b7355: remove tool name and slug unique contraints"""
backup_version_ba1e4a6cfe99_1 = CWD / "backups/backup-version-ba1e4a6cfe99-1.zip"
"""ba1e4a6cfe99: added plural names and alias tables for foods and units"""
backup_version_09aba125b57a_1 = CWD / "backups/backup-version-09aba125b57a-1.zip"
"""09aba125b57a: add OIDC auth method (Safari-mangled ZIP structure)"""
backup_version_86054b40fd06_1 = CWD / "backups/backup-version-86054b40fd06-1.zip"
"""86054b40fd06: added query_filter_string to cookbook and mealplan"""
migrations_paprika = CWD / "migrations/paprika.zip"
migrations_chowdown = CWD / "migrations/chowdown.zip"

Binary file not shown.

View file

@ -84,15 +84,17 @@ def test_database_restore():
test_data.backup_version_ba1e4a6cfe99_1,
test_data.backup_version_bcfdad6b7355_1,
test_data.backup_version_09aba125b57a_1,
test_data.backup_version_86054b40fd06_1,
],
ids=[
"44e8d670719d_1: add extras to shopping lists, list items, and ingredient foods",
"44e8d670719d_2: add extras to shopping lists, list items, and ingredient foods",
"44e8d670719d_3: add extras to shopping lists, list items, and ingredient foods",
"44e8d670719d_4: add extras to shopping lists, list items, and ingredient foods",
"ba1e4a6cfe99_1: added plural names and alias tables for foods and units",
"bcfdad6b7355_1: remove tool name and slug unique contraints",
"09aba125b57a: add OIDC auth method (Safari-mangled ZIP structure)",
"ba1e4a6cfe99_1: added plural names and alias tables for foods and units",
"09aba125b57a_1: add OIDC auth method (Safari-mangled ZIP structure)",
"86054b40fd06_1: added query_filter_string to cookbook and mealplan",
],
)
def test_database_restore_data(backup_path: Path):

View file

@ -9,6 +9,7 @@ from mealie.core.settings.settings import AppSettings
def test_non_default_settings(monkeypatch):
monkeypatch.setenv("DEFAULT_GROUP", "Test Group")
monkeypatch.setenv("DEFAULT_HOUSEHOLD", "Test Household")
monkeypatch.setenv("API_PORT", "8000")
monkeypatch.setenv("API_DOCS", "False")
@ -16,6 +17,7 @@ def test_non_default_settings(monkeypatch):
app_settings = get_app_settings()
assert app_settings.DEFAULT_GROUP == "Test Group"
assert app_settings.DEFAULT_HOUSEHOLD == "Test Household"
assert app_settings.API_PORT == 8000
assert app_settings.API_DOCS is False