snapimage 0.0.1
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/.autotest +3 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/bin/snapimage_generate_config +63 -0
- data/bin/snapimage_server +55 -0
- data/lib/snapimage.rb +24 -0
- data/lib/snapimage/config.rb +51 -0
- data/lib/snapimage/exceptions.rb +25 -0
- data/lib/snapimage/image/image.rb +96 -0
- data/lib/snapimage/image/image_name_utils.rb +131 -0
- data/lib/snapimage/middleware.rb +27 -0
- data/lib/snapimage/rack/request.rb +19 -0
- data/lib/snapimage/rack/request_file.rb +26 -0
- data/lib/snapimage/rack/response.rb +51 -0
- data/lib/snapimage/server.rb +50 -0
- data/lib/snapimage/server_actions/server_actions.authorize.rb +69 -0
- data/lib/snapimage/server_actions/server_actions.delete_resource_images.rb +23 -0
- data/lib/snapimage/server_actions/server_actions.generate_image.rb +167 -0
- data/lib/snapimage/server_actions/server_actions.list_resource_images.rb +23 -0
- data/lib/snapimage/server_actions/server_actions.sync_resource.rb +78 -0
- data/lib/snapimage/storage/storage.rb +120 -0
- data/lib/snapimage/storage/storage_server.local.rb +120 -0
- data/lib/snapimage/storage/storage_server.rb +110 -0
- data/lib/snapimage/version.rb +3 -0
- data/snapimage.gemspec +27 -0
- data/spec/acceptance/delete_resource_images_spec.rb +166 -0
- data/spec/acceptance/list_resource_images_spec.rb +158 -0
- data/spec/acceptance/modify_spec.rb +165 -0
- data/spec/acceptance/sync_spec.rb +260 -0
- data/spec/acceptance/upload_spec.rb +235 -0
- data/spec/snapimage/config_spec.rb +56 -0
- data/spec/snapimage/image/image_name_utils_spec.rb +127 -0
- data/spec/snapimage/image/image_spec.rb +71 -0
- data/spec/snapimage/middleware_spec.rb +27 -0
- data/spec/snapimage/rack/request_file_spec.rb +15 -0
- data/spec/snapimage/rack/request_spec.rb +52 -0
- data/spec/snapimage/rack/response_spec.rb +33 -0
- data/spec/snapimage/server_actions/server_actions.authorize_spec.rb +67 -0
- data/spec/snapimage/server_actions/server_actions.generate_image_spec.rb +146 -0
- data/spec/snapimage/server_actions/server_actions.sync_resource_spec.rb +91 -0
- data/spec/snapimage/server_spec.rb +55 -0
- data/spec/snapimage/storage/assets/local/resource_1/12345678-1x1-0x0x1x1-1x1-1.gif +0 -0
- data/spec/snapimage/storage/assets/local/resource_1/12345678-1x1-0x0x1x1-300x200-0.jpg +0 -0
- data/spec/snapimage/storage/assets/local/resource_1/12345678-1x1.png +0 -0
- data/spec/snapimage/storage/assets/local/resource_2/12345678-1x1-0x0x1x1-1x1-1.gif +0 -0
- data/spec/snapimage/storage/assets/local/resource_2/12345678-1x1-0x0x1x1-300x200-0.jpg +0 -0
- data/spec/snapimage/storage/assets/local/resource_2/12345678-1x1.png +0 -0
- data/spec/snapimage/storage/storage_server.local_spec.rb +150 -0
- data/spec/snapimage/storage/storage_server_spec.rb +97 -0
- data/spec/snapimage/storage/storage_spec.rb +49 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/assets/config.json +8 -0
- data/spec/support/assets/config.yml +9 -0
- data/spec/support/assets/stub-1x1.png +0 -0
- data/spec/support/assets/stub-2048x100.png +0 -0
- data/spec/support/assets/stub-300x200.png +0 -0
- metadata +272 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
module SnapImage
|
2
|
+
# SnapImage API Rack Middleware to handle all SnapImage API calls.
|
3
|
+
class Middleware
|
4
|
+
# Arguments:
|
5
|
+
# * app:: Rack application
|
6
|
+
# * path:: The URL path to access the SnapImage API (defaults to "/snapimage_api")
|
7
|
+
# * config:: Filename of the YAML or JSON config file or a config Hash
|
8
|
+
def initialize(app, options = {})
|
9
|
+
@app = app
|
10
|
+
@path = options[:path] || "/snapimage_api"
|
11
|
+
# TODO: If no config is given, set defaults.
|
12
|
+
# For example, if it's a Rails app, set the filename to
|
13
|
+
# config/snapimage.yml.
|
14
|
+
raise SnapImage::MissingConfig, "Missing config." if options[:config].nil?
|
15
|
+
@config = SnapImage::Config.new(options[:config])
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
request = SnapImage::Request.new(env)
|
20
|
+
if request.path_info == @path
|
21
|
+
SnapImage::Server.new(request, @config).call
|
22
|
+
else
|
23
|
+
@app.call(env)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module SnapImage
|
2
|
+
class Request < Rack::Request
|
3
|
+
def bad_request?
|
4
|
+
!(self.post? && self.POST["json"] && self.json["action"] && self.json["resource_identifier"])
|
5
|
+
end
|
6
|
+
|
7
|
+
# NOTE: Call bad_request? first to make sure there is json to parse.
|
8
|
+
def json
|
9
|
+
@json ||= JSON.parse(self.POST["json"])
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns a SnapImage::RequestFile which encapsulates the file that Rack
|
13
|
+
# provides. Returns nil if there is no file.
|
14
|
+
def file
|
15
|
+
return nil unless self.POST["file"]
|
16
|
+
@file ||= SnapImage::RequestFile.new(self.POST["file"])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module SnapImage
|
2
|
+
class RequestFile
|
3
|
+
# The file comes through Rack's request's POST like this:
|
4
|
+
# {
|
5
|
+
# :filename=>"jpeg.jpeg",
|
6
|
+
# :type=>"image/jpeg",
|
7
|
+
# :name=>"file",
|
8
|
+
# :tempfile=>#<File:/tmp/RackMultipart20120628-19317-1w4ouxp>,
|
9
|
+
# :head=>"Content-Disposition: form-data; name=\"file\"; filename=\"jpeg.jpeg\"\r\nContent-Type: image/jpeg\r\n"}
|
10
|
+
# }
|
11
|
+
def initialize(file)
|
12
|
+
@file = file
|
13
|
+
end
|
14
|
+
|
15
|
+
def file
|
16
|
+
@file[:tempfile]
|
17
|
+
end
|
18
|
+
|
19
|
+
def type
|
20
|
+
return @type if @type
|
21
|
+
@type = File.extname(@file[:filename])[1..-1]
|
22
|
+
@type = "jpg" if type == "jpeg"
|
23
|
+
@type
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module SnapImage
|
2
|
+
class Response < Rack::Response
|
3
|
+
attr_accessor :content_type, :template, :json
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
@content_type = options[:content_type] || "text/json"
|
7
|
+
@template = options[:template] || "{{json}}"
|
8
|
+
@json = {}
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_success(info = {})
|
13
|
+
info[:message] ||= "Success"
|
14
|
+
@json = { status_code: 200 }.merge(info)
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_bad_request
|
18
|
+
@json = { status_code: 400, message: "Bad Request" }
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_authorization_required
|
22
|
+
@json = { status_code: 401, message: "Authorization Required" }
|
23
|
+
end
|
24
|
+
|
25
|
+
def set_authorization_failed
|
26
|
+
@json = { status_code: 402, message: "Authorization Failed" }
|
27
|
+
end
|
28
|
+
|
29
|
+
def set_invalid_image_identifier
|
30
|
+
@json = { status_code: 403, message: "Invalid Image Identifier" }
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_invalid_resource_identifier
|
34
|
+
@json = { status_code: 404, message: "Invalid Resource Identifier" }
|
35
|
+
end
|
36
|
+
|
37
|
+
def set_internal_server_error
|
38
|
+
@json = { status_code: 500, message: "Internal Server Error" }
|
39
|
+
end
|
40
|
+
|
41
|
+
def set_not_implemented
|
42
|
+
@json = { status_code: 501, message: "Not Implemented" }
|
43
|
+
end
|
44
|
+
|
45
|
+
def finish
|
46
|
+
self.body = [@template.gsub(/{{json}}/, @json.to_json)]
|
47
|
+
self["Content-Type"] = @content_type
|
48
|
+
super
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module SnapImage
|
2
|
+
class Server
|
3
|
+
ACTIONS = ["generate_image", "sync_resource", "delete_resource_images", "list_resource_images"]
|
4
|
+
RESOURCE_ID_REGEXP = /^[a-z0-9_-]+(\/[a-z0-9_-]+)*$/
|
5
|
+
|
6
|
+
# Arguments:
|
7
|
+
# * request:: Rack::Request
|
8
|
+
def initialize(request, config)
|
9
|
+
@request = request
|
10
|
+
@config = config
|
11
|
+
@storage = @config.storage
|
12
|
+
end
|
13
|
+
|
14
|
+
# Handles the request and returns a Rack::Response.
|
15
|
+
def call
|
16
|
+
@response = SnapImage::Response.new
|
17
|
+
begin
|
18
|
+
raise SnapImage::BadRequest if @request.bad_request?
|
19
|
+
raise SnapImage::InvalidResourceIdentifier unless !!@request.json["resource_identifier"].match(SnapImage::Server::RESOURCE_ID_REGEXP)
|
20
|
+
@response.content_type = @request.json["response_content_type"] if @request.json["response_content_type"]
|
21
|
+
@response.template = @request.json["response_template"] if @request.json["response_template"]
|
22
|
+
action = @request.json["action"]
|
23
|
+
raise SnapImage::ActionNotImplemented unless ACTIONS.include?(action)
|
24
|
+
@response = get_action_class(action).new(@config, @request, @response).call
|
25
|
+
rescue SnapImage::BadRequest
|
26
|
+
@response.set_bad_request
|
27
|
+
rescue SnapImage::ActionNotImplemented
|
28
|
+
@response.set_not_implemented
|
29
|
+
rescue SnapImage::AuthorizationRequired
|
30
|
+
@response.set_authorization_required
|
31
|
+
rescue SnapImage::AuthorizationFailed
|
32
|
+
@response.set_authorization_failed
|
33
|
+
rescue SnapImage::InvalidImageIdentifier
|
34
|
+
@response.set_invalid_image_identifier
|
35
|
+
rescue SnapImage::InvalidResourceIdentifier
|
36
|
+
@response.set_invalid_resource_identifier
|
37
|
+
#rescue
|
38
|
+
#@response.set_internal_server_error
|
39
|
+
end
|
40
|
+
@response.finish
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def get_action_class(action)
|
46
|
+
klassname = action.split("_").map { |t| t.capitalize }.join("")
|
47
|
+
SnapImage::ServerActions.const_get(klassname)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module SnapImage
|
2
|
+
module ServerActions
|
3
|
+
module Authorize
|
4
|
+
def get_token(role)
|
5
|
+
@request.json["#{role}_security_token"]
|
6
|
+
end
|
7
|
+
|
8
|
+
# Arguments:
|
9
|
+
# * role:: Can be either :client or :server
|
10
|
+
def token_available?(role)
|
11
|
+
!!get_token(role)
|
12
|
+
end
|
13
|
+
|
14
|
+
# A string is generated using
|
15
|
+
# * role:: "client" or "server"
|
16
|
+
# * date:: Date in the format "YYYY-MM-DD"
|
17
|
+
# * salt:: A shared salt
|
18
|
+
# * resource_id:: The resource's identifier
|
19
|
+
# and concatenated as "role:date:salt:resource_id".
|
20
|
+
#
|
21
|
+
# A SHA1 digest is generated off of the string to create a token.
|
22
|
+
#
|
23
|
+
# 3 tokens are generated: [yesterday, today, tomorrow].
|
24
|
+
def generate_tokens(role)
|
25
|
+
salt = @config["security_salt"]
|
26
|
+
now = Time.now
|
27
|
+
yesterday = (now - 24*60*60).strftime("%Y-%m-%d")
|
28
|
+
today = now.strftime("%Y-%m-%d")
|
29
|
+
tomorrow = (now + 24*60*60).strftime("%Y-%m-%d")
|
30
|
+
resource_id = @request.json["resource_identifier"]
|
31
|
+
[
|
32
|
+
Digest::SHA1.hexdigest("#{role}:#{yesterday}:#{salt}:#{resource_id}"),
|
33
|
+
Digest::SHA1.hexdigest("#{role}:#{today}:#{salt}:#{resource_id}"),
|
34
|
+
Digest::SHA1.hexdigest("#{role}:#{tomorrow}:#{salt}:#{resource_id}")
|
35
|
+
]
|
36
|
+
end
|
37
|
+
|
38
|
+
# If "security_salt" is set in the config, authorization is performed.
|
39
|
+
#
|
40
|
+
# A string is generated using
|
41
|
+
# * role:: "client" or "server"
|
42
|
+
# * date:: Date in the format "YYYY-MM-DD"
|
43
|
+
# * salt:: A shared salt
|
44
|
+
# * resource_id:: The resource's identifier
|
45
|
+
# and concatenated as "role:date:salt:resource_id".
|
46
|
+
#
|
47
|
+
# A SHA1 digest is generated off of the string to create a token. A token
|
48
|
+
# for yesterday, today, and tomorrow are generated and used to compare
|
49
|
+
# with the security token.
|
50
|
+
#
|
51
|
+
# When authorization fails, an error is raised. Authorization can fail in
|
52
|
+
# 2 ways.
|
53
|
+
# * AuthorizationRequired:: The role's security token is missing
|
54
|
+
# * AuthorizationFailed:: The security token did not match the generated token
|
55
|
+
#
|
56
|
+
# If authorization is successful, true is returned.
|
57
|
+
#
|
58
|
+
# Arguments:
|
59
|
+
# * role:: Can be either :client or :server
|
60
|
+
def authorize(role)
|
61
|
+
if @config["security_salt"]
|
62
|
+
raise SnapImage::AuthorizationRequired unless token_available?(role)
|
63
|
+
raise SnapImage::AuthorizationFailed unless generate_tokens(role).include?(get_token(role))
|
64
|
+
end
|
65
|
+
return true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module SnapImage
|
2
|
+
module ServerActions
|
3
|
+
class DeleteResourceImages
|
4
|
+
include SnapImage::ServerActions::Authorize
|
5
|
+
|
6
|
+
def initialize(config, request, response)
|
7
|
+
@config = config
|
8
|
+
@storage = config.storage
|
9
|
+
@request = request
|
10
|
+
@response = response
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
authorize(:server)
|
15
|
+
@response.set_success(
|
16
|
+
message: "Delete Resource Images Successful",
|
17
|
+
deleted_image_urls: @storage.delete_resource_images(@request.json["resource_identifier"])
|
18
|
+
)
|
19
|
+
@response
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module SnapImage
|
2
|
+
module ServerActions
|
3
|
+
class GenerateImage
|
4
|
+
include SnapImage::ServerActions::Authorize
|
5
|
+
|
6
|
+
def initialize(config, request, response)
|
7
|
+
@config = config
|
8
|
+
@storage = config.storage
|
9
|
+
@request = request
|
10
|
+
@response = response
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
authorize(:client)
|
15
|
+
if request_valid?
|
16
|
+
image = get_image_for_modification
|
17
|
+
parts = SnapImage::ImageNameUtils.get_image_name_parts(image.public_url)
|
18
|
+
result = modify_image(image)
|
19
|
+
modified_image = result[:image]
|
20
|
+
modified_image_name = result[:name]
|
21
|
+
stored_image = @storage.add_image(modified_image, modified_image_name, @request.json["resource_identifier"])
|
22
|
+
@response.set_success(
|
23
|
+
message: "Get Modified Image Successful",
|
24
|
+
image_url: stored_image.public_url,
|
25
|
+
image_width: stored_image.width,
|
26
|
+
image_height: stored_image.height
|
27
|
+
)
|
28
|
+
else
|
29
|
+
@response.set_bad_request
|
30
|
+
end
|
31
|
+
@response
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# Returns true if the request is valid. False otherwise.
|
37
|
+
def request_valid?
|
38
|
+
source_image_defined?
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns true if either "file" or JSON "url" is defined.
|
42
|
+
def source_image_defined?
|
43
|
+
!!(@request.file || @request.json["url"])
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns true if the image is being uploaded. False otherwise.
|
47
|
+
def upload?
|
48
|
+
@request.file || !@storage.local?(@request.json["url"])
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns true if cropping is required. False otherwise.
|
52
|
+
def crop?
|
53
|
+
@request.json["crop_x"] || @request.json["crop_y"] || @request.json["crop_width"] || @request.json["crop_height"]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns true if all the cropping values are defined. False otherwise.
|
57
|
+
def crop_valid?
|
58
|
+
@request.json["crop_x"] && @request.json["crop_y"] && @request.json["crop_width"] && @request.json["crop_height"]
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns true if resizing is required. False otherwise.
|
62
|
+
def resize?
|
63
|
+
@request.json["width"] || @request.json["height"]
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns true if the image is too large and needs to be resized to fit.
|
67
|
+
# False otherwise.
|
68
|
+
def resize_to_fit?(image)
|
69
|
+
image.width > get_max_width || image.height > get_max_height
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns true if sharpening is required. False otherwise
|
73
|
+
def sharpen?
|
74
|
+
@request.json["sharpen"]
|
75
|
+
end
|
76
|
+
|
77
|
+
# Gets the max width. Takes the lesser of the JSON "max_width" or the
|
78
|
+
# server max width.
|
79
|
+
def get_max_width
|
80
|
+
server_max_width = @config["max_width"]
|
81
|
+
[(@request.json["max_width"] && @request.json["max_width"].to_i || server_max_width), server_max_width].min
|
82
|
+
end
|
83
|
+
|
84
|
+
# Gets the max height. Takes the lesser of the JSON "max_height" or the
|
85
|
+
# server max height.
|
86
|
+
def get_max_height
|
87
|
+
server_max_height = @config["max_height"]
|
88
|
+
[(@request.json["max_height"] && @request.json["max_height"].to_i || server_max_height), server_max_height].min
|
89
|
+
end
|
90
|
+
|
91
|
+
def get_image_for_modification
|
92
|
+
if upload?
|
93
|
+
# Add the image to the storage.
|
94
|
+
if @request.file
|
95
|
+
image = @storage.add_upload(@request.file, @request.json["resource_identifier"])
|
96
|
+
else
|
97
|
+
image = @storage.add_url(@request.json["url"], @request.json["resource_identifier"])
|
98
|
+
end
|
99
|
+
else
|
100
|
+
# Get the base image.
|
101
|
+
raise SnapImage::InvalidImageIdentifier unless SnapImage::ImageNameUtils.valid?(@request.json["url"])
|
102
|
+
image = @storage.get(SnapImage::ImageNameUtils.get_base_image_path(@request.json["url"]))
|
103
|
+
end
|
104
|
+
image
|
105
|
+
end
|
106
|
+
|
107
|
+
# Arguments:
|
108
|
+
# * image:: SnapImage::Image object that represents the base image
|
109
|
+
def modify_image(image)
|
110
|
+
parts = SnapImage::ImageNameUtils.get_image_name_parts(image.public_url)
|
111
|
+
|
112
|
+
# Crop.
|
113
|
+
cropped = crop?
|
114
|
+
crop = nil
|
115
|
+
if cropped
|
116
|
+
raise SnapImage::BadRequest, "Missing crop values." unless crop_valid?
|
117
|
+
crop = {
|
118
|
+
x: @request.json["crop_x"],
|
119
|
+
y: @request.json["crop_y"],
|
120
|
+
width: @request.json["crop_width"],
|
121
|
+
height: @request.json["crop_height"]
|
122
|
+
}
|
123
|
+
image = image.crop(crop[:x], crop[:y], crop[:width], crop[:height])
|
124
|
+
end
|
125
|
+
|
126
|
+
# Resize.
|
127
|
+
resized = resize?
|
128
|
+
if resized
|
129
|
+
width = @request.json["width"] && @request.json["width"].to_i
|
130
|
+
height = @request.json["height"] && @request.json["height"].to_i
|
131
|
+
if width && height
|
132
|
+
# When both width and height are specified, resize without
|
133
|
+
# maintaining the aspect ratio.
|
134
|
+
image = image.resize(width, height, false)
|
135
|
+
else
|
136
|
+
# When only one of width/height is specified, set the other to the
|
137
|
+
# max and maintain the aspect ratio.
|
138
|
+
image = image.resize(width || @config["max_width"], height || @config["max_height"])
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Resize to fit.
|
143
|
+
resized_to_fit = resize_to_fit?(image)
|
144
|
+
image = image.resize(get_max_width, get_max_height) if resized_to_fit
|
145
|
+
|
146
|
+
# Sharpen.
|
147
|
+
sharpened = sharpen?
|
148
|
+
image = image.sharpen if sharpened
|
149
|
+
|
150
|
+
# Get the dimensions at the end.
|
151
|
+
if cropped || resized || resized_to_fit || sharpened
|
152
|
+
modifications = {
|
153
|
+
crop: crop || { x: 0, y: 0, width: parts[:original_dimensions][0], height: parts[:original_dimensions][1] },
|
154
|
+
width: image.width,
|
155
|
+
height: image.height,
|
156
|
+
sharpen: sharpened
|
157
|
+
}
|
158
|
+
name = SnapImage::ImageNameUtils.generate_image_name(parts[:original_dimensions][0], parts[:original_dimensions][1], parts[:extname], {basename: parts[:basename]}.merge(modifications))
|
159
|
+
else
|
160
|
+
name = parts[:filename]
|
161
|
+
end
|
162
|
+
|
163
|
+
{ image: image, name: name }
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module SnapImage
|
2
|
+
module ServerActions
|
3
|
+
class ListResourceImages
|
4
|
+
include SnapImage::ServerActions::Authorize
|
5
|
+
|
6
|
+
def initialize(config, request, response)
|
7
|
+
@config = config
|
8
|
+
@storage = config.storage
|
9
|
+
@request = request
|
10
|
+
@response = response
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
authorize(:server)
|
15
|
+
@response.set_success(
|
16
|
+
message: "List Resource Images Successful",
|
17
|
+
image_urls: @storage.get_resource_urls(@request.json["resource_identifier"])
|
18
|
+
)
|
19
|
+
@response
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|