mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-12-15 14:55:21 -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:
@@ -104,7 +104,6 @@ async def system_startup():
|
||||
indent=4,
|
||||
exclude={
|
||||
"SECRET",
|
||||
"DEFAULT_PASSWORD",
|
||||
"SFTP_PASSWORD",
|
||||
"SFTP_USERNAME",
|
||||
"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
|
||||
|
||||
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
|
||||
|
||||
@@ -13,7 +13,7 @@ def dev_users() -> list[dict]:
|
||||
"full_name": "Jason",
|
||||
"username": "jason",
|
||||
"email": "jason@example.com",
|
||||
"password": hash_password(settings.DEFAULT_PASSWORD),
|
||||
"password": hash_password(settings._DEFAULT_PASSWORD),
|
||||
"group": settings.DEFAULT_GROUP,
|
||||
"admin": False,
|
||||
},
|
||||
@@ -21,7 +21,7 @@ def dev_users() -> list[dict]:
|
||||
"full_name": "Bob",
|
||||
"username": "bob",
|
||||
"email": "bob@example.com",
|
||||
"password": hash_password(settings.DEFAULT_PASSWORD),
|
||||
"password": hash_password(settings._DEFAULT_PASSWORD),
|
||||
"group": settings.DEFAULT_GROUP,
|
||||
"admin": False,
|
||||
},
|
||||
@@ -29,7 +29,7 @@ def dev_users() -> list[dict]:
|
||||
"full_name": "Sarah",
|
||||
"username": "sarah",
|
||||
"email": "sarah@example.com",
|
||||
"password": hash_password(settings.DEFAULT_PASSWORD),
|
||||
"password": hash_password(settings._DEFAULT_PASSWORD),
|
||||
"group": settings.DEFAULT_GROUP,
|
||||
"admin": False,
|
||||
},
|
||||
@@ -37,7 +37,7 @@ def dev_users() -> list[dict]:
|
||||
"full_name": "Sammy",
|
||||
"username": "sammy",
|
||||
"email": "sammy@example.com",
|
||||
"password": hash_password(settings.DEFAULT_PASSWORD),
|
||||
"password": hash_password(settings._DEFAULT_PASSWORD),
|
||||
"group": settings.DEFAULT_GROUP,
|
||||
"admin": False,
|
||||
},
|
||||
@@ -48,8 +48,8 @@ def default_user_init(db: AllRepositories):
|
||||
default_user = {
|
||||
"full_name": "Change Me",
|
||||
"username": "admin",
|
||||
"email": settings.DEFAULT_EMAIL,
|
||||
"password": hash_password(settings.DEFAULT_PASSWORD),
|
||||
"email": settings._DEFAULT_EMAIL,
|
||||
"password": hash_password(settings._DEFAULT_PASSWORD),
|
||||
"group": settings.DEFAULT_GROUP,
|
||||
"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.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")
|
||||
|
||||
@@ -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)
|
||||
def get_app_theme(resp: Response):
|
||||
"""Get's the current theme settings"""
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# 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 .email import EmailReady, EmailSuccess, EmailTest
|
||||
from .maintenance import MaintenanceLogs, MaintenanceStorageDetails, MaintenanceSummary
|
||||
@@ -27,7 +27,9 @@ __all__ = [
|
||||
"MaintenanceSummary",
|
||||
"AdminAboutInfo",
|
||||
"AppInfo",
|
||||
"AppStartupInfo",
|
||||
"AppStatistics",
|
||||
"AppTheme",
|
||||
"CheckAppConfig",
|
||||
"DockerVolumeText",
|
||||
"EmailReady",
|
||||
|
||||
@@ -34,6 +34,15 @@ class AppTheme(MealieModel):
|
||||
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):
|
||||
versionLatest: str
|
||||
api_port: int
|
||||
|
||||
@@ -92,6 +92,25 @@ __all__ = [
|
||||
"RecipeToolOut",
|
||||
"RecipeToolResponse",
|
||||
"RecipeToolSave",
|
||||
"RecipeTimelineEventCreate",
|
||||
"RecipeTimelineEventIn",
|
||||
"RecipeTimelineEventOut",
|
||||
"RecipeTimelineEventPagination",
|
||||
"RecipeTimelineEventUpdate",
|
||||
"TimelineEventImage",
|
||||
"TimelineEventType",
|
||||
"RecipeAsset",
|
||||
"RecipeSettings",
|
||||
"RecipeShareToken",
|
||||
"RecipeShareTokenCreate",
|
||||
"RecipeShareTokenSave",
|
||||
"RecipeShareTokenSummary",
|
||||
"RecipeDuplicate",
|
||||
"RecipeSlug",
|
||||
"RecipeZipTokenResponse",
|
||||
"SlugResponse",
|
||||
"UpdateImageResponse",
|
||||
"RecipeNote",
|
||||
"CategoryBase",
|
||||
"CategoryIn",
|
||||
"CategoryOut",
|
||||
@@ -102,6 +121,12 @@ __all__ = [
|
||||
"TagIn",
|
||||
"TagOut",
|
||||
"TagSave",
|
||||
"RecipeCommentCreate",
|
||||
"RecipeCommentOut",
|
||||
"RecipeCommentPagination",
|
||||
"RecipeCommentSave",
|
||||
"RecipeCommentUpdate",
|
||||
"UserBase",
|
||||
"AssignCategories",
|
||||
"AssignSettings",
|
||||
"AssignTags",
|
||||
@@ -109,34 +134,10 @@ __all__ = [
|
||||
"ExportBase",
|
||||
"ExportRecipes",
|
||||
"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",
|
||||
"RecipeStep",
|
||||
"RecipeImageTypes",
|
||||
"Nutrition",
|
||||
"CreateIngredientFood",
|
||||
"CreateIngredientFoodAlias",
|
||||
"CreateIngredientUnit",
|
||||
@@ -159,20 +160,19 @@ __all__ = [
|
||||
"SaveIngredientFood",
|
||||
"SaveIngredientUnit",
|
||||
"UnitFoodBase",
|
||||
"RecipeAsset",
|
||||
"RecipeTimelineEventCreate",
|
||||
"RecipeTimelineEventIn",
|
||||
"RecipeTimelineEventOut",
|
||||
"RecipeTimelineEventPagination",
|
||||
"RecipeTimelineEventUpdate",
|
||||
"TimelineEventImage",
|
||||
"TimelineEventType",
|
||||
"RecipeDuplicate",
|
||||
"RecipeSlug",
|
||||
"RecipeZipTokenResponse",
|
||||
"SlugResponse",
|
||||
"UpdateImageResponse",
|
||||
"Nutrition",
|
||||
"RecipeSettings",
|
||||
"RecipeNote",
|
||||
"CreateRecipe",
|
||||
"CreateRecipeBulk",
|
||||
"CreateRecipeByUrlBulk",
|
||||
"Recipe",
|
||||
"RecipeCategory",
|
||||
"RecipeCategoryPagination",
|
||||
"RecipeLastMade",
|
||||
"RecipePagination",
|
||||
"RecipeSummary",
|
||||
"RecipeTag",
|
||||
"RecipeTagPagination",
|
||||
"RecipeTool",
|
||||
"RecipeToolPagination",
|
||||
"ScrapeRecipe",
|
||||
"ScrapeRecipeTest",
|
||||
]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# 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_search import SearchFilter
|
||||
from .responses import ErrorResponse, FileTokenResponse, SuccessResponse
|
||||
@@ -15,6 +15,7 @@ __all__ = [
|
||||
"QueryFilterComponent",
|
||||
"RelationalKeyword",
|
||||
"RelationalOperator",
|
||||
"OrderByNullPosition",
|
||||
"OrderDirection",
|
||||
"PaginationBase",
|
||||
"PaginationQuery",
|
||||
|
||||
@@ -116,7 +116,7 @@ class UserOut(UserBase):
|
||||
|
||||
@property
|
||||
def is_default_user(self) -> bool:
|
||||
return self.email == settings.DEFAULT_EMAIL.strip().lower()
|
||||
return self.email == settings._DEFAULT_EMAIL.strip().lower()
|
||||
|
||||
@classmethod
|
||||
def loader_options(cls) -> list[LoaderOption]:
|
||||
|
||||
Reference in New Issue
Block a user