diff --git a/.travis.yml b/.travis.yml
index a690b21..6191048 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,9 +13,12 @@ addons:
before_install:
- cp config/database.example.yml config/database.yml
- - cp config/chexpire.test.yml config/chexpire.yml
- cp config/secrets.example.yml config/secrets.yml
+ # Test configuration loaded from chexpire.defaults.yml,
+ # but chexpire.yml file is required
+ - touch config/chexpire.yml
+
install:
- bundle install
- yarn install
diff --git a/Gemfile b/Gemfile
index e3665cb..14530c2 100644
--- a/Gemfile
+++ b/Gemfile
@@ -38,6 +38,7 @@ gem 'bcrypt', '~> 3.1.7'
gem 'open4'
gem 'naught'
+gem 'hashie'
gem 'whenever', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index 5e091d7..ff2fd77 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -134,6 +134,7 @@ GEM
has_scope (0.7.2)
actionpack (>= 4.1)
activesupport (>= 4.1)
+ hashie (3.5.7)
i18n (1.0.1)
concurrent-ruby (~> 1.0)
io-like (0.3.0)
@@ -354,6 +355,7 @@ DEPENDENCIES
guard
guard-minitest
has_scope
+ hashie
jbuilder (~> 2.5)
kaminari
launchy
diff --git a/INSTALL.md b/INSTALL.md
index 7c6cf3d..afe5a26 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -45,11 +45,13 @@ To use elliptic curve SSH keys, we need to have `libsodium` and its headers.
## Rails configuration
-After cloning this repository, you have to create and edit a few files from example files, for your local development configuration :
+After cloning this repository, you have to create and edit a few files from example or defaults files, for your local development configuration :
- `config/database.yml`
-- `config/chexpire.yml`
- `config/secrets.yml`
+- `config/chexpire.yml` : set at least the `mailer_default_from` and `host` variables. See other configuration overridable in `config/chexpire.defaults.yml`.
+
+Theses files will be ignored by git.
## Database
diff --git a/README.md b/README.md
index 5800ae6..7bd1609 100644
--- a/README.md
+++ b/README.md
@@ -62,5 +62,5 @@ Finally, you have to write the way the checks will be notified to theirs users.
- expires_soon
- recurrent_failures
-First, add your checks kinds and these notifications definitions in the base class for notifier: `app/services/notifier/base.rb` : in the notify method, for your new check kind, a specific method will be called in each notifier. For example, in the email channel, a specific mailer action is called for each couple (check kin, notification kind).
+First, add your checks kinds and these notifications definitions in the base class for notifier: `app/services/notifier/channels/base.rb` : in the notify method, for your new check kind, a specific method will be called in each notifier. For example, in the email channel, a specific mailer action is called for each couple (check kin, notification kind).
Then, in each notifier class, implements the details of this method. If you want to ignore a notification for a given channel, simply write the method and do nothing.
diff --git a/app/controllers/checks_controller.rb b/app/controllers/checks_controller.rb
index d252411..cc12afd 100644
--- a/app/controllers/checks_controller.rb
+++ b/app/controllers/checks_controller.rb
@@ -6,7 +6,9 @@ class ChecksController < ApplicationController
has_scope :kind
has_scope :by_domain
- has_scope :recurrent_failures, type: :boolean
+ has_scope :recurrent_failures, type: :boolean do |_controller, scope, _value|
+ scope.consecutive_failures(Rails.configuration.chexpire.interface.consecutive_failures_as_error)
+ end
def index
@checks = apply_scopes(policy_scope(Check)).order(Hash[*current_sort]).page(params[:page])
diff --git a/app/helpers/checks_helper.rb b/app/helpers/checks_helper.rb
index f779644..beeea2e 100644
--- a/app/helpers/checks_helper.rb
+++ b/app/helpers/checks_helper.rb
@@ -29,7 +29,12 @@ module ChecksHelper
end
end
- def check_in_error(check)
+ def check_in_error?(check)
+ check.consecutive_failures >=
+ Rails.configuration.chexpire.interface.consecutive_failures_as_error
+ end
+
+ def check_error(check)
content_tag(
:span,
Octicons::Octicon.new("alert", class: "ml-1").to_svg.html_safe,
diff --git a/app/mailers/notifications_mailer.rb b/app/mailers/notifications_mailer.rb
index 31a4677..8f79612 100644
--- a/app/mailers/notifications_mailer.rb
+++ b/app/mailers/notifications_mailer.rb
@@ -1,34 +1,38 @@
class NotificationsMailer < ApplicationMailer
helper :application
- before_action do
+ before_action except: :recurrent_failures do
@notification = params.fetch(:notification)
@check = @notification.check
end
- default to: -> { @notification.recipient }
-
def domain_expires_soon
@expire_in_days = Integer(@check.domain_expires_at.to_date - Date.today)
- subject = t(".subject", domain: @check.domain, count: @expire_in_days)
- mail subject: subject
- end
-
- def domain_recurrent_failures
- subject = t(".subject", domain: @check.domain)
- mail subject: subject
+ I18n.with_locale params&.fetch(:locale) { @check.user.locale } do
+ subject = t(".subject", domain: @check.domain, count: @expire_in_days)
+ mail subject: subject, to: @notification.recipient
+ end
end
def ssl_expires_soon
@expire_in_days = Integer(@check.domain_expires_at.to_date - Date.today)
- subject = t(".subject", domain: @check.domain, count: @expire_in_days)
- mail subject: subject
+ I18n.with_locale params&.fetch(:locale) { @check.user.locale } do
+ subject = t(".subject", domain: @check.domain, count: @expire_in_days)
+ mail subject: subject, to: @notification.recipient
+ end
end
- def ssl_recurrent_failures
- subject = t(".subject", domain: @check.domain)
- mail subject: subject
+ def recurrent_failures(user, checks)
+ @checks = checks
+
+ # params generally not set, except for preview mailer
+ params_locale = (params[:locale] if params.present?)
+
+ I18n.with_locale params_locale || user.locale do
+ subject = t(".subject", count: checks.count, domain: checks.first.domain)
+ mail subject: subject, to: user.email
+ end
end
end
diff --git a/app/models/check.rb b/app/models/check.rb
index 296f57f..8e1cb6f 100644
--- a/app/models/check.rb
+++ b/app/models/check.rb
@@ -2,20 +2,21 @@
#
# Table name: checks
#
-# id :bigint(8) not null, primary key
-# active :boolean default(TRUE), not null
-# comment :string(255)
-# domain :string(255) not null
-# domain_created_at :datetime
-# domain_expires_at :datetime
-# domain_updated_at :datetime
-# kind :integer not null
-# last_run_at :datetime
-# last_success_at :datetime
-# vendor :string(255)
-# created_at :datetime not null
-# updated_at :datetime not null
-# user_id :bigint(8)
+# id :bigint(8) not null, primary key
+# active :boolean default(TRUE), not null
+# comment :string(255)
+# consecutive_failures :integer default(0), not null
+# domain :string(255) not null
+# domain_created_at :datetime
+# domain_expires_at :datetime
+# domain_updated_at :datetime
+# kind :integer not null
+# last_run_at :datetime
+# last_success_at :datetime
+# vendor :string(255)
+# created_at :datetime not null
+# updated_at :datetime not null
+# user_id :bigint(8)
#
# Indexes
#
@@ -27,8 +28,6 @@
#
class Check < ApplicationRecord
- ERROR_DELAY_DAYS = 3
-
belongs_to :user
has_many :logs, class_name: "CheckLog", dependent: :destroy
has_many :notifications, validate: true, dependent: :destroy
@@ -51,6 +50,7 @@ class Check < ApplicationRecord
validates :comment, length: { maximum: 255 }
validates :vendor, length: { maximum: 255 }
+ before_save :reset_consecutive_failures
after_update :reset_notifications
after_save :enqueue_sync
@@ -62,30 +62,25 @@ class Check < ApplicationRecord
scope :kind, ->(kind) { where(kind: kind) }
scope :by_domain, ->(domain) { where("domain LIKE ?", "%#{domain}%") }
- scope :recurrent_failures, -> {
- interval = "INTERVAL #{ERROR_DELAY_DAYS} DAY"
- where("last_run_at IS NOT NULL AND created_at <= DATE_SUB(NOW(), #{interval})")
- .where("last_success_at IS NULL OR last_success_at <= DATE_SUB(last_run_at, #{interval})")
+ scope :consecutive_failures, ->(consecutive) {
+ where("consecutive_failures >= ?", consecutive)
}
def self.default_sort
[:domain_expires_at, :asc]
end
- def in_error?
- return false if created_at > ERROR_DELAY_DAYS.days.ago
- return false if last_run_at.nil?
- return true if last_success_at.nil?
-
- last_success_at < ERROR_DELAY_DAYS.days.ago
- end
-
def days_from_last_success
return unless last_success_at.present?
(Date.today - last_success_at.to_date).to_i
end
+ def increment_consecutive_failures!
+ self.consecutive_failures += 1
+ save!
+ end
+
private
def domain_created_at_past
@@ -108,4 +103,11 @@ class Check < ApplicationRecord
notifications.each(&:reset!)
end
+
+ def reset_consecutive_failures
+ return unless last_success_at_changed?
+ return if consecutive_failures_changed?
+
+ self.consecutive_failures = 0
+ end
end
diff --git a/app/services/check_logger.rb b/app/services/check_logger.rb
index e04b077..5fe256a 100644
--- a/app/services/check_logger.rb
+++ b/app/services/check_logger.rb
@@ -1,8 +1,11 @@
class CheckLogger
+ attr_reader :check
attr_reader :check_log
def initialize(check)
+ @check = check
@check_log = CheckLog.create!(check: check, status: :pending)
+ @error_logged = false
end
def log(event, message)
@@ -12,7 +15,13 @@ class CheckLogger
when :parsed_response
log_parsed_response(message)
when :parser_error, :service_error, :standard_error
+ # avoid multiple logging & wrong incrementation of consecutive failures
+ # (because a Service exception could be re-raised from a Job)
+ return if error_logged?
+
log_error(message)
+
+ @error_logged = true
end
end
@@ -41,7 +50,12 @@ class CheckLogger
end
def log_error(exception)
+ check.increment_consecutive_failures!
check_log.error = [exception.message, exception.backtrace].join("\n")
check_log.failed!
end
+
+ def error_logged?
+ @error_logged
+ end
end
diff --git a/app/services/check_processor.rb b/app/services/check_processor.rb
index abe087c..9492505 100644
--- a/app/services/check_processor.rb
+++ b/app/services/check_processor.rb
@@ -28,14 +28,14 @@ module CheckProcessor
def resolve_expire_long_term
scope
.where("DATE(domain_expires_at) >= DATE_ADD(CURDATE(), INTERVAL ? DAY)",
- configuration.long_term)
+ configuration.long_term_interval)
.where("DATEDIFF(domain_expires_at, CURDATE()) MOD ? = 0",
configuration.long_term_frequency)
end
def resolve_expire_short_term
scope.where("DATE(domain_expires_at) < DATE_ADD(CURDATE(), INTERVAL ? DAY)",
- configuration.long_term)
+ configuration.long_term_interval)
end
def resolve_unknown_expiry
@@ -71,12 +71,6 @@ module CheckProcessor
private
def default_configuration
- config = Rails.configuration.chexpire.fetch(configuration_key, {})
-
- OpenStruct.new(
- interval: config.fetch("interval") { 0.00 },
- long_term: config.fetch("long_term") { 60 },
- long_term_frequency: config.fetch("long_term_frequency") { 10 },
- )
+ Rails.configuration.chexpire.fetch(configuration_key)
end
end
diff --git a/app/services/notifier/channels/base.rb b/app/services/notifier/channels/base.rb
index a3e9586..5c879aa 100644
--- a/app/services/notifier/channels/base.rb
+++ b/app/services/notifier/channels/base.rb
@@ -1,39 +1,33 @@
module Notifier
module Channels
class Base
- def notify(reason, notification) # rubocop:disable Metrics/MethodLength
- return unless supports?(reason, notification)
+ def notify(notification) # rubocop:disable Metrics/MethodLength
+ return unless supports?(notification)
notification.ongoing!
- case [notification.check.kind.to_sym, reason]
- when [:domain, :expires_soon]
+ case notification.check.kind.to_sym
+ when :domain
domain_notify_expires_soon(notification)
- when [:domain, :recurrent_failures]
- domain_notify_recurrent_failures(notification)
- when [:ssl, :expires_soon]
+ when :ssl
ssl_notify_expires_soon(notification)
- when [:ssl, :recurrent_failures]
- ssl_notify_recurrent_failures(notification)
else
fail ArgumentError,
- "Invalid notification reason `#{reason}` for check kind `#{notification.check.kind}`."
+ "Invalid notification for check kind `#{notification.check.kind}`."
end
end
private
# :nocov:
- def supports?(_reason, _notification)
+ def supports?(_notification)
fail NotImplementedError,
"#{self.class.name} channel did not implemented method #{__callee__}"
end
%i[
domain_notify_expires_soon
- domain_notify_recurrent_failures
ssl_notify_expires_soon
- ssl_notify_recurrent_failures
].each do |method|
define_method(method) do
fail NotImplementedError,
diff --git a/app/services/notifier/channels/email.rb b/app/services/notifier/channels/email.rb
index 9243b7d..9141ee0 100644
--- a/app/services/notifier/channels/email.rb
+++ b/app/services/notifier/channels/email.rb
@@ -1,29 +1,25 @@
module Notifier
module Channels
class Email < Base
- REASONS = %i[expires_soon recurrent_failures].freeze
+ # Error notifications - all checks grouped by user
+ def notify_recurrent_failures(user, checks)
+ NotificationsMailer.recurrent_failures(user, checks).deliver_now
+ end
protected
- def supports?(reason, _notification)
- REASONS.include?(reason)
+ def supports?(_notification)
+ true
end
+ # Expiration notifications
def domain_notify_expires_soon(notification)
NotificationsMailer.with(notification: notification).domain_expires_soon.deliver_now
end
- def domain_notify_recurrent_failures(notification)
- NotificationsMailer.with(notification: notification).domain_recurrent_failures.deliver_now
- end
-
def ssl_notify_expires_soon(notification)
NotificationsMailer.with(notification: notification).ssl_expires_soon.deliver_now
end
-
- def ssl_notify_recurrent_failures(notification)
- NotificationsMailer.with(notification: notification).ssl_recurrent_failures.deliver_now
- end
end
end
end
diff --git a/app/services/notifier/processor.rb b/app/services/notifier/processor.rb
index 2d7fe15..8d3cad3 100644
--- a/app/services/notifier/processor.rb
+++ b/app/services/notifier/processor.rb
@@ -1,5 +1,5 @@
module Notifier
- Configuration = Struct.new(:interval, :failure_days)
+ Configuration = Struct.new(:interval, :consecutive_failures)
class Processor
attr_reader :configuration
@@ -16,18 +16,19 @@ module Notifier
end
def process_expires_soon
- resolver.resolve_expires_soon.find_each do |notification|
- notifier_channel_for(notification).notify(:expires_soon, notification)
+ resolver.notifications_expiring_soon.find_each do |notification|
+ notifier_channel_for(notification).notify(notification)
sleep configuration.interval
end
end
+ # Notify checks in error by email to the check owner adress email.
+ # A single email contains all checks for a same user.
def process_recurrent_failures
- resolver.resolve_check_failed.find_each do |notification|
- next unless should_notify_for_recurrent_failures?(notification)
-
- notifier_channel_for(notification).notify(:recurrent_failures, notification)
+ failed_checks = resolver.checks_recurrent_failures(configuration.consecutive_failures)
+ failed_checks.group_by(&:user).each_pair do |user, checks|
+ channels[:email].notify_recurrent_failures(user, checks)
sleep configuration.interval
end
@@ -36,21 +37,11 @@ module Notifier
private
def default_configuration
- config = Rails.configuration.chexpire.fetch("notifier", {})
-
- Configuration.new(
- config.fetch("interval") { 0.00 },
- config.fetch("failures_days") { 3 },
- )
+ Rails.configuration.chexpire.fetch("notifier")
end
def notifier_channel_for(notification)
channels.fetch(notification.channel.to_sym)
end
-
- def should_notify_for_recurrent_failures?(_notification)
- true
- # TODO: dependent of logs consecutive failures
- end
end
end
diff --git a/app/services/notifier/resolver.rb b/app/services/notifier/resolver.rb
index a157860..25c3592 100644
--- a/app/services/notifier/resolver.rb
+++ b/app/services/notifier/resolver.rb
@@ -1,18 +1,18 @@
module Notifier
class Resolver
- def resolve_expires_soon
+ def notifications_expiring_soon
scope
.where("checks.domain_expires_at >= CURDATE()")
.where("DATE(checks.domain_expires_at)
<= DATE_ADD(CURDATE(), INTERVAL notifications.interval DAY)")
end
- def resolve_check_failed
- # Only gets here the checks having its last run in error
- # Logical rules are in plain ruby inside processor
- scope
- .includes(check: :logs)
- .merge(Check.last_run_failed)
+ def checks_recurrent_failures(min_consecutive)
+ Check
+ .active
+ .consecutive_failures(min_consecutive)
+ .includes(:user)
+ .where.not(user: ignore_users)
end
private
diff --git a/app/views/checks/_table.html.erb b/app/views/checks/_table.html.erb
index f4020fa..3808d01 100644
--- a/app/views/checks/_table.html.erb
+++ b/app/views/checks/_table.html.erb
@@ -26,7 +26,7 @@
<%= t(".kind_labels.#{check.kind}") %>
- <%= check_in_error(check) if check.in_error? %>
+ <%= check_error(check) if check_in_error?(check) %>
<%= check.domain %>
|
diff --git a/app/views/notifications_mailer/_check_comment_vendor.en.html.erb b/app/views/notifications_mailer/_check_comment_vendor.en.html.erb
index 9c96749..8394dd9 100644
--- a/app/views/notifications_mailer/_check_comment_vendor.en.html.erb
+++ b/app/views/notifications_mailer/_check_comment_vendor.en.html.erb
@@ -1,13 +1,13 @@
-<%- if @check.comment.present? -%>
+<%- if check.comment.present? -%>
You wrote the following comment with this domain:
- <%= @check.comment -%>
+ <%= check.comment -%>
<%- end -%>
-<%- if @check.vendor.present? -%>
-Vendor: <%= @check.vendor %>
+<%- if check.vendor.present? -%>
+Vendor: <%= check.vendor %>
<% end %>
diff --git a/app/views/notifications_mailer/_check_comment_vendor.en.text.erb b/app/views/notifications_mailer/_check_comment_vendor.en.text.erb
index 7407cc1..2f62655 100644
--- a/app/views/notifications_mailer/_check_comment_vendor.en.text.erb
+++ b/app/views/notifications_mailer/_check_comment_vendor.en.text.erb
@@ -1,11 +1,9 @@
-<%- if @check.comment.present? -%>
+<%- if check.comment.present? -%>
You wrote the following comment with this domain:
- <%= @check.comment -%>
+ <%= check.comment -%>
<%- end -%>
-
-
-<%- if @check.vendor.present? -%>
-Vendor: <%= @check.vendor %>
+<%- if check.vendor.present? -%>
+Vendor: <%= check.vendor %>
<% end %>
diff --git a/app/views/notifications_mailer/_check_comment_vendor.fr.html.erb b/app/views/notifications_mailer/_check_comment_vendor.fr.html.erb
index c2d7576..a2772ff 100644
--- a/app/views/notifications_mailer/_check_comment_vendor.fr.html.erb
+++ b/app/views/notifications_mailer/_check_comment_vendor.fr.html.erb
@@ -1,13 +1,13 @@
-<%- if @check.comment.present? -%>
+<%- if check.comment.present? -%>
Vous avez saisi le commentaire suivant pour ce domaine :
- <%= @check.comment -%>
+ <%= check.comment -%>
<%- end -%>
-<%- if @check.vendor.present? -%>
-Fournisseur : <%= @check.vendor %>
+<%- if check.vendor.present? -%>
+Fournisseur : <%= check.vendor %>
<% end %>
diff --git a/app/views/notifications_mailer/_check_comment_vendor.fr.text.erb b/app/views/notifications_mailer/_check_comment_vendor.fr.text.erb
index b52e291..6bddf75 100644
--- a/app/views/notifications_mailer/_check_comment_vendor.fr.text.erb
+++ b/app/views/notifications_mailer/_check_comment_vendor.fr.text.erb
@@ -1,11 +1,8 @@
-<%- if @check.comment.present? -%>
+<%- if check.comment.present? -%>
Vous avez saisi le commentaire suivant pour ce domaine :
-
- <%= @check.comment -%>
+ <%= check.comment -%>
<%- end -%>
-
-
-<%- if @check.vendor.present? -%>
-Fournisseur : <%= @check.vendor %>
+<%- if check.vendor.present? -%>
+Fournisseur : <%= check.vendor %>
<% end %>
diff --git a/app/views/notifications_mailer/_domain_recurrent_failure.en.html.erb b/app/views/notifications_mailer/_domain_recurrent_failure.en.html.erb
new file mode 100644
index 0000000..2b47a94
--- /dev/null
+++ b/app/views/notifications_mailer/_domain_recurrent_failure.en.html.erb
@@ -0,0 +1,23 @@
+
+ Domain: <%= check.domain %> (<%= check.consecutive_failures %> consecutive errors)
+
+
+
+ <%- if check.domain_expires_at.present? %>
+ Last known expiry date : <%= format_utc(check.domain_expires_at) %>.
+
+ <% end %>
+
+ <%- if check.last_success_at.present? %>
+ Last successful check occured : <%= format_utc(check.last_success_at) %>.
+
+ <% end %>
+
+
+
+If you have deleted your domain or have not renewed it, please disable
+or delete the check by following this link:
+<%= edit_check_url(check) %>
+
+
+<%= render "check_comment_vendor", check: check %>
diff --git a/app/views/notifications_mailer/_domain_recurrent_failure.en.text.erb b/app/views/notifications_mailer/_domain_recurrent_failure.en.text.erb
new file mode 100644
index 0000000..61ec36c
--- /dev/null
+++ b/app/views/notifications_mailer/_domain_recurrent_failure.en.text.erb
@@ -0,0 +1,15 @@
+Domain: <%= check.domain %> (<%= check.consecutive_failures %> consecutive errors)
+<%= "-" * (check.domain.length + "Domain: ".length) %>
+
+<%- if check.domain_expires_at.present? %>
+Last known expiry date : <%= format_utc(check.domain_expires_at) %>.
+<% end %>
+<%- if check.last_success_at.present? %>
+Last successful check occured : <%= format_utc(check.last_success_at) %>.
+<% end %>
+
+If you have deleted your domain or have not renewed it, please disable
+or delete the check by following this link:
+<%= edit_check_url(check) %>
+
+<%= render "check_comment_vendor", check: check %>
diff --git a/app/views/notifications_mailer/_domain_recurrent_failure.fr.html.erb b/app/views/notifications_mailer/_domain_recurrent_failure.fr.html.erb
new file mode 100644
index 0000000..ba96bf3
--- /dev/null
+++ b/app/views/notifications_mailer/_domain_recurrent_failure.fr.html.erb
@@ -0,0 +1,18 @@
+
+ Domaine: <%= check.domain %> (<%= check.consecutive_failures %> erreurs consécutives)
+
+ <%- if check.domain_expires_at.present? %>
+ Dernière date d'expiration connue : <%= format_utc(check.domain_expires_at) %>.
+
+ <% end %>
+
+ <%- if check.last_success_at.present? %>
+ Dernière vérification réussie : <%= format_utc(check.last_success_at) %>.
+ <% end %>
+
+
+
+Si vous avez supprimé le domaine ou ne l'avez pas renouvellé, merci de désactiver la vérification associée, avec ce lien :
+<%= link_to nil, edit_check_url(check) %>
+
+<%= render "check_comment_vendor", check: check %>
diff --git a/app/views/notifications_mailer/_domain_recurrent_failure.fr.text.erb b/app/views/notifications_mailer/_domain_recurrent_failure.fr.text.erb
new file mode 100644
index 0000000..82d8c67
--- /dev/null
+++ b/app/views/notifications_mailer/_domain_recurrent_failure.fr.text.erb
@@ -0,0 +1,15 @@
+Domaine: <%= check.domain %> (<%= check.consecutive_failures %> erreurs consécutives)
+<%= "-" * (check.domain.length + "Domaine: ".length) %>
+
+<%- if check.domain_expires_at.present? %>
+Dernière date d'expiration connue : <%= format_utc(check.domain_expires_at) %>.
+<% end %>
+<%- if check.last_success_at.present? %>
+Dernière vérification réussie : <%= format_utc(check.last_success_at) %>.
+<% end %>
+
+Si vous avez supprimé le domaine ou ne l'avez pas renouvellé,
+merci de désactiver la vérification associée, avec ce lien :
+<%= edit_check_url(check) %>
+
+<%= render "check_comment_vendor", check: check %>
diff --git a/app/views/notifications_mailer/_footer_recurrent_failures.en.html.erb b/app/views/notifications_mailer/_footer_recurrent_failures.en.html.erb
index beeffb8..b5159d8 100644
--- a/app/views/notifications_mailer/_footer_recurrent_failures.en.html.erb
+++ b/app/views/notifications_mailer/_footer_recurrent_failures.en.html.erb
@@ -1,11 +1,8 @@
-
--
-You received this email because of the notification <%= interval %> days before
-the last known expiry date.
-You can handle the check by following this link:
-<%= link_to nil, edit_check_url(check) %>
+ You can handle all your checks by following this link:
+<%= link_to nil, checks_url %>
The Chexpire Team
diff --git a/app/views/notifications_mailer/_footer_recurrent_failures.en.text.erb b/app/views/notifications_mailer/_footer_recurrent_failures.en.text.erb
index b5a42ec..e91b7ae 100644
--- a/app/views/notifications_mailer/_footer_recurrent_failures.en.text.erb
+++ b/app/views/notifications_mailer/_footer_recurrent_failures.en.text.erb
@@ -1,8 +1,6 @@
--
-You received this email because of the notification <%= interval %> days before
-the last known expiry date.
-You can handle the check by following this link:
-<%= edit_check_url(check) %>
+You can handle all your checks by following this link:
+<%= checks_url %>
The Chexpire Team
diff --git a/app/views/notifications_mailer/_footer_recurrent_failures.fr.html.erb b/app/views/notifications_mailer/_footer_recurrent_failures.fr.html.erb
index bb35480..0f13c9e 100644
--- a/app/views/notifications_mailer/_footer_recurrent_failures.fr.html.erb
+++ b/app/views/notifications_mailer/_footer_recurrent_failures.fr.html.erb
@@ -1,10 +1,8 @@
-
--
-Vous avez reçu ce courriel à <%= pluralize(interval, "jour", "jours") %> avant la dernière date d'expiration connue.
-Vous pouvez gérer les notifications pour cette vérification à ce adresse :
-<%= link_to nil, edit_check_url(check) %>
+ Vous pouvez gérer l'ensemble de vos vérifications à cette adresse :
+<%= link_to nil, checks_url %>
L'équipe Chexpire
diff --git a/app/views/notifications_mailer/_footer_recurrent_failures.fr.text.erb b/app/views/notifications_mailer/_footer_recurrent_failures.fr.text.erb
index a77dd21..60c4ef6 100644
--- a/app/views/notifications_mailer/_footer_recurrent_failures.fr.text.erb
+++ b/app/views/notifications_mailer/_footer_recurrent_failures.fr.text.erb
@@ -1,8 +1,6 @@
--
-Vous avez reçu ce courriel à <%= pluralize(interval, "jour", "jours") %>
-avant la dernière date d'expiration connue.
-Vous pouvez gérer les notifications pour cette vérification à ce adresse :
-<%= edit_check_url(check) %>
+Vous pouvez gérer l'ensemble de vos vérifications à cette adresse :
+<%= checks_url %>
L'équipe Chexpire
diff --git a/app/views/notifications_mailer/_ssl_recurrent_failure.en.html.erb b/app/views/notifications_mailer/_ssl_recurrent_failure.en.html.erb
new file mode 100644
index 0000000..1ce2fd3
--- /dev/null
+++ b/app/views/notifications_mailer/_ssl_recurrent_failure.en.html.erb
@@ -0,0 +1,22 @@
+
+ SSL: <%= check.domain %> (<%= check.consecutive_failures %> erreurs consécutives)
+
+
+ <%- if check.domain_expires_at.present? %>
+ Last known expiry date : <%= format_utc(check.domain_expires_at) %>.
+
+ <%- end %>
+
+ <%- if check.last_success_at.present? %>
+ Last successful check : <%= format_utc(check.last_success_at) %>.
+
+ <%- end %>
+
+
+
+If there is no more SSL endpoint for this domain, please disable
+or delete the check by following this link:
+<%= edit_check_url(check) %>
+
+
+<%= render "check_comment_vendor", check: check %>
diff --git a/app/views/notifications_mailer/_ssl_recurrent_failure.en.text.erb b/app/views/notifications_mailer/_ssl_recurrent_failure.en.text.erb
new file mode 100644
index 0000000..52c5179
--- /dev/null
+++ b/app/views/notifications_mailer/_ssl_recurrent_failure.en.text.erb
@@ -0,0 +1,15 @@
+SSL: <%= check.domain %> (<%= check.consecutive_failures %> erreurs consécutives)
+<%= "-" * (check.domain.length + "SSL: ".length) %>
+
+<%- if check.domain_expires_at.present? %>
+Last known expiry date : <%= format_utc(check.domain_expires_at) %>.
+<%- end %>
+<%- if check.last_success_at.present? %>
+Last successful check : <%= format_utc(check.last_success_at) %>.
+<%- end %>
+
+If there is no more SSL endpoint for this domain, please disable
+or delete the check by following this link:
+<%= edit_check_url(check) %>
+
+<%= render "check_comment_vendor", check: check %>
diff --git a/app/views/notifications_mailer/_ssl_recurrent_failure.fr.html.erb b/app/views/notifications_mailer/_ssl_recurrent_failure.fr.html.erb
new file mode 100644
index 0000000..18d1cfc
--- /dev/null
+++ b/app/views/notifications_mailer/_ssl_recurrent_failure.fr.html.erb
@@ -0,0 +1,20 @@
+
+ SSL: <%= check.domain %> (<%= check.consecutive_failures %> erreurs consécutives)
+
+
+ <%- if check.domain_expires_at.present? %>
+ Dernière date d'expiration connue : <%= format_utc(check.domain_expires_at) %>.
+
+ <% end %>
+
+ <%- if check.last_success_at.present? %>
+ Dernière vérification réussie : <%= format_utc(check.last_success_at) %>.
+ <% end %>
+
+
+
+ S'il n'y a plus de terminaison SSL pour ce site ou s'il n'existe plus,
+ merci de désactiver la vérification associée, avec ce lien :
+<%= link_to nil, edit_check_url(check) %>
+
+<%= render "check_comment_vendor", check: check %>
diff --git a/app/views/notifications_mailer/_ssl_recurrent_failure.fr.text.erb b/app/views/notifications_mailer/_ssl_recurrent_failure.fr.text.erb
new file mode 100644
index 0000000..4492ca8
--- /dev/null
+++ b/app/views/notifications_mailer/_ssl_recurrent_failure.fr.text.erb
@@ -0,0 +1,15 @@
+SSL: <%= check.domain %> (<%= check.consecutive_failures %> erreurs consécutives)
+<%= "-" * (check.domain.length + "SSL: ".length) %>
+
+<%- if check.domain_expires_at.present? %>
+Dernière date d'expiration connue : <%= format_utc(check.domain_expires_at) %>.
+<% end %>
+<%- if check.last_success_at.present? %>
+Dernière vérification réussie : <%= format_utc(check.last_success_at) %>.
+<% end %>
+
+S'il n'y a plus de terminaison SSL pour ce site ou s'il n'existe plus,
+merci de désactiver la vérification associée, avec ce lien :
+<%= edit_check_url(check) %>
+
+<%= render "check_comment_vendor", check: check %>
diff --git a/app/views/notifications_mailer/domain_expires_soon.en.html.erb b/app/views/notifications_mailer/domain_expires_soon.en.html.erb
index d3b087f..9fb05a7 100644
--- a/app/views/notifications_mailer/domain_expires_soon.en.html.erb
+++ b/app/views/notifications_mailer/domain_expires_soon.en.html.erb
@@ -7,6 +7,6 @@
-<%= render "check_comment_vendor" %>
+<%= render "check_comment_vendor", check: @check %>
<%= render "footer_expires_soon", interval: @notification.interval, check: @check %>
diff --git a/app/views/notifications_mailer/domain_expires_soon.en.text.erb b/app/views/notifications_mailer/domain_expires_soon.en.text.erb
index c42e60a..6e93342 100644
--- a/app/views/notifications_mailer/domain_expires_soon.en.text.erb
+++ b/app/views/notifications_mailer/domain_expires_soon.en.text.erb
@@ -3,7 +3,7 @@ Hi,
the domain <%= @check.domain %> will expire <%= format_utc(@check.domain_expires_at) %>.
-<%= render "check_comment_vendor" %>
+<%= render "check_comment_vendor", check: @check %>
<%= render "footer_expires_soon", interval: @notification.interval, check: @check %>
diff --git a/app/views/notifications_mailer/domain_expires_soon.fr.html.erb b/app/views/notifications_mailer/domain_expires_soon.fr.html.erb
index 9b39910..6aa8e1c 100644
--- a/app/views/notifications_mailer/domain_expires_soon.fr.html.erb
+++ b/app/views/notifications_mailer/domain_expires_soon.fr.html.erb
@@ -7,6 +7,6 @@
-<%= render "check_comment_vendor" %>
+<%= render "check_comment_vendor", check: @check %>
<%= render "footer_expires_soon", interval: @notification.interval, check: @check %>
diff --git a/app/views/notifications_mailer/domain_expires_soon.fr.text.erb b/app/views/notifications_mailer/domain_expires_soon.fr.text.erb
index 2caad62..126ac40 100644
--- a/app/views/notifications_mailer/domain_expires_soon.fr.text.erb
+++ b/app/views/notifications_mailer/domain_expires_soon.fr.text.erb
@@ -3,7 +3,7 @@ Salut,
le domaine <%= @check.domain %> va expirer le <%= format_utc(@check.domain_expires_at) %>.
-<%= render "check_comment_vendor" %>
+<%= render "check_comment_vendor", check: @check %>
<%= render "footer_expires_soon", interval: @notification.interval, check: @check %>
diff --git a/app/views/notifications_mailer/domain_recurrent_failures.en.html.erb b/app/views/notifications_mailer/domain_recurrent_failures.en.html.erb
deleted file mode 100644
index 2146dbc..0000000
--- a/app/views/notifications_mailer/domain_recurrent_failures.en.html.erb
+++ /dev/null
@@ -1,30 +0,0 @@
-
- Hi,
-
-
-
- We had recurrent failures while checking the whois database for domain
- <%= @check.domain %>. As of today, we can't anymore verify the expiry date.
-
-
-
- <%- if @check.domain_expires_at.present? %>
- Our last known expiry date is <%= format_utc(@check.domain_expires_at) %>.
-
- <% end %>
-
- <%- if @check.last_success_at.present? %>
- Our last successful check occured <%= format_utc(@check.last_success_at) %>.
- <% end %>
-
-
-
-If you have deleted the domain or have not renewed it, please disable
-or delete the check by following this link:
-<%= link_to nil, edit_check_url(@check) %>
-
-
-<%= render "check_comment_vendor" %>
-
-
-<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %>
diff --git a/app/views/notifications_mailer/domain_recurrent_failures.en.text.erb b/app/views/notifications_mailer/domain_recurrent_failures.en.text.erb
deleted file mode 100644
index b5ce466..0000000
--- a/app/views/notifications_mailer/domain_recurrent_failures.en.text.erb
+++ /dev/null
@@ -1,20 +0,0 @@
-Hi,
-
-We had recurrent failures while checking the whois database for domain
-<%= @check.domain %>. As of today, we can't anymore verify the expiry date.
-
-<%- if @check.domain_expires_at.present? %>
-The last known expiry date is <%= format_utc(@check.domain_expires_at) %>.
-<% end %>
-<%- if @check.last_success_at.present? %>
-The last successful check occured <%= format_utc(@check.last_success_at) %>.
-<% end %>
-
-If you have deleted your domain or have not renewed it, please disable
-or delete the check by following this link:
-
-<%= edit_check_url(@check) %>
-
-<%= render "check_comment_vendor" %>
-
-<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %>
diff --git a/app/views/notifications_mailer/domain_recurrent_failures.fr.html.erb b/app/views/notifications_mailer/domain_recurrent_failures.fr.html.erb
deleted file mode 100644
index 7da5aed..0000000
--- a/app/views/notifications_mailer/domain_recurrent_failures.fr.html.erb
+++ /dev/null
@@ -1,29 +0,0 @@
-
- Salut,
-
-
-
- Nous avons rencontré de multiples erreurs pendant l'exécution des vérifications du domaine <%= @check.domain %>.
- Nous ne pouvons plus interroger la base Whois pour vérifier la date d'expiration.
-
-
-
- <%- if @check.domain_expires_at.present? %>
- La dernière date d'expiration connue est le <%= format_utc(@check.domain_expires_at) %>.
-
- <% end %>
-
- <%- if @check.last_success_at.present? %>
- Notre dernière vérification réussie a eu lieu le <%= format_utc(@check.last_success_at) %>.
- <% end %>
-
-
-
-Si vous avez supprimé le domaine ou ne l'avez pas renouvellé, merci de désactiver la vérification associée, avec ce lien :
-<%= link_to nil, edit_check_url(@check) %>
-
-
-<%= render "check_comment_vendor" %>
-
-
-<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %>
diff --git a/app/views/notifications_mailer/domain_recurrent_failures.fr.text.erb b/app/views/notifications_mailer/domain_recurrent_failures.fr.text.erb
deleted file mode 100644
index cb8673e..0000000
--- a/app/views/notifications_mailer/domain_recurrent_failures.fr.text.erb
+++ /dev/null
@@ -1,20 +0,0 @@
-Salut,
-
-Nous avons rencontré de multiples erreurs pendant l'exécution des vérifications
-du domaine <%= @check.domain %>.
-Nous ne pouvons plus interroger la base Whois pour vérifier la date d'expiration.
-
-<%- if @check.domain_expires_at.present? %>
-La dernière date d'expiration connue est le <%= format_utc(@check.domain_expires_at) %>.
-<% end %>
-<%- if @check.last_success_at.present? %>
-Notre dernière vérification réussie a eu lieu le <%= format_utc(@check.last_success_at) %>.
-<% end %>
-
-Si vous avez supprimé le domaine ou ne l'avez pas renouvellé,
-merci de désactiver la vérification associée, avec ce lien :
-<%= edit_check_url(@check) %>
-
-<%= render "check_comment_vendor" %>
-
-<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %>
diff --git a/app/views/notifications_mailer/recurrent_failures.en.html.erb b/app/views/notifications_mailer/recurrent_failures.en.html.erb
new file mode 100644
index 0000000..fee55f1
--- /dev/null
+++ b/app/views/notifications_mailer/recurrent_failures.en.html.erb
@@ -0,0 +1,22 @@
+
+ Hi,
+
+
+
+ <%= t(".header", count: @checks.count) %>
+
+
+
+<%- @checks.each_with_index do |check, index| %>
+ <%- if index > 0 -%>
+
+
+
+ <%- end -%>
+
+ <%= render "#{check.kind}_recurrent_failure", check: check %>
+<%- end -%>
+
+
+
+<%= render "footer_recurrent_failures" %>
diff --git a/app/views/notifications_mailer/recurrent_failures.en.text.erb b/app/views/notifications_mailer/recurrent_failures.en.text.erb
new file mode 100644
index 0000000..d58006b
--- /dev/null
+++ b/app/views/notifications_mailer/recurrent_failures.en.text.erb
@@ -0,0 +1,14 @@
+Hi,
+
+<%= t(".header", count: @checks.count) %>
+
+<%- @checks.each_with_index do |check, index| %>
+ <%- if index > 0 -%>
+
+ <%- end -%>
+
+<%= render "#{check.kind}_recurrent_failure", check: check %>
+<%- end -%>
+
+
+<%= render "footer_recurrent_failures" %>
diff --git a/app/views/notifications_mailer/recurrent_failures.fr.html.erb b/app/views/notifications_mailer/recurrent_failures.fr.html.erb
new file mode 100644
index 0000000..513a848
--- /dev/null
+++ b/app/views/notifications_mailer/recurrent_failures.fr.html.erb
@@ -0,0 +1,22 @@
+
+ Salut,
+
+
+
+ <%= t(".header", count: @checks.count) %>
+
+
+
+<%- @checks.each_with_index do |check, index| %>
+ <%- if index > 0 -%>
+
+
+
+ <%- end -%>
+
+ <%= render "#{check.kind}_recurrent_failure", check: check %>
+<%- end -%>
+
+
+
+<%= render "footer_recurrent_failures" %>
diff --git a/app/views/notifications_mailer/recurrent_failures.fr.text.erb b/app/views/notifications_mailer/recurrent_failures.fr.text.erb
new file mode 100644
index 0000000..3726ef9
--- /dev/null
+++ b/app/views/notifications_mailer/recurrent_failures.fr.text.erb
@@ -0,0 +1,14 @@
+Salut,
+
+<%= t(".header", count: @checks.count) %>
+
+<%- @checks.each_with_index do |check, index| %>
+ <%- if index > 0 -%>
+
+ <%- end -%>
+
+<%= render "#{check.kind}_recurrent_failure", check: check %>
+<%- end -%>
+
+
+<%= render "footer_recurrent_failures" %>
diff --git a/app/views/notifications_mailer/ssl_expires_soon.en.html.erb b/app/views/notifications_mailer/ssl_expires_soon.en.html.erb
index 401df10..f0a5515 100644
--- a/app/views/notifications_mailer/ssl_expires_soon.en.html.erb
+++ b/app/views/notifications_mailer/ssl_expires_soon.en.html.erb
@@ -7,6 +7,6 @@
-<%= render "check_comment_vendor" %>
+<%= render "check_comment_vendor", check: @check %>
<%= render "footer_expires_soon", interval: @notification.interval, check: @check %>
diff --git a/app/views/notifications_mailer/ssl_expires_soon.en.text.erb b/app/views/notifications_mailer/ssl_expires_soon.en.text.erb
index a1d1c56..73e13dd 100644
--- a/app/views/notifications_mailer/ssl_expires_soon.en.text.erb
+++ b/app/views/notifications_mailer/ssl_expires_soon.en.text.erb
@@ -3,7 +3,7 @@ Hi,
the SSL certificate for <%= @check.domain %> will expire <%= format_utc(@check.domain_expires_at) %>.
-<%= render "check_comment_vendor" %>
+<%= render "check_comment_vendor", check: @check %>
<%= render "footer_expires_soon", interval: @notification.interval, check: @check %>
diff --git a/app/views/notifications_mailer/ssl_expires_soon.fr.html.erb b/app/views/notifications_mailer/ssl_expires_soon.fr.html.erb
index dfc1c3f..6869687 100644
--- a/app/views/notifications_mailer/ssl_expires_soon.fr.html.erb
+++ b/app/views/notifications_mailer/ssl_expires_soon.fr.html.erb
@@ -7,6 +7,6 @@
-<%= render "check_comment_vendor" %>
+<%= render "check_comment_vendor", check: @check %>
<%= render "footer_expires_soon", interval: @notification.interval, check: @check %>
diff --git a/app/views/notifications_mailer/ssl_expires_soon.fr.text.erb b/app/views/notifications_mailer/ssl_expires_soon.fr.text.erb
index 0664fb5..9f6999c 100644
--- a/app/views/notifications_mailer/ssl_expires_soon.fr.text.erb
+++ b/app/views/notifications_mailer/ssl_expires_soon.fr.text.erb
@@ -3,7 +3,7 @@ Salut,
le certificat SSL pour <%= @check.domain %> va expirer le <%= format_utc(@check.domain_expires_at) %>.
-<%= render "check_comment_vendor" %>
+<%= render "check_comment_vendor", check: @check %>
<%= render "footer_expires_soon", interval: @notification.interval, check: @check %>
diff --git a/app/views/notifications_mailer/ssl_recurrent_failures.en.html.erb b/app/views/notifications_mailer/ssl_recurrent_failures.en.html.erb
deleted file mode 100644
index 602c32d..0000000
--- a/app/views/notifications_mailer/ssl_recurrent_failures.en.html.erb
+++ /dev/null
@@ -1,31 +0,0 @@
-
- Hi,
-
-
-
- We had recurrent failures while checking the SSL certificate for
- <%= @check.domain %>. As of today, we can no longer verify the certificate
- expiry date.
-
-
-
- <%- if @check.domain_expires_at.present? %>
- Our last known expiry date is <%= format_utc(@check.domain_expires_at) %>.
-
- <%- end %>
-
- <%- if @check.last_success_at.present? %>
- Our last successful check occured <%= format_utc(@check.last_success_at) %>.
- <%- end %>
-
-
-
- If there is no more SSL endpoint for this domain, please disable
- or delete the check by following this link:
- <%= link_to nil, edit_check_url(@check) %>
-
-
-<%= render "check_comment_vendor" %>
-
-
-<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %>
diff --git a/app/views/notifications_mailer/ssl_recurrent_failures.en.text.erb b/app/views/notifications_mailer/ssl_recurrent_failures.en.text.erb
deleted file mode 100644
index 2bb6dd3..0000000
--- a/app/views/notifications_mailer/ssl_recurrent_failures.en.text.erb
+++ /dev/null
@@ -1,22 +0,0 @@
-Hi,
-
-We had recurrent failures while checking the SSL certificate for
-<%= @check.domain %>. As of today, we can no longer verify the certificate
-expiry date.
-
-<%- if @check.domain_expires_at.present? %>
-The last known expiry date is <%= format_utc(@check.domain_expires_at) %>.
-<%- end %>
-
-<%- if @check.last_success_at.present? %>
-The last successful check occured <%= format_utc(@check.last_success_at) %>.
-<%- end %>
-
-If there is no more SSL endpoint for this domain, please disable
-or delete the check by following this link:
-
-<%= edit_check_url(@check) %>
-
-<%= render "check_comment_vendor" %>
-
-<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %>
diff --git a/app/views/notifications_mailer/ssl_recurrent_failures.fr.html.erb b/app/views/notifications_mailer/ssl_recurrent_failures.fr.html.erb
deleted file mode 100644
index ea05abc..0000000
--- a/app/views/notifications_mailer/ssl_recurrent_failures.fr.html.erb
+++ /dev/null
@@ -1,35 +0,0 @@
-
- Salut,
-
-
-
- Nous avons rencontré de multiples erreurs
- pendant l'exécution des vérifications du certificat SSL
- du site <%= @check.domain %>.
- Nous ne pouvons plus vérifier la date d'expiration du certificat
- en nous connectant au site.
-
-
-
- <%- if @check.domain_expires_at.present? %>
- La dernière date d'expiration connue est le <%= format_utc(@check.domain_expires_at) %>.
-
- <% end %>
-
- <%- if @check.last_success_at.present? %>
- Notre dernière vérification réussie a eu lieu le <%= format_utc(@check.last_success_at) %>.
- <% end %>
-
-
-
- S'il n'y a plus de terminaison SSL pour ce site ou s'il n'existe plus,
- merci de désactiver la vérification associée, avec ce lien :
-
-
- <%= link_to nil, edit_check_url(@check) %>
-
-
-<%= render "check_comment_vendor" %>
-
-
-<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %>
diff --git a/app/views/notifications_mailer/ssl_recurrent_failures.fr.text.erb b/app/views/notifications_mailer/ssl_recurrent_failures.fr.text.erb
deleted file mode 100644
index fe15787..0000000
--- a/app/views/notifications_mailer/ssl_recurrent_failures.fr.text.erb
+++ /dev/null
@@ -1,22 +0,0 @@
-Salut,
-
-Nous avons rencontré de multiples erreurs pendant l'exécution des vérifications
-du certificat SSL pour le site <%= @check.domain %>.
-Nous ne pouvons plus vérifier la date d'expiration du certificat
-en nous connectant au site.
-
-<%- if @check.domain_expires_at.present? %>
-La dernière date d'expiration connue est le <%= format_utc(@check.domain_expires_at) %>.
-<% end %>
-
-<%- if @check.last_success_at.present? %>
-Notre dernière vérification réussie a eu lieu le <%= format_utc(@check.last_success_at) %>.
-<% end %>
-
-S'il n'y a plus de terminaison SSL pour ce site ou s'il n'existe plus,
-merci de désactiver la vérification associée, avec ce lien :
-<%= edit_check_url(@check) %>
-
-<%= render "check_comment_vendor" %>
-
-<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %>
diff --git a/config/application.rb b/config/application.rb
index 5adecf8..9f5c3df 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -32,6 +32,12 @@ module Chexpire
config.time_zone = "Europe/Paris"
- config.chexpire = config_for(:chexpire)
+ unless Rails.root.join("config", "chexpire.yml").readable?
+ fail "Missing Chexpire configuration file.
+ You have to create the config/chexpire.yml file and set at least the required values.
+ Look at config/chexpire.defaults.yml and INSTALL.md for more information"
+ end
+
+ config.chexpire = Hashie::Mash.new(config_for(:"chexpire.defaults").deep_merge(config_for(:chexpire)))
end
end
diff --git a/config/chexpire.defaults.yml b/config/chexpire.defaults.yml
new file mode 100644
index 0000000..3080d0f
--- /dev/null
+++ b/config/chexpire.defaults.yml
@@ -0,0 +1,53 @@
+# DO NOT EDIT THIS FILE
+#
+# If you want override a value for any environment,
+# create a `config/chexpire.yml` file,
+# write your overrided keys under your environment namespace.
+#
+# Some keys are required to be overidden for your environment.
+#
+# Example:
+#
+# production:
+# mailer_default_from: "contact@yourdomain.org"
+# host: mychexpire.instance.org
+
+default: &default
+ mailer_default_from: "from@example.org" # REQUIRED: Email will be sent with this address as From header
+ host: chexpire.local # REQUIRED: Host of the website.
+
+ interface:
+ consecutive_failures_as_error: 2 # number of consecutive failures before display a check as "in error" (value for interface only)
+ notifier:
+ interval: 0.00 # pause in second between each notification sent
+ consecutive_failures: 4 # number of consecutive failures before sending a notification for recurrent failures
+ checks_domain:
+ interval: 0.5 # pause in second between each whois call
+ long_term_interval: 300 # when last known expiry date exceeds this interval in days, whois verification won't happen every day
+ long_term_frequency: 4 # when last known expiry exceeds $long_term, perform whois verification each $long_term_frequency days instead of every day
+ checks_ssl:
+ check_http_path: # defaults to check_http in $PATH
+ check_http_args: # array of arguments appended to defaults arguments (-C 0 -H $HOSTNAME).
+
+development:
+ <<: *default
+ host: "chexpire.local"
+
+production:
+ <<: *default
+ action_mailer_config:
+ delivery_method: :sendmail
+
+staging:
+ <<: *default
+ action_mailer_config:
+ delivery_method: :sendmail
+
+test:
+ <<: *default
+ mailer_default_from: "testcontact@example.org"
+ host: localhost
+ checks_dummy:
+ interval: 0.0
+ long_term_interval: 60
+ long_term_frequency: 10
diff --git a/config/chexpire.example.yml b/config/chexpire.example.yml
deleted file mode 100644
index 324a5d7..0000000
--- a/config/chexpire.example.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-default: &default
- mailer_default_from: "from@example.org"
- notifier:
- interval: 0.00
- failure_days: 3
- checks_domain:
- interval: 0.5
- long_term: 60
- long_term_frequency: 10
- checks_ssl:
- check_http_path: # default to check_http in $PATH)
- check_http_args: # array of arguments appended to defaults: -C 0 -H $HOSTNAME.
-
-development:
- <<: *default
- host: "chexpire.local"
-
-production:
- action_mailer_config:
- delivery_method: :sendmail
-
-staging:
- action_mailer_config:
- delivery_method: :sendmail
-
-# test configuration included in file used by CI services
-<%= IO.read Rails.root.join("config", "chexpire.test.yml") %>
diff --git a/config/chexpire.test.yml b/config/chexpire.test.yml
deleted file mode 100644
index 6af09a8..0000000
--- a/config/chexpire.test.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-test:
- mailer_default_from: "contact@chexpire.org"
- host: "localhost"
- notifier:
- interval: 0.00
- failure_days: 3
- checks_domain:
- interval: 0.00
- long_term: 60
- long_term_frequency: 10
- checks_ssl:
- check_http_path:
- check_http_args:
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 554bb3f..7fb3d01 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -40,8 +40,13 @@ en:
one: "Domain %{domain} expires TOMORROW!"
other: "Domain %{domain} expires in %{count} days"
- domain_recurrent_failures:
- subject: "Recurrent failures in %{domain} domain expiry check"
+ recurrent_failures:
+ subject:
+ one: "Recurrent failures for %{domain} expiry check"
+ other: "%{count} checks in error"
+ header:
+ one: "We had recurrent failures during excution of the following check:"
+ other: "We had recurrent failures during excution of the %{count} following checks:"
ssl_expires_soon:
subject:
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 52241a1..6be381e 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -75,8 +75,13 @@ fr:
one: "Le domaine %{domain} expire DEMAIN !"
other: "Le domaine %{domain} expire dans %{count} jours"
- domain_recurrent_failures:
- subject: "Erreurs dans la vérification d'expiration du domaine %{domain}"
+ recurrent_failures:
+ subject:
+ one: "Erreurs de vérification d'expiration pour %{domain}"
+ other: "%{count} vérifications en erreur"
+ header:
+ one: "Nous avons rencontré des erreurs pendant l'exécution d'une de vos vérifications :"
+ other: "Nous avons rencontré des erreurs pendant l'exécution des %{count} vérifications suivantes :"
ssl_expires_soon:
subject:
@@ -84,10 +89,6 @@ fr:
one: "Le certificat SSL pour %{domain} expire DEMAIN !"
other: "Le certificat SSL pour %{domain} expire dans %{count} jours"
- ssl_recurrent_failures:
- subject: "Erreurs dans la vérification d'expiration du certificat SSL %{domain}"
-
-
shared:
locales:
en: Anglais
diff --git a/db/migrate/20180801072038_add_consecutive_failures_to_checks.rb b/db/migrate/20180801072038_add_consecutive_failures_to_checks.rb
new file mode 100644
index 0000000..dbf038b
--- /dev/null
+++ b/db/migrate/20180801072038_add_consecutive_failures_to_checks.rb
@@ -0,0 +1,5 @@
+class AddConsecutiveFailuresToChecks < ActiveRecord::Migration[5.2]
+ def change
+ add_column :checks, :consecutive_failures, :integer, default: 0, null: false
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index eda5147..024d864 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2018_06_13_055303) do
+ActiveRecord::Schema.define(version: 2018_08_01_072038) do
create_table "check_logs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.bigint "check_id"
@@ -38,6 +38,7 @@ ActiveRecord::Schema.define(version: 2018_06_13_055303) do
t.boolean "active", default: true, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
+ t.integer "consecutive_failures", default: 0, null: false
t.index ["user_id"], name: "index_checks_on_user_id"
end
diff --git a/db/seeds.rb b/db/seeds.rb
index 996d657..1f353fb 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -43,6 +43,7 @@ check_chexpire_org_error = Check.create!(
vendor: "Some random registrar",
last_run_at: 20.minutes.ago,
created_at: 3.weeks.ago,
+ consecutive_failures: 4,
)
ssl_check_chexpire_org = Check.create!(
@@ -67,6 +68,7 @@ ssl_check_chexpire_org_error = Check.create!(
vendor: "Some random registrar",
last_run_at: 20.minutes.ago,
last_success_at: 4.days.ago,
+ consecutive_failures: 8,
)
diff --git a/test/factories/checks.rb b/test/factories/checks.rb
index f940eb2..a0cf919 100644
--- a/test/factories/checks.rb
+++ b/test/factories/checks.rb
@@ -2,20 +2,21 @@
#
# Table name: checks
#
-# id :bigint(8) not null, primary key
-# active :boolean default(TRUE), not null
-# comment :string(255)
-# domain :string(255) not null
-# domain_created_at :datetime
-# domain_expires_at :datetime
-# domain_updated_at :datetime
-# kind :integer not null
-# last_run_at :datetime
-# last_success_at :datetime
-# vendor :string(255)
-# created_at :datetime not null
-# updated_at :datetime not null
-# user_id :bigint(8)
+# id :bigint(8) not null, primary key
+# active :boolean default(TRUE), not null
+# comment :string(255)
+# consecutive_failures :integer default(0), not null
+# domain :string(255) not null
+# domain_created_at :datetime
+# domain_expires_at :datetime
+# domain_updated_at :datetime
+# kind :integer not null
+# last_run_at :datetime
+# last_success_at :datetime
+# vendor :string(255)
+# created_at :datetime not null
+# updated_at :datetime not null
+# user_id :bigint(8)
#
# Indexes
#
@@ -39,6 +40,7 @@ FactoryBot.define do
comment nil
last_run_at nil
last_success_at nil
+ consecutive_failures 0
trait :domain do
kind :domain
@@ -63,6 +65,7 @@ FactoryBot.define do
end
trait :last_runs_failed do
+ consecutive_failures 5
last_run_at 3.days.ago - 90.minutes
last_success_at 7.days.ago - 2.hours
end
diff --git a/test/factories/users.rb b/test/factories/users.rb
index 4566543..1f8789b 100644
--- a/test/factories/users.rb
+++ b/test/factories/users.rb
@@ -40,5 +40,9 @@ FactoryBot.define do
notifications_enabled true
locale "en"
tos_accepted true
+
+ trait :fr do
+ locale "fr"
+ end
end
end
diff --git a/test/jobs/ssl_sync_job_test.rb b/test/jobs/ssl_sync_job_test.rb
index 30b66a4..44e76ed 100644
--- a/test/jobs/ssl_sync_job_test.rb
+++ b/test/jobs/ssl_sync_job_test.rb
@@ -22,7 +22,6 @@ class SSLSyncJobTest < ActiveJob::TestCase
test "ignore invalid response" do
domain = "domain.fr"
check = create(:check, :nil_dates, domain: domain)
- original_updated_at = check.updated_at
mock_system_command("check_http", expected_command_arg(domain), stdout: "not a response") do
SSLSyncJob.perform_now(check.id)
@@ -32,8 +31,8 @@ class SSLSyncJobTest < ActiveJob::TestCase
assert_just_now check.last_run_at
assert_nil check.last_success_at
- assert_equal original_updated_at, check.updated_at
assert check.active?
+ assert_equal 1, check.consecutive_failures
end
test "should ignore not found (removed) checks" do
@@ -51,9 +50,25 @@ class SSLSyncJobTest < ActiveJob::TestCase
end
end
+ check.reload
+
assert_equal 1, check.logs.count
assert_match(/undefined method \W+valid\?/, check.logs.last.error)
assert check.logs.last.failed?
+ assert_equal 1, check.consecutive_failures
+ end
+
+ test "should reset consecutive failures with a valid response" do
+ domain = "ssl0.domain.org"
+ check = create(:check, :nil_dates, domain: domain, consecutive_failures: 1)
+
+ mock_system_command("check_http", expected_command_arg(domain), stdout: ssl_response(domain)) do
+ SSLSyncJob.perform_now(check.id)
+ end
+
+ check.reload
+
+ assert_equal 0, check.consecutive_failures
end
private
diff --git a/test/jobs/whois_sync_job_test.rb b/test/jobs/whois_sync_job_test.rb
index e96755d..401eba0 100644
--- a/test/jobs/whois_sync_job_test.rb
+++ b/test/jobs/whois_sync_job_test.rb
@@ -33,6 +33,7 @@ class WhoisSyncJobTest < ActiveJob::TestCase
assert_nil check.last_success_at
assert_equal original_updated_at, check.updated_at
assert check.active?
+ assert_equal 1, check.consecutive_failures
end
test "should ignore not found (removed) checks" do
@@ -50,9 +51,12 @@ class WhoisSyncJobTest < ActiveJob::TestCase
end
end
+ check.reload
+
assert_equal 1, check.logs.count
assert_match(/undefined method \W+valid\?/, check.logs.last.error)
assert check.logs.last.failed?
+ assert_equal 1, check.consecutive_failures
end
test "disable check when whois responds domain not found" do
@@ -68,6 +72,7 @@ class WhoisSyncJobTest < ActiveJob::TestCase
refute check.active?
assert_just_now check.last_run_at
assert_nil check.last_success_at
+ assert_equal 1, check.consecutive_failures
end
test "default logger is CheckLogger" do
@@ -80,6 +85,19 @@ class WhoisSyncJobTest < ActiveJob::TestCase
assert_equal 1, check.logs.count
end
+ test "should reset consecutive failures with a valid response" do
+ domain = "domain.fr"
+ check = create(:check, :nil_dates, domain: domain, consecutive_failures: 1)
+
+ mock_system_command("whois", domain, stdout: whois_response(domain)) do
+ WhoisSyncJob.perform_now(check.id)
+ end
+
+ check.reload
+
+ assert_equal 0, check.consecutive_failures
+ end
+
private
def whois_response(domain)
diff --git a/test/mailers/notifications_mailer_test.rb b/test/mailers/notifications_mailer_test.rb
index c261131..6c3f7c4 100644
--- a/test/mailers/notifications_mailer_test.rb
+++ b/test/mailers/notifications_mailer_test.rb
@@ -31,32 +31,32 @@ class NotificationsMailerTest < ActionMailer::TestCase # rubocop:disable Metrics
end
test "domain_expires_soon FR" do
- check = create(:check, domain_expires_at: Time.new(2018, 6, 10, 12, 0, 5, "+02:00"))
+ check = create(:check,
+ domain_expires_at: Time.new(2018, 6, 10, 12, 0, 5, "+02:00"),
+ user: build(:user, :fr))
notification = build(:notification, interval: 10, check: check, recipient: "colin@example.org")
- I18n.with_locale :fr do
- Date.stub :today, Date.new(2018, 6, 2) do
- mail = NotificationsMailer.with(notification: notification).domain_expires_soon
+ Date.stub :today, Date.new(2018, 6, 2) do
+ mail = NotificationsMailer.with(notification: notification).domain_expires_soon
- assert_emails 1 do
- mail.deliver_now
- end
+ assert_emails 1 do
+ mail.deliver_now
+ end
- assert_match "domain.fr", mail.subject
- assert_match "dans 8 jours", mail.subject
- assert_equal ["colin@example.org"], mail.to
- assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from
+ assert_match "domain.fr", mail.subject
+ assert_match "dans 8 jours", mail.subject
+ assert_equal ["colin@example.org"], mail.to
+ assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from
- parts = [mail.text_part.decode_body, mail.html_part.decode_body]
+ parts = [mail.text_part.decode_body, mail.html_part.decode_body]
- parts.each do |part|
- assert_match "domain.fr", part
- assert_match "dim 10 juin 2018 10:00:05 +0000", part
- assert_match "10 jours", part
- assert_match "/checks/#{check.id}/edit", part
- assert_no_match "commentaire", part
- assert_no_match "fournisseur", part
- end
+ parts.each do |part|
+ assert_match "domain.fr", part
+ assert_match "dim 10 juin 2018 10:00:05 +0000", part
+ assert_match "10 jours", part
+ assert_match "/checks/#{check.id}/edit", part
+ assert_no_match "commentaire", part
+ assert_no_match "fournisseur", part
end
end
end
@@ -82,36 +82,34 @@ class NotificationsMailerTest < ActionMailer::TestCase # rubocop:disable Metrics
check = create(:check,
domain_expires_at: 1.week.from_now,
comment: "My comment",
- vendor: "The vendor")
+ vendor: "The vendor",
+ user: build(:user, :fr))
notification = build(:notification, check: check)
- I18n.with_locale :fr do
- mail = NotificationsMailer.with(notification: notification).domain_expires_soon
+ mail = NotificationsMailer.with(notification: notification).domain_expires_soon
- parts = [mail.text_part.decode_body, mail.html_part.decode_body]
+ parts = [mail.text_part.decode_body, mail.html_part.decode_body]
- parts.each do |part|
- assert_match "commentaire", part
- assert_match "Fournisseur", part
- end
+ parts.each do |part|
+ assert_match "commentaire", part
+ assert_match "Fournisseur", part
end
end
- test "domain_recurrent_failures" do
+ test "recurrent_failures" do
last_success_at = Time.new(2018, 5, 30, 6, 10, 0, "+00:00")
domain_expires_at = Time.new(2018, 10, 10, 7, 20, 0, "+04:00")
- check = build(:check, :last_runs_failed,
- domain: "invalid-domain.fr",
- last_success_at: last_success_at,
- domain_expires_at: domain_expires_at,
- comment: "My comment")
- notification = create(:notification, check: check)
+ check = create(:check, :last_runs_failed,
+ domain: "invalid-domain.fr",
+ last_success_at: last_success_at,
+ domain_expires_at: domain_expires_at,
+ comment: "My comment")
- mail = NotificationsMailer.with(notification: notification).domain_recurrent_failures
+ mail = NotificationsMailer.recurrent_failures(check.user, [check])
assert_match "failures", mail.subject
assert_match "invalid-domain.fr", mail.subject
- assert_equal ["recipient@domain.fr"], mail.to
+ assert_match(/user-\d+@chexpire.org/, mail.to.first)
assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from
parts = [mail.text_part.decode_body, mail.html_part.decode_body]
@@ -119,41 +117,39 @@ class NotificationsMailerTest < ActionMailer::TestCase # rubocop:disable Metrics
parts.each do |part|
assert_match "invalid-domain.fr", part
assert_match "recurrent failures", part
- assert_match(/success[a-z ]+ Wed, 30 May 2018 06:10:00 \+0000/, part)
- assert_match(/expiry[a-z ]+ Wed, 10 Oct 2018 03:20:00 \+0000/, part)
+ assert_match(/success[a-z: ]+ Wed, 30 May 2018 06:10:00 \+0000/, part)
+ assert_match(/expiry[a-z: ]+ Wed, 10 Oct 2018 03:20:00 \+0000/, part)
assert_match "My comment", part
assert_match "/checks/#{check.id}/edit", part
end
end
- test "domain_recurrent_failures - FR" do
+ test "recurrent_failures - FR" do
last_success_at = Time.new(2018, 5, 30, 6, 10, 0, "+00:00")
domain_expires_at = Time.new(2018, 10, 10, 7, 20, 0, "+04:00")
- check = build(:check, :last_runs_failed,
- domain: "invalid-domain.fr",
- last_success_at: last_success_at,
- domain_expires_at: domain_expires_at,
- comment: "My comment")
- notification = create(:notification, check: check)
+ check = create(:check, :last_runs_failed,
+ domain: "invalid-domain.fr",
+ last_success_at: last_success_at,
+ domain_expires_at: domain_expires_at,
+ comment: "My comment",
+ user: build(:user, :fr))
- I18n.with_locale :fr do
- mail = NotificationsMailer.with(notification: notification).domain_recurrent_failures
- assert_match "Erreurs", mail.subject
- assert_match "invalid-domain.fr", mail.subject
+ mail = NotificationsMailer.recurrent_failures(check.user, [check])
+ assert_match "Erreurs", mail.subject
+ assert_match "invalid-domain.fr", mail.subject
- assert_equal ["recipient@domain.fr"], mail.to
- assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from
+ assert_match(/user-\d+@chexpire.org/, mail.to.first)
+ assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from
- parts = [mail.text_part.decode_body, mail.html_part.decode_body]
+ parts = [mail.text_part.decode_body, mail.html_part.decode_body]
- parts.each do |part|
- assert_match "invalid-domain.fr", part
- assert_match "erreurs", part
- assert_match(/réussie[a-z ]+ mer 30 mai 2018 06:10:00 \+0000/, part)
- assert_match(/expiration[a-z ]+ mer 10 oct. 2018 03:20:00 \+0000/, part)
- assert_match "commentaire", part
- assert_match "/checks/#{check.id}/edit", part
- end
+ parts.each do |part|
+ assert_match "invalid-domain.fr", part
+ assert_match "erreurs", part
+ assert_match(/réussie[a-z: ]+ mer 30 mai 2018 06:10:00 \+0000/, part)
+ assert_match(/expiration[a-z: ]+ mer 10 oct. 2018 03:20:00 \+0000/, part)
+ assert_match "commentaire", part
+ assert_match "/checks/#{check.id}/edit", part
end
end
@@ -188,95 +184,33 @@ class NotificationsMailerTest < ActionMailer::TestCase # rubocop:disable Metrics
end
test "ssl_expires_soon - FR" do
- check = create(:check, :ssl, domain_expires_at: Time.new(2018, 6, 10, 12, 0, 5, "+02:00"))
+ check = create(:check, :ssl,
+ domain_expires_at: Time.new(2018, 6, 10, 12, 0, 5, "+02:00"),
+ user: build(:user, :fr))
notification = build(:notification, interval: 10, check: check, recipient: "colin@example.org")
- I18n.with_locale :fr do
- Date.stub :today, Date.new(2018, 6, 2) do
- mail = NotificationsMailer.with(notification: notification).ssl_expires_soon
+ Date.stub :today, Date.new(2018, 6, 2) do
+ mail = NotificationsMailer.with(notification: notification).ssl_expires_soon
- assert_emails 1 do
- mail.deliver_now
- end
-
- assert_match "domain.fr", mail.subject
- assert_match "SSL", mail.subject
- assert_match "dans 8 jours", mail.subject
- assert_equal ["colin@example.org"], mail.to
- assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from
-
- parts = [mail.text_part.decode_body, mail.html_part.decode_body]
-
- parts.each do |part|
- assert_match "domain.fr", part
- assert_match "dim 10 juin 2018 10:00:05 +0000", part
- assert_match "10 jours", part
- assert_match "/checks/#{check.id}/edit", part
- assert_no_match "commentaire", part
- assert_no_match "fournisseur", part
- end
+ assert_emails 1 do
+ mail.deliver_now
end
- end
- end
- test "ssl_recurrent_failures" do
- last_success_at = Time.new(2018, 5, 30, 6, 10, 0, "+00:00")
- domain_expires_at = Time.new(2018, 10, 10, 7, 20, 0, "+04:00")
- check = build(:check, :ssl, :last_runs_failed,
- domain: "invalid-domain.fr",
- last_success_at: last_success_at,
- domain_expires_at: domain_expires_at,
- comment: "My comment")
- notification = create(:notification, check: check)
-
- mail = NotificationsMailer.with(notification: notification).ssl_recurrent_failures
- assert_match "failures", mail.subject
- assert_match "invalid-domain.fr", mail.subject
- assert_match "SSL", mail.subject
-
- assert_equal ["recipient@domain.fr"], mail.to
- assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from
-
- parts = [mail.text_part.decode_body, mail.html_part.decode_body]
-
- parts.each do |part|
- assert_match "invalid-domain.fr", part
- assert_match "recurrent failures", part
- assert_match(/success[a-z ]+ Wed, 30 May 2018 06:10:00 \+0000/, part)
- assert_match(/expiry[a-z ]+ Wed, 10 Oct 2018 03:20:00 \+0000/, part)
- assert_match "My comment", part
- assert_match "/checks/#{check.id}/edit", part
- end
- end
-
- test "ssl_recurrent_failures - FR" do
- last_success_at = Time.new(2018, 5, 30, 6, 10, 0, "+00:00")
- domain_expires_at = Time.new(2018, 10, 10, 7, 20, 0, "+04:00")
- check = build(:check, :ssl, :last_runs_failed,
- domain: "invalid-domain.fr",
- last_success_at: last_success_at,
- domain_expires_at: domain_expires_at,
- comment: "My comment")
- notification = create(:notification, check: check)
-
- I18n.with_locale :fr do
- mail = NotificationsMailer.with(notification: notification).ssl_recurrent_failures
- assert_match "Erreurs", mail.subject
- assert_match "invalid-domain.fr", mail.subject
+ assert_match "domain.fr", mail.subject
assert_match "SSL", mail.subject
-
- assert_equal ["recipient@domain.fr"], mail.to
+ assert_match "dans 8 jours", mail.subject
+ assert_equal ["colin@example.org"], mail.to
assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from
parts = [mail.text_part.decode_body, mail.html_part.decode_body]
parts.each do |part|
- assert_match "invalid-domain.fr", part
- assert_match "erreurs", part
- assert_match(/réussie[a-z ]+ mer 30 mai 2018 06:10:00 \+0000/, part)
- assert_match(/expiration[a-z ]+ mer 10 oct. 2018 03:20:00 \+0000/, part)
- assert_match "commentaire", part
+ assert_match "domain.fr", part
+ assert_match "dim 10 juin 2018 10:00:05 +0000", part
+ assert_match "10 jours", part
assert_match "/checks/#{check.id}/edit", part
+ assert_no_match "commentaire", part
+ assert_no_match "fournisseur", part
end
end
end
diff --git a/test/mailers/previews/notifications_mailer_preview.rb b/test/mailers/previews/notifications_mailer_preview.rb
index 01f5085..5371b16 100644
--- a/test/mailers/previews/notifications_mailer_preview.rb
+++ b/test/mailers/previews/notifications_mailer_preview.rb
@@ -6,21 +6,16 @@ class NotificationsMailerPreview < ActionMailer::Preview
NotificationsMailer.with(notification: check.notifications.first).domain_expires_soon
end
- # Preview this email at http://localhost:3000/rails/mailers/notifications_mailer/domain_recurrent_failures
- def domain_recurrent_failures
- check = Check.domain.where("last_run_at != last_success_at").first
- NotificationsMailer.with(notification: check.notifications.first).domain_recurrent_failures
- end
-
# Preview this email at http://localhost:3000/rails/mailers/notifications_mailer/ssl_expires_soon
def ssl_expires_soon
check = Check.ssl.first
NotificationsMailer.with(notification: check.notifications.first).ssl_expires_soon
end
- # Preview this email at http://localhost:3000/rails/mailers/notifications_mailer/ssl_recurrent_failures
- def ssl_recurrent_failures
- check = Check.ssl.where("last_run_at != last_success_at").first
- NotificationsMailer.with(notification: check.notifications.first).ssl_recurrent_failures
+ # Preview this email at http://localhost:3000/rails/mailers/notifications_mailer/recurrent_failures
+ def recurrent_failures
+ user = User.first
+ checks = Check.consecutive_failures(2).where(user: user)
+ NotificationsMailer.recurrent_failures(user, checks)
end
end
diff --git a/test/models/check_test.rb b/test/models/check_test.rb
index 9606150..be81d13 100644
--- a/test/models/check_test.rb
+++ b/test/models/check_test.rb
@@ -2,20 +2,21 @@
#
# Table name: checks
#
-# id :bigint(8) not null, primary key
-# active :boolean default(TRUE), not null
-# comment :string(255)
-# domain :string(255) not null
-# domain_created_at :datetime
-# domain_expires_at :datetime
-# domain_updated_at :datetime
-# kind :integer not null
-# last_run_at :datetime
-# last_success_at :datetime
-# vendor :string(255)
-# created_at :datetime not null
-# updated_at :datetime not null
-# user_id :bigint(8)
+# id :bigint(8) not null, primary key
+# active :boolean default(TRUE), not null
+# comment :string(255)
+# consecutive_failures :integer default(0), not null
+# domain :string(255) not null
+# domain_created_at :datetime
+# domain_expires_at :datetime
+# domain_updated_at :datetime
+# kind :integer not null
+# last_run_at :datetime
+# last_success_at :datetime
+# vendor :string(255)
+# created_at :datetime not null
+# updated_at :datetime not null
+# user_id :bigint(8)
#
# Indexes
#
@@ -50,40 +51,6 @@ class CheckTest < ActiveSupport::TestCase
assert_nil notification.sent_at
end
- test "in_error? for recently added" do
- check = build(:check, created_at: 1.day.ago)
- refute check.in_error?
-
- check = build(:check, created_at: 1.day.ago, last_run_at: 3.minutes.ago)
- refute check.in_error?
-
- check = build(:check, created_at: 1.day.ago, last_success_at: 1.hour.ago)
- refute check.in_error?
- end
-
- test "in_error? for never success check, with at least 1 run" do
- check = build(:check, created_at: 3.weeks.ago, last_run_at: 1.day.ago)
- assert check.in_error?
-
- check = build(:check, created_at: 3.weeks.ago, last_run_at: 4.days.ago)
- assert check.in_error?
- end
-
- test "in_error? ignore check without run" do
- check = build(:check, created_at: 3.weeks.ago)
- refute check.in_error?
- end
-
- test "in_error? for last success a few days ago" do
- check = build(:check, created_at: 3.weeks.ago,
- last_success_at: 10.days.ago, last_run_at: 1.day.ago)
- assert check.in_error?
-
- check = build(:check, created_at: 3.weeks.ago,
- last_success_at: 1.days.ago, last_run_at: 1.day.ago)
- refute check.in_error?
- end
-
test "days_from_last_success without any success" do
check = build(:check)
assert_nil check.days_from_last_success
diff --git a/test/services/check_processor_test.rb b/test/services/check_processor_test.rb
index d5c1387..5804366 100644
--- a/test/services/check_processor_test.rb
+++ b/test/services/check_processor_test.rb
@@ -109,8 +109,8 @@ class CheckProcessorTest < ActiveSupport::TestCase
create_list(:check, 3, :expires_next_week)
configuration = Minitest::Mock.new
- 2.times do configuration.expect(:long_term, 60) end
- configuration.expect(:long_term_frequency, 10)
+ 2.times do configuration.expect(:long_term_interval, 300) end
+ configuration.expect(:long_term_frequency, 4)
3.times do
configuration.expect(:interval, 0.000001)
diff --git a/test/services/notifier/channels/base_test.rb b/test/services/notifier/channels/base_test.rb
index 16856e9..aed7653 100644
--- a/test/services/notifier/channels/base_test.rb
+++ b/test/services/notifier/channels/base_test.rb
@@ -5,8 +5,8 @@ module Notifier
class BaseTest < ActiveSupport::TestCase
setup do
class FakeChannel < Base
- def supports?(reason, _notification)
- reason != :unsupported
+ def supports?(notification)
+ notification.interval < 1_000
end
def domain_notify_expires_soon(*); end
@@ -18,7 +18,7 @@ module Notifier
test "#notify change the status of the notification" do
notification = create(:notification)
- @channel.notify(:expires_soon, notification)
+ @channel.notify(notification)
notification.reload
@@ -26,18 +26,30 @@ module Notifier
assert_just_now notification.sent_at
end
- test "#notify raises an exception for a invalid reason" do
- notification = build(:notification)
+ test "#notify raises an exception for a non supported check kind" do
+ notification = Minitest::Mock.new
+ notification.expect :ongoing!, true
+ notification.expect :interval, 10
+
+ check = Minitest::Mock.new
+ check.expect(:kind, :invalid_kind)
+ check.expect(:kind, :invalid_kind) # twice (second call for exception message)
+
+ notification.expect :check, check
+ notification.expect :check, check
assert_raises ArgumentError do
- @channel.notify(:unknown, notification)
+ @channel.notify(notification)
end
+
+ check.verify
+ notification.verify
end
- test "#notify does nothing when channel does not support a reason" do
- notification = create(:notification)
+ test "#notify does nothing when channel doesn't support a notification whatever the reason" do
+ notification = create(:notification, interval: 10_000)
- @channel.notify(:unsupported, notification)
+ @channel.notify(notification)
notification.reload
diff --git a/test/services/notifier/processor_test.rb b/test/services/notifier/processor_test.rb
index c0aeaf6..92b41c1 100644
--- a/test/services/notifier/processor_test.rb
+++ b/test/services/notifier/processor_test.rb
@@ -22,8 +22,10 @@ module Notifier
end
test "#process_recurrent_failures respects the interval configuration between sends" do
- create_list(:notification, 3, :email, check: build(:check, :last_runs_failed))
- test_interval_respected(:process_recurrent_failures, 3)
+ create_list(:check, 3, :last_runs_failed)
+ test_interval_respected(:process_recurrent_failures, 3) do |configuration|
+ configuration.expect(:consecutive_failures, 4.2)
+ end
end
private
@@ -34,6 +36,9 @@ module Notifier
count_expected.times do
configuration.expect(:interval, 0.000001)
end
+
+ yield configuration if block_given?
+
processor = Processor.new(configuration)
mock = Minitest::Mock.new
diff --git a/test/services/notifier/resolver_test.rb b/test/services/notifier/resolver_test.rb
index e43d474..2b291e7 100644
--- a/test/services/notifier/resolver_test.rb
+++ b/test/services/notifier/resolver_test.rb
@@ -6,58 +6,58 @@ module Notifier
@resolver = Notifier::Resolver.new
end
- test "#resolve_expires_soon ignores user having notification disabled" do
+ test "#notifications_expiring_soon ignores user having notification disabled" do
n1 = create(:notification, check: build(:check, :expires_next_week))
n1.check.user.update_attribute(:notifications_enabled, false)
n2 = create(:notification, check: build(:check, :expires_next_week))
- notifications = @resolver.resolve_expires_soon
+ notifications = @resolver.notifications_expiring_soon
assert_not_includes notifications, n1
assert_includes notifications, n2
end
- test "#resolve_expires_soon ignores inactive checks" do
+ test "#notifications_expiring_soon ignores inactive checks" do
n1 = create(:notification, check: build(:check, :expires_next_week, :inactive))
n2 = create(:notification, check: build(:check, :expires_next_week))
- notifications = @resolver.resolve_expires_soon
+ notifications = @resolver.notifications_expiring_soon
assert_not_includes notifications, n1
assert_includes notifications, n2
end
- test "#resolve_expires_soon gets only checks inside interval" do
+ test "#notifications_expiring_soon gets only checks inside interval" do
n1 = create(:notification, check: build(:check, :expires_next_week), interval: 6)
n2 = create(:notification, check: build(:check, :expires_next_week), interval: 7)
- notifications = @resolver.resolve_expires_soon
+ notifications = @resolver.notifications_expiring_soon
assert_not_includes notifications, n1
assert_includes notifications, n2
end
- test "#resolve_expires_soon can gets several notifications for a same check" do
+ test "#notifications_expiring_soon can gets several notifications for a same check" do
check = create(:check, :expires_next_week)
n1 = create(:notification, check: check, interval: 3)
n2 = create(:notification, check: check, interval: 10)
n3 = create(:notification, check: check, interval: 30)
- notifications = @resolver.resolve_expires_soon
+ notifications = @resolver.notifications_expiring_soon
assert_not_includes notifications, n1
assert_includes notifications, n2
assert_includes notifications, n3
end
- test "#resolve_expires_soon takes care of the status" do
+ test "#notifications_expiring_soon takes care of the status" do
check = create(:check, :expires_next_week)
n1 = create(:notification, check: check)
n2 = create(:notification, :failed, check: check)
n3 = create(:notification, :ongoing, check: check)
n4 = create(:notification, :succeed, check: check)
- notifications = @resolver.resolve_expires_soon
+ notifications = @resolver.notifications_expiring_soon
assert_includes notifications, n1
assert_includes notifications, n2
@@ -65,49 +65,51 @@ module Notifier
assert_not_includes notifications, n4
end
- test "#resolve_expires_soon ignores checks expired and without date" do
+ test "#notifications_expiring_soon ignores checks expired and without date" do
n1 = create(:notification, check: build(:check, :expires_next_week))
n2 = create(:notification, check: build(:check, domain_expires_at: 1.week.ago))
n3 = create(:notification, check: build(:check, :nil_dates))
- notifications = @resolver.resolve_expires_soon
+ notifications = @resolver.notifications_expiring_soon
assert_includes notifications, n1
assert_not_includes notifications, n2
assert_not_includes notifications, n3
end
- test "#resolve_check_failed ignores inactive checks" do
- n1 = create(:notification, check: build(:check, :last_runs_failed, :inactive))
- n2 = create(:notification, check: build(:check, :last_runs_failed))
+ test "#checks_recurrent_failures ignores inactive checks" do
+ c1 = create(:check, :last_runs_failed, :inactive)
+ c2 = create(:check, :last_runs_failed)
- notifications = @resolver.resolve_check_failed
+ checks = @resolver.checks_recurrent_failures(4)
- assert_not_includes notifications, n1
- assert_includes notifications, n2
+ assert_not_includes checks, c1
+ assert_includes checks, c2
end
- test "#resolve_check_failed ignores user having notification disabled" do
- n1 = create(:notification, check: build(:check, :last_runs_failed))
- n1.check.user.update_attribute(:notifications_enabled, false)
- n2 = create(:notification, check: build(:check, :last_runs_failed))
+ test "#checks_recurrent_failures ignores user having notification disabled" do
+ c1 = create(:check, :last_runs_failed)
+ c1.user.update_attribute(:notifications_enabled, false)
+ c2 = create(:check, :last_runs_failed)
- notifications = @resolver.resolve_check_failed
+ checks = @resolver.checks_recurrent_failures(4)
- assert_not_includes notifications, n1
- assert_includes notifications, n2
+ assert_not_includes checks, c1
+ assert_includes checks, c2
end
- test "#resolve_check_failed gets only checks having last run in error" do
- n1 = create(:notification, check: build(:check, :nil_dates))
- n2 = create(:notification, check: build(:check, :last_run_succeed))
- n3 = create(:notification, check: build(:check, :last_runs_failed))
+ test "#checks_recurrent_failures gets only checks having consecutive failures" do
+ c1 = create(:check, :nil_dates)
+ c2 = create(:check, :last_run_succeed)
+ c3 = create(:check, :last_runs_failed, consecutive_failures: 5)
+ c4 = create(:check, :last_runs_failed, consecutive_failures: 3)
- notifications = @resolver.resolve_check_failed
+ checks = @resolver.checks_recurrent_failures(4)
- assert_not_includes notifications, n1
- assert_not_includes notifications, n2
- assert_includes notifications, n3
+ assert_not_includes checks, c1
+ assert_not_includes checks, c2
+ assert_not_includes checks, c4
+ assert_includes checks, c3
end
end
end
|