mountable_file_server 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 53f16655a84e2cec6640805c435f917ce77d482a
4
- data.tar.gz: eaa590e6d805b01e5e488308a5bab98406c17732
3
+ metadata.gz: 9eca97072a7e354d3523e099982afc7cf4234516
4
+ data.tar.gz: 938444d589b364fb81bb16ab26244425601ba4eb
5
5
  SHA512:
6
- metadata.gz: 2e1aae6f8f4547649c2b53af4f8771b6d15f393895e4a72eff662d7ae585d023efc06065639de25356f12b7da4608972c737259c1cb4dc25aaee0dab406f0a4e
7
- data.tar.gz: beb7392313d97415fb62acc49073981dc9682d6eeb828a1b6dd1f8c5e57238fcc1e6263959fb0a4e10065d9d1e5292228167bbef0776545f6c32efb9a3384eb6
6
+ metadata.gz: 09226be2ad7e5f2ccfac19be367b42f44d94e9570a91a2046f541468a1aaca317eae56baf4829455e450814c831e30f3147897ee344f842f245ca846a812d45b
7
+ data.tar.gz: 9f5d940813c63c26497be28472b5e12175ca4be1bec7903f8f5f21fe6412f89cdddaf26e75be3e2e3b4de40a628f898030e33b8f2b509c312625781edcd8067c
data/README.md CHANGED
@@ -1,3 +1,16 @@
1
+ Mountable File Server can be used with any Ruby (on Rails) application and it removes the pain associated with file uploads.
2
+
3
+ ## Core Idea
4
+ app only stores reference to uploaded file
5
+
6
+ ## MountableFileServer::Server
7
+ The core of Mountable File Server (MFS) is a small HTTP API that accepts file uploads and offers endpoints to interact with uploaded files. While the frontend deals directly with the HTTP API, your Ruby application will want to use the Ruby Client `MountableFileServer::Client`.
8
+
9
+
10
+
11
+
12
+
13
+
1
14
  MountableFileServer was born out of my frustations with existing Ruby based file upload solutions. It is certainly not comparable with existing feature-rich plug-and-play solutions that are tied to Ruby on Rails.
2
15
 
3
16
  The fundamental idea is that your application should not be tied to files or handling the upload process. Instead this is handled by a dedicated server which can be run as independet process or be mounted inside your application. It accepts file uploads and returns an unique identifier for the file. This unique identifier is basically a string and the only thing your application has to remember in order to work with uploaded files.
@@ -98,11 +111,8 @@ Returns the URL for an uploaded file. Only works for public files, if you pass t
98
111
  `MountableFileServer::Adapter#pathname_for(id)`
