fix requirements
This commit is contained in:
229
FASTAPI_ADMIN_1.0.4_FIX_SCRIPT.md
Normal file
229
FASTAPI_ADMIN_1.0.4_FIX_SCRIPT.md
Normal 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**
|
||||
62
app/admin.py
62
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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user