visor-meta 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/bin/visor-meta +8 -0
- data/lib/meta/backends/base.rb +302 -0
- data/lib/meta/backends/mongo_db.rb +195 -0
- data/lib/meta/backends/mysql_db.rb +235 -0
- data/lib/meta/cli.rb +333 -0
- data/lib/meta/client.rb +313 -0
- data/lib/meta/server.rb +295 -0
- data/lib/meta/version.rb +5 -0
- data/lib/visor-meta.rb +12 -0
- data/spec/lib/backends/base_spec.rb +209 -0
- data/spec/lib/backends/mongo_db_spec.rb +152 -0
- data/spec/lib/backends/mysql_db_spec.rb +164 -0
- data/spec/lib/client_spec.rb +179 -0
- data/spec/lib/server_spec.rb +214 -0
- metadata +209 -0
data/bin/visor-meta
ADDED
@@ -0,0 +1,302 @@
|
|
1
|
+
module Visor::Meta
|
2
|
+
module Backends
|
3
|
+
|
4
|
+
# This is the Base super class for all Backends. Each new backend inherits from Base,
|
5
|
+
# which contains the model and all validations for the images metadata.
|
6
|
+
#
|
7
|
+
# Implementing a new backend is as simple as create a new backend class which inherits
|
8
|
+
# from Base and them implement the specific methods for querying the underlying database.
|
9
|
+
#
|
10
|
+
class Base
|
11
|
+
# TODO validate owner user
|
12
|
+
|
13
|
+
# Keys validation
|
14
|
+
#
|
15
|
+
# Mandatory attributes
|
16
|
+
MANDATORY = [:name, :architecture]
|
17
|
+
# Read-only attributes
|
18
|
+
READONLY = [:_id, :uri, :created_at, :updated_at, :accessed_at, :access_count]
|
19
|
+
# Optional attributes
|
20
|
+
OPTIONAL = [:owner, :status, :size, :checksum, :access, :type, :format,
|
21
|
+
:uploaded_at, :store, :location, :kernel, :ramdisk]
|
22
|
+
# All attributes
|
23
|
+
ALL = MANDATORY + OPTIONAL + READONLY
|
24
|
+
|
25
|
+
# Values validation
|
26
|
+
#
|
27
|
+
# Architecture options
|
28
|
+
ARCHITECTURE = %w[i386 x86_64]
|
29
|
+
# Access options
|
30
|
+
ACCESS = %w[public private]
|
31
|
+
# Possible disk formats
|
32
|
+
FORMAT = %w[iso vhd vdi vmdk ovf ami aki ari]
|
33
|
+
# Possible types
|
34
|
+
TYPE = %w[kernel ramdisk machine]
|
35
|
+
# Possible status
|
36
|
+
STATUS = %w[locked uploading error available]
|
37
|
+
# Possible storage
|
38
|
+
STORE = %w[s3 cumulus walrus hdfs lcs http file]
|
39
|
+
|
40
|
+
# Presentation options
|
41
|
+
#
|
42
|
+
# Brief attributes used to return only brief information about images.
|
43
|
+
BRIEF = [:_id, :name, :architecture, :type, :format, :store, :size]
|
44
|
+
# Attributes to exclude from get public images requests, allowing to show other custom attributes.
|
45
|
+
DETAIL_EXC = [:accessed_at, :access_count]
|
46
|
+
# Valid parameters to filter results from requests query, add sort parameter and sort direction.
|
47
|
+
FILTERS = ALL + [:sort, :dir]
|
48
|
+
|
49
|
+
attr_reader :db, :host, :port, :user, :password, :conn
|
50
|
+
|
51
|
+
# Initializes a Backend instance.
|
52
|
+
#
|
53
|
+
# @option [Hash] opts Any of the available options can be passed.
|
54
|
+
#
|
55
|
+
# @option opts [String] :host The host address.
|
56
|
+
# @option opts [Integer] :port The port to be used.
|
57
|
+
# @option opts [String] :db The wanted database.
|
58
|
+
# @option opts [String] :user The username to be authenticate db access.
|
59
|
+
# @option opts [String] :password The password to be authenticate db access.
|
60
|
+
# @option opts [Object] :conn The connection pool to access database.
|
61
|
+
#
|
62
|
+
def initialize(opts)
|
63
|
+
@host = opts[:host]
|
64
|
+
@port = opts[:port]
|
65
|
+
@db = opts[:db]
|
66
|
+
@user = opts[:user]
|
67
|
+
@password = opts[:password]
|
68
|
+
@conn = opts[:conn]
|
69
|
+
end
|
70
|
+
|
71
|
+
# Validates the image metadata for a post operation, based on possible keys and values.
|
72
|
+
#
|
73
|
+
# @param [Hash] meta The image metadata.
|
74
|
+
#
|
75
|
+
# @raise[ArgumentError] If some of the metadata fields do not respect the
|
76
|
+
# possible values, contains any read-only or misses any mandatory field.
|
77
|
+
#
|
78
|
+
def validate_data_post(meta)
|
79
|
+
meta.assert_exclusion_keys(READONLY)
|
80
|
+
meta.assert_inclusion_keys(MANDATORY)
|
81
|
+
|
82
|
+
meta.assert_valid_values_for(:architecture, ARCHITECTURE)
|
83
|
+
meta.assert_valid_values_for(:access, ACCESS)
|
84
|
+
meta.assert_valid_values_for(:format, FORMAT)
|
85
|
+
meta.assert_valid_values_for(:type, TYPE)
|
86
|
+
meta.assert_valid_values_for(:store, STORE)
|
87
|
+
|
88
|
+
assert_ramdisk_and_kernel(meta)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Validates the image metadata for a put operation, based on possible keys and values.
|
92
|
+
#
|
93
|
+
# @param [Hash] meta The image metadata.
|
94
|
+
#
|
95
|
+
# @raise[ArgumentError] If some of the metadata fields do not respect the
|
96
|
+
# possible values, contains any read-only or misses any mandatory field.
|
97
|
+
#
|
98
|
+
def validate_data_put(meta)
|
99
|
+
meta.assert_exclusion_keys(READONLY)
|
100
|
+
|
101
|
+
meta.assert_valid_values_for(:architecture, ARCHITECTURE)
|
102
|
+
meta.assert_valid_values_for(:access, ACCESS)
|
103
|
+
meta.assert_valid_values_for(:format, FORMAT)
|
104
|
+
meta.assert_valid_values_for(:type, TYPE)
|
105
|
+
meta.assert_valid_values_for(:store, STORE)
|
106
|
+
|
107
|
+
assert_ramdisk_and_kernel(meta)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Validates that incoming query filters fields are valid.
|
111
|
+
#
|
112
|
+
# @param [Hash] filters The image metadata filters comming from a GET request.
|
113
|
+
#
|
114
|
+
# @raise[ArgumentError] If some of the query filter fields do not respect the
|
115
|
+
# possible values.
|
116
|
+
#
|
117
|
+
def validate_query_filters(filters)
|
118
|
+
filters.symbolize_keys!
|
119
|
+
filters.assert_valid_keys(FILTERS)
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
# Set protected fields value from a post operation.
|
124
|
+
# Being them the _id, uri, owner, size, access, status and created_at.
|
125
|
+
#
|
126
|
+
# @param [Hash] meta The image metadata.
|
127
|
+
#
|
128
|
+
# @option [Hash] opts Any of the available options can be passed.
|
129
|
+
#
|
130
|
+
# @option opts [String] :owner (Nil) The image owner.
|
131
|
+
# @option opts [String] :size (Nil) The image file size.
|
132
|
+
#
|
133
|
+
# @return [Hash] The image metadata filled with protected fields values.
|
134
|
+
#
|
135
|
+
def set_protected_post(meta, opts = {})
|
136
|
+
owner, size = opts[:owner], opts[:size]
|
137
|
+
meta.merge!(_id: SecureRandom.uuid)
|
138
|
+
meta.merge!(access: 'public') unless meta[:access]
|
139
|
+
meta.merge!(owner: owner) if owner
|
140
|
+
meta.merge!(size: size) if size
|
141
|
+
meta.merge!(created_at: Time.now, uri: build_uri(meta[:_id]), status: 'locked')
|
142
|
+
end
|
143
|
+
|
144
|
+
# Set protected fields value from a get operation.
|
145
|
+
# Being them the accessed_at and access_count.
|
146
|
+
#
|
147
|
+
# @param [Hash] meta The image metadata update.
|
148
|
+
#
|
149
|
+
# @return [Hash] The image metadata update with protected fields setted.
|
150
|
+
#
|
151
|
+
def set_protected_put(meta)
|
152
|
+
meta.merge!(updated_at: Time.now)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Build an URI for the given image _id based on VISoR Image Server configuration.
|
156
|
+
#
|
157
|
+
# @param [String] id The _id of the image.
|
158
|
+
#
|
159
|
+
# @return [String] The generated URI.
|
160
|
+
#
|
161
|
+
def build_uri(id)
|
162
|
+
conf = Visor::Common::Config.load_config :visor_image
|
163
|
+
host = conf[:bind_host] || Visor::Meta::Server::DEFAULT_HOST
|
164
|
+
port = conf[:bind_port] || Visor::Meta::Server::DEFAULT_PORT
|
165
|
+
"http://#{host}:#{port}/images/#{id}"
|
166
|
+
end
|
167
|
+
|
168
|
+
# Serializes with JSON and encapsulate additional (not on the table schema) image attributes
|
169
|
+
# on the others schema field.
|
170
|
+
#
|
171
|
+
# This is used for SQL Backends, as they are not schema free.
|
172
|
+
#
|
173
|
+
# @example Instantiate a client with default values:
|
174
|
+
# # So this:
|
175
|
+
# {name: 'example', access: 'public', extra_key: 'value', another: 'value'}
|
176
|
+
# # becomes this:
|
177
|
+
# {name: "example", access: "public", others: "{\"extra_key\":\"value\",\"another\":\"value\"}"}"}
|
178
|
+
#
|
179
|
+
# @param [Hash] meta The image metadata.
|
180
|
+
#
|
181
|
+
def serialize_others(meta)
|
182
|
+
other_keys = meta.keys - ALL
|
183
|
+
unless other_keys.empty?
|
184
|
+
others = {}
|
185
|
+
other_keys.each { |key| others[key] = meta.delete(key) }
|
186
|
+
meta.merge!(others: others.to_json)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Deserializes with JSON and decapsulate additional (not on the table schema) image attributes
|
191
|
+
# from the others schema field.
|
192
|
+
#
|
193
|
+
# This is used for SQL Backends, as they are not schema free.
|
194
|
+
#
|
195
|
+
# @example Instantiate a client with default values:
|
196
|
+
# # So this:
|
197
|
+
# {name: "example", access: "public", others: "{\"extra_key\":\"value\",\"another\":\"value\"}"}"}
|
198
|
+
# # becomes this:
|
199
|
+
# {name: 'example', access: 'public', extra_key: 'value', another: 'value'}
|
200
|
+
#
|
201
|
+
# @param [Hash] meta The image metadata.
|
202
|
+
#
|
203
|
+
def deserialize_others(meta)
|
204
|
+
if meta[:others]
|
205
|
+
others = meta.delete :others
|
206
|
+
meta.merge! JSON.parse(others, symbolize_names: true)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# Verifies if a given object is a String, a Time or a Hash.
|
211
|
+
#
|
212
|
+
# @param [Object] v The input value.
|
213
|
+
#
|
214
|
+
# @return [true, false] If the provided value is or not a String, a Time or a Hash.
|
215
|
+
#
|
216
|
+
def string_time_or_hash?(v)
|
217
|
+
v.is_a?(String) or v.is_a?(Time) or v.is_a?(Hash)
|
218
|
+
end
|
219
|
+
|
220
|
+
# Generates a compatible SQL WHERE string from a hash.
|
221
|
+
#
|
222
|
+
# @param [Hash] h The input hash.
|
223
|
+
#
|
224
|
+
# @return [String] A string as "k='v' AND k1='v1'",
|
225
|
+
# only Strings Times or Hashes values are surrounded with '<value>'.
|
226
|
+
#
|
227
|
+
def to_sql_where(h)
|
228
|
+
h.map { |k, v| string_time_or_hash?(v) ? "#{k}='#{v}'" : "#{k}=#{v}" }.join(' AND ')
|
229
|
+
end
|
230
|
+
|
231
|
+
# Generates a compatible SQL UPDATE string from a hash.
|
232
|
+
#
|
233
|
+
# @param [Hash] h The input hash.
|
234
|
+
#
|
235
|
+
# @return [String] A string as "k='v', k1='v1'",
|
236
|
+
# only Strings Times or Hashes values are surrounded with '<value>'.
|
237
|
+
#
|
238
|
+
def to_sql_update(h)
|
239
|
+
h.map { |k, v| string_time_or_hash?(v) ? "#{k}='#{v}'" : "#{k}=#{v}" }.join(', ')
|
240
|
+
end
|
241
|
+
|
242
|
+
# Generates a compatible SQL INSERT string from a hash.
|
243
|
+
#
|
244
|
+
# @param [Hash] h The input hash.
|
245
|
+
#
|
246
|
+
# @return [String] A string as "(k, k1) VALUES ('v', 'v1')",
|
247
|
+
# only Strings Times or Hashes values are surrounded with '<value>'.
|
248
|
+
#
|
249
|
+
def to_sql_insert(h)
|
250
|
+
surround = h.values.map { |v| string_time_or_hash?(v) ? "'#{v}'" : v }
|
251
|
+
%W{(#{h.keys.join(', ')}) (#{surround.join(', ')})}
|
252
|
+
end
|
253
|
+
|
254
|
+
private
|
255
|
+
|
256
|
+
# Assert that an image referenced as the corresponding kernel or ramdisk image
|
257
|
+
# is present and is a kernel or ramdisk image.
|
258
|
+
#
|
259
|
+
# A valid kernel image is an image that has its type setted to 'kernel'
|
260
|
+
# and/or its format setted to 'aki' (Amazon Kernel Image).
|
261
|
+
#
|
262
|
+
# A valid ramdisk image is an image that has its type setted to 'ramdisk'
|
263
|
+
# and/or its format setted to 'ari' (Amazon Ramdisk Image).
|
264
|
+
#
|
265
|
+
# As all backends implement the same external API, we can call here the #get_image
|
266
|
+
# without self and it will pickup the self.get_image method of the backend in use.
|
267
|
+
#
|
268
|
+
# @param [Hash] meta The image metadata.
|
269
|
+
#
|
270
|
+
# @raise[NotFound] If the referenced image is not found.
|
271
|
+
# @raise[ArgumentError] If the referenced image is not a kernel or ramdisk image.
|
272
|
+
#
|
273
|
+
def assert_ramdisk_and_kernel(meta)
|
274
|
+
if meta[:kernel]
|
275
|
+
id = meta[:kernel]
|
276
|
+
type = get_image(id).symbolize_keys[:type]
|
277
|
+
if type != 'kernel' && meta[:format] != 'aki'
|
278
|
+
raise ArgumentError, "The image with id #{id} is not a kernel image."
|
279
|
+
end
|
280
|
+
end
|
281
|
+
if meta[:ramdisk]
|
282
|
+
id = meta[:ramdisk]
|
283
|
+
type = get_image(id).symbolize_keys[:type]
|
284
|
+
if type != 'ramdisk' && meta[:format] != 'ari'
|
285
|
+
raise ArgumentError, "The image with id #{id} is not a ramdisk image."
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# Generate a message with the possible values for a given attribute.
|
291
|
+
#
|
292
|
+
# @param [Symbol] attr The attribute.
|
293
|
+
# @param [String] value The current invalid attribute value.
|
294
|
+
#
|
295
|
+
#def invalid_options_for attr, value
|
296
|
+
# options = self.class.const_get(attr.to_s.upcase).join(', ')
|
297
|
+
# "Invalid image #{attr.to_s} '#{value}', available options:\n #{options}"
|
298
|
+
#end
|
299
|
+
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
require 'mongo'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module Visor::Meta
|
5
|
+
module Backends
|
6
|
+
|
7
|
+
# The MongoDB Backend for the VISoR Meta.
|
8
|
+
#
|
9
|
+
class MongoDB < Base
|
10
|
+
|
11
|
+
include Visor::Common::Exception
|
12
|
+
|
13
|
+
# Connection constants
|
14
|
+
#
|
15
|
+
# Default MongoDB database
|
16
|
+
DEFAULT_DB = 'visor'
|
17
|
+
# Default MongoDB host address
|
18
|
+
DEFAULT_HOST = '127.0.0.1'
|
19
|
+
# Default MongoDB host port
|
20
|
+
DEFAULT_PORT = 27017
|
21
|
+
# Default MongoDB user
|
22
|
+
DEFAULT_USER = nil
|
23
|
+
# Default MongoDB password
|
24
|
+
DEFAULT_PASSWORD = nil
|
25
|
+
|
26
|
+
# Initializes a MongoDB Backend instance.
|
27
|
+
#
|
28
|
+
# @option [Hash] opts Any of the available options can be passed.
|
29
|
+
#
|
30
|
+
# @option opts [String] :uri The connection uri, if provided, no other option needs to be setted.
|
31
|
+
# @option opts [String] :db (DEFAULT_DB) The wanted database.
|
32
|
+
# @option opts [String] :host (DEFAULT_HOST) The host address.
|
33
|
+
# @option opts [Integer] :port (DEFAULT_PORT) The port to be used.
|
34
|
+
# @option opts [String] :user (DEFAULT_USER) The user to be used.
|
35
|
+
# @option opts [String] :password (DEFAULT_PASSWORD) The password to be used.
|
36
|
+
# @option opts [Object] :conn The connection pool to access database.
|
37
|
+
#
|
38
|
+
def self.connect(opts = {})
|
39
|
+
opts[:uri] ||= ''
|
40
|
+
uri = URI.parse(opts[:uri])
|
41
|
+
opts[:db] = uri.path ? uri.path.gsub('/', '') : DEFAULT_DB
|
42
|
+
opts[:host] = uri.host || DEFAULT_HOST
|
43
|
+
opts[:port] = uri.port || DEFAULT_PORT
|
44
|
+
opts[:user] = uri.user || DEFAULT_USER
|
45
|
+
opts[:password] = uri.password || DEFAULT_PASSWORD
|
46
|
+
|
47
|
+
self.new opts
|
48
|
+
end
|
49
|
+
|
50
|
+
def initialize(opts)
|
51
|
+
super opts
|
52
|
+
@conn = connection
|
53
|
+
end
|
54
|
+
|
55
|
+
# Establishes and returns a MongoDB database connection.
|
56
|
+
#
|
57
|
+
# @return [Mongo::Collection] A MongoDB collection object.
|
58
|
+
#
|
59
|
+
def connection
|
60
|
+
db = Mongo::Connection.new(@host, @port, :pool_size => 10, :pool_timeout => 5).db(@db)
|
61
|
+
db.authenticate(@user, @password) unless @user.empty? && @password.empty?
|
62
|
+
db.collection('images')
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns the requested image metadata.
|
66
|
+
#
|
67
|
+
# @param [Integer] id The requested image's _id.
|
68
|
+
# @param [true, false] pass_timestamps If we want to pass timestamps setting step.
|
69
|
+
#
|
70
|
+
# @return [BSON::OrderedHash] The requested image metadata.
|
71
|
+
#
|
72
|
+
# @raise [NotFound] If image not found.
|
73
|
+
#
|
74
|
+
def get_image(id, pass_timestamps = false)
|
75
|
+
meta = @conn.find_one({_id: id}, fields: exclude)
|
76
|
+
raise NotFound, "No image found with id '#{id}'." if meta.nil?
|
77
|
+
set_protected_get id unless pass_timestamps
|
78
|
+
meta
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns an array with the public images metadata.
|
82
|
+
#
|
83
|
+
# @param [true, false] brief (false) If true, the returned images will
|
84
|
+
# only contain BRIEF attributes.
|
85
|
+
#
|
86
|
+
# @option [Hash] filters Image attributes for filtering the returned results.
|
87
|
+
# Besides common attributes filters, the following options can be passed to.
|
88
|
+
#
|
89
|
+
# @option opts [String] :sort (_id) The image attribute to sort returned results.
|
90
|
+
#
|
91
|
+
# @return [Array] The public images metadata.
|
92
|
+
#
|
93
|
+
# @raise [NotFound] If there is no public images.
|
94
|
+
#
|
95
|
+
def get_public_images(brief = false, filters = {})
|
96
|
+
validate_query_filters filters unless filters.empty?
|
97
|
+
|
98
|
+
sort = [(filters.delete(:sort) || '_id'), (filters.delete(:dir) || 'asc')]
|
99
|
+
filters.merge!({access: 'public'}) unless filters[:owner]
|
100
|
+
fields = brief ? BRIEF : exclude
|
101
|
+
|
102
|
+
pub = @conn.find(filters, fields: fields, sort: sort).to_a
|
103
|
+
|
104
|
+
raise NotFound, "No public images found." if pub.empty? && filters.empty?
|
105
|
+
raise NotFound, "No public images found with given parameters." if pub.empty?
|
106
|
+
|
107
|
+
pub
|
108
|
+
end
|
109
|
+
|
110
|
+
# Delete an image record.
|
111
|
+
#
|
112
|
+
# @param [Integer] id The image's _id to remove.
|
113
|
+
#
|
114
|
+
# @return [BSON::OrderedHash] The deleted image metadata.
|
115
|
+
#
|
116
|
+
# @raise [NotFound] If image not found.
|
117
|
+
#
|
118
|
+
def delete_image(id)
|
119
|
+
img = @conn.find_one({_id: id})
|
120
|
+
raise NotFound, "No image found with id '#{id}'." unless img
|
121
|
+
|
122
|
+
@conn.remove({_id: id})
|
123
|
+
img
|
124
|
+
end
|
125
|
+
|
126
|
+
# Delete all images records.
|
127
|
+
#
|
128
|
+
def delete_all!
|
129
|
+
@conn.remove
|
130
|
+
end
|
131
|
+
|
132
|
+
# Create a new image record for the given metadata.
|
133
|
+
#
|
134
|
+
# @param [Hash] meta The image metadata.
|
135
|
+
# @option [Hash] opts Any of the available options can be passed.
|
136
|
+
#
|
137
|
+
# @option opts [String] :owner (Nil) The owner of the image.
|
138
|
+
# @option opts [Integer] :size (Nil) The image file size.
|
139
|
+
#
|
140
|
+
# @return [BSON::OrderedHash] The already added image metadata.
|
141
|
+
# @raise [Invalid] If image meta validation fails.
|
142
|
+
#
|
143
|
+
def post_image(meta, opts = {})
|
144
|
+
validate_data_post meta
|
145
|
+
set_protected_post meta, opts
|
146
|
+
id = @conn.insert(meta)
|
147
|
+
self.get_image(id, true)
|
148
|
+
end
|
149
|
+
|
150
|
+
# Update an image's metadata.
|
151
|
+
#
|
152
|
+
# @param [Integer] id The image _id to update.
|
153
|
+
# @param [Hash] update The image metadata to update.
|
154
|
+
#
|
155
|
+
# @return [BSON::OrderedHash] The updated image metadata.
|
156
|
+
# @raise [Invalid] If update metadata validation fails.
|
157
|
+
# @raise [NotFound] If image not found.
|
158
|
+
#
|
159
|
+
def put_image(id, update)
|
160
|
+
validate_data_put update
|
161
|
+
|
162
|
+
img = @conn.find_one({_id: id})
|
163
|
+
raise NotFound, "No image found with id '#{id}'." unless img
|
164
|
+
|
165
|
+
set_protected_put update
|
166
|
+
@conn.update({_id: id}, :$set => update)
|
167
|
+
self.get_image(id, true)
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
private
|
172
|
+
|
173
|
+
# Retrieve a hash with all fields that should not be retrieved from database.
|
174
|
+
# This sets each key to 0, so Mongo ignores each one of the keys present in it.
|
175
|
+
#
|
176
|
+
# @return [Hash] The image parameters that should not be retrieved from database.
|
177
|
+
#
|
178
|
+
def exclude
|
179
|
+
DETAIL_EXC.inject({}) { |h, v| h[v] = 0; h }
|
180
|
+
end
|
181
|
+
|
182
|
+
# Atomically set protected fields value from a get operation.
|
183
|
+
# Being them the accessed_at and access_count.
|
184
|
+
#
|
185
|
+
# @param [String] id The _id of the image being retrieved.
|
186
|
+
#
|
187
|
+
def set_protected_get(id)
|
188
|
+
@conn.update({_id: id}, :$set => {accessed_at: Time.now}, :$inc => {access_count: 1})
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
|