Add missing templates and API endpoints.

This commit is contained in:
Jens Luedicke
2025-07-03 09:26:47 +02:00
parent d10f5547a5
commit 387243d516
5 changed files with 2033 additions and 0 deletions

179
app.py
View File

@@ -3313,6 +3313,185 @@ def get_filtered_analytics_data(user, mode, start_date=None, end_date=None, proj
return query.order_by(TimeEntry.arrival_time.desc()).all()
@app.route('/api/companies/<int:company_id>/teams')
@system_admin_required
def api_company_teams(company_id):
"""API: Get teams for a specific company (System Admin only)"""
teams = Team.query.filter_by(company_id=company_id).order_by(Team.name).all()
return jsonify([{
'id': team.id,
'name': team.name,
'description': team.description
} for team in teams])
@app.route('/api/system-admin/stats')
@system_admin_required
def api_system_admin_stats():
"""API: Get real-time system statistics for dashboard"""
from datetime import datetime, timedelta
# Get basic counts
total_companies = Company.query.count()
total_users = User.query.count()
total_teams = Team.query.count()
total_projects = Project.query.count()
total_time_entries = TimeEntry.query.count()
# Active sessions
active_sessions = TimeEntry.query.filter_by(departure_time=None, is_paused=False).count()
paused_sessions = TimeEntry.query.filter_by(is_paused=True).count()
# Recent activity (last 24 hours)
yesterday = datetime.now() - timedelta(days=1)
recent_users = User.query.filter(User.created_at >= yesterday).count()
recent_companies = Company.query.filter(Company.created_at >= yesterday).count()
recent_time_entries = TimeEntry.query.filter(TimeEntry.arrival_time >= yesterday).count()
# System health
orphaned_users = User.query.filter_by(company_id=None).count()
orphaned_time_entries = TimeEntry.query.filter_by(user_id=None).count()
blocked_users = User.query.filter_by(is_blocked=True).count()
unverified_users = User.query.filter_by(is_verified=False).count()
return jsonify({
'totals': {
'companies': total_companies,
'users': total_users,
'teams': total_teams,
'projects': total_projects,
'time_entries': total_time_entries
},
'active': {
'sessions': active_sessions,
'paused_sessions': paused_sessions
},
'recent': {
'users': recent_users,
'companies': recent_companies,
'time_entries': recent_time_entries
},
'health': {
'orphaned_users': orphaned_users,
'orphaned_time_entries': orphaned_time_entries,
'blocked_users': blocked_users,
'unverified_users': unverified_users
}
})
@app.route('/api/system-admin/companies/<int:company_id>/users')
@system_admin_required
def api_company_users(company_id):
"""API: Get users for a specific company (System Admin only)"""
company = Company.query.get_or_404(company_id)
users = User.query.filter_by(company_id=company.id).order_by(User.username).all()
return jsonify({
'company': {
'id': company.id,
'name': company.name,
'is_personal': company.is_personal
},
'users': [{
'id': user.id,
'username': user.username,
'email': user.email,
'role': user.role.value,
'is_blocked': user.is_blocked,
'is_verified': user.is_verified,
'created_at': user.created_at.isoformat(),
'team_id': user.team_id
} for user in users]
})
@app.route('/api/system-admin/users/<int:user_id>/toggle-block', methods=['POST'])
@system_admin_required
def api_toggle_user_block(user_id):
"""API: Toggle user blocked status (System Admin only)"""
user = User.query.get_or_404(user_id)
# Safety check: prevent blocking yourself
if user.id == g.user.id:
return jsonify({'error': 'Cannot block your own account'}), 400
# Safety check: prevent blocking the last system admin
if user.role == Role.SYSTEM_ADMIN and not user.is_blocked:
system_admin_count = User.query.filter_by(role=Role.SYSTEM_ADMIN, is_blocked=False).count()
if system_admin_count <= 1:
return jsonify({'error': 'Cannot block the last system administrator'}), 400
user.is_blocked = not user.is_blocked
db.session.commit()
return jsonify({
'id': user.id,
'username': user.username,
'is_blocked': user.is_blocked,
'message': f'User {"blocked" if user.is_blocked else "unblocked"} successfully'
})
@app.route('/api/system-admin/companies/<int:company_id>/stats')
@system_admin_required
def api_company_stats(company_id):
"""API: Get detailed statistics for a specific company"""
company = Company.query.get_or_404(company_id)
# User counts by role
role_counts = {}
for role in Role:
count = User.query.filter_by(company_id=company.id, role=role).count()
if count > 0:
role_counts[role.value] = count
# Team and project counts
team_count = Team.query.filter_by(company_id=company.id).count()
project_count = Project.query.filter_by(company_id=company.id).count()
active_projects = Project.query.filter_by(company_id=company.id, is_active=True).count()
# Time entries statistics
from datetime import datetime, timedelta
week_ago = datetime.now() - timedelta(days=7)
month_ago = datetime.now() - timedelta(days=30)
weekly_entries = TimeEntry.query.join(User).filter(
User.company_id == company.id,
TimeEntry.arrival_time >= week_ago
).count()
monthly_entries = TimeEntry.query.join(User).filter(
User.company_id == company.id,
TimeEntry.arrival_time >= month_ago
).count()
# Active sessions
active_sessions = TimeEntry.query.join(User).filter(
User.company_id == company.id,
TimeEntry.departure_time == None,
TimeEntry.is_paused == False
).count()
return jsonify({
'company': {
'id': company.id,
'name': company.name,
'is_personal': company.is_personal,
'is_active': company.is_active
},
'users': {
'total': sum(role_counts.values()),
'by_role': role_counts
},
'structure': {
'teams': team_count,
'projects': project_count,
'active_projects': active_projects
},
'activity': {
'weekly_entries': weekly_entries,
'monthly_entries': monthly_entries,
'active_sessions': active_sessions
}
})
@app.route('/api/analytics/export')
@login_required
def analytics_export():