nordabiz/blueprints/community/calendar/routes.py
Maciej Pienczyn 66856a697d refactor(phase1): Extract blueprints for reports, contacts, classifieds, calendar
Phase 1 of app.py refactoring - reducing from ~14,455 to ~13,699 lines.

New structure:
- blueprints/reports/ - 4 routes (/raporty/*)
- blueprints/community/contacts/ - 6 routes (/kontakty/*)
- blueprints/community/classifieds/ - 4 routes (/tablica/*)
- blueprints/community/calendar/ - 3 routes (/kalendarz/*)
- utils/ - decorators, helpers, notifications, analytics
- extensions.py - Flask extensions (csrf, login_manager, limiter)
- config.py - environment configurations

Updated templates with blueprint-prefixed url_for() calls.

⚠️ DO NOT DEPLOY before presentation on 2026-01-30 19:00

Tested on DEV: all endpoints working correctly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 10:10:45 +01:00

182 lines
5.6 KiB
Python

"""
Calendar Routes
===============
Public calendar and event registration endpoints.
"""
from datetime import date
import calendar as cal_module
from flask import render_template, request, redirect, url_for, flash, jsonify
from flask_login import login_required, current_user
from . import bp
from database import SessionLocal, NordaEvent, EventAttendee
# Polish month names
POLISH_MONTHS = {
1: 'Styczeń', 2: 'Luty', 3: 'Marzec', 4: 'Kwiecień',
5: 'Maj', 6: 'Czerwiec', 7: 'Lipiec', 8: 'Sierpień',
9: 'Wrzesień', 10: 'Październik', 11: 'Listopad', 12: 'Grudzień'
}
@bp.route('/', endpoint='calendar_index')
@login_required
def index():
"""Kalendarz wydarzeń Norda Biznes - widok listy lub siatki miesięcznej"""
db = SessionLocal()
try:
today = date.today()
# Parametry widoku
view_mode = request.args.get('view', 'list') # list lub grid
year = request.args.get('year', today.year, type=int)
month = request.args.get('month', today.month, type=int)
# Walidacja miesiąca/roku
if month < 1:
month = 12
year -= 1
elif month > 12:
month = 1
year += 1
# Oblicz poprzedni/następny miesiąc
if month == 1:
prev_month, prev_year = 12, year - 1
else:
prev_month, prev_year = month - 1, year
if month == 12:
next_month, next_year = 1, year + 1
else:
next_month, next_year = month + 1, year
# Dane dla widoku siatki
month_days = []
events_by_day = {}
if view_mode == 'grid':
# Pobierz wydarzenia z danego miesiąca
first_day = date(year, month, 1)
last_day = date(year, month, cal_module.monthrange(year, month)[1])
events = db.query(NordaEvent).filter(
NordaEvent.event_date >= first_day,
NordaEvent.event_date <= last_day
).order_by(NordaEvent.event_date.asc()).all()
# Przygotuj strukturę kalendarza (poniedziałek = 0)
cal = cal_module.Calendar(firstweekday=0)
month_days = cal.monthdayscalendar(year, month)
# Mapuj wydarzenia na dni
for event in events:
day = event.event_date.day
if day not in events_by_day:
events_by_day[day] = []
events_by_day[day].append(event)
# Dane dla widoku listy (zawsze potrzebne dla fallback)
upcoming = db.query(NordaEvent).filter(
NordaEvent.event_date >= today
).order_by(NordaEvent.event_date.asc()).all()
past = db.query(NordaEvent).filter(
NordaEvent.event_date < today
).order_by(NordaEvent.event_date.desc()).limit(5).all()
return render_template('calendar/index.html',
# Dane dla widoku listy
upcoming_events=upcoming,
past_events=past,
today=today,
# Dane dla widoku siatki
view_mode=view_mode,
year=year,
month=month,
month_name=POLISH_MONTHS.get(month, ''),
month_days=month_days,
events_by_day=events_by_day,
prev_month=prev_month,
prev_year=prev_year,
next_month=next_month,
next_year=next_year,
)
finally:
db.close()
@bp.route('/<int:event_id>', endpoint='calendar_event')
@login_required
def event(event_id):
"""Szczegóły wydarzenia"""
db = SessionLocal()
try:
event = db.query(NordaEvent).filter(NordaEvent.id == event_id).first()
if not event:
flash('Wydarzenie nie istnieje.', 'error')
return redirect(url_for('calendar_index'))
# Sprawdź czy użytkownik jest zapisany
user_attending = db.query(EventAttendee).filter(
EventAttendee.event_id == event_id,
EventAttendee.user_id == current_user.id
).first()
return render_template('calendar/event.html',
event=event,
user_attending=user_attending
)
finally:
db.close()
@bp.route('/<int:event_id>/rsvp', methods=['POST'], endpoint='calendar_rsvp')
@login_required
def rsvp(event_id):
"""Zapisz się / wypisz z wydarzenia"""
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
# Sprawdź czy już zapisany
existing = db.query(EventAttendee).filter(
EventAttendee.event_id == event_id,
EventAttendee.user_id == current_user.id
).first()
if existing:
# Wypisz
db.delete(existing)
db.commit()
return jsonify({
'success': True,
'action': 'removed',
'message': 'Wypisano z wydarzenia',
'attendee_count': event.attendee_count
})
else:
# Zapisz
if event.max_attendees and event.attendee_count >= event.max_attendees:
return jsonify({'success': False, 'error': 'Brak wolnych miejsc'}), 400
attendee = EventAttendee(
event_id=event_id,
user_id=current_user.id,
status='confirmed'
)
db.add(attendee)
db.commit()
return jsonify({
'success': True,
'action': 'added',
'message': 'Zapisano na wydarzenie',
'attendee_count': event.attendee_count
})
finally:
db.close()