106 行
3.4 KiB
Ruby
106 行
3.4 KiB
Ruby
class MaterialSyncSuppression < ApplicationRecord
|
|
SOURCE_KINDS = [
|
|
'uri',
|
|
'google_drive_path',
|
|
'google_drive_path_prefix',
|
|
'google_drive_file',
|
|
'legacy_drive_path',
|
|
'legacy_drive_path_prefix'
|
|
].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
|
|
|
|
before_validation :assign_normalized_source_key
|
|
|
|
validates :source_kind, presence: true, inclusion: { in: SOURCE_KINDS }
|
|
validates :reason, presence: true, inclusion: { in: REASONS }
|
|
validates :normalized_source_key, presence: true, uniqueness: true
|
|
validate :source_value_must_be_present
|
|
validate :drive_path_must_be_safe_relative_path
|
|
|
|
def self.normalize_source_key source_kind:,
|
|
source_uri: nil,
|
|
drive_path: nil,
|
|
drive_file_id: nil,
|
|
source_path: nil,
|
|
source_file_id: nil
|
|
kind = source_kind.to_s
|
|
value =
|
|
case kind
|
|
when 'uri'
|
|
source_uri.to_s.strip
|
|
when 'google_drive_path', 'google_drive_path_prefix',
|
|
'legacy_drive_path', 'legacy_drive_path_prefix'
|
|
(source_path || drive_path).to_s.strip.gsub(%r{/+}, '/')
|
|
when 'google_drive_file'
|
|
(source_file_id || drive_file_id).to_s.strip
|
|
else
|
|
''
|
|
end
|
|
|
|
return nil if kind.blank? || value.blank?
|
|
|
|
"#{ kind }:#{ value }"
|
|
end
|
|
|
|
private
|
|
|
|
def assign_normalized_source_key
|
|
normalize_path_fields!
|
|
self.normalized_source_key =
|
|
self.class.normalize_source_key(source_kind:,
|
|
source_uri:,
|
|
drive_path:,
|
|
drive_file_id:)
|
|
end
|
|
|
|
def source_value_must_be_present
|
|
return if normalized_source_key.present?
|
|
|
|
errors.add(:base, '同期元を指定してください.')
|
|
end
|
|
|
|
def drive_path_must_be_safe_relative_path
|
|
return unless source_kind.in?(
|
|
['google_drive_path', 'google_drive_path_prefix',
|
|
'legacy_drive_path', 'legacy_drive_path_prefix'])
|
|
|
|
value = drive_path.to_s
|
|
return if value.blank?
|
|
|
|
if value.start_with?('/') || value.match?(/\A[A-Za-z]:\//)
|
|
errors.add(:drive_path, '相対 path を指定してください.')
|
|
end
|
|
if value.start_with?('My Drive/', 'マイドライブ/')
|
|
errors.add(:drive_path, '同期元フォルダからの相対 path を指定してください.')
|
|
end
|
|
errors.add(:drive_path, 'NUL は使へません.') if value.include?("\0")
|
|
errors.add(:drive_path, '連続スラッシュは使へません.') if value.include?('//')
|
|
errors.add(:drive_path, '末尾スラッシュは使へません.') if value.end_with?('/')
|
|
|
|
parts = value.split('/')
|
|
if parts.any? { |part| part.in?(['.', '..']) }
|
|
errors.add(:drive_path, '. や .. は使へません.')
|
|
end
|
|
end
|
|
|
|
def normalize_path_fields!
|
|
return unless source_kind.in?(
|
|
['google_drive_path', 'google_drive_path_prefix',
|
|
'legacy_drive_path', 'legacy_drive_path_prefix'])
|
|
|
|
self.drive_path = drive_path.to_s.tr('\\', '/').strip.presence
|
|
end
|
|
end
|