LIM configured no logging at all, so the instruction fetcher had no trail to follow. Adds a rotating file handler on the root logger plus two owner-only admin pages. - Admin > Logs: filter by level, source and text; tracebacks kept with their error; auto-refresh, raw download, rotated-file browsing and rotate-now - Admin > Logs > Brickset API calls: every outbound call recorded with method, params, caller, duration, result count and error, plus daily quota accounting (only getSets counts) and a comparison against getKeyUsageStats - New owner concept (services/ownership.py): a single account, distinct from is_admin, since these pages expose other admins activity. Defaults to the first admin; flask owner show/set to change - Services now log through module loggers; retention setting and pruning for call records - New CLI: flask owner show/set, flask logs path/prune - New table brickset_api_calls, created automatically at boot; LOG_* env vars, /data/logs in Docker
236 lines
7.6 KiB
Batchfile
236 lines
7.6 KiB
Batchfile
@echo off
|
|
REM ===========================================================================
|
|
REM LEGO Instructions Manager - Instruction Fetcher + Logging installer
|
|
REM
|
|
REM RUN THIS FROM THE FOLDER YOU EXTRACTED THE UPDATE INTO, not from your
|
|
REM LIM install - the two cannot be the same folder.
|
|
REM
|
|
REM Copies 22 named files into an existing LIM install, backing up every
|
|
REM file it replaces first. Whole directories are never copied, so your
|
|
REM uploads and database are not involved.
|
|
REM
|
|
REM Usage: install_instruction_fetcher.bat [target]
|
|
REM Default target: E:\LIM
|
|
REM
|
|
REM Created by: Jess Rogerson (yelling commands at Claude.AI)
|
|
REM ===========================================================================
|
|
|
|
setlocal EnableDelayedExpansion
|
|
|
|
set "SOURCE=%~dp0"
|
|
set "TARGET=%~1"
|
|
if "%TARGET%"=="" set "TARGET=E:\LIM"
|
|
set "MISSING=0"
|
|
set "COPYFAIL=0"
|
|
set "SAVED=0"
|
|
|
|
for %%A in ("%SOURCE%.") do set "SRCFULL=%%~fA"
|
|
for %%B in ("%TARGET%\.") do set "DSTFULL=%%~fB"
|
|
|
|
echo.
|
|
echo Source : %SRCFULL%
|
|
echo Target : %DSTFULL%
|
|
echo.
|
|
|
|
REM --- refuse to copy a folder onto itself -----------------------------------
|
|
if /i "%SRCFULL%"=="%DSTFULL%" goto :samedir
|
|
|
|
if not exist "%TARGET%\app\__init__.py" goto :nottarget
|
|
|
|
REM --- are the update files actually here? -----------------------------------
|
|
echo Checking the update files...
|
|
call :need ".env.docker.example"
|
|
call :need ".env.example"
|
|
call :need "README.md"
|
|
call :need "app\__init__.py"
|
|
call :need "app\cli.py"
|
|
call :need "app\config.py"
|
|
call :need "app\models\__init__.py"
|
|
call :need "app\models\api_call.py"
|
|
call :need "app\models\instruction.py"
|
|
call :need "app\models\instruction_fetch.py"
|
|
call :need "app\models\site_setting.py"
|
|
call :need "app\routes\__init__.py"
|
|
call :need "app\routes\instruction_fetch.py"
|
|
call :need "app\routes\logs.py"
|
|
call :need "app\services\brickset_api.py"
|
|
call :need "app\services\fetch_worker.py"
|
|
call :need "app\services\instruction_fetcher.py"
|
|
call :need "app\services\logging_setup.py"
|
|
call :need "app\services\ownership.py"
|
|
call :need "app\services\schema_upgrade.py"
|
|
call :need "app\templates\admin\brickset_calls.html"
|
|
call :need "app\templates\admin\dashboard.html"
|
|
call :need "app\templates\admin\instruction_fetch.html"
|
|
call :need "app\templates\admin\logs.html"
|
|
call :need "app\templates\admin\settings.html"
|
|
call :need "diagnose_fetcher.py"
|
|
call :need "docker-compose.yml"
|
|
call :need "docker\entrypoint.sh"
|
|
call :need "docs\INSTRUCTION_FETCHER.md"
|
|
call :need "docs\LOGGING.md"
|
|
if not "%MISSING%"=="0" goto :incomplete
|
|
echo all 30 present.
|
|
|
|
REM --- backup ------------------------------------------------------------------
|
|
for /f "tokens=2 delims==" %%I in ('wmic os get localdatetime /value') do set "DT=%%I"
|
|
set "STAMP=!DT:~0,8!-!DT:~8,6!"
|
|
set "BACKUP=%TARGET%\_backup_fetcher_!STAMP!"
|
|
|
|
echo.
|
|
echo Backing up the files about to be replaced:
|
|
echo !BACKUP!
|
|
echo.
|
|
mkdir "!BACKUP!" 2>nul
|
|
call :save ".env.docker.example"
|
|
call :save ".env.example"
|
|
call :save "README.md"
|
|
call :save "app\__init__.py"
|
|
call :save "app\cli.py"
|
|
call :save "app\config.py"
|
|
call :save "app\models\__init__.py"
|
|
call :save "app\models\api_call.py"
|
|
call :save "app\models\instruction.py"
|
|
call :save "app\models\instruction_fetch.py"
|
|
call :save "app\models\site_setting.py"
|
|
call :save "app\routes\__init__.py"
|
|
call :save "app\routes\instruction_fetch.py"
|
|
call :save "app\routes\logs.py"
|
|
call :save "app\services\brickset_api.py"
|
|
call :save "app\services\fetch_worker.py"
|
|
call :save "app\services\instruction_fetcher.py"
|
|
call :save "app\services\logging_setup.py"
|
|
call :save "app\services\ownership.py"
|
|
call :save "app\services\schema_upgrade.py"
|
|
call :save "app\templates\admin\brickset_calls.html"
|
|
call :save "app\templates\admin\dashboard.html"
|
|
call :save "app\templates\admin\instruction_fetch.html"
|
|
call :save "app\templates\admin\logs.html"
|
|
call :save "app\templates\admin\settings.html"
|
|
call :save "diagnose_fetcher.py"
|
|
call :save "docker-compose.yml"
|
|
call :save "docker\entrypoint.sh"
|
|
call :save "docs\INSTRUCTION_FETCHER.md"
|
|
call :save "docs\LOGGING.md"
|
|
echo %SAVED% file^(s^) backed up.
|
|
|
|
REM --- install -------------------------------------------------------------------
|
|
echo.
|
|
echo Installing...
|
|
call :put ".env.docker.example"
|
|
call :put ".env.example"
|
|
call :put "README.md"
|
|
call :put "app\__init__.py"
|
|
call :put "app\cli.py"
|
|
call :put "app\config.py"
|
|
call :put "app\models\__init__.py"
|
|
call :put "app\models\api_call.py"
|
|
call :put "app\models\instruction.py"
|
|
call :put "app\models\instruction_fetch.py"
|
|
call :put "app\models\site_setting.py"
|
|
call :put "app\routes\__init__.py"
|
|
call :put "app\routes\instruction_fetch.py"
|
|
call :put "app\routes\logs.py"
|
|
call :put "app\services\brickset_api.py"
|
|
call :put "app\services\fetch_worker.py"
|
|
call :put "app\services\instruction_fetcher.py"
|
|
call :put "app\services\logging_setup.py"
|
|
call :put "app\services\ownership.py"
|
|
call :put "app\services\schema_upgrade.py"
|
|
call :put "app\templates\admin\brickset_calls.html"
|
|
call :put "app\templates\admin\dashboard.html"
|
|
call :put "app\templates\admin\instruction_fetch.html"
|
|
call :put "app\templates\admin\logs.html"
|
|
call :put "app\templates\admin\settings.html"
|
|
call :put "diagnose_fetcher.py"
|
|
call :put "docker-compose.yml"
|
|
call :put "docker\entrypoint.sh"
|
|
call :put "docs\INSTRUCTION_FETCHER.md"
|
|
call :put "docs\LOGGING.md"
|
|
if not "%COPYFAIL%"=="0" goto :copyfailed
|
|
|
|
echo.
|
|
echo ==========================================================
|
|
echo Done - 30 files installed.
|
|
echo.
|
|
echo No migration step: the new table and columns are created
|
|
echo the next time LIM starts.
|
|
echo.
|
|
echo 1. Restart LIM (start_lim.bat)
|
|
echo 2. Admin ^> Instruction Fetcher
|
|
echo 3. Queue sets, then switch the fetcher on
|
|
echo.
|
|
echo To push the same change to Gitea, run push_fetcher_update.bat
|
|
echo FROM THIS FOLDER (not from %TARGET%).
|
|
echo.
|
|
echo Rollback: copy the files in
|
|
echo !BACKUP!
|
|
echo back over %TARGET%
|
|
echo ==========================================================
|
|
echo.
|
|
pause
|
|
exit /b 0
|
|
|
|
REM --- exits ---------------------------------------------------------------------
|
|
|
|
:samedir
|
|
echo ERROR: the source and target are the same folder.
|
|
echo.
|
|
echo You are running this script from inside your LIM install, so there
|
|
echo is nothing to copy - which is why an earlier run appeared to work
|
|
echo but changed nothing.
|
|
echo.
|
|
echo Open the folder you extracted the update into (the one containing
|
|
echo app\services\instruction_fetcher.py) and run it from there:
|
|
echo.
|
|
echo cd /d C:\path\to\lim-instruction-fetcher
|
|
echo install_instruction_fetcher.bat %TARGET%
|
|
goto :fail
|
|
|
|
:nottarget
|
|
echo ERROR: %TARGET% does not look like a LIM install
|
|
echo ^(no app\__init__.py^).
|
|
echo.
|
|
echo Pass the right path, e.g. install_instruction_fetcher.bat D:\LIM
|
|
goto :fail
|
|
|
|
:incomplete
|
|
echo.
|
|
echo ERROR: %MISSING% file^(s^) missing from
|
|
echo %SRCFULL%
|
|
echo.
|
|
echo This is not the extracted update folder. Look for the one
|
|
echo containing app\services\instruction_fetcher.py.
|
|
goto :fail
|
|
|
|
:copyfailed
|
|
echo.
|
|
echo ERROR: %COPYFAIL% file^(s^) could not be copied. Is LIM still running?
|
|
echo Stop it and run this again; the backup in
|
|
echo !BACKUP!
|
|
echo has the originals.
|
|
goto :fail
|
|
|
|
:need
|
|
if not exist "%SOURCE%%~1" echo MISSING: %~1 & set /a MISSING+=1
|
|
goto :eof
|
|
|
|
:save
|
|
if not exist "%TARGET%\%~1" goto :eof
|
|
for %%F in ("!BACKUP!\%~1") do if not exist "%%~dpF" mkdir "%%~dpF"
|
|
copy /Y "%TARGET%\%~1" "!BACKUP!\%~1" >nul
|
|
if not errorlevel 1 echo saved %~1 & set /a SAVED+=1
|
|
goto :eof
|
|
|
|
:put
|
|
for %%F in ("%TARGET%\%~1") do if not exist "%%~dpF" mkdir "%%~dpF"
|
|
copy /Y "%SOURCE%%~1" "%TARGET%\%~1" >nul
|
|
if errorlevel 1 echo FAILED: %~1 & set /a COPYFAIL+=1
|
|
goto :eof
|
|
|
|
:fail
|
|
echo.
|
|
echo Nothing was changed.
|
|
pause
|
|
exit /b 1
|