Skip to content

Commit d55bddd

Browse files
authored
Merge pull request #250 from ncbo/cloudflare-analytics/369
Add Cloudflare Analytics notification and refactor template rendering
2 parents 6752f53 + 3249a03 commit d55bddd

4 files changed

Lines changed: 160 additions & 54 deletions

File tree

lib/ontologies_linked_data/config/config.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def config(&block)
3333
# Java/JVM options
3434
@settings.java_max_heap_size ||= '10240M'
3535

36-
@settings.ui_name ||= 'Bioportal'
36+
@settings.ui_name ||= 'BioPortal'
3737
@settings.ui_host ||= 'bioportal.bioontology.org'
3838
@settings.replace_url_prefix ||= false
3939
@settings.id_url_prefix ||= DEFAULT_PREFIX

lib/ontologies_linked_data/utils/notifications.rb

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,16 +106,41 @@ def self.reset_password(user, token)
106106

107107
def self.obofoundry_sync(missing_onts, obsolete_onts)
108108
ui_name = LinkedData.settings.ui_name
109+
subject = "[#{ui_name}] OBO Foundry synchronization report"
110+
recipients = Notifier.ontoportal_admin_emails
111+
body = render_template('obofoundry_sync.erb', {
112+
ui_name: ui_name,
113+
missing_onts: missing_onts,
114+
obsolete_onts: obsolete_onts,
115+
})
116+
117+
Notifier.notify_mails_grouped(subject, body, recipients)
118+
end
119+
120+
def self.cloudflare_analytics(result_data)
121+
ui_name = LinkedData.settings.ui_name
122+
subject = "[#{ui_name}] Cloudflare Analytics daily collection result: #{result_data[:status]}"
123+
recipients = Notifier.ontoportal_admin_emails
124+
body = render_template('cloudflare_analytics.erb', {
125+
result_data: result_data
126+
})
127+
128+
Notifier.notify_mails_grouped(subject, body, recipients)
129+
end
130+
131+
private
132+
133+
def self.render_template(template_name, locals = {})
109134
gem_path = Gem.loaded_specs['ontologies_linked_data'].full_gem_path
110-
template = File.read(File.join(gem_path, 'views/emails/obofoundry_sync.erb'))
135+
template_path = File.join(gem_path, 'views', 'emails', template_name)
136+
template = File.read(template_path)
111137

112138
b = binding
113-
b.local_variable_set(:ui_name, ui_name)
114-
b.local_variable_set(:missing_onts, missing_onts)
115-
b.local_variable_set(:obsolete_onts, obsolete_onts)
116-
body = ERB.new(template).result(b)
139+
locals.each { |k, v| b.local_variable_set(k, v) }
117140

118-
Notifier.notify_ontoportal_admins("[#{ui_name}] OBO Foundry synchronization report", body)
141+
ERB.new(template).result(b)
142+
rescue Errno::ENOENT => e
143+
raise "Template not found: #{template_path}"
119144
end
120145

121146
NEW_NOTE = <<EOS

test/util/test_notifications.rb

Lines changed: 112 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,43 @@
1-
require_relative "../test_case"
2-
3-
require "email_spec"
4-
require "logger"
1+
require_relative '../test_case'
52

3+
require 'email_spec'
4+
require 'logger'
5+
require 'mocha/minitest'
66

77
class TestNotifications < LinkedData::TestCase
88
include EmailSpec::Helpers
99

1010
def self.before_suite
11-
@@notifications_enabled = LinkedData.settings.enable_notifications
12-
@@disable_override = LinkedData.settings.email_disable_override
13-
@@old_support_mails = LinkedData.settings.ontoportal_admin_emails
14-
if @@old_support_mails.nil? || @@old_support_mails.empty?
15-
LinkedData.settings.ontoportal_admin_emails = ["ontoportal-support@mail.com"]
16-
end
11+
# Store original settings
12+
@original_settings = {
13+
notifications_enabled: LinkedData.settings.enable_notifications,
14+
disable_override: LinkedData.settings.email_disable_override,
15+
admin_emails: LinkedData.settings.ontoportal_admin_emails
16+
}
17+
1718
LinkedData.settings.email_disable_override = true
1819
LinkedData.settings.enable_notifications = true
20+
LinkedData.settings.ontoportal_admin_emails = ['ontoportal-support@mail.com']
21+
1922
@@ui_name = LinkedData.settings.ui_name
2023
@@support_mails = LinkedData.settings.ontoportal_admin_emails
21-
@@ont = LinkedData::SampleData::Ontology.create_ontologies_and_submissions(ont_count: 1, submission_count: 1)[2].first
24+
@@ont = LinkedData::SampleData::Ontology.create_ontologies_and_submissions(ont_count: 1,
25+
submission_count: 1)[2].first
2226
@@ont.bring_remaining
2327
@@user = @@ont.administeredBy.first
24-
@@subscription = self.new("before_suite")._subscription(@@ont)
28+
@@subscription = new('before_suite')._subscription(@@ont)
2529
@@user.bring_remaining
2630
@@user.subscription = [@@subscription]
2731
@@user.save
2832
end
2933

3034
def self.after_suite
31-
LinkedData.settings.enable_notifications = @@notifications_enabled
32-
LinkedData.settings.email_disable_override = @@disable_override
33-
LinkedData.settings.ontoportal_admin_emails = @@old_support_mails
34-
@@ont.delete if defined?(@@ont)
35-
@@subscription.delete if defined?(@@subscription)
36-
@@user.delete if defined?(@@user)
35+
# Restore original settings
36+
LinkedData.settings.enable_notifications = @original_settings[:notifications_enabled]
37+
LinkedData.settings.email_disable_override = @original_settings[:disable_override]
38+
LinkedData.settings.ontoportal_admin_emails = @original_settings[:admin_emails]
39+
40+
[@@ont, @@subscription, @@user].each(&:delete)
3741
end
3842

3943
def setup
@@ -44,14 +48,14 @@ def setup
4448
def _subscription(ont)
4549
subscription = LinkedData::Models::Users::Subscription.new
4650
subscription.ontology = ont
47-
subscription.notification_type = LinkedData::Models::Users::NotificationType.find("ALL").first
51+
subscription.notification_type = LinkedData::Models::Users::NotificationType.find('ALL').first
4852
subscription.save
4953
end
5054

5155
def test_send_notification
52-
recipients = ["test@example.org"]
53-
subject = "Test subject"
54-
body = "My test body"
56+
recipients = ['test@example.org']
57+
subject = 'Test subject'
58+
body = 'My test body'
5559

5660
# Email recipient address will be overridden
5761
LinkedData.settings.email_disable_override = false
@@ -60,21 +64,17 @@ def test_send_notification
6064

6165
# Disable override
6266
LinkedData.settings.email_disable_override = true
63-
LinkedData::Utils::Notifier.notify({
64-
recipients: recipients,
65-
subject: subject,
66-
body: body
67-
})
67+
LinkedData::Utils::Notifier.notify({ recipients: recipients, subject: subject, body: body })
6868
assert_equal recipients, last_email_sent.to
6969
assert_equal [LinkedData.settings.email_sender], last_email_sent.from
7070
assert_equal last_email_sent.body.raw_source, body
7171
assert_equal last_email_sent.subject, subject
7272
end
7373

7474
def test_new_note_notification
75-
recipients = ["test@example.org"]
76-
subject = "Test note subject"
77-
body = "Test note body"
75+
recipients = ['test@example.org']
76+
subject = 'Test note subject'
77+
body = 'Test note body'
7878
note = LinkedData::Models::Note.new
7979
note.creator = @@user
8080
note.subject = subject
@@ -84,11 +84,11 @@ def test_new_note_notification
8484
assert_match "[#{@@ui_name} Notes]", last_email_sent.subject
8585
assert_equal [@@user.email], last_email_sent.to
8686
ensure
87-
note.delete if note
87+
note&.delete
8888
end
8989

9090
def test_processing_complete_notification
91-
options = { ont_count: 1, submission_count: 2, acronym: "NOTIFY" }
91+
options = { ont_count: 1, submission_count: 2, acronym: 'NOTIFY' }
9292
ont = LinkedData::SampleData::Ontology.create_ontologies_and_submissions(options)[2].first
9393
subscription = _subscription(ont)
9494
@@user.subscription = @@user.subscription.dup << subscription
@@ -101,50 +101,52 @@ def test_processing_complete_notification
101101

102102
first_user = subscription.user.first
103103
first_user.bring :email
104-
assert_match "Parsing Success", all_emails.first.subject
104+
assert_match 'Parsing Success', all_emails.first.subject
105105
assert_equal [first_user.email], all_emails.first.to
106106

107-
assert_match ("Parsing Success"), all_emails.last.subject
107+
assert_match 'Parsing Success', all_emails.last.subject
108108
assert_equal @@support_mails.uniq.sort, all_emails[1].to.sort
109109
assert_equal admin_mails.uniq.sort, all_emails.last.to.sort
110110

111-
112111
reset_mailer
113-
sub = ont.submissions.sort_by { |s| s.id}.first
114-
sub.process_submission(Logger.new(TestLogFile.new), {archive: true})
112+
sub = ont.submissions.sort_by { |s| s.id }.first
113+
sub.process_submission(Logger.new(TestLogFile.new), { archive: true })
115114

116115
assert_empty all_emails
117116
ensure
118-
ont.delete if ont
119-
subscription.delete if subscription
117+
ont&.delete
118+
subscription&.delete
120119
end
121120

122121
def test_disable_administrative_notifications
123122
LinkedData.settings.enable_administrative_notifications = false
124-
options = { ont_count: 1, submission_count: 1, acronym: "DONTNOTIFY" }
123+
options = { ont_count: 1, submission_count: 1, acronym: 'DONTNOTIFY' }
125124
ont = LinkedData::SampleData::Ontology.create_ontologies_and_submissions(options)[2].first
126125
ont.latest_submission(status: :any).process_submission(Logger.new(TestLogFile.new))
127126
admin_mails = LinkedData::Utils::Notifier.ontology_admin_emails(ont)
128127
assert_equal 1, all_emails.size, 'number of send emails'
129128

130129
refute_match @@support_mails, last_email_sent.to.sort
131130
assert_equal admin_mails, last_email_sent.to.sort
132-
assert_match ("Parsing Success"), all_emails.last.subject
131+
assert_match 'Parsing Success', all_emails.last.subject
133132
LinkedData.settings.enable_administrative_notifications = true
134133
ensure
135-
ont.delete if ont
134+
ont&.delete
136135
end
137136

138137
def test_remote_ontology_pull_notification
139-
recipients = ["test@example.org"]
140-
ont_count, acronyms, ontologies = LinkedData::SampleData::Ontology.create_ontologies_and_submissions(ont_count: 1, submission_count: 1, process_submission: false)
138+
recipients = ['test@example.org']
139+
_ont_count, _acronyms, ontologies = LinkedData::SampleData::Ontology.create_ontologies_and_submissions(
140+
ont_count: 1, submission_count: 1, process_submission: false
141+
)
141142

142-
ont = LinkedData::Models::Ontology.find(ontologies[0].id).include(:acronym, :administeredBy, :name, :submissions).first
143+
ont = LinkedData::Models::Ontology.find(ontologies[0].id)
144+
.include(:acronym, :administeredBy, :name, :submissions).first
143145
ont_admins = Array.new(3) { LinkedData::Models::User.new }
144146
ont_admins.each_with_index do |user, i|
145147
user.username = "Test User #{i}"
146148
user.email = "tester_#{i}@example.org"
147-
user.password = "password"
149+
user.password = 'password'
148150
user.save
149151
assert user.valid?, user.errors
150152
end
@@ -164,7 +166,70 @@ def test_remote_ontology_pull_notification
164166
assert_equal admin_mails, last_email_sent.to.sort
165167
ensure
166168
ont_admins.each do |user|
167-
user.delete if user
169+
user&.delete
170+
end
171+
end
172+
173+
def test_cloudflare_analytics_success_notification
174+
start_time = Time.now - 3600
175+
end_time = Time.now
176+
result_data = {
177+
start_time: start_time,
178+
end_time: end_time,
179+
duration: 3600,
180+
status: 'success',
181+
error: nil
182+
}
183+
184+
LinkedData::Utils::Notifications.cloudflare_analytics(result_data)
185+
186+
assert_equal 1, all_emails.size
187+
assert_match 'success', last_email_sent.subject
188+
assert_includes last_email_sent.body.raw_source, 'completed successfully'
189+
assert_includes last_email_sent.body.raw_source, start_time.to_s
190+
end
191+
192+
def test_cloudflare_analytics_failure_notification
193+
start_time = Time.now - 3600
194+
end_time = Time.now
195+
result_data = {
196+
start_time: start_time,
197+
end_time: end_time,
198+
duration: 3600,
199+
status: 'error',
200+
error: 'Connection timeout'
201+
}
202+
203+
LinkedData::Utils::Notifications.cloudflare_analytics(result_data)
204+
205+
assert_equal 1, all_emails.size
206+
assert_match 'error', last_email_sent.subject
207+
assert_includes last_email_sent.body.raw_source, 'Connection timeout'
208+
end
209+
210+
def test_render_template
211+
gem_path = '/fake/gem/path'
212+
Gem.loaded_specs.stubs(:[]).with('ontologies_linked_data').returns(
213+
stub(full_gem_path: gem_path)
214+
)
215+
216+
template_content = 'Hello <%= name %>!'
217+
File.expects(:read).with("#{gem_path}/views/emails/test.erb").returns(template_content)
218+
219+
result = LinkedData::Utils::Notifications.render_template('test.erb', { name: 'World' })
220+
assert_equal 'Hello World!', result
221+
end
222+
223+
def test_render_template_file_not_found
224+
gem_path = '/fake/gem/path'
225+
Gem.loaded_specs.stubs(:[]).with('ontologies_linked_data').returns(
226+
stub(full_gem_path: gem_path)
227+
)
228+
229+
File.expects(:read).raises(Errno::ENOENT)
230+
231+
assert_raises(RuntimeError, 'Template not found') do
232+
LinkedData::Utils::Notifications.render_template('nonexistent.erb', {})
168233
end
169234
end
170235

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<% if result_data[:status] == 'success' %>
2+
Cloudflare Analytics job completed successfully<br><br>
3+
4+
Start time: <%= result_data[:start_time].utc %><br>
5+
End time: <%= result_data[:end_time].utc %><br>
6+
Duration: <%= result_data[:duration] %> seconds<br><br>
7+
<% else %>
8+
<span style="font-weight: bold; color: red;">Cloudflare Analytics job failed!</span><br><br>
9+
10+
Start time: <%= result_data[:start_time].utc %><br>
11+
End time: <%= result_data[:end_time].utc %><br>
12+
Duration: <%= result_data[:duration] %> seconds<br><br>
13+
14+
Error:
15+
<pre><%= result_data[:error] %></pre><br><br>
16+
<% end %>

0 commit comments

Comments
 (0)