Initial commit – AufmaßCreater v2.35
This commit is contained in:
@@ -0,0 +1,376 @@
|
||||
from flask import Blueprint, render_template, request, flash, redirect, url_for, jsonify, current_app
|
||||
from flask_login import login_required, current_user
|
||||
from app.extensions import db
|
||||
from app.models.company import Company
|
||||
from app.models.user import User
|
||||
from app.models.project import Project
|
||||
from app.models.contract import Contract
|
||||
from app.models.module import Module
|
||||
from app.models.company_module import CompanyModule
|
||||
from app.models.user_module import UserModulePermission
|
||||
from app.models.project_access import ProjectAccess
|
||||
from app.models.license import License, LicenseModule
|
||||
from app.models.aufmass import Aufmass
|
||||
from app.models.position import Position
|
||||
from app.models.settings import Settings
|
||||
|
||||
superadmin_bp = Blueprint('superadmin', __name__)
|
||||
|
||||
def _require_superadmin():
|
||||
if not current_user.is_superadmin():
|
||||
flash('Nur für Superadmins.', 'danger')
|
||||
return False
|
||||
return True
|
||||
|
||||
@superadmin_bp.route('/')
|
||||
@login_required
|
||||
def dashboard():
|
||||
if not _require_superadmin():
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
firmsen = Company.query.order_by(Company.name).all()
|
||||
gesamt_user = User.query.count()
|
||||
gesamt_projekte = Project.query.count()
|
||||
|
||||
all_licenses = License.query.all()
|
||||
gesamt_lizenzen = len(all_licenses)
|
||||
gesamt_max_mitarbeiter = sum((l.max_mitarbeiter or 0) for l in all_licenses if not l.unlimited_users)
|
||||
# Unlimited companies count as "max" being their actual user count
|
||||
for l in all_licenses:
|
||||
if l.unlimited_users:
|
||||
gesamt_max_mitarbeiter += l.used_users
|
||||
gesamt_max_module_slots = sum((l.max_module_slots or 0) for l in all_licenses if not l.unlimited_modules)
|
||||
for l in all_licenses:
|
||||
if l.unlimited_modules:
|
||||
gesamt_max_module_slots += l.used_module_slots
|
||||
gesamt_module_anzahl = Module.query.count()
|
||||
belegte_module_slots = db.session.query(UserModulePermission.id)\
|
||||
.filter(UserModulePermission.aktiv==True).count()
|
||||
|
||||
for f in firmsen:
|
||||
f._user_count = User.query.filter_by(company_id=f.id).count()
|
||||
lic = License.query.filter_by(company_id=f.id, aktiv=True).first()
|
||||
if lic:
|
||||
f._license_slots = '\u221e' if lic.unlimited_users else f'{f._user_count} / {lic.max_mitarbeiter}'
|
||||
f._module_slots = '\u221e' if lic.unlimited_modules else f'{lic.used_module_slots} / {lic.max_module_slots}'
|
||||
f._licensed_modules = LicenseModule.query.filter_by(license_id=lic.id, aktiv=True).count()
|
||||
else:
|
||||
f._license_slots = '–'
|
||||
f._module_slots = '–'
|
||||
f._licensed_modules = 0
|
||||
|
||||
reg_enabled = Settings.get('registration_enabled', 'false') == 'true'
|
||||
return render_template('superadmin/dashboard.html', titel='Superadmin',
|
||||
firmsen=firmsen, gesamt_user=gesamt_user,
|
||||
gesamt_projekte=gesamt_projekte,
|
||||
gesamt_lizenzen=gesamt_lizenzen,
|
||||
gesamt_max_mitarbeiter=gesamt_max_mitarbeiter,
|
||||
gesamt_max_module_slots=gesamt_max_module_slots,
|
||||
gesamt_module_anzahl=gesamt_module_anzahl,
|
||||
belegte_module_slots=belegte_module_slots,
|
||||
registration_enabled=reg_enabled)
|
||||
|
||||
@superadmin_bp.route('/firma/neu', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def firma_create():
|
||||
if not _require_superadmin():
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
if request.method == 'POST':
|
||||
name = request.form.get('name', '').strip()
|
||||
if not name:
|
||||
flash('Firmenname ist erforderlich.', 'danger')
|
||||
return render_template('superadmin/firma_form.html', titel='Neue Firma', company=None)
|
||||
slug = name.lower().replace(' ', '-').replace('ä','ae').replace('ö','oe').replace('ü','ue')[:100]
|
||||
base_slug = slug
|
||||
counter = 1
|
||||
while Company.query.filter_by(slug=slug).first():
|
||||
slug = f"{base_slug}-{counter}"
|
||||
counter += 1
|
||||
company = Company(
|
||||
name=name, slug=slug,
|
||||
strasse=request.form.get('strasse', '').strip(),
|
||||
house_number=request.form.get('house_number', '').strip(),
|
||||
plz=request.form.get('plz', '').strip(),
|
||||
ort=request.form.get('ort', '').strip(),
|
||||
telefon=request.form.get('telefon', '').strip(),
|
||||
email=request.form.get('email', '').strip(),
|
||||
aktiv=True
|
||||
)
|
||||
db.session.add(company)
|
||||
db.session.flush()
|
||||
|
||||
# Optional: Firmadmin-User direkt anlegen
|
||||
admin_email = request.form.get('admin_email', '').strip()
|
||||
admin_password = request.form.get('admin_password', '').strip()
|
||||
if admin_email and admin_password:
|
||||
if User.query.filter_by(email=admin_email).first():
|
||||
flash('E-Mail existiert bereits. Firma wurde trotzdem angelegt.', 'warning')
|
||||
else:
|
||||
user = User(
|
||||
company_id=company.id, email=admin_email,
|
||||
vorname=request.form.get('admin_vorname', '').strip(),
|
||||
nachname=request.form.get('admin_nachname', '').strip(),
|
||||
rolle='firmadmin',
|
||||
darf_projekte_anlegen=True, darf_lv_verwalten=True,
|
||||
darf_preise_sehen=True, darf_aufmass_verwalten=True,
|
||||
)
|
||||
user.set_password(admin_password)
|
||||
db.session.add(user)
|
||||
|
||||
db.session.commit()
|
||||
flash(f'Firma "{name}" angelegt.', 'success')
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=company.id))
|
||||
return render_template('superadmin/firma_form.html', titel='Neue Firma', company=None)
|
||||
|
||||
@superadmin_bp.route('/firma/<int:company_id>/edit', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def firma_edit(company_id):
|
||||
if not _require_superadmin():
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
company = Company.query.get_or_404(company_id)
|
||||
if request.method == 'POST':
|
||||
company.name = request.form.get('name', company.name).strip()
|
||||
company.strasse = request.form.get('strasse', '').strip()
|
||||
company.house_number = request.form.get('house_number', '').strip()
|
||||
company.plz = request.form.get('plz', '').strip()
|
||||
company.ort = request.form.get('ort', '').strip()
|
||||
company.telefon = request.form.get('telefon', '').strip()
|
||||
company.email = request.form.get('email', '').strip()
|
||||
db.session.commit()
|
||||
flash('Firmendaten aktualisiert.', 'success')
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=company.id))
|
||||
return render_template('superadmin/firma_form.html', titel=f'Firma bearbeiten: {company.name}', company=company)
|
||||
|
||||
@superadmin_bp.route('/firma/<int:company_id>/user/neu', methods=['POST'])
|
||||
@login_required
|
||||
def firma_user_create(company_id):
|
||||
if not _require_superadmin():
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
company = Company.query.get_or_404(company_id)
|
||||
email = request.form.get('email', '').strip()
|
||||
if not email:
|
||||
flash('E-Mail ist erforderlich.', 'danger')
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=company.id))
|
||||
if User.query.filter_by(email=email).first():
|
||||
flash('E-Mail existiert bereits.', 'danger')
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=company.id))
|
||||
password = request.form.get('password', '').strip()
|
||||
if not password:
|
||||
flash('Passwort ist erforderlich.', 'danger')
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=company.id))
|
||||
rolle = request.form.get('rolle', 'mitarbeiter')
|
||||
if rolle not in ('mitarbeiter', 'firmadmin'):
|
||||
rolle = 'mitarbeiter'
|
||||
user = User(
|
||||
company_id=company.id, email=email,
|
||||
vorname=request.form.get('vorname', '').strip(),
|
||||
nachname=request.form.get('nachname', '').strip(),
|
||||
rolle=rolle,
|
||||
darf_projekte_anlegen=bool(request.form.get('darf_projekte_anlegen')),
|
||||
darf_lv_verwalten=bool(request.form.get('darf_lv_verwalten')),
|
||||
darf_preise_sehen=bool(request.form.get('darf_preise_sehen')),
|
||||
darf_aufmass_verwalten=bool(request.form.get('darf_aufmass_verwalten')),
|
||||
darf_evergabe_nutzen=bool(request.form.get('darf_evergabe_nutzen')),
|
||||
darf_kopfdaten_holen=bool(request.form.get('darf_kopfdaten_holen')),
|
||||
darf_aufmass_uebertragen=bool(request.form.get('darf_aufmass_uebertragen')),
|
||||
)
|
||||
user.set_password(password)
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
flash(f'Benutzer {user.full_name} angelegt.', 'success')
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=company.id))
|
||||
|
||||
@superadmin_bp.route('/firma/<int:company_id>')
|
||||
@login_required
|
||||
def firma_detail(company_id):
|
||||
if not _require_superadmin():
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
company = Company.query.get_or_404(company_id)
|
||||
users = User.query.filter_by(company_id=company.id).order_by(User.email).all()
|
||||
projekte = Project.query.filter_by(company_id=company.id).order_by(Project.erstellt_am.desc()).all()
|
||||
licenses = License.query.filter_by(company_id=company.id).order_by(License.erstellt_am.desc()).all()
|
||||
contracts = Contract.query.filter_by(company_id=company.id).order_by(Contract.name).all()
|
||||
modules = Module.query.order_by(Module.sortierung).all()
|
||||
company_modules = {cm.module_id for cm in CompanyModule.query.filter_by(company_id=company.id, aktiv=True).all()}
|
||||
all_modules = Module.query.order_by(Module.sortierung).all()
|
||||
return render_template('superadmin/firma_detail.html', company=company,
|
||||
users=users, projekte=projekte, licenses=licenses,
|
||||
contracts=contracts, modules=modules,
|
||||
company_modules=company_modules, all_modules=all_modules,
|
||||
titel=f'Firma: {company.name}')
|
||||
|
||||
@superadmin_bp.route('/firma/<int:company_id>/toggle')
|
||||
@login_required
|
||||
def firma_toggle(company_id):
|
||||
if not _require_superadmin():
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
company = Company.query.get_or_404(company_id)
|
||||
company.aktiv = not company.aktiv
|
||||
db.session.commit()
|
||||
flash(f'Firma {"aktiviert" if company.aktiv else "deaktiviert"}.', 'success')
|
||||
return redirect(url_for('superadmin.dashboard'))
|
||||
|
||||
@superadmin_bp.route('/user/<int:user_id>/toggle')
|
||||
@login_required
|
||||
def user_toggle(user_id):
|
||||
if not _require_superadmin():
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
user = User.query.get_or_404(user_id)
|
||||
user.aktiv = not user.aktiv
|
||||
db.session.commit()
|
||||
flash(f'User {"aktiviert" if user.aktiv else "deaktiviert"}.', 'success')
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=user.company_id))
|
||||
|
||||
@superadmin_bp.route('/user/<int:user_id>/make-superadmin')
|
||||
@login_required
|
||||
def user_make_superadmin(user_id):
|
||||
if not _require_superadmin():
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
user = User.query.get_or_404(user_id)
|
||||
if user.is_superadmin():
|
||||
user.rolle = 'firmadmin'
|
||||
else:
|
||||
user.rolle = 'superadmin'
|
||||
db.session.commit()
|
||||
flash(f'User {user.email} ist jetzt {user.rolle}.', 'success')
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=user.company_id))
|
||||
|
||||
@superadmin_bp.route('/user/<int:user_id>/loeschen', methods=['POST'])
|
||||
@login_required
|
||||
def user_loeschen(user_id):
|
||||
if not _require_superadmin():
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
user = User.query.get_or_404(user_id)
|
||||
if user.id == current_user.id:
|
||||
flash('Sie können sich nicht selbst löschen.', 'danger')
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=user.company_id))
|
||||
email = user.email
|
||||
ProjectAccess.query.filter_by(user_id=user.id).delete()
|
||||
UserModulePermission.query.filter_by(user_id=user.id).delete()
|
||||
db.session.delete(user)
|
||||
db.session.commit()
|
||||
flash(f'Benutzer {email} gelöscht.', 'success')
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=user.company_id))
|
||||
|
||||
@superadmin_bp.route('/company/<int:company_id>/module/<int:module_id>/toggle')
|
||||
@login_required
|
||||
def company_module_toggle(company_id, module_id):
|
||||
if not _require_superadmin():
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
cm = CompanyModule.query.filter_by(company_id=company_id, module_id=module_id).first()
|
||||
if cm:
|
||||
cm.aktiv = not cm.aktiv
|
||||
else:
|
||||
cm = CompanyModule(company_id=company_id, module_id=module_id, aktiv=True)
|
||||
db.session.add(cm)
|
||||
db.session.commit()
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=company_id))
|
||||
|
||||
@superadmin_bp.route('/firma/<int:company_id>/license/create', methods=['POST'])
|
||||
@login_required
|
||||
def license_create(company_id):
|
||||
if not _require_superadmin():
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
company = Company.query.get_or_404(company_id)
|
||||
max_mitarbeiter = request.form.get('max_mitarbeiter', type=int) or 5
|
||||
max_module_slots = request.form.get('max_module_slots', type=int) or 5
|
||||
unlimited_users = bool(request.form.get('unlimited_users'))
|
||||
unlimited_modules = bool(request.form.get('unlimited_modules'))
|
||||
uid = License.generate_uid(company.name)
|
||||
lic = License(company_id=company_id, uid=uid,
|
||||
max_mitarbeiter=max_mitarbeiter,
|
||||
max_module_slots=max_module_slots,
|
||||
unlimited_users=unlimited_users,
|
||||
unlimited_modules=unlimited_modules)
|
||||
db.session.add(lic)
|
||||
db.session.flush()
|
||||
# Assign selected modules
|
||||
mod_ids = request.form.getlist('modules')
|
||||
for mid in mod_ids:
|
||||
db.session.add(LicenseModule(license_id=lic.id, module_id=int(mid), aktiv=True))
|
||||
db.session.commit()
|
||||
flash('Lizenz angelegt.', 'success')
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=company_id))
|
||||
|
||||
@superadmin_bp.route('/license/<int:license_id>/edit', methods=['POST'])
|
||||
@login_required
|
||||
def license_edit(license_id):
|
||||
if not _require_superadmin():
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
lic = License.query.get_or_404(license_id)
|
||||
lic.max_mitarbeiter = request.form.get('max_mitarbeiter', type=int) or lic.max_mitarbeiter
|
||||
lic.max_module_slots = request.form.get('max_module_slots', type=int) or lic.max_module_slots
|
||||
lic.unlimited_users = bool(request.form.get('unlimited_users'))
|
||||
lic.unlimited_modules = bool(request.form.get('unlimited_modules'))
|
||||
# Update module assignments
|
||||
new_mod_ids = set(int(x) for x in request.form.getlist('modules'))
|
||||
for lm in lic.modules.filter_by(aktiv=True).all():
|
||||
if lm.module_id not in new_mod_ids:
|
||||
lm.aktiv = False
|
||||
existing_ids = {lm.module_id for lm in lic.modules.filter_by(aktiv=True).all()}
|
||||
for mid in new_mod_ids:
|
||||
if mid not in existing_ids:
|
||||
db.session.add(LicenseModule(license_id=lic.id, module_id=mid, aktiv=True))
|
||||
db.session.commit()
|
||||
flash('Lizenz aktualisiert.', 'success')
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=lic.company_id))
|
||||
|
||||
@superadmin_bp.route('/license/<int:license_id>/delete', methods=['POST'])
|
||||
@login_required
|
||||
def license_delete(license_id):
|
||||
if not _require_superadmin():
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
lic = License.query.get_or_404(license_id)
|
||||
company_id = lic.company_id
|
||||
db.session.delete(lic)
|
||||
db.session.commit()
|
||||
flash('Lizenz gelöscht.', 'success')
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=company_id))
|
||||
|
||||
@superadmin_bp.route('/license/<int:license_id>/module/<int:module_id>/toggle')
|
||||
@login_required
|
||||
def license_module_toggle(license_id, module_id):
|
||||
if not _require_superadmin():
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
lm = LicenseModule.query.filter_by(license_id=license_id, module_id=module_id).first()
|
||||
if lm:
|
||||
lm.aktiv = not lm.aktiv
|
||||
else:
|
||||
lm = LicenseModule(license_id=license_id, module_id=module_id, aktiv=True)
|
||||
db.session.add(lm)
|
||||
db.session.commit()
|
||||
lic = License.query.get(license_id)
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=lic.company_id))
|
||||
|
||||
@superadmin_bp.route('/firma/<int:company_id>/evergabe/toggle')
|
||||
@login_required
|
||||
def firma_evergabe_toggle(company_id):
|
||||
if not _require_superadmin():
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
company = Company.query.get_or_404(company_id)
|
||||
company.evergabe_aktiviert = not company.evergabe_aktiviert
|
||||
db.session.commit()
|
||||
flash(f'E-Vergabe Addon {"freigeschaltet" if company.evergabe_aktiviert else "deaktiviert"}.', 'success')
|
||||
return redirect(url_for('superadmin.firma_detail', company_id=company_id))
|
||||
|
||||
@superadmin_bp.route('/registration/toggle')
|
||||
@login_required
|
||||
def registration_toggle():
|
||||
if not _require_superadmin():
|
||||
if request.headers.get('HX-Request'):
|
||||
return jsonify({'error': 'Zugriff verweigert'}), 403
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
current = Settings.get('registration_enabled', 'false') == 'true'
|
||||
Settings.set('registration_enabled', 'false' if current else 'true')
|
||||
current_app.config['REGISTRATION_ENABLED'] = not current
|
||||
if request.headers.get('HX-Request'):
|
||||
return jsonify({'ok': True, 'registration_enabled': not current})
|
||||
flash(f'Registrierung {"aktiviert" if not current else "deaktiviert"}.', 'success')
|
||||
return redirect(url_for('superadmin.dashboard'))
|
||||
|
||||
@superadmin_bp.route('/registration/status')
|
||||
@login_required
|
||||
def registration_status():
|
||||
if not _require_superadmin():
|
||||
return jsonify({'error': 'Zugriff verweigert'}), 403
|
||||
enabled = Settings.get('registration_enabled', 'false') == 'true'
|
||||
return jsonify({'registration_enabled': enabled})
|
||||
Reference in New Issue
Block a user