Merge pull request #1338 from betagouv/fix-1309

Fix 1309
This commit is contained in:
Mathieu Magnin 2018-01-30 14:47:32 +01:00 committed by GitHub
commit 3cff988bf3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 95 additions and 67 deletions

View file

@ -64,8 +64,6 @@ gem 'leaflet-rails'
gem 'leaflet-markercluster-rails', '~> 0.7.0'
gem 'leaflet-draw-rails'
gem 'bootstrap-datepicker-rails'
gem 'chartkick'
gem 'logstasher'

View file

@ -93,8 +93,6 @@ GEM
bcrypt (3.1.11)
bindata (2.4.1)
bindex (0.5.0)
bootstrap-datepicker-rails (1.6.4.1)
railties (>= 3.0)
bootstrap-sass (3.3.7)
autoprefixer-rails (>= 5.2.1)
sass (>= 3.3.4)
@ -753,7 +751,6 @@ DEPENDENCIES
active_model_serializers
administrate
apipie-rails
bootstrap-datepicker-rails
bootstrap-sass (~> 3.3.5)
bootstrap-wysihtml5-rails (~> 0.3.3.8)
brakeman

View file

@ -17,8 +17,6 @@
//= require chartkick
//= require_tree ./old_design
//= require bootstrap-sprockets
//= require bootstrap-datepicker/core
//= require bootstrap-datepicker/locales/bootstrap-datepicker.fr.js
//= require leaflet.js
//= require d3.min

View file

@ -46,7 +46,6 @@
// = require attestation_recapitulatif
// = require_self
// = require bootstrap-datepicker3
// = require leaflet
// = require font-awesome
// = require franceconnect

View file

@ -1,5 +1,4 @@
@import "bootstrap";
@import "bootstrap-datepicker3";
#description-page #liste-champs {

View file

@ -19,6 +19,16 @@ class ChampDecorator < Draper::Decorator
end
end
def date_for_input
if object.value.present?
if type_champ == "date"
object.value
elsif type_champ == "datetime" && object.value != ' 00:00'
DateTime.parse(object.value, "%Y-%m-%d %H:%M").strftime("%Y-%m-%d")
end
end
end
def description_with_links
description.gsub(URI.regexp, '<a target="_blank" href="\0">\0</a>') if description
end

View file

@ -6,7 +6,7 @@ class Champ < ActiveRecord::Base
delegate :libelle, :type_champ, :order_place, :mandatory, :description, :drop_down_list, to: :type_de_champ
before_save :format_date_to_iso, if: Proc.new { type_champ == 'date' }
before_save :serialize_datetime_if_needed, if: Proc.new { type_champ == 'datetime' }
before_save :format_datetime, if: Proc.new { type_champ == 'datetime' }
before_save :multiple_select_to_string, if: Proc.new { type_champ == 'multiple_drop_down_list' }
after_save :internal_notification, if: Proc.new { dossier.present? }
@ -17,15 +17,6 @@ class Champ < ActiveRecord::Base
mandatory
end
def data_provide
return 'datepicker' if (type_champ == 'datetime') && !(BROWSER.value.chrome? || BROWSER.value.edge?)
return 'typeahead' if type_champ == 'address'
end
def data_date_format
('dd/mm/yyyy' if type_champ == 'datetime')
end
def same_hour? num
same_date? num, '%H'
end
@ -102,7 +93,7 @@ class Champ < ActiveRecord::Base
self.value = date
end
def serialize_datetime_if_needed
def format_datetime
if (value =~ /=>/).present?
date = begin
hash_date = YAML.safe_load(value.gsub('=>', ': '))
@ -111,8 +102,11 @@ class Champ < ActiveRecord::Base
rescue
nil
end
self.value = date
elsif /^\d{2}\/\d{2}\/\d{4}\s\d{2}:\d{2}$/ =~ value # old browsers can send with dd/mm/yyyy hh:mm format
self.value = DateTime.parse(value, "%d/%m/%Y %H:%M").strftime("%Y-%m-%d %H:%M")
elsif !(/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}$/ =~ value) # a datetime not correctly formatted should not be stored
self.value = nil
end
end

