paperclip-dropbox 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Dropbox
|
2
2
|
|
3
|
-
This gem extends [Paperclip](https://github.com/thoughtbot/paperclip) with
|
3
|
+
This gem extends [Paperclip](https://github.com/thoughtbot/paperclip) with
|
4
|
+
Dropbox storage.
|
4
5
|
|
5
6
|
## Installation
|
6
7
|
|
@@ -10,9 +11,59 @@ Put it in your `Gemfile`:
|
|
10
11
|
gem "paperclip-dropbox"
|
11
12
|
```
|
12
13
|
|
13
|
-
|
14
|
+
And run `bundle install`.
|
14
15
|
|
15
|
-
##
|
16
|
+
## Dropbox Setup
|
17
|
+
|
18
|
+
You must [create a Dropbox app](https://www.dropbox.com/developers/apps) and
|
19
|
+
authorize it to access the Dropbox account you want to use for storage. You have
|
20
|
+
a choice of two access types: **App folder** or **Full Dropbox**.
|
21
|
+
|
22
|
+
### "Full Dropbox" access
|
23
|
+
|
24
|
+
Files will be stored in the [Public folder](https://www.dropbox.com/help/16/en).
|
25
|
+
Download URLs are predictable, valid forever, and don't require an API call to
|
26
|
+
retrieve, but this may not be a good thing if you don't want your files to be
|
27
|
+
easily accessed. When using one account to store data for multiple sites (e.g.
|
28
|
+
staging and production instances), it's up to you to make sure they don't step
|
29
|
+
on each other's toes.
|
30
|
+
|
31
|
+
Note that accounts created after October 4, 2012 don't have the Public folder
|
32
|
+
enabled by default: [Go here](https://www.dropbox.com/enable_public_folder) to
|
33
|
+
enable it. If you get a message that the folder is deleted, just create a folder
|
34
|
+
in the root named "Public", and it should gain the special icon.
|
35
|
+
|
36
|
+
### "App folder" access
|
37
|
+
|
38
|
+
Files will be stored in a subfolder under Apps (configurable in the app
|
39
|
+
settings). Download URLs are generated on demand by calling the Dropbox API, and
|
40
|
+
are only valid for 4 hours. This means your files are slightly "less public",
|
41
|
+
and you can isolate data from multiple sites by creating multiple apps.
|
42
|
+
|
43
|
+
**In app folder mode, every call to `#url` on an attachment will result in an
|
44
|
+
HTTP request to Dropbox.** Whether or not this is acceptable will depend on what
|
45
|
+
you're storing and how you're exposing it to users.
|
46
|
+
|
47
|
+
### Authorizing your app
|
48
|
+
|
49
|
+
After creating your app, it will have an "App key" and "App secret". Provide
|
50
|
+
these and the access type (`dropbox` or `app_folder`) to the authorization Rake task:
|
51
|
+
|
52
|
+
```
|
53
|
+
$ rake dropbox:authorize APP_KEY=your_app_key APP_SECRET=your_app_secret ACCESS_TYPE=your_access_type
|
54
|
+
```
|
55
|
+
|
56
|
+
It will output an authorization URL that you must visit to grant the app access.
|
57
|
+
It will then output your access token, access token secret, and user ID.
|
58
|
+
|
59
|
+
For non-Rails projects, you must require this task in your `Rakefile`:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
# Rakefile
|
63
|
+
load "paperclip/dropbox/tasks.rake"
|
64
|
+
```
|
65
|
+
|
66
|
+
## Configuration
|
16
67
|
|
17
68
|
Example:
|
18
69
|
|
@@ -25,20 +76,13 @@ class User < ActiveRecord::Base
|
|
25
76
|
end
|
26
77
|
```
|
27
78
|
|
28
|
-
Valid options for `#has_attached_file` are:
|
29
|
-
|
30
|
-
- `:dropbox_credentials` – A Hash, a File, or a path to the file where your
|
31
|
-
Dropbox configuration is located
|
32
|
-
|
33
|
-
- `:dropbox_options` – A Hash that accepts some Dropbox-specific options (they
|
34
|
-
are explained more below)
|
35
|
-
|
36
|
-
## Configuration
|
37
|
-
|
38
79
|
### The `:dropbox_credentials` option
|
39
80
|
|
40
|
-
|
41
|
-
|
81
|
+
This can be a hash or path to a YAML file containing the keys listed in the
|
82
|
+
example below. These are obtained from your Dropbox app settings and the
|
83
|
+
authorization Rake task.
|
84
|
+
|
85
|
+
Example `config/dropbox.yml`:
|
42
86
|
|
43
87
|
```erb
|
44
88
|
app_key: <%= ENV["DROPBOX_APP_KEY"] %>
|
@@ -46,106 +90,83 @@ app_secret: <%= ENV["DROPBOX_APP_SECRET"] %>
|
|
46
90
|
access_token: <%= ENV["DROPBOX_ACCESS_TOKEN"] %>
|
47
91
|
access_token_secret: <%= ENV["DROPBOX_ACCESS_TOKEN_SECRET"] %>
|
48
92
|
user_id: <%= ENV["DROPBOX_USER_ID"] %>
|
93
|
+
access_type: <%= ENV["DROPBOX_ACCESS_TYPE"] %>
|
49
94
|
```
|
50
95
|
|
51
|
-
|
52
|
-
Instead set them in
|
53
|
-
|
54
|
-
|
96
|
+
It is good practice to not include the credentials directly in the YAML file.
|
97
|
+
Instead you can set them in environment variables and embed them with ERB. Note
|
98
|
+
`access_type` must be either `"dropbox"` or `"app_folder"` depending on the
|
99
|
+
access type of your app; see **Dropbox Setup** above.
|
55
100
|
|
56
|
-
|
57
|
-
and create a new app there, which will then provide you your app key and secret.
|
58
|
-
Note that your app has to have the **Full Dropbox** access level (not the "App folder").
|
59
|
-
This is because the uploaded files have to be stored in your `Public` folder.
|
101
|
+
You can also nest your credentials in environments (like in your `database.yml`):
|
60
102
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
103
|
+
```erb
|
104
|
+
development:
|
105
|
+
app_key: "..."
|
106
|
+
...
|
107
|
+
production:
|
108
|
+
app_key: "..."
|
109
|
+
...
|
110
|
+
```
|
69
111
|
|
70
112
|
### The `:dropbox_options` option
|
71
113
|
|
72
|
-
|
114
|
+
This is a hash containing any of the following options:
|
73
115
|
|
74
|
-
- `:path` –
|
75
|
-
- `:
|
76
|
-
|
77
|
-
- `:
|
116
|
+
- `:path` – Block, works similarly to Paperclip's `:path` option
|
117
|
+
- `:unique_filename` – Boolean, whether to generate unique names for files in
|
118
|
+
the absence of a custom `:path`
|
119
|
+
- `:environment` – String, the environment name to use for selecting namespaced
|
120
|
+
credentials in a non-Rails app
|
78
121
|
|
79
|
-
The `:path` option
|
80
|
-
|
81
|
-
|
122
|
+
The `:path` option should be a block that returns a path that the uploaded file
|
123
|
+
should be saved to. The block yields the attachment style and is executed in the
|
124
|
+
scope of the model instance. For example:
|
82
125
|
|
83
126
|
```ruby
|
84
127
|
class User < ActiveRecord::Base
|
85
128
|
has_attached_file :avatar,
|
86
129
|
:storage => :dropbox,
|
87
|
-
:dropbox_credentials => "
|
130
|
+
:dropbox_credentials => "#{Rails.root}/config/dropbox.yml",
|
88
131
|
:styles => { :medium => "300x300" },
|
89
132
|
:dropbox_options => {
|
90
|
-
:path => proc { |style| "#{style}/#{id}_#{avatar.original_filename}"}
|
133
|
+
:path => proc { |style| "#{style}/#{id}_#{avatar.original_filename}" }
|
91
134
|
}
|
92
135
|
end
|
93
136
|
```
|
94
137
|
|
95
|
-
Let's say now that a new user is created with the ID of `23`, and a `photo.jpg`
|
96
|
-
avatar. The following files would be saved to the Dropbox:
|
138
|
+
Let's say now that a new user is created with the ID of `23`, and a `photo.jpg`
|
139
|
+
as his avatar. The following files would be saved to the Dropbox:
|
97
140
|
|
98
141
|
```
|
99
142
|
Public/original/23_photo.jpg
|
100
143
|
Public/medium/23_photo_medium.jpg
|
101
144
|
```
|
102
145
|
|
103
|
-
The other file is called `photo_medium.jpg` because style names (other than
|
104
|
-
will always be appended to the filenames, for better management.
|
105
|
-
|
106
|
-
Files in Dropbox inside a certain folder have to have **unique filenames**, otherwise exception
|
107
|
-
`Paperclip::Storage::Dropbox::FileExists` is thrown. To help you with that, you
|
108
|
-
can set
|
146
|
+
The other file is called `photo_medium.jpg` because style names (other than
|
147
|
+
`original`) will always be appended to the filenames, for better management.
|
109
148
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
```
|
149
|
+
Filenames within a Dropbox folder must be unique; uploading a file with a
|
150
|
+
duplicate name will throw error `Paperclip::Storage::Dropbox::FileExists`. If
|
151
|
+
you don't want to bother crafting your own unique filenames with the `:path`
|
152
|
+
option, you can instead set the `:unique_filename` option to true and it will
|
153
|
+
take care of that.
|
116
154
|
|
117
|
-
|
155
|
+
### URL options
|
118
156
|
|
119
|
-
|
157
|
+
When using `dropbox` access type, the `#url` method of attachments returns a
|
158
|
+
URL to a "landing page" that provides a preview of the file and a download link.
|
159
|
+
To make `#url` return a direct file download link, set the `:download` option as
|
160
|
+
a parameter:
|
120
161
|
|
121
162
|
```ruby
|
122
163
|
user.avatar.url(:download => true)
|
123
164
|
```
|
124
165
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
### The `dropbox:authorize` rake task
|
129
|
-
|
130
|
-
You just provide it your app key and secret:
|
131
|
-
|
132
|
-
```
|
133
|
-
$ rake dropbox:authorize APP_KEY=your_app_key APP_SECRET=your_app_secret
|
134
|
-
```
|
135
|
-
|
136
|
-
It will provide you an authorization URL which you have to visit, and after that
|
137
|
-
it will output the rest of your credentials, which you just copy-paste wherever
|
138
|
-
you need to.
|
139
|
-
|
140
|
-
If you're in a non-Rails application, to get this rake task, you must require it in
|
141
|
-
your `Rakefile`:
|
142
|
-
|
143
|
-
```ruby
|
144
|
-
# Rakefile
|
145
|
-
require "rake"
|
146
|
-
require "paperclip/dropbox/rake"
|
147
|
-
```
|
166
|
+
When using `app_folder` access type, `#url` always returns a direct link, and
|
167
|
+
setting the `:download` option simply forces the file to be downloaded even if
|
168
|
+
the browser would normally just display it.
|
148
169
|
|
149
170
|
## License
|
150
171
|
|
151
|
-
[MIT](https://github.com/janko-m/paperclip-dropbox/blob/master/LICENSE)
|
172
|
+
[MIT License](https://github.com/janko-m/paperclip-dropbox/blob/master/LICENSE)
|
@@ -5,15 +5,15 @@ module Paperclip
|
|
5
5
|
module Rake
|
6
6
|
extend self
|
7
7
|
|
8
|
-
def authorize(app_key, app_secret)
|
8
|
+
def authorize(app_key, app_secret, access_type)
|
9
9
|
session = create_new_session(app_key, app_secret)
|
10
10
|
|
11
|
-
puts "
|
11
|
+
puts "Visit this URL: #{session.get_authorize_url}"
|
12
12
|
print "And after you approved the authorization confirm it here (y/n): "
|
13
13
|
|
14
14
|
assert_answer!
|
15
15
|
session.get_access_token
|
16
|
-
dropbox_client = DropboxClient.new(session,
|
16
|
+
dropbox_client = DropboxClient.new(session, access_type)
|
17
17
|
account_info = dropbox_client.account_info
|
18
18
|
|
19
19
|
puts <<-MESSAGE
|
@@ -23,7 +23,6 @@ Authorization was successful. Here you go:
|
|
23
23
|
access_token: #{session.access_token.key}
|
24
24
|
access_token_secret: #{session.access_token.secret}
|
25
25
|
user_id: #{account_info["uid"]}
|
26
|
-
|
27
26
|
MESSAGE
|
28
27
|
end
|
29
28
|
|
@@ -1,12 +1,13 @@
|
|
1
|
-
require "rake"
|
2
|
-
require "paperclip/dropbox/rake" unless defined?(Paperclip::Dropbox::Rake)
|
1
|
+
require "paperclip/dropbox/rake"
|
3
2
|
|
4
3
|
namespace :dropbox do
|
5
4
|
desc "Obtains your Dropbox credentials"
|
6
5
|
task :authorize do
|
7
6
|
if ENV["APP_KEY"].nil? or ENV["APP_SECRET"].nil?
|
8
|
-
|
7
|
+
puts "USAGE: `rake dropbox:authorize APP_KEY=your_app_key APP_SECRET=your_app_secret` ACCESS_TYPE=your_access_type"
|
8
|
+
exit
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
|
+
Paperclip::Dropbox::Rake.authorize(ENV["APP_KEY"], ENV["APP_SECRET"], ENV["ACCESS_TYPE"] || "dropbox")
|
11
12
|
end
|
12
13
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'dropbox_sdk'
|
2
2
|
require 'active_support/core_ext/hash/keys'
|
3
|
-
require 'active_support/core_ext/hash/slice'
|
4
3
|
require 'active_support/inflector/methods'
|
5
4
|
require 'yaml'
|
6
5
|
require 'erb'
|
@@ -38,30 +37,47 @@ module Paperclip
|
|
38
37
|
end
|
39
38
|
|
40
39
|
def exists?(style)
|
41
|
-
|
40
|
+
metadata = dropbox_metadata(style)
|
41
|
+
!metadata.nil? && !metadata['is_deleted']
|
42
42
|
rescue DropboxError
|
43
43
|
false
|
44
44
|
end
|
45
45
|
|
46
46
|
def url(*args)
|
47
|
-
|
47
|
+
if present?
|
48
48
|
style = args.first.is_a?(Symbol) ? args.first : default_style
|
49
49
|
options = args.last.is_a?(Hash) ? args.last : {}
|
50
50
|
query = options[:download] ? "?dl=1" : ""
|
51
51
|
|
52
|
-
|
52
|
+
if app_folder_mode
|
53
|
+
dropbox_client.media(path(style))['url'] + query
|
54
|
+
else
|
55
|
+
File.join("http://dl.dropbox.com/u/#{user_id}", path_for_url(style) + query)
|
56
|
+
end
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
56
60
|
def path(style)
|
57
|
-
|
61
|
+
if app_folder_mode
|
62
|
+
path_for_url(style)
|
63
|
+
else
|
64
|
+
File.join("Public", path_for_url(style))
|
65
|
+
end
|
58
66
|
end
|
59
67
|
|
60
68
|
def path_for_url(style)
|
61
|
-
|
62
|
-
result += extension if result !~ /\.\w{3,4}$/
|
69
|
+
path = instance.instance_exec(style, &file_path)
|
63
70
|
style_suffix = (style != default_style ? "_#{style}" : "")
|
64
|
-
|
71
|
+
|
72
|
+
if original_extension && path =~ /#{original_extension}$/
|
73
|
+
path.sub(original_extension, "#{style_suffix}#{original_extension}")
|
74
|
+
else
|
75
|
+
path + style_suffix + original_extension.to_s
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def dropbox_metadata(style = default_style)
|
80
|
+
dropbox_client.metadata(path(style))
|
65
81
|
end
|
66
82
|
|
67
83
|
def copy_to_local_file(style, destination_path)
|
@@ -70,16 +86,29 @@ module Paperclip
|
|
70
86
|
local_file.close
|
71
87
|
end
|
72
88
|
|
89
|
+
def dropbox_client
|
90
|
+
@dropbox_client ||= begin
|
91
|
+
assert_required_keys
|
92
|
+
session = DropboxSession.new(@dropbox_credentials[:app_key], @dropbox_credentials[:app_secret])
|
93
|
+
session.set_access_token(@dropbox_credentials[:access_token], @dropbox_credentials[:access_token_secret])
|
94
|
+
DropboxClient.new(session, @dropbox_credentials[:access_type] || 'dropbox')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
73
98
|
private
|
74
99
|
|
75
|
-
def
|
76
|
-
original_filename[
|
100
|
+
def original_extension
|
101
|
+
original_filename[/\.[^.]+$/]
|
77
102
|
end
|
78
103
|
|
79
104
|
def user_id
|
80
105
|
@dropbox_credentials[:user_id]
|
81
106
|
end
|
82
107
|
|
108
|
+
def app_folder_mode
|
109
|
+
@dropbox_credentials[:access_type] == 'app_folder'
|
110
|
+
end
|
111
|
+
|
83
112
|
def file_path
|
84
113
|
return @dropbox_options[:path] if @dropbox_options[:path]
|
85
114
|
|
@@ -90,19 +119,13 @@ module Paperclip
|
|
90
119
|
end
|
91
120
|
end
|
92
121
|
|
93
|
-
def dropbox_client
|
94
|
-
@dropbox_client ||= begin
|
95
|
-
assert_required_keys
|
96
|
-
session = DropboxSession.new(@dropbox_credentials[:app_key], @dropbox_credentials[:app_secret])
|
97
|
-
session.set_access_token(@dropbox_credentials[:access_token], @dropbox_credentials[:access_token_secret])
|
98
|
-
DropboxClient.new(session, "dropbox")
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
122
|
def assert_required_keys
|
103
123
|
[:app_key, :app_secret, :access_token, :access_token_secret, :user_id].each do |key|
|
104
124
|
@dropbox_credentials.fetch(key)
|
105
125
|
end
|
126
|
+
if @dropbox_credentials[:access_type] and not ['dropbox', 'app_folder'].include?(@dropbox_credentials[:access_type])
|
127
|
+
raise KeyError, ":access_type must be 'dropbox' or 'app_folder'"
|
128
|
+
end
|
106
129
|
end
|
107
130
|
|
108
131
|
def parse_credentials(credentials)
|
data/paperclip-dropbox.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
4
|
gem.name = "paperclip-dropbox"
|
5
|
-
gem.version = "1.0
|
5
|
+
gem.version = "1.1.0"
|
6
6
|
gem.platform = Gem::Platform::RUBY
|
7
7
|
|
8
8
|
gem.homepage = "https://github.com/janko-m/paperclip-dropbox"
|
@@ -21,11 +21,12 @@ Gem::Specification.new do |gem|
|
|
21
21
|
gem.add_dependency "paperclip", "~> 3.1"
|
22
22
|
gem.add_dependency "dropbox-sdk", "~> 1.3"
|
23
23
|
|
24
|
-
gem.add_development_dependency "rake", "
|
24
|
+
gem.add_development_dependency "rake", ">= 0.9"
|
25
25
|
gem.add_development_dependency "rspec", "~> 2.11"
|
26
26
|
gem.add_development_dependency "vcr", "~> 2.2"
|
27
27
|
gem.add_development_dependency "fakeweb", "~> 1.3"
|
28
28
|
gem.add_development_dependency "activerecord", "~> 3.2"
|
29
29
|
gem.add_development_dependency "rack-test", "~> 0.6"
|
30
30
|
gem.add_development_dependency "sqlite3", "~> 1.3"
|
31
|
+
gem.add_development_dependency "rest-client", "~> 1.6"
|
31
32
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paperclip-dropbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: paperclip
|
@@ -48,7 +48,7 @@ dependencies:
|
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
50
50
|
requirements:
|
51
|
-
- -
|
51
|
+
- - ! '>='
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '0.9'
|
54
54
|
type: :development
|
@@ -56,7 +56,7 @@ dependencies:
|
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
none: false
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0.9'
|
62
62
|
- !ruby/object:Gem::Dependency
|
@@ -155,6 +155,22 @@ dependencies:
|
|
155
155
|
- - ~>
|
156
156
|
- !ruby/object:Gem::Version
|
157
157
|
version: '1.3'
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: rest-client
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ~>
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '1.6'
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ~>
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '1.6'
|
158
174
|
description: Extends Paperclip with Dropbox storage.
|
159
175
|
email:
|
160
176
|
- janko.marohnic@gmail.com
|
@@ -164,7 +180,7 @@ extra_rdoc_files: []
|
|
164
180
|
files:
|
165
181
|
- lib/paperclip/dropbox/railtie.rb
|
166
182
|
- lib/paperclip/dropbox/rake.rb
|
167
|
-
- lib/paperclip/dropbox/tasks
|
183
|
+
- lib/paperclip/dropbox/tasks.rake
|
168
184
|
- lib/paperclip/dropbox.rb
|
169
185
|
- lib/paperclip/storage/dropbox.rb
|
170
186
|
- lib/paperclip-dropbox.rb
|
@@ -190,6 +206,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
190
206
|
- - ! '>='
|
191
207
|
- !ruby/object:Gem::Version
|
192
208
|
version: '0'
|
209
|
+
segments:
|
210
|
+
- 0
|
211
|
+
hash: -208715218772659661
|
193
212
|
requirements: []
|
194
213
|
rubyforge_project:
|
195
214
|
rubygems_version: 1.8.23
|
@@ -197,4 +216,3 @@ signing_key:
|
|
197
216
|
specification_version: 3
|
198
217
|
summary: Extends Paperclip with Dropbox storage.
|
199
218
|
test_files: []
|
200
|
-
has_rdoc:
|