21
1
Fork 0
mirror of https://github.com/Evolix/chexpire.git synced 2024-05-06 18:48:38 +02:00

Manual expiray date support for unsupported domain

Validation is made when leaving the input field with an ajax call on the
/checks/support.json path. JSON response include the normalized domain
name (more TODO) and the supported status.
UI is updated with Javascript accordingly to this response.

Closes #62
This commit is contained in:
Colin Darie 2018-08-29 16:42:00 +02:00
parent ef1229d900
commit 09be8a38c2
No known key found for this signature in database
GPG key ID: 4FB865FDBCA4BCC4
12 changed files with 165 additions and 29 deletions

View file

@ -3,7 +3,7 @@
class ChecksController < ApplicationController
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_policy_scoped, only: :index
@ -65,6 +65,11 @@ class ChecksController < ApplicationController
redirect_to checks_path
end
def supports
@check = Check.new(new_check_params)
authorize @check
end
private
def set_check
@ -81,7 +86,7 @@ class ChecksController < ApplicationController
end
def check_params(*others)
params.require(:check).permit(:domain, :domain_created_at, :comment, :vendor, *others,
params.require(:check).permit(:domain, :domain_expires_at, :comment, :vendor, *others,
notifications_attributes: [:id, :channel, :recipient, :interval])
end

View 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;

View file

@ -20,9 +20,13 @@ import 'bootstrap/js/dist/tooltip';
import '../scss';
import checkValidationInitialize from '../components/check_validation';
Rails.start()
Turbolinks.start()
document.addEventListener("turbolinks:load", () => {
$('[data-toggle="tooltip"]').tooltip();
checkValidationInitialize();
});

View file

@ -51,6 +51,7 @@ class Check < ApplicationRecord
validates :domain, presence: true
validate :domain_created_at_past
validate :domain_updated_at_past
validates :domain_expires_at, presence: true, unless: :supported?
validates :comment, length: { maximum: 255 }
validates :vendor, length: { maximum: 255 }

View file

@ -20,6 +20,10 @@ class CheckPolicy < ApplicationPolicy
owner?
end
def supports?
new?
end
private
def owner?

View file

@ -3,13 +3,34 @@
<%= simple_form_for(check) do |f| %>
<%= f.input :domain,
autofocus: true,
input_html: { autocapitalize: :none, autocorrect: :off },
label: t(".#{check.kind || "generic" }.domain") %>
input_html: { autocapitalize: :none, autocorrect: :off, data: { kind: check.kind } },
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? %>
<%= f.input :kind, as: check.kind.present? ? :hidden : :radio_buttons, collection: Check.kinds.keys %>
<% 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: :string,
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"),
hint: t(".domain_expires_at_hint")
%>
</div>
<%= f.input :comment %>
<%= f.input :vendor %>

View 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

View file

@ -119,6 +119,12 @@ en:
domain: Domain
domain:
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_hint: |
Fill the expiry date in YYYY-MM-DD format.
domain_expires_at_placeholder: YYYY-MM-DD.
ssl:
domain: Hostname
notifications_hint: |

View file

@ -11,6 +11,7 @@ fr:
kind: Type
domain_created_at: "Date de création"
domain_updated_at: "Date de modification"
domain_expires_at: "Date d'expiration"
notification:
interval: Délai
recipient: Destinataire
@ -151,6 +152,12 @@ fr:
domain: Domaine
domain:
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_hint: |
Renseignez la date d'expiration au format AAAA-MM-JJ.
domain_expires_at_placeholder: AAAA-MM-JJ
ssl:
domain: Nom d'hôte
notifications_hint: |

View file

@ -1,10 +1,29 @@
# Copyright (C) 2018 Colin Darie <colin@darie.eu>, 2018 Evolix <info@evolix.fr>
# 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
#
# Prefix Verb URI Pattern Controller#Action
# 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
# POST /checks(.:format) checks#create
# new_check GET /checks/new(.:format) checks#new
@ -44,18 +63,3 @@
# letters GET / letter_opener_web/letters#index
# letter GET /:id(/:style)(.:format) letter_opener_web/letters#show
# 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

View file

@ -8,7 +8,7 @@ if Rails.env.development?
# same name.
Annotate.set_defaults(
'routes' => 'before',
'position_in_routes' => 'before',
'position_in_routes' => 'after',
'position_in_class' => 'before',
'position_in_test' => 'before',
'position_in_fixture' => 'before',

View file

@ -25,6 +25,26 @@ class ChecksTest < ApplicationSystemTestCase
fill_and_valid_new_check
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
visit new_check_path(kind: :ssl)