# Tickets controller - handles ticket viewing and downloads with SEO-friendly URLs # # This controller manages individual ticket display and downloads # Uses event-slug-ticket-id format for SEO-friendly URLs class TicketsController < ApplicationController before_action :authenticate_user! before_action :set_ticket_from_seo_params, only: [:show, :view, :download, :retry_payment] # Display ticket details def show @event = @ticket.event end # Display ticket in PDF-like format def view @event = @ticket.event end # Download PDF ticket - only accessible by ticket owner # User must be authenticated to download ticket def download # Generate PDF using Grover begin Rails.logger.info "Starting PDF generation for ticket ID: #{@ticket.id}" # Render the HTML template html = render_to_string( partial: "tickets/pdf_ticket", layout: false, locals: { ticket: @ticket } ) Rails.logger.info "HTML template rendered successfully, length: #{html.length}" # Configure Grover options for PDF generation pdf_options = { format: 'A4', margin: { top: '0.5in', bottom: '0.5in', left: '0.5in', right: '0.5in' }, print_background: true, display_header_footer: false, prefer_css_page_size: true, launch_args: ["--no-sandbox", "--disable-setuid-sandbox"] # For better compatibility } # Generate PDF pdf = Grover.new(html, pdf_options).to_pdf Rails.logger.info "PDF generation completed for ticket ID: #{@ticket.id}" # Send PDF as download with SEO-friendly filename send_data pdf, filename: "billet-#{@ticket.event.slug}-#{@ticket.id}.pdf", type: 'application/pdf', disposition: 'attachment' rescue => e Rails.logger.error "PDF generation failed for ticket ID: #{@ticket.id} - Error: #{e.message}" Rails.logger.error e.backtrace.join("\n") redirect_to view_ticket_path(event_slug: @ticket.event.slug, ticket_id: @ticket.id), alert: "Erreur lors de la génération du PDF. Veuillez réessayer." end end # Redirect retry payment to order system def retry_payment # Look for draft order for this ticket's event order = current_user.orders.find_by(event: @ticket.event, status: "draft") if order&.can_retry_payment? year = order.event.start_time.year month = format("%02d", order.event.start_time.month) redirect_to event_checkout_path(year: year, month: month, slug: order.event.slug) else redirect_to seo_event_path(@ticket.event), alert: "Aucune commande disponible pour un nouveau paiement" end end # Legacy redirects for backward compatibility def payment_success redirect_to booking_payment_success_path(session_id: params[:session_id]) end def payment_cancel redirect_to booking_payment_cancelled_path end private def set_ticket_from_seo_params # Parse event_slug and ticket_id from the SEO-friendly format: event-slug-123 slug_and_id = params[:event_slug_ticket_id] || "#{params[:event_slug]}-#{params[:ticket_id]}" # Split by last dash to separate event slug from ticket ID parts = slug_and_id.split('-') ticket_id = parts.pop event_slug = parts.join('-') # Find ticket and ensure it belongs to current user @ticket = Ticket.joins(order: :user) .includes(:event, :ticket_type, order: :user) .joins(:event) .where( tickets: { id: ticket_id }, orders: { user_id: current_user.id }, events: { slug: event_slug } ) .first unless @ticket redirect_to dashboard_path, alert: "Billet non trouvé ou vous n'avez pas l'autorisation d'accéder à ce billet" end end # Generate SEO-friendly path for an event def seo_event_path(event) year = event.start_time.year month = format("%02d", event.start_time.month) event_path(year: year, month: month, slug: event.slug) end helper_method :seo_event_path end