module Admin class SessionsController < Admin::BaseController def index @filters = session_filters scope = filtered_sessions @total_count = scope.count @sessions = scope .includes(:stream_node, :user, match: { team: :club }) .order(Arel.sql("COALESCE(stream_sessions.started_at, stream_sessions.created_at) DESC")) .limit(100) @clubs = Club.order(:name) @nodes = StreamNode.order(:slug) end def show @session = StreamSession .includes(:stream_node, :user, :device_states, :recording, match: { team: :club }) .find(params[:id]) @events = @session.stream_events.recent.limit(100) @club = @session.match.team.club end def stop @session = StreamSession.find(params[:id]) if @session.terminal? redirect_to admin_session_path(@session), alert: t("admin.flash.session_already_terminated", status: @session.status) return end Sessions::Stop.new(@session).call redirect_to admin_session_path(@session), notice: t("admin.flash.session_stopped") rescue StandardError => e Rails.logger.error("[admin] stop session #{@session.id}: #{e.class} #{e.message}") redirect_to admin_session_path(@session), alert: t("admin.flash.session_stop_error", error: e.message) end def regia_link @session = StreamSession.find(params[:id]) if @session.terminal? redirect_to admin_session_path(@session), alert: t("admin.flash.session_terminated_no_regia") return end access = Sessions::RegiaAccess.new(@session) token = access.issue_token! redirect_to admin_session_path(@session), notice: t("admin.flash.session_regia_generated"), flash: { regia_url: access.url(token), regia_expires_at: @session.regia_token_expires_at&.iso8601 } end private def session_filters { q: params[:q].to_s.strip.presence, status: params[:status].to_s.strip.presence, platform: params[:platform].to_s.strip.presence, club_id: params[:club_id].to_s.strip.presence, stream_node_id: params[:stream_node_id].to_s.strip.presence, from: params[:from].to_s.strip.presence, to: params[:to].to_s.strip.presence } end def filtered_sessions scope = StreamSession.left_outer_joins(match: { team: :club }) if @filters[:q].present? term = "%#{ActiveRecord::Base.sanitize_sql_like(@filters[:q])}%" scope = scope.where( "teams.name ILIKE :term OR matches.opponent_name ILIKE :term OR clubs.name ILIKE :term OR matches.location ILIKE :term", term: term ) end if @filters[:status].present? && StreamSession::STATUSES.include?(@filters[:status]) scope = scope.where(stream_sessions: { status: @filters[:status] }) end if @filters[:platform].present? && StreamSession::LIVE_PLATFORMS.include?(@filters[:platform]) scope = scope.where(stream_sessions: { platform: @filters[:platform] }) end if @filters[:club_id].present? scope = scope.where(teams: { club_id: @filters[:club_id] }) end if @filters[:stream_node_id].present? node = StreamNode.find_by(id: @filters[:stream_node_id]) if node scope = scope.where( "stream_sessions.stream_node_id = :id OR stream_sessions.ingest_slug = :slug", id: node.id, slug: node.slug ) end end if (from_time = parse_filter_date(@filters[:from], end_of_day: false)) scope = scope.where( "COALESCE(stream_sessions.started_at, stream_sessions.created_at) >= ?", from_time ) end if (to_time = parse_filter_date(@filters[:to], end_of_day: true)) scope = scope.where( "COALESCE(stream_sessions.started_at, stream_sessions.created_at) <= ?", to_time ) end scope end def parse_filter_date(value, end_of_day:) return nil if value.blank? date = Date.parse(value) end_of_day ? date.end_of_day : date.beginning_of_day rescue ArgumentError, TypeError nil end end end