feat(calendar): add guest API endpoints (POST/PATCH/DELETE)

This commit is contained in:
Maciej Pienczyn 2026-03-31 14:00:23 +02:00
parent afee91e52c
commit 2a9f6fbf1f

View File

@ -12,7 +12,7 @@ from flask import render_template, request, redirect, url_for, flash, jsonify, R
from flask_login import login_required, current_user
from . import bp
from database import SessionLocal, NordaEvent, EventAttendee
from database import SessionLocal, NordaEvent, EventAttendee, EventGuest
# Polish month names
@ -274,6 +274,12 @@ def event(event_id):
EventAttendee.user_id == current_user.id
).first()
# Pobierz gości bieżącego użytkownika na to wydarzenie
user_guests = db.query(EventGuest).filter(
EventGuest.event_id == event_id,
EventGuest.host_user_id == current_user.id
).order_by(EventGuest.created_at.asc()).all()
# Find speaker as user or company
speaker_user_id = None
speaker_company_slug = None
@ -301,6 +307,7 @@ def event(event_id):
return render_template('calendar/event.html',
event=event,
user_attending=user_attending,
user_guests=user_guests,
speaker_user_id=speaker_user_id,
speaker_company_slug=speaker_company_slug,
enriched_description=enriched_description,
@ -344,7 +351,7 @@ def rsvp(event_id):
})
else:
# Skip max_attendees check for external events
if not is_ext and event.max_attendees and event.attendee_count >= event.max_attendees:
if not is_ext and event.max_attendees and event.total_attendee_count >= event.max_attendees:
return jsonify({'success': False, 'error': 'Brak wolnych miejsc'}), 400
attendee = EventAttendee(
@ -364,6 +371,150 @@ def rsvp(event_id):
db.close()
MAX_GUESTS_PER_USER = 5
@bp.route('/<int:event_id>/guests', methods=['POST'], endpoint='calendar_add_guest')
@login_required
def add_guest(event_id):
"""Dodaj osobę towarzyszącą na wydarzenie"""
db = SessionLocal()
try:
event = db.query(NordaEvent).filter(NordaEvent.id == event_id).first()
if not event:
return jsonify({'success': False, 'error': 'Wydarzenie nie istnieje'}), 404
if event.is_past:
return jsonify({'success': False, 'error': 'Wydarzenie już się odbyło'}), 400
if not event.can_user_attend(current_user):
return jsonify({'success': False, 'error': 'Nie masz uprawnień'}), 403
if getattr(event, 'is_external', False):
return jsonify({'success': False, 'error': 'Rejestracja gości niedostępna dla wydarzeń zewnętrznych'}), 400
# Sprawdź limit gości per użytkownik
guest_count = db.query(EventGuest).filter(
EventGuest.event_id == event_id,
EventGuest.host_user_id == current_user.id
).count()
if guest_count >= MAX_GUESTS_PER_USER:
return jsonify({'success': False, 'error': f'Maksymalnie {MAX_GUESTS_PER_USER} gości na wydarzenie'}), 400
# Sprawdź limit miejsc
if event.max_attendees and event.total_attendee_count >= event.max_attendees:
return jsonify({'success': False, 'error': 'Brak wolnych miejsc'}), 400
data = request.get_json() or {}
first_name = (data.get('first_name') or '').strip()
last_name = (data.get('last_name') or '').strip()
organization = (data.get('organization') or '').strip()
# Minimum jedno pole
if not first_name and not last_name and not organization:
return jsonify({'success': False, 'error': 'Podaj przynajmniej imię, nazwisko lub firmę'}), 400
guest = EventGuest(
event_id=event_id,
host_user_id=current_user.id,
first_name=first_name or None,
last_name=last_name or None,
organization=organization or None,
)
db.add(guest)
db.commit()
return jsonify({
'success': True,
'action': 'added',
'guest': {
'id': guest.id,
'first_name': guest.first_name,
'last_name': guest.last_name,
'organization': guest.organization,
'display_name': guest.display_name,
}
}), 201
finally:
db.close()
@bp.route('/<int:event_id>/guests/<int:guest_id>', methods=['PATCH'], endpoint='calendar_edit_guest')
@login_required
def edit_guest(event_id, guest_id):
"""Edytuj dane osoby towarzyszącej"""
db = SessionLocal()
try:
guest = db.query(EventGuest).filter(
EventGuest.id == guest_id,
EventGuest.event_id == event_id
).first()
if not guest:
return jsonify({'success': False, 'error': 'Gość nie znaleziony'}), 404
# Tylko host lub admin
from database import SystemRole
if guest.host_user_id != current_user.id and not current_user.has_role(SystemRole.OFFICE_MANAGER):
return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403
event = db.query(NordaEvent).filter(NordaEvent.id == event_id).first()
if event and event.is_past:
return jsonify({'success': False, 'error': 'Wydarzenie już się odbyło'}), 400
data = request.get_json() or {}
first_name = (data.get('first_name') or '').strip()
last_name = (data.get('last_name') or '').strip()
organization = (data.get('organization') or '').strip()
if not first_name and not last_name and not organization:
return jsonify({'success': False, 'error': 'Podaj przynajmniej imię, nazwisko lub firmę'}), 400
guest.first_name = first_name or None
guest.last_name = last_name or None
guest.organization = organization or None
db.commit()
return jsonify({
'success': True,
'action': 'updated',
'guest': {
'id': guest.id,
'first_name': guest.first_name,
'last_name': guest.last_name,
'organization': guest.organization,
'display_name': guest.display_name,
}
})
finally:
db.close()
@bp.route('/<int:event_id>/guests/<int:guest_id>', methods=['DELETE'], endpoint='calendar_delete_guest')
@login_required
def delete_guest(event_id, guest_id):
"""Usuń osobę towarzyszącą z wydarzenia"""
db = SessionLocal()
try:
guest = db.query(EventGuest).filter(
EventGuest.id == guest_id,
EventGuest.event_id == event_id
).first()
if not guest:
return jsonify({'success': False, 'error': 'Gość nie znaleziony'}), 404
# Tylko host lub admin
from database import SystemRole
if guest.host_user_id != current_user.id and not current_user.has_role(SystemRole.OFFICE_MANAGER):
return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403
db.delete(guest)
db.commit()
return jsonify({'success': True, 'action': 'removed'})
finally:
db.close()
@bp.route('/ical', endpoint='calendar_ical')
def ical_feed():
"""