ashishprajapati/activestorage-dropbox

View on GitHub
lib/active_storage/service/dropbox_service.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

require "dropbox_api"

module ActiveStorage
  # Wraps the Dropbox Storage as an Active Storage service. See ActiveStorage::Service for the generic API
  # documentation that applies to all services.
  class Service::DropboxService < Service
    def initialize(**config)
      @config = config
    end

    def upload(key, io, checksum: nil, filename: nil, content_type: nil, disposition: nil, custom_metadata: {})
      instrument :upload, key: key, checksum: checksum do
        client.upload_by_chunks "/"+key, io
      rescue DropboxApi::Errors::UploadError
        raise ActiveStorage::IntegrityError
      end
    end

    def download(key, &block)
      if block_given?
        instrument :streaming_download, key: key do
          stream(key, &block)
        end
      else
        instrument :download, key: key do
          download_for(key)
        rescue DropboxApi::Errors::NotFoundError
          raise ActiveStorage::FileNotFoundError
        end
      end
    end

    def delete(key)
      instrument :delete, key: key do
        client.delete("/"+key)
      rescue DropboxApi::Errors::NotFoundError
        # Ignore files already deleted
      end
    end

    def delete_prefixed(prefix)
      instrument :delete_prefixed, prefix: prefix do
        client.delete("/"+prefix[0..-2])
      rescue DropboxApi::Errors::NotFoundError
        # Ignore files already deleted
      end
    end

    def exist?(key)
      instrument :exist, key: key do |payload|
        begin
          answer = client.get_metadata("/"+key).present?
        rescue DropboxApi::Errors::NotFoundError
          answer = false
        end
        payload[:exist] = answer
        answer
      end
    end

    def url(key, expires_in:, filename:, disposition:, content_type:)
      instrument :url, key: key do |payload|
        generated_url = file_for(key).link
        payload[:url] = generated_url
        generated_url
      end
    end

    private

      attr_reader :config

      def file_for(key)
        client.get_temporary_link("/"+key)
      end

      def download_for(key)
        client.download("/"+key) do |chunk|
          return chunk.force_encoding(Encoding::BINARY)
        end
      end

      # Reads the file for the given key in chunks, yielding each to the block.
      def stream(key)
        begin
          file = client.download("/"+key) do |chunk|
            yield chunk
          end
        rescue DropboxApi::Errors::NotFoundError
          raise ActiveStorage::FileNotFoundError
        end
      end

      def client
        @client ||= DropboxApi::Client.new(config.fetch(:access_token))
      end
  end
end