ama_layout 5.12.0 → 6.3.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -2
  3. data/ama_layout.gemspec +20 -21
  4. data/app/assets/javascripts/ama_layout/desktop/foundation-custom.js +8 -10
  5. data/app/assets/javascripts/ama_layout/desktop/index.js +0 -1
  6. data/app/helpers/ama_layout_path_helper.rb +5 -5
  7. data/app/views/ama_layout/_siteheader.html.erb +3 -8
  8. data/lib/ama_layout.rb +20 -28
  9. data/lib/ama_layout/decorators/moneris_decorator.rb +2 -3
  10. data/lib/ama_layout/decorators/navigation_decorator.rb +6 -52
  11. data/lib/ama_layout/decorators/navigation_item_decorator.rb +2 -3
  12. data/lib/ama_layout/moneris.rb +1 -4
  13. data/lib/ama_layout/navigation.rb +1 -7
  14. data/lib/ama_layout/navigation.yml +6 -58
  15. data/lib/ama_layout/navigation_item.rb +1 -4
  16. data/lib/ama_layout/version.rb +1 -1
  17. data/spec/ama_layout/decorators/navigation_decorator_spec.rb +8 -124
  18. data/spec/ama_layout/decorators/navigation_item_decorator_spec.rb +4 -2
  19. data/spec/ama_layout/navigation_spec.rb +43 -13
  20. data/spec/helpers/ama_layout_path_helper_spec.rb +6 -6
  21. data/spec/internal/app/controllers/application_controller.rb +0 -21
  22. data/spec/internal/config/routes.rb +0 -1
  23. data/spec/spec_helper.rb +16 -9
  24. data/styles.scss +0 -0
  25. metadata +41 -79
  26. data/PULL_REQUEST_TEMPLATE.md +0 -10
  27. data/app/assets/javascripts/ama_layout/notifications.coffee +0 -17
  28. data/app/controllers/ama_layout/api/v1/notifications_controller.rb +0 -18
  29. data/app/views/ama_layout/_notification.html.erb +0 -10
  30. data/app/views/ama_layout/_notification_sidebar.html.erb +0 -22
  31. data/app/views/ama_layout/_notifications.html.erb +0 -6
  32. data/app/views/ama_layout/_sign_out_link.html.erb +0 -3
  33. data/config/routes.rb +0 -9
  34. data/lib/ama_layout/decorators/notification_decorator.rb +0 -46
  35. data/lib/ama_layout/draper_replacement.rb +0 -27
  36. data/lib/ama_layout/navigation_helper.rb +0 -31
  37. data/lib/ama_layout/notification.rb +0 -87
  38. data/lib/ama_layout/notification_scrubber.rb +0 -13
  39. data/lib/ama_layout/notification_set.rb +0 -140
  40. data/lib/ama_layout/notifications.rb +0 -73
  41. data/lib/ama_layout/notifications/abstract_store.rb +0 -17
  42. data/lib/ama_layout/notifications/redis_store.rb +0 -38
  43. data/spec/ama_layout/controllers/ama_layout/api/v1/notifications_controller_spec.rb +0 -13
  44. data/spec/ama_layout/decorators/notification_decorator_spec.rb +0 -57
  45. data/spec/ama_layout/navigation_helper_spec.rb +0 -63
  46. data/spec/ama_layout/notification_scrubber_spec.rb +0 -10
  47. data/spec/ama_layout/notification_set_spec.rb +0 -281
  48. data/spec/ama_layout/notification_spec.rb +0 -193
  49. data/spec/ama_layout/notifications/abstract_store_spec.rb +0 -23
  50. data/spec/ama_layout/notifications/redis_store_spec.rb +0 -94
  51. data/spec/ama_layout/notifications_spec.rb +0 -109
  52. data/spec/factories/users.rb +0 -35
  53. data/spec/support/shared_examples/member_navigation.rb +0 -105
