diff options
| author | Luc Donnet | 2017-07-26 10:10:57 +0200 |
|---|---|---|
| committer | Luc Donnet | 2017-07-26 10:10:57 +0200 |
| commit | a486dbe65187aade64c998e21dae139f8bccc6d1 (patch) | |
| tree | 4f25b8c5c08b7acd784db197440d1cf27632e7be | |
| parent | a692df1c4c336a971219f714bee01a156f4cf8e9 (diff) | |
| parent | cada0f02d732dce25492d7f7eb6d6232d56188dd (diff) | |
| download | chouette-core-a486dbe65187aade64c998e21dae139f8bccc6d1.tar.bz2 | |
Merge branch 'master' into 4161_StopPoints_RouteEdit
23 files changed, 391 insertions, 115 deletions
diff --git a/app/assets/javascripts/cleanup.coffee b/app/assets/javascripts/cleanup.coffee index 7e291aa9e..41aa1ff15 100644 --- a/app/assets/javascripts/cleanup.coffee +++ b/app/assets/javascripts/cleanup.coffee @@ -4,11 +4,16 @@ $(document).on("change", 'input[name="clean_up[date_type]"]', (e) -> if type == 'before' end_date.hide() - $("label[for='clean_up_begin_date_3i']").html("Date de fin de la purge"); + $('label.begin_date').addClass 'hidden' + $('label.end_date').removeClass 'hidden' + else if type == 'after' end_date.hide() - $("label[for='clean_up_begin_date_3i']").html("Date de début de la purge"); + $('label.begin_date').removeClass 'hidden' + $('label.end_date').addClass 'hidden' + else - $("label[for='clean_up_begin_date_3i']").html("Date de début de la purge"); + $('label.begin_date').removeClass 'hidden' + $('label.end_date').addClass 'hidden' end_date.show() ) diff --git a/app/controllers/time_tables_controller.rb b/app/controllers/time_tables_controller.rb index 6849b1592..0054963c9 100644 --- a/app/controllers/time_tables_controller.rb +++ b/app/controllers/time_tables_controller.rb @@ -35,7 +35,7 @@ class TimeTablesController < ChouetteController def create tt_params = time_table_params - if tt_params[:calendar_id] + if tt_params[:calendar_id] && tt_params[:calendar_id] != "" %i(monday tuesday wednesday thursday friday saturday sunday).map { |d| tt_params[d] = true } calendar = Calendar.find(tt_params[:calendar_id]) tt_params[:calendar_id] = nil if tt_params.has_key?(:dates_attributes) || tt_params.has_key?(:periods_attributes) diff --git a/app/helpers/breadcrumb_helper.rb b/app/helpers/breadcrumb_helper.rb index 1f8690f38..55031d4f3 100644 --- a/app/helpers/breadcrumb_helper.rb +++ b/app/helpers/breadcrumb_helper.rb @@ -73,13 +73,13 @@ module BreadcrumbHelper end def calendar_breadcrumb(action) - add_breadcrumb I18n.t('breadcrumbs.referentials'), referentials_path + add_breadcrumb I18n.t('breadcrumbs.referentials'), workbenches_path add_breadcrumb I18n.t('calendars.index.title'), calendars_path add_breadcrumb @calendar.name if %i(show edit).include? action end def workbench_breadcrumb(action) - add_breadcrumb I18n.t("breadcrumbs.referentials"), referentials_path + add_breadcrumb I18n.t("breadcrumbs.referentials"), workbenches_path add_breadcrumb breadcrumb_label(@workbench), workbench_path(@workbench), :title => breadcrumb_tooltip(@workbench) end @@ -215,7 +215,7 @@ module BreadcrumbHelper end def import_breadcrumb (action) - add_breadcrumb I18n.t("breadcrumbs.referentials"), referentials_path + add_breadcrumb I18n.t("breadcrumbs.referentials"), workbenches_path add_breadcrumb breadcrumb_label(@workbench), workbench_path(@workbench), :title => breadcrumb_tooltip(@workbench) add_breadcrumb I18n.t("breadcrumbs.imports"), workbench_imports_path(@workbench) @@ -257,7 +257,7 @@ module BreadcrumbHelper end def organisation_breadcrumb (action = :index) - add_breadcrumb I18n.t("breadcrumbs.referentials"), referentials_path + add_breadcrumb I18n.t("breadcrumbs.referentials"), workbenches_path add_breadcrumb breadcrumb_label(@organisation), organisation_path,:title => breadcrumb_tooltip(@organisation) unless action == :index end diff --git a/app/models/chouette/line.rb b/app/models/chouette/line.rb index 33a2fbb00..63d2d1606 100644 --- a/app/models/chouette/line.rb +++ b/app/models/chouette/line.rb @@ -1,5 +1,5 @@ class Chouette::Line < Chouette::ActiveRecord - include DefaultNetexAttributesSupport + include StifCodifligneAttributesSupport include LineRestrictions include LineReferentialSupport include StifTransportModeEnumerations diff --git a/app/models/chouette/stif_codifligne_objectid.rb b/app/models/chouette/stif_codifligne_objectid.rb new file mode 100644 index 000000000..46109e24f --- /dev/null +++ b/app/models/chouette/stif_codifligne_objectid.rb @@ -0,0 +1,18 @@ +class Chouette::StifCodifligneObjectid < String + + @@format = /^([A-Za-z_]+):([A-Za-z]+):([A-Za-z]+):([0-9A-Za-z_-]+)$/ + cattr_reader :format + + def parts + match(format).try(:captures) + end + + def object_type + parts.try(:third) + end + + def local_id + parts.try(:fourth) + end + +end diff --git a/app/models/chouette/stif_reflex_objectid.rb b/app/models/chouette/stif_reflex_objectid.rb new file mode 100644 index 000000000..c41a9325a --- /dev/null +++ b/app/models/chouette/stif_reflex_objectid.rb @@ -0,0 +1,18 @@ +class Chouette::StifReflexObjectid < String + + @@format = /^([A-Za-z_]+):([0-9A-Za-z_-]+):([A-Za-z]+):([0-9A-Za-z_-]+):([A-Za-z]+)$/ + cattr_reader :format + + def parts + match(format).try(:captures) + end + + def object_type + parts.try(:third) + end + + def local_id + parts.try(:fourth) + end + +end diff --git a/app/models/chouette/stop_area.rb b/app/models/chouette/stop_area.rb index 4d98027d6..43bc82f7f 100644 --- a/app/models/chouette/stop_area.rb +++ b/app/models/chouette/stop_area.rb @@ -4,20 +4,16 @@ require 'geo_ruby' class Chouette::StopArea < Chouette::ActiveRecord # FIXME http://jira.codehaus.org/browse/JRUBY-6358 self.primary_key = "id" + include Geokit::Mappable + include StifReflexAttributesSupport include ProjectionFields include StopAreaRestrictions + include StopAreaReferentialSupport extend Enumerize enumerize :area_type, in: %i(zdep zder zdlp zdlr lda) - def self.model_name - ActiveModel::Name.new self, Chouette, self.name.demodulize - end - # Refs #1627 - # include DefaultAttributesSupport - include StopAreaReferentialSupport - with_options dependent: :destroy do |assoc| assoc.has_many :stop_points assoc.has_many :access_points @@ -57,13 +53,6 @@ class Chouette::StopArea < Chouette::ActiveRecord after_update :clean_invalid_access_links before_save :coordinates_to_lat_lng - # Refs #1627 - before_validation :prepare_auto_columns - def prepare_auto_columns - self.object_version = 1 - self.creator_id = 'chouette' - end - def combine_lat_lng if self.latitude.nil? || self.longitude.nil? "" diff --git a/app/models/chouette/time_table.rb b/app/models/chouette/time_table.rb index d907d797e..713ce0b21 100644 --- a/app/models/chouette/time_table.rb +++ b/app/models/chouette/time_table.rb @@ -38,26 +38,26 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord validates_associated :periods def continuous_dates + in_days = self.dates.where(in_out: true).sort_by(&:date) chunk = {} group = nil - self.dates.where(in_out: true).each_with_index do |date, index| + in_days.each_with_index do |date, index| group ||= index - group = (date.date == dates[index - 1].date + 1.day) ? group : group + 1 + group = (date.date == in_days[index - 1].date + 1.day) ? group : group + 1 chunk[group] ||= [] chunk[group] << date end - chunk.values + # Remove less than 2 continuous day chunk + chunk.values.delete_if {|dates| dates.count < 2} end def convert_continuous_dates_to_periods chunks = self.continuous_dates - # Remove less than 3 continuous day chunk - chunks.delete_if {|chunk| chunk.count < 3} transaction do chunks.each do |chunk| self.periods.create!(period_start: chunk.first.date, period_end: chunk.last.date) - chunk.map(&:destroy) + self.dates.delete(chunk) end end end @@ -415,7 +415,7 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord def clone_periods periods = [] self.periods.each { |p| periods << p.copy} - periods + periods.sort_by(&:period_start) end def included_days @@ -436,7 +436,7 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord # produce a copy of periods without anyone overlapping or including another - def optimize_periods + def optimize_overlapping_periods periods = self.clone_periods optimized = [] i=0 @@ -461,6 +461,59 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord optimized.sort { |a,b| a.period_start <=> b.period_start} end + def continuous_periods + periods = self.periods.sort_by(&:period_start) + chunk = {} + group = nil + periods.each_with_index do |period, index| + group ||= index + group = (period.period_start - 1.day == periods[index - 1].period_end) ? group : group + 1 + chunk[group] ||= [] + chunk[group] << period + end + chunk.values.delete_if {|periods| periods.count < 2} + end + + def convert_continuous_periods_into_one + chunks = self.continuous_periods + + transaction do + chunks.each do |chunk| + self.periods.create!(period_start: chunk.first.period_start, period_end: chunk.last.period_end) + self.periods.delete chunk + end + end + end + + #update a period if a in_day is just before or after + def optimize_continuous_dates_and_periods + return self.periods if self.included_days.empty? || periods.empty? + + periods = self.clone_periods + optimized = [] + + i = 0 + while i < periods.length + period = periods[i] + j = 0 + in_days = self.reload.dates.where(in_out: true).sort_by(&:date) + while j < in_days.length + day = in_days[j] + if period.period_start - 1.day === day.date + period.period_start = day.date + self.dates.delete day + elsif period.period_end + 1.day === day.date + period.period_end = day.date + self.dates.delete day + end + j += 1 + end + i += 1 + optimized << period + end + optimized + end + # add a peculiar day or switch it from excluded to included def add_included_day(d) if self.excluded_date?(d) @@ -478,22 +531,27 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord def merge!(another_tt) transaction do self.periods = another_tt.clone_periods + self.periods - self.periods = self.optimize_periods # For included dates another_tt.included_days.map{ |d| add_included_day(d) } # For excluded dates - existing_out_date = self.dates.where(in_out: false).map(&:date) - another_tt.dates.where(in_out: false).each do |d| - unless existing_out_date.include?(d.date) - self.dates << Chouette::TimeTableDate.new(:date => d.date, :in_out => false) + self.dates.where(in_out: false).each do |d| + self.dates.delete d if another_tt.include_in_periods?(d.date) && !another_tt.excluded_date?(d.date) + end + + another_tt.excluded_days.each do |d| + unless self.reload.excluded_date?(d) + self.dates << Chouette::TimeTableDate.new(date: d, in_out: false) end + self.save! end - self.save! - end - self.convert_continuous_dates_to_periods + self.convert_continuous_dates_to_periods + self.periods = self.optimize_continuous_dates_and_periods + self.convert_continuous_periods_into_one + self.periods = self.optimize_overlapping_periods + end end def included_days_in_dates_and_periods diff --git a/app/models/concerns/stif_codifligne_attributes_support.rb b/app/models/concerns/stif_codifligne_attributes_support.rb new file mode 100644 index 000000000..d4370e505 --- /dev/null +++ b/app/models/concerns/stif_codifligne_attributes_support.rb @@ -0,0 +1,21 @@ +module StifCodifligneAttributesSupport + extend ActiveSupport::Concern + + included do + validates_presence_of :objectid + end + + module ClassMethods + def object_id_key + model_name + end + + def model_name + ActiveModel::Name.new self, Chouette, self.name.demodulize + end + end + + def objectid + Chouette::StifCodifligneObjectid.new read_attribute(:objectid).to_s + end +end diff --git a/app/models/concerns/stif_reflex_attributes_support.rb b/app/models/concerns/stif_reflex_attributes_support.rb new file mode 100644 index 000000000..e6236a146 --- /dev/null +++ b/app/models/concerns/stif_reflex_attributes_support.rb @@ -0,0 +1,21 @@ +module StifReflexAttributesSupport + extend ActiveSupport::Concern + + included do + validates_presence_of :objectid + end + + module ClassMethods + def object_id_key + model_name + end + + def model_name + ActiveModel::Name.new self, Chouette, self.name.demodulize + end + end + + def objectid + Chouette::StifReflexObjectid.new read_attribute(:objectid).to_s + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 64d66883f..c2aa14bda 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -29,29 +29,6 @@ class User < ActiveRecord::Base scope :with_organisation, -> { where.not(organisation_id: nil) } - def self.destructive_permissions_for(models) - models.product( %w{create destroy update} ).map{ |model_action| model_action.join('.') } - end - - @@edit_offer_permissions = - destructive_permissions_for( %w[ - access_points - connection_links - calendars - footnotes - journey_patterns - referentials - routes - routing_constraint_zones - time_tables - vehicle_journeys - ]) << 'boiv:edit-offer' - - mattr_reader :edit_offer_permissions - - def self.all_permissions - edit_offer_permissions - end # Callback invoked by DeviseCasAuthenticable::Model#authernticate_with_cas_ticket def cas_extra_attributes=(extra_attributes) @@ -59,7 +36,7 @@ class User < ActiveRecord::Base self.name = extra[:full_name] self.email = extra[:email] self.organisation = Organisation.sync_update extra[:organisation_code], extra[:organisation_name], extra[:functional_scope] - self.permissions = extra[:permissions].include?('boiv:edit-offer') ? @@edit_offer_permissions : [] + self.permissions = Stif::PermissionTranslator.translate(extra[:permissions]) end def self.portail_api_request @@ -87,7 +64,7 @@ class User < ActiveRecord::Base user.locked_at = el['locked_at'] user.organisation = Organisation.sync_update el['organization_code'], el['organization_name'], el['functional_scope'] user.synced_at = Time.now - user.permissions = el['permissions'].include?('boiv:edit-offer') ? @@edit_offer_permissions : [] + user.permissions = Stif::PermissionTranslator.translate(el['permissions']) user.save end end diff --git a/app/policies/login_policy.rb b/app/policies/login_policy.rb index 3364c37ac..5b07b97f3 100644 --- a/app/policies/login_policy.rb +++ b/app/policies/login_policy.rb @@ -7,7 +7,7 @@ class LoginPolicy end def boiv? - !(user.permissions || []).grep(%r{\Aboiv:.}).empty? + (user.permissions || []).include?('sessions:create') end end diff --git a/app/views/referentials/show.html.slim b/app/views/referentials/show.html.slim index d3687c3a7..425f8014a 100644 --- a/app/views/referentials/show.html.slim +++ b/app/views/referentials/show.html.slim @@ -91,9 +91,13 @@ .row .col-lg-8.col-ld-offset-2.col-md-8.col-md-offset-2.col-sm-8.col-sm-offset-2.col-xs-12 = f.input :date_type, as: :radio_buttons, label: false - = f.input :begin_date, as: :date, label: t('titles.clean_up.begin_date'),:wrapper_html => { class: 'date smart_date', title: t('titles.clean_up.begin_date') } - = f.input :end_date, as: :date, label: t('titles.clean_up.end_date'), :wrapper_html => { class: 'date cleanup_end_date_wrapper smart_date', title: t('titles.clean_up.end_date'), id: "end_date" } + .col-lg-8.col-ld-offset-2.col-md-8.col-md-offset-2.col-sm-8.col-sm-offset-2.col-xs-12 + label.control-label.begin_date = t('titles.clean_up.begin_date') + label.control-label.end_date.hidden = t('titles.clean_up.end_date') + = f.input :begin_date, as: :date, label: false, wrapper_html: { class: 'date smart_date' } + + = f.input :end_date, as: :date, label: t('titles.clean_up.end_date'), wrapper_html: { class: 'date cleanup_end_date_wrapper smart_date', id: "end_date" } .modal-footer button.btn.btn-link type='button' data-dismiss='modal' Annuler diff --git a/app/views/workbenches/show.html.slim b/app/views/workbenches/show.html.slim index bb8b71ab2..a9ce2f704 100644 --- a/app/views/workbenches/show.html.slim +++ b/app/views/workbenches/show.html.slim @@ -7,8 +7,8 @@ / Below is secundary actions & optional contents (filters, ...) .row.mb-sm .col-lg-12.text-right - = link_to t('actions.import'), workbench_imports_path(@workbench), class: 'btn btn-primary' - if policy(Referential).create? + = link_to t('actions.import'), workbench_imports_path(@workbench), class: 'btn btn-primary' = link_to t('actions.add'), new_referential_path(workbench_id: @workbench), class: 'btn btn-primary' / PageContent diff --git a/lib/stif/permission_translator.rb b/lib/stif/permission_translator.rb index 7032f910a..afe69756e 100644 --- a/lib/stif/permission_translator.rb +++ b/lib/stif/permission_translator.rb @@ -1,7 +1,45 @@ module Stif module PermissionTranslator extend self + def translate(sso_extra_permissions) - %w{sessions:create} + sso_extra_permissions + .sort + .flat_map(&method(:extra_permission_translation)) + .uniq + end + + private + + def all_destructive_permissions + destructive_permissions_for( all_resources ) + end + + def all_resources + %w[ + access_points + connection_links calendars + footnotes + journey_patterns + referentials routes routing_constraint_zones + time_tables + vehicle_journeys + ] + end + + def destructive_permissions_for(models) + @__destructive_permissions_for__ ||= + models.product( %w{create destroy update} ).map{ |model_action| model_action.join('.') } + end + + def extra_permission_translation extra_permission + translation_table.fetch(extra_permission, []) + end + + def translation_table + { + "boiv:read-offer" => %w{sessions:create}, + "boiv:edit-offer" => all_destructive_permissions + %w{sessions:create}, + } end end end diff --git a/spec/controllers/devise/cas_sessions_controller_spec.rb b/spec/controllers/devise/cas_sessions_controller_spec.rb index 950d141fd..c82fd2cdb 100644 --- a/spec/controllers/devise/cas_sessions_controller_spec.rb +++ b/spec/controllers/devise/cas_sessions_controller_spec.rb @@ -1,25 +1,37 @@ RSpec.describe Devise::CasSessionsController, type: :controller do - login_user + before do + @user = signed_in_user + allow_any_instance_of(Warden::Proxy).to receive(:authenticate).and_return @user + allow_any_instance_of(Warden::Proxy).to receive(:authenticate!).and_return @user + @request.env["devise.mapping"] = Devise.mappings[:user] + end + context 'login is correctly redirected' do + let( :signed_in_user ){ build_stubbed :user } it 'to #service' do get :new - expect(response).to redirect_to(unauthenticated_root_path) + expect( response ).to be_redirect + expect( response.redirect_url ).to eq("http://stif-portail-dev.af83.priv/sessions/login?service=http%3A%2F%2Ftest.host%2Fusers%2Fservice") end end - context 'user does not have any boiv:.+ permission' do - xit 'cannot login and will be redirected to the login page, with a corresponding message' do + context 'user does not have permission sessions:create' do + let( :signed_in_user ){ build_stubbed :user } + + it 'cannot login and will be redirected to the login page, with a corresponding message' do get :service expect(controller).to set_flash[:alert].to(%r{IBOO}) - expect(response).to redirect_to("http://stif-portail-dev.af83.priv/sessions/login?service=http%3A%2F%2Ftest.host%2Fusers%2Fservice") + expect(response).to redirect_to "http://stif-portail-dev.af83.priv/sessions/logout?service=http%3A%2F%2Ftest.host%2Fusers%2Fservice" end end - context 'user does have a boiv:.+ permission' do + context 'user does have permission sessions:create' do + let( :signed_in_user ){ build_stubbed :allmighty_user } + it 'can login and will be redirected to the referentials page' do - @user.update_attribute :permissions, (@user.permissions << 'boiv:UnameIt') + @user.permissions << 'sessions:create' get :service expect(response).to redirect_to(authenticated_root_path) end diff --git a/spec/lib/stif/permission_translator_spec.rb b/spec/lib/stif/permission_translator_spec.rb index 3672c7937..1af21364c 100644 --- a/spec/lib/stif/permission_translator_spec.rb +++ b/spec/lib/stif/permission_translator_spec.rb @@ -1,10 +1,45 @@ RSpec.describe Stif::PermissionTranslator do - context "SSO Permission boiv:read:offer →" do + context "No SSO Permissions" do + it { expect(described_class.translate([])).to be_empty } + end + + context "SSO Permission boiv:read-offer →" do it "sessions:create only" do - expect( described_class.translate(%w{boiv:read:offer}) ).to eq(%w{sessions:create}) + expect( described_class.translate(%w{boiv:read-offer}) ).to eq(%w{sessions:create}) + end + + end + + context "SSO Permission boiv:edit-offer →" do + + it "all permissions" do + expect( described_class.translate(%w{boiv:edit-offer}) ).to eq(Support::Permissions.all_permissions) + end + + it "all permissions, no doubletons" do + expect( described_class.translate(%w{boiv:edit-offer boiv:read-offer}) ).to eq(Support::Permissions.all_permissions) end + it "all permissions, input order agnostic" do + expect( described_class.translate(%w{boiv:read-offer boiv:edit-offer}) ).to eq(Support::Permissions.all_permissions) + end + end + + context "SSO Permission ignores garbage (no injection) →" do + it "remains empty" do + expect( described_class.translate(%w{referentials.create}) ).to be_empty + end + + it "remains at boiv:read-offer level" do + expect( described_class.translate(%w{referentials.create boiv:read-offer calendars.delete}) ).to eq(%w{sessions:create}) + end + + it "does not add garbage or doubletons for boiv:edit-offer level" do + expect( + described_class.translate(%w{xxx boiv:read-offer lines.delete boiv:edit-offer footnotes.update}) + ).to eq(Support::Permissions.all_permissions) + end end end diff --git a/spec/models/chouette/line_spec.rb b/spec/models/chouette/line_spec.rb index 5a339e7ed..2e5882012 100644 --- a/spec/models/chouette/line_spec.rb +++ b/spec/models/chouette/line_spec.rb @@ -1,17 +1,12 @@ require 'spec_helper' describe Chouette::Line, :type => :model do - subject { create(:line) } - it { is_expected.to belong_to(:line_referential) } + it { should belong_to(:line_referential) } # it { is_expected.to validate_presence_of :network } # it { is_expected.to validate_presence_of :company } - - it { is_expected.to validate_presence_of :name } - - # it { should validate_presence_of :objectid } - it { is_expected.to validate_uniqueness_of :objectid } + it { should validate_presence_of :name } describe '#display_name' do it 'should display local_id, number, name and company name' do @@ -22,7 +17,7 @@ describe Chouette::Line, :type => :model do describe '#objectid' do subject { super().objectid } - it { is_expected.to be_kind_of(Chouette::NetexObjectId) } + it { is_expected.to be_kind_of(Chouette::StifCodifligneObjectid) } end # it { should validate_numericality_of :objectversion } diff --git a/spec/models/chouette/stop_area_spec.rb b/spec/models/chouette/stop_area_spec.rb index 1a2ff8ede..293ae5202 100644 --- a/spec/models/chouette/stop_area_spec.rb +++ b/spec/models/chouette/stop_area_spec.rb @@ -7,16 +7,15 @@ describe Chouette::StopArea, :type => :model do let!(:commercial_stop_point) { create :stop_area, :area_type => "lda" } let!(:stop_place) { create :stop_area, :area_type => "zdlp" } - # Refs #1627 - # describe '#objectid' do - # subject { super().objectid } - # it { is_expected.to be_kind_of(Chouette::ObjectId) } - # end - - it { is_expected.to belong_to(:stop_area_referential) } - it { is_expected.to validate_presence_of :name } - it { is_expected.to validate_numericality_of :latitude } - it { is_expected.to validate_numericality_of :longitude } + describe '#objectid' do + subject { super().objectid } + it { should be_kind_of(Chouette::StifReflexObjectid) } + end + + it { should belong_to(:stop_area_referential) } + it { should validate_presence_of :name } + it { should validate_numericality_of :latitude } + it { should validate_numericality_of :longitude } # describe ".latitude" do # it "should accept -90 value" do diff --git a/spec/models/chouette/time_table_spec.rb b/spec/models/chouette/time_table_spec.rb index bd74a2d4c..304cb0184 100644 --- a/spec/models/chouette/time_table_spec.rb +++ b/spec/models/chouette/time_table_spec.rb @@ -14,6 +14,8 @@ describe Chouette::TimeTable, :type => :model do describe "#merge! with time_table" do let(:another_tt) { create(:time_table) } let(:another_tt_periods_to_range) { another_tt.periods.map{|p| p.period_start..p.period_end } } + let(:dates) { another_tt.dates.map(&:date) } + let(:continuous_dates) { another_tt.continuous_dates.flatten.map(&:date) } # Make sur we don't have overlapping periods or dates before do @@ -22,12 +24,19 @@ describe Chouette::TimeTable, :type => :model do p.period_end = p.period_end + 1.year end another_tt.dates.each{| d| d.date = d.date + 1.year } + another_tt.save end it 'should merge dates' do subject.dates.clear subject.merge!(another_tt) - expect(subject.dates.map(&:date)).to include(*another_tt.dates.map(&:date)) + expect(subject.dates.map(&:date)).to match_array(dates - continuous_dates) + end + + it 'should not merge continuous dates' do + subject.dates.clear + subject.merge!(another_tt) + expect(subject.dates.map(&:date)).not_to include(*continuous_dates) end it 'should merge periods' do @@ -50,28 +59,42 @@ describe Chouette::TimeTable, :type => :model do subject.merge!(another_tt) expect(subject.dates.map(&:date)).to include(another_tt.dates.last.date) end + + it 'should remove date in_out false if other tt doesnt have them' do + subject.dates.create(in_out: false, date: Date.today + 5.day + 1.year) + + expect { + subject.merge!(another_tt) + }.to change {subject.reload.excluded_days.count}.by(-1) + end end context "#merge! with calendar" do let(:calendar) { create(:calendar, date_ranges: [Date.today + 1.year..Date.tomorrow + 1.year]) } + let(:another_tt) { calendar.convert_to_time_table } + let(:dates) { subject.dates.map(&:date) } + let(:continuous_dates) { subject.continuous_dates.flatten.map(&:date) } it 'should merge calendar dates' do subject.dates.clear - subject.merge!(calendar.convert_to_time_table) - expect(subject.dates.map(&:date)).to include(*calendar.dates) + subject.merge!(another_tt) + expect(subject.dates.map(&:date)).to match_array(dates - continuous_dates) + end + + it 'should not merge calendar continuous dates' do + subject.dates.clear + subject.merge!(another_tt) + expect(subject.dates.map(&:date)).not_to include(*continuous_dates) end it 'should merge calendar periods with no periods in source' do subject.periods.clear - another_tt = calendar.convert_to_time_table subject.merge!(another_tt) expect(subject_periods_to_range).to include(*calendar.date_ranges) end it 'should add calendar periods with existing periods in source' do - another_tt = calendar.convert_to_time_table subject.merge!(another_tt) - expect(subject_periods_to_range).to include(*calendar.date_ranges) end end @@ -1109,7 +1132,7 @@ end - describe "#optimize_periods" do + describe "#optimize_overlapping_periods" do before do subject.periods.clear subject.periods << Chouette::TimeTablePeriod.new( @@ -1127,7 +1150,7 @@ end subject.int_day_types = 4|8|16 end it "should return 2 ordered periods" do - periods = subject.optimize_periods + periods = subject.optimize_overlapping_periods expect(periods.size).to eq(2) expect(periods[0].period_start).to eq(Date.new(2014, 6, 1)) expect(periods[0].period_end).to eq(Date.new(2014, 6, 14)) diff --git a/spec/models/time_table_combination_spec.rb b/spec/models/time_table_combination_spec.rb index 3e60fa444..ee934f50d 100644 --- a/spec/models/time_table_combination_spec.rb +++ b/spec/models/time_table_combination_spec.rb @@ -8,30 +8,93 @@ describe TimeTableCombination, :type => :model do describe '#continuous_dates' do it 'should group continuous dates' do dates = source.dates.where(in_out: true) - expect(source.continuous_dates[0].count).to eq(dates.count) + expect(source.continuous_dates.flatten.count).to eq(dates.count) - # 6 more continuous date, 1 isolated date + # 6 more continuous dates, 2 isolated dates (10..15).each do |n| source.dates.create(date: Date.today + n.day, in_out: true) end - source.dates.create(date: Date.today + 1.year, in_out: true) + + (1..2).each do |n| + source.dates.create(date: Date.today + n.day + 1.year, in_out: true) + end + expect(source.reload.continuous_dates[1].count).to eq(6) - expect(source.reload.continuous_dates[2].count).to eq(1) + expect(source.reload.continuous_dates[2].count).to eq(2) end end describe '#convert_continuous_dates_to_periods' do it 'should convert continuous dates to periods' do + source.dates.clear + (10..12).each do |n| source.dates.create(date: Date.today + n.day, in_out: true) end - source.dates.create(date: Date.today + 1.year, in_out: true) + + (1..3).each do |n| + source.dates.create(date: Date.today + n.day + 1.year, in_out: true) + end expect { source.reload.convert_continuous_dates_to_periods }.to change {source.periods.count}.by(2) - expect(source.reload.dates.where(in_out: true).count).to eq(1) + expect(source.reload.dates.where(in_out: true).count).to eq(0) + end + end + + describe '#continuous_periods' do + it 'should group continuous periods' do + source.periods.clear + + start_date = Date.today + 1.year + end_date = start_date + 10 + + # 6 more continuous dates, 2 isolated dates + 0.upto(4) do |i| + source.periods.create(period_start: start_date, period_end: end_date) + start_date = end_date + 1 + end_date = start_date + 10 + end + + expect(source.reload.continuous_periods.flatten.count).to eq(5) + end + end + + describe '#convert_continuous_periods_into_one' do + it 'should convert continuous periods into one' do + source.periods.clear + + start_date = Date.today + 1.year + end_date = start_date + 10 + + # 6 more continuous dates, 2 isolated dates + 0.upto(4) do |i| + source.periods.create(period_start: start_date, period_end: end_date) + start_date = end_date + 1 + end_date = start_date + 10 + end + + expect { + source.reload.convert_continuous_periods_into_one + }.to change {source.periods.count}.by(-4) + end + end + + describe '#optimize_continuous_dates_and_periods' do + it 'should update period if timetable has in_date just before or after ' do + source.dates.clear + source.periods.clear + + source.periods.create(period_start: Date.today, period_end: Date.today + 10.day) + source.dates.create(date: Date.today - 1.day, in_out: true) + + expect { + source.periods = source.optimize_continuous_dates_and_periods + }.to change {source.dates.count}.by(-1) + + expect(source.reload.periods.first.period_start).to eq(Date.today - 1.day) end end @@ -129,4 +192,3 @@ describe TimeTableCombination, :type => :model do end end end - diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 6f98e5ce7..3a9ae37e9 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,6 +1,4 @@ -require 'spec_helper' - -describe User, :type => :model do +RSpec.describe User, :type => :model do # it { should validate_uniqueness_of :email } # it { should validate_presence_of :name } @@ -116,9 +114,11 @@ describe User, :type => :model do end context 'permissions' do + let( :all_permissions ){ Stif::PermissionTranslator.translate(%w{boiv:edit-offer}) } + it 'should give edit permissions to user if user has "edit offer" permission in portail' do User.portail_sync - expect(User.find_by(username: 'vlatka.pavisic').permissions).to include_all(User.edit_offer_permissions) + expect(User.find_by(username: 'vlatka.pavisic').permissions).to eq(all_permissions) expect(User.find_by(username: 'pierre.vabre').permissions).to be_empty end end diff --git a/spec/support/permissions.rb b/spec/support/permissions.rb index a13010f65..fcf9ae9c4 100644 --- a/spec/support/permissions.rb +++ b/spec/support/permissions.rb @@ -15,6 +15,7 @@ module Support %w[ access_points connection_links + calendars footnotes journey_patterns referentials |
