lib/intranet/pictures/json_db_provider.rb in intranet-pictures-1.1.0 vs lib/intranet/pictures/json_db_provider.rb in intranet-pictures-2.0.0
- old
+ new
@@ -3,50 +3,47 @@
require 'json'
require 'mimemagic'
module Intranet
module Pictures
- # Provides pictures data and pictures groups listings from a database file in JSON format.
+ # Provides pictures data and pictures listings from a database file in JSON format.
#
# === Structure of the JSON database
# See the example below.
#
# The title of the pictures gallery is indicated in +title+
#
# Pictures are described individually as a hash in the +pictures+ array. The mandatory keys in
# this hash are:
- # * +id+ : unique identifier of the picture
# * +uri+ : location of the picture, relative to the JSON file
# * +title+ : description of the picture
# * +datetime+ : date and time of the picture, as a string in ISO8601 format
# * +height+ and +width+ : size in pixels of the picture
#
- # Pictures are meant to be grouped in various group types (event, city, region/country, ...).
- # Each group type is defined as an entry in the +groups+ hash and consists of a set of groups,
- # each of them described by a hash with the following keys:
+ # Additional keys may be added (for instance: event, city, region/country, ...); they will be
+ # used to group pictures sharing the same value of a given key.
+ # Some groups may be defined in the +groups+ hash to add a thumbnail picture and a brief text
+ # description for them. The possible keys in this hash are:
# * +id+ : unique identifier of the group, mandatory
- # * +title+ : human-readable group name, mandatory
# * +brief+ : optional short text associated to the group name
# * +uri+ : optional group thumbnail, relative to the JSON file
#
- # Each image is associated to at most one group in each group type by by a a "foreign key"
- # constraint of the type *picture*.+group_type+ = *group*.+id+.
# @example Structure of the JSON database (not all mandatory are present for readability)
# {
# "title": "gallery title",
# "groups": {
# "event": [
- # { "id": "party", "title": "...", "brief": "...", "uri": "party.jpg", ... },
+ # { "id": "Party", "brief": "...", "uri": "party.jpg", ... },
# { ... }
# ],
# "city": [
- # { "id": "houston", "title": "...", "uri": "houston.png", ... },
+ # { "id": "Houston", "uri": "houston.png", ... },
# { ... }
# ]
# },
# "pictures": [
- # { "uri": "dir/pic0.jpg", "datetime": "...", "event": "party", "city": "houston", ... },
+ # { "uri": "dir/pic0.jpg", "datetime": "...", "event": "Party", "city": "Houston", ... },
# { ... }
# ]
# }
class JsonDbProvider
# Initializes a new pictures data provider.
@@ -64,51 +61,20 @@
def title
load_json
@json.fetch('title').to_s
end
- # Returns the list of available group types.
- # @return [Array<String>] The available group types.
- # @raise KeyError If no group type is defined in JSON file.
- def group_types
- load_json
- @json.fetch('groups').keys
- end
-
- # Returns the list of the groups satisfying the following conditions:
- # * the group is of the given +type+, and
- # * at least one picture belonging to that group matches the +selector+.
- # Results are returned ordered by *group*.+sort_by+ in ascending order if +asc+, and in
- # descending order otherwise.
- # @param type [String] The group type.
- # @param selector [Hash<String,String>] The pictures selector, interpreted as a logical AND
- # combination of all key/value pairs provided.
- # @param sort_by [String] The group field to sort the results by, or nil if results should be
- # returned without particular sorting.
- # @param asc [Boolean] True to sort returned groups in ascending order, False to sort in
- # descending order.
- # @return [Array<Hash{'id'=>String, 'title'=>String, ...}>] The selected groups.
- # @raise KeyError If JSON file is malformed, if +type+ does not match an existing group type,
- # or if +sort_by+ is not an existing group field.
- def list_groups(type, selector = {}, sort_by = nil, asc = true)
- load_json
- groups = select_groups(type, selector).map { |g| g.except('uri') }
- groups.sort_by! { |g| g.fetch(sort_by) } unless sort_by.nil?
- groups.reverse! unless asc
- groups
- end
-
# Returns the list of the pictures matching +selector+.
- # Results are returned ordered by *picture*.+sort_by+ in ascending order if +asc+, and in
- # descending order otherwise.
+ # Results are returned ordered by +sort_by+ in ascending order if +asc+, and in descending
+ # order otherwise.
# @param selector [Hash<String,String>] The pictures selector, interpreted as a logical AND
# combination of all key/value pairs provided.
# @param sort_by [String] The picture field to sort the results by, or nil if results should
# be returned without particular sorting.
- # @param asc [Boolean] True to sort returned pictures in ascending order, False to sort in
- # descending order.
- # @return [Array<Hash{'id'=>String, 'title'=>String, 'datetime'=>String, 'height'=>Integer,
+ # @param asc [Boolean] True to sort returned pictures in ascending order, False to sort them
+ # in descending order.
+ # @return [Array<Hash{'title'=>String, 'datetime'=>String, 'height'=>Integer,
# 'width'=>Integer, ...}>] The selected pictures.
# @raise KeyError If JSON file is malformed, or if +sort_by+ is not an existing picture field.
def list_pictures(selector = {}, sort_by = nil, asc = true)
load_json
pics = select_pictures(selector).map { |p| p.except('uri') }
@@ -120,41 +86,52 @@
# Returns the picture file matching +selector+.
# @param selector [Hash<String,String>] The picture selector, which should return exactly one
# picture.
# @return [String, Blob] The MIME type of the picture, and the picture file content.
# @raise KeyError If JSON file is malformed, if selector does not match exactly one picture,
- # or if the *picture*.+uri+ does not refer to an existing image file.
+ # or if the picture +uri+ does not refer to an existing image file.
def picture(selector = {})
load_json
pic = select_pictures(selector)
raise KeyError unless pic.size == 1
path = File.join(@json_dir, pic.first.fetch('uri'))
- open_image_file(path)
+ read_image_file(path)
end
- # Returns the thumbnail picture of the group satisfying the following conditions:
- # * the group is of the given +type+, and
- # * at least one picture belonging to that group matches the +selector+.
- # @param type [String] The group type.
- # @param selector [Hash<String,String>] The pictures selector, interpreted as a logical AND
- # combination of all key/value pairs provided. The
- # selector should return exactly one group.
+ # Returns the thumbnail picture of the group whose type is +key+ and named +value+.
+ # @param key [String] The group type.
+ # @param value [String] The group name.
# @return [String, Blob] The MIME type of the picture, and the picture file content. Nil may
# be returned if no thumbnail is available for that group.
- # @raise KeyError If JSON file is malformed, if selector does not match exactly one group,
- # or if the *group*.+uri+ does not refer to an existing image file.
- def group_thumbnail(type, selector = {})
+ # @raise KeyError If JSON file is malformed, if key/value do not designate exactly one group,
+ # or if the group +uri+ does not refer to an existing image file.
+ def group_thumbnail(key, value)
load_json
- group = select_groups(type, selector)
+ group = select_group(key, value)
raise KeyError unless group.size == 1
return nil if group.first['uri'].nil?
path = File.join(@json_dir, group.first.fetch('uri'))
- open_image_file(path)
+ read_image_file(path)
end
+ # Returns the brief text of the group whose type is +key+ and named +value+.
+ # @param key [String] The group type.
+ # @param value [String] The group name.
+ # @return [String] The brief text of the group, or an empty string if no brief is available.
+ # @raise KeyError If JSON file is malformed or if key/value do not designate exactly one
+ # group.
+ def group_brief(key, value)
+ load_json
+ group = select_group(key, value)
+ raise KeyError unless group.size == 1
+ return '' if group.first['brief'].nil?
+
+ group.first.fetch('brief')
+ end
+
private
# (Re)load the JSON file if modified on disk
def load_json
mtime = File.mtime(@json_file)
@@ -162,11 +139,11 @@
@json = JSON.parse(File.read(@json_file))
@json_time = mtime
end
- def open_image_file(path)
+ def read_image_file(path)
mime_type = MimeMagic.by_path(path).type
raise KeyError unless mime_type.start_with?('image/')
[MimeMagic.by_path(path).type, File.read(path)]
rescue Errno::ENOENT
@@ -177,22 +154,15 @@
selector.all? { |k, v| picture.fetch(k) == v }
rescue KeyError
false
end
- def select_groups(type, selector)
- return @json.fetch('groups').fetch(type) if selector.empty? # optimization
-
- groups_id = select_pictures_having(type, selector).map { |p| p.fetch(type) }.uniq.compact
- @json.fetch('groups').fetch(type).select { |g| groups_id.include?(g.fetch('id')) }
- end
-
def select_pictures(selector)
@json.fetch('pictures').select { |p| picture_match?(p, selector) }
end
- def select_pictures_having(group_type, selector)
- @json.fetch('pictures').select { |p| p.key?(group_type) && picture_match?(p, selector) }
+ def select_group(type, id)
+ @json.fetch('groups').fetch(type).select { |g| g.fetch('id') == id }
end
end
end
end