View file

@ -1,5 +1,5 @@
%input.form-control{ name: "champs['#{champ.id}']",
placeholder: "JJ/MM/AAAA",
id: "champs_#{champ.id}",
value: champ.value ? champ.object.value : champ.value,
value: champ.date_for_input,
type: "date" }

View file

@ -1,18 +1,13 @@
%input.form-control{ name: "champs['#{champ.id}']",
placeholder: champ.libelle,
id: "champs_#{champ.id}",
value: (champ.value.split(/[ ][0-9]*:[0-9]*/).first if champ.value.present?),
type: champ.type_champ,
'data-provide' => champ.data_provide,
'data-date-format' => champ.data_date_format }
= render partial: 'users/description/champs/date', locals: { champ: champ }
%select.form-control{ name: "time_hour['#{champ.id}']", style: 'margin-left: 5px;', id: "time_hour_#{champ.id}" }
%br
%select.form-control{ name: "time_hour['#{champ.id}']", style: 'width:70px;display:inline;', id: "time_hour_#{champ.id}" }
- (0..23).each do |num|
- num = "%.2i" %num
%option{ value: num, selected: (:selected if champ.same_hour?(num)) }
= num
h
%select.form-control{ name: "time_minute['#{champ.id}']", id: "time_minute_#{champ.id}" }
%select.form-control{ name: "time_minute['#{champ.id}']", style: 'width:70px;display:inline;', id: "time_minute_#{champ.id}" }
- (0..59).each do |num|
- num = "%.2i" %num
- if num.to_i%5 == 0

View file

@ -0,0 +1,30 @@
namespace :'2018_01_18_clean_datetime_in_champs' do
task clean: :environment do
datetime_champs = TypeDeChamp.where(type_champ: "datetime").flat_map{ |t| t.champ }
# Match " HH:MM" => nil a datetime is not valid if not composed by date AND time
datetime_champs.select { |c| /^\s\d{2}:\d{2}$/.match(c.value) }.each do |c|
puts "cleaning #{c.value} => nil"
c.update_columns(value: nil)
end
# Match "dd/mm/YYYY HH:MM" => "YYYY-mm-dd HH:MM"
datetime_champs.select { |c| /^\d{2}\/\d{2}\/\d{4}\s\d{2}:\d{2}$/ =~ c.value }.each do |c|
formated_date = DateTime.parse(c.value, "%d/%m/%Y %H:%M").strftime("%Y-%m-%d %H:%M")
puts "cleaning #{c.value} => #{formated_date}"
c.update_columns(value: formated_date)
end
# Match "ddmmYYYY HH:MM" => "YYYY-mm-dd HH:MM"
datetime_champs.select { |c| /^\d{8}\s\d{2}:\d{2}$/ =~ c.value }.each do |c|
day = c.value[0,2]
month = c.value[2,2]
year = c.value[4,4]
hours = c.value[9,2]
minutes = c.value[12,2]
formated_date = "#{year}-#{month}-#{day} #{hours}:#{minutes}"
puts "cleaning #{c.value} => #{formated_date}"
c.update_columns(value: formated_date)
end
end
end

View file

@ -249,7 +249,7 @@ shared_examples 'description_controller_spec' do
describe 'Sauvegarde des champs' do
let(:champs_dossier) { dossier.champs }
let(:dossier_text_value) { 'test value' }
let(:dossier_date_value) { '23/06/2016' }
let(:dossier_date_value) { '2018-01-31' }
let(:dossier_hour_value) { '17' }
let(:dossier_minute_value) { '00' }
let(:dossier_datetime_champ_id) { dossier.champs.find { |c| c.type_champ == "datetime" }.id }

View file

