paperclip-dropbox 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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:
|