mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-05-31 12:15:42 -04:00
Refactor/app settings (#251)
* fix env setup bugs * remove unused import * fix layout issues * changelog Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
parent
786ddae05b
commit
94cda5bb83
@ -12,4 +12,5 @@
|
|||||||
- Fix Backup download blocked by authentication
|
- Fix Backup download blocked by authentication
|
||||||
- Random meal-planner will no longer duplicate recipes unless no other options
|
- Random meal-planner will no longer duplicate recipes unless no other options
|
||||||
- New Quick Week button to generate next 5 day week of recipe slots.
|
- New Quick Week button to generate next 5 day week of recipe slots.
|
||||||
|
- Minor UI tweaks
|
||||||
|
|
||||||
|
@ -42,4 +42,7 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.v-text-field{
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -10,14 +10,14 @@
|
|||||||
<v-checkbox
|
<v-checkbox
|
||||||
hide-details
|
hide-details
|
||||||
v-model="ingredient.checked"
|
v-model="ingredient.checked"
|
||||||
class=" pt-0 ingredients my-auto py-auto"
|
class="pt-0 my-auto py-auto"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
>
|
>
|
||||||
</v-checkbox>
|
</v-checkbox>
|
||||||
|
|
||||||
<v-list-item-content>
|
<v-list-item-content>
|
||||||
<vue-markdown
|
<vue-markdown
|
||||||
class="my-auto text-subtitle-1 mb-0"
|
class="ma-0 pa-0 text-subtitle-1 dense-markdown"
|
||||||
:source="ingredient.text"
|
:source="ingredient.text"
|
||||||
>
|
>
|
||||||
</vue-markdown>
|
</vue-markdown>
|
||||||
@ -55,12 +55,8 @@ export default {
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style >
|
||||||
p {
|
.dense-markdown p {
|
||||||
margin-bottom: auto !important;
|
margin: auto !important;
|
||||||
}
|
|
||||||
|
|
||||||
.my-card-text {
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -57,28 +57,23 @@
|
|||||||
<strong>{{ groupSettings.webhookTime }}</strong>
|
<strong>{{ groupSettings.webhookTime }}</strong>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<v-row dense align="center">
|
<v-row dense class="flex align-center">
|
||||||
<v-col cols="12" md="2" sm="5">
|
<v-switch
|
||||||
<v-switch
|
class="mx-2"
|
||||||
v-model="groupSettings.webhookEnable"
|
v-model="groupSettings.webhookEnable"
|
||||||
:label="$t('general.enabled')"
|
:label="$t('general.enabled')"
|
||||||
></v-switch>
|
></v-switch>
|
||||||
</v-col>
|
<TimePickerDialog @save-time="saveTime" class="ma-2" />
|
||||||
<v-col cols="12" md="3" sm="5">
|
<v-btn class="ma-2" color="info" @click="testWebhooks">
|
||||||
<TimePickerDialog @save-time="saveTime" />
|
<v-icon left> mdi-webhook </v-icon>
|
||||||
</v-col>
|
{{ $t("settings.webhooks.test-webhooks") }}
|
||||||
<v-col cols="12" md="4" sm="5">
|
</v-btn>
|
||||||
<v-btn text color="info" @click="testWebhooks">
|
|
||||||
<v-icon left> mdi-webhook </v-icon>
|
|
||||||
{{ $t("settings.webhooks.test-webhooks") }}
|
|
||||||
</v-btn>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
<v-row
|
<v-row
|
||||||
v-for="(url, index) in groupSettings.webhookUrls"
|
v-for="(url, index) in groupSettings.webhookUrls"
|
||||||
:key="index"
|
:key="index"
|
||||||
align="center"
|
align=" center"
|
||||||
dense
|
dense
|
||||||
>
|
>
|
||||||
<v-col cols="1">
|
<v-col cols="1">
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
import secrets
|
import secrets
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Optional, Union
|
||||||
|
|
||||||
import dotenv
|
from pydantic import BaseSettings, Field, validator
|
||||||
|
|
||||||
APP_VERSION = "v0.4.0"
|
APP_VERSION = "v0.4.0"
|
||||||
DB_VERSION = "v0.4.0"
|
DB_VERSION = "v0.4.0"
|
||||||
@ -11,7 +12,6 @@ CWD = Path(__file__).parent
|
|||||||
BASE_DIR = CWD.parent.parent
|
BASE_DIR = CWD.parent.parent
|
||||||
|
|
||||||
ENV = BASE_DIR.joinpath(".env")
|
ENV = BASE_DIR.joinpath(".env")
|
||||||
dotenv.load_dotenv(ENV)
|
|
||||||
PRODUCTION = os.environ.get("ENV")
|
PRODUCTION = os.environ.get("ENV")
|
||||||
|
|
||||||
|
|
||||||
@ -38,6 +38,11 @@ def determine_secrets(data_dir: Path, production: bool) -> str:
|
|||||||
return new_secret
|
return new_secret
|
||||||
|
|
||||||
|
|
||||||
|
# General
|
||||||
|
DATA_DIR = determine_data_dir(PRODUCTION)
|
||||||
|
LOGGER_FILE = DATA_DIR.joinpath("mealie.log")
|
||||||
|
|
||||||
|
|
||||||
class AppDirectories:
|
class AppDirectories:
|
||||||
def __init__(self, cwd, data_dir) -> None:
|
def __init__(self, cwd, data_dir) -> None:
|
||||||
self.DATA_DIR = data_dir
|
self.DATA_DIR = data_dir
|
||||||
@ -74,36 +79,51 @@ class AppDirectories:
|
|||||||
dir.mkdir(parents=True, exist_ok=True)
|
dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
class AppSettings:
|
|
||||||
def __init__(self, app_dirs: AppDirectories) -> None:
|
|
||||||
global DB_VERSION
|
|
||||||
self.PRODUCTION = bool(os.environ.get("ENV"))
|
|
||||||
self.IS_DEMO = os.getenv("DEMO", "False") == "True"
|
|
||||||
self.API_PORT = int(os.getenv("API_PORT", 9000))
|
|
||||||
self.API = os.getenv("API_DOCS", "True") == "True"
|
|
||||||
self.DOCS_URL = "/docs" if self.API else None
|
|
||||||
self.REDOC_URL = "/redoc" if self.API else None
|
|
||||||
self.SECRET = determine_secrets(app_dirs.DATA_DIR, self.PRODUCTION)
|
|
||||||
self.DATABASE_TYPE = os.getenv("DB_TYPE", "sqlite")
|
|
||||||
|
|
||||||
# Used to Set SQLite File Version
|
|
||||||
self.SQLITE_FILE = None
|
|
||||||
if self.DATABASE_TYPE == "sqlite":
|
|
||||||
self.SQLITE_FILE = app_dirs.SQLITE_DIR.joinpath(f"mealie_{DB_VERSION}.sqlite")
|
|
||||||
else:
|
|
||||||
raise Exception("Unable to determine database type. Acceptible options are 'sqlite'")
|
|
||||||
|
|
||||||
self.DEFAULT_GROUP = os.getenv("DEFAULT_GROUP", "Home")
|
|
||||||
self.DEFAULT_PASSWORD = os.getenv("DEFAULT_PASSWORD", "MyPassword")
|
|
||||||
|
|
||||||
# Not Used!
|
|
||||||
self.SFTP_USERNAME = os.getenv("SFTP_USERNAME", None)
|
|
||||||
self.SFTP_PASSWORD = os.getenv("SFTP_PASSWORD", None)
|
|
||||||
|
|
||||||
|
|
||||||
# General
|
|
||||||
DATA_DIR = determine_data_dir(PRODUCTION)
|
|
||||||
LOGGER_FILE = DATA_DIR.joinpath("mealie.log")
|
|
||||||
|
|
||||||
app_dirs = AppDirectories(CWD, DATA_DIR)
|
app_dirs = AppDirectories(CWD, DATA_DIR)
|
||||||
settings = AppSettings(app_dirs)
|
|
||||||
|
|
||||||
|
class AppSettings(BaseSettings):
|
||||||
|
global DATA_DIR
|
||||||
|
PRODUCTION: bool = Field(False, env="ENV")
|
||||||
|
IS_DEMO: bool = False
|
||||||
|
API_PORT: int = 9000
|
||||||
|
API_DOCS: bool = True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def DOCS_URL(self) -> str:
|
||||||
|
return "/docs" if self.API_DOCS else None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def REDOC_URL(self) -> str:
|
||||||
|
return "/redoc" if self.API_DOCS else None
|
||||||
|
|
||||||
|
SECRET: str = determine_secrets(DATA_DIR, PRODUCTION)
|
||||||
|
DATABASE_TYPE: str = Field("sqlite", env="DB_TYPE")
|
||||||
|
|
||||||
|
@validator("DATABASE_TYPE", pre=True)
|
||||||
|
def validate_db_type(cls, v: str) -> Optional[str]:
|
||||||
|
if v != "sqlite":
|
||||||
|
raise ValueError("Unable to determine database type. Acceptible options are 'sqlite'")
|
||||||
|
else:
|
||||||
|
return v
|
||||||
|
|
||||||
|
# Used to Set SQLite File Version
|
||||||
|
SQLITE_FILE: Optional[Union[str, Path]]
|
||||||
|
|
||||||
|
@validator("SQLITE_FILE", pre=True)
|
||||||
|
def identify_sqlite_file(cls, v: str) -> Optional[str]:
|
||||||
|
return app_dirs.SQLITE_DIR.joinpath(f"mealie_{DB_VERSION}.sqlite")
|
||||||
|
|
||||||
|
DEFAULT_GROUP: str = "Home"
|
||||||
|
DEFAULT_PASSWORD: str = "MyPassword"
|
||||||
|
|
||||||
|
# Not Used!
|
||||||
|
SFTP_USERNAME: Optional[str]
|
||||||
|
SFTP_PASSWORD: Optional[str]
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
env_file = BASE_DIR.joinpath(".env")
|
||||||
|
env_file_encoding = "utf-8"
|
||||||
|
|
||||||
|
|
||||||
|
settings = AppSettings()
|
||||||
|
@ -4,19 +4,39 @@ import pytest
|
|||||||
from mealie.core.config import CWD, DATA_DIR, AppDirectories, AppSettings, determine_data_dir, determine_secrets
|
from mealie.core.config import CWD, DATA_DIR, AppDirectories, AppSettings, determine_data_dir, determine_secrets
|
||||||
|
|
||||||
|
|
||||||
|
def test_default_settings(monkeypatch):
|
||||||
|
monkeypatch.delenv("DEFAULT_GROUP", raising=False)
|
||||||
|
monkeypatch.delenv("DEFAULT_PASSWORD", raising=False)
|
||||||
|
monkeypatch.delenv("API_PORT", raising=False)
|
||||||
|
monkeypatch.delenv("API_DOCS", raising=False)
|
||||||
|
monkeypatch.delenv("DB_TYPE", raising=False)
|
||||||
|
monkeypatch.delenv("IS_DEMO", raising=False)
|
||||||
|
|
||||||
|
app_settings = AppSettings()
|
||||||
|
|
||||||
|
assert app_settings.DEFAULT_GROUP == "Home"
|
||||||
|
assert app_settings.DEFAULT_PASSWORD == "MyPassword"
|
||||||
|
assert app_settings.DATABASE_TYPE == "sqlite"
|
||||||
|
assert app_settings.API_PORT == 9000
|
||||||
|
assert app_settings.API_DOCS is True
|
||||||
|
assert app_settings.IS_DEMO is False
|
||||||
|
|
||||||
|
assert app_settings.REDOC_URL == "/redoc"
|
||||||
|
assert app_settings.DOCS_URL == "/docs"
|
||||||
|
|
||||||
|
|
||||||
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("DEFAULT_PASSWORD", "Test Password")
|
||||||
monkeypatch.setenv("API_PORT", "8000")
|
monkeypatch.setenv("API_PORT", "8000")
|
||||||
monkeypatch.setenv("API_DOCS", False)
|
monkeypatch.setenv("API_DOCS", False)
|
||||||
|
|
||||||
app_dirs = AppDirectories(CWD, DATA_DIR)
|
app_settings = AppSettings()
|
||||||
app_settings = AppSettings(app_dirs)
|
|
||||||
|
|
||||||
assert app_settings.DEFAULT_GROUP == "Test Group"
|
assert app_settings.DEFAULT_GROUP == "Test Group"
|
||||||
assert app_settings.DEFAULT_PASSWORD == "Test Password"
|
assert app_settings.DEFAULT_PASSWORD == "Test Password"
|
||||||
assert app_settings.API_PORT == 8000
|
assert app_settings.API_PORT == 8000
|
||||||
assert app_settings.API is False
|
assert app_settings.API_DOCS is False
|
||||||
|
|
||||||
assert app_settings.REDOC_URL is None
|
assert app_settings.REDOC_URL is None
|
||||||
assert app_settings.DOCS_URL is None
|
assert app_settings.DOCS_URL is None
|
||||||
@ -25,9 +45,8 @@ def test_non_default_settings(monkeypatch):
|
|||||||
def test_unknown_database(monkeypatch):
|
def test_unknown_database(monkeypatch):
|
||||||
monkeypatch.setenv("DB_TYPE", "nonsense")
|
monkeypatch.setenv("DB_TYPE", "nonsense")
|
||||||
|
|
||||||
with pytest.raises(Exception, match="Unable to determine database type. Acceptible options are 'sqlite'"):
|
with pytest.raises(ValueError, match="Unable to determine database type. Acceptible options are 'sqlite'"):
|
||||||
app_dirs = AppDirectories(CWD, DATA_DIR)
|
AppSettings()
|
||||||
AppSettings(app_dirs)
|
|
||||||
|
|
||||||
|
|
||||||
def test_secret_generation(tmp_path):
|
def test_secret_generation(tmp_path):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user