From deb73e253641d30d7e70ba18036c5a7167524f5d Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 6 Jan 2026 03:04:20 -0800 Subject: [PATCH] add download endpoints for raid images - download_image action for single image download (icon/thumbnail) - download_images action to queue async download job - download_status action to check job progress --- app/controllers/api/v1/raids_controller.rb | 81 +++++++++++++++++++++- config/routes.rb | 8 ++- 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/v1/raids_controller.rb b/app/controllers/api/v1/raids_controller.rb index aac0abb..17cfdfb 100644 --- a/app/controllers/api/v1/raids_controller.rb +++ b/app/controllers/api/v1/raids_controller.rb @@ -3,8 +3,8 @@ module Api module V1 class RaidsController < Api::V1::ApiController - before_action :set_raid, only: %i[show update destroy] - before_action :ensure_editor_role, only: %i[create update destroy] + before_action :set_raid, only: %i[show update destroy download_image download_images download_status] + before_action :ensure_editor_role, only: %i[create update destroy download_image download_images] # GET /raids def index @@ -57,6 +57,83 @@ module Api end end + # POST /raids/:id/download_image + # Synchronously downloads a single image for a raid + def download_image + size = params[:size] + force = params[:force] == true + + valid_sizes = Granblue::Downloaders::RaidDownloader::SIZES + unless valid_sizes.include?(size) + return render json: { error: "Invalid size. Must be one of: #{valid_sizes.join(', ')}" }, status: :unprocessable_entity + end + + # Check if the required ID exists + if size == 'icon' && @raid.enemy_id.blank? + return render json: { error: 'Raid has no enemy_id configured' }, status: :unprocessable_entity + end + if size == 'thumbnail' && @raid.summon_id.blank? + return render json: { error: 'Raid has no summon_id configured' }, status: :unprocessable_entity + end + + begin + downloader = Granblue::Downloaders::RaidDownloader.new( + @raid, + storage: :s3, + force: force, + verbose: true + ) + + downloader.download(size) + + render json: { + success: true, + raid_id: @raid.id, + slug: @raid.slug, + size: size, + message: 'Image downloaded successfully' + } + rescue StandardError => e + Rails.logger.error "[RAIDS] Image download error for #{@raid.id}: #{e.message}" + render json: { success: false, error: e.message }, status: :internal_server_error + end + end + + # POST /raids/:id/download_images + # Triggers async image download for a raid + def download_images + DownloadRaidImagesJob.perform_later( + @raid.id, + force: params.dig(:options, :force) == true, + size: params.dig(:options, :size) || 'all' + ) + + DownloadRaidImagesJob.update_status( + @raid.id, + 'queued', + progress: 0, + images_downloaded: 0 + ) + + render json: { + status: 'queued', + raid_id: @raid.id, + slug: @raid.slug, + message: 'Image download job has been queued' + }, status: :accepted + end + + # GET /raids/:id/download_status + # Returns the status of an image download job + def download_status + status = DownloadRaidImagesJob.status(@raid.id) + + render json: status.merge( + raid_id: @raid.id, + slug: @raid.slug + ) + end + # GET /raids/groups (legacy endpoint) def groups render json: RaidGroupBlueprint.render(RaidGroup.includes(raids: :group).ordered, view: :full) diff --git a/config/routes.rb b/config/routes.rb index 189b5cb..651bd1a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -113,7 +113,13 @@ Rails.application.routes.draw do # Raids and RaidGroups resources :raid_groups, only: %i[index show create update destroy] - resources :raids, only: %i[index show create update destroy] + resources :raids, only: %i[index show create update destroy] do + member do + post :download_image + post :download_images + get :download_status + end + end get 'raids/groups', to: 'raids#groups' # Legacy endpoint get 'weapon_keys', to: 'weapon_keys#all'