intranet-pictures 2.2.0 → 3.0.0.rc1
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 +39 -27
- data/lib/intranet/pictures/responder.rb +43 -74
- data/lib/intranet/pictures/version.rb +1 -1
- data/lib/intranet/resources/haml/pictures_home.haml +18 -25
- data/lib/intranet/resources/locales/en.yml +1 -15
- data/lib/intranet/resources/locales/fr.yml +1 -15
- data/lib/intranet/resources/www/jpictures.js +29 -3
- data/lib/intranet/resources/www/style.css +21 -3
- data/spec/intranet/pictures/json_db_provider_spec.rb +40 -23
- data/spec/intranet/pictures/responder_spec.rb +122 -176
- data/spec/intranet/pictures/sample-db.json +13 -9
- metadata +4 -5
- data/lib/intranet/resources/haml/pictures_browse.haml +0 -14
@@ -21,7 +21,8 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
21
21
|
@core = Intranet::Core.new(logger)
|
22
22
|
|
23
23
|
@provider = Intranet::Pictures::JsonDbProvider.new(File.join(__dir__, 'sample-db.json'))
|
24
|
-
|
24
|
+
defaults = { 'group_by' => 'location', 'sort_by' => 'datetime', 'sort_order' => 'desc' }
|
25
|
+
@responder = described_class.new(@provider, defaults)
|
25
26
|
@core.register_module(
|
26
27
|
@responder, ['pictures'], File.absolute_path('../../../lib/intranet/resources', __dir__)
|
27
28
|
)
|
@@ -29,14 +30,14 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
29
30
|
|
30
31
|
describe '#in_menu?' do
|
31
32
|
it 'should return the value provided at initialization' do
|
32
|
-
expect(described_class.new(nil,
|
33
|
-
expect(described_class.new(nil,
|
33
|
+
expect(described_class.new(nil, {}, false).in_menu?).to be false
|
34
|
+
expect(described_class.new(nil, {}, true).in_menu?).to be true
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
37
38
|
describe '#resources_dir' do
|
38
39
|
it 'should return the absolute path of the resources directory' do
|
39
|
-
expect(described_class.new(nil,
|
40
|
+
expect(described_class.new(nil, {}, false).resources_dir).to eql(
|
40
41
|
File.absolute_path('../../../lib/intranet/resources', __dir__)
|
41
42
|
)
|
42
43
|
end
|
@@ -44,35 +45,42 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
44
45
|
|
45
46
|
describe '#title' do
|
46
47
|
it 'should return the title of the webpage provided by the module' do
|
47
|
-
expect(@responder.title).to eql('
|
48
|
+
expect(@responder.title).to eql(I18n.t('pictures.menu'))
|
48
49
|
end
|
49
50
|
end
|
50
51
|
|
51
52
|
describe '#generate_page' do
|
52
53
|
context 'when asked for \'/index.html\'' do
|
53
|
-
it 'should return a partial HTML content
|
54
|
-
#
|
55
|
-
|
56
|
-
@responder.
|
57
|
-
code, mime, content = @responder.generate_page('/index.html', {})
|
54
|
+
it 'should return a partial HTML content with selected pictures grouped as requested' do
|
55
|
+
# No parameter in query: use default configuration provided at initialization & show all pictures
|
56
|
+
query = {}
|
57
|
+
code, mime, content = @responder.generate_page('/index.html', query)
|
58
58
|
expect(code).to eql(206)
|
59
59
|
expect(mime).to eql('text/html')
|
60
60
|
expect(content).to eql(
|
61
61
|
{
|
62
|
-
content: "<section>\n<h2
|
62
|
+
content: "<section>\n<h2>#{I18n.t('pictures.menu')}</h2>\n" \
|
63
63
|
"<ul class='breadcrumb'>\n" \
|
64
64
|
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
65
65
|
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
66
|
-
"<li>My Gallery</li>\n" \
|
67
66
|
"</ul>\n\n" \
|
68
|
-
"<
|
67
|
+
"<h4>Tags</h4>\n" \
|
68
|
+
"<div id='tags'>\n" \
|
69
|
+
"<button class='tag' onclick='filterByTag("Cherry blossom");' type='button'>\nCherry blossom\n</button>\n" \
|
70
|
+
"<button class='tag' onclick='filterByTag("Louvre");' type='button'>\nLouvre\n</button>\n" \
|
71
|
+
"<button class='tag' onclick='filterByTag("MoMAK");' type='button'>\nMoMAK\n</button>\n" \
|
72
|
+
"<button class='tag' onclick='filterByTag("Modern art");' type='button'>\nModern art\n</button>\n" \
|
73
|
+
"<button class='tag' onclick='filterByTag("Pyramid");' type='button'>\nPyramid\n</button>\n" \
|
74
|
+
"<button class='tag' onclick='filterByTag("Urban photography");' type='button'>\nUrban photography\n</button>\n" \
|
75
|
+
"</div>\n" \
|
76
|
+
"<h4>#{I18n.t('pictures.nav.location')}</h4>\n" \
|
69
77
|
"<ul class='groups'>\n" \
|
70
|
-
"<li title='New York, USA'>\n<a onclick='openImagesGallery("location=New York, USA&sort_by=datetime");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=New York, USA")'></div>\n<figcaption>\nNew York, USA\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
71
|
-
"<li title='Paris, France'>\n<a onclick='openImagesGallery("location=Paris, France&sort_by=datetime");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Paris, France")'></div>\n<figcaption>\nParis, France\n<br>\n<em>The City of Light</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
78
|
+
"<li title='New York, USA'>\n<a onclick='openImagesGallery("location=New York, USA&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=New York, USA")'></div>\n<figcaption>\nNew York, USA\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
79
|
+
"<li title='Paris, France'>\n<a onclick='openImagesGallery("location=Paris, France&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Paris, France")'></div>\n<figcaption>\nParis, France\n<br>\n<em>The City of Light</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
80
|
+
"<li title='Tokyo, Japan'>\n<a onclick='openImagesGallery("location=Tokyo, Japan&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Tokyo, Japan")'></div>\n<figcaption>\nTokyo, Japan\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
72
81
|
"</ul>\n" \
|
73
|
-
"<p class='see_more'>\n<a href='browse.html?group_by=location&sort_by=datetime&sort_order=desc'>#{I18n.t('pictures.see_more')}</a>\n</p>\n" \
|
74
82
|
"</section>\n",
|
75
|
-
title: '
|
83
|
+
title: I18n.t('pictures.menu'),
|
76
84
|
stylesheets: [
|
77
85
|
'design/style.css',
|
78
86
|
'design/photoswipe/photoswipe.css',
|
@@ -82,28 +90,34 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
82
90
|
}
|
83
91
|
)
|
84
92
|
|
85
|
-
#
|
86
|
-
|
87
|
-
@responder.
|
88
|
-
code, mime, content = @responder.generate_page('/index.html', {})
|
93
|
+
# Query overrides group_by field
|
94
|
+
query = { 'group_by' => 'author' }
|
95
|
+
code, mime, content = @responder.generate_page('/index.html', query)
|
89
96
|
expect(code).to eql(206)
|
90
97
|
expect(mime).to eql('text/html')
|
91
98
|
expect(content).to eql(
|
92
99
|
{
|
93
|
-
content: "<section>\n<h2
|
100
|
+
content: "<section>\n<h2>#{I18n.t('pictures.menu')}</h2>\n" \
|
94
101
|
"<ul class='breadcrumb'>\n" \
|
95
102
|
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
96
103
|
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
97
|
-
"<li>My Gallery</li>\n" \
|
98
104
|
"</ul>\n\n" \
|
99
|
-
"<
|
105
|
+
"<h4>Tags</h4>\n" \
|
106
|
+
"<div id='tags'>\n" \
|
107
|
+
"<button class='tag' onclick='filterByTag("Cherry blossom");' type='button'>\nCherry blossom\n</button>\n" \
|
108
|
+
"<button class='tag' onclick='filterByTag("Louvre");' type='button'>\nLouvre\n</button>\n" \
|
109
|
+
"<button class='tag' onclick='filterByTag("MoMAK");' type='button'>\nMoMAK\n</button>\n" \
|
110
|
+
"<button class='tag' onclick='filterByTag("Modern art");' type='button'>\nModern art\n</button>\n" \
|
111
|
+
"<button class='tag' onclick='filterByTag("Pyramid");' type='button'>\nPyramid\n</button>\n" \
|
112
|
+
"<button class='tag' onclick='filterByTag("Urban photography");' type='button'>\nUrban photography\n</button>\n" \
|
113
|
+
"</div>\n" \
|
114
|
+
"<h4>#{I18n.t('pictures.nav.author')}</h4>\n" \
|
100
115
|
"<ul class='groups'>\n" \
|
101
|
-
"<li title='
|
102
|
-
"<li title='
|
116
|
+
"<li title='Jane Doe'>\n<a onclick='openImagesGallery("author=Jane Doe&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?author=Jane Doe")'></div>\n<figcaption>\nJane Doe\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
117
|
+
"<li title='John Doe'>\n<a onclick='openImagesGallery("author=John Doe&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?author=John Doe")'></div>\n<figcaption>\nJohn Doe\n<br>\n<em>Best photographer ever</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
103
118
|
"</ul>\n" \
|
104
|
-
"<p class='see_more'>\n<a href='browse.html?group_by=location&sort_by=datetime'>#{I18n.t('pictures.see_more')}</a>\n</p>\n" \
|
105
119
|
"</section>\n",
|
106
|
-
title: '
|
120
|
+
title: I18n.t('pictures.menu'),
|
107
121
|
stylesheets: [
|
108
122
|
'design/style.css',
|
109
123
|
'design/photoswipe/photoswipe.css',
|
@@ -113,28 +127,34 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
113
127
|
}
|
114
128
|
)
|
115
129
|
|
116
|
-
#
|
117
|
-
|
118
|
-
@responder.
|
119
|
-
code, mime, content = @responder.generate_page('/index.html', {})
|
130
|
+
# Query overrides group_by field. This field is present for some pictures only.
|
131
|
+
query = { 'group_by' => 'camera' }
|
132
|
+
code, mime, content = @responder.generate_page('/index.html', query)
|
120
133
|
expect(code).to eql(206)
|
121
134
|
expect(mime).to eql('text/html')
|
122
135
|
expect(content).to eql(
|
123
136
|
{
|
124
|
-
content: "<section>\n<h2
|
137
|
+
content: "<section>\n<h2>#{I18n.t('pictures.menu')}</h2>\n" \
|
125
138
|
"<ul class='breadcrumb'>\n" \
|
126
139
|
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
127
140
|
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
128
|
-
"<li>My Gallery</li>\n" \
|
129
141
|
"</ul>\n\n" \
|
130
|
-
"<
|
142
|
+
"<h4>Tags</h4>\n" \
|
143
|
+
"<div id='tags'>\n" \
|
144
|
+
"<button class='tag' onclick='filterByTag("Cherry blossom");' type='button'>\nCherry blossom\n</button>\n" \
|
145
|
+
"<button class='tag' onclick='filterByTag("Louvre");' type='button'>\nLouvre\n</button>\n" \
|
146
|
+
"<button class='tag' onclick='filterByTag("MoMAK");' type='button'>\nMoMAK\n</button>\n" \
|
147
|
+
"<button class='tag' onclick='filterByTag("Modern art");' type='button'>\nModern art\n</button>\n" \
|
148
|
+
"<button class='tag' onclick='filterByTag("Pyramid");' type='button'>\nPyramid\n</button>\n" \
|
149
|
+
"<button class='tag' onclick='filterByTag("Urban photography");' type='button'>\nUrban photography\n</button>\n" \
|
150
|
+
"</div>\n" \
|
151
|
+
"<h4>#{I18n.t('pictures.nav.camera')}</h4>\n" \
|
131
152
|
"<ul class='groups'>\n" \
|
132
|
-
"<li title='
|
133
|
-
"<li title='
|
134
|
-
"<li title='New York, USA'>\n<a onclick='openImagesGallery("location=New York, USA&sort_by=datetime");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=New York, USA")'></div>\n<figcaption>\nNew York, USA\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
153
|
+
"<li title='Canon EOS 5D MARK IV'>\n<a onclick='openImagesGallery("camera=Canon EOS 5D MARK IV&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?camera=Canon EOS 5D MARK IV")'></div>\n<figcaption>\nCanon EOS 5D MARK IV\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
154
|
+
"<li title='Apple iPhone 11'>\n<a onclick='openImagesGallery("camera=Apple iPhone 11&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?camera=Apple iPhone 11")'></div>\n<figcaption>\nApple iPhone 11\n<br>\n<em>Best smartphone ever</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
135
155
|
"</ul>\n" \
|
136
156
|
"</section>\n",
|
137
|
-
title: '
|
157
|
+
title: I18n.t('pictures.menu'),
|
138
158
|
stylesheets: [
|
139
159
|
'design/style.css',
|
140
160
|
'design/photoswipe/photoswipe.css',
|
@@ -144,111 +164,30 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
144
164
|
}
|
145
165
|
)
|
146
166
|
|
147
|
-
#
|
148
|
-
|
149
|
-
@responder.
|
150
|
-
code, mime, content = @responder.generate_page('/index.html', {})
|
151
|
-
expect(code).to eql(404)
|
152
|
-
expect(mime).to be_empty
|
153
|
-
expect(content).to be_empty
|
154
|
-
end
|
155
|
-
|
156
|
-
it 'should return a partial HTML content showing all groups according to configuration' do
|
157
|
-
# Nominal case without recents
|
158
|
-
home_groups = [{ 'group_by' => 'location', 'sort_by' => 'location',
|
159
|
-
'browse_group_by' => 'author' }]
|
160
|
-
@responder.instance_variable_set(:@home_groups, home_groups)
|
161
|
-
code, mime, content = @responder.generate_page('/index.html', {})
|
162
|
-
expect(code).to eql(206)
|
163
|
-
expect(mime).to eql('text/html')
|
164
|
-
expect(content).to eql(
|
165
|
-
{
|
166
|
-
content: "<section>\n<h2>My Gallery</h2>\n" \
|
167
|
-
"<ul class='breadcrumb'>\n" \
|
168
|
-
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
169
|
-
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
170
|
-
"<li>My Gallery</li>\n" \
|
171
|
-
"</ul>\n\n" \
|
172
|
-
"<h3>#{I18n.t('pictures.browse_by.location')}</h3>\n" \
|
173
|
-
"<ul class='groups wide'>\n" \
|
174
|
-
"<li title='New York, USA'>\n<a href='browse.html?group_by=author&location=New York, USA'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=New York, USA")'></div>\n<figcaption>\nNew York, USA\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
175
|
-
"<li title='Paris, France'>\n<a href='browse.html?group_by=author&location=Paris, France'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Paris, France")'></div>\n<figcaption>\nParis, France\n<br>\n<em>The City of Light</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
176
|
-
"<li title='Tokyo, Japan'>\n<a href='browse.html?group_by=author&location=Tokyo, Japan'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Tokyo, Japan")'></div>\n<figcaption>\nTokyo, Japan\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
177
|
-
"</ul>\n" \
|
178
|
-
"</section>\n",
|
179
|
-
title: 'My Gallery',
|
180
|
-
stylesheets: [
|
181
|
-
'design/style.css',
|
182
|
-
'design/photoswipe/photoswipe.css',
|
183
|
-
'design/photoswipe/photoswipe-dynamic-caption-plugin.css'
|
184
|
-
],
|
185
|
-
scripts: [{ src: 'design/jpictures.js', type: 'module' }]
|
186
|
-
}
|
187
|
-
)
|
188
|
-
|
189
|
-
# Nominal case with recents
|
190
|
-
recents = [{ 'group_by' => 'location', 'sort_by' => 'location', 'sort_order' => 'asc' }]
|
191
|
-
@responder.instance_variable_set(:@recents, recents)
|
192
|
-
home_groups = [{ 'group_by' => 'author', 'sort_by' => 'author', 'sort_order' => 'asc',
|
193
|
-
'browse_group_by' => 'location', 'browse_sort_by' => 'location', 'browse_sort_order' => 'desc' }]
|
194
|
-
@responder.instance_variable_set(:@home_groups, home_groups)
|
195
|
-
code, mime, content = @responder.generate_page('/index.html', {})
|
196
|
-
expect(code).to eql(206)
|
197
|
-
expect(mime).to eql('text/html')
|
198
|
-
expect(content).to eql(
|
199
|
-
{
|
200
|
-
content: "<section>\n<h2>My Gallery</h2>\n" \
|
201
|
-
"<ul class='breadcrumb'>\n" \
|
202
|
-
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
203
|
-
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
204
|
-
"<li>My Gallery</li>\n" \
|
205
|
-
"</ul>\n\n" \
|
206
|
-
"<h3>#{I18n.t('pictures.recents.location')}</h3>\n" \
|
207
|
-
"<ul class='groups'>\n" \
|
208
|
-
"<li title='New York, USA'>\n<a onclick='openImagesGallery("location=New York, USA&sort_by=datetime");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=New York, USA")'></div>\n<figcaption>\nNew York, USA\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
209
|
-
"<li title='Paris, France'>\n<a onclick='openImagesGallery("location=Paris, France&sort_by=datetime");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Paris, France")'></div>\n<figcaption>\nParis, France\n<br>\n<em>The City of Light</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
210
|
-
"<li title='Tokyo, Japan'>\n<a onclick='openImagesGallery("location=Tokyo, Japan&sort_by=datetime");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Tokyo, Japan")'></div>\n<figcaption>\nTokyo, Japan\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
211
|
-
"</ul>\n" \
|
212
|
-
"<h3>#{I18n.t('pictures.browse_by.author')}</h3>\n" \
|
213
|
-
"<ul class='groups wide'>\n" \
|
214
|
-
"<li title='Jane Doe'>\n<a href='browse.html?group_by=location&sort_by=location&sort_order=desc&author=Jane Doe'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?author=Jane Doe")'></div>\n<figcaption>\nJane Doe\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
215
|
-
"<li title='John Doe'>\n<a href='browse.html?group_by=location&sort_by=location&sort_order=desc&author=John Doe'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?author=John Doe")'></div>\n<figcaption>\nJohn Doe\n<br>\n<em>Best photographer ever</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
216
|
-
"</ul>\n" \
|
217
|
-
"</section>\n",
|
218
|
-
title: 'My Gallery',
|
219
|
-
stylesheets: [
|
220
|
-
'design/style.css',
|
221
|
-
'design/photoswipe/photoswipe.css',
|
222
|
-
'design/photoswipe/photoswipe-dynamic-caption-plugin.css'
|
223
|
-
],
|
224
|
-
scripts: [{ src: 'design/jpictures.js', type: 'module' }]
|
225
|
-
}
|
226
|
-
)
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
context 'when asked for \'/browse.html\'' do
|
231
|
-
it 'should return a partial HTML content with selected pictures grouped as requested' do
|
232
|
-
# No selector nor sort order
|
233
|
-
query = { 'group_by' => 'author' }
|
234
|
-
code, mime, content = @responder.generate_page('/browse.html', query)
|
167
|
+
# Query overrides defaults & specifies a valid selector
|
168
|
+
query = { 'group_by' => 'location', 'author' => 'John Doe', 'sort_by' => 'location', 'sort_order' => 'desc' }
|
169
|
+
code, mime, content = @responder.generate_page('/index.html', query)
|
235
170
|
expect(code).to eql(206)
|
236
171
|
expect(mime).to eql('text/html')
|
237
172
|
expect(content).to eql(
|
238
173
|
{
|
239
|
-
content: "<section>\n<h2
|
174
|
+
content: "<section>\n<h2>#{I18n.t('pictures.menu')}</h2>\n" \
|
240
175
|
"<ul class='breadcrumb'>\n" \
|
241
176
|
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
242
177
|
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
243
|
-
"<li>\n<a href='index.html'>My Gallery</a>\n</li>\n" \
|
244
|
-
"<li>#{I18n.t('pictures.nav.author')}</li>\n" \
|
245
178
|
"</ul>\n\n" \
|
179
|
+
"<h4>Tags</h4>\n" \
|
180
|
+
"<div id='tags'>\n" \
|
181
|
+
"<button class='tag' onclick='filterByTag("Louvre");' type='button'>\nLouvre\n</button>\n" \
|
182
|
+
"<button class='tag' onclick='filterByTag("Modern art");' type='button'>\nModern art\n</button>\n" \
|
183
|
+
"</div>\n" \
|
184
|
+
"<h4>#{I18n.t('pictures.nav.location')}</h4>\n" \
|
246
185
|
"<ul class='groups'>\n" \
|
247
|
-
"<li title='
|
248
|
-
"<li title='
|
186
|
+
"<li title='Tokyo, Japan'>\n<a onclick='openImagesGallery("author=John Doe&location=Tokyo, Japan&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Tokyo, Japan")'></div>\n<figcaption>\nTokyo, Japan\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
187
|
+
"<li title='Paris, France'>\n<a onclick='openImagesGallery("author=John Doe&location=Paris, France&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Paris, France")'></div>\n<figcaption>\nParis, France\n<br>\n<em>The City of Light</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
249
188
|
"</ul>\n" \
|
250
189
|
"</section>\n",
|
251
|
-
title: '
|
190
|
+
title: I18n.t('pictures.menu'),
|
252
191
|
stylesheets: [
|
253
192
|
'design/style.css',
|
254
193
|
'design/photoswipe/photoswipe.css',
|
@@ -258,26 +197,24 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
258
197
|
}
|
259
198
|
)
|
260
199
|
|
261
|
-
#
|
262
|
-
query = { 'group_by' => 'location', '
|
263
|
-
code, mime, content = @responder.generate_page('/
|
200
|
+
# Invalid selector
|
201
|
+
query = { 'group_by' => 'location', 'foo' => 'bar' }
|
202
|
+
code, mime, content = @responder.generate_page('/index.html', query)
|
264
203
|
expect(code).to eql(206)
|
265
204
|
expect(mime).to eql('text/html')
|
266
205
|
expect(content).to eql(
|
267
206
|
{
|
268
|
-
content: "<section>\n<h2
|
207
|
+
content: "<section>\n<h2>#{I18n.t('pictures.menu')}</h2>\n" \
|
269
208
|
"<ul class='breadcrumb'>\n" \
|
270
209
|
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
271
210
|
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
272
|
-
"<li>\n<a href='index.html'>My Gallery</a>\n</li>\n" \
|
273
|
-
"<li>#{I18n.t('pictures.nav.location')} (John Doe)</li>\n" \
|
274
211
|
"</ul>\n\n" \
|
275
|
-
"<
|
276
|
-
"<
|
277
|
-
"<
|
278
|
-
"</
|
212
|
+
"<h4>Tags</h4>\n" \
|
213
|
+
"<p>\n<em>#{I18n.t('pictures.no_result_found')}</em>\n</p>\n" \
|
214
|
+
"<h4>#{I18n.t('pictures.nav.location')}</h4>\n" \
|
215
|
+
"<p>\n<em>#{I18n.t('pictures.no_result_found')}</em>\n</p>\n" \
|
279
216
|
"</section>\n",
|
280
|
-
title: '
|
217
|
+
title: I18n.t('pictures.menu'),
|
281
218
|
stylesheets: [
|
282
219
|
'design/style.css',
|
283
220
|
'design/photoswipe/photoswipe.css',
|
@@ -287,23 +224,31 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
287
224
|
}
|
288
225
|
)
|
289
226
|
|
290
|
-
# Invalid
|
291
|
-
query = { 'group_by' => '
|
292
|
-
code, mime, content = @responder.generate_page('/
|
227
|
+
# Invalid grouping criteria
|
228
|
+
query = { 'group_by' => 'foo' }
|
229
|
+
code, mime, content = @responder.generate_page('/index.html', query)
|
293
230
|
expect(code).to eql(206)
|
294
231
|
expect(mime).to eql('text/html')
|
295
232
|
expect(content).to eql(
|
296
233
|
{
|
297
|
-
content: "<section>\n<h2
|
234
|
+
content: "<section>\n<h2>#{I18n.t('pictures.menu')}</h2>\n" \
|
298
235
|
"<ul class='breadcrumb'>\n" \
|
299
236
|
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
300
237
|
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
301
|
-
"<li>\n<a href='index.html'>My Gallery</a>\n</li>\n" \
|
302
|
-
"<li>#{I18n.t('pictures.nav.location')} (bar)</li>\n" \
|
303
238
|
"</ul>\n\n" \
|
304
|
-
"<
|
239
|
+
"<h4>Tags</h4>\n" \
|
240
|
+
"<div id='tags'>\n" \
|
241
|
+
"<button class='tag' onclick='filterByTag("Cherry blossom");' type='button'>\nCherry blossom\n</button>\n" \
|
242
|
+
"<button class='tag' onclick='filterByTag("Louvre");' type='button'>\nLouvre\n</button>\n" \
|
243
|
+
"<button class='tag' onclick='filterByTag("MoMAK");' type='button'>\nMoMAK\n</button>\n" \
|
244
|
+
"<button class='tag' onclick='filterByTag("Modern art");' type='button'>\nModern art\n</button>\n" \
|
245
|
+
"<button class='tag' onclick='filterByTag("Pyramid");' type='button'>\nPyramid\n</button>\n" \
|
246
|
+
"<button class='tag' onclick='filterByTag("Urban photography");' type='button'>\nUrban photography\n</button>\n" \
|
247
|
+
"</div>\n" \
|
248
|
+
"<h4>#{I18n.t('pictures.nav.foo')}</h4>\n" \
|
249
|
+
"<p>\n<em>#{I18n.t('pictures.no_result_found')}</em>\n</p>\n" \
|
305
250
|
"</section>\n",
|
306
|
-
title: '
|
251
|
+
title: I18n.t('pictures.menu'),
|
307
252
|
stylesheets: [
|
308
253
|
'design/style.css',
|
309
254
|
'design/photoswipe/photoswipe.css',
|
@@ -313,16 +258,9 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
313
258
|
}
|
314
259
|
)
|
315
260
|
|
316
|
-
# Invalid grouping criteria
|
317
|
-
query = { 'group_by' => 'foo' }
|
318
|
-
code, mime, content = @responder.generate_page('/browse.html', query)
|
319
|
-
expect(code).to eql(404)
|
320
|
-
expect(mime).to be_empty
|
321
|
-
expect(content).to be_empty
|
322
|
-
|
323
261
|
# Invalid sorting criteria
|
324
262
|
query = { 'group_by' => 'location', 'sort_order' => 'foo' }
|
325
|
-
code, mime, content = @responder.generate_page('/
|
263
|
+
code, mime, content = @responder.generate_page('/index.html', query)
|
326
264
|
expect(code).to eql(404)
|
327
265
|
expect(mime).to be_empty
|
328
266
|
expect(content).to be_empty
|
@@ -395,6 +333,13 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
395
333
|
expect(mime).to eql('application/json')
|
396
334
|
expect(content).to eql(''.to_json)
|
397
335
|
|
336
|
+
# Non-existing group
|
337
|
+
query = { 'flash' => 'true' }
|
338
|
+
code, mime, content = @responder.generate_page('/api/group_brief', query)
|
339
|
+
expect(code).to eql(404)
|
340
|
+
expect(mime).to be_empty
|
341
|
+
expect(content).to be_empty
|
342
|
+
|
398
343
|
# Invalid query
|
399
344
|
query = { 'location' => 'Tokyo, Japan', 'camera' => 'Canon EOS 5D MARK IV' }
|
400
345
|
code, mime, content = @responder.generate_page('/api/group_brief', query)
|
@@ -406,52 +351,53 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
406
351
|
|
407
352
|
context 'when asked for \'/api/pictures\'' do
|
408
353
|
it 'should return a JSON representation of the selected pictures' do
|
409
|
-
# All pictures (no selector
|
354
|
+
# All pictures (no selector & default sort order)
|
410
355
|
code, mime, content = @responder.generate_page('/api/pictures', {})
|
411
356
|
expect(code).to eql(200)
|
412
357
|
expect(mime).to eql('application/json')
|
413
358
|
expect(content).to eql(
|
414
359
|
[
|
415
|
-
{ 'datetime' => '
|
416
|
-
{ 'datetime' => '2020:06:
|
417
|
-
{ 'datetime' => '2020:06:
|
418
|
-
{ 'datetime' => '
|
419
|
-
{ 'datetime' => '2019:07:22 09:
|
360
|
+
{ 'datetime' => '2020:06:20 18:14:09', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'New York, USA', 'tags' => 'Urban photography' },
|
361
|
+
{ 'datetime' => '2020:06:20 06:09:54', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'Paris, France', 'camera' => 'Canon EOS 5D MARK IV', 'tags' => ['Louvre', 'Pyramid', 'Urban photography'] },
|
362
|
+
{ 'datetime' => '2020:06:19 07:51:05', 'flash' => 'false', 'author' => 'Jane Doe', 'location' => 'Tokyo, Japan', 'tags' => ['MoMAK', 'Modern art', 'Cherry blossom'] },
|
363
|
+
{ 'datetime' => '2019:07:22 09:45:17', 'author' => 'John Doe', 'location' => 'Tokyo, Japan' },
|
364
|
+
{ 'datetime' => '2019:07:22 09:41:31', 'author' => 'John Doe', 'location' => 'Paris, France', 'camera' => 'Apple iPhone 11', 'tags' => ['Modern art', 'Louvre'] }
|
420
365
|
].to_json
|
421
366
|
)
|
422
367
|
|
423
|
-
# Valid selector
|
424
|
-
query = { 'author' => 'Jane Doe', 'flash' => true }
|
368
|
+
# Valid selector & default sort order
|
369
|
+
query = { 'author' => 'Jane Doe', 'flash' => 'true' }
|
425
370
|
code, mime, content = @responder.generate_page('/api/pictures', query)
|
426
371
|
expect(code).to eql(200)
|
427
372
|
expect(mime).to eql('application/json')
|
428
373
|
expect(content).to eql(
|
429
374
|
[
|
430
|
-
{ 'datetime' => '2020:06:20 18:14:09', 'flash' => true, 'author' => 'Jane Doe', 'location' => 'New York, USA' },
|
431
|
-
{ 'datetime' => '2020:06:20 06:09:54', 'flash' => true, 'author' => 'Jane Doe', 'location' => 'Paris, France', 'camera' => 'Canon EOS 5D MARK IV' }
|
375
|
+
{ 'datetime' => '2020:06:20 18:14:09', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'New York, USA', 'tags' => 'Urban photography' },
|
376
|
+
{ 'datetime' => '2020:06:20 06:09:54', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'Paris, France', 'camera' => 'Canon EOS 5D MARK IV', 'tags' => ['Louvre', 'Pyramid', 'Urban photography'] }
|
432
377
|
].to_json
|
433
378
|
)
|
434
379
|
|
435
380
|
# Valid selector, valid sort order
|
436
|
-
query = { 'author' => 'Jane Doe', '
|
381
|
+
query = { 'author' => 'Jane Doe', 'tags' => 'Urban photography', 'sort_by' => 'datetime',
|
382
|
+
'sort_order' => 'asc' }
|
437
383
|
code, mime, content = @responder.generate_page('/api/pictures', query)
|
438
384
|
expect(code).to eql(200)
|
439
385
|
expect(mime).to eql('application/json')
|
440
386
|
expect(content).to eql(
|
441
387
|
[
|
442
|
-
{ 'datetime' => '2020:06:20 06:09:54', 'flash' => true, 'author' => 'Jane Doe', 'location' => 'Paris, France', 'camera' => 'Canon EOS 5D MARK IV' },
|
443
|
-
{ 'datetime' => '2020:06:20 18:14:09', 'flash' => true, 'author' => 'Jane Doe', 'location' => 'New York, USA' }
|
388
|
+
{ 'datetime' => '2020:06:20 06:09:54', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'Paris, France', 'camera' => 'Canon EOS 5D MARK IV', 'tags' => ['Louvre', 'Pyramid', 'Urban photography'] },
|
389
|
+
{ 'datetime' => '2020:06:20 18:14:09', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'New York, USA', 'tags' => 'Urban photography' }
|
444
390
|
].to_json
|
445
391
|
)
|
446
|
-
query = { 'author' => 'Jane Doe', 'flash' => true, 'sort_by' => 'location',
|
392
|
+
query = { 'author' => 'Jane Doe', 'flash' => 'true', 'sort_by' => 'location',
|
447
393
|
'sort_order' => 'desc' }
|
448
394
|
code, mime, content = @responder.generate_page('/api/pictures', query)
|
449
395
|
expect(code).to eql(200)
|
450
396
|
expect(mime).to eql('application/json')
|
451
397
|
expect(content).to eql(
|
452
398
|
[
|
453
|
-
{ 'datetime' => '2020:06:20 06:09:54', 'flash' => true, 'author' => 'Jane Doe', 'location' => 'Paris, France', 'camera' => 'Canon EOS 5D MARK IV' },
|
454
|
-
{ 'datetime' => '2020:06:20 18:14:09', 'flash' => true, 'author' => 'Jane Doe', 'location' => 'New York, USA' }
|
399
|
+
{ 'datetime' => '2020:06:20 06:09:54', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'Paris, France', 'camera' => 'Canon EOS 5D MARK IV', 'tags' => ['Louvre', 'Pyramid', 'Urban photography'] },
|
400
|
+
{ 'datetime' => '2020:06:20 18:14:09', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'New York, USA', 'tags' => 'Urban photography' }
|
455
401
|
].to_json
|
456
402
|
)
|
457
403
|
|
@@ -1,5 +1,4 @@
|
|
1
1
|
{
|
2
|
-
"title": "My Gallery",
|
3
2
|
"groups": {
|
4
3
|
"author": [
|
5
4
|
{
|
@@ -27,7 +26,8 @@
|
|
27
26
|
],
|
28
27
|
"camera": [
|
29
28
|
{
|
30
|
-
"id": "Apple iPhone 11"
|
29
|
+
"id": "Apple iPhone 11",
|
30
|
+
"brief": "Best smartphone ever"
|
31
31
|
},
|
32
32
|
{
|
33
33
|
"id": "Canon EOS 5D MARK IV"
|
@@ -40,29 +40,33 @@
|
|
40
40
|
"datetime": "2019:07:22 09:41:31",
|
41
41
|
"author": "John Doe",
|
42
42
|
"location": "Paris, France",
|
43
|
-
"camera": "Apple iPhone 11"
|
43
|
+
"camera": "Apple iPhone 11",
|
44
|
+
"tags": [ "Modern art", "Louvre" ]
|
44
45
|
},
|
45
46
|
{
|
46
47
|
"uri": "./alpha.png",
|
47
48
|
"datetime": "2020:06:19 07:51:05",
|
48
|
-
"flash": false,
|
49
|
+
"flash": "false",
|
49
50
|
"author": "Jane Doe",
|
50
|
-
"location": "Tokyo, Japan"
|
51
|
+
"location": "Tokyo, Japan",
|
52
|
+
"tags": [ "MoMAK", "Modern art", "Cherry blossom" ]
|
51
53
|
},
|
52
54
|
{
|
53
55
|
"uri": "pic3.jpg",
|
54
56
|
"datetime": "2020:06:20 18:14:09",
|
55
|
-
"flash": true,
|
57
|
+
"flash": "true",
|
56
58
|
"author": "Jane Doe",
|
57
|
-
"location": "New York, USA"
|
59
|
+
"location": "New York, USA",
|
60
|
+
"tags": "Urban photography"
|
58
61
|
},
|
59
62
|
{
|
60
63
|
"uri": "sample-db.json",
|
61
64
|
"datetime": "2020:06:20 06:09:54",
|
62
|
-
"flash": true,
|
65
|
+
"flash": "true",
|
63
66
|
"author": "Jane Doe",
|
64
67
|
"location": "Paris, France",
|
65
|
-
"camera": "Canon EOS 5D MARK IV"
|
68
|
+
"camera": "Canon EOS 5D MARK IV",
|
69
|
+
"tags": [ "Louvre", "Pyramid", "Urban photography" ]
|
66
70
|
},
|
67
71
|
{
|
68
72
|
"datetime": "2019:07:22 09:45:17",
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: intranet-pictures
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ebling Mis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: intranet-core
|
@@ -53,7 +53,6 @@ files:
|
|
53
53
|
- lib/intranet/pictures/json_db_provider.rb
|
54
54
|
- lib/intranet/pictures/responder.rb
|
55
55
|
- lib/intranet/pictures/version.rb
|
56
|
-
- lib/intranet/resources/haml/pictures_browse.haml
|
57
56
|
- lib/intranet/resources/haml/pictures_home.haml
|
58
57
|
- lib/intranet/resources/locales/en.yml
|
59
58
|
- lib/intranet/resources/locales/fr.yml
|
@@ -89,9 +88,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
88
|
version: '3.0'
|
90
89
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
90
|
requirements:
|
92
|
-
- - "
|
91
|
+
- - ">"
|
93
92
|
- !ruby/object:Gem::Version
|
94
|
-
version:
|
93
|
+
version: 1.3.1
|
95
94
|
requirements: []
|
96
95
|
rubygems_version: 3.3.15
|
97
96
|
signing_key:
|
@@ -1,14 +0,0 @@
|
|
1
|
-
%section
|
2
|
-
= to_markup 'title_and_breadcrumb', {title: title, nav: nav}
|
3
|
-
%ul.groups
|
4
|
-
- groups.each do |group_name|
|
5
|
-
%li{ title: group_name }
|
6
|
-
%a{ onclick: 'openImagesGallery("' + gallery_url(group_key, group_name, filters) + '");' }
|
7
|
-
%figure
|
8
|
-
%div{ style: 'background-image: url("api/group_thumbnail?' + group_key + '=' + group_name + '")' }
|
9
|
-
%figcaption
|
10
|
-
= group_name
|
11
|
-
- group_brief = api_group_brief({ group_key => group_name })
|
12
|
-
- unless group_brief.empty?
|
13
|
-
%br
|
14
|
-
%em= group_brief
|