attr_writer :bucket, :storage_type event :storage_type_change, :store, on: :update, when: proc { |c| c.storage_type_changed? } do # carrierwave stores file if @cache_id is not nil attachment.cache_stored_file! # attachment.retrieve_from_cache!(attachment.cache_name) update_storage_attributes # next line might be necessary to move files to cloud # make sure that we get the new identifier # otherwise action_id will return wrong id for new identifier db_content_will_change! write_identifier end event :validate_storage_type, :validate, on: :save do if will_become_coded? unless mod || @new_mod errors.add :storage_type, "mod argument needed to save card as coded" end if codename.blank? errors.add :storage_type, "codename needed for storage type coded" end end unless known_storage_type? will_be_stored_as errors.add :storage_type, "unknown storage type: #{@new_storage_type}" end end event :validate_storage_type_update, :validate, on: :update do # FIXME: make it possible to retrieve the file from cloud storage # to store it somewhere else. Currently, it only works to change the # storage type if a new file is provided # i.e. `update_attributes storage_type: :local` fails but # `update_attributes storage_type: :local, file: [file handle]` is ok if cloud? && storage_type_changed? && !file_changed? errors.add :storage_type, "moving files from cloud elsewhere "\ "is not supported" end end event :loose_coded_status_on_update, :initialize, on: :update, when: :coded? do return if @new_mod @new_storage_type ||= storage_type_from_config end event :change_bucket_if_read_only, :initialize, on: :update, when: :cloud? do return unless bucket_config[:read_only] @new_storage_type = storage_type_from_config end event :update_public_link_on_create, :integrate, on: :create, when: :local? do update_public_link end event :remove_public_link_on_delete, :integrate, on: :delete, when: :local? do remove_public_links end event :update_public_link, after: :update_read_rule, when: :local? do return if content.blank? if who_can(:read).include? Card::AnyoneID create_public_links else remove_public_links end end def create_public_links path = attachment.public_path return if File.exist? path FileUtils.mkdir_p File.dirname(path) File.symlink attachment.path, path unless File.symlink? path create_versions_public_links end def create_versions_public_links attachment.versions.each do |_name, version| next if File.symlink? version.public_path File.symlink version.path, version.public_path end end def remove_public_links symlink_dir = File.dirname attachment.public_path return unless Dir.exist? symlink_dir FileUtils.rm_rf symlink_dir end def will_be_stored_as @new_storage_type || storage_type end def cloud? storage_type == :cloud end def web? storage_type == :web end def local? storage_type == :local end def coded? storage_type == :coded end def will_become_coded? will_be_stored_as == :coded end def deprecated_mod_file? content && (lines = content.split("\n")) && lines.size == 4 end def mod @mod ||= coded? && mod_from_content end def mod_from_content if content =~ %r{^:[^/]+/([^.]+)} Regexp.last_match(1) # current mod_file format else mod_from_deprecated_content end end # old format is still used in card_changes def mod_from_deprecated_content return if content =~ /^\~/ return unless (lines = content.split("\n")) && lines.size == 4 lines.last end def remote_storage? cloud? || web? end def no_upload? storage_type_from_config == :web end def bucket @bucket ||= cloud? && ((new_card? && bucket_from_config) || bucket_from_content || bucket_from_config) end def bucket_config @bucket_config ||= load_bucket_config end def load_bucket_config return {} unless bucket bucket_config = Cardio.config.file_buckets && Cardio.config.file_buckets[bucket.to_sym] bucket_config &&= bucket_config.symbolize_keys bucket_config ||= {} # we don't want :attributes hash symbolized, so we can't use # deep_symbolize_keys bucket_config[:credentials] &&= bucket_config[:credentials].symbolize_keys ensure_bucket_config do load_bucket_config_from_env bucket_config end end def ensure_bucket_config config = yield unless config.present? raise Card::Error, "couldn't find configuration for bucket #{bucket}" end unless config[:credentials] raise Card::Error, "couldn't find credentials for bucket #{bucket}" end config end def load_bucket_config_from_env config config ||= {} CarrierWave::FileCardUploader::CONFIG_OPTIONS.each do |key| next if key.in? [:attributes, :credentials] replace_with_env_variable config, key end config[:credentials] ||= {} load_bucket_credentials_from_env config[:credentials] config.delete :credentials unless config[:credentials].present? config end def load_bucket_credentials_from_env cred_config cred_opt_pattern = Regexp.new(/^(?:#{bucket.to_s.upcase}_)?CREDENTIALS_(?