99
112
  Returns a [Pathname](http://ruby-doc.org/stdlib-2.2.2/libdoc/pathname/rdoc/Pathname.html) object for the uploaded file. The pathname will always point to the file on disk independent from the files type or current storage location.
100
113
 
101
- ## Example
102
- TBW
103
-
104
- ## Deployment
105
- TBW
114
+ # Publish on RubyGems.org
106
115
 
107
- ## License
108
- [MIT](https://github.com/stravid/mountable_file_server/blob/master/LICENSE.txt)
116
+ 1. Increment `lib/mountable_image_server/version.rb` to your liking.
117
+ 2. Make a Git commit.
118
+ 3. Run `bundle exec rake release`.
@@ -1,8 +1,12 @@
1
+ require 'mountable_file_server/storage'
2
+ require 'mountable_file_server/unique_identifier'
3
+ require 'mountable_file_server/file_accessor'
4
+
1
5
  module MountableFileServer
2
6
  class Adapter
3
7
  attr_reader :configuration
4
8
 
5
- def initialize(configuration = MountableFileServer.configuration)
9
+ def initialize(configuration = MountableFileServer.config)
6
10
  @configuration = configuration
7
11
  end
8
12
 
@@ -23,14 +27,15 @@ module MountableFileServer
23
27
  Storage.new(configuration).move_to_permanent_storage uid
24
28
  end
25
29
 
26
- def remove_from_permanent_storage(uid)
30
+ def remove_from_storage(uid)
27
31
  uid = UniqueIdentifier.new uid
28
- Storage.new(configuration).remove_from_permanent_storage uid
32
+ Storage.new(configuration).remove_from_storage uid
29
33
  end
30
34
 
31
35
  def url_for(uid)
32
- uid = UniqueIdentifier.new uid
33
- FileAccessor.new(uid, configuration).url
36
+ # uid = UniqueIdentifier.new uid
37
+ # FileAccessor.new(uid, configuration).url
38
+ configuration.base_url + uid
34
39
  end
35
40
 
36
41
  def pathname_for(uid)
@@ -0,0 +1,44 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'stringio'
4
+
5
+ module MountableFileServer
6
+ class Client
7
+ def move_to_permanent_storage(fid)
8
+ if MountableFileServer.config.base_url.start_with?('http')
9
+ uri = ::URI.parse(MountableFileServer.config.base_url)
10
+ http = Net::HTTP.new(uri.host, uri.port)
11
+ http.set_debug_output($stdout)
12
+ request = Net::HTTP::Post.new(uri.request_uri + fid + '/store-permanent')
13
+
14
+ http.request(request)
15
+ else
16
+ MountableFileServer::Server.new.call({
17
+ "rack.input" => StringIO.new(""),
18
+ "REQUEST_METHOD"=> "POST",
19
+ "PATH_INFO"=> "/#{fid}/store-permanent",
20
+ })
21
+ end
22
+ end
23
+
24
+ def remove_from_storage(fid)
25
+ if MountableFileServer.config.base_url.start_with?('http')
26
+ uri = ::URI.parse(MountableFileServer.config.base_url)
27
+ http = Net::HTTP.new(uri.host, uri.port)
28
+ request = Net::HTTP::Delete.new(uri.request_uri + fid)
29
+
30
+ http.request(request)
31
+ else
32
+ MountableFileServer::Server.new.call({
33
+ "rack.input" => StringIO.new(""),
34
+ "REQUEST_METHOD"=> "DELETE",
35
+ "PATH_INFO"=> "/#{fid}",
36
+ })
37
+ end
38
+ end
39
+
40
+ def url_for(fid)
41
+ MountableFileServer.config.base_url + fid
42
+ end
43
+ end
44
+ end
@@ -7,17 +7,17 @@ module MountableFileServer
7
7
  class FileAccessor
8
8
  attr_reader :uid, :configuration
9
9
 
10
- def initialize(uid, configuration = MountableFileServer.configuration)
10
+ def initialize(uid, configuration = MountableFileServer.config)
11
11
  @uid = uid
12
12
  @configuration = configuration
13
13
  end
14
14
 
15
15
  def temporary_pathname
16
- Pathname(configuration.stored_at) + 'tmp' + uid
16
+ Pathname(configuration.storage_path) + 'tmp' + uid
17
17
  end
18
18
 
19
19
  def permanent_pathname
20
- Pathname(configuration.stored_at) + uid.type + uid
20
+ Pathname(configuration.storage_path) + uid.type + uid
21
21
  end
22
22
 
23
23
  def pathname
@@ -31,7 +31,7 @@ module MountableFileServer
31
31
  def url
32
32
  raise NotAccessibleViaURL unless uid.public?
33
33
 
34
- URI.new (Pathname(configuration.mounted_at) + uid).to_s
34
+ URI.new (Pathname(configuration.base_url) + uid).to_s
35
35
  end
36
36
 
37
37
  private
@@ -0,0 +1,45 @@
1
+ require 'dimensions'
2
+
3
+ module MountableFileServer
4
+ class Metadata
5
+ attr_reader :size, :content_type, :height, :width
6
+
7
+ def initialize(size:, content_type:, width: nil, height: nil)
8
+ @size = size
9
+ @content_type = content_type
10
+ @width = width
11
+ @height = height
12
+ end
13
+
14
+ def to_h
15
+ hash = {
16
+ size: size,
17
+ content_type: content_type
18
+ }
19
+
20
+ if width && height
21
+ hash = hash.merge({
22
+ height: height,
23
+ width: width
24
+ })
25
+ end
26
+
27
+ hash
28
+ end
29
+
30
+ def self.for_path(path)
31
+ parameters = {}
32
+
33
+ parameters[:content_type] = `file --brief --mime-type #{path}`.strip
34
+ parameters[:size] = File.size(path)
35
+
36
+ if ['image/png', 'image/jpeg', 'image/gif', 'image/tiff'].include?(parameters[:content_type])
37
+ dimensions = Dimensions.dimensions(path)
38
+ parameters[:width] = dimensions[0]
39
+ parameters[:height] = dimensions[1]
40
+ end
41
+
42
+ new(parameters)
43
+ end
44
+ end
45
+ end
@@ -1,4 +1,6 @@
1
1
  require 'mountable_file_server'
2
+ require 'mountable_file_server/server'
3
+ require 'mountable_file_server/client'
2
4
 
3
5
  module MountableFileServer
4
6
  class Engine < Rails::Engine
@@ -0,0 +1,49 @@
1
+ require 'sinatra/base'
2
+ require 'pathname'
3
+
4
+ require 'mountable_file_server/adapter'
5
+ require 'mountable_file_server/metadata'
6
+
7
+ module MountableFileServer
8
+ class Server < Sinatra::Base
9
+ post '/' do
10
+ adapter = Adapter.new
11
+ pathname = Pathname(params[:file][:tempfile].path)
12
+ type = params[:type]
13
+ fid = adapter.store_temporary(pathname, type, pathname.extname)
14
+ url = adapter.url_for(fid)
15
+ metadata = Metadata.for_path(pathname)
16
+
17
+ content_type :json
18
+ status 201
19
+
20
+ {
21
+ fid: fid,
22
+ url: url,
23
+ metadata: metadata.to_h
24
+ }.to_json
25
+ end
26
+
27
+ get '/:fid' do |fid|
28
+ adapter = Adapter.new
29
+ pathname = adapter.pathname_for(fid)
30
+ send_file pathname
31
+ end
32
+
33
+ post '/:fid/store-permanent' do |fid|
34
+ adapter = Adapter.new
35
+ adapter.move_to_permanent_storage(fid)
36
+
37
+ content_type :json
38
+ status 200
39
+ end
40
+
41
+ delete '/:fid' do |fid|
42
+ adapter = Adapter.new
43
+ adapter.remove_from_storage(fid)
44
+
45
+ content_type :json
46
+ status 200
47
+ end
48
+ end
49
+ end
@@ -2,7 +2,7 @@ module MountableFileServer
2
2
  class Storage
3
3
  attr_reader :configuration
4
4
 
5
- def initialize(configuration = MountableFileServer.configuration)
5
+ def initialize(configuration = MountableFileServer.config)
6
6
  @configuration = configuration
7
7
  end
8
8
 
@@ -26,8 +26,8 @@ module MountableFileServer
26
26
  source.rename destination
27
27
  end
28
28
 
29
- def remove_from_permanent_storage(uid)
30
- source = FileAccessor.new(uid, configuration).permanent_pathname
29
+ def remove_from_storage(uid)
30
+ source = FileAccessor.new(uid, configuration).pathname
31
31
  source.delete
32
32
  end
33
33
  end
@@ -1,6 +1,5 @@
1
1
  require 'uri'
2
2
  require 'pathname'
3
- require 'url_safe_base64'
4
3
 
5
4
  module MountableFileServer
6
5
  class URI < String
@@ -12,22 +11,8 @@ module MountableFileServer
12
11
  UniqueIdentifier.new filename
13
12
  end
14
13
 
15
- def encoded_processing_instructions
16
- /\.(\w+)\./.match(filename).captures.first
17
- end
18
-
19
- def decoded_processing_instructions
20
- UrlSafeBase64.decode64 encoded_processing_instructions
21
- end
22
-
23
14
  def filename
24
15
  Pathname(::URI.parse(self).path).basename.to_s
25
16
  end
26
-
27
- def resize(instructions)
28
- encoded_instructions = UrlSafeBase64.encode64 instructions
29
-
30
- URI.new self.gsub('.', ".#{encoded_instructions}.")
31
- end
32
17
  end
33
18
  end
@@ -1,3 +1,3 @@
1
1
  module MountableFileServer
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -1,24 +1,10 @@
1
+ require "dry-configurable"
2
+
1
3
  require "mountable_file_server/version"
2
4
 
3
5
  module MountableFileServer
4
- require "mountable_file_server/configuration"
5
- require "mountable_file_server/file_accessor"
6
- require "mountable_file_server/unique_identifier"
7
- require "mountable_file_server/storage"
8
- require "mountable_file_server/uri"
9
-
10
- require "mountable_file_server/adapter"
11
- require "mountable_file_server/endpoint"
12
-
13
- class << self
14
- attr_writer :configuration
15
- end
16
-
17
- def self.configuration
18
- @configuration ||= Configuration.new
19
- end
6
+ extend Dry::Configurable
20
7
 
21
- def self.configure
22
- yield(configuration)
23
- end
8
+ setting :base_url
9
+ setting :storage_path
24
10
  end
@@ -21,15 +21,14 @@ Gem::Specification.new do |spec|
21
21
  spec.add_development_dependency "bundler", "~> 1.7"
22
22
  spec.add_development_dependency "rake", "~> 10.0"
23
23
  spec.add_development_dependency "minitest", "~> 5.8.0"
24
- spec.add_development_dependency "rails", "~> 4.2.3"
24
+ spec.add_development_dependency "rails", "~> 5.0.2"
25
25
  spec.add_development_dependency "capybara", "~> 2.4.4"
26
26
  spec.add_development_dependency "sqlite3", "~> 1.3.10"
27
27
  spec.add_development_dependency "poltergeist", "~> 1.6.0"
28
28
  spec.add_development_dependency "rack-test", "~> 0.6.3"
29
- spec.add_development_dependency "bogus", "~> 0.1.6"
29
+ spec.add_development_dependency "webmock", "~> 2.1.0"
30
30
 
31
- spec.add_runtime_dependency "rack", "~> 1.6"
32
- spec.add_runtime_dependency "sinatra", "~> 1.4.5"
33
- spec.add_runtime_dependency "mini_magick"
34
- spec.add_runtime_dependency "url_safe_base64"
31
+ spec.add_runtime_dependency "sinatra", "~> 2.0.0.rc1"
32
+ spec.add_runtime_dependency "dry-configurable", "~> 0.1.6"
33
+ spec.add_runtime_dependency "dimensions", "~> 1.3.0"
35
34
  end
@@ -1,61 +1,44 @@
1
1
  (function() {
2
- var lastUploadId = 0;
3
- var finishedUploads = [];
4
-
5
- var dispatchEvent = function($element, name, payload) {
6
- var event = document.createEvent('CustomEvent');
7
-
8
- event.initCustomEvent(name, true, false, payload);
9
- $element.dispatchEvent(event);
10
- };
11
-
12
- var uploadFile = function($element, file, uploadId) {
13
- var url = $element.getAttribute('data-endpoint');
14
- var type = $element.getAttribute('data-type');
15
- var xhr = new XMLHttpRequest();
16
- var formData = new FormData();
17
-
18
- formData.append('file', file);
19
- formData.append('type', type);
20
-
21
- xhr.open('POST', url, true);
22
-
23
- xhr.onreadystatechange = function() {
24
- if (xhr.readyState === 4 && xhr.status === 200) {
25
- finishedUploads.push(uploadId);
26
-
27
- response = JSON.parse(xhr.responseText);
28
-
29
- dispatchEvent($element, 'upload:success', {
30
- uploadId: uploadId,
31
- uid: response.uid,
32
- wasLastUpload: lastUploadId == finishedUploads.length
33
- });
34
- }
35
- }
36
-
37
- xhr.upload.addEventListener('progress', function(progressEvent) {
38
- if (progressEvent.lengthComputable) {
39
- dispatchEvent($element, 'upload:progress', {
40
- uploadId: uploadId,
41
- progress: progressEvent
2
+ var MountableFileServerUploader = function(options) {
3
+ return {
4
+ url: options.url,
5
+ uploadFile: function(options) {
6
+
7
+ var file = options.file;
8
+ var type = options.type;
9
+ var onStart = options.onStart || function() {};
10
+ var onProgress = options.onProgress || function() {};
11
+ var onSuccess = options.onSuccess || function() {};
12
+ var xhr = new XMLHttpRequest();
13
+ var formData = new FormData();
14
+
15
+ formData.append('file', file);
16
+ formData.append('type', type);
17
+
18
+ xhr.open('POST', this.url, true);
19
+
20
+ xhr.onreadystatechange = function() {
21
+ if (xhr.readyState === 4 && xhr.status === 201) {
22
+ var response = JSON.parse(xhr.responseText);
23
+
24
+ response.original_filename = file.name;
25
+
26
+ onSuccess(response);
27
+ }
28
+ }
29
+
30
+ xhr.upload.addEventListener('progress', function(progressEvent) {
31
+ if (progressEvent.lengthComputable) {
32
+ onProgress(progressEvent);
33
+ }
42
34
  });
43
- }
44
- });
45
-
46
- xhr.send(formData);
47
35
 
48
- dispatchEvent($element, 'upload:start', {
49
- uploadId: uploadId,
50
- file: file
51
- });
52
- };
36
+ xhr.send(formData);
53
37
 
54
- var internalUploadFiles = function($element, files) {
55
- for (var i = 0; i < files.length; i++) {
56
- uploadFile($element, files[i], ++lastUploadId);
57
- }
38
+ onStart();
39
+ }
40
+ };
58
41
  };
59
42
 
60
- window.uploadFiles = internalUploadFiles;
43
+ window.MountableFileServerUploader = MountableFileServerUploader;
61
44
  })();
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mountable_file_server
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Strauß
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-24 00:00:00.000000000 Z
11
+ date: 2017-03-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 4.2.3
61
+ version: 5.0.2
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 4.2.3
68
+ version: 5.0.2
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: capybara
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -123,75 +123,61 @@ dependencies:
123
123
  - !ruby/object:Gem::Version
124
124
  version: 0.6.3
125
125
  - !ruby/object:Gem::Dependency
126
- name: bogus
126
+ name: webmock
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 0.1.6
131
+ version: 2.1.0
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 0.1.6
138
+ version: 2.1.0
139
139
  - !ruby/object:Gem::Dependency
140
- name: rack
140
+ name: sinatra
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '1.6'
145
+ version: 2.0.0.rc1
146
146
  type: :runtime
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '1.6'
152
+ version: 2.0.0.rc1
153
153
  - !ruby/object:Gem::Dependency
154
- name: sinatra
154
+ name: dry-configurable
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - "~>"
158
158
  - !ruby/object:Gem::Version
159
- version: 1.4.5
159
+ version: 0.1.6
160
160
  type: :runtime
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
- version: 1.4.5
167
- - !ruby/object:Gem::Dependency
168
- name: mini_magick
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - ">="
172
- - !ruby/object:Gem::Version
173
- version: '0'
174
- type: :runtime
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - ">="
179
- - !ruby/object:Gem::Version
180
- version: '0'
166
+ version: 0.1.6
181
167
  - !ruby/object:Gem::Dependency
182
- name: url_safe_base64
168
+ name: dimensions
183
169
  requirement: !ruby/object:Gem::Requirement
184
170
  requirements:
185
- - - ">="
171
+ - - "~>"
186
172
  - !ruby/object:Gem::Version
187
- version: '0'
173
+ version: 1.3.0
188
174
  type: :runtime
189
175
  prerelease: false
190
176
  version_requirements: !ruby/object:Gem::Requirement
191
177
  requirements:
192
- - - ">="
178
+ - - "~>"
193
179
  - !ruby/object:Gem::Version
194
- version: '0'
180
+ version: 1.3.0
195
181
  description: ''
196
182
  email:
197
183
  - david@strauss.io
@@ -208,10 +194,11 @@ files:
208
194
  - Rakefile
209
195
  - lib/mountable_file_server.rb
210
196
  - lib/mountable_file_server/adapter.rb
211
- - lib/mountable_file_server/configuration.rb
212
- - lib/mountable_file_server/endpoint.rb
197
+ - lib/mountable_file_server/client.rb
213
198
  - lib/mountable_file_server/file_accessor.rb
199
+ - lib/mountable_file_server/metadata.rb
214
200
  - lib/mountable_file_server/rails.rb
201
+ - lib/mountable_file_server/server.rb
215
202
  - lib/mountable_file_server/storage.rb
216
203
  - lib/mountable_file_server/unique_identifier.rb
217
204
  - lib/mountable_file_server/uri.rb
@@ -238,7 +225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
238
225
  version: '0'
239
226
  requirements: []
240
227
  rubyforge_project:
241
- rubygems_version: 2.4.5
228
+ rubygems_version: 2.5.1
242
229
  signing_key:
243
230
  specification_version: 4
244
231
  summary: Simple mountable server that handles file uploads
@@ -1,10 +0,0 @@
1
- module MountableFileServer
2
- class Configuration
3
- attr_accessor :mounted_at, :stored_at
4
-
5
- def initialize(mounted_at = '', stored_at = '')
6
- @mounted_at = mounted_at
7
- @stored_at = stored_at
8
- end
9
- end
10
- end
@@ -1,58 +0,0 @@
1
- require 'sinatra/base'
2
- require 'url_safe_base64'
3
- require 'mini_magick'
4
- require 'pathname'
5
-
6
- module MountableFileServer
7
- class Endpoint < Sinatra::Base
8
- attr_reader :configuration
9
-
10
- def initialize(configuration = MountableFileServer.configuration)
11
- @configuration = configuration
12
- super
13
- end
14
-
15
- post '/' do
16
- pathname = Pathname(params[:file][:tempfile].path)
17
- type = params[:type]
18
- adapter = Adapter.new configuration
19
- uid = adapter.store_temporary(pathname, type, pathname.extname)
20
-
21
-
22
- content_type :json
23
- { uid: uid }.to_json
24
- end
25
-
26
- get '/*' do
27
- deliver_file unescape(request.path_info)
28
- end
29
-
30
- def deliver_file(filename)
31
- path_to_file = File.join(configuration.stored_at, 'public', filename)
32
-
33
- if File.file?(path_to_file)
34
- send_file path_to_file
35
- else
36
- if filename.count('.') == 2
37
- parts = filename.split('.')
38
- base_filename = "#{parts[0]}.#{parts[2]}"
39
- path_to_base_file = File.join(configuration.stored_at, 'public', base_filename)
40
-
41
- if File.file?(path_to_base_file)
42
- resize_command = UrlSafeBase64.decode64 parts[1]
43
- image = MiniMagick::Image.open path_to_base_file
44
- image.resize resize_command.to_s
45
- image.write path_to_file
46
- send_file path_to_file
47
- else
48
- not_found
49
- end
50
- else
51
- not_found
52
- end
53
-
54
- not_found
55
- end
56
- end
57
- end
58
- end