mirror of
https://github.com/Evolix/chexpire.git
synced 2024-04-27 06:20:50 +02:00
Merge pull request #90 from Evolix/unsupported-whois
Manual mode for unsupported TLDs
This commit is contained in:
commit
0f3571b3bb
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
class ChecksController < ApplicationController
|
class ChecksController < ApplicationController
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
before_action :set_check, except: [:index, :new, :create]
|
before_action :set_check, except: [:index, :new, :create, :supports]
|
||||||
after_action :verify_authorized, except: :index
|
after_action :verify_authorized, except: :index
|
||||||
after_action :verify_policy_scoped, only: :index
|
after_action :verify_policy_scoped, only: :index
|
||||||
|
|
||||||
|
@ -65,6 +65,11 @@ class ChecksController < ApplicationController
|
||||||
redirect_to checks_path
|
redirect_to checks_path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def supports
|
||||||
|
@check = Check.new(new_check_params)
|
||||||
|
authorize @check
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_check
|
def set_check
|
||||||
|
@ -82,7 +87,7 @@ class ChecksController < ApplicationController
|
||||||
|
|
||||||
def check_params(*others)
|
def check_params(*others)
|
||||||
params.require(:check)
|
params.require(:check)
|
||||||
.permit(:domain, :domain_created_at, :comment, :vendor, :round_robin, *others,
|
.permit(:domain, :domain_expires_at, :comment, :vendor, :round_robin, *others,
|
||||||
notifications_attributes: [:id, :channel, :recipient, :interval])
|
notifications_attributes: [:id, :channel, :recipient, :interval])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
57
app/frontend/components/check_validation.js
Normal file
57
app/frontend/components/check_validation.js
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright (C) 2018 Colin Darie <colin@darie.eu>, 2018 Evolix <info@evolix.fr>
|
||||||
|
// License: GNU AGPL-3+ (see full text in LICENSE file)
|
||||||
|
|
||||||
|
function checkValidationInitialize() {
|
||||||
|
const element = document.getElementById("check_domain");
|
||||||
|
|
||||||
|
if (element && element.dataset.kind == "domain") {
|
||||||
|
addEventSupportListener(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addEventSupportListener(element) {
|
||||||
|
element.addEventListener("blur", event => {
|
||||||
|
const request = $.ajax("/checks/supports.json", {
|
||||||
|
method: "post",
|
||||||
|
dataType: "json",
|
||||||
|
data: {
|
||||||
|
check: {
|
||||||
|
domain: event.target.value,
|
||||||
|
kind: element.dataset.kind,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
request.done(response => {
|
||||||
|
const { supported } = response.check;
|
||||||
|
|
||||||
|
toggleUnsupportedContainers(supported);
|
||||||
|
setFocus(supported);
|
||||||
|
|
||||||
|
// set normalized domain
|
||||||
|
element.value = response.check.domain;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleUnsupportedContainers(supported) {
|
||||||
|
const containerClass = supported ? "d-none" : "d-block";
|
||||||
|
|
||||||
|
document.getElementById("check_domain_expires_at_container").className = containerClass;
|
||||||
|
|
||||||
|
const domainHint = document.getElementById("check_domain_unsupported_container");
|
||||||
|
domainHint.classList.remove("d-none");
|
||||||
|
domainHint.classList.remove("d-block");
|
||||||
|
domainHint.classList.add(containerClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function setFocus(supported) {
|
||||||
|
if (supported) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("check_domain_expires_at").focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default checkValidationInitialize;
|
|
@ -20,9 +20,13 @@ import 'bootstrap/js/dist/tooltip';
|
||||||
|
|
||||||
import '../scss';
|
import '../scss';
|
||||||
|
|
||||||
|
import checkValidationInitialize from '../components/check_validation';
|
||||||
|
|
||||||
Rails.start()
|
Rails.start()
|
||||||
Turbolinks.start()
|
Turbolinks.start()
|
||||||
|
|
||||||
document.addEventListener("turbolinks:load", () => {
|
document.addEventListener("turbolinks:load", () => {
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
|
|
||||||
|
checkValidationInitialize();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (C) 2018 Colin Darie <colin@darie.eu>, 2018 Evolix <info@evolix.fr>
|
// Copyright (C) 2018 Colin Darie <colin@darie.eu>, 2018 Evolix <info@evolix.fr>
|
||||||
// License: GNU AGPL-3+ (see full text in LICENSE file)
|
// License: GNU AGPL-3+ (see full text in LICENSE file)
|
||||||
|
|
||||||
$input-placeholder-color: #013d3a;
|
$input-placeholder-color: #b9bbbb;
|
||||||
$enable-rounded: false;
|
$enable-rounded: false;
|
||||||
$theme-colors: (
|
$theme-colors: (
|
||||||
"primary": #118b83, //light-green
|
"primary": #118b83, //light-green
|
||||||
|
|
|
@ -20,9 +20,6 @@ class WhoisSyncJob < ApplicationJob
|
||||||
return unless response.valid?
|
return unless response.valid?
|
||||||
|
|
||||||
update_from_response(response)
|
update_from_response(response)
|
||||||
rescue Whois::DomainNotFoundError
|
|
||||||
check.active = false
|
|
||||||
check.save!
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_from_response(response)
|
def update_from_response(response)
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
# kind :integer not null
|
# kind :integer not null
|
||||||
# last_run_at :datetime
|
# last_run_at :datetime
|
||||||
# last_success_at :datetime
|
# last_success_at :datetime
|
||||||
|
# mode :integer default("auto"), not null
|
||||||
# round_robin :boolean default(TRUE)
|
# round_robin :boolean default(TRUE)
|
||||||
# vendor :string(255)
|
# vendor :string(255)
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
|
@ -39,6 +40,7 @@ class Check < ApplicationRecord
|
||||||
reject_if: lambda { |at| at["recipient"].blank? && at["interval"].blank? }
|
reject_if: lambda { |at| at["recipient"].blank? && at["interval"].blank? }
|
||||||
|
|
||||||
enum kind: [:domain, :ssl]
|
enum kind: [:domain, :ssl]
|
||||||
|
enum mode: [:auto, :manual]
|
||||||
|
|
||||||
self.skip_time_zone_conversion_for_attributes = [
|
self.skip_time_zone_conversion_for_attributes = [
|
||||||
:domain_created_at,
|
:domain_created_at,
|
||||||
|
@ -50,10 +52,12 @@ class Check < ApplicationRecord
|
||||||
validates :domain, presence: true
|
validates :domain, presence: true
|
||||||
validate :domain_created_at_past
|
validate :domain_created_at_past
|
||||||
validate :domain_updated_at_past
|
validate :domain_updated_at_past
|
||||||
|
validates :domain_expires_at, presence: true, unless: :supported?
|
||||||
validates :comment, length: { maximum: 255 }
|
validates :comment, length: { maximum: 255 }
|
||||||
validates :vendor, length: { maximum: 255 }
|
validates :vendor, length: { maximum: 255 }
|
||||||
|
|
||||||
before_save :reset_consecutive_failures
|
before_save :reset_consecutive_failures
|
||||||
|
before_save :set_mode
|
||||||
after_update :reset_notifications
|
after_update :reset_notifications
|
||||||
after_save :enqueue_sync
|
after_save :enqueue_sync
|
||||||
|
|
||||||
|
@ -84,6 +88,20 @@ class Check < ApplicationRecord
|
||||||
save!
|
save!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def supported?
|
||||||
|
return true unless domain?
|
||||||
|
return true if domain.blank?
|
||||||
|
|
||||||
|
begin
|
||||||
|
Whois::Parser.for(domain)
|
||||||
|
true
|
||||||
|
rescue Whois::UnsupportedDomainError
|
||||||
|
false
|
||||||
|
rescue StandardError
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def domain_created_at_past
|
def domain_created_at_past
|
||||||
|
@ -113,4 +131,9 @@ class Check < ApplicationRecord
|
||||||
|
|
||||||
self.consecutive_failures = 0
|
self.consecutive_failures = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_mode
|
||||||
|
return unless domain_changed?
|
||||||
|
self.mode = supported? ? :auto : :manual
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,6 +20,10 @@ class CheckPolicy < ApplicationPolicy
|
||||||
owner?
|
owner?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def supports?
|
||||||
|
new?
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def owner?
|
def owner?
|
||||||
|
|
|
@ -54,6 +54,7 @@ module CheckProcessor
|
||||||
def base_scope
|
def base_scope
|
||||||
Check
|
Check
|
||||||
.active
|
.active
|
||||||
|
.auto
|
||||||
.where("last_run_at IS NULL OR last_run_at < DATE_SUB(NOW(), INTERVAL 12 HOUR)")
|
.where("last_run_at IS NULL OR last_run_at < DATE_SUB(NOW(), INTERVAL 12 HOUR)")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,33 @@
|
||||||
<%= simple_form_for(check) do |f| %>
|
<%= simple_form_for(check) do |f| %>
|
||||||
<%= f.input :domain,
|
<%= f.input :domain,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
input_html: { autocapitalize: :none, autocorrect: :off },
|
input_html: { autocapitalize: :none, autocorrect: :off, data: { kind: check.kind } },
|
||||||
label: t(".#{check.kind || "generic" }.domain") %>
|
label: t(".#{check.kind || "generic" }.domain"),
|
||||||
|
hint: t(".#{check.kind || "generic" }.unsupported"),
|
||||||
|
hint_html: {
|
||||||
|
id: "check_domain_unsupported_container",
|
||||||
|
class: "#{check.supported? && 'd-none'}",
|
||||||
|
}
|
||||||
|
%>
|
||||||
|
|
||||||
<% if check.new_record? %>
|
<% if check.new_record? %>
|
||||||
<%= f.input :kind, as: check.kind.present? ? :hidden : :radio_buttons, collection: Check.kinds.keys %>
|
<%= f.input :kind, as: check.kind.present? ? :hidden : :radio_buttons, collection: Check.kinds.keys %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
<div id="check_domain_expires_at_container" class="<%= check.supported? ? "d-none" : "d-block" %>">
|
||||||
|
<%= f.input :domain_expires_at,
|
||||||
|
required: true,
|
||||||
|
input_html: {
|
||||||
|
type: :date,
|
||||||
|
value: check.domain_expires_at&.to_date,
|
||||||
|
min: Date.yesterday,
|
||||||
|
max: 10.years.from_now.end_of_year.to_date
|
||||||
|
},
|
||||||
|
as: :string,
|
||||||
|
placeholder: t(".domain_expires_at_placeholder")
|
||||||
|
%>
|
||||||
|
</div>
|
||||||
|
|
||||||
<%= f.input :comment %>
|
<%= f.input :comment %>
|
||||||
<%= f.input :vendor %>
|
<%= f.input :vendor %>
|
||||||
|
|
||||||
|
|
7
app/views/checks/supports.json.jbuilder
Normal file
7
app/views/checks/supports.json.jbuilder
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Copyright (C) 2018 Colin Darie <colin@darie.eu>, 2018 Evolix <info@evolix.fr>
|
||||||
|
# License: GNU AGPL-3+ (see full text in LICENSE file)
|
||||||
|
|
||||||
|
json.check do
|
||||||
|
json.supported @check.supported?
|
||||||
|
json.domain normalize_domain(@check.domain)
|
||||||
|
end
|
|
@ -72,17 +72,17 @@ en:
|
||||||
sign_in: "Log in"
|
sign_in: "Log in"
|
||||||
sign_out: "Log out"
|
sign_out: "Log out"
|
||||||
profile: "Profile"
|
profile: "Profile"
|
||||||
home_header:
|
home_header:
|
||||||
welcome: "Chexpire"
|
welcome: "Chexpire"
|
||||||
intro: "Never forget to renew a domain name or SSL certificate."
|
intro: "Never forget to renew a domain name or SSL certificate."
|
||||||
beta_banner:
|
beta_banner:
|
||||||
beta_info: "Chexpire is in \"beta\" release: only few TLD (.com/.net/.org/.fr) are verified for domain name checks and TLS 1.2 is not supported for SSL checks."
|
beta_info: "Chexpire is in \"beta\" release: only few TLD (.com/.net/.org/.fr) are verified for domain name checks and TLS 1.2 is not supported for SSL checks."
|
||||||
issue_link: "Please report issues."
|
issue_link: "Please report issues."
|
||||||
|
|
||||||
pages:
|
pages:
|
||||||
|
|
||||||
home:
|
home:
|
||||||
why: "Why Chexpire?"
|
why: "Why Chexpire?"
|
||||||
description: "Chexpire is a Free Software (AGPLv3 license) to manage the expiration of domain names and SSL certificates. It is primarily an ergonomic web interface that allows you easily to add new domain names/SSL certificates to monitor, and custom/unlimited notifications to be notified before expiration."
|
description: "Chexpire is a Free Software (AGPLv3 license) to manage the expiration of domain names and SSL certificates. It is primarily an ergonomic web interface that allows you easily to add new domain names/SSL certificates to monitor, and custom/unlimited notifications to be notified before expiration."
|
||||||
centralization: "Centralize all your expiry dates"
|
centralization: "Centralize all your expiry dates"
|
||||||
centralization-details: "Do you have domain names at different registrars? many Let's Encrypt SSL certificates with automatic renewal? You will enjoy everything centralized in a web interface: adding a domain name/SSL certificate in two clicks, sorted list, search bar etc."
|
centralization-details: "Do you have domain names at different registrars? many Let's Encrypt SSL certificates with automatic renewal? You will enjoy everything centralized in a web interface: adding a domain name/SSL certificate in two clicks, sorted list, search bar etc."
|
||||||
|
@ -119,6 +119,10 @@ en:
|
||||||
domain: Domain
|
domain: Domain
|
||||||
domain:
|
domain:
|
||||||
domain: Domain name
|
domain: Domain name
|
||||||
|
unsupported: |
|
||||||
|
This top-level domain isn't currently automatically supported.
|
||||||
|
You'll have to fill and maintain yourself the expiry date.
|
||||||
|
domain_expires_at_placeholder: YYYY-MM-DD.
|
||||||
ssl:
|
ssl:
|
||||||
domain: Hostname
|
domain: Hostname
|
||||||
notifications_hint: |
|
notifications_hint: |
|
||||||
|
|
|
@ -11,6 +11,7 @@ fr:
|
||||||
kind: Type
|
kind: Type
|
||||||
domain_created_at: "Date de création"
|
domain_created_at: "Date de création"
|
||||||
domain_updated_at: "Date de modification"
|
domain_updated_at: "Date de modification"
|
||||||
|
domain_expires_at: "Date d'expiration"
|
||||||
notification:
|
notification:
|
||||||
interval: Délai
|
interval: Délai
|
||||||
recipient: Destinataire
|
recipient: Destinataire
|
||||||
|
@ -104,17 +105,17 @@ fr:
|
||||||
sign_in: "Connexion"
|
sign_in: "Connexion"
|
||||||
sign_out: "Déconnexion"
|
sign_out: "Déconnexion"
|
||||||
profile: "Profil"
|
profile: "Profil"
|
||||||
home_header:
|
home_header:
|
||||||
welcome: "Chexpire"
|
welcome: "Chexpire"
|
||||||
intro: "vous n'oublierez plus jamais de renouveler un nom de domaine ou un certificat SSL."
|
intro: "vous n'oublierez plus jamais de renouveler un nom de domaine ou un certificat SSL."
|
||||||
beta_banner:
|
beta_banner:
|
||||||
beta_info: "Chexpire est en version \"beta\" : seuls certains TLD (.com/.net/.org/.fr) sont vérifiés pour les noms de domaine et TLS 1.2 n'est pas supporté pour les vérifications SSL."
|
beta_info: "Chexpire est en version \"beta\" : seuls certains TLD (.com/.net/.org/.fr) sont vérifiés pour les noms de domaine et TLS 1.2 n'est pas supporté pour les vérifications SSL."
|
||||||
issue_link: "Merci de nous reporter bugs et suggestions."
|
issue_link: "Merci de nous reporter bugs et suggestions."
|
||||||
|
|
||||||
pages:
|
pages:
|
||||||
|
|
||||||
home:
|
home:
|
||||||
why: "Pourquoi Chexpire ?"
|
why: "Pourquoi Chexpire ?"
|
||||||
description: "Chexpire est un Logiciel Libre (licence AGPLv3) permettant de gérer l'expiration de noms de domaine et de certificats SSL. C'est avant tout une interface web ergonomique permettant d'ajouter simplement de nouveaux noms de domaine/certificats SSL à surveiller, et des notifications sur mesure et illimitées pour être averti·e avant expiration."
|
description: "Chexpire est un Logiciel Libre (licence AGPLv3) permettant de gérer l'expiration de noms de domaine et de certificats SSL. C'est avant tout une interface web ergonomique permettant d'ajouter simplement de nouveaux noms de domaine/certificats SSL à surveiller, et des notifications sur mesure et illimitées pour être averti·e avant expiration."
|
||||||
centralization: "Centralisez toutes vos dates d'expiration"
|
centralization: "Centralisez toutes vos dates d'expiration"
|
||||||
centralization-details: "Vous avez des noms de domaine chez différents registrars ? de nombreux certificats SSL Let's Encrypt en renouvellement automatique ? Vous allez apprécier de tout centraliser simplement dans une interface web : ajout d'un nom de domaine/certificat SSL en deux clics, liste récapitulative triée, barre de recherche etc."
|
centralization-details: "Vous avez des noms de domaine chez différents registrars ? de nombreux certificats SSL Let's Encrypt en renouvellement automatique ? Vous allez apprécier de tout centraliser simplement dans une interface web : ajout d'un nom de domaine/certificat SSL en deux clics, liste récapitulative triée, barre de recherche etc."
|
||||||
|
@ -151,6 +152,10 @@ fr:
|
||||||
domain: Domaine
|
domain: Domaine
|
||||||
domain:
|
domain:
|
||||||
domain: Nom de domaine
|
domain: Nom de domaine
|
||||||
|
unsupported: |
|
||||||
|
Cette extension n'est pas supportée automatiquement actuellement.
|
||||||
|
Vous devrez saisir et maintenir vous-même sa date d'expiration.
|
||||||
|
domain_expires_at_placeholder: AAAA-MM-JJ
|
||||||
ssl:
|
ssl:
|
||||||
domain: Nom d'hôte
|
domain: Nom d'hôte
|
||||||
notifications_hint: |
|
notifications_hint: |
|
||||||
|
|
|
@ -1,10 +1,29 @@
|
||||||
# Copyright (C) 2018 Colin Darie <colin@darie.eu>, 2018 Evolix <info@evolix.fr>
|
# Copyright (C) 2018 Colin Darie <colin@darie.eu>, 2018 Evolix <info@evolix.fr>
|
||||||
# License: GNU AGPL-3+ (see full text in LICENSE file)
|
# License: GNU AGPL-3+ (see full text in LICENSE file)
|
||||||
|
|
||||||
|
# In order to update the route map below,
|
||||||
|
# run `bundle exec annotate -r` after modifying this file
|
||||||
|
Rails.application.routes.draw do
|
||||||
|
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
|
||||||
|
|
||||||
|
resources :checks, except: [:show] do
|
||||||
|
resources :notifications, only: [:destroy]
|
||||||
|
collection do
|
||||||
|
post :supports, format: :json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
devise_for :users
|
||||||
|
root to: "pages#home"
|
||||||
|
|
||||||
|
mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
|
||||||
|
end
|
||||||
|
|
||||||
# == Route Map
|
# == Route Map
|
||||||
#
|
#
|
||||||
# Prefix Verb URI Pattern Controller#Action
|
# Prefix Verb URI Pattern Controller#Action
|
||||||
# check_notification DELETE /checks/:check_id/notifications/:id(.:format) notifications#destroy
|
# check_notification DELETE /checks/:check_id/notifications/:id(.:format) notifications#destroy
|
||||||
|
# supports_checks POST /checks/supports(.:format) checks#supports
|
||||||
# checks GET /checks(.:format) checks#index
|
# checks GET /checks(.:format) checks#index
|
||||||
# POST /checks(.:format) checks#create
|
# POST /checks(.:format) checks#create
|
||||||
# new_check GET /checks/new(.:format) checks#new
|
# new_check GET /checks/new(.:format) checks#new
|
||||||
|
@ -37,25 +56,10 @@
|
||||||
# rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show
|
# rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show
|
||||||
# update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update
|
# update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update
|
||||||
# rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create
|
# rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create
|
||||||
#
|
#
|
||||||
# Routes for LetterOpenerWeb::Engine:
|
# Routes for LetterOpenerWeb::Engine:
|
||||||
# clear_letters DELETE /clear(.:format) letter_opener_web/letters#clear
|
# clear_letters DELETE /clear(.:format) letter_opener_web/letters#clear
|
||||||
# delete_letter DELETE /:id(.:format) letter_opener_web/letters#destroy
|
# delete_letter DELETE /:id(.:format) letter_opener_web/letters#destroy
|
||||||
# letters GET / letter_opener_web/letters#index
|
# letters GET / letter_opener_web/letters#index
|
||||||
# letter GET /:id(/:style)(.:format) letter_opener_web/letters#show
|
# letter GET /:id(/:style)(.:format) letter_opener_web/letters#show
|
||||||
# GET /:id/attachments/:file(.:format) letter_opener_web/letters#attachment
|
# GET /:id/attachments/:file(.:format) letter_opener_web/letters#attachment
|
||||||
|
|
||||||
# In order to update the route map above,
|
|
||||||
# run `bundle exec annotate -r` after modifying this file
|
|
||||||
Rails.application.routes.draw do
|
|
||||||
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
|
|
||||||
|
|
||||||
resources :checks, except: [:show] do
|
|
||||||
resources :notifications, only: [:destroy]
|
|
||||||
end
|
|
||||||
|
|
||||||
devise_for :users
|
|
||||||
root to: "pages#home"
|
|
||||||
|
|
||||||
mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
|
|
||||||
end
|
|
||||||
|
|
5
db/migrate/20180829134404_add_mode_to_checks.rb
Normal file
5
db/migrate/20180829134404_add_mode_to_checks.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
class AddModeToChecks < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
add_column :checks, :mode, :integer, default: 0, null: false
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2018_08_01_072038) do
|
ActiveRecord::Schema.define(version: 2018_08_29_134404) do
|
||||||
|
|
||||||
create_table "check_logs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
|
create_table "check_logs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
|
||||||
t.bigint "check_id"
|
t.bigint "check_id"
|
||||||
|
@ -40,6 +40,7 @@ ActiveRecord::Schema.define(version: 2018_08_01_072038) do
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.boolean "round_robin", default: true
|
t.boolean "round_robin", default: true
|
||||||
t.integer "consecutive_failures", default: 0, null: false
|
t.integer "consecutive_failures", default: 0, null: false
|
||||||
|
t.integer "mode", default: 0, null: false
|
||||||
t.index ["user_id"], name: "index_checks_on_user_id"
|
t.index ["user_id"], name: "index_checks_on_user_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ if Rails.env.development?
|
||||||
# same name.
|
# same name.
|
||||||
Annotate.set_defaults(
|
Annotate.set_defaults(
|
||||||
'routes' => 'before',
|
'routes' => 'before',
|
||||||
'position_in_routes' => 'before',
|
'position_in_routes' => 'after',
|
||||||
'position_in_class' => 'before',
|
'position_in_class' => 'before',
|
||||||
'position_in_test' => 'before',
|
'position_in_test' => 'before',
|
||||||
'position_in_fixture' => 'before',
|
'position_in_fixture' => 'before',
|
||||||
|
|
14
lib/tasks/one_shot.rake
Normal file
14
lib/tasks/one_shot.rake
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
namespace :one_shot do
|
||||||
|
desc "Set manual mode for unsupported checks"
|
||||||
|
task reset_checks_modes: :environment do
|
||||||
|
Check.domain.find_each do |check|
|
||||||
|
check.mode = if check.supported?
|
||||||
|
:auto
|
||||||
|
else
|
||||||
|
:manual
|
||||||
|
end
|
||||||
|
|
||||||
|
check.save(validate: false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -15,6 +15,7 @@
|
||||||
# kind :integer not null
|
# kind :integer not null
|
||||||
# last_run_at :datetime
|
# last_run_at :datetime
|
||||||
# last_success_at :datetime
|
# last_success_at :datetime
|
||||||
|
# mode :integer default("auto"), not null
|
||||||
# round_robin :boolean default(TRUE)
|
# round_robin :boolean default(TRUE)
|
||||||
# vendor :string(255)
|
# vendor :string(255)
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
|
@ -44,6 +45,7 @@ FactoryBot.define do
|
||||||
last_run_at nil
|
last_run_at nil
|
||||||
last_success_at nil
|
last_success_at nil
|
||||||
consecutive_failures 0
|
consecutive_failures 0
|
||||||
|
mode :auto
|
||||||
|
|
||||||
trait :domain do
|
trait :domain do
|
||||||
kind :domain
|
kind :domain
|
||||||
|
|
|
@ -24,7 +24,6 @@ class WhoisSyncJobTest < ActiveJob::TestCase
|
||||||
|
|
||||||
test "ignore invalid response (domain.fr)" do
|
test "ignore invalid response (domain.fr)" do
|
||||||
check = create(:check, :nil_dates, domain: "domain.fr")
|
check = create(:check, :nil_dates, domain: "domain.fr")
|
||||||
original_updated_at = check.updated_at
|
|
||||||
|
|
||||||
mock_system_command("whois", "domain.fr", stdout: "not a response") do
|
mock_system_command("whois", "domain.fr", stdout: "not a response") do
|
||||||
WhoisSyncJob.perform_now(check.id)
|
WhoisSyncJob.perform_now(check.id)
|
||||||
|
@ -34,7 +33,6 @@ class WhoisSyncJobTest < ActiveJob::TestCase
|
||||||
|
|
||||||
assert_just_now check.last_run_at
|
assert_just_now check.last_run_at
|
||||||
assert_nil check.last_success_at
|
assert_nil check.last_success_at
|
||||||
assert_equal original_updated_at, check.updated_at
|
|
||||||
assert check.active?
|
assert check.active?
|
||||||
assert_equal 1, check.consecutive_failures
|
assert_equal 1, check.consecutive_failures
|
||||||
end
|
end
|
||||||
|
@ -62,7 +60,7 @@ class WhoisSyncJobTest < ActiveJob::TestCase
|
||||||
assert_equal 1, check.consecutive_failures
|
assert_equal 1, check.consecutive_failures
|
||||||
end
|
end
|
||||||
|
|
||||||
test "disable check when whois responds domain not found" do
|
test "increment consecutive failures when whois responds domain not found" do
|
||||||
domain = "willneverexist.fr"
|
domain = "willneverexist.fr"
|
||||||
check = create(:check, :nil_dates, domain: domain)
|
check = create(:check, :nil_dates, domain: domain)
|
||||||
|
|
||||||
|
@ -72,7 +70,6 @@ class WhoisSyncJobTest < ActiveJob::TestCase
|
||||||
|
|
||||||
check.reload
|
check.reload
|
||||||
|
|
||||||
refute check.active?
|
|
||||||
assert_just_now check.last_run_at
|
assert_just_now check.last_run_at
|
||||||
assert_nil check.last_success_at
|
assert_nil check.last_success_at
|
||||||
assert_equal 1, check.consecutive_failures
|
assert_equal 1, check.consecutive_failures
|
||||||
|
|
|
@ -71,4 +71,34 @@ class CheckTest < ActiveSupport::TestCase
|
||||||
check = build(:check, last_success_at: (10.1 * 24).hours.ago)
|
check = build(:check, last_success_at: (10.1 * 24).hours.ago)
|
||||||
assert_equal 10, check.days_from_last_success
|
assert_equal 10, check.days_from_last_success
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "supported? for domain" do
|
||||||
|
check = build(:check, :domain, domain: "domain.fr")
|
||||||
|
assert check.supported?
|
||||||
|
|
||||||
|
check = build(:check, :domain, domain: "domain.cn")
|
||||||
|
refute check.supported?
|
||||||
|
|
||||||
|
# an empty domain name is still considered as supported
|
||||||
|
check = build(:check, :domain, domain: "")
|
||||||
|
assert check.supported?
|
||||||
|
end
|
||||||
|
|
||||||
|
test "supported? for SSL" do
|
||||||
|
check = build(:check, :ssl)
|
||||||
|
assert check.supported?
|
||||||
|
|
||||||
|
check = build(:check, :ssl, domain: "domain.cn")
|
||||||
|
assert check.supported?
|
||||||
|
end
|
||||||
|
|
||||||
|
test "set mode before saving" do
|
||||||
|
check = build(:check, domain: "domain.fr")
|
||||||
|
check.save!
|
||||||
|
assert check.auto?
|
||||||
|
|
||||||
|
check.domain = "domain.xyz"
|
||||||
|
check.save!
|
||||||
|
assert check.mode?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -108,6 +108,16 @@ class CheckProcessorTest < ActiveSupport::TestCase
|
||||||
assert_not_includes checks, c2
|
assert_not_includes checks, c2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "resolvers does not include manual checks" do
|
||||||
|
c1 = create(:check, :expires_next_week)
|
||||||
|
c2 = create(:check, :expires_next_week, domain: "fff.wxyz")
|
||||||
|
|
||||||
|
checks = @processor.resolve_expire_short_term
|
||||||
|
|
||||||
|
assert_includes checks, c1
|
||||||
|
assert_not_includes checks, c2
|
||||||
|
end
|
||||||
|
|
||||||
test "#sync_dates respects the interval configuration between sends" do
|
test "#sync_dates respects the interval configuration between sends" do
|
||||||
create_list(:check, 3, :expires_next_week)
|
create_list(:check, 3, :expires_next_week)
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,26 @@ class ChecksTest < ApplicationSystemTestCase
|
||||||
fill_and_valid_new_check
|
fill_and_valid_new_check
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "create a manual domain check" do
|
||||||
|
visit new_check_path(kind: :domain)
|
||||||
|
|
||||||
|
domain = "unsupported.wxyz"
|
||||||
|
fill_in("check[domain]", with: domain)
|
||||||
|
|
||||||
|
page.find("body").click # simulate blur
|
||||||
|
fill_in("check[domain_expires_at]", with: "2022-04-05")
|
||||||
|
|
||||||
|
click_button
|
||||||
|
|
||||||
|
assert_equal checks_path, page.current_path
|
||||||
|
|
||||||
|
assert page.has_css?(".alert-success")
|
||||||
|
assert page.has_content?(domain)
|
||||||
|
|
||||||
|
check = Check.last
|
||||||
|
assert_equal Date.new(2022, 4, 5), check.domain_expires_at
|
||||||
|
end
|
||||||
|
|
||||||
test "create a predefined ssl check" do
|
test "create a predefined ssl check" do
|
||||||
visit new_check_path(kind: :ssl)
|
visit new_check_path(kind: :ssl)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue