lib/intranet/pictures/responder.rb in intranet-pictures-1.1.0 vs lib/intranet/pictures/responder.rb in intranet-pictures-2.0.0
- old
+ new
@@ -7,43 +7,50 @@
require_relative 'version'
module Intranet
module Pictures
# The responder for the Pictures monitor module of the Intranet.
- class Responder < AbstractResponder
+ class Responder < AbstractResponder # rubocop:disable Metrics/ClassLength
include Core::HamlWrapper # 'inherits' from methods of HamlWrapper
# Returns the name of the module.
# @return [String] The name of the module.
def self.module_name
NAME
end
- # The version of the module, according to semantic versionning.
+ # Returns the version of the module, according to semantic versionning.
# @return [String] The version of the module.
def self.module_version
VERSION
end
- # The homepage of the module.
+ # Returns the homepage URL of the module.
# @return [String] The homepage URL of the module.
def self.module_homepage
HOMEPAGE_URL
end
# Initializes a new Pictures responder instance.
- # @param provider [#title,#group_types,#list_groups,#group_thumbnail,#list_pictures,#picture]
+ # @param provider [#title,#list_pictures,#group_thumbnail,#group_brief,#picture]
# The pictures provider.
# @see Intranet::Pictures::JsonDbProvider The specification of the provider, and in particular
# the minimal mandatory elements that must be returned by the operations.
- # @param recents [Array<Hash{group_type:String, sort_by:String, asc:Boolean, limit:Integer}>]
- # The description of the recent pictures album to be displayed on the module home page (all
- # keys except +group_type+ may be omitted).
- # @param home_groups [Array<Hash{group_type:String, sort_by:String, asc:Boolean,
- # browse:String, browse_sort_by:String, browse_asc:Boolean}>]
- # The description of the groups to be displayed on the module home page. All groups of the
- # +group_type+ will be displayed and link to a page showing all groups of the +browse+ type.
+ # @param recents [Array<Hash{group_by:String, sort_by:String, sort_order:String,
+ # limit:Integer}>]
+ # The description of the recent pictures to be displayed on the module home page. Pictures
+ # will first be sorted according to +sort_by+ and +sort_order+, then grouped by +group_by+,
+ # keeping only the first +limit+ elements, or all if +limit+ is zero. All keys except
+ # +group_by+ may be omitted.
+ # @param home_groups [Array<Hash{group_by:String, sort_by:String, sort_order:String,
+ # browse_group_by:String, browse_sort_by:String, browse_sort_order:String}>]
+ # The description of the pictures groups to be displayed on the module home page, after the
+ # +recents+. Pictures will first be sorted according to +sort_by+ and +sort_order+, then
+ # grouped by +group_by+. The obtained groups will be displayed with their thumbnail,
+ # (optional) brief text and a link to display images of that group sorted according to
+ # +browse_sort_by+ and +browse_sort_order+ and grouped by +browse_group_by+. All keys except
+ # +group_by+ and +browse_group_by+ may be omitted.
# @param in_menu [Boolean] Whether the module instance should be displayed in the main
# navigation menu or not.
def initialize(provider, recents = [], home_groups = [], in_menu = true)
@provider = provider
@recents = recents
@@ -63,63 +70,78 @@
def resources_dir
File.absolute_path(File.join('..', 'resources'), __dir__)
end
# Generates the HTML content associated to the given +path+ and +query+.
- # === REST API Description:
- # * Read-only access to pictures listings under */api/pictures* using +GET+ method, response
- # is in JSON format with the following structure:
+ # @param path [String] The requested URI, relative to that module root URI.
+ # @param query [Hash<String,String>] The URI variable/value pairs, if any.
+ # @return [Integer, String, String] The HTTP return code, the MIME type and the answer body.
+ #
+ # Relevant queries are as follows:
+ #
+ # * If +path+ is +/browse.html+, key/value pairs may be used to restrict the displayed images
+ # to those satisfying all the pairs. Moreover, +sort_by+ (followed by a key), +sort_order+
+ # (followed by either +asc+ or +desc+) and +group_by+ may be used to alter the way images
+ # are displayed.
+ # * If +path+ is +/api/group_thumbnail+ or +/api/group_brief+, query must contain only a
+ # single key/value pair designating the pictures group.
+ # * If +path+ is +/api/pictures+, key/value pairs may be used to restrict the displayed images
+ # to those satisfying all the pairs. Moreover, +sort_by+ (followed by a key), and
+ # +sort_order+ (followed by either +asc+ or +desc+) may be used to alter the order in which
+ # images are returned.
+ # * If +path+ is +api/picture+, key/value pairs must be used to select a single image from the
+ # gallery.
+ #
+ # When +path+ is +/api/pictures+, the selected pictures are returned in JSON format (REST API)
+ # with the following structure:
# [
# { "id": "...", "height": 480, "width": 640, "title": "...", "datetime": "...", ... },
# { ... }
# ]
- # * Read-only access to groups listings under */api/groups/*+group_type+ using +GET+ method,
- # response is in JSON format with the following structure:
- # [
- # { "id": "...", "title": "...", ... },
- # { ... }
- # ]
- # @param path [String] The requested URI, relative to that module root URI.
- # @param query [Hash<String,String>] The URI variable/value pairs, if any.
- # @return [Integer, String, String] The HTTP return code, the MIME type and the answer body.
def generate_page(path, query)
case path
- when %r{^/index\.html$} then serve_home
- when %r{^/browse_\w+\.html$}
- serve_groups(path.gsub(%r{^/browse_(\w+)\.html$}, '\\1'), query)
+ when %r{^/index\.html$} then serve_home
+ when %r{^/browse\.html$} then serve_browse(query)
when %r{^/api/} then serve_api(path.gsub(%r{^/api}, ''), query)
when %r{^/i18n\.js$} then serve_i18n_js
else super(path, query)
end
end
- # The title of the Pictures module, as displayed on the web page.
+ # Returns the title of the Pictures module, as displayed on the web page.
# @return [String] The title of the Pictures module web page.
def title
@provider.title
end
private
# Extract a selector from the given +query+.
- # @return [Hash<String,String>] The picture or group selector.
+ # @return [Hash<String,String>] The picture selector.
def selector(query)
- query.except('sort_by', 'sort_order')
+ query.except('group_by', 'sort_by', 'sort_order')
end
- # Extract the sort criteria from the given +query+.
- # @return [String] The key to use to sort pictures or groups, or nil if no sort order is
- # specified in +query+.
+ # Extract the grouping criteria from the given +query+, ie. the key that will be used to group
+ # the selected pictures.
+ # @return [String] The key to use to group pictures.
+ # @raise KeyError If no grouping criteria is specified.
+ def group_by(query)
+ query.fetch('group_by')
+ end
+
+ # Extract the sorting criteria from the given +query+, ie. the key that will be used to sort
+ # the selected pictures.
+ # @return [String] The key to use to sort pictures, or nil if no sorting is specified.
def sort_by(query)
query.fetch('sort_by')
rescue KeyError
nil
end
- # Extract the sort order from the given +query+.
- # @return [Boolean] False if the pictures or groups should be sorted in descending order,
- # True otherwise.
+ # Extract the sorting order from the given +query+.
+ # @return [Boolean] True if the pictures should be sorted in ascending order, False otherwise.
# @raise KeyError If the query requests an invalid sort order.
def sort_order(query)
return false if query['sort_order'] == 'desc'
return true if query['sort_order'].nil? || query['sort_order'] == 'asc'
@@ -141,69 +163,72 @@
##########################################################################
### Servicing of the HTML "display-able" content ###
##########################################################################
- def active_filters(query)
- selector(query).map do |k, v|
- { k => @provider.list_groups(k, { k => v }).first.fetch('title') }
- rescue KeyError
- { k => v }
- end.reduce({}, :merge)
+ def collect_groups(selector, group_by, sort_by, sort_order)
+ # Select all pictures, sort them & eventually keep only group names (first occurrence only)
+ @provider.list_pictures(selector, sort_by, sort_order).map do |picture|
+ picture.fetch(group_by)
+ end.uniq
end
+ def hash_to_query(hash)
+ hash.map { |k, v| [k, v].join('=') }.join('&')
+ end
+
def recent_groups
@recents.map do |recent|
- groups = @provider.list_groups(recent[:group_type], {}, recent[:sort_by], recent[:asc])
+ groups = collect_groups({}, group_by(recent), sort_by(recent), sort_order(recent))
see_more_url = ''
- if recent[:limit].to_i.positive?
- groups = groups.first(recent[:limit])
- see_more_url = "browse_#{recent[:group_type]}.html?sort_by=#{recent[:sort_by]}"
- see_more_url += '&sort_order=desc' unless recent[:asc]
+ if recent['limit'].to_i.positive?
+ groups = groups.first(recent['limit'].to_i)
+ see_more_url = "browse.html?#{hash_to_query(recent.except('limit'))}"
end
- { group_type: recent[:group_type], groups: groups, see_more_url: see_more_url }
+ { group_key: group_by(recent), groups: groups, see_more_url: see_more_url }
end
end
def all_groups
- @home_groups.map do |section|
- groups = @provider.list_groups(section[:group_type], {}, section[:sort_by], section[:asc])
- url_prefix = "browse_#{section[:browse]}.html?sort_by=#{section[:browse_sort_by]}"
- url_prefix += '&sort_order=desc' unless section[:browse_asc]
- { group_type: section[:group_type], groups: groups, url_prefix: url_prefix }
+ @home_groups.map do |sec|
+ groups = collect_groups({}, group_by(sec), sort_by(sec), sort_order(sec))
+ url_prefix = "browse.html?group_by=#{sec['browse_group_by']}"
+ url_prefix += "&sort_by=#{sec['browse_sort_by']}" if sec['browse_sort_by']
+ url_prefix += "&sort_order=#{sec['browse_sort_order']}" if sec['browse_sort_order']
+ { group_key: group_by(sec), groups: groups, url_prefix: url_prefix }
end
end
- def make_nav(group_type = nil, query = {})
+ def make_nav(query = {})
h = { I18n.t('nav.home') => '/index.html', I18n.t('pictures.menu') => nil, title => nil }
- unless group_type.nil?
+ unless query['group_by'].nil?
h[title] = 'index.html'
- extra_key = I18n.t("pictures.nav.#{group_type}")
- filters = active_filters(query).values
+ extra_key = I18n.t("pictures.nav.#{group_by(query)}")
+ filters = selector(query).values
extra_key += " (#{filters.join(', ')})" unless filters.empty?
h.store(extra_key, nil)
end
h
end
- def gallery_url(group_type, group_id, filters = {})
- filters.store(group_type, group_id)
+ def gallery_url(key, value, filters = {})
+ filters.store(key, value)
filters.store('sort_by', 'datetime')
- filters.map { |k, v| [k, v].join('=') }.join('&')
+ hash_to_query(filters)
end
def serve_home
content = to_markup('pictures_home', nav: make_nav)
[206, 'text/html',
{ content: content, title: title, stylesheets: stylesheets, scripts: scripts }]
rescue KeyError
[404, '', '']
end
- def serve_groups(type, query)
- groups = @provider.list_groups(type, selector(query), sort_by(query), sort_order(query))
- content = to_markup('pictures_browse', nav: make_nav(type, query), group_type: type,
+ def serve_browse(query)
+ groups = collect_groups(selector(query), group_by(query), sort_by(query), sort_order(query))
+ content = to_markup('pictures_browse', nav: make_nav(query), group_key: group_by(query),
filters: selector(query), groups: groups)
[206, 'text/html',
{ content: content, title: title, stylesheets: stylesheets, scripts: scripts }]
rescue KeyError
[404, '', '']
@@ -220,31 +245,35 @@
##########################################################################
### Servicing of the REST API (raw JSON data & pictures) ###
##########################################################################
- def api_list_groups(path, query)
- group_type = path.split('/')[2].to_s
- @provider.list_groups(group_type, selector(query), sort_by(query), sort_order(query))
- end
+ def api_group_thumbnail(query)
+ raise KeyError unless query.size == 1
- def api_group_thumbnail(path, query)
- group_type = path.split('/')[2].to_s
- pic = @provider.group_thumbnail(group_type, selector(query))
+ key, value = query.first
+ pic = @provider.group_thumbnail(key, value)
if pic.nil?
pic = ['image/svg+xml', File.read(File.join(resources_dir, 'www', 'group_thumbnail.svg'))]
end
pic
end
+ def api_group_brief(query)
+ raise KeyError unless query.size == 1
+
+ key, value = query.first
+ @provider.group_brief(key, value)
+ end
+
def api_list_pictures(query)
@provider.list_pictures(selector(query), sort_by(query), sort_order(query))
end
def serve_api(path, query)
case path
- when %r{^/groups/} then [200, 'application/json', api_list_groups(path, query).to_json]
- when %r{^/group/} then [200, api_group_thumbnail(path, query)].flatten
+ when %r{^/group_thumbnail$} then [200, api_group_thumbnail(query)].flatten
+ when %r{^/group_brief$} then [200, 'application/json', api_group_brief(query).to_json]
when %r{^/pictures$} then [200, 'application/json', api_list_pictures(query).to_json]
when %r{^/picture$} then [200, @provider.picture(query)].flatten
else [404, '', '']
end
rescue KeyError