gemini (kostenintensives) app-aufbauen
This commit is contained in:
1 parent
c74bca1e13
commit
8232f4d8f7
11 files changed
+659
-519
No files matched your search
@@ -35,6 +35,9 @@ import uuid
|
||||
# corrected for py3.13 from config import Config, config_map
|
||||
from config import Config, config_map
|
||||
from models import db, Tenant, User, UserRole, Submission, FormConfig, AuditLog, SubmissionStatus
|
||||
from utils.cli import register_cli_commands
|
||||
from utils.middleware import setup_dev_mode_middleware, get_current_user, get_current_tenant
|
||||
from utils.helpers import get_request_context
|
||||
|
||||
|
||||
# Initialize extensions globally (will be bound to app in create_app)
|
||||
@@ -219,259 +222,6 @@ def register_error_handlers(app: Flask) -> None:
|
||||
}, 500
|
||||
|
||||
|
||||
def register_cli_commands(app: Flask) -> None:
|
||||
"""
|
||||
Register custom CLI commands for the application.
|
||||
|
||||
:param app: Flask application instance
|
||||
"""
|
||||
import click
|
||||
from flask.cli import with_appcontext
|
||||
|
||||
@app.cli.command('seed-db')
|
||||
@with_appcontext
|
||||
def seed_db():
|
||||
"""Seed the database with test data for development."""
|
||||
import uuid
|
||||
|
||||
# Check if data already exists
|
||||
if Tenant.query.first():
|
||||
print('Database already contains data. Use --force to overwrite.')
|
||||
return
|
||||
|
||||
# Create dev tenant
|
||||
tenant = Tenant(
|
||||
id='tenant_dev_123',
|
||||
name='Development Tenant',
|
||||
public_key='dev-public-key-12345',
|
||||
allowed_origins='http://localhost:5000,http://localhost:8080',
|
||||
status=TenantStatus.ACTIVE
|
||||
)
|
||||
db.session.add(tenant)
|
||||
|
||||
# Create sample form
|
||||
sample_form = FormConfig(
|
||||
id='form_sample_001',
|
||||
tenant_id='tenant_dev_123',
|
||||
name='Contact Form',
|
||||
description='Sample contact form for testing',
|
||||
form_structure={
|
||||
'version': '1.0',
|
||||
'fields': [
|
||||
{
|
||||
'name': 'name',
|
||||
'type': 'text',
|
||||
'label': 'Your Name',
|
||||
'required': True,
|
||||
'validation': {'min_length': 2, 'max_length': 100}
|
||||
},
|
||||
{
|
||||
'name': 'email',
|
||||
'type': 'email',
|
||||
'label': 'Email Address',
|
||||
'required': True,
|
||||
'validation': {'pattern': r'^[^@]+@[^@]+\.[^@]+$'}
|
||||
},
|
||||
{
|
||||
'name': 'subject',
|
||||
'type': 'text',
|
||||
'label': 'Subject',
|
||||
'required': True
|
||||
},
|
||||
{
|
||||
'name': 'message',
|
||||
'type': 'textarea',
|
||||
'label': 'Message',
|
||||
'required': True,
|
||||
'validation': {'min_length': 10}
|
||||
}
|
||||
],
|
||||
'submit_button': {
|
||||
'text': 'Send Message',
|
||||
'style': 'primary'
|
||||
}
|
||||
},
|
||||
settings={
|
||||
'email_notification': {
|
||||
'enabled': False,
|
||||
'recipients': ['admin@formeleon.local']
|
||||
},
|
||||
'success_message': 'Thank you for your message!',
|
||||
'recaptcha_enabled': True
|
||||
}
|
||||
)
|
||||
db.session.add(sample_form)
|
||||
|
||||
# Create dev admin user
|
||||
admin_user = User(
|
||||
id='user_dev_admin_001',
|
||||
email=app.config.get('DEV_USER_EMAIL', 'dev@formeleon.local'),
|
||||
name=app.config.get('DEV_USER_NAME', 'Dev Admin'),
|
||||
role=UserRole.ADMIN,
|
||||
sub='dev-admin-sub-123'
|
||||
)
|
||||
db.session.add(admin_user)
|
||||
|
||||
# Associate user with tenant
|
||||
from models import user_tenant_association
|
||||
db.session.execute(
|
||||
user_tenant_association.insert().values(
|
||||
user_id=admin_user.id,
|
||||
tenant_id=tenant.id
|
||||
)
|
||||
)
|
||||
|
||||
db.session.commit()
|
||||
print(f'Seeded database with tenant {tenant.id}, form {sample_form.id}, and user {admin_user.id}')
|
||||
|
||||
@app.cli.command('create-tenant')
|
||||
@click.argument('name')
|
||||
@click.argument('public_key')
|
||||
@click.option('--allowed-origins', default='*', help='Comma-separated allowed origins')
|
||||
@with_appcontext
|
||||
def create_tenant(name, public_key, allowed_origins):
|
||||
"""Create a new tenant."""
|
||||
tenant_id = f'tenant_{name.lower().replace(" ", "_")}_{str(uuid.uuid4())[:8]}'
|
||||
tenant = Tenant(
|
||||
id=tenant_id,
|
||||
name=name,
|
||||
public_key=public_key,
|
||||
allowed_origins=allowed_origins
|
||||
)
|
||||
db.session.add(tenant)
|
||||
db.session.commit()
|
||||
print(f'Created tenant {tenant_id} with public key {public_key}')
|
||||
|
||||
@app.cli.command('create-user')
|
||||
@click.argument('email')
|
||||
@click.argument('name')
|
||||
@click.option('--role', default='user', help='User role: admin, tenant_admin, user, viewer')
|
||||
@with_appcontext
|
||||
def create_user(email, name, role):
|
||||
"""Create a new user."""
|
||||
from models import UserRole as UR
|
||||
role_enum = getattr(UR, role.upper(), UR.USER)
|
||||
user_id = f'user_{email.split("@")[0]}_{str(uuid.uuid4())[:8]}'
|
||||
user = User(
|
||||
id=user_id,
|
||||
email=email,
|
||||
name=name,
|
||||
role=role_enum
|
||||
)
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
print(f'Created user {user_id} with email {email} and role {role}')
|
||||
|
||||
|
||||
def setup_dev_mode_middleware(app: Flask) -> None:
|
||||
"""
|
||||
Set up development mode middleware for fake authentication.
|
||||
|
||||
This middleware injects a fake Zitadel user session when DEV_MODE is enabled,
|
||||
bypassing the need for actual OIDC authentication during development.
|
||||
|
||||
:param app: Flask application instance
|
||||
"""
|
||||
from functools import wraps
|
||||
|
||||
@app.before_request
|
||||
def inject_dev_user():
|
||||
"""Inject dev user into session if DEV_MODE is enabled."""
|
||||
# Skip for static files, auth routes, and API routes
|
||||
if (request.path.startswith('/static/') or
|
||||
request.path.startswith('/auth/') or
|
||||
request.path.startswith('/api/')):
|
||||
return
|
||||
|
||||
# Skip if user is already authenticated
|
||||
if 'user_id' in session:
|
||||
return
|
||||
|
||||
# Inject dev user
|
||||
dev_user = {
|
||||
'id': 'user_dev_admin_001',
|
||||
'email': app.config.get('DEV_USER_EMAIL', 'dev@formeleon.local'),
|
||||
'name': app.config.get('DEV_USER_NAME', 'Dev Admin'),
|
||||
'role': app.config.get('DEV_USER_ROLE', 'admin'),
|
||||
'sub': 'dev-admin-sub-123',
|
||||
'tenant_id': app.config.get('DEV_TENANT_ID', 'tenant_dev_123'),
|
||||
'dev_mode': True
|
||||
}
|
||||
session['user_id'] = dev_user['id']
|
||||
session['user'] = dev_user
|
||||
session.permanent = True
|
||||
|
||||
# Load or create dev user in database
|
||||
from models import User, UserRole, Tenant
|
||||
user = User.query.get(dev_user['id'])
|
||||
if not user:
|
||||
role = UserRole.ADMIN if dev_user['role'] == 'admin' else UserRole.USER
|
||||
user = User(
|
||||
id=dev_user['id'],
|
||||
email=dev_user['email'],
|
||||
name=dev_user['name'],
|
||||
role=role,
|
||||
sub=dev_user['sub']
|
||||
)
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
|
||||
# Ensure dev tenant exists
|
||||
tenant = Tenant.query.get(dev_user['tenant_id'])
|
||||
if not tenant:
|
||||
tenant = Tenant(
|
||||
id=dev_user['tenant_id'],
|
||||
name='Development Tenant',
|
||||
public_key='dev-public-key-12345',
|
||||
allowed_origins='*'
|
||||
)
|
||||
db.session.add(tenant)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def get_current_user() -> Optional[User]:
|
||||
"""
|
||||
Get the current authenticated user from the request context.
|
||||
|
||||
:return: User object if authenticated, None otherwise
|
||||
"""
|
||||
from flask import session
|
||||
if 'user_id' not in session:
|
||||
return None
|
||||
return User.query.get(session['user_id'])
|
||||
|
||||
|
||||
def get_current_tenant() -> Optional[Tenant]:
|
||||
"""
|
||||
Get the current tenant from the request context.
|
||||
|
||||
:return: Tenant object if available, None otherwise
|
||||
"""
|
||||
from flask import session
|
||||
if 'tenant_id' in session:
|
||||
return Tenant.query.get(session['tenant_id'])
|
||||
|
||||
user = get_current_user()
|
||||
if user and user.tenants:
|
||||
return user.tenants[0]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def get_request_context() -> dict:
|
||||
"""
|
||||
Get standardized request context for audit logging.
|
||||
|
||||
:return: Dictionary with request context information
|
||||
"""
|
||||
return {
|
||||
'ip_address': request.remote_addr,
|
||||
'user_agent': request.user_agent.string if request.user_agent else None,
|
||||
'path': request.path,
|
||||
'method': request.method
|
||||
}
|
||||
|
||||
|
||||
# Create application instance
|
||||
app = create_app()
|
||||
|
||||
|
||||
Reference in new issue
Block a user