mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-11-03 18:53:17 -05:00 
			
		
		
		
	feat: auto detect first login (#2722)
* 'hide' default email and password env variables * first login API endpoint * run code-generators * frontend indicators for default username and pw * remove old env variables from docs * fix env set variable * remove password from tests
This commit is contained in:
		@@ -5,12 +5,10 @@
 | 
				
			|||||||
### General
 | 
					### General
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Variables     |        Default        | Description                                                                         |
 | 
					| Variables     |        Default        | Description                                                                         |
 | 
				
			||||||
| ---------------- | :-------------------: | ----------------------------------------------------------------------------------- |
 | 
					| ------------- | :-------------------: | ----------------------------------------------------------------------------------- |
 | 
				
			||||||
| PUID          |          911          | UserID permissions between host OS and container                                    |
 | 
					| PUID          |          911          | UserID permissions between host OS and container                                    |
 | 
				
			||||||
| PGID          |          911          | GroupID permissions between host OS and container                                   |
 | 
					| PGID          |          911          | GroupID permissions between host OS and container                                   |
 | 
				
			||||||
| DEFAULT_GROUP |         Home          | The default group for users                                                         |
 | 
					| DEFAULT_GROUP |         Home          | The default group for users                                                         |
 | 
				
			||||||
| DEFAULT_EMAIL    | changeme@example.com  | The default username for the superuser                                              |
 | 
					 | 
				
			||||||
| DEFAULT_PASSWORD |       MyPassword      | The default password for the superuser                                              |
 | 
					 | 
				
			||||||
| BASE_URL      | http://localhost:8080 | Used for Notifications                                                              |
 | 
					| BASE_URL      | http://localhost:8080 | Used for Notifications                                                              |
 | 
				
			||||||
| TOKEN_TIME    |          48           | The time in hours that a login/auth token is valid                                  |
 | 
					| 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** |
 | 
					| API_PORT      |         9000          | The port exposed by backend API. **Do not change this if you're running in Docker** |
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,117 +3,117 @@ export const LOCALES = [
 | 
				
			|||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "繁體中文 (Chinese traditional)",
 | 
					    name: "繁體中文 (Chinese traditional)",
 | 
				
			||||||
    value: "zh-TW",
 | 
					    value: "zh-TW",
 | 
				
			||||||
    progress: 26,
 | 
					    progress: 28,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "简体中文 (Chinese simplified)",
 | 
					    name: "简体中文 (Chinese simplified)",
 | 
				
			||||||
    value: "zh-CN",
 | 
					    value: "zh-CN",
 | 
				
			||||||
    progress: 34,
 | 
					    progress: 65,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Tiếng Việt (Vietnamese)",
 | 
					    name: "Tiếng Việt (Vietnamese)",
 | 
				
			||||||
    value: "vi-VN",
 | 
					    value: "vi-VN",
 | 
				
			||||||
    progress: 0,
 | 
					    progress: 2,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Українська (Ukrainian)",
 | 
					    name: "Українська (Ukrainian)",
 | 
				
			||||||
    value: "uk-UA",
 | 
					    value: "uk-UA",
 | 
				
			||||||
    progress: 100,
 | 
					    progress: 99,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Türkçe (Turkish)",
 | 
					    name: "Türkçe (Turkish)",
 | 
				
			||||||
    value: "tr-TR",
 | 
					    value: "tr-TR",
 | 
				
			||||||
    progress: 47,
 | 
					    progress: 50,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Svenska (Swedish)",
 | 
					    name: "Svenska (Swedish)",
 | 
				
			||||||
    value: "sv-SE",
 | 
					    value: "sv-SE",
 | 
				
			||||||
    progress: 60,
 | 
					    progress: 71,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "српски (Serbian)",
 | 
					    name: "српски (Serbian)",
 | 
				
			||||||
    value: "sr-SP",
 | 
					    value: "sr-SP",
 | 
				
			||||||
    progress: 2,
 | 
					    progress: 4,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Slovenian",
 | 
					    name: "Slovenian",
 | 
				
			||||||
    value: "sl-SI",
 | 
					    value: "sl-SI",
 | 
				
			||||||
    progress: 47,
 | 
					    progress: 49,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Slovak",
 | 
					    name: "Slovak",
 | 
				
			||||||
    value: "sk-SK",
 | 
					    value: "sk-SK",
 | 
				
			||||||
    progress: 99,
 | 
					    progress: 97,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Pусский (Russian)",
 | 
					    name: "Pусский (Russian)",
 | 
				
			||||||
    value: "ru-RU",
 | 
					    value: "ru-RU",
 | 
				
			||||||
    progress: 31,
 | 
					    progress: 99,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Română (Romanian)",
 | 
					    name: "Română (Romanian)",
 | 
				
			||||||
    value: "ro-RO",
 | 
					    value: "ro-RO",
 | 
				
			||||||
    progress: 12,
 | 
					    progress: 32,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Português (Portuguese)",
 | 
					    name: "Português (Portuguese)",
 | 
				
			||||||
    value: "pt-PT",
 | 
					    value: "pt-PT",
 | 
				
			||||||
    progress: 69,
 | 
					    progress: 99,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Português do Brasil (Brazilian Portuguese)",
 | 
					    name: "Português do Brasil (Brazilian Portuguese)",
 | 
				
			||||||
    value: "pt-BR",
 | 
					    value: "pt-BR",
 | 
				
			||||||
    progress: 97,
 | 
					    progress: 98,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Polski (Polish)",
 | 
					    name: "Polski (Polish)",
 | 
				
			||||||
    value: "pl-PL",
 | 
					    value: "pl-PL",
 | 
				
			||||||
    progress: 99,
 | 
					    progress: 97,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Norsk (Norwegian)",
 | 
					    name: "Norsk (Norwegian)",
 | 
				
			||||||
    value: "no-NO",
 | 
					    value: "no-NO",
 | 
				
			||||||
    progress: 73,
 | 
					    progress: 85,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Nederlands (Dutch)",
 | 
					    name: "Nederlands (Dutch)",
 | 
				
			||||||
    value: "nl-NL",
 | 
					    value: "nl-NL",
 | 
				
			||||||
    progress: 100,
 | 
					    progress: 98,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Latvian",
 | 
					    name: "Latvian",
 | 
				
			||||||
    value: "lv-LV",
 | 
					    value: "lv-LV",
 | 
				
			||||||
    progress: 0,
 | 
					    progress: 1,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Lithuanian",
 | 
					    name: "Lithuanian",
 | 
				
			||||||
    value: "lt-LT",
 | 
					    value: "lt-LT",
 | 
				
			||||||
    progress: 99,
 | 
					    progress: 97,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "한국어 (Korean)",
 | 
					    name: "한국어 (Korean)",
 | 
				
			||||||
    value: "ko-KR",
 | 
					    value: "ko-KR",
 | 
				
			||||||
    progress: 3,
 | 
					    progress: 5,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "日本語 (Japanese)",
 | 
					    name: "日本語 (Japanese)",
 | 
				
			||||||
    value: "ja-JP",
 | 
					    value: "ja-JP",
 | 
				
			||||||
    progress: 9,
 | 
					    progress: 11,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Italiano (Italian)",
 | 
					    name: "Italiano (Italian)",
 | 
				
			||||||
    value: "it-IT",
 | 
					    value: "it-IT",
 | 
				
			||||||
    progress: 98,
 | 
					    progress: 96,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Magyar (Hungarian)",
 | 
					    name: "Magyar (Hungarian)",
 | 
				
			||||||
    value: "hu-HU",
 | 
					    value: "hu-HU",
 | 
				
			||||||
    progress: 43,
 | 
					    progress: 99,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Croatian",
 | 
					    name: "Croatian",
 | 
				
			||||||
    value: "hr-HR",
 | 
					    value: "hr-HR",
 | 
				
			||||||
    progress: 100,
 | 
					    progress: 97,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "עברית (Hebrew)",
 | 
					    name: "עברית (Hebrew)",
 | 
				
			||||||
@@ -123,27 +123,27 @@ export const LOCALES = [
 | 
				
			|||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Galician",
 | 
					    name: "Galician",
 | 
				
			||||||
    value: "gl-ES",
 | 
					    value: "gl-ES",
 | 
				
			||||||
    progress: 0,
 | 
					    progress: 1,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Français (French)",
 | 
					    name: "Français (French)",
 | 
				
			||||||
    value: "fr-FR",
 | 
					    value: "fr-FR",
 | 
				
			||||||
    progress: 100,
 | 
					    progress: 99,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "French, Canada",
 | 
					    name: "French, Canada",
 | 
				
			||||||
    value: "fr-CA",
 | 
					    value: "fr-CA",
 | 
				
			||||||
    progress: 54,
 | 
					    progress: 97,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Suomi (Finnish)",
 | 
					    name: "Suomi (Finnish)",
 | 
				
			||||||
    value: "fi-FI",
 | 
					    value: "fi-FI",
 | 
				
			||||||
    progress: 31,
 | 
					    progress: 95,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Español (Spanish)",
 | 
					    name: "Español (Spanish)",
 | 
				
			||||||
    value: "es-ES",
 | 
					    value: "es-ES",
 | 
				
			||||||
    progress: 59,
 | 
					    progress: 76,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "American English",
 | 
					    name: "American English",
 | 
				
			||||||
@@ -153,46 +153,46 @@ export const LOCALES = [
 | 
				
			|||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "British English",
 | 
					    name: "British English",
 | 
				
			||||||
    value: "en-GB",
 | 
					    value: "en-GB",
 | 
				
			||||||
    progress: 2,
 | 
					    progress: 4,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Ελληνικά (Greek)",
 | 
					    name: "Ελληνικά (Greek)",
 | 
				
			||||||
    value: "el-GR",
 | 
					    value: "el-GR",
 | 
				
			||||||
    progress: 33,
 | 
					    progress: 35,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Deutsch (German)",
 | 
					    name: "Deutsch (German)",
 | 
				
			||||||
    value: "de-DE",
 | 
					    value: "de-DE",
 | 
				
			||||||
    progress: 100,
 | 
					    progress: 99,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Dansk (Danish)",
 | 
					    name: "Dansk (Danish)",
 | 
				
			||||||
    value: "da-DK",
 | 
					    value: "da-DK",
 | 
				
			||||||
    progress: 90,
 | 
					    progress: 100,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Čeština (Czech)",
 | 
					    name: "Čeština (Czech)",
 | 
				
			||||||
    value: "cs-CZ",
 | 
					    value: "cs-CZ",
 | 
				
			||||||
    progress: 60,
 | 
					    progress: 66,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Català (Catalan)",
 | 
					    name: "Català (Catalan)",
 | 
				
			||||||
    value: "ca-ES",
 | 
					    value: "ca-ES",
 | 
				
			||||||
    progress: 54,
 | 
					    progress: 61,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Bulgarian",
 | 
					    name: "Bulgarian",
 | 
				
			||||||
    value: "bg-BG",
 | 
					    value: "bg-BG",
 | 
				
			||||||
    progress: 13,
 | 
					    progress: 99,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "العربية (Arabic)",
 | 
					    name: "العربية (Arabic)",
 | 
				
			||||||
    value: "ar-SA",
 | 
					    value: "ar-SA",
 | 
				
			||||||
    progress: 7,
 | 
					    progress: 16,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: "Afrikaans (Afrikaans)",
 | 
					    name: "Afrikaans (Afrikaans)",
 | 
				
			||||||
    value: "af-ZA",
 | 
					    value: "af-ZA",
 | 
				
			||||||
    progress: 0,
 | 
					    progress: 96,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -868,7 +868,9 @@
 | 
				
			|||||||
    "user-can-invite-other-to-group": "User can invite other to group",
 | 
					    "user-can-invite-other-to-group": "User can invite other to group",
 | 
				
			||||||
    "user-can-manage-group": "User can manage group",
 | 
					    "user-can-manage-group": "User can manage group",
 | 
				
			||||||
    "user-can-organize-group-data": "User can organize group data",
 | 
					    "user-can-organize-group-data": "User can organize group data",
 | 
				
			||||||
    "enable-advanced-features": "Enable advanced features"
 | 
					    "enable-advanced-features": "Enable advanced features",
 | 
				
			||||||
 | 
					    "it-looks-like-this-is-your-first-time-logging-in": "It looks like this is your first time logging in.",
 | 
				
			||||||
 | 
					    "dont-want-to-see-this-anymore-be-sure-to-change-your-email": "Don't want to see this anymore? Be sure to change your email in your user settings!"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "language-dialog": {
 | 
					  "language-dialog": {
 | 
				
			||||||
    "translated": "translated",
 | 
					    "translated": "translated",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,6 +34,9 @@ export interface AppInfo {
 | 
				
			|||||||
  demoStatus: boolean;
 | 
					  demoStatus: boolean;
 | 
				
			||||||
  allowSignup: boolean;
 | 
					  allowSignup: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					export interface AppStartupInfo {
 | 
				
			||||||
 | 
					  isFirstLogin: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
export interface AppStatistics {
 | 
					export interface AppStatistics {
 | 
				
			||||||
  totalRecipes: number;
 | 
					  totalRecipes: number;
 | 
				
			||||||
  totalUsers: number;
 | 
					  totalUsers: number;
 | 
				
			||||||
@@ -41,6 +44,22 @@ export interface AppStatistics {
 | 
				
			|||||||
  uncategorizedRecipes: number;
 | 
					  uncategorizedRecipes: number;
 | 
				
			||||||
  untaggedRecipes: number;
 | 
					  untaggedRecipes: number;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					export interface AppTheme {
 | 
				
			||||||
 | 
					  lightPrimary?: string;
 | 
				
			||||||
 | 
					  lightAccent?: string;
 | 
				
			||||||
 | 
					  lightSecondary?: string;
 | 
				
			||||||
 | 
					  lightSuccess?: string;
 | 
				
			||||||
 | 
					  lightInfo?: string;
 | 
				
			||||||
 | 
					  lightWarning?: string;
 | 
				
			||||||
 | 
					  lightError?: string;
 | 
				
			||||||
 | 
					  darkPrimary?: string;
 | 
				
			||||||
 | 
					  darkAccent?: string;
 | 
				
			||||||
 | 
					  darkSecondary?: string;
 | 
				
			||||||
 | 
					  darkSuccess?: string;
 | 
				
			||||||
 | 
					  darkInfo?: string;
 | 
				
			||||||
 | 
					  darkWarning?: string;
 | 
				
			||||||
 | 
					  darkError?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
export interface BackupOptions {
 | 
					export interface BackupOptions {
 | 
				
			||||||
  recipes?: boolean;
 | 
					  recipes?: boolean;
 | 
				
			||||||
  settings?: boolean;
 | 
					  settings?: boolean;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,14 @@
 | 
				
			|||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type WebhookType = "mealplan";
 | 
					export type WebhookType = "mealplan";
 | 
				
			||||||
export type SupportedMigrations = "nextcloud" | "chowdown" | "copymethat" | "paprika" | "mealie_alpha" | "tandoor" | "plantoeat";
 | 
					export type SupportedMigrations =
 | 
				
			||||||
 | 
					  | "nextcloud"
 | 
				
			||||||
 | 
					  | "chowdown"
 | 
				
			||||||
 | 
					  | "copymethat"
 | 
				
			||||||
 | 
					  | "paprika"
 | 
				
			||||||
 | 
					  | "mealie_alpha"
 | 
				
			||||||
 | 
					  | "tandoor"
 | 
				
			||||||
 | 
					  | "plantoeat";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface CreateGroupPreferences {
 | 
					export interface CreateGroupPreferences {
 | 
				
			||||||
  privateGroup?: boolean;
 | 
					  privateGroup?: boolean;
 | 
				
			||||||
@@ -263,39 +270,56 @@ export interface RecipeIngredient {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
export interface IngredientUnit {
 | 
					export interface IngredientUnit {
 | 
				
			||||||
  name: string;
 | 
					  name: string;
 | 
				
			||||||
 | 
					  pluralName?: string;
 | 
				
			||||||
  description?: string;
 | 
					  description?: string;
 | 
				
			||||||
  extras?: {
 | 
					  extras?: {
 | 
				
			||||||
    [k: string]: unknown;
 | 
					    [k: string]: unknown;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  fraction?: boolean;
 | 
					  fraction?: boolean;
 | 
				
			||||||
  abbreviation?: string;
 | 
					  abbreviation?: string;
 | 
				
			||||||
 | 
					  pluralAbbreviation?: string;
 | 
				
			||||||
  useAbbreviation?: boolean;
 | 
					  useAbbreviation?: boolean;
 | 
				
			||||||
 | 
					  aliases?: IngredientUnitAlias[];
 | 
				
			||||||
  id: string;
 | 
					  id: string;
 | 
				
			||||||
  createdAt?: string;
 | 
					  createdAt?: string;
 | 
				
			||||||
  updateAt?: string;
 | 
					  updateAt?: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					export interface IngredientUnitAlias {
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
export interface CreateIngredientUnit {
 | 
					export interface CreateIngredientUnit {
 | 
				
			||||||
  name: string;
 | 
					  name: string;
 | 
				
			||||||
 | 
					  pluralName?: string;
 | 
				
			||||||
  description?: string;
 | 
					  description?: string;
 | 
				
			||||||
  extras?: {
 | 
					  extras?: {
 | 
				
			||||||
    [k: string]: unknown;
 | 
					    [k: string]: unknown;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  fraction?: boolean;
 | 
					  fraction?: boolean;
 | 
				
			||||||
  abbreviation?: string;
 | 
					  abbreviation?: string;
 | 
				
			||||||
 | 
					  pluralAbbreviation?: string;
 | 
				
			||||||
  useAbbreviation?: boolean;
 | 
					  useAbbreviation?: boolean;
 | 
				
			||||||
 | 
					  aliases?: CreateIngredientUnitAlias[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export interface CreateIngredientUnitAlias {
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
export interface IngredientFood {
 | 
					export interface IngredientFood {
 | 
				
			||||||
  name: string;
 | 
					  name: string;
 | 
				
			||||||
 | 
					  pluralName?: string;
 | 
				
			||||||
  description?: string;
 | 
					  description?: string;
 | 
				
			||||||
  extras?: {
 | 
					  extras?: {
 | 
				
			||||||
    [k: string]: unknown;
 | 
					    [k: string]: unknown;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  labelId?: string;
 | 
					  labelId?: string;
 | 
				
			||||||
 | 
					  aliases?: IngredientFoodAlias[];
 | 
				
			||||||
  id: string;
 | 
					  id: string;
 | 
				
			||||||
  label?: MultiPurposeLabelSummary;
 | 
					  label?: MultiPurposeLabelSummary;
 | 
				
			||||||
  createdAt?: string;
 | 
					  createdAt?: string;
 | 
				
			||||||
  updateAt?: string;
 | 
					  updateAt?: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					export interface IngredientFoodAlias {
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
export interface MultiPurposeLabelSummary {
 | 
					export interface MultiPurposeLabelSummary {
 | 
				
			||||||
  name: string;
 | 
					  name: string;
 | 
				
			||||||
  color?: string;
 | 
					  color?: string;
 | 
				
			||||||
@@ -304,11 +328,16 @@ export interface MultiPurposeLabelSummary {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
export interface CreateIngredientFood {
 | 
					export interface CreateIngredientFood {
 | 
				
			||||||
  name: string;
 | 
					  name: string;
 | 
				
			||||||
 | 
					  pluralName?: string;
 | 
				
			||||||
  description?: string;
 | 
					  description?: string;
 | 
				
			||||||
  extras?: {
 | 
					  extras?: {
 | 
				
			||||||
    [k: string]: unknown;
 | 
					    [k: string]: unknown;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  labelId?: string;
 | 
					  labelId?: string;
 | 
				
			||||||
 | 
					  aliases?: CreateIngredientFoodAlias[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export interface CreateIngredientFoodAlias {
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
export interface ShoppingListCreate {
 | 
					export interface ShoppingListCreate {
 | 
				
			||||||
  name?: string;
 | 
					  name?: string;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@
 | 
				
			|||||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
 | 
					/* Do not modify it by hand - just update the pydantic models and then re-run the script
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type OrderByNullPosition = "first" | "last";
 | 
				
			||||||
export type OrderDirection = "asc" | "desc";
 | 
					export type OrderDirection = "asc" | "desc";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ErrorResponse {
 | 
					export interface ErrorResponse {
 | 
				
			||||||
@@ -19,6 +20,7 @@ export interface PaginationQuery {
 | 
				
			|||||||
  page?: number;
 | 
					  page?: number;
 | 
				
			||||||
  perPage?: number;
 | 
					  perPage?: number;
 | 
				
			||||||
  orderBy?: string;
 | 
					  orderBy?: string;
 | 
				
			||||||
 | 
					  orderByNullPosition?: OrderByNullPosition;
 | 
				
			||||||
  orderDirection?: OrderDirection & string;
 | 
					  orderDirection?: OrderDirection & string;
 | 
				
			||||||
  queryFilter?: string;
 | 
					  queryFilter?: string;
 | 
				
			||||||
  paginationSeed?: string;
 | 
					  paginationSeed?: string;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,18 @@
 | 
				
			|||||||
      'bg-off-white': !$vuetify.theme.dark && !isDark,
 | 
					      'bg-off-white': !$vuetify.theme.dark && !isDark,
 | 
				
			||||||
    }"
 | 
					    }"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
 | 
					    <v-alert v-if="isFirstLogin" class="my-4" type="info" icon="mdi-information">
 | 
				
			||||||
 | 
					      <div>
 | 
				
			||||||
 | 
					        <p class="mb-3">
 | 
				
			||||||
 | 
					          {{ $tc('user.it-looks-like-this-is-your-first-time-logging-in')}}
 | 
				
			||||||
 | 
					        </p>
 | 
				
			||||||
 | 
					        <p class="mb-1"><strong>{{ $tc('user.username') }}:</strong> changeme@example.com</p>
 | 
				
			||||||
 | 
					        <p class="mb-3"><strong>{{  $tc('user.password') }}:</strong> MyPassword</p>
 | 
				
			||||||
 | 
					        <p>
 | 
				
			||||||
 | 
					          {{  $tc('user.dont-want-to-see-this-anymore-be-sure-to-change-your-email') }}
 | 
				
			||||||
 | 
					        </p>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </v-alert>
 | 
				
			||||||
    <v-card tag="section" class="d-flex flex-column align-center" width="600px">
 | 
					    <v-card tag="section" class="d-flex flex-column align-center" width="600px">
 | 
				
			||||||
      <v-toolbar width="100%" color="primary" class="d-flex justify-center mb-4" dark>
 | 
					      <v-toolbar width="100%" color="primary" class="d-flex justify-center mb-4" dark>
 | 
				
			||||||
        <v-toolbar-title class="headline text-h4"> Mealie </v-toolbar-title>
 | 
					        <v-toolbar-title class="headline text-h4"> Mealie </v-toolbar-title>
 | 
				
			||||||
@@ -101,12 +113,14 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
import { defineComponent, ref, useContext, computed, reactive, useRouter } from "@nuxtjs/composition-api";
 | 
					import { defineComponent, ref, useContext, computed, reactive, useRouter, useAsync } from "@nuxtjs/composition-api";
 | 
				
			||||||
import { useDark, whenever } from "@vueuse/core";
 | 
					import { useDark, whenever } from "@vueuse/core";
 | 
				
			||||||
import { useLoggedInState } from "~/composables/use-logged-in-state";
 | 
					import { useLoggedInState } from "~/composables/use-logged-in-state";
 | 
				
			||||||
import { useAppInfo } from "~/composables/api";
 | 
					import { useAppInfo } from "~/composables/api";
 | 
				
			||||||
import { usePasswordField } from "~/composables/use-passwords";
 | 
					import { usePasswordField } from "~/composables/use-passwords";
 | 
				
			||||||
import { alert } from "~/composables/use-toast";
 | 
					import { alert } from "~/composables/use-toast";
 | 
				
			||||||
 | 
					import { useAsyncKey } from "~/composables/use-utils";
 | 
				
			||||||
 | 
					import { AppStartupInfo } from "~/lib/api/types/admin";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default defineComponent({
 | 
					export default defineComponent({
 | 
				
			||||||
  layout: "blank",
 | 
					  layout: "blank",
 | 
				
			||||||
@@ -115,7 +129,7 @@ export default defineComponent({
 | 
				
			|||||||
    const isDark = useDark();
 | 
					    const isDark = useDark();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const router = useRouter();
 | 
					    const router = useRouter();
 | 
				
			||||||
    const { $auth, i18n } = useContext();
 | 
					    const { $auth, i18n, $axios } = useContext();
 | 
				
			||||||
    const { loggedIn } = useLoggedInState();
 | 
					    const { loggedIn } = useLoggedInState();
 | 
				
			||||||
    const groupSlug = computed(() => $auth.user?.groupSlug);
 | 
					    const groupSlug = computed(() => $auth.user?.groupSlug);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -133,6 +147,13 @@ export default defineComponent({
 | 
				
			|||||||
      remember: false,
 | 
					      remember: false,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const isFirstLogin = ref(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useAsync(async () => {
 | 
				
			||||||
 | 
					      const data = await $axios.get<AppStartupInfo>("/api/app/about/startup-info");
 | 
				
			||||||
 | 
					      isFirstLogin.value = data.data.isFirstLogin;
 | 
				
			||||||
 | 
					  }, useAsyncKey());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const loggingIn = ref(false);
 | 
					    const loggingIn = ref(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const appInfo = useAppInfo();
 | 
					    const appInfo = useAppInfo();
 | 
				
			||||||
@@ -182,6 +203,7 @@ export default defineComponent({
 | 
				
			|||||||
      passwordIcon,
 | 
					      passwordIcon,
 | 
				
			||||||
      inputType,
 | 
					      inputType,
 | 
				
			||||||
      togglePasswordShow,
 | 
					      togglePasswordShow,
 | 
				
			||||||
 | 
					      isFirstLogin
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -104,7 +104,6 @@ async def system_startup():
 | 
				
			|||||||
            indent=4,
 | 
					            indent=4,
 | 
				
			||||||
            exclude={
 | 
					            exclude={
 | 
				
			||||||
                "SECRET",
 | 
					                "SECRET",
 | 
				
			||||||
                "DEFAULT_PASSWORD",
 | 
					 | 
				
			||||||
                "SFTP_PASSWORD",
 | 
					                "SFTP_PASSWORD",
 | 
				
			||||||
                "SFTP_USERNAME",
 | 
					                "SFTP_USERNAME",
 | 
				
			||||||
                "DB_URL",  # replace by DB_URL_PUBLIC for logs
 | 
					                "DB_URL",  # replace by DB_URL_PUBLIC for logs
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,8 +85,17 @@ class AppSettings(BaseSettings):
 | 
				
			|||||||
        return self.DB_PROVIDER.db_url_public if self.DB_PROVIDER else None
 | 
					        return self.DB_PROVIDER.db_url_public if self.DB_PROVIDER else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DEFAULT_GROUP: str = "Home"
 | 
					    DEFAULT_GROUP: str = "Home"
 | 
				
			||||||
    DEFAULT_EMAIL: str = "changeme@example.com"
 | 
					
 | 
				
			||||||
    DEFAULT_PASSWORD: str = "MyPassword"
 | 
					    _DEFAULT_EMAIL: str = "changeme@example.com"
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    This is the default email used for the first user created in the database. This is only used if no users
 | 
				
			||||||
 | 
					    exist in the database. it should no longer be set by end users.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    _DEFAULT_PASSWORD: str = "MyPassword"
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    This is the default password used for the first user created in the database. This is only used if no users
 | 
				
			||||||
 | 
					    exist in the database. it should no longer be set by end users.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # ===============================================
 | 
					    # ===============================================
 | 
				
			||||||
    # Email Configuration
 | 
					    # Email Configuration
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@ def dev_users() -> list[dict]:
 | 
				
			|||||||
            "full_name": "Jason",
 | 
					            "full_name": "Jason",
 | 
				
			||||||
            "username": "jason",
 | 
					            "username": "jason",
 | 
				
			||||||
            "email": "jason@example.com",
 | 
					            "email": "jason@example.com",
 | 
				
			||||||
            "password": hash_password(settings.DEFAULT_PASSWORD),
 | 
					            "password": hash_password(settings._DEFAULT_PASSWORD),
 | 
				
			||||||
            "group": settings.DEFAULT_GROUP,
 | 
					            "group": settings.DEFAULT_GROUP,
 | 
				
			||||||
            "admin": False,
 | 
					            "admin": False,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@@ -21,7 +21,7 @@ def dev_users() -> list[dict]:
 | 
				
			|||||||
            "full_name": "Bob",
 | 
					            "full_name": "Bob",
 | 
				
			||||||
            "username": "bob",
 | 
					            "username": "bob",
 | 
				
			||||||
            "email": "bob@example.com",
 | 
					            "email": "bob@example.com",
 | 
				
			||||||
            "password": hash_password(settings.DEFAULT_PASSWORD),
 | 
					            "password": hash_password(settings._DEFAULT_PASSWORD),
 | 
				
			||||||
            "group": settings.DEFAULT_GROUP,
 | 
					            "group": settings.DEFAULT_GROUP,
 | 
				
			||||||
            "admin": False,
 | 
					            "admin": False,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@@ -29,7 +29,7 @@ def dev_users() -> list[dict]:
 | 
				
			|||||||
            "full_name": "Sarah",
 | 
					            "full_name": "Sarah",
 | 
				
			||||||
            "username": "sarah",
 | 
					            "username": "sarah",
 | 
				
			||||||
            "email": "sarah@example.com",
 | 
					            "email": "sarah@example.com",
 | 
				
			||||||
            "password": hash_password(settings.DEFAULT_PASSWORD),
 | 
					            "password": hash_password(settings._DEFAULT_PASSWORD),
 | 
				
			||||||
            "group": settings.DEFAULT_GROUP,
 | 
					            "group": settings.DEFAULT_GROUP,
 | 
				
			||||||
            "admin": False,
 | 
					            "admin": False,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@@ -37,7 +37,7 @@ def dev_users() -> list[dict]:
 | 
				
			|||||||
            "full_name": "Sammy",
 | 
					            "full_name": "Sammy",
 | 
				
			||||||
            "username": "sammy",
 | 
					            "username": "sammy",
 | 
				
			||||||
            "email": "sammy@example.com",
 | 
					            "email": "sammy@example.com",
 | 
				
			||||||
            "password": hash_password(settings.DEFAULT_PASSWORD),
 | 
					            "password": hash_password(settings._DEFAULT_PASSWORD),
 | 
				
			||||||
            "group": settings.DEFAULT_GROUP,
 | 
					            "group": settings.DEFAULT_GROUP,
 | 
				
			||||||
            "admin": False,
 | 
					            "admin": False,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@@ -48,8 +48,8 @@ def default_user_init(db: AllRepositories):
 | 
				
			|||||||
    default_user = {
 | 
					    default_user = {
 | 
				
			||||||
        "full_name": "Change Me",
 | 
					        "full_name": "Change Me",
 | 
				
			||||||
        "username": "admin",
 | 
					        "username": "admin",
 | 
				
			||||||
        "email": settings.DEFAULT_EMAIL,
 | 
					        "email": settings._DEFAULT_EMAIL,
 | 
				
			||||||
        "password": hash_password(settings.DEFAULT_PASSWORD),
 | 
					        "password": hash_password(settings._DEFAULT_PASSWORD),
 | 
				
			||||||
        "group": settings.DEFAULT_GROUP,
 | 
					        "group": settings.DEFAULT_GROUP,
 | 
				
			||||||
        "admin": True,
 | 
					        "admin": True,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,11 @@
 | 
				
			|||||||
from fastapi import APIRouter, Response
 | 
					from fastapi import APIRouter, Depends, Response
 | 
				
			||||||
 | 
					from sqlalchemy.orm.session import Session
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from mealie.core.config import get_app_settings
 | 
					from mealie.core.config import get_app_settings
 | 
				
			||||||
from mealie.core.settings.static import APP_VERSION
 | 
					from mealie.core.settings.static import APP_VERSION
 | 
				
			||||||
from mealie.schema.admin.about import AppInfo, AppTheme
 | 
					from mealie.db.db_setup import generate_session
 | 
				
			||||||
 | 
					from mealie.db.models.users.users import User
 | 
				
			||||||
 | 
					from mealie.schema.admin.about import AppInfo, AppStartupInfo, AppTheme
 | 
				
			||||||
 | 
					
 | 
				
			||||||
router = APIRouter(prefix="/about")
 | 
					router = APIRouter(prefix="/about")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,6 +23,21 @@ def get_app_info():
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@router.get("/startup-info", response_model=AppStartupInfo)
 | 
				
			||||||
 | 
					def get_startup_info(session: Session = Depends(generate_session)):
 | 
				
			||||||
 | 
					    """returns helpful startup information"""
 | 
				
			||||||
 | 
					    settings = get_app_settings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    is_first_login = False
 | 
				
			||||||
 | 
					    with session as db:
 | 
				
			||||||
 | 
					        if db.query(User).filter_by(email=settings._DEFAULT_EMAIL).count() > 0:
 | 
				
			||||||
 | 
					            is_first_login = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return AppStartupInfo(
 | 
				
			||||||
 | 
					        is_first_login=is_first_login,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@router.get("/theme", response_model=AppTheme)
 | 
					@router.get("/theme", response_model=AppTheme)
 | 
				
			||||||
def get_app_theme(resp: Response):
 | 
					def get_app_theme(resp: Response):
 | 
				
			||||||
    """Get's the current theme settings"""
 | 
					    """Get's the current theme settings"""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
# This file is auto-generated by gen_schema_exports.py
 | 
					# This file is auto-generated by gen_schema_exports.py
 | 
				
			||||||
from .about import AdminAboutInfo, AppInfo, AppStatistics, CheckAppConfig, DockerVolumeText
 | 
					from .about import AdminAboutInfo, AppInfo, AppStartupInfo, AppStatistics, AppTheme, CheckAppConfig, DockerVolumeText
 | 
				
			||||||
from .backup import AllBackups, BackupFile, BackupOptions, CreateBackup, ImportJob
 | 
					from .backup import AllBackups, BackupFile, BackupOptions, CreateBackup, ImportJob
 | 
				
			||||||
from .email import EmailReady, EmailSuccess, EmailTest
 | 
					from .email import EmailReady, EmailSuccess, EmailTest
 | 
				
			||||||
from .maintenance import MaintenanceLogs, MaintenanceStorageDetails, MaintenanceSummary
 | 
					from .maintenance import MaintenanceLogs, MaintenanceStorageDetails, MaintenanceSummary
 | 
				
			||||||
@@ -27,7 +27,9 @@ __all__ = [
 | 
				
			|||||||
    "MaintenanceSummary",
 | 
					    "MaintenanceSummary",
 | 
				
			||||||
    "AdminAboutInfo",
 | 
					    "AdminAboutInfo",
 | 
				
			||||||
    "AppInfo",
 | 
					    "AppInfo",
 | 
				
			||||||
 | 
					    "AppStartupInfo",
 | 
				
			||||||
    "AppStatistics",
 | 
					    "AppStatistics",
 | 
				
			||||||
 | 
					    "AppTheme",
 | 
				
			||||||
    "CheckAppConfig",
 | 
					    "CheckAppConfig",
 | 
				
			||||||
    "DockerVolumeText",
 | 
					    "DockerVolumeText",
 | 
				
			||||||
    "EmailReady",
 | 
					    "EmailReady",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,6 +34,15 @@ class AppTheme(MealieModel):
 | 
				
			|||||||
    dark_error: str = "#EF5350"
 | 
					    dark_error: str = "#EF5350"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AppStartupInfo(MealieModel):
 | 
				
			||||||
 | 
					    is_first_login: bool
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    The applications best guess that a user hasn't logged in. Currently, it really
 | 
				
			||||||
 | 
					    on indicates that the 'changeme@example.com' user is still in the database. Once
 | 
				
			||||||
 | 
					    it is removed, this will always return False.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AdminAboutInfo(AppInfo):
 | 
					class AdminAboutInfo(AppInfo):
 | 
				
			||||||
    versionLatest: str
 | 
					    versionLatest: str
 | 
				
			||||||
    api_port: int
 | 
					    api_port: int
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -92,6 +92,25 @@ __all__ = [
 | 
				
			|||||||
    "RecipeToolOut",
 | 
					    "RecipeToolOut",
 | 
				
			||||||
    "RecipeToolResponse",
 | 
					    "RecipeToolResponse",
 | 
				
			||||||
    "RecipeToolSave",
 | 
					    "RecipeToolSave",
 | 
				
			||||||
 | 
					    "RecipeTimelineEventCreate",
 | 
				
			||||||
 | 
					    "RecipeTimelineEventIn",
 | 
				
			||||||
 | 
					    "RecipeTimelineEventOut",
 | 
				
			||||||
 | 
					    "RecipeTimelineEventPagination",
 | 
				
			||||||
 | 
					    "RecipeTimelineEventUpdate",
 | 
				
			||||||
 | 
					    "TimelineEventImage",
 | 
				
			||||||
 | 
					    "TimelineEventType",
 | 
				
			||||||
 | 
					    "RecipeAsset",
 | 
				
			||||||
 | 
					    "RecipeSettings",
 | 
				
			||||||
 | 
					    "RecipeShareToken",
 | 
				
			||||||
 | 
					    "RecipeShareTokenCreate",
 | 
				
			||||||
 | 
					    "RecipeShareTokenSave",
 | 
				
			||||||
 | 
					    "RecipeShareTokenSummary",
 | 
				
			||||||
 | 
					    "RecipeDuplicate",
 | 
				
			||||||
 | 
					    "RecipeSlug",
 | 
				
			||||||
 | 
					    "RecipeZipTokenResponse",
 | 
				
			||||||
 | 
					    "SlugResponse",
 | 
				
			||||||
 | 
					    "UpdateImageResponse",
 | 
				
			||||||
 | 
					    "RecipeNote",
 | 
				
			||||||
    "CategoryBase",
 | 
					    "CategoryBase",
 | 
				
			||||||
    "CategoryIn",
 | 
					    "CategoryIn",
 | 
				
			||||||
    "CategoryOut",
 | 
					    "CategoryOut",
 | 
				
			||||||
@@ -102,6 +121,12 @@ __all__ = [
 | 
				
			|||||||
    "TagIn",
 | 
					    "TagIn",
 | 
				
			||||||
    "TagOut",
 | 
					    "TagOut",
 | 
				
			||||||
    "TagSave",
 | 
					    "TagSave",
 | 
				
			||||||
 | 
					    "RecipeCommentCreate",
 | 
				
			||||||
 | 
					    "RecipeCommentOut",
 | 
				
			||||||
 | 
					    "RecipeCommentPagination",
 | 
				
			||||||
 | 
					    "RecipeCommentSave",
 | 
				
			||||||
 | 
					    "RecipeCommentUpdate",
 | 
				
			||||||
 | 
					    "UserBase",
 | 
				
			||||||
    "AssignCategories",
 | 
					    "AssignCategories",
 | 
				
			||||||
    "AssignSettings",
 | 
					    "AssignSettings",
 | 
				
			||||||
    "AssignTags",
 | 
					    "AssignTags",
 | 
				
			||||||
@@ -109,34 +134,10 @@ __all__ = [
 | 
				
			|||||||
    "ExportBase",
 | 
					    "ExportBase",
 | 
				
			||||||
    "ExportRecipes",
 | 
					    "ExportRecipes",
 | 
				
			||||||
    "ExportTypes",
 | 
					    "ExportTypes",
 | 
				
			||||||
    "RecipeShareToken",
 | 
					 | 
				
			||||||
    "RecipeShareTokenCreate",
 | 
					 | 
				
			||||||
    "RecipeShareTokenSave",
 | 
					 | 
				
			||||||
    "RecipeShareTokenSummary",
 | 
					 | 
				
			||||||
    "ScrapeRecipe",
 | 
					 | 
				
			||||||
    "ScrapeRecipeTest",
 | 
					 | 
				
			||||||
    "RecipeCommentCreate",
 | 
					 | 
				
			||||||
    "RecipeCommentOut",
 | 
					 | 
				
			||||||
    "RecipeCommentPagination",
 | 
					 | 
				
			||||||
    "RecipeCommentSave",
 | 
					 | 
				
			||||||
    "RecipeCommentUpdate",
 | 
					 | 
				
			||||||
    "UserBase",
 | 
					 | 
				
			||||||
    "RecipeImageTypes",
 | 
					 | 
				
			||||||
    "CreateRecipe",
 | 
					 | 
				
			||||||
    "CreateRecipeBulk",
 | 
					 | 
				
			||||||
    "CreateRecipeByUrlBulk",
 | 
					 | 
				
			||||||
    "Recipe",
 | 
					 | 
				
			||||||
    "RecipeCategory",
 | 
					 | 
				
			||||||
    "RecipeCategoryPagination",
 | 
					 | 
				
			||||||
    "RecipeLastMade",
 | 
					 | 
				
			||||||
    "RecipePagination",
 | 
					 | 
				
			||||||
    "RecipeSummary",
 | 
					 | 
				
			||||||
    "RecipeTag",
 | 
					 | 
				
			||||||
    "RecipeTagPagination",
 | 
					 | 
				
			||||||
    "RecipeTool",
 | 
					 | 
				
			||||||
    "RecipeToolPagination",
 | 
					 | 
				
			||||||
    "IngredientReferences",
 | 
					    "IngredientReferences",
 | 
				
			||||||
    "RecipeStep",
 | 
					    "RecipeStep",
 | 
				
			||||||
 | 
					    "RecipeImageTypes",
 | 
				
			||||||
 | 
					    "Nutrition",
 | 
				
			||||||
    "CreateIngredientFood",
 | 
					    "CreateIngredientFood",
 | 
				
			||||||
    "CreateIngredientFoodAlias",
 | 
					    "CreateIngredientFoodAlias",
 | 
				
			||||||
    "CreateIngredientUnit",
 | 
					    "CreateIngredientUnit",
 | 
				
			||||||
@@ -159,20 +160,19 @@ __all__ = [
 | 
				
			|||||||
    "SaveIngredientFood",
 | 
					    "SaveIngredientFood",
 | 
				
			||||||
    "SaveIngredientUnit",
 | 
					    "SaveIngredientUnit",
 | 
				
			||||||
    "UnitFoodBase",
 | 
					    "UnitFoodBase",
 | 
				
			||||||
    "RecipeAsset",
 | 
					    "CreateRecipe",
 | 
				
			||||||
    "RecipeTimelineEventCreate",
 | 
					    "CreateRecipeBulk",
 | 
				
			||||||
    "RecipeTimelineEventIn",
 | 
					    "CreateRecipeByUrlBulk",
 | 
				
			||||||
    "RecipeTimelineEventOut",
 | 
					    "Recipe",
 | 
				
			||||||
    "RecipeTimelineEventPagination",
 | 
					    "RecipeCategory",
 | 
				
			||||||
    "RecipeTimelineEventUpdate",
 | 
					    "RecipeCategoryPagination",
 | 
				
			||||||
    "TimelineEventImage",
 | 
					    "RecipeLastMade",
 | 
				
			||||||
    "TimelineEventType",
 | 
					    "RecipePagination",
 | 
				
			||||||
    "RecipeDuplicate",
 | 
					    "RecipeSummary",
 | 
				
			||||||
    "RecipeSlug",
 | 
					    "RecipeTag",
 | 
				
			||||||
    "RecipeZipTokenResponse",
 | 
					    "RecipeTagPagination",
 | 
				
			||||||
    "SlugResponse",
 | 
					    "RecipeTool",
 | 
				
			||||||
    "UpdateImageResponse",
 | 
					    "RecipeToolPagination",
 | 
				
			||||||
    "Nutrition",
 | 
					    "ScrapeRecipe",
 | 
				
			||||||
    "RecipeSettings",
 | 
					    "ScrapeRecipeTest",
 | 
				
			||||||
    "RecipeNote",
 | 
					 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
# This file is auto-generated by gen_schema_exports.py
 | 
					# This file is auto-generated by gen_schema_exports.py
 | 
				
			||||||
from .pagination import OrderDirection, PaginationBase, PaginationQuery, RecipeSearchQuery
 | 
					from .pagination import OrderByNullPosition, OrderDirection, PaginationBase, PaginationQuery, RecipeSearchQuery
 | 
				
			||||||
from .query_filter import LogicalOperator, QueryFilter, QueryFilterComponent, RelationalKeyword, RelationalOperator
 | 
					from .query_filter import LogicalOperator, QueryFilter, QueryFilterComponent, RelationalKeyword, RelationalOperator
 | 
				
			||||||
from .query_search import SearchFilter
 | 
					from .query_search import SearchFilter
 | 
				
			||||||
from .responses import ErrorResponse, FileTokenResponse, SuccessResponse
 | 
					from .responses import ErrorResponse, FileTokenResponse, SuccessResponse
 | 
				
			||||||
@@ -15,6 +15,7 @@ __all__ = [
 | 
				
			|||||||
    "QueryFilterComponent",
 | 
					    "QueryFilterComponent",
 | 
				
			||||||
    "RelationalKeyword",
 | 
					    "RelationalKeyword",
 | 
				
			||||||
    "RelationalOperator",
 | 
					    "RelationalOperator",
 | 
				
			||||||
 | 
					    "OrderByNullPosition",
 | 
				
			||||||
    "OrderDirection",
 | 
					    "OrderDirection",
 | 
				
			||||||
    "PaginationBase",
 | 
					    "PaginationBase",
 | 
				
			||||||
    "PaginationQuery",
 | 
					    "PaginationQuery",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -116,7 +116,7 @@ class UserOut(UserBase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def is_default_user(self) -> bool:
 | 
					    def is_default_user(self) -> bool:
 | 
				
			||||||
        return self.email == settings.DEFAULT_EMAIL.strip().lower()
 | 
					        return self.email == settings._DEFAULT_EMAIL.strip().lower()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def loader_options(cls) -> list[LoaderOption]:
 | 
					    def loader_options(cls) -> list[LoaderOption]:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								tests/fixtures/fixture_admin.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								tests/fixtures/fixture_admin.py
									
									
									
									
										vendored
									
									
								
							@@ -10,7 +10,7 @@ from tests.utils import api_routes
 | 
				
			|||||||
def admin_token(api_client: TestClient):
 | 
					def admin_token(api_client: TestClient):
 | 
				
			||||||
    settings = get_app_settings()
 | 
					    settings = get_app_settings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    form_data = {"username": settings.DEFAULT_EMAIL, "password": settings.DEFAULT_PASSWORD}
 | 
					    form_data = {"username": settings._DEFAULT_EMAIL, "password": settings._DEFAULT_PASSWORD}
 | 
				
			||||||
    return utils.login(form_data, api_client)
 | 
					    return utils.login(form_data, api_client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,7 +18,7 @@ def admin_token(api_client: TestClient):
 | 
				
			|||||||
def admin_user(api_client: TestClient):
 | 
					def admin_user(api_client: TestClient):
 | 
				
			||||||
    settings = get_app_settings()
 | 
					    settings = get_app_settings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    form_data = {"username": settings.DEFAULT_EMAIL, "password": settings.DEFAULT_PASSWORD}
 | 
					    form_data = {"username": settings._DEFAULT_EMAIL, "password": settings._DEFAULT_PASSWORD}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    token = utils.login(form_data, api_client)
 | 
					    token = utils.login(form_data, api_client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -33,7 +33,7 @@ def admin_user(api_client: TestClient):
 | 
				
			|||||||
        yield utils.TestUser(
 | 
					        yield utils.TestUser(
 | 
				
			||||||
            _group_id=user_data.get("groupId"),
 | 
					            _group_id=user_data.get("groupId"),
 | 
				
			||||||
            user_id=user_data.get("id"),
 | 
					            user_id=user_data.get("id"),
 | 
				
			||||||
            password=settings.DEFAULT_PASSWORD,
 | 
					            password=settings._DEFAULT_PASSWORD,
 | 
				
			||||||
            username=user_data.get("username"),
 | 
					            username=user_data.get("username"),
 | 
				
			||||||
            email=user_data.get("email"),
 | 
					            email=user_data.get("email"),
 | 
				
			||||||
            token=token,
 | 
					            token=token,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,7 +36,7 @@ def test_init_superuser(api_client: TestClient, admin_user: TestUser):
 | 
				
			|||||||
    assert admin_data["groupId"] == admin_user.group_id
 | 
					    assert admin_data["groupId"] == admin_user.group_id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert admin_data["fullName"] == "Change Me"
 | 
					    assert admin_data["fullName"] == "Change Me"
 | 
				
			||||||
    assert admin_data["email"] == settings.DEFAULT_EMAIL
 | 
					    assert admin_data["email"] == settings._DEFAULT_EMAIL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_create_user(api_client: TestClient, admin_token):
 | 
					def test_create_user(api_client: TestClient, admin_token):
 | 
				
			||||||
@@ -95,7 +95,7 @@ def test_update_other_user_as_not_admin(api_client: TestClient, unique_user: Tes
 | 
				
			|||||||
    update_data = {
 | 
					    update_data = {
 | 
				
			||||||
        "id": unique_user.user_id,
 | 
					        "id": unique_user.user_id,
 | 
				
			||||||
        "fullName": "Updated Name",
 | 
					        "fullName": "Updated Name",
 | 
				
			||||||
        "email": settings.DEFAULT_EMAIL,
 | 
					        "email": settings._DEFAULT_EMAIL,
 | 
				
			||||||
        "group": "Home",
 | 
					        "group": "Home",
 | 
				
			||||||
        "admin": True,
 | 
					        "admin": True,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@ from tests.utils.fixture_schemas import TestUser
 | 
				
			|||||||
def test_failed_login(api_client: TestClient):
 | 
					def test_failed_login(api_client: TestClient):
 | 
				
			||||||
    settings = get_app_settings()
 | 
					    settings = get_app_settings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    form_data = {"username": settings.DEFAULT_EMAIL, "password": "WRONG_PASSWORD"}
 | 
					    form_data = {"username": settings._DEFAULT_EMAIL, "password": "WRONG_PASSWORD"}
 | 
				
			||||||
    response = api_client.post(api_routes.auth_token, data=form_data)
 | 
					    response = api_client.post(api_routes.auth_token, data=form_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert response.status_code == 401
 | 
					    assert response.status_code == 401
 | 
				
			||||||
@@ -23,7 +23,7 @@ def test_failed_login(api_client: TestClient):
 | 
				
			|||||||
def test_superuser_login(api_client: TestClient, admin_token):
 | 
					def test_superuser_login(api_client: TestClient, admin_token):
 | 
				
			||||||
    settings = get_app_settings()
 | 
					    settings = get_app_settings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    form_data = {"username": settings.DEFAULT_EMAIL, "password": settings.DEFAULT_PASSWORD}
 | 
					    form_data = {"username": settings._DEFAULT_EMAIL, "password": settings._DEFAULT_PASSWORD}
 | 
				
			||||||
    response = api_client.post(api_routes.auth_token, data=form_data)
 | 
					    response = api_client.post(api_routes.auth_token, data=form_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert response.status_code == 200
 | 
					    assert response.status_code == 200
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,6 @@ from mealie.core.settings.settings import AppSettings
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def test_non_default_settings(monkeypatch):
 | 
					def test_non_default_settings(monkeypatch):
 | 
				
			||||||
    monkeypatch.setenv("DEFAULT_GROUP", "Test Group")
 | 
					    monkeypatch.setenv("DEFAULT_GROUP", "Test Group")
 | 
				
			||||||
    monkeypatch.setenv("DEFAULT_PASSWORD", "Test Password")
 | 
					 | 
				
			||||||
    monkeypatch.setenv("API_PORT", "8000")
 | 
					    monkeypatch.setenv("API_PORT", "8000")
 | 
				
			||||||
    monkeypatch.setenv("API_DOCS", "False")
 | 
					    monkeypatch.setenv("API_DOCS", "False")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -17,7 +16,6 @@ def test_non_default_settings(monkeypatch):
 | 
				
			|||||||
    app_settings = get_app_settings()
 | 
					    app_settings = get_app_settings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert app_settings.DEFAULT_GROUP == "Test Group"
 | 
					    assert app_settings.DEFAULT_GROUP == "Test Group"
 | 
				
			||||||
    assert app_settings.DEFAULT_PASSWORD == "Test Password"
 | 
					 | 
				
			||||||
    assert app_settings.API_PORT == 8000
 | 
					    assert app_settings.API_PORT == 8000
 | 
				
			||||||
    assert app_settings.API_DOCS is False
 | 
					    assert app_settings.API_DOCS is False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,6 +45,10 @@ admin_users_unlock = "/api/admin/users/unlock"
 | 
				
			|||||||
"""`/api/admin/users/unlock`"""
 | 
					"""`/api/admin/users/unlock`"""
 | 
				
			||||||
app_about = "/api/app/about"
 | 
					app_about = "/api/app/about"
 | 
				
			||||||
"""`/api/app/about`"""
 | 
					"""`/api/app/about`"""
 | 
				
			||||||
 | 
					app_about_startup_info = "/api/app/about/startup-info"
 | 
				
			||||||
 | 
					"""`/api/app/about/startup-info`"""
 | 
				
			||||||
 | 
					app_about_theme = "/api/app/about/theme"
 | 
				
			||||||
 | 
					"""`/api/app/about/theme`"""
 | 
				
			||||||
auth_refresh = "/api/auth/refresh"
 | 
					auth_refresh = "/api/auth/refresh"
 | 
				
			||||||
"""`/api/auth/refresh`"""
 | 
					"""`/api/auth/refresh`"""
 | 
				
			||||||
auth_token = "/api/auth/token"
 | 
					auth_token = "/api/auth/token"
 | 
				
			||||||
@@ -183,6 +187,8 @@ users_reset_password = "/api/users/reset-password"
 | 
				
			|||||||
"""`/api/users/reset-password`"""
 | 
					"""`/api/users/reset-password`"""
 | 
				
			||||||
users_self = "/api/users/self"
 | 
					users_self = "/api/users/self"
 | 
				
			||||||
"""`/api/users/self`"""
 | 
					"""`/api/users/self`"""
 | 
				
			||||||
 | 
					users_self_group = "/api/users/self/group"
 | 
				
			||||||
 | 
					"""`/api/users/self/group`"""
 | 
				
			||||||
utils_download = "/api/utils/download"
 | 
					utils_download = "/api/utils/download"
 | 
				
			||||||
"""`/api/utils/download`"""
 | 
					"""`/api/utils/download`"""
 | 
				
			||||||
validators_group = "/api/validators/group"
 | 
					validators_group = "/api/validators/group"
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user