Fix wallet manager database compatibility and users table schema migrations

parent 37d57c28
...@@ -8,6 +8,7 @@ include cli.py ...@@ -8,6 +8,7 @@ include cli.py
recursive-include config *.json recursive-include config *.json
recursive-include config *.md recursive-include config *.md
recursive-include aisbf *.py recursive-include aisbf *.py
recursive-include aisbf/payments/wallet *.py
recursive-include templates *.html recursive-include templates *.html
recursive-include templates *.css recursive-include templates *.css
recursive-include templates *.js recursive-include templates *.js
......
...@@ -153,14 +153,22 @@ check_package_upgrade() { ...@@ -153,14 +153,22 @@ check_package_upgrade() {
# Function to create venv if it doesn't exist # Function to create venv if it doesn't exist
ensure_venv() { ensure_venv() {
if [ "$DEBUG" = "true" ]; then
echo "=== DEBUG: ensure_venv called ==="
echo "VENV_DIR: $VENV_DIR"
echo "SHARE_DIR: $SHARE_DIR"
fi
if [ ! -d "$VENV_DIR" ]; then if [ ! -d "$VENV_DIR" ]; then
echo "Creating virtual environment at $VENV_DIR" echo "Creating virtual environment at $VENV_DIR"
# Create venv with --system-site-packages to access system-installed aisbf # Create venv with --system-site-packages to access system-installed aisbf
[ "$DEBUG" = "true" ] && echo "=== DEBUG: Creating venv ==="
python3 -m venv --system-site-packages "$VENV_DIR" python3 -m venv --system-site-packages "$VENV_DIR"
# Install requirements if requirements.txt exists # Install requirements if requirements.txt exists
if [ -f "$SHARE_DIR/requirements.txt" ]; then if [ -f "$SHARE_DIR/requirements.txt" ]; then
echo "Installing requirements from $SHARE_DIR/requirements.txt" echo "Installing requirements from $SHARE_DIR/requirements.txt"
[ "$DEBUG" = "true" ] && echo "=== DEBUG: Installing requirements ==="
if ! "$VENV_DIR/bin/pip" install -r "$SHARE_DIR/requirements.txt"; then if ! "$VENV_DIR/bin/pip" install -r "$SHARE_DIR/requirements.txt"; then
echo "" echo ""
echo "==========================================" echo "=========================================="
...@@ -184,18 +192,22 @@ ensure_venv() { ...@@ -184,18 +192,22 @@ ensure_venv() {
echo "" echo ""
exit 1 exit 1
fi fi
[ "$DEBUG" = "true" ] && echo "=== DEBUG: Force reinstalling uvicorn ==="
# Force reinstall uvicorn in venv to ensure it's available inside the virtual environment # Force reinstall uvicorn in venv to ensure it's available inside the virtual environment
"$VENV_DIR/bin/pip" install --force-reinstall uvicorn "$VENV_DIR/bin/pip" install --force-reinstall uvicorn
fi fi
# Save version for future upgrade detection # Save version for future upgrade detection
[ "$DEBUG" = "true" ] && echo "=== DEBUG: Saving version info ==="
python3 -c "import aisbf; print(aisbf.__version__)" > "$VENV_DIR/.aisbf_version" 2>/dev/null || echo "unknown" > "$VENV_DIR/.aisbf_version" python3 -c "import aisbf; print(aisbf.__version__)" > "$VENV_DIR/.aisbf_version" 2>/dev/null || echo "unknown" > "$VENV_DIR/.aisbf_version"
else else
[ "$DEBUG" = "true" ] && echo "=== DEBUG: Venv already exists, checking for upgrades ==="
# Check if package was upgraded via pip # Check if package was upgraded via pip
if check_package_upgrade; then if check_package_upgrade; then
echo "Package upgrade detected, updating venv dependencies..." echo "Package upgrade detected, updating venv dependencies..."
# Only update requirements, aisbf is accessed from system site-packages # Only update requirements, aisbf is accessed from system site-packages
if [ -f "$SHARE_DIR/requirements.txt" ]; then if [ -f "$SHARE_DIR/requirements.txt" ]; then
[ "$DEBUG" = "true" ] && echo "=== DEBUG: Updating requirements ==="
if ! "$VENV_DIR/bin/pip" install -r "$SHARE_DIR/requirements.txt"; then if ! "$VENV_DIR/bin/pip" install -r "$SHARE_DIR/requirements.txt"; then
echo "" echo ""
echo "==========================================" echo "=========================================="
...@@ -207,13 +219,17 @@ ensure_venv() { ...@@ -207,13 +219,17 @@ ensure_venv() {
echo "" echo ""
exit 1 exit 1
fi fi
[ "$DEBUG" = "true" ] && echo "=== DEBUG: Force reinstalling uvicorn ==="
# Force reinstall uvicorn in venv to ensure it's available inside the virtual environment # Force reinstall uvicorn in venv to ensure it's available inside the virtual environment
"$VENV_DIR/bin/pip" install --force-reinstall uvicorn "$VENV_DIR/bin/pip" install --force-reinstall uvicorn
fi fi
python3 -c "import aisbf; print(aisbf.__version__)" > "$VENV_DIR/.aisbf_version" 2>/dev/null || echo "unknown" > "$VENV_DIR/.aisbf_version" python3 -c "import aisbf; print(aisbf.__version__)" > "$VENV_DIR/.aisbf_version" 2>/dev/null || echo "unknown" > "$VENV_DIR/.aisbf_version"
echo "Virtual environment updated successfully" echo "Virtual environment updated successfully"
else
[ "$DEBUG" = "true" ] && echo "=== DEBUG: No package upgrade detected ==="
fi fi
fi fi
[ "$DEBUG" = "true" ] && echo "=== DEBUG: ensure_venv completed ==="
} }
# Function to update venv packages (only install missing ones, no forced upgrades) # Function to update venv packages (only install missing ones, no forced upgrades)
...@@ -255,29 +271,65 @@ update_venv() { ...@@ -255,29 +271,65 @@ update_venv() {
# Function to start the server # Function to start the server
start_server() { start_server() {
echo "=== DEBUG: Starting start_server function ==="
echo "SHARE_DIR: $SHARE_DIR"
echo "VENV_DIR: $VENV_DIR"
echo "LOG_DIR: $LOG_DIR"
# Ensure venv exists # Ensure venv exists
echo "=== DEBUG: Ensuring venv exists ==="
ensure_venv ensure_venv
echo "=== DEBUG: Venv check complete ==="
# Get host and port from config # Get host and port from config
echo "=== DEBUG: Getting host and port ==="
HOST=$(get_host) HOST=$(get_host)
PORT=$(get_port) PORT=$(get_port)
echo "=== DEBUG: Host=$HOST, Port=$PORT ==="
# Activate the virtual environment # Activate the virtual environment
echo "=== DEBUG: Activating virtual environment ==="
source $VENV_DIR/bin/activate source $VENV_DIR/bin/activate
echo "=== DEBUG: Virtual environment activated ==="
# Check Python path and imports
echo "=== DEBUG: Checking Python environment ==="
echo "Python executable: $(which python3)"
python3 -c "import sys; print('Python version:', sys.version); print('Python path:', sys.path[:3])"
echo "=== DEBUG: Testing basic imports ==="
python3 -c "import uvicorn; print('uvicorn imported successfully')" 2>&1 || echo "ERROR: Failed to import uvicorn"
python3 -c "import fastapi; print('fastapi imported successfully')" 2>&1 || echo "ERROR: Failed to import fastapi"
# Change to share directory where main.py is located # Change to share directory where main.py is located
echo "=== DEBUG: Changing to share directory ==="
cd $SHARE_DIR cd $SHARE_DIR
echo "=== DEBUG: Current directory: $(pwd) ==="
ls -la main.py 2>/dev/null || echo "WARNING: main.py not found in $SHARE_DIR"
echo "Starting AISBF on $HOST:$PORT..." echo "Starting AISBF on $HOST:$PORT..."
# Check if debug mode is enabled # Check if debug mode is enabled
if [ "$DEBUG" = "true" ]; then if [ "$DEBUG" = "true" ]; then
echo "Debug mode enabled - showing all debug messages" echo "Debug mode enabled - showing all debug messages"
export AISBF_DEBUG=true export AISBF_DEBUG=true
fi fi
# Test importing main module before starting uvicorn
echo "=== DEBUG: Testing main module import ==="
python3 -c "
try:
import main
print('main module imported successfully')
except Exception as e:
print(f'ERROR: Failed to import main module: {e}')
import traceback
traceback.print_exc()
exit(1)
" 2>&1
# Start the proxy server - runs in foreground # Start the proxy server - runs in foreground
# Use exec to replace the shell process so signals are properly handled # Use exec to replace the shell process so signals are properly handled
echo "=== DEBUG: Starting uvicorn ==="
if [ "$DEBUG" = "true" ]; then if [ "$DEBUG" = "true" ]; then
exec uvicorn main:app --host $HOST --port $PORT --log-level debug 2>&1 | tee -a "$LOG_DIR/aisbf_stdout.log" exec uvicorn main:app --host $HOST --port $PORT --log-level debug 2>&1 | tee -a "$LOG_DIR/aisbf_stdout.log"
else else
......
This diff is collapsed.
...@@ -155,8 +155,8 @@ ...@@ -155,8 +155,8 @@
} }
}, },
"billing": { "billing": {
"currency": "USD", "currency": "EUR",
"currency_symbol": "$", "currency_symbol": "",
"currency_decimals": 2, "currency_decimals": 2,
"payment_methods": { "payment_methods": {
"paypal": { "paypal": {
......
This diff is collapsed.
...@@ -28,7 +28,7 @@ keywords = [ ...@@ -28,7 +28,7 @@ keywords = [
"broker", "broker",
] ]
classifiers = [ classifiers = [
"Development Status :: 3 - Alpha", "Development Status :: 4 - Beta",
"Intended Audience :: Developers", "Intended Audience :: Developers",
"Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Libraries :: Python Modules",
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
......
...@@ -58,7 +58,7 @@ setup( ...@@ -58,7 +58,7 @@ setup(
url="https://git.nexlab.net/nexlab/aisbf.git", url="https://git.nexlab.net/nexlab/aisbf.git",
packages=find_packages(), packages=find_packages(),
classifiers=[ classifiers=[
"Development Status :: 3 - Alpha", "Development Status :: 4 - Beta",
"Intended Audience :: Developers", "Intended Audience :: Developers",
"Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Libraries :: Python Modules",
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
...@@ -184,6 +184,12 @@ setup( ...@@ -184,6 +184,12 @@ setup(
'aisbf/payments/notifications/__init__.py', 'aisbf/payments/notifications/__init__.py',
'aisbf/payments/notifications/email.py', 'aisbf/payments/notifications/email.py',
]), ]),
# aisbf.payments.wallet subpackage
('share/aisbf/aisbf/payments/wallet', [
'aisbf/payments/wallet/__init__.py',
'aisbf/payments/wallet/manager.py',
'aisbf/payments/wallet/routes.py',
]),
# Install dashboard templates # Install dashboard templates
('share/aisbf/templates', [ ('share/aisbf/templates', [
'templates/base.html', 'templates/base.html',
...@@ -259,4 +265,4 @@ setup( ...@@ -259,4 +265,4 @@ setup(
cmdclass={ cmdclass={
'install': InstallCommand, 'install': InstallCommand,
}, },
) )
\ No newline at end of file
...@@ -504,6 +504,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. ...@@ -504,6 +504,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
<a href="{{ url_for(request, '/dashboard/analytics') }}" {% if '/analytics' in request.path %}class="active"{% endif %}>Analytics</a> <a href="{{ url_for(request, '/dashboard/analytics') }}" {% if '/analytics' in request.path %}class="active"{% endif %}>Analytics</a>
{% if request.session.user_id %} {% if request.session.user_id %}
<a href="{{ url_for(request, '/dashboard/user/tokens') }}" {% if '/user/tokens' in request.path %}class="active"{% endif %}>API Tokens</a> <a href="{{ url_for(request, '/dashboard/user/tokens') }}" {% if '/user/tokens' in request.path %}class="active"{% endif %}>API Tokens</a>
<a href="{{ url_for(request, '/dashboard/wallet') }}" {% if '/wallet' in request.path %}class="active"{% endif %}>Wallet</a>
{% endif %} {% endif %}
{% if request.session.role == 'admin' %} {% if request.session.role == 'admin' %}
<a href="{{ url_for(request, '/dashboard/users') }}" {% if '/users' in request.path %}class="active"{% endif %}>Users</a> <a href="{{ url_for(request, '/dashboard/users') }}" {% if '/users' in request.path %}class="active"{% endif %}>Users</a>
...@@ -527,6 +528,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. ...@@ -527,6 +528,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
<a href="{{ url_for(request, '/dashboard/user/tokens') }}">API Tokens</a> <a href="{{ url_for(request, '/dashboard/user/tokens') }}">API Tokens</a>
<a href="{{ url_for(request, '/dashboard/cache-settings') }}">Cache Settings</a> <a href="{{ url_for(request, '/dashboard/cache-settings') }}">Cache Settings</a>
<a href="{{ url_for(request, '/dashboard/subscription') }}">Subscription</a> <a href="{{ url_for(request, '/dashboard/subscription') }}">Subscription</a>
<a href="{{ url_for(request, '/dashboard/wallet') }}">Wallet</a>
<a href="{{ url_for(request, '/dashboard/billing') }}">Billing</a> <a href="{{ url_for(request, '/dashboard/billing') }}">Billing</a>
<a href="{{ url_for(request, '/dashboard/change-password') }}">Change Password</a> <a href="{{ url_for(request, '/dashboard/change-password') }}">Change Password</a>
{% endif %} {% endif %}
......
...@@ -6,7 +6,13 @@ ...@@ -6,7 +6,13 @@
<h2 style="margin-bottom: 30px;">Add Payment Method</h2> <h2 style="margin-bottom: 30px;">Add Payment Method</h2>
<div style="background: #16213e; border: 2px solid #4a9eff; border-radius: 8px; padding: 30px; margin-bottom: 20px;"> <div style="background: #16213e; border: 2px solid #4a9eff; border-radius: 8px; padding: 30px; margin-bottom: 20px;">
<p style="color: #a0a0a0; margin-bottom: 30px;">Choose a payment method to add to your account. You can use this for subscription payments and plan upgrades.</p> <p style="color: #a0a0a0; margin-bottom: 10px;">Choose a payment method to add to your account.</p>
<div style="background: #1a1a2e; border-left: 3px solid #4ade80; padding: 15px; margin-bottom: 30px; border-radius: 4px;">
<p style="margin: 0; color: #e0e0e0;">
<i class="fas fa-info-circle me-2 text-success"></i>
<strong>Important:</strong> Only <strong>Credit Card (Stripe)</strong> can be used for automatic subscription renewals. All other payment methods are for wallet top-ups only.
</p>
</div>
<!-- Stripe and PayPal --> <!-- Stripe and PayPal -->
{% if 'stripe' in enabled_gateways or 'paypal' in enabled_gateways %} {% if 'stripe' in enabled_gateways or 'paypal' in enabled_gateways %}
......
...@@ -9,6 +9,16 @@ ...@@ -9,6 +9,16 @@
<i class="fas fa-cog me-2"></i>Payment System Settings <i class="fas fa-cog me-2"></i>Payment System Settings
</h2> </h2>
<!-- Currency Selection Warning -->
<div style="background: #1a1a2e; border-left: 4px solid #f39c12; padding: 15px; margin-bottom: 25px; border-radius: 4px;">
<div style="color: #f39c12; font-weight: bold; margin-bottom: 8px;">
<i class="fas fa-info-circle me-2"></i>Important Note About Currency Selection
</div>
<div style="color: #e0e0e0; font-size: 14px;">
We do not suggest using USD if you are not in the USA. This project does not support the actions of the USA in the international context and we don't support a politic of war and threats to allies.
</div>
</div>
<!-- Encryption Key Configuration --> <!-- Encryption Key Configuration -->
<div style="background: #16213e; border: 2px solid #e74c3c; border-radius: 8px; padding: 20px; margin-bottom: 20px;"> <div style="background: #16213e; border: 2px solid #e74c3c; border-radius: 8px; padding: 20px; margin-bottom: 20px;">
<h3 style="margin: 0 0 20px 0; color: #e74c3c;"> <h3 style="margin: 0 0 20px 0; color: #e74c3c;">
......
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<h2 style="margin-bottom: 30px;">Billing & Payments</h2> <h2 style="margin-bottom: 20px;">Billing & Payments</h2>
<!-- Wallet Balance Banner -->
<div style="background: linear-gradient(135deg, #1a4a2e, #0f3460); border: 2px solid #28a745; border-radius: 8px; padding: 20px; margin-bottom: 20px;">
<div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 15px;">
<div>
<div style="color: #a0a0a0; font-size: 14px; margin-bottom: 5px;">Wallet Balance</div>
<div style="font-size: 32px; font-weight: bold; color: #4ade80;">${{ wallet.balance }}</div>
<div style="color: #a0a0a0; font-size: 13px; margin-top: 5px;">
All subscription renewals and payments are automatically charged from your wallet first.
</div>
</div>
<a href="{{ url_for(request, '/dashboard/wallet') }}" class="btn" style="background: #28a745;">
<i class="fas fa-wallet me-2"></i>Manage Wallet
</a>
</div>
</div>
{% if success %} {% if success %}
<div class="alert alert-success">{{ success }}</div> <div class="alert alert-success">{{ success }}</div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment