このコミットが含まれているのは:
@@ -9,6 +9,10 @@ class Material < ApplicationRecord
|
||||
belongs_to :tag, optional: true
|
||||
belongs_to :created_by_user, class_name: 'User', optional: true
|
||||
belongs_to :updated_by_user, class_name: 'User', optional: true
|
||||
belongs_to :file_suppressed_by_user, class_name: 'User', optional: true
|
||||
|
||||
has_many :material_versions, dependent: :destroy
|
||||
has_many :material_export_items, dependent: :destroy
|
||||
|
||||
has_one_attached :file, dependent: :purge
|
||||
|
||||
@@ -18,11 +22,18 @@ class Material < ApplicationRecord
|
||||
validate :tag_must_be_material_category
|
||||
|
||||
def content_type
|
||||
return nil if file_suppressed?
|
||||
return nil unless file&.attached?
|
||||
|
||||
file.blob.content_type
|
||||
end
|
||||
|
||||
def file_suppressed? = file_suppressed_at.present?
|
||||
|
||||
def snapshot_export_paths
|
||||
material_export_items.order(:profile).pluck(:profile, :export_path).to_h
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def file_must_be_attached
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
class MaterialExportItem < ApplicationRecord
|
||||
VALID_PROFILES = ['legacy_drive'].freeze
|
||||
|
||||
belongs_to :material
|
||||
belongs_to :created_by_user, class_name: 'User', optional: true
|
||||
|
||||
validates :profile, presence: true, inclusion: { in: VALID_PROFILES }
|
||||
validates :export_path, presence: true, uniqueness: { scope: :profile }
|
||||
validates :material_id, uniqueness: { scope: :profile }
|
||||
validate :export_path_must_be_relative_safe_path
|
||||
|
||||
scope :enabled, -> { where(enabled: true) }
|
||||
|
||||
private
|
||||
|
||||
def export_path_must_be_relative_safe_path
|
||||
return if export_path.blank?
|
||||
|
||||
if export_path.start_with?('/')
|
||||
errors.add(:export_path, '絶対パスは使へません.')
|
||||
end
|
||||
|
||||
if export_path.match?(/\A[A-Za-z]:\//)
|
||||
errors.add(:export_path, '絶対パスは使へません.')
|
||||
end
|
||||
|
||||
if export_path.include?('\\')
|
||||
errors.add(:export_path, '/ 区切りで指定してください.')
|
||||
end
|
||||
|
||||
if export_path.include?("\0")
|
||||
errors.add(:export_path, 'NUL は使へません.')
|
||||
end
|
||||
|
||||
parts = export_path.split('/')
|
||||
if export_path.include?('//')
|
||||
errors.add(:export_path, '空の path segment は使へません.')
|
||||
end
|
||||
|
||||
if parts.any? { |part| part.in?(['.', '..']) }
|
||||
errors.add(:export_path, '.. は使へません.')
|
||||
end
|
||||
|
||||
if export_path.end_with?('/')
|
||||
errors.add(:export_path, 'directory path は使へません.')
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,29 @@
|
||||
class MaterialImportBlock < ApplicationRecord
|
||||
MATCH_KINDS = ['sha256', 'exact_path', 'path_prefix', 'manual'].freeze
|
||||
REASONS = [
|
||||
'copyright_high_risk',
|
||||
'copyright_takedown',
|
||||
'adult_or_sensitive',
|
||||
'personal_information',
|
||||
'malware_or_dangerous_file',
|
||||
'duplicate_or_low_quality',
|
||||
'source_owner_request',
|
||||
'other'
|
||||
].freeze
|
||||
|
||||
belongs_to :created_by_user, class_name: 'User', optional: true
|
||||
|
||||
validates :match_kind, presence: true, inclusion: { in: MATCH_KINDS }
|
||||
validates :reason, presence: true, inclusion: { in: REASONS }
|
||||
validates :sha256, length: { is: 64 }, allow_blank: true
|
||||
validate :match_value_must_be_present
|
||||
|
||||
private
|
||||
|
||||
def match_value_must_be_present
|
||||
return if match_kind == 'manual'
|
||||
return if sha256.present? || external_path_pattern.present?
|
||||
|
||||
errors.add(:base, 'sha256 または external_path_pattern は必須です.')
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,18 @@
|
||||
class MaterialVersion < ApplicationRecord
|
||||
EVENT_TYPE_MAP = { create: 'create',
|
||||
update: 'update',
|
||||
discard: 'discard',
|
||||
restore: 'restore',
|
||||
suppress: 'suppress' }.freeze
|
||||
|
||||
include VersionRecord
|
||||
|
||||
belongs_to :material
|
||||
belongs_to :tag, optional: true
|
||||
belongs_to :parent, class_name: 'Material', optional: true
|
||||
belongs_to :updated_by_user, class_name: 'User', optional: true
|
||||
|
||||
def export_paths_hash
|
||||
export_paths_json || {}
|
||||
end
|
||||
end
|
||||
@@ -1,15 +1,23 @@
|
||||
module VersionRecord
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
DEFAULT_EVENT_TYPE_MAP = { create: 'create',
|
||||
update: 'update',
|
||||
discard: 'discard',
|
||||
restore: 'restore' }.freeze
|
||||
|
||||
def readonly? = persisted?
|
||||
|
||||
included do
|
||||
event_type_map = if const_defined?(:EVENT_TYPE_MAP, false)
|
||||
const_get(:EVENT_TYPE_MAP)
|
||||
else
|
||||
DEFAULT_EVENT_TYPE_MAP
|
||||
end
|
||||
|
||||
belongs_to :created_by_user, class_name: 'User', optional: true
|
||||
|
||||
enum :event_type, { create: 'create',
|
||||
update: 'update',
|
||||
discard: 'discard',
|
||||
restore: 'restore' }, prefix: true, validate: true
|
||||
enum :event_type, event_type_map, prefix: true, validate: true
|
||||
|
||||
validates :version_no, presence: true, numericality: { only_integer: true, greater_than: 0 }
|
||||
validates :event_type, presence: true
|
||||
|
||||
新しい課題から参照
ユーザをブロックする