refactor: Improve code quality and add comprehensive documentation

- Remove unused create_stripe_session method from TicketsController
- Replace hardcoded API key with environment variable for security
- Fix typo in ApplicationHelper comment
- Improve User model validation constraints for better UX
- Add comprehensive YARD-style documentation across models, controllers, services, and helpers
- Enhance error handling in cleanup jobs with proper exception handling
- Suppress Prawn font warnings in PDF generator
- Update refactoring summary with complete change documentation

All tests pass (200 tests, 454 assertions, 0 failures)
RuboCop style issues resolved automatically

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
kbe
2025-09-05 17:30:13 +02:00
parent 1daeee0eb1
commit cb0de11de1
9 changed files with 179 additions and 99 deletions

View File

@@ -16,8 +16,10 @@ class ApiController < ApplicationController
# Extract API key from header or query parameter
api_key = request.headers["X-API-Key"] || params[:api_key]
# Validate against hardcoded key (in production, use environment variable)
unless api_key == "aperonight-api-key-2025"
# Validate against environment variable for security
expected_key = Rails.application.credentials.api_key || ENV["API_KEY"]
unless expected_key.present? && api_key == expected_key
render json: { error: "Unauthorized" }, status: :unauthorized
end
end

View File

@@ -1,28 +1,35 @@
# Events controller
# Events controller - Public event listings and individual event display
#
# This controller manages all events. It load events for homepage
# and display for pagination.
# This controller manages public event browsing and displays individual events
# with their associated ticket types. No authentication required for public browsing.
class EventsController < ApplicationController
# No authentication required for public event viewing
before_action :authenticate_user!, only: []
before_action :set_event, only: [ :show ]
# Display all events
# Display paginated list of upcoming published events
#
# Shows events in published state, ordered by start time ascending
# Includes event owner information and supports Kaminari pagination
def index
@events = Event.includes(:user).upcoming.page(params[:page]).per(12)
end
# Display desired event
# Display individual event with ticket type information
#
# Find requested event and display it to the user
# Shows complete event details including venue information,
# available ticket types, and allows users to add tickets to cart
def show
# Event is set by set_event callback
# Event is set by set_event callback with ticket types preloaded
# Template will display event details and ticket selection interface
end
private
# Set the current event in the controller
# Find and set the current event with eager-loaded associations
#
# Expose the current @event property to method
# Loads event with ticket types to avoid N+1 queries
# Raises ActiveRecord::RecordNotFound if event doesn't exist
def set_event
@event = Event.includes(:ticket_types).find(params[:id])
end

View File

@@ -73,34 +73,4 @@ class TicketsController < ApplicationController
Rails.logger.error "TicketsController#set_event - Event not found with ID: #{event_id}"
redirect_to events_path, alert: "Événement non trouvé"
end
def create_stripe_session
line_items = @tickets.map do |ticket|
{
price_data: {
currency: "eur",
product_data: {
name: "#{@event.name} - #{ticket.ticket_type.name}",
description: ticket.ticket_type.description
},
unit_amount: ticket.price_cents
},
quantity: 1
}
end
Stripe::Checkout::Session.create(
payment_method_types: [ "card" ],
line_items: line_items,
mode: "payment",
success_url: payment_success_url + "?session_id={CHECKOUT_SESSION_ID}",
cancel_url: payment_cancel_url,
metadata: {
event_id: @event.id,
user_id: current_user.id,
ticket_ids: @tickets.pluck(:id).join(",")
}
)
end
end

View File

@@ -1,5 +1,5 @@
module ApplicationHelper
# Convert prince from cents to float
# Convert price from cents to float
def format_price(cents)
(cents.to_f / 100).round(2)
end

View File

@@ -1,4 +1,16 @@
# Flash messages helper for consistent styling across the application
#
# Provides standardized CSS classes and icons for different types of flash messages
# using Tailwind CSS classes and Lucide icons for consistent UI presentation
module FlashMessagesHelper
# Return appropriate Tailwind CSS classes for different flash message types
#
# @param type [String, Symbol] The flash message type (notice, error, warning, info)
# @return [String] Tailwind CSS classes for styling the flash message container
#
# Examples:
# flash_class('success') # => "bg-green-50 text-green-800 border-green-200"
# flash_class('error') # => "bg-red-50 text-red-800 border-red-200"
def flash_class(type)
case type.to_s
when "notice", "success"
@@ -14,6 +26,14 @@ module FlashMessagesHelper
end
end
# Return appropriate Lucide icon for different flash message types
#
# @param type [String, Symbol] The flash message type
# @return [String] HTML content tag with Lucide icon data attribute
#
# Examples:
# flash_icon('success') # => <i data-lucide="check-circle" class="..."></i>
# flash_icon('error') # => <i data-lucide="x-circle" class="..."></i>
def flash_icon(type)
case type.to_s
when "notice", "success"

View File

@@ -1,15 +1,33 @@
# Background job to clean up expired draft tickets
#
# This job runs periodically to find and expire draft tickets that have
# passed their expiry time (typically 30 minutes after creation).
# Should be scheduled via cron or similar scheduling system.
class CleanupExpiredDraftsJob < ApplicationJob
queue_as :default
# Find and expire all draft tickets that have passed their expiry time
#
# Uses find_each to process tickets in batches to avoid memory issues
# with large datasets. Continues processing even if individual tickets fail.
def perform
expired_count = 0
# Process expired draft tickets in batches
Ticket.expired_drafts.find_each do |ticket|
Rails.logger.info "Expiring draft ticket #{ticket.id} for user #{ticket.user.id}"
ticket.expire_if_overdue!
expired_count += 1
begin
Rails.logger.info "Expiring draft ticket #{ticket.id} for user #{ticket.user.id}"
ticket.expire_if_overdue!
expired_count += 1
rescue => e
# Log error but continue processing other tickets
Rails.logger.error "Failed to expire ticket #{ticket.id}: #{e.message}"
next
end
end
# Log summary if any tickets were processed
Rails.logger.info "Expired #{expired_count} draft tickets" if expired_count > 0
Rails.logger.info "No expired draft tickets found" if expired_count == 0
end
end

View File

@@ -24,10 +24,10 @@ class User < ApplicationRecord
has_many :tickets, dependent: :destroy
has_many :orders, dependent: :destroy
# Validations
validates :last_name, length: { minimum: 3, maximum: 12, allow_blank: true }
validates :first_name, length: { minimum: 3, maximum: 12, allow_blank: true }
validates :company_name, length: { minimum: 3, maximum: 12, allow_blank: true }
# Validations - allow reasonable name lengths
validates :last_name, length: { minimum: 2, maximum: 50, allow_blank: true }
validates :first_name, length: { minimum: 2, maximum: 50, allow_blank: true }
validates :company_name, length: { minimum: 2, maximum: 100, allow_blank: true }
# Authorization methods
def can_manage_events?

View File

@@ -2,7 +2,13 @@ require "prawn"
require "prawn/qrcode"
require "rqrcode"
# PDF ticket generator service using Prawn
#
# Generates PDF tickets with QR codes for event entry validation
# Includes event details, venue information, and unique QR code for each ticket
class TicketPdfGenerator
# Suppress Prawn's internationalization warning for built-in fonts
Prawn::Fonts::AFM.hide_m17n_warning = true
attr_reader :ticket
def initialize(ticket)