refact
This commit is contained in:
@@ -96,6 +96,10 @@ ActiveAdmin.register WarpEngine::ApplicationToken, as: "Application Token" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
controller do
|
controller do
|
||||||
|
def scoped_collection
|
||||||
|
super.kept
|
||||||
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
create! do |success, _failure|
|
create! do |success, _failure|
|
||||||
success.html do
|
success.html do
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ ActiveAdmin.register WarpEngine::Download, as: "Download" do
|
|||||||
|
|
||||||
controller do
|
controller do
|
||||||
def scoped_collection
|
def scoped_collection
|
||||||
super.includes(release: :software)
|
super.kept.includes(release: :software)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,6 +5,12 @@ ActiveAdmin.register WarpEngine::ExternalLink, as: "External Link" do
|
|||||||
|
|
||||||
belongs_to :software
|
belongs_to :software
|
||||||
|
|
||||||
|
controller do
|
||||||
|
def scoped_collection
|
||||||
|
super.kept
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
index do
|
index do
|
||||||
selectable_column
|
selectable_column
|
||||||
id_column
|
id_column
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ ActiveAdmin.register WarpEngine::Pipeline, as: "Pipeline" do
|
|||||||
f.inputs do
|
f.inputs do
|
||||||
f.input :platform, as: :select, collection: WarpEngine::PlatformLink::SUPPORTED_PLATFORMS
|
f.input :platform, as: :select, collection: WarpEngine::PlatformLink::SUPPORTED_PLATFORMS
|
||||||
f.input :software_id, as: :select,
|
f.input :software_id, as: :select,
|
||||||
collection: WarpEngine::Software.order(:title).map { |s| [ s.title, s.id ] },
|
collection: WarpEngine::Software.kept.order(:title).map { |s| [ s.title, s.id ] },
|
||||||
include_blank: "- none -",
|
include_blank: "- none -",
|
||||||
hint: "One pipeline per software. Picking one that another pipeline already " \
|
hint: "One pipeline per software. Picking one that another pipeline already " \
|
||||||
"has moves the link here — that pipeline is left without a software, " \
|
"has moves the link here — that pipeline is left without a software, " \
|
||||||
@@ -124,7 +124,7 @@ ActiveAdmin.register WarpEngine::Pipeline, as: "Pipeline" do
|
|||||||
|
|
||||||
controller do
|
controller do
|
||||||
def scoped_collection
|
def scoped_collection
|
||||||
super.includes(:software)
|
super.kept.includes(:software)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ ActiveAdmin.register WarpEngine::PlatformLink, as: "Platform Link" do
|
|||||||
scope("Bevy") { |s| s.where(platform: "bevy") }
|
scope("Bevy") { |s| s.where(platform: "bevy") }
|
||||||
scope("Phaser") { |s| s.where(platform: "phaser") }
|
scope("Phaser") { |s| s.where(platform: "phaser") }
|
||||||
|
|
||||||
|
controller do
|
||||||
|
def scoped_collection
|
||||||
|
super.kept
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
index do
|
index do
|
||||||
selectable_column
|
selectable_column
|
||||||
id_column
|
id_column
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ ActiveAdmin.register WarpEngine::Release, as: "Release" do
|
|||||||
|
|
||||||
filter :version
|
filter :version
|
||||||
|
|
||||||
|
controller do
|
||||||
|
def scoped_collection
|
||||||
|
super.kept
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
show do
|
show do
|
||||||
attributes_table do
|
attributes_table do
|
||||||
row :id
|
row :id
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ ActiveAdmin.register WarpEngine::Software, as: "Software" do
|
|||||||
|
|
||||||
controller do
|
controller do
|
||||||
def scoped_collection
|
def scoped_collection
|
||||||
super.includes({ releases: :release_assets }, software_images: :image)
|
super.kept.includes({ releases: :release_assets }, software_images: :image)
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_resource
|
def find_resource
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ module WarpEngine
|
|||||||
token = current_application_token
|
token = current_application_token
|
||||||
return true if token.nil? || token.unrestricted?
|
return true if token.nil? || token.unrestricted?
|
||||||
|
|
||||||
software = WarpEngine::Software.find_by(name: name)
|
software = WarpEngine::Software.kept.find_by(name: name)
|
||||||
return true if software.nil? || software.owner_id.nil?
|
return true if software.nil? || software.owner_id.nil?
|
||||||
|
|
||||||
software.owner_type == token.owner_type && software.owner_id == token.owner_id
|
software.owner_type == token.owner_type && software.owner_id == token.owner_id
|
||||||
@@ -53,7 +53,7 @@ module WarpEngine
|
|||||||
token = current_application_token
|
token = current_application_token
|
||||||
return if token.nil? || token.unrestricted?
|
return if token.nil? || token.unrestricted?
|
||||||
|
|
||||||
software = WarpEngine::Software.find_by(name: name)
|
software = WarpEngine::Software.kept.find_by(name: name)
|
||||||
return if software.nil? || software.owner_id.present?
|
return if software.nil? || software.owner_id.present?
|
||||||
|
|
||||||
software.update_columns(owner_type: token.owner_type, owner_id: token.owner_id)
|
software.update_columns(owner_type: token.owner_type, owner_id: token.owner_id)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
require "warp_engine/access_denied"
|
||||||
|
|
||||||
module WarpEngine
|
module WarpEngine
|
||||||
class ApiController < ActionController::API
|
class ApiController < ActionController::API
|
||||||
resource_description do
|
resource_description do
|
||||||
@@ -10,7 +12,7 @@ module WarpEngine
|
|||||||
include WarpEngine::ApiErrorRendering
|
include WarpEngine::ApiErrorRendering
|
||||||
include WarpEngine::SubjectAuthentication
|
include WarpEngine::SubjectAuthentication
|
||||||
|
|
||||||
rescue_from WarpEngine::DownloadService::Denied do
|
rescue_from WarpEngine::AccessDenied do
|
||||||
render json: { error: "Forbidden" }, status: :forbidden
|
render json: { error: "Forbidden" }, status: :forbidden
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
module WarpEngine
|
||||||
|
module SoftDeletable
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
scope :kept, -> { where(deleted_at: nil) }
|
||||||
|
scope :discarded, -> { where.not(deleted_at: nil) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def soft_delete!
|
||||||
|
update_column(:deleted_at, Time.current)
|
||||||
|
end
|
||||||
|
|
||||||
|
def restore!
|
||||||
|
update_column(:deleted_at, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
def discarded?
|
||||||
|
deleted_at.present?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,5 +1,13 @@
|
|||||||
module WarpEngine
|
module WarpEngine
|
||||||
class ApplicationRecord < ActiveRecord::Base
|
class ApplicationRecord < ActiveRecord::Base
|
||||||
self.abstract_class = true
|
self.abstract_class = true
|
||||||
|
|
||||||
|
def self.ransackable_attributes(auth_object = nil)
|
||||||
|
column_names
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.ransackable_associations(auth_object = nil)
|
||||||
|
reflect_on_all_associations.map(&:name).map(&:to_s)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,12 +9,13 @@ module WarpEngine
|
|||||||
|
|
||||||
CATALOG_SCOPE = "catalog".freeze
|
CATALOG_SCOPE = "catalog".freeze
|
||||||
|
|
||||||
|
include SoftDeletable
|
||||||
|
|
||||||
attr_reader :plain_token
|
attr_reader :plain_token
|
||||||
|
|
||||||
belongs_to :owner, polymorphic: true
|
belongs_to :owner, polymorphic: true
|
||||||
|
|
||||||
default_scope { where(deleted_at: nil) }
|
scope :active, -> { kept.where("expires_at IS NULL OR expires_at > ?", Time.current) }
|
||||||
scope :active, -> { where("expires_at IS NULL OR expires_at > ?", Time.current) }
|
|
||||||
|
|
||||||
before_validation :assign_owner_type, on: :create
|
before_validation :assign_owner_type, on: :create
|
||||||
before_validation :generate_token, on: :create
|
before_validation :generate_token, on: :create
|
||||||
@@ -45,7 +46,7 @@ module WarpEngine
|
|||||||
end
|
end
|
||||||
|
|
||||||
def revoke!
|
def revoke!
|
||||||
update_column(:deleted_at, Time.current)
|
soft_delete!
|
||||||
end
|
end
|
||||||
|
|
||||||
def touch_last_used!
|
def touch_last_used!
|
||||||
@@ -60,10 +61,6 @@ module WarpEngine
|
|||||||
self.scopes = value.to_s.split(",").map(&:strip).reject(&:blank?).uniq
|
self.scopes = value.to_s.split(",").map(&:strip).reject(&:blank?).uniq
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.ransackable_attributes(auth_object = nil)
|
|
||||||
%w[created_at deleted_at expires_at id last_used_at name owner_id owner_type token_prefix unrestricted updated_at]
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.ransackable_associations(auth_object = nil)
|
def self.ransackable_associations(auth_object = nil)
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -46,10 +46,6 @@ module WarpEngine
|
|||||||
where(expires_at: ...Time.current).where.not(issued_token: nil).update_all(issued_token: nil)
|
where(expires_at: ...Time.current).where.not(issued_token: nil).update_all(issued_token: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.ransackable_attributes(auth_object = nil)
|
|
||||||
%w[approved_at client_name created_at denied_at expires_at id subject_id subject_type updated_at user_code]
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.ransackable_associations(auth_object = nil)
|
def self.ransackable_associations(auth_object = nil)
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,19 +1,11 @@
|
|||||||
module WarpEngine
|
module WarpEngine
|
||||||
class Download < ApplicationRecord
|
class Download < ApplicationRecord
|
||||||
|
include SoftDeletable
|
||||||
|
|
||||||
belongs_to :release, optional: true
|
belongs_to :release, optional: true
|
||||||
|
|
||||||
validates :file_path, presence: 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
|
|
||||||
|
|
||||||
ActiveSupport.run_load_hooks(:warp_engine_download, self)
|
ActiveSupport.run_load_hooks(:warp_engine_download, self)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,21 +2,13 @@ module WarpEngine
|
|||||||
class ExternalLink < ApplicationRecord
|
class ExternalLink < ApplicationRecord
|
||||||
self.table_name = "external_links"
|
self.table_name = "external_links"
|
||||||
|
|
||||||
|
include SoftDeletable
|
||||||
|
|
||||||
belongs_to :software
|
belongs_to :software
|
||||||
|
|
||||||
validates :label, presence: true
|
validates :label, presence: true
|
||||||
validates :url, 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
|
|
||||||
|
|
||||||
ActiveSupport.run_load_hooks(:warp_engine_external_link, self)
|
ActiveSupport.run_load_hooks(:warp_engine_external_link, self)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ module WarpEngine
|
|||||||
|
|
||||||
UNKNOWN_PLATFORM = "unknown".freeze
|
UNKNOWN_PLATFORM = "unknown".freeze
|
||||||
|
|
||||||
|
include SoftDeletable
|
||||||
|
|
||||||
belongs_to :software, class_name: "WarpEngine::Software", optional: true
|
belongs_to :software, class_name: "WarpEngine::Software", optional: true
|
||||||
|
|
||||||
attr_reader :software_taken_from
|
attr_reader :software_taken_from
|
||||||
|
|
||||||
default_scope { where(deleted_at: nil) }
|
|
||||||
|
|
||||||
before_save :claim_software_from_other_pipelines, if: :will_save_change_to_software_id?
|
before_save :claim_software_from_other_pipelines, if: :will_save_change_to_software_id?
|
||||||
|
|
||||||
validates :woodpecker_repo_id, presence: true, uniqueness: true
|
validates :woodpecker_repo_id, presence: true, uniqueness: true
|
||||||
@@ -18,7 +18,9 @@ module WarpEngine
|
|||||||
validates :platform, presence: true,
|
validates :platform, presence: true,
|
||||||
inclusion: { in: WarpEngine::PlatformLink::SUPPORTED_PLATFORMS + [ UNKNOWN_PLATFORM ] }
|
inclusion: { in: WarpEngine::PlatformLink::SUPPORTED_PLATFORMS + [ UNKNOWN_PLATFORM ] }
|
||||||
|
|
||||||
scope :active, -> { where(active: true) }
|
scope :active, -> { kept.where(active: true) }
|
||||||
|
|
||||||
|
scope :by_remote_repo_id, ->(id) { where(woodpecker_repo_id: id) }
|
||||||
|
|
||||||
def full_name
|
def full_name
|
||||||
"#{repo_owner}/#{repo_name}"
|
"#{repo_owner}/#{repo_name}"
|
||||||
@@ -32,13 +34,8 @@ module WarpEngine
|
|||||||
self.woodpecker_repo_id = value
|
self.woodpecker_repo_id = value
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.ransackable_attributes(auth_object = nil)
|
def self.find_or_initialize_by_remote_repo_id(id)
|
||||||
%w[active created_at deleted_at id last_pipeline_at last_pipeline_status
|
find_or_initialize_by(woodpecker_repo_id: id)
|
||||||
platform repo_name repo_owner software_id woodpecker_repo_id]
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.ransackable_associations(auth_object = nil)
|
|
||||||
%w[software]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -4,23 +4,16 @@ module WarpEngine
|
|||||||
|
|
||||||
SUPPORTED_PLATFORMS = WarpEngine::Platform::NAMES
|
SUPPORTED_PLATFORMS = WarpEngine::Platform::NAMES
|
||||||
|
|
||||||
|
include SoftDeletable
|
||||||
|
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
validates :url, presence: true
|
validates :url, presence: true
|
||||||
validates :platform, presence: true, inclusion: { in: SUPPORTED_PLATFORMS }
|
validates :platform, presence: true, inclusion: { in: SUPPORTED_PLATFORMS }
|
||||||
|
|
||||||
default_scope { where(deleted_at: nil) }
|
|
||||||
scope :ordered, -> { order(:position) }
|
scope :ordered, -> { 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)
|
def self.for_platform(platform)
|
||||||
ordered.where(platform: platform).to_a
|
kept.ordered.where(platform: platform).to_a
|
||||||
end
|
end
|
||||||
|
|
||||||
ActiveSupport.run_load_hooks(:warp_engine_platform_link, self)
|
ActiveSupport.run_load_hooks(:warp_engine_platform_link, self)
|
||||||
|
|||||||
@@ -2,19 +2,25 @@ module WarpEngine
|
|||||||
class Release < ApplicationRecord
|
class Release < ApplicationRecord
|
||||||
self.table_name = "releases"
|
self.table_name = "releases"
|
||||||
|
|
||||||
|
include SoftDeletable
|
||||||
|
|
||||||
belongs_to :software
|
belongs_to :software
|
||||||
has_many :downloads
|
has_many :downloads, -> { kept }
|
||||||
has_many :release_assets
|
has_many :release_assets, -> { kept }
|
||||||
|
|
||||||
accepts_nested_attributes_for :release_assets, allow_destroy: true
|
accepts_nested_attributes_for :release_assets, allow_destroy: true
|
||||||
|
|
||||||
validates :version, presence: true
|
validates :version, presence: true
|
||||||
validates :version, uniqueness: { scope: :software_id }
|
validates :version, uniqueness: { scope: :software_id }
|
||||||
|
|
||||||
default_scope { where(deleted_at: nil) }
|
|
||||||
|
|
||||||
validate :c64_cannot_be_web_playable
|
validate :c64_cannot_be_web_playable
|
||||||
|
|
||||||
|
def self.latest_non_dev(releases)
|
||||||
|
sorted = releases.sort_by { |r| [r.created_at || Time.at(0), r.id] }.reverse
|
||||||
|
candidates = sorted.reject { |r| r.version.to_s.start_with?("dev-") }
|
||||||
|
candidates.empty? ? sorted.first : candidates.first
|
||||||
|
end
|
||||||
|
|
||||||
def c64_cannot_be_web_playable
|
def c64_cannot_be_web_playable
|
||||||
return unless software&.platform == "c64"
|
return unless software&.platform == "c64"
|
||||||
|
|
||||||
@@ -24,14 +30,6 @@ module WarpEngine
|
|||||||
end
|
end
|
||||||
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
|
|
||||||
|
|
||||||
ActiveSupport.run_load_hooks(:warp_engine_release, self)
|
ActiveSupport.run_load_hooks(:warp_engine_release, self)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ module WarpEngine
|
|||||||
win_x86 win_x64 linux_x86 linux_x64 linux_arm64
|
win_x86 win_x64 linux_x86 linux_x64 linux_arm64
|
||||||
mac_x64 mac_arm64 mac_universal].freeze
|
mac_x64 mac_arm64 mac_universal].freeze
|
||||||
|
|
||||||
|
include SoftDeletable
|
||||||
|
|
||||||
belongs_to :release
|
belongs_to :release
|
||||||
|
|
||||||
enum :kind, KINDS.index_by(&:itself)
|
enum :kind, KINDS.index_by(&:itself)
|
||||||
@@ -11,21 +13,11 @@ module WarpEngine
|
|||||||
validates :path, presence: true
|
validates :path, presence: true
|
||||||
validates :kind, uniqueness: { scope: :release_id }
|
validates :kind, uniqueness: { scope: :release_id }
|
||||||
|
|
||||||
default_scope { where(deleted_at: nil) }
|
|
||||||
|
|
||||||
def self.for_relative_path(relative)
|
def self.for_relative_path(relative)
|
||||||
absolute = File.join(WarpEngine.config.file_container_path, relative.to_s)
|
absolute = File.join(WarpEngine.config.file_container_path, relative.to_s)
|
||||||
find_by(path: absolute) || where("path LIKE ?", "%/#{sanitize_sql_like(relative.to_s)}").first
|
find_by(path: absolute) || where("path LIKE ?", "%/#{sanitize_sql_like(relative.to_s)}").first
|
||||||
end
|
end
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
ActiveSupport.run_load_hooks(:warp_engine_release_asset, self)
|
ActiveSupport.run_load_hooks(:warp_engine_release_asset, self)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,14 +4,16 @@ module WarpEngine
|
|||||||
|
|
||||||
STATUSES = %w[development demo released archived].freeze
|
STATUSES = %w[development demo released archived].freeze
|
||||||
|
|
||||||
|
include SoftDeletable
|
||||||
|
|
||||||
belongs_to :owner, polymorphic: true, optional: true
|
belongs_to :owner, polymorphic: true, optional: true
|
||||||
|
|
||||||
has_many :software_images, -> { ordered }, foreign_key: :software_id, dependent: :destroy
|
has_many :software_images, -> { ordered }, foreign_key: :software_id, dependent: :destroy
|
||||||
has_many :images, through: :software_images
|
has_many :images, through: :software_images
|
||||||
has_many :releases, foreign_key: :software_id
|
has_many :releases, -> { kept }, foreign_key: :software_id
|
||||||
has_many :downloads, through: :releases
|
has_many :downloads, through: :releases
|
||||||
has_many :external_links, foreign_key: :software_id
|
has_many :external_links, -> { kept }, foreign_key: :software_id
|
||||||
has_one :pipeline, foreign_key: :software_id
|
has_one :pipeline, -> { kept }, foreign_key: :software_id
|
||||||
|
|
||||||
accepts_nested_attributes_for :software_images, allow_destroy: true
|
accepts_nested_attributes_for :software_images, allow_destroy: true
|
||||||
accepts_nested_attributes_for :external_links, allow_destroy: true
|
accepts_nested_attributes_for :external_links, allow_destroy: true
|
||||||
@@ -22,16 +24,6 @@ module WarpEngine
|
|||||||
validates :platform, presence: true, inclusion: { in: WarpEngine::Platform::NAMES }
|
validates :platform, presence: true, inclusion: { in: WarpEngine::Platform::NAMES }
|
||||||
validates :status, inclusion: { in: STATUSES }, allow_blank: true
|
validates :status, inclusion: { in: STATUSES }, allow_blank: true
|
||||||
|
|
||||||
default_scope { where(deleted_at: nil) }
|
|
||||||
|
|
||||||
def self.ransackable_attributes(auth_object = nil)
|
|
||||||
%w[author created_at desc highlighted id license name owner_id owner_type platform site status story title updated_at]
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.ransackable_associations(auth_object = nil)
|
|
||||||
%w[releases external_links software_images images]
|
|
||||||
end
|
|
||||||
|
|
||||||
ActiveSupport.run_load_hooks(:warp_engine_software, self)
|
ActiveSupport.run_load_hooks(:warp_engine_software, self)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -15,14 +15,6 @@ module WarpEngine
|
|||||||
|
|
||||||
scope :ordered, -> { order(:position) }
|
scope :ordered, -> { 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
|
|
||||||
|
|
||||||
ActiveSupport.run_load_hooks(:warp_engine_software_image, self)
|
ActiveSupport.run_load_hooks(:warp_engine_software_image, self)
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
module WarpEngine
|
||||||
|
module AccessPolicyGuard
|
||||||
|
private
|
||||||
|
|
||||||
|
def authorize_download!(asset:, subject:, request: nil)
|
||||||
|
grant = WarpEngine.access_policy.authorize_download(asset: asset, subject: subject, request: request)
|
||||||
|
raise WarpEngine::AccessDenied if grant.nil?
|
||||||
|
grant
|
||||||
|
rescue WarpEngine::AccessDenied
|
||||||
|
raise
|
||||||
|
rescue StandardError => e
|
||||||
|
Rails.logger.error("[WarpEngine::AccessPolicy] #{e.class}: #{e.message}")
|
||||||
|
raise WarpEngine::AccessDenied
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -11,6 +11,19 @@ module WarpEngine
|
|||||||
raw = JSON.parse(File.read(path), symbolize_names: true)
|
raw = JSON.parse(File.read(path), symbolize_names: true)
|
||||||
raw.slice(*METADATA_KEYS)
|
raw.slice(*METADATA_KEYS)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def parse_lua_metadata(source_path)
|
||||||
|
metadata = {}
|
||||||
|
File.foreach(source_path) do |line|
|
||||||
|
break unless line.start_with?("--")
|
||||||
|
parts = line[2..].split(":", 2)
|
||||||
|
next if parts.length != 2
|
||||||
|
key = parts[0].strip.downcase.to_sym
|
||||||
|
value = parts[1].strip
|
||||||
|
metadata[key] = value
|
||||||
|
end
|
||||||
|
metadata.slice(*METADATA_KEYS)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ module WarpEngine
|
|||||||
private
|
private
|
||||||
|
|
||||||
def update_or_create_software(attrs)
|
def update_or_create_software(attrs)
|
||||||
software = WarpEngine::Software.unscoped.find_or_initialize_by(name: attrs[:name])
|
software = WarpEngine::Software.find_or_initialize_by(name: attrs[:name])
|
||||||
software.assign_attributes(attrs.except(:name))
|
software.assign_attributes(attrs.except(:name))
|
||||||
software.deleted_at = nil
|
software.deleted_at = nil
|
||||||
software.save!
|
software.save!
|
||||||
@@ -12,14 +12,14 @@ module WarpEngine
|
|||||||
end
|
end
|
||||||
|
|
||||||
def upsert_external_link(software_id, label, url)
|
def upsert_external_link(software_id, label, url)
|
||||||
link = WarpEngine::ExternalLink.unscoped.find_or_initialize_by(software_id: software_id, label: label)
|
link = WarpEngine::ExternalLink.find_or_initialize_by(software_id: software_id, label: label)
|
||||||
link.url = url
|
link.url = url
|
||||||
link.deleted_at = nil
|
link.deleted_at = nil
|
||||||
link.save!
|
link.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_release_if_not_exists(attrs)
|
def create_release_if_not_exists(attrs)
|
||||||
existing = WarpEngine::Release.unscoped.find_by(software_id: attrs[:software_id], version: attrs[:version])
|
existing = WarpEngine::Release.find_by(software_id: attrs[:software_id], version: attrs[:version])
|
||||||
return existing if existing
|
return existing if existing
|
||||||
|
|
||||||
WarpEngine::Release.create!(attrs)
|
WarpEngine::Release.create!(attrs)
|
||||||
@@ -27,7 +27,7 @@ module WarpEngine
|
|||||||
|
|
||||||
def sync_release_assets(release, kind_paths)
|
def sync_release_assets(release, kind_paths)
|
||||||
kind_paths.each do |kind, path|
|
kind_paths.each do |kind, path|
|
||||||
asset = WarpEngine::ReleaseAsset.unscoped.find_or_initialize_by(release_id: release.id, kind: kind)
|
asset = WarpEngine::ReleaseAsset.find_or_initialize_by(release_id: release.id, kind: kind)
|
||||||
asset.path = path
|
asset.path = path
|
||||||
asset.deleted_at = nil
|
asset.deleted_at = nil
|
||||||
asset.save!
|
asset.save!
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ module WarpEngine
|
|||||||
private
|
private
|
||||||
|
|
||||||
def scope
|
def scope
|
||||||
relation = WarpEngine::Software.order(:name).includes(releases: :release_assets)
|
relation = WarpEngine::Software.kept.order(:name).includes(releases: :release_assets)
|
||||||
relation = relation.where(name: name) if name
|
relation = relation.where(name: name) if name
|
||||||
relation = relation.where(platform: platform) if platform
|
relation = relation.where(platform: platform) if platform
|
||||||
relation
|
relation
|
||||||
@@ -113,9 +113,7 @@ module WarpEngine
|
|||||||
def sorted(all) = all.sort_by { |release| [ release.created_at || Time.at(0), release.id ] }.reverse
|
def sorted(all) = all.sort_by { |release| [ release.created_at || Time.at(0), release.id ] }.reverse
|
||||||
|
|
||||||
def latest(all)
|
def latest(all)
|
||||||
candidates = all.reject { |release| release.version.to_s.start_with?("dev-") }
|
Release.latest_non_dev(all)
|
||||||
candidates = all if candidates.empty?
|
|
||||||
sorted(candidates).first
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ module WarpEngine
|
|||||||
end
|
end
|
||||||
|
|
||||||
def show(name)
|
def show(name)
|
||||||
software = WarpEngine::Software.find_by!(name: name)
|
software = WarpEngine::Software.kept.find_by!(name: name)
|
||||||
expected = WarpEngine::Platform.find!(software.platform).expected_kinds
|
expected = WarpEngine::Platform.find!(software.platform).expected_kinds
|
||||||
|
|
||||||
releases = software.releases.includes(:release_assets).order(updated_at: :desc)
|
releases = software.releases.includes(:release_assets).order(updated_at: :desc)
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
|
require "warp_engine/access_denied"
|
||||||
|
|
||||||
module WarpEngine
|
module WarpEngine
|
||||||
class DownloadService
|
class DownloadService
|
||||||
|
|
||||||
class Denied < StandardError; end
|
Denied = WarpEngine::AccessDenied
|
||||||
|
|
||||||
|
include AccessPolicyGuard
|
||||||
|
|
||||||
def locate(path:, ip:, user_agent:, referer:, subject: nil, request: nil)
|
def locate(path:, ip:, user_agent:, referer:, subject: nil, request: nil)
|
||||||
relative = path.to_s
|
relative = path.to_s
|
||||||
return nil unless storage.file?(relative)
|
return nil unless storage.file?(relative)
|
||||||
|
|
||||||
asset = find_asset(relative)
|
asset = find_asset(relative)
|
||||||
grant = authorize!(asset, subject, request)
|
grant = authorize_download!(asset: asset, subject: subject, request: request)
|
||||||
|
|
||||||
log_download(relative, asset: asset, ip: ip, user_agent: user_agent, referer: referer, subject: subject)
|
log_download(relative, asset: asset, ip: ip, user_agent: user_agent, referer: referer, subject: subject)
|
||||||
|
|
||||||
@@ -31,18 +35,6 @@ module WarpEngine
|
|||||||
WarpEngine.storage
|
WarpEngine.storage
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorize!(asset, subject, request)
|
|
||||||
grant = WarpEngine.access_policy.authorize_download(asset: asset, subject: subject, request: request)
|
|
||||||
raise Denied if grant.nil?
|
|
||||||
|
|
||||||
grant
|
|
||||||
rescue Denied
|
|
||||||
raise
|
|
||||||
rescue StandardError => e
|
|
||||||
Rails.logger.error("[WarpEngine::AccessPolicy] #{e.class}: #{e.message}")
|
|
||||||
raise Denied
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_asset(relative)
|
def find_asset(relative)
|
||||||
WarpEngine::ReleaseAsset.for_relative_path(relative)
|
WarpEngine::ReleaseAsset.for_relative_path(relative)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ module WarpEngine
|
|||||||
|
|
||||||
safe_name = sanitize_name(uploaded_file.original_filename)
|
safe_name = sanitize_name(uploaded_file.original_filename)
|
||||||
target = dir.join(safe_name)
|
target = dir.join(safe_name)
|
||||||
raise ArgumentError, "Path escape" unless target.to_s.start_with?(base_path.to_s)
|
ensure_within_base!(target)
|
||||||
|
|
||||||
IO.copy_stream(uploaded_file.to_io, target.to_s)
|
IO.copy_stream(uploaded_file.to_io, target.to_s)
|
||||||
target.relative_path_from(base_path).to_s
|
target.relative_path_from(base_path).to_s
|
||||||
@@ -53,7 +53,7 @@ module WarpEngine
|
|||||||
|
|
||||||
safe_name = sanitize_name(new_name)
|
safe_name = sanitize_name(new_name)
|
||||||
new_full = full.parent.join(safe_name)
|
new_full = full.parent.join(safe_name)
|
||||||
raise ArgumentError, "Path escape" unless new_full.to_s.start_with?(base_path.to_s)
|
ensure_within_base!(new_full)
|
||||||
|
|
||||||
full.rename(new_full)
|
full.rename(new_full)
|
||||||
new_full.relative_path_from(base_path).to_s
|
new_full.relative_path_from(base_path).to_s
|
||||||
@@ -65,7 +65,7 @@ module WarpEngine
|
|||||||
|
|
||||||
safe_name = sanitize_name(folder_name)
|
safe_name = sanitize_name(folder_name)
|
||||||
new_dir = parent.join(safe_name)
|
new_dir = parent.join(safe_name)
|
||||||
raise ArgumentError, "Path escape" unless new_dir.to_s.start_with?(base_path.to_s)
|
ensure_within_base!(new_dir)
|
||||||
|
|
||||||
new_dir.mkdir
|
new_dir.mkdir
|
||||||
new_dir.relative_path_from(base_path).to_s
|
new_dir.relative_path_from(base_path).to_s
|
||||||
@@ -73,6 +73,10 @@ module WarpEngine
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def ensure_within_base!(path)
|
||||||
|
raise ArgumentError, "Path escape" unless path.to_s.start_with?(base_path.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
def safe_path!(relative_path)
|
def safe_path!(relative_path)
|
||||||
cleaned = relative_path.to_s.gsub("..", "").squeeze("/").gsub(%r{^/|/$}, "")
|
cleaned = relative_path.to_s.gsub("..", "").squeeze("/").gsub(%r{^/|/$}, "")
|
||||||
full = base_path.join(cleaned)
|
full = base_path.join(cleaned)
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
|
require "warp_engine/access_denied"
|
||||||
|
|
||||||
module WarpEngine
|
module WarpEngine
|
||||||
class FileService
|
class FileService
|
||||||
|
|
||||||
|
include AccessPolicyGuard
|
||||||
|
|
||||||
def show(input, subject: nil)
|
def show(input, subject: nil)
|
||||||
relative = input.path.to_s
|
relative = input.path.to_s
|
||||||
|
|
||||||
@@ -21,19 +25,10 @@ module WarpEngine
|
|||||||
private
|
private
|
||||||
|
|
||||||
def authorize!(relative, subject)
|
def authorize!(relative, subject)
|
||||||
|
|
||||||
return WarpEngine::Access::Grant::OPEN if WarpEngine::AccessPolicy.open?
|
return WarpEngine::Access::Grant::OPEN if WarpEngine::AccessPolicy.open?
|
||||||
|
|
||||||
asset = WarpEngine::ReleaseAsset.for_relative_path(relative)
|
asset = WarpEngine::ReleaseAsset.for_relative_path(relative)
|
||||||
grant = WarpEngine.access_policy.authorize_download(asset: asset, subject: subject, request: nil)
|
authorize_download!(asset: asset, subject: subject, request: nil)
|
||||||
raise WarpEngine::DownloadService::Denied if grant.nil?
|
|
||||||
|
|
||||||
grant
|
|
||||||
rescue WarpEngine::DownloadService::Denied
|
|
||||||
raise
|
|
||||||
rescue StandardError => e
|
|
||||||
Rails.logger.error("[WarpEngine::AccessPolicy] #{e.class}: #{e.message}")
|
|
||||||
raise WarpEngine::DownloadService::Denied
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def storage
|
def storage
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ module WarpEngine
|
|||||||
remote_ids = remote_repos.map(&:id)
|
remote_ids = remote_repos.map(&:id)
|
||||||
|
|
||||||
remote_repos.each do |remote|
|
remote_repos.each do |remote|
|
||||||
record = Pipeline.unscoped.find_or_initialize_by(woodpecker_repo_id: remote.id)
|
record = Pipeline.find_or_initialize_by_remote_repo_id(remote.id)
|
||||||
|
|
||||||
was_new = record.new_record?
|
was_new = record.new_record?
|
||||||
record.assign_attributes(
|
record.assign_attributes(
|
||||||
@@ -27,7 +27,7 @@ module WarpEngine
|
|||||||
results[was_new ? :created : :updated] << record
|
results[was_new ? :created : :updated] << record
|
||||||
end
|
end
|
||||||
|
|
||||||
Pipeline.where.not(woodpecker_repo_id: remote_ids).find_each do |orphan|
|
Pipeline.kept.where.not(woodpecker_repo_id: remote_ids).find_each do |orphan|
|
||||||
orphan.update!(active: false) if orphan.active?
|
orphan.update!(active: false) if orphan.active?
|
||||||
results[:deactivated] << orphan
|
results[:deactivated] << orphan
|
||||||
end
|
end
|
||||||
@@ -42,7 +42,7 @@ module WarpEngine
|
|||||||
|
|
||||||
def deactivate(repo_id)
|
def deactivate(repo_id)
|
||||||
@ci.deactivate_repo(repo_id)
|
@ci.deactivate_repo(repo_id)
|
||||||
record = Pipeline.find_by!(woodpecker_repo_id: repo_id)
|
record = Pipeline.kept.find_by!(woodpecker_repo_id: repo_id)
|
||||||
record.update!(active: false)
|
record.update!(active: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ module WarpEngine
|
|||||||
|
|
||||||
def sync_single(repo_id)
|
def sync_single(repo_id)
|
||||||
remote = @ci.repo(repo_id)
|
remote = @ci.repo(repo_id)
|
||||||
record = Pipeline.unscoped.find_or_initialize_by(woodpecker_repo_id: repo_id)
|
record = Pipeline.find_or_initialize_by_remote_repo_id(repo_id)
|
||||||
record.assign_attributes(
|
record.assign_attributes(
|
||||||
repo_name: remote.name, repo_owner: remote.owner,
|
repo_name: remote.name, repo_owner: remote.owner,
|
||||||
active: remote.active?, deleted_at: nil
|
active: remote.active?, deleted_at: nil
|
||||||
@@ -63,7 +63,7 @@ module WarpEngine
|
|||||||
def assign_platform(record, repo_name)
|
def assign_platform(record, repo_name)
|
||||||
return unless record.platform.blank? || record.platform == Pipeline::UNKNOWN_PLATFORM
|
return unless record.platform.blank? || record.platform == Pipeline::UNKNOWN_PLATFORM
|
||||||
|
|
||||||
sw = Software.find_by(name: repo_name)
|
sw = Software.kept.find_by(name: repo_name)
|
||||||
record.platform = sw&.platform || Pipeline::UNKNOWN_PLATFORM
|
record.platform = sw&.platform || Pipeline::UNKNOWN_PLATFORM
|
||||||
record.software = sw if sw
|
record.software = sw if sw
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -21,19 +21,6 @@ module WarpEngine
|
|||||||
def parse_metadata(versioned)
|
def parse_metadata(versioned)
|
||||||
parse_lua_metadata(full_path("#{versioned}.lua"))
|
parse_lua_metadata(full_path("#{versioned}.lua"))
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_lua_metadata(source_path)
|
|
||||||
metadata = {}
|
|
||||||
File.foreach(source_path) do |line|
|
|
||||||
break unless line.start_with?("--")
|
|
||||||
parts = line[2..].split(":", 2)
|
|
||||||
next if parts.length != 2
|
|
||||||
key = parts[0].strip.downcase.to_sym
|
|
||||||
value = parts[1].strip
|
|
||||||
metadata[key] = value
|
|
||||||
end
|
|
||||||
metadata.slice(*MetadataParsing::METADATA_KEYS)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ module WarpEngine
|
|||||||
pipelines = pipelines_for_token(application_token)
|
pipelines = pipelines_for_token(application_token)
|
||||||
return { rotated: false, reason: "no pipelines" } if pipelines.empty?
|
return { rotated: false, reason: "no pipelines" } if pipelines.empty?
|
||||||
|
|
||||||
|
new_token = nil
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
new_token = ApplicationToken.create!(
|
new_token = ApplicationToken.create!(
|
||||||
name: "#{application_token.name} (rotated #{Date.current})",
|
name: "#{application_token.name} (rotated #{Date.current})",
|
||||||
owner_id: application_token.owner_id,
|
owner_id: application_token.owner_id,
|
||||||
@@ -44,14 +46,18 @@ module WarpEngine
|
|||||||
expires_at: application_token.expires_at,
|
expires_at: application_token.expires_at,
|
||||||
unrestricted: application_token.unrestricted?
|
unrestricted: application_token.unrestricted?
|
||||||
)
|
)
|
||||||
|
application_token.soft_delete!
|
||||||
|
end
|
||||||
|
|
||||||
result = provision(new_token.plain_token, pipelines: pipelines)
|
result = provision(new_token.plain_token, pipelines: pipelines)
|
||||||
|
|
||||||
if result[:synced].any?
|
if result[:synced].any?
|
||||||
application_token.revoke!
|
|
||||||
{ rotated: true, new_token: new_token, sync_result: result }
|
{ rotated: true, new_token: new_token, sync_result: result }
|
||||||
else
|
else
|
||||||
new_token.revoke!
|
ActiveRecord::Base.transaction do
|
||||||
|
application_token.restore!
|
||||||
|
new_token.soft_delete!
|
||||||
|
end
|
||||||
{ rotated: false, reason: "all pipelines failed", sync_result: result }
|
{ rotated: false, reason: "all pipelines failed", sync_result: result }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -60,7 +66,7 @@ module WarpEngine
|
|||||||
if application_token.unrestricted?
|
if application_token.unrestricted?
|
||||||
Pipeline.active.to_a
|
Pipeline.active.to_a
|
||||||
else
|
else
|
||||||
software_ids = Software.where(
|
software_ids = Software.kept.where(
|
||||||
owner_type: application_token.owner_type,
|
owner_type: application_token.owner_type,
|
||||||
owner_id: application_token.owner_id
|
owner_id: application_token.owner_id
|
||||||
).pluck(:id)
|
).pluck(:id)
|
||||||
|
|||||||
@@ -3,13 +3,15 @@ module WarpEngine
|
|||||||
include SoftwareResponseBuilder
|
include SoftwareResponseBuilder
|
||||||
|
|
||||||
def index(subject: nil)
|
def index(subject: nil)
|
||||||
software = visible_scope(subject).includes(:external_links, :software_images)
|
software = visible_scope(subject)
|
||||||
|
.includes(releases: :release_assets)
|
||||||
|
.includes(:external_links, :software_images)
|
||||||
.where(highlighted: true)
|
.where(highlighted: true)
|
||||||
.order(id: :desc)
|
.order(id: :desc)
|
||||||
.first
|
.first
|
||||||
return nil unless software
|
return nil unless software
|
||||||
|
|
||||||
releases = WarpEngine::Release.includes(:release_assets).where(software_id: software.id).to_a
|
releases = software.releases.to_a
|
||||||
build_response(software, releases, download_counts_for(releases.map(&:id)), subject: subject)
|
build_response(software, releases, download_counts_for(releases.map(&:id)), subject: subject)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ module WarpEngine
|
|||||||
|
|
||||||
def build_response(software, releases, download_counts, subject: nil)
|
def build_response(software, releases, download_counts, subject: nil)
|
||||||
sorted = releases.sort_by { |r| r.created_at || Time.at(0) }.reverse
|
sorted = releases.sort_by { |r| r.created_at || Time.at(0) }.reverse
|
||||||
latest = sorted.reject { |r| r.version.to_s.start_with?("dev-") }.first
|
latest = Release.latest_non_dev(releases)
|
||||||
|
|
||||||
web_playable = latest if latest&.release_assets&.any? { |a| a.kind == "html" }
|
web_playable = latest if latest&.release_assets&.any? { |a| a.kind == "html" }
|
||||||
total_downloads = releases.sum { |r| download_counts.fetch(r.id, 0) }
|
total_downloads = releases.sum { |r| download_counts.fetch(r.id, 0) }
|
||||||
@@ -36,7 +36,7 @@ module WarpEngine
|
|||||||
|
|
||||||
def download_counts_for(release_ids)
|
def download_counts_for(release_ids)
|
||||||
return {} if release_ids.empty?
|
return {} if release_ids.empty?
|
||||||
WarpEngine::Download.where(release_id: release_ids).group(:release_id).count
|
WarpEngine::Download.kept.where(release_id: release_ids).group(:release_id).count
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ require "warp_engine/configuration"
|
|||||||
require "warp_engine/platform"
|
require "warp_engine/platform"
|
||||||
require "warp_engine/storage"
|
require "warp_engine/storage"
|
||||||
require "warp_engine/access"
|
require "warp_engine/access"
|
||||||
|
require "warp_engine/access_denied"
|
||||||
require "warp_engine/images"
|
require "warp_engine/images"
|
||||||
require "warp_engine/ci"
|
require "warp_engine/ci"
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ module WarpEngine
|
|||||||
|
|
||||||
class Open
|
class Open
|
||||||
def visible_software_scope(subject: nil)
|
def visible_software_scope(subject: nil)
|
||||||
WarpEngine::Software.all
|
WarpEngine::Software.kept
|
||||||
end
|
end
|
||||||
|
|
||||||
def access_for(software:, subject: nil)
|
def access_for(software:, subject: nil)
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
module WarpEngine
|
||||||
|
class AccessDenied < StandardError; end
|
||||||
|
end
|
||||||
@@ -109,8 +109,8 @@ RSpec.describe WarpEngine::ApplicationToken, type: :model do
|
|||||||
token = create(:application_token)
|
token = create(:application_token)
|
||||||
token.revoke!
|
token.revoke!
|
||||||
|
|
||||||
expect(described_class.find_by(id: token.id)).to be_nil
|
expect(described_class.kept.find_by(id: token.id)).to be_nil
|
||||||
expect(described_class.unscoped.find(token.id).deleted_at).to be_present
|
expect(described_class.find(token.id).deleted_at).to be_present
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -36,18 +36,24 @@ RSpec.describe WarpEngine::Pipeline do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "default_scope" do
|
describe ".kept scope" do
|
||||||
it "excludes soft-deleted records" do
|
it "excludes soft-deleted records" do
|
||||||
repo = create(:pipeline)
|
repo = create(:pipeline)
|
||||||
repo.update_column(:deleted_at, Time.current)
|
repo.update_column(:deleted_at, Time.current)
|
||||||
|
|
||||||
expect(described_class.all).not_to include(repo)
|
expect(described_class.kept).not_to include(repo)
|
||||||
expect(described_class.unscoped).to include(repo)
|
end
|
||||||
|
|
||||||
|
it "includes soft-deleted records without scope" do
|
||||||
|
repo = create(:pipeline)
|
||||||
|
repo.update_column(:deleted_at, Time.current)
|
||||||
|
|
||||||
|
expect(described_class.all).to include(repo)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe ".active" do
|
describe ".active" do
|
||||||
it "returns only active repos" do
|
it "returns only active kept repos" do
|
||||||
active = create(:pipeline, active: true)
|
active = create(:pipeline, active: true)
|
||||||
inactive = create(:pipeline, active: false)
|
inactive = create(:pipeline, active: false)
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,19 @@ RSpec.describe WarpEngine::Software, type: :model do
|
|||||||
it { should have_many(:external_links) }
|
it { should have_many(:external_links) }
|
||||||
it { should have_many(:software_images).dependent(:destroy) }
|
it { should have_many(:software_images).dependent(:destroy) }
|
||||||
|
|
||||||
describe "default scope" do
|
describe ".kept scope" do
|
||||||
it "excludes soft-deleted records" do
|
it "excludes soft-deleted records" do
|
||||||
active = create(:software)
|
active = create(:software)
|
||||||
create(:software, deleted_at: Time.current)
|
create(:software, deleted_at: Time.current)
|
||||||
|
|
||||||
expect(WarpEngine::Software.all).to eq([active])
|
expect(WarpEngine::Software.kept).to eq([active])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "includes soft-deleted records without scope" do
|
||||||
|
active = create(:software)
|
||||||
|
deleted = create(:software, deleted_at: Time.current)
|
||||||
|
|
||||||
|
expect(WarpEngine::Software.all).to contain_exactly(active, deleted)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user