@ -61,4 +61,36 @@ describe ChampDecorator do
end
end
end
describe '#date_for_input' do
subject { decorator.date_for_input }
describe "for a date" do
let(:type_champ) { :date }
context "when value is an ISO date" do
before { champ.update value: "2017-12-31" }
it { is_expected.to eq "2017-12-31" }
end
context "when value is empty" do
before { champ.update value: nil }
it { is_expected.to eq nil }
end
end
describe "for a datetime" do
let(:type_champ) { :date }
context "when value is an formatted datetime" do
before { champ.update value: "2017-12-30 23:17" }
it { is_expected.to eq "2017-12-30" }
end
context "when value is empty" do
before { champ.update value: nil }
it { is_expected.to eq nil }
end
end
end
end

View file

@ -26,28 +26,6 @@ shared_examples 'champ_spec' do
end
end
describe 'data_provide' do
let(:champ) { create :champ }
subject { champ.data_provide }
context 'when type_champ is datetime' do
before do
champ.type_de_champ = create :type_de_champ_public, type_champ: 'datetime'
end
it { is_expected.to eq 'datepicker' }
end
context 'when type_champ is address' do
before do
champ.type_de_champ = create :type_de_champ_public, type_champ: 'address'
end
it { is_expected.to eq 'typeahead' }
end
end
describe '.departement', vcr: { cassette_name: 'call_geo_api_departements' } do
subject { Champ.departements }

View file

@ -5,24 +5,22 @@ describe Champ do
it_should_behave_like "champ_spec"
describe '#serialize_datetime_if_needed' do
describe '#format_datetime' do
let(:type_de_champ) { TypeDeChamp.new(type_champ: 'datetime') }
let(:champ) { Champ.new(type_de_champ: type_de_champ, value: value) }
before { champ.save }
# when using the old form, and the ChampsService Class
# TODO: to remove
context 'when the value is already serialized' do
let(:value) { '12/01/2017 10:23' }
context 'when the value is sent by a modern browser' do
let(:value) { '2017-12-31 10:23' }
it { expect(champ.value).to eq(value) }
end
context 'when the value is not already serialized' do
let(:value) { '{ 1=>2017, 2=>01, 3=>12, 4=>10, 5=>23 }' }
context 'when the value is sent by a old browser' do
let(:value) { '31/12/2018 09:26' }
it { expect(champ.value).to eq('12/01/2017 10:23') }
it { expect(champ.value).to eq('2018-12-31 09:26') }
end
end

View file

@ -179,10 +179,10 @@ describe TagsSubstitutionConcern, type: :model do
dossier.champs
.select { |champ| champ.type_champ == 'datetime' }
.first
.update_attributes(value: '13/09/2017 09:00')
.update_attributes(value: '2017-09-13 09:00')
end
it { is_expected.to eq('15/04/2017 13/09/2017 09:00') }
it { is_expected.to eq('15/04/2017 2017-09-13 09:00') }
end
end
end

View file

@ -28,7 +28,7 @@ describe ChampsService do
end
it 'parses and save the date' do
expect(champ_datetime.value).to eq('d 12:24')
expect(champ_datetime.value).to eq(nil)
end
end

View file

@ -66,7 +66,7 @@ describe 'users/description/show.html.haml', type: :view do
let(:champ_datetime) { champs.where(type_de_champ_id: types_de_champ.id).first }
before do
champ_datetime.value = "22/06/2016 12:05"
champ_datetime.value = "2016-06-22 12:05"
champ_datetime.save
render
end
@ -82,7 +82,7 @@ describe 'users/description/show.html.haml', type: :view do
end
describe 'datetime value is correctly setup when is not nil' do
it { expect(rendered).to have_css("input[type='datetime'][id='champs_#{champ_datetime.id}'][value='22/06/2016']") }
it { expect(rendered).to have_css("input[type='date'][id='champs_#{champ_datetime.id}'][value='2016-06-22']") }
it { expect(rendered).to have_css("option[value='12'][selected='selected']") }
it { expect(rendered).to have_css("option[value='05'][selected='selected']") }
end