Phase 2: move the 8 catalog models into the WarpEngine engine
- Software, Release, ReleaseAsset, ExternalLink, PlatformLink, Image, SoftwareImage, Download now live in the engine under WarpEngine::, on top of WarpEngine::ApplicationRecord; table names unchanged (empty prefix) - each model runs an ActiveSupport load hook (:warp_engine_<model>) as a host extension point - WarpEngine::Image reads its upload path from WarpEngine.config - host references fully qualified (services, serializers, admin, specs); admin registrations renamed with as: so /admin URLs and route helpers are byte-identical; factories pinned to the namespaced classes - Member#image now class_name: "WarpEngine::Image" Verified: full suite green, /api/software and /api/builds byte-identical to the phase-0 baselines, admin routes unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
ActiveAdmin.register Download do
|
||||
ActiveAdmin.register WarpEngine::Download, as: "Download" do
|
||||
actions :index, :show
|
||||
|
||||
menu priority: 7, label: "📊 Download Stats"
|
||||
@@ -15,21 +15,21 @@ ActiveAdmin.register Download do
|
||||
sidebar "Summary", only: :index do
|
||||
dl style: "display:grid;grid-template-columns:1fr auto;gap:6px 12px;margin:0;" do
|
||||
dt { strong "Total" }
|
||||
dd { b Download.count.to_s }
|
||||
dd { b WarpEngine::Download.count.to_s }
|
||||
|
||||
dt { strong "Today" }
|
||||
dd { b Download.where("created_at >= ?", Date.current.beginning_of_day).count.to_s }
|
||||
dd { b WarpEngine::Download.where("created_at >= ?", Date.current.beginning_of_day).count.to_s }
|
||||
|
||||
dt { strong "This week" }
|
||||
dd { b Download.where("created_at >= ?", 1.week.ago).count.to_s }
|
||||
dd { b WarpEngine::Download.where("created_at >= ?", 1.week.ago).count.to_s }
|
||||
|
||||
dt { strong "This month" }
|
||||
dd { b Download.where("created_at >= ?", 1.month.ago).count.to_s }
|
||||
dd { b WarpEngine::Download.where("created_at >= ?", 1.month.ago).count.to_s }
|
||||
end
|
||||
end
|
||||
|
||||
sidebar "Top 10 Files", only: :index do
|
||||
table_for Download.group(:file_path)
|
||||
table_for WarpEngine::Download.group(:file_path)
|
||||
.select("file_path, COUNT(*) as dl_count, MAX(created_at) as last_dl")
|
||||
.order("dl_count DESC")
|
||||
.limit(10) do
|
||||
@@ -39,7 +39,7 @@ ActiveAdmin.register Download do
|
||||
end
|
||||
|
||||
sidebar "Top 5 Software", only: :index do
|
||||
rows = Download.joins(release: :software)
|
||||
rows = WarpEngine::Download.joins(release: :software)
|
||||
.group("softwares.title")
|
||||
.order("count_all DESC")
|
||||
.limit(5)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ActiveAdmin.register ExternalLink do
|
||||
ActiveAdmin.register WarpEngine::ExternalLink, as: "External Link" do
|
||||
permit_params :software_id, :label, :url
|
||||
|
||||
menu false
|
||||
|
||||
@@ -61,7 +61,7 @@ ActiveAdmin.register_page "Files" do
|
||||
# Pre-fetch download counts for files in current directory
|
||||
file_entries = entries.select { |e| e[:type] != :directory }
|
||||
dl_counts = if file_entries.any?
|
||||
Download.where(file_path: file_entries.map { |e| e[:path] })
|
||||
WarpEngine::Download.where(file_path: file_entries.map { |e| e[:path] })
|
||||
.group(:file_path)
|
||||
.count
|
||||
else
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
ActiveAdmin.register Image do
|
||||
ActiveAdmin.register WarpEngine::Image, as: "Image" do
|
||||
permit_params :file_upload
|
||||
|
||||
menu priority: 5, label: "🖼️ Images"
|
||||
|
||||
used_ids = -> { SoftwareImage.distinct.pluck(:image_id) + ImageUsage.used_image_ids }
|
||||
used_ids = -> { WarpEngine::SoftwareImage.distinct.pluck(:image_id) + ImageUsage.used_image_ids }
|
||||
|
||||
scope :all, default: true
|
||||
scope("In use") { |scope| scope.where(id: used_ids.call) }
|
||||
@@ -11,7 +11,7 @@ ActiveAdmin.register Image do
|
||||
|
||||
batch_action :delete_orphans, confirm: "Delete all selected orphan images and their files?" do |ids|
|
||||
orphan_ids = ids.map(&:to_i) - used_ids.call
|
||||
Image.where(id: orphan_ids).find_each do |img|
|
||||
WarpEngine::Image.where(id: orphan_ids).find_each do |img|
|
||||
File.delete(img.file_path) if File.exist?(img.file_path)
|
||||
img.destroy
|
||||
end
|
||||
|
||||
@@ -41,7 +41,7 @@ ActiveAdmin.register Member do
|
||||
f.template.image_tag("/api/image/#{resource.image_id}", style: "max-height:80px;max-width:160px;object-fit:contain;margin-top:6px;").html_safe
|
||||
end
|
||||
f.input :image_id, as: :select, label: "Image",
|
||||
collection: Image.order(:original_filename).map { |img| [ img.original_filename, img.id ] },
|
||||
collection: WarpEngine::Image.order(:original_filename).map { |img| [ img.original_filename, img.id ] },
|
||||
include_blank: "— no image (use avatar_filename) —",
|
||||
hint: img_hint
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ActiveAdmin.register PlatformLink do
|
||||
ActiveAdmin.register WarpEngine::PlatformLink, as: "Platform Link" do
|
||||
permit_params :name, :url, :platform, :position
|
||||
|
||||
menu priority: 5, label: "🔗 Platform Links"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ActiveAdmin.register Release do
|
||||
ActiveAdmin.register WarpEngine::Release, as: "Release" do
|
||||
actions :index, :show
|
||||
|
||||
menu false
|
||||
@@ -38,7 +38,7 @@ ActiveAdmin.register Release do
|
||||
end
|
||||
|
||||
panel "Downloads by File" do
|
||||
file_stats = Download.where(release_id: resource.id)
|
||||
file_stats = WarpEngine::Download.where(release_id: resource.id)
|
||||
.group(:file_path)
|
||||
.select("file_path, COUNT(*) as dl_count, MAX(created_at) as last_dl")
|
||||
.order("dl_count DESC")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ActiveAdmin.register Software do
|
||||
ActiveAdmin.register WarpEngine::Software, as: "Software" do
|
||||
permit_params :name, :title, :author, :desc, :story,
|
||||
:license, :platform, :status, :highlighted,
|
||||
software_images_attributes: [ :id, :image_id, :is_default, :position, :file_upload, :_destroy ],
|
||||
@@ -56,7 +56,7 @@ ActiveAdmin.register Software do
|
||||
|
||||
sidebar "Download Statistics", only: :show do
|
||||
sw = resource
|
||||
total = Download.joins(:release).where(releases: { software_id: sw.id }).count
|
||||
total = WarpEngine::Download.joins(:release).where(releases: { software_id: sw.id }).count
|
||||
|
||||
div style: "margin-bottom:12px;" do
|
||||
strong "Total downloads: "
|
||||
@@ -64,7 +64,7 @@ ActiveAdmin.register Software do
|
||||
end
|
||||
|
||||
sw.releases.each do |rel|
|
||||
file_stats = Download.where(release_id: rel.id)
|
||||
file_stats = WarpEngine::Download.where(release_id: rel.id)
|
||||
.group(:file_path)
|
||||
.select("file_path, COUNT(*) as dl_count, MAX(created_at) as last_dl")
|
||||
.order("dl_count DESC")
|
||||
@@ -108,7 +108,7 @@ ActiveAdmin.register Software do
|
||||
si.template.image_tag("/api/image/#{si.object.image_id}", style: "max-height:80px;max-width:160px;object-fit:contain;margin-top:6px;").html_safe
|
||||
end
|
||||
si.input :image_id, as: :select, label: "Image",
|
||||
collection: Image.order(:original_filename).map { |img| [ img.original_filename, img.id ] },
|
||||
collection: WarpEngine::Image.order(:original_filename).map { |img| [ img.original_filename, img.id ] },
|
||||
include_blank: "— select —",
|
||||
hint: img_hint
|
||||
si.input :file_upload, as: :file, label: "Upload new image"
|
||||
@@ -128,7 +128,7 @@ ActiveAdmin.register Software do
|
||||
f.has_many :releases, allow_destroy: true, new_record: true do |r|
|
||||
r.input :version
|
||||
r.has_many :release_assets, allow_destroy: true, new_record: true do |ra|
|
||||
ra.input :kind, as: :select, collection: ReleaseAsset::KINDS, include_blank: false
|
||||
ra.input :kind, as: :select, collection: WarpEngine::ReleaseAsset::KINDS, include_blank: false
|
||||
ra.input :path
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
class Download < ApplicationRecord
|
||||
belongs_to :release, optional: true
|
||||
|
||||
validates :file_path, presence: true
|
||||
|
||||
default_scope { where(deleted_at: nil) }
|
||||
|
||||
def self.ransackable_attributes(auth_object = nil)
|
||||
%w[created_at deleted_at file_path id ip_address referer release_id updated_at user_agent]
|
||||
end
|
||||
|
||||
def self.ransackable_associations(auth_object = nil)
|
||||
%w[release]
|
||||
end
|
||||
end
|
||||
@@ -1,18 +0,0 @@
|
||||
class ExternalLink < ApplicationRecord
|
||||
self.table_name = "external_links"
|
||||
|
||||
belongs_to :software
|
||||
|
||||
validates :label, presence: true
|
||||
validates :url, presence: true
|
||||
|
||||
default_scope { where(deleted_at: nil) }
|
||||
|
||||
def self.ransackable_attributes(auth_object = nil)
|
||||
%w[created_at deleted_at id label software_id updated_at url]
|
||||
end
|
||||
|
||||
def self.ransackable_associations(auth_object = nil)
|
||||
%w[software]
|
||||
end
|
||||
end
|
||||
@@ -1,33 +0,0 @@
|
||||
class Image < ApplicationRecord
|
||||
# Híváskor kiértékelve, hogy a path ne class-load-kor rögzüljön.
|
||||
def self.upload_path
|
||||
ENV.fetch("IMAGE_CONTAINER_PATH", "/images")
|
||||
end
|
||||
|
||||
has_many :software_images, dependent: :restrict_with_error
|
||||
|
||||
default_scope { where(deleted_at: nil) }
|
||||
|
||||
attr_accessor :file_upload
|
||||
|
||||
before_save :process_upload, if: -> { file_upload.present? }
|
||||
|
||||
def self.ransackable_attributes(auth_object = nil)
|
||||
%w[content_type created_at deleted_at filename id original_filename updated_at]
|
||||
end
|
||||
|
||||
def file_path
|
||||
File.join(self.class.upload_path, filename.to_s)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def process_upload
|
||||
FileUtils.mkdir_p(self.class.upload_path)
|
||||
self.original_filename = file_upload.original_filename
|
||||
self.content_type = file_upload.content_type.presence || "application/octet-stream"
|
||||
ext = File.extname(file_upload.original_filename)
|
||||
self.filename = "#{SecureRandom.uuid}#{ext}"
|
||||
IO.copy_stream(file_upload.to_io, file_path)
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
class Member < ApplicationRecord
|
||||
belongs_to :image, optional: true
|
||||
belongs_to :image, class_name: "WarpEngine::Image", optional: true
|
||||
has_one :admin_user
|
||||
|
||||
validates :nick, presence: true, uniqueness: true
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
class PlatformLink < ApplicationRecord
|
||||
self.table_name = "platform_links"
|
||||
|
||||
SUPPORTED_PLATFORMS = %w[tic80 ebitengine love c64 godot bevy phaser].freeze
|
||||
|
||||
validates :name, presence: true
|
||||
validates :url, presence: true
|
||||
validates :platform, presence: true, inclusion: { in: SUPPORTED_PLATFORMS }
|
||||
|
||||
default_scope { where(deleted_at: nil).order(:position) }
|
||||
|
||||
def self.ransackable_attributes(auth_object = nil)
|
||||
%w[created_at deleted_at id name platform position updated_at url]
|
||||
end
|
||||
|
||||
def self.ransackable_associations(auth_object = nil)
|
||||
[]
|
||||
end
|
||||
|
||||
def self.for_platform(platform)
|
||||
where(platform: platform).to_a
|
||||
end
|
||||
end
|
||||
@@ -1,33 +0,0 @@
|
||||
class Release < ApplicationRecord
|
||||
self.table_name = "releases"
|
||||
|
||||
belongs_to :software
|
||||
has_many :downloads
|
||||
has_many :release_assets
|
||||
|
||||
accepts_nested_attributes_for :release_assets, allow_destroy: true
|
||||
|
||||
validates :version, presence: true
|
||||
validates :version, uniqueness: { scope: :software_id }
|
||||
|
||||
default_scope { where(deleted_at: nil) }
|
||||
|
||||
validate :c64_cannot_be_web_playable
|
||||
|
||||
def c64_cannot_be_web_playable
|
||||
return unless software&.platform == "c64"
|
||||
|
||||
has_html = release_assets.reject(&:marked_for_destruction?).any? { |a| a.kind == "html" }
|
||||
if has_html
|
||||
errors.add(:base, "C64 releases cannot be web playable (download only)")
|
||||
end
|
||||
end
|
||||
|
||||
def self.ransackable_attributes(auth_object = nil)
|
||||
%w[created_at deleted_at id software_id updated_at version]
|
||||
end
|
||||
|
||||
def self.ransackable_associations(auth_object = nil)
|
||||
%w[downloads release_assets software]
|
||||
end
|
||||
end
|
||||
@@ -1,22 +0,0 @@
|
||||
class ReleaseAsset < ApplicationRecord
|
||||
KINDS = %w[cartridge source html docs
|
||||
win_x86 win_x64 linux_x86 linux_x64
|
||||
mac_x64 mac_arm64 mac_universal].freeze
|
||||
|
||||
belongs_to :release
|
||||
|
||||
enum :kind, KINDS.index_by(&:itself)
|
||||
|
||||
validates :path, presence: true
|
||||
validates :kind, uniqueness: { scope: :release_id }
|
||||
|
||||
default_scope { where(deleted_at: nil) }
|
||||
|
||||
def self.ransackable_attributes(auth_object = nil)
|
||||
%w[created_at deleted_at id kind path release_id updated_at]
|
||||
end
|
||||
|
||||
def self.ransackable_associations(auth_object = nil)
|
||||
%w[release]
|
||||
end
|
||||
end
|
||||
@@ -1,27 +0,0 @@
|
||||
class Software < ApplicationRecord
|
||||
self.table_name = "softwares"
|
||||
|
||||
has_many :software_images, foreign_key: :software_id, dependent: :destroy
|
||||
has_many :images, through: :software_images
|
||||
has_many :releases, foreign_key: :software_id
|
||||
has_many :downloads, through: :releases
|
||||
has_many :external_links, foreign_key: :software_id
|
||||
|
||||
accepts_nested_attributes_for :software_images, allow_destroy: true
|
||||
accepts_nested_attributes_for :external_links, allow_destroy: true
|
||||
accepts_nested_attributes_for :releases, allow_destroy: true
|
||||
|
||||
validates :name, presence: true, uniqueness: true
|
||||
validates :title, presence: true
|
||||
validates :platform, presence: true
|
||||
|
||||
default_scope { where(deleted_at: nil) }
|
||||
|
||||
def self.ransackable_attributes(auth_object = nil)
|
||||
%w[author created_at desc highlighted id license name platform site status story title updated_at]
|
||||
end
|
||||
|
||||
def self.ransackable_associations(auth_object = nil)
|
||||
%w[releases external_links software_images images]
|
||||
end
|
||||
end
|
||||
@@ -1,41 +0,0 @@
|
||||
class SoftwareImage < ApplicationRecord
|
||||
belongs_to :software
|
||||
belongs_to :image, optional: true
|
||||
|
||||
attr_accessor :file_upload
|
||||
|
||||
before_validation :create_image_from_upload, if: -> { file_upload.present? }
|
||||
|
||||
validates :image_id, presence: true
|
||||
validates :image_id, uniqueness: { scope: :software_id }
|
||||
validates :position, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
||||
|
||||
before_save :unset_other_defaults, if: -> { is_default? && is_default_changed? }
|
||||
|
||||
default_scope { order(:position) }
|
||||
|
||||
def self.ransackable_attributes(auth_object = nil)
|
||||
%w[created_at id image_id is_default position software_id updated_at]
|
||||
end
|
||||
|
||||
def self.ransackable_associations(auth_object = nil)
|
||||
%w[image software]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_image_from_upload
|
||||
img = Image.new(file_upload: file_upload)
|
||||
if img.save
|
||||
self.image = img
|
||||
else
|
||||
errors.add(:file_upload, img.errors.full_messages.join(", "))
|
||||
end
|
||||
end
|
||||
|
||||
def unset_other_defaults
|
||||
SoftwareImage.where(software_id: software_id, is_default: true)
|
||||
.where.not(id: id)
|
||||
.update_all(is_default: false)
|
||||
end
|
||||
end
|
||||
@@ -15,7 +15,7 @@ class SoftwareSerializer < Blueprinter::Base
|
||||
field :status
|
||||
field(:highlighted) { |sw| sw.highlighted ? true : false }
|
||||
field(:externalLinks) { |sw| ExternalLinkSerializer.render_as_hash(sw.external_links) }
|
||||
field(:platformLinks) { |sw| PlatformLinkSerializer.render_as_hash(PlatformLink.for_platform(sw.platform)) }
|
||||
field(:platformLinks) { |sw| PlatformLinkSerializer.render_as_hash(WarpEngine::PlatformLink.for_platform(sw.platform)) }
|
||||
field(:imageUrl) { |sw|
|
||||
si = sw.software_images.detect(&:is_default?) || sw.software_images.first
|
||||
si ? "/api/image/#{si.image_id}" : nil
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class BuildsService
|
||||
def index
|
||||
platforms = PlatformLink::SUPPORTED_PLATFORMS.each_with_object({}) do |platform, hash|
|
||||
platforms = WarpEngine::PlatformLink::SUPPORTED_PLATFORMS.each_with_object({}) do |platform, hash|
|
||||
service_class = "SoftwareUpdater::#{platform.camelize}Service".constantize
|
||||
hash[platform] = {
|
||||
label: service_class.label,
|
||||
@@ -8,13 +8,13 @@ class BuildsService
|
||||
}
|
||||
end
|
||||
|
||||
all_kinds = ReleaseAsset::KINDS
|
||||
all_kinds = WarpEngine::ReleaseAsset::KINDS
|
||||
|
||||
{ platforms: platforms, allKinds: all_kinds }
|
||||
end
|
||||
|
||||
def show(name)
|
||||
software = Software.find_by!(name: name)
|
||||
software = WarpEngine::Software.find_by!(name: name)
|
||||
service_class = "SoftwareUpdater::#{software.platform.camelize}Service".constantize
|
||||
expected = service_class.expected_kinds
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ module SoftwareUpdater
|
||||
private
|
||||
|
||||
def update_or_create_software(attrs)
|
||||
software = Software.unscoped.find_or_initialize_by(name: attrs[:name])
|
||||
software = WarpEngine::Software.unscoped.find_or_initialize_by(name: attrs[:name])
|
||||
software.assign_attributes(attrs.except(:name))
|
||||
software.deleted_at = nil
|
||||
software.save!
|
||||
@@ -11,22 +11,22 @@ module SoftwareUpdater
|
||||
end
|
||||
|
||||
def upsert_external_link(software_id, label, url)
|
||||
link = ExternalLink.unscoped.find_or_initialize_by(software_id: software_id, label: label)
|
||||
link = WarpEngine::ExternalLink.unscoped.find_or_initialize_by(software_id: software_id, label: label)
|
||||
link.url = url
|
||||
link.deleted_at = nil
|
||||
link.save!
|
||||
end
|
||||
|
||||
def create_release_if_not_exists(attrs)
|
||||
existing = Release.unscoped.find_by(software_id: attrs[:software_id], version: attrs[:version])
|
||||
existing = WarpEngine::Release.unscoped.find_by(software_id: attrs[:software_id], version: attrs[:version])
|
||||
return existing if existing
|
||||
|
||||
Release.create!(attrs)
|
||||
WarpEngine::Release.create!(attrs)
|
||||
end
|
||||
|
||||
def sync_release_assets(release, kind_paths)
|
||||
kind_paths.each do |kind, path|
|
||||
asset = ReleaseAsset.unscoped.find_or_initialize_by(release_id: release.id, kind: kind)
|
||||
asset = WarpEngine::ReleaseAsset.unscoped.find_or_initialize_by(release_id: release.id, kind: kind)
|
||||
asset.path = path
|
||||
asset.deleted_at = nil
|
||||
asset.save!
|
||||
|
||||
@@ -16,10 +16,10 @@ class DownloadService
|
||||
return nil unless File.file?(full_path)
|
||||
|
||||
escaped = sanitized.gsub("%", "\\%").gsub("_", "\\_")
|
||||
asset = ReleaseAsset.find_by(path: File.join(self.class.container_base, sanitized)) ||
|
||||
ReleaseAsset.where("path LIKE ?", "%#{escaped}%").first
|
||||
asset = WarpEngine::ReleaseAsset.find_by(path: File.join(self.class.container_base, sanitized)) ||
|
||||
WarpEngine::ReleaseAsset.where("path LIKE ?", "%#{escaped}%").first
|
||||
|
||||
Download.create!(
|
||||
WarpEngine::Download.create!(
|
||||
file_path: sanitized,
|
||||
release: asset&.release,
|
||||
ip_address: ip,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class ImageService
|
||||
def show(input)
|
||||
Image.find(input.id)
|
||||
WarpEngine::Image.find(input.id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -26,7 +26,7 @@ class RssService
|
||||
end
|
||||
|
||||
def releases_feed
|
||||
releases = Release.includes(:software)
|
||||
releases = WarpEngine::Release.includes(:software)
|
||||
.order(created_at: :desc)
|
||||
.limit(50)
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@ class SoftwareHighlightedService
|
||||
include SoftwareResponseBuilder
|
||||
|
||||
def index
|
||||
software = Software.includes(:external_links, :software_images)
|
||||
software = WarpEngine::Software.includes(:external_links, :software_images)
|
||||
.where(highlighted: true)
|
||||
.order(id: :desc)
|
||||
.first
|
||||
return nil unless software
|
||||
|
||||
releases = Release.includes(:release_assets).where(software_id: software.id).to_a
|
||||
releases = WarpEngine::Release.includes(:release_assets).where(software_id: software.id).to_a
|
||||
build_response(software, releases, download_counts_for(releases.map(&:id)))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,6 +20,6 @@ module SoftwareResponseBuilder
|
||||
# Egyetlen csoportosított lekérdezés release-enkénti letöltésszámokhoz (N+1 helyett).
|
||||
def download_counts_for(release_ids)
|
||||
return {} if release_ids.empty?
|
||||
Download.where(release_id: release_ids).group(:release_id).count
|
||||
WarpEngine::Download.where(release_id: release_ids).group(:release_id).count
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@ class SoftwareService
|
||||
include SoftwareResponseBuilder
|
||||
|
||||
def index
|
||||
softwares = Software.includes(releases: [ :release_assets ]).includes(:external_links, :software_images).all
|
||||
softwares = WarpEngine::Software.includes(releases: [ :release_assets ]).includes(:external_links, :software_images).all
|
||||
counts = download_counts_for(softwares.flat_map { |sw| sw.releases.map(&:id) })
|
||||
{ softwares: softwares.map { |sw| build_response(sw, sw.releases.to_a, counts) } }
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class UpdateService
|
||||
def update(input)
|
||||
unless PlatformLink::SUPPORTED_PLATFORMS.include?(input.platform)
|
||||
unless WarpEngine::PlatformLink::SUPPORTED_PLATFORMS.include?(input.platform)
|
||||
raise ArgumentError, "Unsupported platform: #{input.platform}"
|
||||
end
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ RSpec.describe Api::SoftwareBuildsController, type: :request do
|
||||
let!(:release) { create(:release, software: software, version: "2.0.0") }
|
||||
|
||||
before do
|
||||
ReleaseAsset.create!(release: release, kind: "html", path: "/test/html")
|
||||
WarpEngine::ReleaseAsset.create!(release: release, kind: "html", path: "/test/html")
|
||||
end
|
||||
|
||||
it "returns per-software build info" do
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FactoryBot.define do
|
||||
factory :download do
|
||||
factory :download, class: "WarpEngine::Download" do
|
||||
file_path { "/test/file.tic" }
|
||||
ip_address { "127.0.0.1" }
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FactoryBot.define do
|
||||
factory :platform_link do
|
||||
factory :platform_link, class: "WarpEngine::PlatformLink" do
|
||||
sequence(:name) { |n| "Link #{n}" }
|
||||
platform { "tic80" }
|
||||
url { "https://example.com/link" }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FactoryBot.define do
|
||||
factory :release do
|
||||
factory :release, class: "WarpEngine::Release" do
|
||||
software
|
||||
sequence(:version) { |n| "1.0.#{n}" }
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FactoryBot.define do
|
||||
factory :software do
|
||||
factory :software, class: "WarpEngine::Software" do
|
||||
sequence(:name) { |n| "game-#{n}" }
|
||||
title { "Test Game" }
|
||||
author { "dev" }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Download, type: :model do
|
||||
RSpec.describe WarpEngine::Download, type: :model do
|
||||
it { should validate_presence_of(:file_path) }
|
||||
it { should belong_to(:release).optional }
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe PlatformLink, type: :model do
|
||||
RSpec.describe WarpEngine::PlatformLink, type: :model do
|
||||
describe "validations" do
|
||||
it { should validate_presence_of(:name) }
|
||||
it { should validate_presence_of(:url) }
|
||||
@@ -13,7 +13,7 @@ RSpec.describe PlatformLink, type: :model do
|
||||
end
|
||||
|
||||
it "accepts valid platforms" do
|
||||
PlatformLink::SUPPORTED_PLATFORMS.each do |p|
|
||||
WarpEngine::PlatformLink::SUPPORTED_PLATFORMS.each do |p|
|
||||
link = build(:platform_link, platform: p)
|
||||
expect(link).to be_valid
|
||||
end
|
||||
@@ -25,14 +25,14 @@ RSpec.describe PlatformLink, type: :model do
|
||||
active = create(:platform_link)
|
||||
create(:platform_link, deleted_at: Time.current)
|
||||
|
||||
expect(PlatformLink.all).to eq([active])
|
||||
expect(WarpEngine::PlatformLink.all).to eq([active])
|
||||
end
|
||||
|
||||
it "orders by position" do
|
||||
second = create(:platform_link, position: 2)
|
||||
first = create(:platform_link, position: 1)
|
||||
|
||||
expect(PlatformLink.all).to eq([first, second])
|
||||
expect(WarpEngine::PlatformLink.all).to eq([first, second])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -41,12 +41,12 @@ RSpec.describe PlatformLink, type: :model do
|
||||
tic80_link = create(:platform_link, platform: "tic80")
|
||||
create(:platform_link, platform: "love")
|
||||
|
||||
result = PlatformLink.for_platform("tic80")
|
||||
result = WarpEngine::PlatformLink.for_platform("tic80")
|
||||
expect(result).to eq([tic80_link])
|
||||
end
|
||||
|
||||
it "returns empty array for platform without links" do
|
||||
expect(PlatformLink.for_platform("godot")).to eq([])
|
||||
expect(WarpEngine::PlatformLink.for_platform("godot")).to eq([])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Release, type: :model do
|
||||
RSpec.describe WarpEngine::Release, type: :model do
|
||||
it { should belong_to(:software) }
|
||||
it { should have_many(:downloads) }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Software, type: :model do
|
||||
RSpec.describe WarpEngine::Software, type: :model do
|
||||
subject { build(:software) }
|
||||
|
||||
it { should validate_presence_of(:name) }
|
||||
@@ -19,7 +19,7 @@ RSpec.describe Software, type: :model do
|
||||
active = create(:software)
|
||||
create(:software, deleted_at: Time.current)
|
||||
|
||||
expect(Software.all).to eq([active])
|
||||
expect(WarpEngine::Software.all).to eq([active])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,12 +14,12 @@ RSpec.describe BuildsService do
|
||||
expect(result[:platforms]["c64"][:kinds]).to eq(["cartridge"])
|
||||
end
|
||||
|
||||
it "returns allKinds matching ReleaseAsset::KINDS" do
|
||||
expect(result[:allKinds]).to eq(ReleaseAsset::KINDS)
|
||||
it "returns allKinds matching WarpEngine::ReleaseAsset::KINDS" do
|
||||
expect(result[:allKinds]).to eq(WarpEngine::ReleaseAsset::KINDS)
|
||||
end
|
||||
|
||||
it "includes all supported platforms" do
|
||||
PlatformLink::SUPPORTED_PLATFORMS.each do |platform|
|
||||
WarpEngine::PlatformLink::SUPPORTED_PLATFORMS.each do |platform|
|
||||
expect(result[:platforms]).to have_key(platform)
|
||||
end
|
||||
end
|
||||
@@ -30,8 +30,8 @@ RSpec.describe BuildsService do
|
||||
let!(:release) { create(:release, software: software, version: "1.0.0") }
|
||||
|
||||
before do
|
||||
ReleaseAsset.create!(release: release, kind: "html", path: "/test/html")
|
||||
ReleaseAsset.create!(release: release, kind: "win_x64", path: "/test/win")
|
||||
WarpEngine::ReleaseAsset.create!(release: release, kind: "html", path: "/test/html")
|
||||
WarpEngine::ReleaseAsset.create!(release: release, kind: "win_x64", path: "/test/win")
|
||||
end
|
||||
|
||||
it "returns expected and actual kinds per release" do
|
||||
|
||||
@@ -25,12 +25,12 @@ RSpec.describe SoftwareUpdater::Tic80Service do
|
||||
|
||||
after do
|
||||
FileUtils.remove_entry(tmpdir)
|
||||
Software.unscoped.where(name: name).each do |sw|
|
||||
Release.unscoped.where(software_id: sw.id).each do |r|
|
||||
ReleaseAsset.unscoped.where(release_id: r.id).delete_all
|
||||
WarpEngine::Software.unscoped.where(name: name).each do |sw|
|
||||
WarpEngine::Release.unscoped.where(software_id: sw.id).each do |r|
|
||||
WarpEngine::ReleaseAsset.unscoped.where(release_id: r.id).delete_all
|
||||
r.delete
|
||||
end
|
||||
ExternalLink.unscoped.where(software_id: sw.id).delete_all
|
||||
WarpEngine::ExternalLink.unscoped.where(software_id: sw.id).delete_all
|
||||
sw.delete
|
||||
end
|
||||
end
|
||||
@@ -44,7 +44,7 @@ RSpec.describe SoftwareUpdater::Tic80Service do
|
||||
end
|
||||
|
||||
def asset_kinds(release)
|
||||
ReleaseAsset.unscoped.where(release_id: release.id).pluck(:kind)
|
||||
WarpEngine::ReleaseAsset.unscoped.where(release_id: release.id).pluck(:kind)
|
||||
end
|
||||
|
||||
it "registers the release without a docs zip" do
|
||||
|
||||
Reference in New Issue
Block a user