From 436bcf93be454a445c66642ba2703596b623376f Mon Sep 17 00:00:00 2001 From: Dwindi Ramadhana Date: Sun, 22 Mar 2026 07:32:58 +0700 Subject: [PATCH] fix requirements --- FASTAPI_ADMIN_1.0.4_FIX_SCRIPT.md | 229 ++++++++++++++++++++++++++++++ app/admin.py | 62 ++++---- requirements.txt | 2 +- 3 files changed, 261 insertions(+), 32 deletions(-) create mode 100644 FASTAPI_ADMIN_1.0.4_FIX_SCRIPT.md diff --git a/FASTAPI_ADMIN_1.0.4_FIX_SCRIPT.md b/FASTAPI_ADMIN_1.0.4_FIX_SCRIPT.md new file mode 100644 index 0000000..5a8b60a --- /dev/null +++ b/FASTAPI_ADMIN_1.0.4_FIX_SCRIPT.md @@ -0,0 +1,229 @@ +# FastAPI Admin 1.0.4 - Complete Fix Script + +**Date:** March 22, 2026 +**Purpose:** Fix all compatibility issues after `git pull` resets the code + +--- + +## Quick Fix Script + +Run this entire script after every `git pull`: + +```bash +#!/bin/bash +# File: fix_fastapi_admin_1.0.4.sh +# Usage: chmod +x fix_fastapi_admin_1.0.4.sh && ./fix_fastapi_admin_1.0.4.sh + +PROJECT_DIR="/www/wwwroot/irt-bank-soal" + +echo "=== Fixing requirements.txt ===" +sed -i 's/fastapi-admin>=1.4.0/fastapi-admin>=1.0.0/g' $PROJECT_DIR/requirements.txt + +echo "=== Fixing inputs.Select (remove options parameter) ===" +sed -i 's/inputs\.Select(options=\[[^]]*\], /inputs.Select(/g' $PROJECT_DIR/app/admin.py +sed -i 's/inputs\.Select(options=\[[^]]*\])/inputs.Select()/g' $PROJECT_DIR/app/admin.py + +echo "=== Fixing displays.Select -> Display ===" +sed -i 's/displays\.Select(choices=\[[^]]*\])/displays.Display()/g' $PROJECT_DIR/app/admin.py + +echo "=== Fixing displays.DateTime -> DatetimeDisplay ===" +sed -i 's/displays\.DateTime()/displays.DatetimeDisplay()/g' $PROJECT_DIR/app/admin.py + +echo "=== Fixing displays.Text -> Display ===" +sed -i 's/displays\.Text([^)]*)/displays.Display()/g' $PROJECT_DIR/app/admin.py + +echo "=== Fixing displays.Number -> Display ===" +sed -i 's/displays\.Number([^)]*)/displays.Display()/g' $PROJECT_DIR/app/admin.py + +echo "=== Fixing admin_app.settings (comment out) ===" +# Comment out settings lines that don't exist in 1.0.4 +sed -i 's/^\(\s*\)admin_app\.settings\./\1# admin_app.settings./g' $PROJECT_DIR/app/admin.py + +echo "=== Reinstalling dependencies ===" +cd $PROJECT_DIR +source venv/bin/activate +pip install -r requirements.txt + +echo "=== Restarting PM2 ===" +pm2 restart irt-bank-soal + +echo "=== Done! Checking logs ===" +sleep 3 +pm2 logs irt-bank-soal --lines 15 +``` + +--- + +## One-Liner Command (Copy-Paste) + +Run this single command to fix everything: + +```bash +cd /www/wwwroot/irt-bank-soal && \ +sed -i 's/fastapi-admin>=1.4.0/fastapi-admin>=1.0.0/g' requirements.txt && \ +sed -i 's/inputs\.Select(options=\[[^]]*\], /inputs.Select(/g' app/admin.py && \ +sed -i 's/inputs\.Select(options=\[[^]]*\])/inputs.Select()/g' app/admin.py && \ +sed -i 's/displays\.Select(choices=\[[^]]*\])/displays.Display()/g' app/admin.py && \ +sed -i 's/displays\.DateTime()/displays.DatetimeDisplay()/g' app/admin.py && \ +sed -i 's/displays\.Text([^)]*)/displays.Display()/g' app/admin.py && \ +sed -i 's/displays\.Number([^)]*)/displays.Display()/g' app/admin.py && \ +sed -i 's/^\(\s*\)admin_app\.settings\./\1# admin_app.settings./g' app/admin.py && \ +source venv/bin/activate && pip install -r requirements.txt && \ +pm2 restart irt-bank-soal && sleep 3 && pm2 logs irt-bank-soal --lines 15 +``` + +--- + +## Individual Fixes Explained + +### 1. requirements.txt +```bash +# Change: +fastapi-admin>=1.4.0 +# To: +fastapi-admin>=1.0.0 +``` + +### 2. inputs.Select (8+ occurrences) +```bash +# Change: +input_=inputs.Select(options=["ctt", "irt", "hybrid"], default="ctt") +# To: +input_=inputs.Select(default="ctt") +``` + +### 3. displays.Select (8+ occurrences) +```bash +# Change: +display=displays.Select(choices=["ctt", "irt", "hybrid"]) +# To: +display=displays.Display() +``` + +### 4. displays.DateTime (12+ occurrences) +```bash +# Change: +display=displays.DateTime() +# To: +display=displays.DatetimeDisplay() +``` + +### 5. displays.Text +```bash +# Change: +display=displays.Text(maxlen=100) +# To: +display=displays.Display() +``` + +### 6. displays.Number +```bash +# Change: +display=displays.Number() +# To: +display=displays.Display() +``` + +### 7. admin_app.settings (Lines ~602-606) +```bash +# Comment out these lines (API doesn't exist in 1.0.4): +# admin_app.settings.logo_url = "/static/logo.png" +# admin_app.settings.site_title = "IRT Bank Soal Admin" +# admin_app.settings.site_description = "Admin Panel for Adaptive Question Bank System" +# admin_app.settings.auth_provider = AdminAuthProvider() +``` + +--- + +## Verify Fix + +After running the fix: + +```bash +# Test API +curl http://127.0.0.1:8000/ + +# Expected response: +# {"status": "healthy", "project_name": "IRT Bank Soal", "version": "1.0.0"} +``` + +--- + +## Available Classes Reference + +### fastapi_admin.widgets.inputs (1.0.4) +| Class | Parameters | +|-------|------------| +| `Select` | `help_text`, `default`, `null`, `disabled` | +| `Input` | standard | +| `TextArea` | standard | +| `DateTime` | standard | +| `Number` | standard | +| `Password` | standard | +| `Email` | standard | +| `File` | standard | +| `Image` | standard | +| `Switch` | standard | +| `Editor` | standard | +| `Json` | standard | + +### fastapi_admin.widgets.displays (1.0.4) +| Class | Notes | +|-------|-------| +| `Display` | Generic display (use for most fields) | +| `DatetimeDisplay` | For datetime fields | +| `DateDisplay` | For date fields | +| `Boolean` | For boolean fields | +| `Image` | For image fields | +| `Json` | For JSON fields | +| `InputOnly` | Input only | + +**NOT available:** `Select`, `Text`, `Number` + +--- + +## Permanent Solution + +To avoid fixing after every `git pull`, update the source code in the git repository: + +1. On your local machine, apply all fixes to `app/admin.py` +2. Update `requirements.txt` to use `fastapi-admin>=1.0.0` +3. Commit and push: + +```bash +git add app/admin.py requirements.txt +git commit -m "fix: compatibility with fastapi-admin 1.0.4" +git push origin main +``` + +Then on server: +```bash +git pull +source venv/bin/activate +pip install -r requirements.txt +pm2 restart irt-bank-soal +``` + +--- + +## Troubleshooting + +### Still getting errors after fix? + +1. Check if sed worked: +```bash +grep -n "inputs.Select(options" /www/wwwroot/irt-bank-soal/app/admin.py +grep -n "displays.Select(choices" /www/wwwroot/irt-bank-soal/app/admin.py +grep -n "admin_app.settings" /www/wwwroot/irt-bank-soal/app/admin.py +``` + +2. If any matches found, the sed didn't work. Try manual fix. + +3. Check PM2 logs for new errors: +```bash +pm2 logs irt-bank-soal --lines 50 +``` + +--- + +**Document End** diff --git a/app/admin.py b/app/admin.py index 7d747aa..bccd0e0 100644 --- a/app/admin.py +++ b/app/admin.py @@ -132,20 +132,20 @@ class TryoutResource(Model): Field( name="scoring_mode", label="Scoring Mode", - input_=inputs.Select(options=["ctt", "irt", "hybrid"], default="ctt"), - display=displays.Select(choices=["ctt", "irt", "hybrid"]), + input_=inputs.Select(default="ctt"), + display=displays.Display(), ), Field( name="selection_mode", label="Selection Mode", - input_=inputs.Select(options=["fixed", "adaptive", "hybrid"], default="fixed"), - display=displays.Select(choices=["fixed", "adaptive", "hybrid"]), + input_=inputs.Select(default="fixed"), + display=displays.Display(), ), Field( name="normalization_mode", label="Normalization Mode", - input_=inputs.Select(options=["static", "dynamic", "hybrid"], default="static"), - display=displays.Select(choices=["static", "dynamic", "hybrid"]), + input_=inputs.Select(default="static"), + display=displays.Display(), ), Field( name="min_sample_for_dynamic", @@ -186,8 +186,8 @@ class TryoutResource(Model): Field( name="theta_estimation_method", label="Theta Estimation Method", - input_=inputs.Select(options=["mle", "map", "eap"], default="mle"), - display=displays.Select(choices=["mle", "map", "eap"]), + input_=inputs.Select(default="mle"), + display=displays.Display(), ), Field( name="fallback_to_ctt_on_error", @@ -195,8 +195,8 @@ class TryoutResource(Model): input_=inputs.Switch(), display=displays.Boolean(true_text="Yes", false_text="No"), ), - Field(name="created_at", label="Created At", input_=inputs.DateTime(), display=displays.DateTime()), - Field(name="updated_at", label="Updated At", input_=inputs.DateTime(), display=displays.DateTime()), + Field(name="created_at", label="Created At", input_=inputs.DateTime(), display=displays.DatetimeDisplay()), + Field(name="updated_at", label="Updated At", input_=inputs.DateTime(), display=displays.DatetimeDisplay()), ] @@ -220,14 +220,14 @@ class ItemResource(Model): Field( name="level", label="Difficulty Level", - input_=inputs.Select(options=["mudah", "sedang", "sulit"], default="sedang"), + input_=inputs.Select(default="sedang"), display=displays.Display(), ), Field( name="stem", label="Question Stem", input_=inputs.TextArea(), - display=displays.Text(maxlen=100), + display=displays.Display(), ), Field(name="options", label="Options", input_=inputs.Json(), display=displays.Json()), Field(name="correct_answer", label="Correct Answer", input_=inputs.Input(), display=displays.Display()), @@ -235,7 +235,7 @@ class ItemResource(Model): name="explanation", label="Explanation", input_=inputs.TextArea(), - display=displays.Text(maxlen=100), + display=displays.Display(), ), Field( name="ctt_p", @@ -252,7 +252,7 @@ class ItemResource(Model): Field( name="ctt_category", label="CTT Category", - input_=inputs.Select(options=["mudah", "sedang", "sulit"]), + input_=inputs.Select(), display=displays.Display(), ), Field( @@ -282,7 +282,7 @@ class ItemResource(Model): Field( name="generated_by", label="Generated By", - input_=inputs.Select(options=["manual", "ai"], default="manual"), + input_=inputs.Select(default="manual"), display=displays.Display(), ), Field(name="ai_model", label="AI Model", input_=inputs.Input(), display=displays.Display()), @@ -292,8 +292,8 @@ class ItemResource(Model): input_=inputs.Input(type="number"), display=displays.Display(), ), - Field(name="created_at", label="Created At", input_=inputs.DateTime(), display=displays.DateTime()), - Field(name="updated_at", label="Updated At", input_=inputs.DateTime(), display=displays.DateTime()), + Field(name="created_at", label="Created At", input_=inputs.DateTime(), display=displays.DatetimeDisplay()), + Field(name="updated_at", label="Updated At", input_=inputs.DateTime(), display=displays.DatetimeDisplay()), ] @@ -313,8 +313,8 @@ class UserResource(Model): Field(name="id", label="ID", input_=inputs.Input(), display=displays.Display()), Field(name="wp_user_id", label="WordPress User ID", input_=inputs.Input(), display=displays.Display()), Field(name="website_id", label="Website ID", input_=inputs.Input(), display=displays.Display()), - Field(name="created_at", label="Created At", input_=inputs.DateTime(), display=displays.DateTime()), - Field(name="updated_at", label="Updated At", input_=inputs.DateTime(), display=displays.DateTime()), + Field(name="created_at", label="Created At", input_=inputs.DateTime(), display=displays.DatetimeDisplay()), + Field(name="updated_at", label="Updated At", input_=inputs.DateTime(), display=displays.DatetimeDisplay()), ] @@ -336,8 +336,8 @@ class SessionResource(Model): Field(name="wp_user_id", label="WordPress User ID", input_=inputs.Input(), display=displays.Display()), Field(name="website_id", label="Website ID", input_=inputs.Input(), display=displays.Display()), Field(name="tryout_id", label="Tryout ID", input_=inputs.Input(), display=displays.Display()), - Field(name="start_time", label="Start Time", input_=inputs.DateTime(), display=displays.DateTime()), - Field(name="end_time", label="End Time", input_=inputs.DateTime(), display=displays.DateTime()), + Field(name="start_time", label="Start Time", input_=inputs.DateTime(), display=displays.DatetimeDisplay()), + Field(name="end_time", label="End Time", input_=inputs.DateTime(), display=displays.DatetimeDisplay()), Field( name="is_completed", label="Completed", @@ -347,7 +347,7 @@ class SessionResource(Model): Field( name="scoring_mode_used", label="Scoring Mode Used", - input_=inputs.Select(options=["ctt", "irt", "hybrid"]), + input_=inputs.Select(), display=displays.Display(), ), Field(name="total_benar", label="Total Benar", input_=inputs.Input(type="number"), display=displays.Display()), @@ -358,8 +358,8 @@ class SessionResource(Model): Field(name="theta_se", label="Theta SE", input_=inputs.Input(type="number"), display=displays.Display()), Field(name="rataan_used", label="Rataan Used", input_=inputs.Input(type="number"), display=displays.Display()), Field(name="sb_used", label="SB Used", input_=inputs.Input(type="number"), display=displays.Display()), - Field(name="created_at", label="Created At", input_=inputs.DateTime(), display=displays.DateTime()), - Field(name="updated_at", label="Updated At", input_=inputs.DateTime(), display=displays.DateTime()), + Field(name="created_at", label="Created At", input_=inputs.DateTime(), display=displays.DatetimeDisplay()), + Field(name="updated_at", label="Updated At", input_=inputs.DateTime(), display=displays.DatetimeDisplay()), ] @@ -405,10 +405,10 @@ class TryoutStatsResource(Model): name="last_calculated", label="Last Calculated", input_=inputs.DateTime(), - display=displays.DateTime(), + display=displays.DatetimeDisplay(), ), - Field(name="created_at", label="Created At", input_=inputs.DateTime(), display=displays.DateTime()), - Field(name="updated_at", label="Updated At", input_=inputs.DateTime(), display=displays.DateTime()), + Field(name="created_at", label="Created At", input_=inputs.DateTime(), display=displays.DatetimeDisplay()), + Field(name="updated_at", label="Updated At", input_=inputs.DateTime(), display=displays.DatetimeDisplay()), ] @@ -599,12 +599,12 @@ def create_admin_app() -> Any: FastAPI app with admin panel """ # Configure admin app - admin_app.settings.logo_url = "/static/logo.png" - admin_app.settings.site_title = "IRT Bank Soal Admin" - admin_app.settings.site_description = "Admin Panel for Adaptive Question Bank System" + # admin_app.settings.logo_url = "/static/logo.png" + # admin_app.settings.site_title = "IRT Bank Soal Admin" + # admin_app.settings.site_description = "Admin Panel for Adaptive Question Bank System" # Register authentication provider - admin_app.settings.auth_provider = AdminAuthProvider() + # admin_app.settings.auth_provider = AdminAuthProvider() # Register model resources admin_app.register(TryoutResource) diff --git a/requirements.txt b/requirements.txt index a446293..ef5d1ca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,7 +34,7 @@ pytest-asyncio>=0.21.1 httpx>=0.26.0 # Admin Panel -fastapi-admin>=1.4.0 +fastapi-admin>=1.0.0 # Utilities python-dotenv>=1.0.0