@@ -1,73 +0,0 @@
1
- module AmaLayout
2
- # Usage:
3
- #
4
- # class MyClass
5
- # include AmaLayout::Notifications
6
- #
7
- # notification_store AmaLayout::Notifications::RedisStore.new(options)
8
- # notification_foreign_key :a_method_name_or_proc # defaults to :id
9
- #
10
- # ...
11
- # end
12
- #
13
- module Notifications
14
- InvalidNotificationStore = Class.new(StandardError)
15
-
16
- def self.included(base)
17
- base.extend(ClassMethods)
18
- base.include(InstanceMethods)
19
- end
20
-
21
- module InstanceMethods
22
- def notifications
23
- @notifications ||= NotificationSet.new(_store, _foreign_key)
24
- end
25
-
26
- def notifications=(other)
27
- @notifications = other
28
- end
29
-
30
- private
31
-
32
- def _store
33
- self.class._notification_store || invalid_store!
34
- end
35
-
36
- def _foreign_key
37
- self.class._notification_foreign_key.call(self)
38
- end
39
-
40
- def invalid_store!
41
- raise InvalidNotificationStore, 'a notification store must be specified'
42
- end
43
- end
44
-
45
- module ClassMethods
46
- def notification_store(store)
47
- self._notification_store = store
48
- end
49
-
50
- def notification_foreign_key(key)
51
- self._notification_foreign_key = key
52
- end
53
-
54
- def _notification_foreign_key
55
- @_notification_foreign_key || Proc.new(&:id)
56
- end
57
-
58
- def _notification_store
59
- @_notification_store
60
- end
61
-
62
- private
63
-
64
- def _notification_store=(store)
65
- @_notification_store = store
66
- end
67
-
68
- def _notification_foreign_key=(key)
69
- @_notification_foreign_key = key.to_proc
70
- end
71
- end
72
- end
73
- end
@@ -1,17 +0,0 @@
1
- module AmaLayout
2
- module Notifications
3
- class AbstractStore
4
- def get(key, opts = {})
5
- raise NotImplementedError, 'you must define a #get method in a subclass'
6
- end
7
-
8
- def set(key, value, opts = {})
9
- raise NotImplementedError, 'you must define a #set method in a subclass'
10
- end
11
-
12
- def delete(key, opts = {})
13
- raise NotImplementedError, 'you must define a #delete method in a subclass'
14
- end
15
- end
16
- end
17
- end
@@ -1,38 +0,0 @@
1
- module AmaLayout
2
- module Notifications
3
- class RedisStore < AbstractStore
4
- delegate :clear, to: :base
5
-
6
- attr_accessor :base
7
-
8
- def initialize(opts = {})
9
- self.base = ActiveSupport::Cache.lookup_store(
10
- :redis_store,
11
- opts.merge(raw: true)
12
- )
13
- end
14
-
15
- def get(key, opts = {})
16
- if opts.fetch(:default, false)
17
- base.fetch(key) { opts[:default] }
18
- else
19
- base.read(key)
20
- end
21
- end
22
-
23
- def set(key, value, opts = {})
24
- base.write(key, value, opts) == 'OK'
25
- end
26
-
27
- def delete(key, opts = {})
28
- base.delete(key, opts) == 1
29
- end
30
-
31
- def transaction
32
- base.data.multi do
33
- yield self
34
- end
35
- end
36
- end
37
- end
38
- end
@@ -1,13 +0,0 @@
1
- describe AmaLayout::Api::V1::NotificationsController, type: :controller do
2
- describe 'DELETE api/v1/notifications' do
3
- routes { AmaLayout::Engine.routes }
4
-
5
- before(:each) do
6
- delete :dismiss_all
7
- end
8
-
9
- it 'returns a 204 No Content status' do
10
- expect(response).to have_http_status(:no_content)
11
- end
12
- end
13
- end
@@ -1,57 +0,0 @@
1
- describe AmaLayout::NotificationDecorator do
2
- let(:notification) do
3
- AmaLayout::Notification.new(
4
- header: 'test',
5
- content: 'content',
6
- type: :warning,
7
- created_at: Date.yesterday.beginning_of_day,
8
- active: true
9
- )
10
- end
11
- subject { described_class.new(notification) }
12
-
13
- describe '#created_at' do
14
- around(:each) do |example|
15
- Timecop.freeze(Time.zone.local(2017, 8)) do
16
- example.run
17
- end
18
- end
19
-
20
- it 'returns the time elapsed in english words' do
21
- expect(subject.created_at).to eq('1 day ago')
22
- end
23
- end
24
-
25
- describe '#icon' do
26
- it 'returns a div' do
27
- expect(subject.icon).to include('<div')
28
- end
29
-
30
- it 'contains the proper icon class' do
31
- expect(subject.icon).to include('fa-exclamation')
32
- end
33
-
34
- it 'contains the proper colour class' do
35
- expect(subject.icon).to include('right-sidebar__content-icon--orange')
36
- end
37
- end
38
-
39
- describe '#active_class' do
40
- context 'when active' do
41
- it 'returns the proper class' do
42
- expect(subject.active_class).to_not include('inactive')
43
- expect(subject.active_class).to include('active')
44
- end
45
- end
46
-
47
- context 'when inactive' do
48
- before(:each) do
49
- notification.dismiss!
50
- end
51
-
52
- it 'returns the proper class' do
53
- expect(subject.active_class).to include('inactive')
54
- end
55
- end
56
- end
57
- end
@@ -1,63 +0,0 @@
1
- describe AmaLayout::NavigationHelper do
2
- subject { FactoryGirl.create(:user) }
3
-
4
- describe '#navigation' do
5
- before(:each) do
6
- subject.class.include(AmaLayout::NavigationHelper).new
7
- end
8
-
9
- context 'non-member' do
10
- subject { FactoryGirl.create(:user, :non_member) }
11
-
12
- it 'shows non-member sidebar menu' do
13
- expect(subject.navigation).to eq 'non-member'
14
- end
15
- end
16
-
17
- context 'member' do
18
- it 'shows member sidebar menu' do
19
- expect(subject.navigation).to eq 'member'
20
- end
21
- end
22
-
23
- context 'member with accr' do
24
- subject { FactoryGirl.create(:user, :with_accr) }
25
-
26
- it 'shows member sidebar menu' do
27
- expect(subject.navigation).to eq 'member'
28
- end
29
- end
30
-
31
- context 'member with mpp' do
32
- subject { FactoryGirl.create(:user, :with_mpp) }
33
-
34
- it 'shows member sidebar menu' do
35
- expect(subject.navigation).to eq 'member'
36
- end
37
- end
38
-
39
- context 'member in-renewal' do
40
- subject { FactoryGirl.create(:user, :in_renewal) }
41
-
42
- it 'shows in-renewal sidebar menu' do
43
- expect(subject.navigation).to eq 'member-in-renewal'
44
- end
45
- end
46
-
47
- context 'member in-renewal late' do
48
- subject { FactoryGirl.create(:user, :in_renewal_late) }
49
-
50
- it 'shows in-renewal-late sidebar menu' do
51
- expect(subject.navigation).to eq 'member-in-renewal-late'
52
- end
53
- end
54
-
55
- context 'member with outstanding balance' do
56
- subject { FactoryGirl.create(:user, :outstanding_balance) }
57
-
58
- it 'shows member-with-outstanding-balance sidebar menu' do
59
- expect(subject.navigation).to eq 'member-with-outstanding-balance'
60
- end
61
- end
62
- end
63
- end
@@ -1,10 +0,0 @@
1
- describe AmaLayout::NotificationScrubber do
2
- describe '#initialize' do
3
- let(:sanitized) { Loofah.fragment(string).scrub!(subject).to_s }
4
- let(:string) { '<script>alert("haxxed");</script><a href="#" invalid="test">test</a>waffles' }
5
-
6
- it 'scrubs HTML tags from a string' do
7
- expect(sanitized).to eq('alert("haxxed");<a href="#">test</a>waffles')
8
- end
9
- end
10
- end
@@ -1,281 +0,0 @@
1
- describe AmaLayout::NotificationSet do
2
- let(:store) do
3
- AmaLayout::Notifications::RedisStore.new(
4
- db: 4,
5
- namespace: 'test_notifications',
6
- host: 'localhost'
7
- )
8
- end
9
- let(:key) { 1 }
10
- let(:duration) { AmaLayout::Notification::DEFAULT_LIFESPAN }
11
- let(:store_key) { key.to_s }
12
- let(:digest) { base_notification.digest }
13
- let(:base_notification) do
14
- AmaLayout::Notification.new(
15
- type: :notice,
16
- header: 'test',
17
- content: 'test',
18
- lifespan: duration,
19
- version: '1.0.0',
20
- created_at: Time.zone.local(2017, 06, 19),
21
- active: true
22
- )
23
- end
24
- let(:json) do
25
- <<-JSON
26
- {
27
- "#{digest}": {
28
- "type": "notice",
29
- "header": "test",
30
- "content": "test",
31
- "created_at": "2017-06-19T06:00:00.000Z",
32
- "active": true,
33
- "lifespan": #{duration},
34
- "version": "1.0.0"
35
- }
36
- }
37
- JSON
38
- end
39
- let(:stale_json) do
40
- <<-JSON
41
- {
42
- "d3c2bc71904100674325791b371db7446097f956ea76a304e787abd5f2588665": {
43
- "type": "notice",
44
- "header": "stale",
45
- "content": "stale",
46
- "created_at": "2012-06-19T06:00:00.000Z",
47
- "active": true,
48
- "lifespan": #{duration},
49
- "version": "1.0.0"
50
- }
51
- }
52
- JSON
53
- end
54
-
55
- subject { described_class.new(store, key) }
56
-
57
- around(:each) do |example|
58
- Timecop.freeze(Time.zone.local(2017, 6, 19)) do
59
- store.clear
60
- example.run
61
- store.clear
62
- end
63
- end
64
-
65
- describe '#initialize' do
66
- context 'with valid JSON in data store' do
67
- before(:each) do
68
- store.set(store_key, notification)
69
- end
70
-
71
- context 'without stale notifications in the data store' do
72
- let(:notification) { json }
73
-
74
- it 'fetches the notifications' do
75
- expect(subject.size).to eq(1)
76
- end
77
- end
78
-
79
- context 'with stale notifications in the data store' do
80
- let(:notification) { stale_json }
81
-
82
- it 'returns an empty set' do
83
- expect(subject).to be_empty
84
- end
85
-
86
- it 'cleans out stale notifications from the data store' do
87
- subject
88
- expect(store.get(store_key)).to eq('{}')
89
- end
90
- end
91
- end
92
-
93
- context 'with invalid JSON in data store' do
94
- before(:each) do
95
- store.set(store_key, '{"invalid_json":')
96
- end
97
-
98
- it 'logs to Rails logger' do
99
- expect(Rails.logger).to receive(:error).with(instance_of(String))
100
- subject
101
- end
102
-
103
- it 'deletes the key in data store' do
104
- subject
105
- expect(store.get(store_key)).to be nil
106
- end
107
-
108
- it 'returns an empty set' do
109
- expect(subject).to be_empty
110
- end
111
-
112
- it 'sets the base attribute to a hash' do
113
- expect(subject.base).to be_a(Hash)
114
- end
115
- end
116
-
117
- context 'with no entry in data store' do
118
- it 'returns an empty set' do
119
- expect(subject).to be_empty
120
- end
121
- end
122
- end
123
-
124
- describe '#create' do
125
- it 'returns the NotificationSet instance' do
126
- expect(subject.create(header: 'test', content: 'test')).to be_a(described_class)
127
- end
128
-
129
- it 'creates a new active notification' do
130
- subject.create(header: 'test', content: 'test')
131
- expect(subject.size).to eq(1)
132
- end
133
-
134
- it 'saves a notification in data store' do
135
- subject.create(header: 'test', content: 'test')
136
- expect(store.get(store_key)).to be_a(String)
137
- end
138
-
139
- context 'when the same notification exists but is dismissed' do
140
- before(:each) do
141
- store.set(store_key, json)
142
- subject.first.dismiss!
143
- subject.save
144
- subject.create(header: 'test', content: 'test')
145
- end
146
-
147
- it 'does not overwrite the notification' do
148
- expect(subject.active).to be_empty
149
- end
150
-
151
- it 'still has the dismissed notification in the data store' do
152
- data = JSON.parse(store.get(store_key))
153
- notification = data.values.first
154
- expect(data.values.first['active']).to be false
155
- end
156
- end
157
- end
158
-
159
- describe '#delete' do
160
- before(:each) do
161
- subject.create(base_notification.to_h)
162
- end
163
-
164
- context 'with an array as an argument' do
165
- it 'deletes the notification from the data store' do
166
- data = subject.delete([digest])
167
- expect(data).to be_a(described_class)
168
- expect(data).to be_empty
169
- expect(store.get(store_key)).to eq('{}')
170
- end
171
-
172
- it 'returns falsey if nothing is deleted' do
173
- expect(subject.delete(['missing'])).to be_falsey
174
- end
175
- end
176
-
177
- context 'with string arguments' do
178
- it 'deletes the notification from the data store' do
179
- data = subject.delete(digest)
180
- expect(data).to be_a(described_class)
181
- expect(data).to be_empty
182
- expect(store.get(store_key)).to eq('{}')
183
- end
184
-
185
- it 'returns falsey if nothing is deleted' do
186
- expect(subject.delete('missing')).to be_falsey
187
- end
188
- end
189
- end
190
-
191
- describe '#destroy' do
192
- context 'when data is removed' do
193
- before(:each) do
194
- subject.create(header: 'test', content: 'test', lifespan: 1.day)
195
- end
196
-
197
- it 'returns a NotificationSet instance' do
198
- expect(subject.destroy!).to be_a(described_class)
199
- end
200
-
201
- it 'removes the notifications from the data store' do
202
- subject.destroy!
203
- expect(store.get(store_key)).to be nil
204
- end
205
-
206
- it 'returns an empty set' do
207
- expect(subject.destroy!).to be_empty
208
- end
209
- end
210
-
211
- context 'when data is not removed' do
212
- it 'returns false' do
213
- expect(subject.destroy!).to be false
214
- end
215
- end
216
- end
217
-
218
- describe '#find' do
219
- context 'when id is not preset' do
220
- it 'returns nil' do
221
- expect(subject.find('invalid')).to be nil
222
- end
223
- end
224
-
225
- context 'when id is present' do
226
- let(:id) { subject.last.id }
227
-
228
- before(:each) do
229
- subject.create(header: 'test', content: 'test')
230
- end
231
-
232
- it 'returns the notification' do
233
- expect(subject.find(id)).to eq(subject.last)
234
- end
235
- end
236
- end
237
-
238
- describe '#save' do
239
- before(:each) do
240
- subject.create(header: 'test', content: 'test')
241
- end
242
-
243
- it 'saves the notifications' do
244
- expect(subject.last.active?).to be true
245
- subject.last.dismiss!
246
- subject.save
247
- expect(subject.active).to be_empty
248
- end
249
-
250
- it 'returns the NotificationSet instance' do
251
- expect(subject.save).to be_a(described_class)
252
- end
253
- end
254
-
255
- describe '#inspect' do
256
- it 'returns a stringified instance' do
257
- expect(subject.inspect).to eq('<AmaLayout::NotificationSet>: []')
258
- end
259
- end
260
-
261
- context 'scoping' do
262
- before(:each) do
263
- subject.create(header: 'test', content: 'test')
264
- subject.create(header: 'inactive', content: 'inactive')
265
- subject.last.dismiss!
266
- subject.save
267
- end
268
-
269
- describe '#all' do
270
- it 'returns both active and inactive notifications' do
271
- expect(subject.all.size).to eq(2)
272
- end
273
- end
274
-
275
- describe '#active' do
276
- it 'returns only active notifications' do
277
- expect(subject.active.size).to eq(1)
278
- end
279
- end
280
- end
281
- end