fix requirements

This commit is contained in:
Dwindi Ramadhana
2026-03-22 07:32:58 +07:00
parent e20efeb6b1
commit 436bcf93be
3 changed files with 261 additions and 32 deletions

View File

@@ -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**

View File

@@ -132,20 +132,20 @@ class TryoutResource(Model):
Field( Field(
name="scoring_mode", name="scoring_mode",
label="Scoring Mode", label="Scoring Mode",
input_=inputs.Select(options=["ctt", "irt", "hybrid"], default="ctt"), input_=inputs.Select(default="ctt"),
display=displays.Select(choices=["ctt", "irt", "hybrid"]), display=displays.Display(),
), ),
Field( Field(
name="selection_mode", name="selection_mode",
label="Selection Mode", label="Selection Mode",
input_=inputs.Select(options=["fixed", "adaptive", "hybrid"], default="fixed"), input_=inputs.Select(default="fixed"),
display=displays.Select(choices=["fixed", "adaptive", "hybrid"]), display=displays.Display(),
), ),
Field( Field(
name="normalization_mode", name="normalization_mode",
label="Normalization Mode", label="Normalization Mode",
input_=inputs.Select(options=["static", "dynamic", "hybrid"], default="static"), input_=inputs.Select(default="static"),
display=displays.Select(choices=["static", "dynamic", "hybrid"]), display=displays.Display(),
), ),
Field( Field(
name="min_sample_for_dynamic", name="min_sample_for_dynamic",
@@ -186,8 +186,8 @@ class TryoutResource(Model):
Field( Field(
name="theta_estimation_method", name="theta_estimation_method",
label="Theta Estimation Method", label="Theta Estimation Method",
input_=inputs.Select(options=["mle", "map", "eap"], default="mle"), input_=inputs.Select(default="mle"),
display=displays.Select(choices=["mle", "map", "eap"]), display=displays.Display(),
), ),
Field( Field(
name="fallback_to_ctt_on_error", name="fallback_to_ctt_on_error",
@@ -195,8 +195,8 @@ class TryoutResource(Model):
input_=inputs.Switch(), input_=inputs.Switch(),
display=displays.Boolean(true_text="Yes", false_text="No"), display=displays.Boolean(true_text="Yes", false_text="No"),
), ),
Field(name="created_at", label="Created 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.DateTime()), Field(name="updated_at", label="Updated At", input_=inputs.DateTime(), display=displays.DatetimeDisplay()),
] ]
@@ -220,14 +220,14 @@ class ItemResource(Model):
Field( Field(
name="level", name="level",
label="Difficulty Level", label="Difficulty Level",
input_=inputs.Select(options=["mudah", "sedang", "sulit"], default="sedang"), input_=inputs.Select(default="sedang"),
display=displays.Display(), display=displays.Display(),
), ),
Field( Field(
name="stem", name="stem",
label="Question Stem", label="Question Stem",
input_=inputs.TextArea(), input_=inputs.TextArea(),
display=displays.Text(maxlen=100), display=displays.Display(),
), ),
Field(name="options", label="Options", input_=inputs.Json(), display=displays.Json()), Field(name="options", label="Options", input_=inputs.Json(), display=displays.Json()),
Field(name="correct_answer", label="Correct Answer", input_=inputs.Input(), display=displays.Display()), Field(name="correct_answer", label="Correct Answer", input_=inputs.Input(), display=displays.Display()),
@@ -235,7 +235,7 @@ class ItemResource(Model):
name="explanation", name="explanation",
label="Explanation", label="Explanation",
input_=inputs.TextArea(), input_=inputs.TextArea(),
display=displays.Text(maxlen=100), display=displays.Display(),
), ),
Field( Field(
name="ctt_p", name="ctt_p",
@@ -252,7 +252,7 @@ class ItemResource(Model):
Field( Field(
name="ctt_category", name="ctt_category",
label="CTT Category", label="CTT Category",
input_=inputs.Select(options=["mudah", "sedang", "sulit"]), input_=inputs.Select(),
display=displays.Display(), display=displays.Display(),
), ),
Field( Field(
@@ -282,7 +282,7 @@ class ItemResource(Model):
Field( Field(
name="generated_by", name="generated_by",
label="Generated By", label="Generated By",
input_=inputs.Select(options=["manual", "ai"], default="manual"), input_=inputs.Select(default="manual"),
display=displays.Display(), display=displays.Display(),
), ),
Field(name="ai_model", label="AI Model", input_=inputs.Input(), 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"), input_=inputs.Input(type="number"),
display=displays.Display(), display=displays.Display(),
), ),
Field(name="created_at", label="Created 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.DateTime()), 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="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="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="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="created_at", label="Created At", input_=inputs.DateTime(), display=displays.DatetimeDisplay()),
Field(name="updated_at", label="Updated At", input_=inputs.DateTime(), display=displays.DateTime()), 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="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="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="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="start_time", label="Start Time", input_=inputs.DateTime(), display=displays.DatetimeDisplay()),
Field(name="end_time", label="End Time", input_=inputs.DateTime(), display=displays.DateTime()), Field(name="end_time", label="End Time", input_=inputs.DateTime(), display=displays.DatetimeDisplay()),
Field( Field(
name="is_completed", name="is_completed",
label="Completed", label="Completed",
@@ -347,7 +347,7 @@ class SessionResource(Model):
Field( Field(
name="scoring_mode_used", name="scoring_mode_used",
label="Scoring Mode Used", label="Scoring Mode Used",
input_=inputs.Select(options=["ctt", "irt", "hybrid"]), input_=inputs.Select(),
display=displays.Display(), display=displays.Display(),
), ),
Field(name="total_benar", label="Total Benar", input_=inputs.Input(type="number"), 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="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="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="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="created_at", label="Created At", input_=inputs.DateTime(), display=displays.DatetimeDisplay()),
Field(name="updated_at", label="Updated At", input_=inputs.DateTime(), display=displays.DateTime()), Field(name="updated_at", label="Updated At", input_=inputs.DateTime(), display=displays.DatetimeDisplay()),
] ]
@@ -405,10 +405,10 @@ class TryoutStatsResource(Model):
name="last_calculated", name="last_calculated",
label="Last Calculated", label="Last Calculated",
input_=inputs.DateTime(), input_=inputs.DateTime(),
display=displays.DateTime(), display=displays.DatetimeDisplay(),
), ),
Field(name="created_at", label="Created 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.DateTime()), 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 FastAPI app with admin panel
""" """
# Configure admin app # Configure admin app
admin_app.settings.logo_url = "/static/logo.png" # admin_app.settings.logo_url = "/static/logo.png"
admin_app.settings.site_title = "IRT Bank Soal Admin" # admin_app.settings.site_title = "IRT Bank Soal Admin"
admin_app.settings.site_description = "Admin Panel for Adaptive Question Bank System" # admin_app.settings.site_description = "Admin Panel for Adaptive Question Bank System"
# Register authentication provider # Register authentication provider
admin_app.settings.auth_provider = AdminAuthProvider() # admin_app.settings.auth_provider = AdminAuthProvider()
# Register model resources # Register model resources
admin_app.register(TryoutResource) admin_app.register(TryoutResource)

View File

@@ -34,7 +34,7 @@ pytest-asyncio>=0.21.1
httpx>=0.26.0 httpx>=0.26.0
# Admin Panel # Admin Panel
fastapi-admin>=1.4.0 fastapi-admin>=1.0.0
# Utilities # Utilities
python-dotenv>=1.0.0 python-dotenv>=1.0.0