ama_layout 5.6.0 → 5.7.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/app/assets/javascripts/ama_layout/desktop/index.js +1 -0
- data/app/assets/javascripts/ama_layout/notifications.coffee +17 -0
- data/app/controllers/ama_layout/api/v1/notifications_controller.rb +18 -0
- data/app/views/ama_layout/_notification.html.erb +10 -0
- data/app/views/ama_layout/_notification_sidebar.html.erb +22 -0
- data/app/views/ama_layout/_notifications.html.erb +6 -0
- data/app/views/ama_layout/_siteheader.html.erb +6 -1
- data/config/routes.rb +9 -0
- data/lib/ama_layout.rb +6 -6
- data/lib/ama_layout/decorators/navigation_decorator.rb +47 -0
- data/lib/ama_layout/decorators/notification_decorator.rb +45 -0
- data/lib/ama_layout/notification.rb +7 -2
- data/lib/ama_layout/notification_scrubber.rb +13 -0
- data/lib/ama_layout/notification_set.rb +12 -2
- data/lib/ama_layout/version.rb +1 -1
- data/spec/ama_layout/controllers/ama_layout/api/v1/notifications_controller_spec.rb +13 -0
- data/spec/ama_layout/decorators/navigation_decorator_spec.rb +121 -2
- data/spec/ama_layout/decorators/notification_decorator_spec.rb +57 -0
- data/spec/ama_layout/notification_scrubber_spec.rb +10 -0
- data/spec/ama_layout/notification_set_spec.rb +49 -5
- data/spec/ama_layout/notifications_spec.rb +1 -1
- data/spec/internal/app/controllers/application_controller.rb +21 -0
- data/spec/internal/config/routes.rb +1 -0
- data/spec/spec_helper.rb +0 -6
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 681ee492fa8e24d8f976759f37763fb2aa82a6bc
|
4
|
+
data.tar.gz: 0174f1cfcb34cf34c3747af2159930a49edba280
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2329ee194ad518c686aaca74a7dac3b730d467d5e0e4952c4ec0d4b1a088d68fbf43be1f5bab0d4fc915829e3ae1f0fc891cc1645792288e9c737bbb1ad8fd7c
|
7
|
+
data.tar.gz: b04fbb19aac1aed374ca4f4f14c8499dac9f055e245f8f5b869f02d018d9a23d48e2d72a0e2b05fced356f884a2981dc0a5aa59a5c6dc93299050a4f7f9fe9a7
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class AMALayout.Notifications
|
2
|
+
constructor: () ->
|
3
|
+
$(document).on 'click', '[data-notifications-toggle]', (event) =>
|
4
|
+
event.preventDefault();
|
5
|
+
badge = event.currentTarget
|
6
|
+
if $(badge).find('[data-notification-count]').remove().size()
|
7
|
+
@request()
|
8
|
+
|
9
|
+
request: () ->
|
10
|
+
$.ajax(
|
11
|
+
type: 'DELETE',
|
12
|
+
url: '/ama_layout/api/v1/notifications',
|
13
|
+
timeout: 10000
|
14
|
+
)
|
15
|
+
|
16
|
+
$(document).ready ->
|
17
|
+
window.AMALayout.notifications = new AMALayout.Notifications()
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module AmaLayout
|
2
|
+
module Api
|
3
|
+
module V1
|
4
|
+
class NotificationsController < ApplicationController
|
5
|
+
before_action :require_login
|
6
|
+
|
7
|
+
# DELETE /api/v1/notifications
|
8
|
+
# Dismiss all user notifications
|
9
|
+
def dismiss_all
|
10
|
+
notifications = current_user.notifications
|
11
|
+
notifications.each(&:dismiss!)
|
12
|
+
notifications.save
|
13
|
+
head :no_content
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<div class="row <%= notification.active_class %>">
|
2
|
+
<div class="small-2 column">
|
3
|
+
<%= notification.icon %>
|
4
|
+
</div>
|
5
|
+
<div class="small-10 column">
|
6
|
+
<p class="bold"><%= notification.header %></p>
|
7
|
+
<p><%= sanitize notification.content, scrubber: AmaLayout::NotificationScrubber.new %></p>
|
8
|
+
<p class="micetype"><%= notification.created_at %></p>
|
9
|
+
</div>
|
10
|
+
</div>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<div class="off-canvas position-right right-sidebar" id="offCanvasRight" data-off-canvas>
|
2
|
+
<div class="row column right-sidebar__header">
|
3
|
+
<h2 class="mt1">Notification Centre</h2>
|
4
|
+
<button class="close-button" aria-label="Close menu" type="button" data-close>
|
5
|
+
<span aria-hidden="true">×</span>
|
6
|
+
</button>
|
7
|
+
</div>
|
8
|
+
<div class="row column">
|
9
|
+
<%= navigation.notifications_heading %>
|
10
|
+
</div>
|
11
|
+
<%= render partial: 'ama_layout/notification', collection: notifications %>
|
12
|
+
<div class="row column">
|
13
|
+
<p class="mt1">Did You Know?</p>
|
14
|
+
<div class="section-content">
|
15
|
+
<p class="bold">Sign up for Vehicle Registration Auto-Renew</p>
|
16
|
+
<p>
|
17
|
+
We'll process your payment and mail you a new registration certificate and licence plate sticker. It's that simple!
|
18
|
+
</p>
|
19
|
+
<%= link_to 'Sign up now', "#{Rails.configuration.registries_site}/order/registrations/new", class: 'button--right button--expand-small-down' %>
|
20
|
+
</div>
|
21
|
+
</div>
|
22
|
+
</div>
|
@@ -2,6 +2,10 @@
|
|
2
2
|
<div class="title-bar" data-responsive-toggle="main-menu" data-hide-for="large">
|
3
3
|
<button class="menu-icon" type="button" data-toggle="offCanvasLeft"></button>
|
4
4
|
<%= link_to(image_tag("ama-logo.png"), "https://www.ama.ab.ca", class: "title-bar__logo") %>
|
5
|
+
<a href="#" data-toggle="offCanvasRight" data-notifications-toggle>
|
6
|
+
<i class="fa fa-2x fa-bell notification__icon"></i>
|
7
|
+
<%= navigation.notification_badge %>
|
8
|
+
</a>
|
5
9
|
</div>
|
6
10
|
<div class="top-bar" id="main-menu">
|
7
11
|
<div class="top-bar-left">
|
@@ -9,6 +13,7 @@
|
|
9
13
|
</div>
|
10
14
|
<div class="top-bar-right">
|
11
15
|
<ul class="menu" data-responsive-menu="drilldown medium-dropdown">
|
16
|
+
<%= navigation.notifications %>
|
12
17
|
<li>
|
13
18
|
<a href="<%= Rails.configuration.gatekeeper_site %>/help" target="_blank">Help</a>
|
14
19
|
</li>
|
@@ -43,7 +48,7 @@
|
|
43
48
|
</ul>
|
44
49
|
</div>
|
45
50
|
</div>
|
46
|
-
|
51
|
+
<%= navigation.notification_sidebar %>
|
47
52
|
<div class="javascript_errors error_notification" hidden></div>
|
48
53
|
<noscript>
|
49
54
|
<div class="mt1 large-12 columns text-center error_notification">
|
data/config/routes.rb
ADDED
data/lib/ama_layout.rb
CHANGED
@@ -17,16 +17,16 @@ require 'ama_layout/controllers/action_controller'
|
|
17
17
|
require 'ama_layout/notifications/abstract_store'
|
18
18
|
require 'ama_layout/notifications/redis_store'
|
19
19
|
require 'ama_layout/notification'
|
20
|
+
require 'ama_layout/decorators/notification_decorator'
|
21
|
+
require 'ama_layout/notification_scrubber'
|
20
22
|
require 'ama_layout/notification_set'
|
21
23
|
require 'ama_layout/notifications'
|
22
24
|
|
23
25
|
module AmaLayout
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
::ActionController::Base.send :include, AmaLayout::ActionController
|
29
|
-
end
|
26
|
+
class Engine < Rails::Engine
|
27
|
+
initializer('ama_layout') do
|
28
|
+
I18n.load_path << File.join(self.root, 'app', 'config', 'locales', 'en.yml')
|
29
|
+
::ActionController::Base.send :include, AmaLayout::ActionController
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
@@ -32,5 +32,52 @@ module AmaLayout
|
|
32
32
|
def account_toggle
|
33
33
|
h.render partial: "account_toggle"
|
34
34
|
end
|
35
|
+
|
36
|
+
def notifications
|
37
|
+
if user
|
38
|
+
h.render 'ama_layout/notifications', notifications: user.notifications, navigation: self
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def notification_badge
|
43
|
+
if new_notifications?
|
44
|
+
h.content_tag(
|
45
|
+
:div,
|
46
|
+
active_notification_count,
|
47
|
+
class: 'notification__badge',
|
48
|
+
data: {
|
49
|
+
notification_count: true
|
50
|
+
}
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def notification_sidebar
|
56
|
+
if user
|
57
|
+
h.render 'ama_layout/notification_sidebar', navigation: self, notifications: decorated_notifications
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def notifications_heading
|
62
|
+
if user.notifications.any?
|
63
|
+
h.content_tag :p, 'Most Recent Notifications', class: 'mt1'
|
64
|
+
else
|
65
|
+
h.content_tag :p, 'No Recent Notifications', class: 'mt1 italic'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def decorated_notifications
|
72
|
+
AmaLayout::NotificationDecorator.decorate_collection(user.notifications)
|
73
|
+
end
|
74
|
+
|
75
|
+
def active_notification_count
|
76
|
+
user && user.notifications.active.size || 0
|
77
|
+
end
|
78
|
+
|
79
|
+
def new_notifications?
|
80
|
+
active_notification_count > 0
|
81
|
+
end
|
35
82
|
end
|
36
83
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module AmaLayout
|
2
|
+
class NotificationDecorator < Draper::Decorator
|
3
|
+
delegate_all
|
4
|
+
|
5
|
+
ICONS = {
|
6
|
+
notice: {
|
7
|
+
icon_class: 'fa-info',
|
8
|
+
colour_class: 'right-sidebar__content-icon--blue' # currently not in use
|
9
|
+
},
|
10
|
+
warning: {
|
11
|
+
icon_class: 'fa-exclamation',
|
12
|
+
colour_class: 'right-sidebar__content-icon--orange'
|
13
|
+
},
|
14
|
+
alert: {
|
15
|
+
icon_class: 'fa-exclamation-triangle',
|
16
|
+
colour_class: 'right-sidebar__content-icon--red'
|
17
|
+
}
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
def created_at
|
21
|
+
"#{time_elapsed} ago".humanize
|
22
|
+
end
|
23
|
+
|
24
|
+
def icon
|
25
|
+
h.content_tag :div, class: icon_data.fetch(:colour_class) do
|
26
|
+
klass = icon_data.fetch(:icon_class)
|
27
|
+
h.content_tag :i, nil, class: "fa #{klass} right-sidebar__notice-icon"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def active_class
|
32
|
+
active? ? 'right-sidebar__content--active' : 'right-sidebar__content--inactive'
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def icon_data
|
38
|
+
@icon_data ||= ICONS.fetch(type)
|
39
|
+
end
|
40
|
+
|
41
|
+
def time_elapsed
|
42
|
+
h.time_ago_in_words(object.created_at, include_seconds: true)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -1,18 +1,22 @@
|
|
1
1
|
module AmaLayout
|
2
2
|
class Notification
|
3
|
+
include Draper::Decoratable
|
4
|
+
|
3
5
|
TYPES = %i[notice warning alert].freeze
|
4
6
|
DEFAULT_LIFESPAN = 1.year.freeze
|
5
7
|
FORMAT_VERSION = '1.0.0'.freeze
|
6
8
|
|
7
9
|
# NOTE: The following attributes are designed to be immutable - you need
|
8
10
|
# make a new instance to change them. The only mutable attribute is :active.
|
9
|
-
attr_reader :id, :type, :header, :content, :created_at, :lifespan,
|
11
|
+
attr_reader :id, :type, :brand, :header, :content, :created_at, :lifespan,
|
12
|
+
:version
|
10
13
|
attr_accessor :active
|
11
14
|
|
12
15
|
def initialize(args = {})
|
13
16
|
args = args.with_indifferent_access
|
14
17
|
@id = args[:id]
|
15
18
|
@type = args.fetch(:type, :notice).to_sym
|
19
|
+
@brand = args[:brand]
|
16
20
|
@header = args.fetch(:header)
|
17
21
|
@content = args.fetch(:content)
|
18
22
|
@created_at = parse_time(args.fetch(:created_at))
|
@@ -41,7 +45,7 @@ module AmaLayout
|
|
41
45
|
|
42
46
|
def digest
|
43
47
|
Digest::SHA256.hexdigest(
|
44
|
-
"#{type}#{header}#{content}#{
|
48
|
+
"#{type}#{header}#{content}#{brand}#{version}"
|
45
49
|
)
|
46
50
|
end
|
47
51
|
|
@@ -54,6 +58,7 @@ module AmaLayout
|
|
54
58
|
# consistency with the underlying data store.
|
55
59
|
{
|
56
60
|
'type' => type.to_s,
|
61
|
+
'brand' => brand,
|
57
62
|
'header' => header,
|
58
63
|
'content' => content,
|
59
64
|
'created_at' => created_at.iso8601,
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module AmaLayout
|
2
|
+
class NotificationScrubber < Rails::Html::PermitScrubber
|
3
|
+
def initialize
|
4
|
+
super
|
5
|
+
self.tags = %w(i a div span strong br em h1 h2 h3 h4 h5 h6 blockquote)
|
6
|
+
self.attributes = %w(href class id)
|
7
|
+
end
|
8
|
+
|
9
|
+
def skip_node?(node)
|
10
|
+
node.text?
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -5,8 +5,9 @@ module AmaLayout
|
|
5
5
|
# The raw serialization format is JSON as follows (keys are SHA256 hashes):
|
6
6
|
#
|
7
7
|
# {
|
8
|
-
# "
|
8
|
+
# "57107043eab0f60a37f7735307dc6fc6709d04eec2dbeea8c284958057af9b77": {
|
9
9
|
# "type": "notice",
|
10
|
+
# "brand": "membership",
|
10
11
|
# "header": "test",
|
11
12
|
# "content": "test",
|
12
13
|
# "created_at": "2017-06-19T11:26:57.730-06:00",
|
@@ -20,7 +21,7 @@ module AmaLayout
|
|
20
21
|
include Enumerable
|
21
22
|
attr_accessor :base, :data_store, :key
|
22
23
|
|
23
|
-
delegate :each, :first, :last, :size, :[], :empty?, :any?, to: :
|
24
|
+
delegate :each, :first, :last, :size, :[], :empty?, :any?, to: :all
|
24
25
|
|
25
26
|
def initialize(data_store, key)
|
26
27
|
self.data_store = data_store
|
@@ -50,6 +51,15 @@ module AmaLayout
|
|
50
51
|
data_store.delete(key) && reload!
|
51
52
|
end
|
52
53
|
|
54
|
+
def delete(*digests)
|
55
|
+
digests = Array.wrap(digests.flatten)
|
56
|
+
delta = all.reject { |n| digests.include?(n.digest) }
|
57
|
+
if delta != all
|
58
|
+
@all = delta
|
59
|
+
save
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
53
63
|
def find(digest)
|
54
64
|
all.find { |n| n.id == digest }
|
55
65
|
end
|
data/lib/ama_layout/version.rb
CHANGED
@@ -0,0 +1,13 @@
|
|
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
|
@@ -7,8 +7,8 @@ describe AmaLayout::NavigationDecorator do
|
|
7
7
|
let(:membership_site) { "http://membership.waffles.ca" }
|
8
8
|
let(:driveredonline_site) { "http://driveredonline.waffles.ca" }
|
9
9
|
let(:registries_site) { "http://registries.waffles.ca" }
|
10
|
-
let(:automotive_site) { "http://automotive.waffles.ca"}
|
11
|
-
let(:travel_site) { "http://travel.waffles.ca"}
|
10
|
+
let(:automotive_site) { "http://automotive.waffles.ca" }
|
11
|
+
let(:travel_site) { "http://travel.waffles.ca" }
|
12
12
|
|
13
13
|
before(:each) do
|
14
14
|
allow(Rails.configuration).to receive(:gatekeeper_site).and_return(gatekeeper_site)
|
@@ -129,4 +129,123 @@ describe AmaLayout::NavigationDecorator do
|
|
129
129
|
expect(navigation_presenter.account_toggle).to eq "render"
|
130
130
|
end
|
131
131
|
end
|
132
|
+
|
133
|
+
context 'notification center' do
|
134
|
+
let(:store) do
|
135
|
+
AmaLayout::Notifications::RedisStore.new(
|
136
|
+
db: 4,
|
137
|
+
namespace: 'test_notifications',
|
138
|
+
host: 'localhost'
|
139
|
+
)
|
140
|
+
end
|
141
|
+
let(:notification_set) { AmaLayout::NotificationSet.new(store, 1) }
|
142
|
+
let(:user) { OpenStruct.new(navigation: 'member', notifications: notification_set) }
|
143
|
+
let(:navigation) { FactoryGirl.build :navigation, user: user }
|
144
|
+
subject { described_class.new(navigation) }
|
145
|
+
|
146
|
+
around(:each) do |example|
|
147
|
+
Timecop.freeze(Time.zone.local(2017, 6, 19)) do
|
148
|
+
store.clear
|
149
|
+
example.run
|
150
|
+
store.clear
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe '#notifications' do
|
155
|
+
it 'renders the content to the page' do
|
156
|
+
expect(subject.h).to receive(:render).once.and_return true
|
157
|
+
expect(subject.notifications).to be true
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe '#notification_badge' do
|
162
|
+
context 'with 1 active notification' do
|
163
|
+
before(:each) do
|
164
|
+
user.notifications.create(
|
165
|
+
type: :warning,
|
166
|
+
header: 'test',
|
167
|
+
content: 'test'
|
168
|
+
)
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'returns a div with the count of active notifications' do
|
172
|
+
expect(subject.notification_badge).to include('div')
|
173
|
+
expect(subject.notification_badge).to include('1')
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'with only inactive notifications' do
|
178
|
+
before(:each) do
|
179
|
+
user.notifications.create(
|
180
|
+
type: :warning,
|
181
|
+
header: 'test',
|
182
|
+
content: 'test'
|
183
|
+
)
|
184
|
+
user.notifications.first.dismiss!
|
185
|
+
user.notifications.save
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'does not return the badge markup' do
|
189
|
+
expect(subject.notification_badge).to be nil
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
context 'with only active and inactive notifications' do
|
194
|
+
before(:each) do
|
195
|
+
user.notifications.create(
|
196
|
+
type: :warning,
|
197
|
+
header: 'test',
|
198
|
+
content: 'test'
|
199
|
+
)
|
200
|
+
2.times do |i|
|
201
|
+
user.notifications.create(
|
202
|
+
type: :notice,
|
203
|
+
header: i,
|
204
|
+
content: i
|
205
|
+
)
|
206
|
+
end
|
207
|
+
user.notifications.first.dismiss!
|
208
|
+
user.notifications.save
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'returns a div with the count of active notifications' do
|
212
|
+
expect(subject.notification_badge).to include('div')
|
213
|
+
expect(subject.notification_badge).to include('2')
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe '#notification_sidebar' do
|
219
|
+
it 'renders content to the page' do
|
220
|
+
expect(subject.h).to receive(:render).once.and_return true
|
221
|
+
expect(subject.notification_sidebar).to be true
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe '#notifications_heading' do
|
226
|
+
context 'when notifications are present' do
|
227
|
+
before(:each) do
|
228
|
+
user.notifications.create(
|
229
|
+
type: :warning,
|
230
|
+
header: 'test',
|
231
|
+
content: 'test'
|
232
|
+
)
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'returns the correct heading' do
|
236
|
+
expect(subject.notifications_heading).to include('Most Recent Notifications')
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
context 'when notifications are not present' do
|
241
|
+
it 'returns the correct heading' do
|
242
|
+
expect(subject.notifications_heading).to include('No Recent Notifications')
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'italicizes the message' do
|
246
|
+
expect(subject.notifications_heading).to include('italic')
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
132
251
|
end
|
@@ -0,0 +1,57 @@
|
|
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
|
@@ -0,0 +1,10 @@
|
|
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
|
@@ -7,12 +7,24 @@ describe AmaLayout::NotificationSet do
|
|
7
7
|
)
|
8
8
|
end
|
9
9
|
let(:key) { 1 }
|
10
|
-
let(:duration) { AmaLayout::Notification::DEFAULT_LIFESPAN
|
10
|
+
let(:duration) { AmaLayout::Notification::DEFAULT_LIFESPAN }
|
11
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
|
12
24
|
let(:json) do
|
13
25
|
<<-JSON
|
14
26
|
{
|
15
|
-
"
|
27
|
+
"#{digest}": {
|
16
28
|
"type": "notice",
|
17
29
|
"header": "test",
|
18
30
|
"content": "test",
|
@@ -50,7 +62,7 @@ describe AmaLayout::NotificationSet do
|
|
50
62
|
end
|
51
63
|
end
|
52
64
|
|
53
|
-
describe '#
|
65
|
+
describe '#initialize' do
|
54
66
|
context 'with valid JSON in data store' do
|
55
67
|
before(:each) do
|
56
68
|
store.set(store_key, notification)
|
@@ -133,7 +145,7 @@ describe AmaLayout::NotificationSet do
|
|
133
145
|
end
|
134
146
|
|
135
147
|
it 'does not overwrite the notification' do
|
136
|
-
expect(subject).to be_empty
|
148
|
+
expect(subject.active).to be_empty
|
137
149
|
end
|
138
150
|
|
139
151
|
it 'still has the dismissed notification in the data store' do
|
@@ -144,6 +156,38 @@ describe AmaLayout::NotificationSet do
|
|
144
156
|
end
|
145
157
|
end
|
146
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
|
+
|
147
191
|
describe '#destroy' do
|
148
192
|
context 'when data is removed' do
|
149
193
|
before(:each) do
|
@@ -200,7 +244,7 @@ describe AmaLayout::NotificationSet do
|
|
200
244
|
expect(subject.last.active?).to be true
|
201
245
|
subject.last.dismiss!
|
202
246
|
subject.save
|
203
|
-
expect(subject).to be_empty
|
247
|
+
expect(subject.active).to be_empty
|
204
248
|
end
|
205
249
|
|
206
250
|
it 'returns the NotificationSet instance' do
|
@@ -9,7 +9,7 @@ describe AmaLayout::Notifications do
|
|
9
9
|
let(:json) do
|
10
10
|
<<-JSON
|
11
11
|
{
|
12
|
-
"
|
12
|
+
"02ac263cea5660e9f9020cb46e93772ed7755f2a60c40ad8961d2a15c1f99e6f": {
|
13
13
|
"type": "notice",
|
14
14
|
"header": "test",
|
15
15
|
"content": "test",
|
@@ -1,2 +1,23 @@
|
|
1
1
|
class ApplicationController < ActionController::Base
|
2
|
+
class NotificationsStub
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def each
|
6
|
+
[OpenStruct.new(dismiss!: true)].each do |element|
|
7
|
+
yield element
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def save
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def require_login
|
17
|
+
@current_user = OpenStruct.new(notifications: NotificationsStub.new)
|
18
|
+
end
|
19
|
+
|
20
|
+
def current_user
|
21
|
+
@current_user
|
22
|
+
end
|
2
23
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -18,12 +18,6 @@ ActionView::TestCase::TestController.instance_eval do
|
|
18
18
|
helper Rails.application.routes.url_helpers
|
19
19
|
end
|
20
20
|
|
21
|
-
ActionView::TestCase::TestController.class_eval do
|
22
|
-
def _routes
|
23
|
-
Rails.application.routes
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
21
|
Draper::ViewContext.test_strategy :fast
|
28
22
|
|
29
23
|
RSpec.configure do |config|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ama_layout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael van den Beuken
|
@@ -18,7 +18,7 @@ authors:
|
|
18
18
|
autorequire:
|
19
19
|
bindir: bin
|
20
20
|
cert_chain: []
|
21
|
-
date: 2017-06
|
21
|
+
date: 2017-07-06 00:00:00.000000000 Z
|
22
22
|
dependencies:
|
23
23
|
- !ruby/object:Gem::Dependency
|
24
24
|
name: foundation-rails
|
@@ -271,8 +271,10 @@ files:
|
|
271
271
|
- app/assets/javascripts/ama_layout/mobile/mobile_menu.coffee
|
272
272
|
- app/assets/javascripts/ama_layout/mobile/ready.coffee
|
273
273
|
- app/assets/javascripts/ama_layout/mobile/tablesaw.stackonly.js
|
274
|
+
- app/assets/javascripts/ama_layout/notifications.coffee
|
274
275
|
- app/assets/javascripts/ama_layout/real_date_picker.coffee
|
275
276
|
- app/config/locales/en.yml
|
277
|
+
- app/controllers/ama_layout/api/v1/notifications_controller.rb
|
276
278
|
- app/helpers/ama_layout_breadcrumb_helper.rb
|
277
279
|
- app/helpers/ama_layout_content_helper.rb
|
278
280
|
- app/helpers/ama_layout_path_helper.rb
|
@@ -286,6 +288,9 @@ files:
|
|
286
288
|
- app/views/ama_layout/_main_top_nav_item.html.erb
|
287
289
|
- app/views/ama_layout/_notice.html.erb
|
288
290
|
- app/views/ama_layout/_notices.html.erb
|
291
|
+
- app/views/ama_layout/_notification.html.erb
|
292
|
+
- app/views/ama_layout/_notification_sidebar.html.erb
|
293
|
+
- app/views/ama_layout/_notifications.html.erb
|
289
294
|
- app/views/ama_layout/_sidebar.html.erb
|
290
295
|
- app/views/ama_layout/_siteheader.html.erb
|
291
296
|
- app/views/ama_layout/_sub_nav.html.erb
|
@@ -295,12 +300,14 @@ files:
|
|
295
300
|
- app/views/ama_layout/_top_sub_nav.html.erb
|
296
301
|
- app/views/ama_layout/_top_sub_nav_item.html.erb
|
297
302
|
- app/views/application/_account_toggle.html.erb
|
303
|
+
- config/routes.rb
|
298
304
|
- lib/ama_layout.rb
|
299
305
|
- lib/ama_layout/breadcrumb_builder.rb
|
300
306
|
- lib/ama_layout/controllers/action_controller.rb
|
301
307
|
- lib/ama_layout/decorators/moneris_decorator.rb
|
302
308
|
- lib/ama_layout/decorators/navigation_decorator.rb
|
303
309
|
- lib/ama_layout/decorators/navigation_item_decorator.rb
|
310
|
+
- lib/ama_layout/decorators/notification_decorator.rb
|
304
311
|
- lib/ama_layout/moneris.rb
|
305
312
|
- lib/ama_layout/moneris/textbox.txt
|
306
313
|
- lib/ama_layout/navigation.rb
|
@@ -308,16 +315,19 @@ files:
|
|
308
315
|
- lib/ama_layout/navigation_helper.rb
|
309
316
|
- lib/ama_layout/navigation_item.rb
|
310
317
|
- lib/ama_layout/notification.rb
|
318
|
+
- lib/ama_layout/notification_scrubber.rb
|
311
319
|
- lib/ama_layout/notification_set.rb
|
312
320
|
- lib/ama_layout/notifications.rb
|
313
321
|
- lib/ama_layout/notifications/abstract_store.rb
|
314
322
|
- lib/ama_layout/notifications/redis_store.rb
|
315
323
|
- lib/ama_layout/version.rb
|
316
324
|
- spec/ama_layout/breadcrumb_builder_spec.rb
|
325
|
+
- spec/ama_layout/controllers/ama_layout/api/v1/notifications_controller_spec.rb
|
317
326
|
- spec/ama_layout/controllers/pages_controller_spec.rb
|
318
327
|
- spec/ama_layout/decorators/moneris_decorator_spec.rb
|
319
328
|
- spec/ama_layout/decorators/navigation_decorator_spec.rb
|
320
329
|
- spec/ama_layout/decorators/navigation_item_decorator_spec.rb
|
330
|
+
- spec/ama_layout/decorators/notification_decorator_spec.rb
|
321
331
|
- spec/ama_layout/fixtures/navigation.yml
|
322
332
|
- spec/ama_layout/fixtures/real_date_picker.html
|
323
333
|
- spec/ama_layout/javascripts/real_date_picker_spec.coffee
|
@@ -325,6 +335,7 @@ files:
|
|
325
335
|
- spec/ama_layout/navigation_helper_spec.rb
|
326
336
|
- spec/ama_layout/navigation_item_spec.rb
|
327
337
|
- spec/ama_layout/navigation_spec.rb
|
338
|
+
- spec/ama_layout/notification_scrubber_spec.rb
|
328
339
|
- spec/ama_layout/notification_set_spec.rb
|
329
340
|
- spec/ama_layout/notification_spec.rb
|
330
341
|
- spec/ama_layout/notifications/abstract_store_spec.rb
|
@@ -371,10 +382,12 @@ specification_version: 4
|
|
371
382
|
summary: ".ama.ab.ca site layouts"
|
372
383
|
test_files:
|
373
384
|
- spec/ama_layout/breadcrumb_builder_spec.rb
|
385
|
+
- spec/ama_layout/controllers/ama_layout/api/v1/notifications_controller_spec.rb
|
374
386
|
- spec/ama_layout/controllers/pages_controller_spec.rb
|
375
387
|
- spec/ama_layout/decorators/moneris_decorator_spec.rb
|
376
388
|
- spec/ama_layout/decorators/navigation_decorator_spec.rb
|
377
389
|
- spec/ama_layout/decorators/navigation_item_decorator_spec.rb
|
390
|
+
- spec/ama_layout/decorators/notification_decorator_spec.rb
|
378
391
|
- spec/ama_layout/fixtures/navigation.yml
|
379
392
|
- spec/ama_layout/fixtures/real_date_picker.html
|
380
393
|
- spec/ama_layout/javascripts/real_date_picker_spec.coffee
|
@@ -382,6 +395,7 @@ test_files:
|
|
382
395
|
- spec/ama_layout/navigation_helper_spec.rb
|
383
396
|
- spec/ama_layout/navigation_item_spec.rb
|
384
397
|
- spec/ama_layout/navigation_spec.rb
|
398
|
+
- spec/ama_layout/notification_scrubber_spec.rb
|
385
399
|
- spec/ama_layout/notification_set_spec.rb
|
386
400
|
- spec/ama_layout/notification_spec.rb
|
387
401
|
- spec/ama_layout/notifications/abstract_store_spec.rb
|