intranet-pictures 0.0.0 → 1.0.0
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.
- checksums.yaml +4 -4
- data/lib/intranet/pictures/json_db_provider.rb +196 -0
- data/lib/intranet/pictures/responder.rb +247 -0
- data/lib/intranet/pictures/version.rb +1 -1
- data/lib/intranet/resources/haml/pictures_browse.haml +14 -0
- data/lib/intranet/resources/haml/pictures_home.haml +36 -0
- data/lib/intranet/resources/haml/pictures_photoswipe.haml +23 -0
- data/lib/intranet/resources/locales/en.yml +28 -0
- data/lib/intranet/resources/locales/fr.yml +28 -0
- data/lib/intranet/resources/www/group_thumbnail.jpg +0 -0
- data/lib/intranet/resources/www/jpictures.js +42 -0
- data/lib/intranet/resources/www/photoswipe/LICENSE +21 -0
- data/lib/intranet/resources/www/photoswipe/default-skin/default-skin.css +484 -0
- data/lib/intranet/resources/www/photoswipe/default-skin/default-skin.png +0 -0
- data/lib/intranet/resources/www/photoswipe/default-skin/default-skin.svg +1 -0
- data/lib/intranet/resources/www/photoswipe/default-skin/preloader.gif +0 -0
- data/lib/intranet/resources/www/photoswipe/photoswipe-ui-default.js +861 -0
- data/lib/intranet/resources/www/photoswipe/photoswipe-ui-default.min.js +4 -0
- data/lib/intranet/resources/www/photoswipe/photoswipe.css +179 -0
- data/lib/intranet/resources/www/photoswipe/photoswipe.js +3734 -0
- data/lib/intranet/resources/www/photoswipe/photoswipe.min.js +4 -0
- data/lib/intranet/resources/www/style.css +81 -0
- data/spec/intranet/pictures/alpha.png +0 -0
- data/spec/intranet/pictures/json_db_provider_spec.rb +273 -0
- data/spec/intranet/pictures/responder_spec.rb +499 -0
- data/spec/intranet/pictures/sample-db.json +71 -0
- data/spec/intranet/pictures/white.jpg +0 -0
- data/spec/spec_helper.rb +6 -2
- metadata +52 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9d501ee87ce3a72f55276eaed283010fe6290149e51815a52e9f7814921f6ec
|
4
|
+
data.tar.gz: b22160bb395f4a7b1676f4fa844b8e0954f0eb5292152370f6c5b5cd1c60f9ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d82750698f54a3328135679a1adbfeaa3f38cdac2c1e9fe5d870441bf162a35758c942aa131d4c191bea69fb7a8fc01f94a3bfc3f33d2e212a4a581e552adbf
|
7
|
+
data.tar.gz: 31cf32b5245d7b808bcc8714883feede4ef20a8af956bfd0c3cdca95ac9f5e461a32452df4e2f8b6da4a33bf0e54af4c3354157fbe92efd27c2ee059d77c77f3
|
@@ -0,0 +1,196 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'mimemagic'
|
5
|
+
|
6
|
+
module Intranet
|
7
|
+
module Pictures
|
8
|
+
# Provides pictures data and pictures groups listings from a database file in JSON format.
|
9
|
+
#
|
10
|
+
# === Structure of the JSON database
|
11
|
+
# See the example below.
|
12
|
+
#
|
13
|
+
# The title of the pictures gallery is indicated in +title+
|
14
|
+
#
|
15
|
+
# Pictures are described individually as a hash in the +pictures+ array. The mandatory keys in
|
16
|
+
# this hash are:
|
17
|
+
# * +id+ : unique identifier of the picture
|
18
|
+
# * +uri+ : location of the picture, relative to the JSON file
|
19
|
+
# * +title+ : description of the picture
|
20
|
+
# * +datetime+ : date and time of the picture, as a string in ISO8601 format
|
21
|
+
# * +height+ and +width+ : size in pixels of the picture
|
22
|
+
#
|
23
|
+
# Pictures are meant to be grouped in various group types (event, city, region/country, ...).
|
24
|
+
# Each group type is defined as an entry in the +groups+ hash and consists of a set of groups,
|
25
|
+
# each of them described by a hash with the following keys:
|
26
|
+
# * +id+ : unique identifier of the group, mandatory
|
27
|
+
# * +title+ : human-readable group name, mandatory
|
28
|
+
# * +brief+ : optional short text associated to the group name
|
29
|
+
# * +uri+ : optional group thumbnail, relative to the JSON file
|
30
|
+
#
|
31
|
+
# Each image is associated to at most one group in each group type by by a a "foreign key"
|
32
|
+
# constraint of the type *picture*.+group_type+ = *group*.+id+.
|
33
|
+
# @example Structure of the JSON database (not all mandatory are present for readability)
|
34
|
+
# {
|
35
|
+
# "title": "gallery title",
|
36
|
+
# "groups": {
|
37
|
+
# "event": [
|
38
|
+
# { "id": "party", "title": "...", "brief": "...", "uri": "party.jpg", ... },
|
39
|
+
# { ... }
|
40
|
+
# ],
|
41
|
+
# "city": [
|
42
|
+
# { "id": "houston", "title": "...", "uri": "houston.png", ... },
|
43
|
+
# { ... }
|
44
|
+
# ]
|
45
|
+
# },
|
46
|
+
# "pictures": [
|
47
|
+
# { "uri": "dir/pic0.jpg", "datetime": "...", "event": "party", "city": "houston", ... },
|
48
|
+
# { ... }
|
49
|
+
# ]
|
50
|
+
# }
|
51
|
+
class JsonDbProvider
|
52
|
+
# Initializes a new pictures data provider.
|
53
|
+
# @param json_file [String] The path to the JSON database file.
|
54
|
+
def initialize(json_file)
|
55
|
+
@json_dir = File.dirname(json_file) # also works for URLs
|
56
|
+
@json_file = json_file
|
57
|
+
@json_time = Time.at(0)
|
58
|
+
load_json
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns the pictures gallery title.
|
62
|
+
# @return [String] The gallery title.
|
63
|
+
# @raise KeyError If no title is defined in JSON file.
|
64
|
+
def title
|
65
|
+
load_json
|
66
|
+
@json.fetch('title').to_s
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns the list of available group types.
|
70
|
+
# @return [Array<String>] The available group types.
|
71
|
+
# @raise KeyError If no group type is defined in JSON file.
|
72
|
+
def group_types
|
73
|
+
load_json
|
74
|
+
@json.fetch('groups').keys
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns the list of the groups satisfying the following conditions:
|
78
|
+
# * the group is of the given +type+, and
|
79
|
+
# * at least one picture belonging to that group matches the +selector+.
|
80
|
+
# Results are returned ordered by *group*.+sort_by+ in ascending order if +asc+, and in
|
81
|
+
# descending order otherwise.
|
82
|
+
# @param type [String] The group type.
|
83
|
+
# @param selector [Hash<String,String>] The pictures selector, interpreted as a logical AND
|
84
|
+
# combination of all key/value pairs provided.
|
85
|
+
# @param sort_by [String] The group field to sort the results by, or nil if results should be
|
86
|
+
# returned without particular sorting.
|
87
|
+
# @param asc [Boolean] True to sort returned groups in ascending order, False to sort in
|
88
|
+
# descending order.
|
89
|
+
# @return [Array<Hash{'id'=>String, 'title'=>String, ...}>] The selected groups.
|
90
|
+
# @raise KeyError If JSON file is malformed, if +type+ does not match an existing group type,
|
91
|
+
# or if +sort_by+ is not an existing group field.
|
92
|
+
def list_groups(type, selector = {}, sort_by = nil, asc = true)
|
93
|
+
load_json
|
94
|
+
groups = select_groups(type, selector).map { |g| g.except('uri') }
|
95
|
+
groups.sort_by! { |g| g.fetch(sort_by) } unless sort_by.nil?
|
96
|
+
groups.reverse! unless asc
|
97
|
+
groups
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns the list of the pictures matching +selector+.
|
101
|
+
# Results are returned ordered by *picture*.+sort_by+ in ascending order if +asc+, and in
|
102
|
+
# descending order otherwise.
|
103
|
+
# @param selector [Hash<String,String>] The pictures selector, interpreted as a logical AND
|
104
|
+
# combination of all key/value pairs provided.
|
105
|
+
# @param sort_by [String] The picture field to sort the results by, or nil if results should
|
106
|
+
# be returned without particular sorting.
|
107
|
+
# @param asc [Boolean] True to sort returned pictures in ascending order, False to sort in
|
108
|
+
# descending order.
|
109
|
+
# @return [Array<Hash{'id'=>String, 'title'=>String, 'datetime'=>String, 'height'=>Integer,
|
110
|
+
# 'width'=>Integer, ...}>] The selected pictures.
|
111
|
+
# @raise KeyError If JSON file is malformed, or if +sort_by+ is not an existing picture field.
|
112
|
+
def list_pictures(selector = {}, sort_by = nil, asc = true)
|
113
|
+
load_json
|
114
|
+
pics = select_pictures(selector).map { |p| p.except('uri') }
|
115
|
+
pics.sort_by! { |p| p.fetch(sort_by) } unless sort_by.nil?
|
116
|
+
pics.reverse! unless asc
|
117
|
+
pics
|
118
|
+
end
|
119
|
+
|
120
|
+
# Returns the picture file matching +selector+.
|
121
|
+
# @param selector [Hash<String,String>] The picture selector, which should return exactly one
|
122
|
+
# picture.
|
123
|
+
# @return [String, Blob] The MIME type of the picture, and the picture file content.
|
124
|
+
# @raise KeyError If JSON file is malformed, if selector does not match exactly one picture,
|
125
|
+
# or if the *picture*.+uri+ does not refer to an existing image file.
|
126
|
+
def picture(selector = {})
|
127
|
+
load_json
|
128
|
+
pic = select_pictures(selector)
|
129
|
+
raise KeyError unless pic.size == 1
|
130
|
+
|
131
|
+
path = File.join(@json_dir, pic.first.fetch('uri'))
|
132
|
+
open_image_file(path)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns the thumbnail picture of the group satisfying the following conditions:
|
136
|
+
# * the group is of the given +type+, and
|
137
|
+
# * at least one picture belonging to that group matches the +selector+.
|
138
|
+
# @param type [String] The group type.
|
139
|
+
# @param selector [Hash<String,String>] The pictures selector, interpreted as a logical AND
|
140
|
+
# combination of all key/value pairs provided. The
|
141
|
+
# selector should return exactly one group.
|
142
|
+
# @return [String, Blob] The MIME type of the picture, and the picture file content. Nil may
|
143
|
+
# be returned if no thumbnail is available for that group.
|
144
|
+
# @raise KeyError If JSON file is malformed, if selector does not match exactly one group,
|
145
|
+
# or if the *group*.+uri+ does not refer to an existing image file.
|
146
|
+
def group_thumbnail(type, selector = {})
|
147
|
+
load_json
|
148
|
+
group = select_groups(type, selector)
|
149
|
+
raise KeyError unless group.size == 1
|
150
|
+
return nil if group.first['uri'].nil?
|
151
|
+
|
152
|
+
path = File.join(@json_dir, group.first.fetch('uri'))
|
153
|
+
open_image_file(path)
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
# (Re)load the JSON file if modified on disk
|
159
|
+
def load_json
|
160
|
+
mtime = File.mtime(@json_file)
|
161
|
+
return unless @json_time < File.mtime(@json_file)
|
162
|
+
|
163
|
+
@json = JSON.parse(File.read(@json_file))
|
164
|
+
@json_time = mtime
|
165
|
+
end
|
166
|
+
|
167
|
+
def open_image_file(path)
|
168
|
+
mime_type = MimeMagic.by_path(path).type
|
169
|
+
raise KeyError unless mime_type.start_with?('image/')
|
170
|
+
|
171
|
+
[MimeMagic.by_path(path).type, File.read(path)]
|
172
|
+
rescue Errno::ENOENT
|
173
|
+
raise KeyError
|
174
|
+
end
|
175
|
+
|
176
|
+
def picture_match?(picture, selector)
|
177
|
+
selector.all? { |k, v| picture.fetch(k) == v }
|
178
|
+
rescue KeyError
|
179
|
+
false
|
180
|
+
end
|
181
|
+
|
182
|
+
def select_groups(type, selector)
|
183
|
+
return @json.fetch('groups').fetch(type) if selector.empty? # optimization
|
184
|
+
|
185
|
+
groups_id = @json.fetch('pictures').map do |p|
|
186
|
+
p.fetch(type) if picture_match?(p, selector)
|
187
|
+
end.uniq.compact
|
188
|
+
@json.fetch('groups').fetch(type).select { |g| groups_id.include?(g.fetch('id')) }
|
189
|
+
end
|
190
|
+
|
191
|
+
def select_pictures(selector)
|
192
|
+
@json.fetch('pictures').select { |p| picture_match?(p, selector) }
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,247 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'intranet/abstract_responder'
|
4
|
+
require 'intranet/core/haml_wrapper'
|
5
|
+
require 'intranet/core/locales'
|
6
|
+
require 'json'
|
7
|
+
require_relative 'version'
|
8
|
+
|
9
|
+
module Intranet
|
10
|
+
module Pictures
|
11
|
+
# The responder for the Pictures monitor module of the Intranet.
|
12
|
+
class Responder < AbstractResponder
|
13
|
+
include Core::HamlWrapper # 'inherits' from methods of HamlWrapper
|
14
|
+
|
15
|
+
# Returns the name of the module.
|
16
|
+
# @return [String] The name of the module.
|
17
|
+
def self.module_name
|
18
|
+
NAME
|
19
|
+
end
|
20
|
+
|
21
|
+
# The version of the module, according to semantic versionning.
|
22
|
+
# @return [String] The version of the module.
|
23
|
+
def self.module_version
|
24
|
+
VERSION
|
25
|
+
end
|
26
|
+
|
27
|
+
# The homepage of the module.
|
28
|
+
# @return [String] The homepage URL of the module.
|
29
|
+
def self.module_homepage
|
30
|
+
HOMEPAGE_URL
|
31
|
+
end
|
32
|
+
|
33
|
+
# Initializes a new Pictures responder instance.
|
34
|
+
# @param provider [#title,#group_types,#list_groups,#group_thumbnail,#list_pictures,#picture]
|
35
|
+
# The pictures provider.
|
36
|
+
# @see Intranet::Pictures::JsonDbProvider The specification of the provider, and in particular
|
37
|
+
# the minimal mandatory elements that must be returned by the operations.
|
38
|
+
# @param recents [Array<Hash{group_type:String, sort_by:String, asc:Boolean, limit:Integer}>]
|
39
|
+
# The description of the recent pictures album to be displayed on the module home page (all
|
40
|
+
# keys except +group_type+ may be omitted).
|
41
|
+
# @param home_groups [Array<Hash{group_type:String, sort_by:String, asc:Boolean,
|
42
|
+
# browse:String, browse_sort_by:String, browse_asc:Boolean}>]
|
43
|
+
# The description of the groups to be displayed on the module home page. All groups of the
|
44
|
+
# +group_type+ will be displayed and link to a page showing all groups of the +browse+ type.
|
45
|
+
# @param in_menu [Boolean] Whether the module instance should be displayed in the main
|
46
|
+
# navigation menu or not.
|
47
|
+
def initialize(provider, recents = [], home_groups = [], in_menu = true)
|
48
|
+
@provider = provider
|
49
|
+
@recents = recents
|
50
|
+
@in_menu = in_menu
|
51
|
+
@home_groups = home_groups
|
52
|
+
end
|
53
|
+
|
54
|
+
# Specifies if the responder instance should be displayed in the main navigation menu or not.
|
55
|
+
# @return [Boolean] True if the responder instance should be added to the main navigation
|
56
|
+
# menu, False otherwise.
|
57
|
+
def in_menu?
|
58
|
+
@in_menu
|
59
|
+
end
|
60
|
+
|
61
|
+
# Specifies the absolute path to the resources directory for that module.
|
62
|
+
# @return [String] The absolute path to the resources directory for the module.
|
63
|
+
def resources_dir
|
64
|
+
File.absolute_path(File.join('..', 'resources'), __dir__)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Generates the HTML content associated to the given +path+ and +query+.
|
68
|
+
# === REST API Description:
|
69
|
+
# * Read-only access to pictures listings under */api/pictures* using +GET+ method, response
|
70
|
+
# is in JSON format with the following structure:
|
71
|
+
# [
|
72
|
+
# { "id": "...", "height": 480, "width": 640, "title": "...", "datetime": "...", ... },
|
73
|
+
# { ... }
|
74
|
+
# ]
|
75
|
+
# * Read-only access to groups listings under */api/groups/*+group_type+ using +GET+ method,
|
76
|
+
# response is in JSON format with the following structure:
|
77
|
+
# [
|
78
|
+
# { "id": "...", "title": "...", ... },
|
79
|
+
# { ... }
|
80
|
+
# ]
|
81
|
+
# @param path [String] The requested URI, relative to that module root URI.
|
82
|
+
# @param query [Hash<String,String>] The URI variable/value pairs, if any.
|
83
|
+
# @return [Integer, String, String] The HTTP return code, the MIME type and the answer body.
|
84
|
+
def generate_page(path, query)
|
85
|
+
case path
|
86
|
+
when %r{^/index\.html$} then serve_home
|
87
|
+
when %r{^/browse_\w+\.html$}
|
88
|
+
serve_groups(path.gsub(%r{^/browse_(\w+)\.html$}, '\\1'), query)
|
89
|
+
when %r{^/api/} then serve_api(path.gsub(%r{^/api}, ''), query)
|
90
|
+
else super(path, query)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# The title of the Pictures module, as displayed on the web page.
|
95
|
+
# @return [String] The title of the Pictures module web page.
|
96
|
+
def title
|
97
|
+
@provider.title
|
98
|
+
end
|
99
|
+
|
100
|
+
# Provides the list of Cascade Style Sheets (CSS) dependencies for this module.
|
101
|
+
# @return [Array<String>] The list of CSS dependencies.
|
102
|
+
def css_dependencies
|
103
|
+
super + ['design/style.css',
|
104
|
+
'design/photoswipe/photoswipe.css',
|
105
|
+
'design/photoswipe/default-skin/default-skin.css']
|
106
|
+
end
|
107
|
+
|
108
|
+
# Provides the list of Javascript files (JS) dependencies for this module.
|
109
|
+
# @return [Array<String>] The list of JS dependencies.
|
110
|
+
def js_dependencies
|
111
|
+
super + ['design/jpictures.js',
|
112
|
+
'design/photoswipe/photoswipe.min.js',
|
113
|
+
'design/photoswipe/photoswipe-ui-default.min.js']
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
# Extract a selector from the given +query+.
|
119
|
+
# @return [Hash<String,String>] The picture or group selector.
|
120
|
+
def selector(query)
|
121
|
+
query.except('sort_by', 'sort_order')
|
122
|
+
end
|
123
|
+
|
124
|
+
# Extract the sort criteria from the given +query+.
|
125
|
+
# @return [String] The key to use to sort pictures or groups, or nil if no sort order is
|
126
|
+
# specified in +query+.
|
127
|
+
def sort_by(query)
|
128
|
+
query.fetch('sort_by')
|
129
|
+
rescue KeyError
|
130
|
+
nil
|
131
|
+
end
|
132
|
+
|
133
|
+
# Extract the sort order from the given +query+.
|
134
|
+
# @return [Boolean] False if the pictures or groups should be sorted in descending order,
|
135
|
+
# True otherwise.
|
136
|
+
# @raise KeyError If the query requests an invalid sort order.
|
137
|
+
def sort_order(query)
|
138
|
+
return false if query['sort_order'] == 'desc'
|
139
|
+
return true if query['sort_order'].nil? || query['sort_order'] == 'asc'
|
140
|
+
|
141
|
+
raise KeyError # incorrect value for 'sort_order'
|
142
|
+
end
|
143
|
+
|
144
|
+
##########################################################################
|
145
|
+
### Servicing of the HTML "display-able" content ###
|
146
|
+
##########################################################################
|
147
|
+
|
148
|
+
def active_filters(query)
|
149
|
+
selector(query).map do |k, v|
|
150
|
+
{ k => @provider.list_groups(k, { k => v }).first.fetch('title') }
|
151
|
+
rescue KeyError
|
152
|
+
{ k => v }
|
153
|
+
end.reduce({}, :merge)
|
154
|
+
end
|
155
|
+
|
156
|
+
def recent_groups
|
157
|
+
@recents.map do |recent|
|
158
|
+
groups = @provider.list_groups(recent[:group_type], {}, recent[:sort_by], recent[:asc])
|
159
|
+
see_more_url = ''
|
160
|
+
if recent[:limit].to_i.positive?
|
161
|
+
groups = groups.first(recent[:limit])
|
162
|
+
see_more_url = "browse_#{recent[:group_type]}.html?sort_by=#{recent[:sort_by]}"
|
163
|
+
see_more_url += '&sort_order=desc' unless recent[:asc]
|
164
|
+
end
|
165
|
+
{ group_type: recent[:group_type], groups: groups, see_more_url: see_more_url }
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def all_groups
|
170
|
+
@home_groups.map do |section|
|
171
|
+
groups = @provider.list_groups(section[:group_type], {}, section[:sort_by], section[:asc])
|
172
|
+
url_prefix = "browse_#{section[:browse]}.html?sort_by=#{section[:browse_sort_by]}"
|
173
|
+
url_prefix += '&sort_order=desc' unless section[:browse_asc]
|
174
|
+
{ group_type: section[:group_type], groups: groups, url_prefix: url_prefix }
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def make_nav(group_type = nil, query = {})
|
179
|
+
h = { I18n.t('nav.home') => '/index.html', I18n.t('pictures.menu') => nil, title => nil }
|
180
|
+
unless group_type.nil?
|
181
|
+
h[title] = 'index.html'
|
182
|
+
extra_key = I18n.t("pictures.nav.#{group_type}")
|
183
|
+
filters = active_filters(query).values
|
184
|
+
extra_key += " (#{filters.join(', ')})" unless filters.empty?
|
185
|
+
h.store(extra_key, nil)
|
186
|
+
end
|
187
|
+
h
|
188
|
+
end
|
189
|
+
|
190
|
+
def gallery_url(group_type, group_id, filters = {})
|
191
|
+
filters.store(group_type, group_id)
|
192
|
+
filters.store('sort_by', 'datetime')
|
193
|
+
filters.map { |k, v| [k, v].join('=') }.join('&')
|
194
|
+
end
|
195
|
+
|
196
|
+
def serve_home
|
197
|
+
content = to_markup('pictures_home', nav: make_nav)
|
198
|
+
[206, 'text/html', { content: content, title: title }]
|
199
|
+
rescue KeyError
|
200
|
+
[404, '', '']
|
201
|
+
end
|
202
|
+
|
203
|
+
def serve_groups(type, query)
|
204
|
+
groups = @provider.list_groups(type, selector(query), sort_by(query), sort_order(query))
|
205
|
+
content = to_markup('pictures_browse', nav: make_nav(type, query), group_type: type,
|
206
|
+
filters: selector(query), groups: groups)
|
207
|
+
[206, 'text/html', { content: content, title: title }]
|
208
|
+
rescue KeyError
|
209
|
+
[404, '', '']
|
210
|
+
end
|
211
|
+
|
212
|
+
##########################################################################
|
213
|
+
### Servicing of the REST API (raw JSON data & pictures) ###
|
214
|
+
##########################################################################
|
215
|
+
|
216
|
+
def api_list_groups(path, query)
|
217
|
+
group_type = path.split('/')[2].to_s
|
218
|
+
@provider.list_groups(group_type, selector(query), sort_by(query), sort_order(query))
|
219
|
+
end
|
220
|
+
|
221
|
+
def api_group_thumbnail(path, query)
|
222
|
+
group_type = path.split('/')[2].to_s
|
223
|
+
pic = @provider.group_thumbnail(group_type, selector(query))
|
224
|
+
if pic.nil?
|
225
|
+
pic = ['image/jpeg', File.read(File.join(resources_dir, 'www', 'group_thumbnail.jpg'))]
|
226
|
+
end
|
227
|
+
pic
|
228
|
+
end
|
229
|
+
|
230
|
+
def api_list_pictures(query)
|
231
|
+
@provider.list_pictures(selector(query), sort_by(query), sort_order(query))
|
232
|
+
end
|
233
|
+
|
234
|
+
def serve_api(path, query)
|
235
|
+
case path
|
236
|
+
when %r{^/groups/} then [200, 'application/json', api_list_groups(path, query).to_json]
|
237
|
+
when %r{^/group/} then [200, api_group_thumbnail(path, query)].flatten
|
238
|
+
when %r{^/pictures$} then [200, 'application/json', api_list_pictures(query).to_json]
|
239
|
+
when %r{^/picture$} then [200, @provider.picture(query)].flatten
|
240
|
+
else [404, '', '']
|
241
|
+
end
|
242
|
+
rescue KeyError
|
243
|
+
[404, '', '']
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|