aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Dockerfile6
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock20
-rw-r--r--INSTALL.md44
-rw-r--r--app/assets/javascripts/application.js3
-rw-r--r--app/assets/javascripts/i18n/extended.coffee24
-rw-r--r--app/assets/stylesheets/components/_tables.sass25
-rw-r--r--app/assets/stylesheets/modules/_vj_collection.sass62
-rw-r--r--app/controllers/application_controller.rb10
-rw-r--r--app/controllers/autocomplete_stop_areas_controller.rb2
-rw-r--r--app/controllers/calendars_controller.rb46
-rw-r--r--app/controllers/compliance_control_sets_controller.rb40
-rw-r--r--app/controllers/referential_vehicle_journeys_controller.rb21
-rw-r--r--app/controllers/referentials_controller.rb12
-rw-r--r--app/controllers/snapshots_controller.rb14
-rw-r--r--app/controllers/statuses_controller.rb20
-rw-r--r--app/controllers/vehicle_journeys_controller.rb6
-rw-r--r--app/decorators/calendar_decorator.rb2
-rw-r--r--app/decorators/company_decorator.rb19
-rw-r--r--app/decorators/compliance_control_decorator.rb18
-rw-r--r--app/decorators/compliance_control_set_decorator.rb2
-rw-r--r--app/decorators/import_decorator.rb7
-rw-r--r--app/decorators/import_resources_decorator.rb2
-rw-r--r--app/decorators/line_decorator.rb10
-rw-r--r--app/decorators/network_decorator.rb14
-rw-r--r--app/decorators/purchase_window_decorator.rb18
-rw-r--r--app/decorators/referential_decorator.rb4
-rw-r--r--app/decorators/referential_line_decorator.rb10
-rw-r--r--app/decorators/referential_network_decorator.rb21
-rw-r--r--app/decorators/route_decorator.rb29
-rw-r--r--app/decorators/routing_constraint_zone_decorator.rb39
-rw-r--r--app/decorators/stop_area_decorator.rb22
-rw-r--r--app/decorators/time_table_decorator.rb2
-rw-r--r--app/helpers/referentials_helper.rb10
-rw-r--r--app/helpers/table_builder_helper.rb9
-rw-r--r--app/helpers/table_builder_helper/custom_links.rb7
-rw-r--r--app/helpers/table_builder_helper/url.rb3
-rw-r--r--app/javascript/helpers/stop_area_header_manager.js6
-rw-r--r--app/javascript/routes/components/BSelect2.js2
-rw-r--r--app/javascript/routes/components/OlMap.js24
-rw-r--r--app/javascript/routes/components/StopPoint.js12
-rw-r--r--app/javascript/routes/components/StopPointList.js8
-rw-r--r--app/javascript/time_tables/actions/index.js12
-rw-r--r--app/javascript/time_tables/components/ConfirmModal.js10
-rw-r--r--app/javascript/time_tables/components/ErrorModal.js6
-rw-r--r--app/javascript/time_tables/components/Metas.js12
-rw-r--r--app/javascript/time_tables/components/PeriodForm.js14
-rw-r--r--app/javascript/time_tables/components/TagsSelect2.js2
-rw-r--r--app/javascript/time_tables/components/Timetable.js8
-rw-r--r--app/javascript/vehicle_journeys/actions/index.js30
-rw-r--r--app/javascript/vehicle_journeys/components/ConfirmModal.js6
-rw-r--r--app/javascript/vehicle_journeys/components/Filters.js18
-rw-r--r--app/javascript/vehicle_journeys/components/Navigate.js5
-rw-r--r--app/javascript/vehicle_journeys/components/ToggleArrivals.js2
-rw-r--r--app/javascript/vehicle_journeys/components/Tools.js4
-rw-r--r--app/javascript/vehicle_journeys/components/VehicleJourney.js48
-rw-r--r--app/javascript/vehicle_journeys/components/VehicleJourneys.js78
-rw-r--r--app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js20
-rw-r--r--app/javascript/vehicle_journeys/components/tools/VehicleJourneyInfoButton.js4
-rw-r--r--app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js10
-rw-r--r--app/javascript/vehicle_journeys/reducers/vehicleJourneys.js25
-rw-r--r--app/models/calendar.rb3
-rw-r--r--app/models/chouette/company.rb1
-rw-r--r--app/models/chouette/journey_pattern.rb16
-rw-r--r--app/models/chouette/line.rb9
-rw-r--r--app/models/chouette/purchase_window.rb1
-rw-r--r--app/models/chouette/route.rb8
-rw-r--r--app/models/chouette/routing_constraint_zone.rb4
-rw-r--r--app/models/chouette/stop_area.rb10
-rw-r--r--app/models/chouette/time_table.rb4
-rw-r--r--app/models/chouette/vehicle_journey.rb6
-rw-r--r--app/models/chouette/vehicle_journey_at_stop.rb8
-rw-r--r--app/models/chouette/vehicle_journey_at_stops_day_offset.rb16
-rw-r--r--app/models/compliance_check_set.rb14
-rw-r--r--app/models/compliance_control.rb5
-rw-r--r--app/models/concerns/checksum_support.rb25
-rw-r--r--app/models/concerns/min_max_values_validation.rb1
-rw-r--r--app/models/concerns/timetable_support.rb1
-rw-r--r--app/models/import.rb10
-rw-r--r--app/models/line_control/route.rb2
-rw-r--r--app/models/organisation.rb4
-rw-r--r--app/models/referential.rb7
-rw-r--r--app/models/route_control/opposite_route.rb2
-rw-r--r--app/models/route_control/opposite_route_terminus.rb2
-rw-r--r--app/models/simple_importer.rb422
-rw-r--r--app/models/user.rb1
-rw-r--r--app/models/vehicle_journey_control/delta.rb1
-rw-r--r--app/models/vehicle_journey_control/waiting_time.rb1
-rw-r--r--app/models/workbench.rb7
-rw-r--r--app/models/workgroup.rb1
-rw-r--r--app/services/parent_import_notifier.rb15
-rw-r--r--app/services/parent_notifier.rb19
-rw-r--r--app/views/calendar_mailer/created.html.slim4
-rw-r--r--app/views/calendar_mailer/updated.html.slim2
-rw-r--r--app/views/calendars/_filters.html.slim4
-rw-r--r--app/views/calendars/_form_advanced.html.slim2
-rw-r--r--app/views/calendars/_form_simple.html.slim2
-rw-r--r--app/views/calendars/edit.html.slim2
-rw-r--r--app/views/calendars/index.html.slim4
-rw-r--r--app/views/calendars/new.html.slim2
-rw-r--r--app/views/calendars/show.html.slim2
-rw-r--r--app/views/compliance_check_sets/index.html.slim4
-rw-r--r--app/views/compliance_controls/new.html.slim4
-rw-r--r--app/views/compliance_controls/show.html.slim4
-rw-r--r--app/views/dashboards/_dashboard.html.slim36
-rw-r--r--app/views/errors/forbidden.html.slim2
-rw-r--r--app/views/errors/server_error.html.slim2
-rw-r--r--app/views/layouts/application.html.slim2
-rw-r--r--app/views/layouts/navigation/_main_nav_left_content_stif.html.slim10
-rw-r--r--app/views/layouts/snapshots/actions_links.html.slim21
-rw-r--r--app/views/layouts/snapshots/default.html.slim19
-rw-r--r--app/views/purchase_windows/show.html.slim1
-rw-r--r--app/views/referential_vehicle_journeys/index.html.slim10
-rw-r--r--app/views/referentials/_form.html.slim4
-rw-r--r--app/views/referentials/_overview.html.slim2
-rw-r--r--app/views/referentials/select_compliance_control_set.html.slim2
-rw-r--r--app/views/routes/_form.html.slim2
-rw-r--r--app/views/stif/dashboards/_dashboard.html.slim6
-rw-r--r--app/views/time_tables/_form.html.slim2
-rw-r--r--app/views/time_tables/edit.html.slim2
-rw-r--r--app/views/time_tables/index.html.slim2
-rw-r--r--app/views/vehicle_journeys/index.html.slim2
-rw-r--r--app/views/vehicle_journeys/show.rabl10
-rw-r--r--app/views/workbenches/show.html.slim6
-rw-r--r--config/breadcrumbs.rb16
-rw-r--r--config/deploy.rb11
-rw-r--r--config/environments/development.rb1
-rw-r--r--config/environments/production.rb1
-rw-r--r--config/initializers/apartment.rb1
-rw-r--r--config/initializers/sidekiq.rb4
-rw-r--r--config/locales/compliance_controls.fr.yml4
-rw-r--r--config/locales/en.yml5
-rw-r--r--config/locales/fr.yml4
-rw-r--r--config/locales/imports.en.yml2
-rw-r--r--config/locales/imports.fr.yml2
-rw-r--r--config/locales/journey_patterns.en.yml1
-rw-r--r--config/locales/stop_areas.en.yml4
-rw-r--r--config/locales/stop_areas.fr.yml4
-rw-r--r--config/locales/stop_points.en.yml1
-rw-r--r--config/locales/stop_points.fr.yml3
-rw-r--r--config/locales/vehicle_journeys.en.yml120
-rw-r--r--config/locales/vehicle_journeys.fr.yml121
-rw-r--r--config/routes.rb214
-rw-r--r--config/schedule.rb6
-rw-r--r--config/secrets.yml.docker1
-rw-r--r--config/webpack/environment.js2
-rw-r--r--config/webpack/production.js7
-rw-r--r--config/webpack/staging.js2
-rw-r--r--db/migrate/20180123174450_add_workgroup_id_to_calendars.rb6
-rw-r--r--db/migrate/20180129210928_create_simple_importers.rb10
-rw-r--r--db/schema.rb9
-rw-r--r--lib/af83/decorator.rb63
-rw-r--r--lib/af83/decorator/enhanced_decorator.rb22
-rw-r--r--lib/af83/decorator/link.rb5
-rw-r--r--lib/stif/dashboard.rb6
-rw-r--r--lib/tasks/ci.rake15
-rw-r--r--lib/tasks/compliance_check_sets.rb11
-rw-r--r--lib/tasks/imports.rake104
-rw-r--r--lib/tasks/install.rake4
-rw-r--r--package.json8
-rw-r--r--spec/controllers/api/v1/stop_area_controller_spec.rb9
-rw-r--r--spec/controllers/autocomplete_stop_areas_controller_spec.rb14
-rw-r--r--spec/controllers/referentials_controller_spec.rb56
-rw-r--r--spec/controllers/statuses_controller_spec.rb50
-rw-r--r--spec/controllers/vehicle_journeys_controller_spec.rb24
-rw-r--r--spec/decorators/referential_decorator_spec.rb15
-rw-r--r--spec/factories/calendars.rb1
-rw-r--r--spec/factories/chouette_routes.rb1
-rw-r--r--spec/factories/chouette_stop_areas.rb8
-rw-r--r--spec/factories/compliance_controls/vehicle_journey_control_factories.rb2
-rw-r--r--spec/features/access_points_spec.rb2
-rw-r--r--spec/features/calendars_permissions_spec.rb7
-rw-r--r--spec/features/referential_stop_areas_spec.rb2
-rw-r--r--spec/features/referentials_spec.rb12
-rw-r--r--spec/features/workbenches/workbenches_permissions_spec.rb2
-rw-r--r--spec/features/workbenches/workbenches_show_spec.rb4
-rw-r--r--spec/fixtures/simple_importer/lines_mapping.csv11
-rw-r--r--spec/fixtures/simple_importer/stop_area.csv2
-rw-r--r--spec/fixtures/simple_importer/stop_area_full.csv3
-rw-r--r--spec/fixtures/simple_importer/stop_area_full_reverse.csv3
-rw-r--r--spec/fixtures/simple_importer/stop_area_incomplete.csv3
-rw-r--r--spec/fixtures/simple_importer/stop_area_missing_street_name.csv2
-rw-r--r--spec/fixtures/simple_importer/stop_points_full.csv11
-rw-r--r--spec/helpers/table_builder_helper_spec.rb22
-rw-r--r--spec/javascript/preprocessor.js15
-rw-r--r--spec/javascript/time_table/actions_spec.js1
-rw-r--r--spec/javascript/vehicle_journeys/components/VehicleJourneys_spec.js7
-rw-r--r--spec/javascript/vehicle_journeys/components/__snapshots__/VehicleJourneys_spec.js.snap26
-rw-r--r--spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js8
-rw-r--r--spec/mailers/calendar_mailer_spec.rb2
-rw-r--r--spec/models/calendar_spec.rb2
-rw-r--r--spec/models/chouette/footnote_spec.rb12
-rw-r--r--spec/models/chouette/journey_pattern_spec.rb27
-rw-r--r--spec/models/chouette/route/route_base_spec.rb4
-rw-r--r--spec/models/chouette/routing_constraint_zone_spec.rb2
-rw-r--r--spec/models/chouette/time_table_period_spec.rb2
-rw-r--r--spec/models/chouette/time_table_spec.rb2
-rw-r--r--spec/models/chouette/vehicle_journey_at_stop_spec.rb6
-rw-r--r--spec/models/chouette/vehicle_journey_spec.rb4
-rw-r--r--spec/models/compliance_check_spec.rb32
-rw-r--r--spec/models/import_spec.rb52
-rw-r--r--spec/models/simple_importer_spec.rb394
-rw-r--r--spec/services/parent_notifier_spec.rb (renamed from spec/services/parent_import_notifier_spec.rb)16
-rw-r--r--spec/support/checksum_support.rb67
-rw-r--r--spec/support/decorator_helpers.rb1
-rw-r--r--spec/support/integration_spec_helper.rb15
-rw-r--r--spec/support/pundit/pundit_view_policy.rb13
-rw-r--r--spec/support/referential.rb4
-rw-r--r--spec/support/snapshot_support.rb60
-rw-r--r--spec/views/companies/__snapshots__/companies/index.snap4
-rw-r--r--spec/views/companies/__snapshots__/companies/index_create.snap4
-rw-r--r--spec/views/companies/__snapshots__/companies/index_destroy.snap4
-rw-r--r--spec/views/companies/__snapshots__/companies/index_update.snap4
-rw-r--r--spec/views/companies/__snapshots__/companies/show.snap4
-rw-r--r--spec/views/companies/__snapshots__/companies/show_create.snap4
-rw-r--r--spec/views/companies/__snapshots__/companies/show_destroy.snap7
-rw-r--r--spec/views/companies/__snapshots__/companies/show_update.snap7
-rw-r--r--spec/views/companies/index.html.erb_spec.rb29
-rw-r--r--spec/views/companies/show.html.erb_spec.rb29
-rw-r--r--spec/views/lines/__snapshots__/lines/index.snap4
-rw-r--r--spec/views/lines/__snapshots__/lines/index_create.snap4
-rw-r--r--spec/views/lines/__snapshots__/lines/index_destroy.snap4
-rw-r--r--spec/views/lines/__snapshots__/lines/index_update.snap4
-rw-r--r--spec/views/lines/__snapshots__/lines/show.snap9
-rw-r--r--spec/views/lines/__snapshots__/lines/show_create.snap9
-rw-r--r--spec/views/lines/__snapshots__/lines/show_destroy.snap9
-rw-r--r--spec/views/lines/__snapshots__/lines/show_update.snap9
-rw-r--r--spec/views/lines/index.html.slim_spec.rb84
-rw-r--r--spec/views/lines/show.html.erb_spec.rb26
-rw-r--r--spec/views/networks/__snapshots__/networks/index.snap4
-rw-r--r--spec/views/networks/__snapshots__/networks/index_create.snap4
-rw-r--r--spec/views/networks/__snapshots__/networks/index_destroy.snap4
-rw-r--r--spec/views/networks/__snapshots__/networks/index_update.snap4
-rw-r--r--spec/views/networks/__snapshots__/networks/show.snap4
-rw-r--r--spec/views/networks/__snapshots__/networks/show_create.snap4
-rw-r--r--spec/views/networks/__snapshots__/networks/show_destroy.snap7
-rw-r--r--spec/views/networks/__snapshots__/networks/show_update.snap7
-rw-r--r--spec/views/networks/index.html.erb_spec.rb28
-rw-r--r--spec/views/networks/show.html.erb_spec.rb30
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show.snap9
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show_create.snap9
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show_destroy.snap9
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show_purchase_windows.snap9
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show_purchase_windows_create.snap9
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show_purchase_windows_destroy.snap9
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show_purchase_windows_update.snap12
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show_readonly.snap9
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show_readonly_create.snap9
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show_readonly_destroy.snap9
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show_readonly_update.snap9
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys.snap9
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys_create.snap9
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys_destroy.snap9
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys_update.snap12
-rw-r--r--spec/views/referentials/__snapshots__/referentials/show_update.snap12
-rw-r--r--spec/views/referentials/show.html.erb_spec.rb7
257 files changed, 3254 insertions, 881 deletions
diff --git a/.gitignore b/.gitignore
index acdb5e230..dd4d057ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,8 @@
/tmp
*~
public/assets/
+public/javascripts/i18n.js
+public/javascripts/translations.js
# for vim users
*.swp
diff --git a/Dockerfile b/Dockerfile
index 8259981f8..e484de431 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
FROM debian:stable-slim
-ENV RAILS_ENV=production RAILS_SERVE_STATIC_FILES=true RAILS_LOG_TO_STDOUT=true
+ENV RAILS_ENV=production RAILS_SERVE_STATIC_FILES=true RAILS_LOG_TO_STDOUT=true SIDEKIQ_REDIS_URL=redis://redis:6379/12
RUN apt-get update && \
apt-get install -y --no-install-recommends ruby2.3 && \
@@ -12,10 +12,10 @@ RUN apt-get update && \
COPY stif-boiv-release.tar.gz /
RUN mkdir /app && apt-get update &&\
- apt-get -y install --no-install-recommends build-essential ruby2.3-dev libpq-dev libxml2-dev zlib1g-dev libproj-dev&& \
+ apt-get -y install --no-install-recommends build-essential ruby2.3-dev libpq-dev libxml2-dev zlib1g-dev libproj-dev libmagic1 libmagic-dev&& \
tar -C /app -zxf stif-boiv-release.tar.gz && \
cd /app && bundle install --local && \
- apt-get -y remove build-essential ruby2.3-dev libpq-dev libxml2-dev zlib1g-dev && \
+ apt-get -y remove build-essential ruby2.3-dev libpq-dev libxml2-dev zlib1g-dev libmagic-dev&& \
apt-get clean && apt-get -y autoremove && rm -rf /var/lib/apt/lists/* && \
cd /app && rm config/database.yml && mv config/database.yml.docker config/database.yml && \
cd /app && rm config/secrets.yml && mv config/secrets.yml.docker config/secrets.yml && \
diff --git a/Gemfile b/Gemfile
index bb1a42df0..75298659f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -16,7 +16,7 @@ gem 'uglifier', '~> 2.7.2'
gem 'coffee-rails', '~> 4.0.0'
# Webpacker
-gem 'webpacker', '3.0.2'
+gem 'webpacker', '3.2.1'
# Use jquery as the JavaScript library
gem 'jquery-rails', '~> 3.1.4' # Update to v4 for Rails 4.2
@@ -103,6 +103,7 @@ gem 'will_paginate-bootstrap'
gem 'gretel'
gem 'country_select'
gem 'flag-icons-rails'
+gem 'i18n-js'
# Format Output
gem 'json'
@@ -141,6 +142,7 @@ gem 'rake'
gem 'devise-async'
gem 'apartment', '~> 1.0.0'
gem 'aasm'
+gem 'activerecord-nulldb-adapter'
gem 'puma', '~> 3.10.0'
gem 'newrelic_rpm'
@@ -176,6 +178,7 @@ group :test do
gem 'simplecov-rcov', :require => false
gem 'htmlbeautifier'
gem 'timecop'
+ gem 'rspec-snapshot'
end
group :test, :development, :dev do
diff --git a/Gemfile.lock b/Gemfile.lock
index 805ee460d..046167e69 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -269,8 +269,10 @@ GEM
htmlbeautifier (1.3.1)
httparty (0.14.0)
multi_xml (>= 0.5.2)
- i18n (0.9.3)
+ i18n (0.9.4)
concurrent-ruby (~> 1.0)
+ i18n-js (3.0.4)
+ i18n (~> 0.6, >= 0.6.6)
i18n-tasks (0.9.15)
activesupport (>= 4.0.2)
ast (>= 2.1.0)
@@ -318,7 +320,7 @@ GEM
mime-types-data (3.2016.0521)
mimemagic (0.3.2)
mini_portile2 (2.3.0)
- minitest (5.11.2)
+ minitest (5.11.3)
money (6.10.1)
i18n (>= 0.6.4, < 1.0)
multi_json (1.12.1)
@@ -447,6 +449,10 @@ GEM
roo (2.7.1)
nokogiri (~> 1)
rubyzip (~> 1.1, < 2.0.0)
+ rspec (3.5.0)
+ rspec-core (~> 3.5.0)
+ rspec-expectations (~> 3.5.0)
+ rspec-mocks (~> 3.5.0)
rspec-core (3.5.4)
rspec-support (~> 3.5.0)
rspec-expectations (3.5.0)
@@ -463,6 +469,8 @@ GEM
rspec-expectations (~> 3.5.0)
rspec-mocks (~> 3.5.0)
rspec-support (~> 3.5.0)
+ rspec-snapshot (0.1.1)
+ rspec (> 3.0.0)
rspec-support (3.5.0)
ruby-filemagic (0.7.2)
ruby-graphviz (1.2.3)
@@ -553,7 +561,7 @@ GEM
json (>= 1.8, < 3.0)
parser (>= 2.3.0.7)
rainbow (>= 1.99.1, < 3.0)
- tzinfo (1.2.4)
+ tzinfo (1.2.5)
thread_safe (~> 0.1)
uglifier (2.7.2)
execjs (>= 0.3.0)
@@ -566,7 +574,7 @@ GEM
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff
- webpacker (3.0.2)
+ webpacker (3.2.1)
activesupport (>= 4.2)
rack-proxy (>= 0.6.1)
railties (>= 4.2)
@@ -638,6 +646,7 @@ DEPENDENCIES
gretel
has_array_of!
htmlbeautifier
+ i18n-js
i18n-tasks
inherited_resources
jbuilder (~> 2.0)
@@ -681,6 +690,7 @@ DEPENDENCIES
rgeo (~> 0.5.2)
roo
rspec-rails (~> 3.5.0)
+ rspec-snapshot
rubyzip
sass-rails (~> 4.0.3)
sawyer (~> 0.6.0)
@@ -703,7 +713,7 @@ DEPENDENCIES
transpec
uglifier (~> 2.7.2)
webmock
- webpacker (= 3.0.2)
+ webpacker (= 3.2.1)
whenever!
will_paginate
will_paginate-bootstrap
diff --git a/INSTALL.md b/INSTALL.md
index 9e04730f7..e44b072f4 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -46,6 +46,7 @@ yarn install
bundle config build.libv8 --with-system-v8
bundle
```
+
or
```sh
@@ -95,6 +96,46 @@ On mac/OS :
brew install postgis
```
+<<<<<<< HEAD
+### Authentication
+
+See `config.chouette_authentication_settings`.
+
+Use the database authentication or get an invitation to [STIF Portail](http://stif-portail-dev.af83.priv/).
+
+### Run seed
+
+Run :
+
+ bundle exec rake db:seed
+
+Two users are created : stif-boiv@af83.com/secret and stif-boiv+transporteur@af83.com/secret
+
+If you have access to STIF CodifLigne and Reflex :
+
+ bundle exec rake codifligne:sync
+ bundle exec rake reflex:sync
+
+To create Referential with some data (Route, JourneyPattern, VehicleJourney, etc) :
+
+ bundle exec rake referential:create
+
+# Troubleshooting
+
+If PG complains about illegal type `hstore` in your tests that is probably because the shared extension is not installed, here is what to do:
+
+#### Check installation
+
+* Run tests
+
+ bundle exec rake spec
+ bundle exec rake teaspoon
+
+* Start local server
+
+ bundle exec rails server
+
+=======
On debian/ubuntu system :
```sh
@@ -135,6 +176,7 @@ RAILS_ENV=test bundle exec rake db:create db:migrate
```
#### Load seed datas
+>>>>>>> master
```sh
bundle exec rake db:seed:stif
@@ -169,7 +211,7 @@ bundle exec rake referential:create
#### Run tests
-#### Rspec
+#### Rspec
```sh
bundle exec rake spec
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 4c5aff22f..6a79f7e8e 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -22,3 +22,6 @@
//= require_directory .
// require('whatwg-fetch')
// require('babel-polyfill')
+//= require "i18n"
+//= require "i18n/extended"
+//= require "i18n/translations"
diff --git a/app/assets/javascripts/i18n/extended.coffee b/app/assets/javascripts/i18n/extended.coffee
new file mode 100644
index 000000000..aeb67bd09
--- /dev/null
+++ b/app/assets/javascripts/i18n/extended.coffee
@@ -0,0 +1,24 @@
+#= require i18n
+
+decorateI18n = (_i18n)->
+ _i18n.tc = (key, opts={}) ->
+ out = _i18n.t(key, opts)
+ out += " " if _i18n.locale == "fr"
+ out + ":"
+
+ _i18n.model_name = (model, opts={}) ->
+ last_key = if opts.plural then "other" else "one"
+ _i18n.t("activerecord.models.#{model}.#{last_key}")
+
+ _i18n.attribute_name = (model, attribute, opts={}) ->
+ _i18n.t("activerecord.attributes.#{model}.#{attribute}")
+
+ _i18n.enumerize = (enumerize, key, opts={}) ->
+ I18n.t("enumerize.#{enumerize}.#{key}")
+
+ _i18n
+
+module?.exports = decorateI18n
+
+if I18n?
+ decorateI18n(I18n)
diff --git a/app/assets/stylesheets/components/_tables.sass b/app/assets/stylesheets/components/_tables.sass
index 35e1122f3..ef19bd538 100644
--- a/app/assets/stylesheets/components/_tables.sass
+++ b/app/assets/stylesheets/components/_tables.sass
@@ -9,7 +9,6 @@
font-weight: 700
border-bottom: 2px solid $darkgrey
vertical-align: middle
-
> a
position: relative
display: block
@@ -326,6 +325,26 @@
padding: 6px 8px
border-bottom: 2px solid rgba($grey, 0.5)
border-top: 1px solid rgba($grey, 0.5)
+ text-transform: capitalize
+
+ .info-button
+ position: absolute
+ width: 20px
+ height: 20px
+ top: 0
+ right: 0
+ margin: 6px 8px
+ button
+ border: none
+ background: $blue
+ border-radius: 20px
+ width: 100%
+ height: 100%
+ font-size: 12px
+ line-height: 14px
+ color: white
+ outline: none
+
.td
position: relative
padding: 6px 8px
@@ -355,6 +374,8 @@
.th
text-align: right
border-top-color: transparent
+ > div:not(.btn-group)
+ min-height: 20px
.td > .headlined
&:before
@@ -389,7 +410,7 @@
.th
> div:not(.btn-group)
- min-height: 19px
+ min-height: 20px
> *:first-child
padding-right: 30px
diff --git a/app/assets/stylesheets/modules/_vj_collection.sass b/app/assets/stylesheets/modules/_vj_collection.sass
index d99c67bd7..d9079daa2 100644
--- a/app/assets/stylesheets/modules/_vj_collection.sass
+++ b/app/assets/stylesheets/modules/_vj_collection.sass
@@ -86,6 +86,20 @@
&:after
bottom: 50%
+
+ .table-2entries .t2e-head
+ .detailed-timetables
+ .fa
+ margin-right: 5px
+ .detailed-timetables-bt
+ text-decoration: none
+ .fa
+ margin-right: 5px
+ color: $red
+ transition: transform 0.1s
+ &.active .fa
+ transform: rotate(180deg)
+
.table-2entries .t2e-head > .td:nth-child(2) > div,
.table-2entries .t2e-head > .td:last-child > div,
.table-2entries.no_result .t2e-head > .td:last-child > div
@@ -103,6 +117,54 @@
top: 50%
margin-top: -8px
+ .detailed-timetables
+ padding-top: 10px
+ text-align: left
+ margin-bottom: -5px
+
+ & > div
+ position: relative
+ border-left: 1px solid $lightgrey
+ padding-left: 10px
+ a
+ text-decoration: none
+ border: none
+ &:before
+ position: absolute
+ left: 0px
+ top: 0
+ right: -8px
+ content: ""
+ border-top: 1px solid $lightgrey
+ font-size: 0.8em
+ height: 44px
+ position: relative
+ padding-bottom: 5px
+
+ p
+ margin: 0
+ p:first-child
+ padding-top: 8px
+ font-weight: bold
+
+ .t2e-item-list .detailed-timetables > div
+ border-left: none
+ &:after
+ top: 50%
+ left: 50%
+ content: ""
+ border: 1px solid black
+ width: 20px
+ height: 20px
+ margin-left: -10px
+ margin-top: -10px
+ position: absolute
+ border-radius: 20px
+ &.active:after
+ background: black
+ &:before
+ left: -8px
+
// Errors
.table-2entries .t2e-item-list
.t2e-item
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index c5ecc505a..c4961123d 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -36,16 +36,6 @@ class ApplicationController < ActionController::Base
end
helper_method :current_organisation
- def current_offer_workbench
- current_organisation.workbenches.find_by_name("Gestion de l'offre")
- end
- helper_method :current_offer_workbench
-
- def current_workgroup
- current_offer_workbench.workgroup
- end
- helper_method :current_workgroup
-
def current_functional_scope
functional_scope = current_organisation.sso_attributes.try(:[], "functional_scope") if current_organisation
JSON.parse(functional_scope) if functional_scope
diff --git a/app/controllers/autocomplete_stop_areas_controller.rb b/app/controllers/autocomplete_stop_areas_controller.rb
index d82fa316a..79154a6e0 100644
--- a/app/controllers/autocomplete_stop_areas_controller.rb
+++ b/app/controllers/autocomplete_stop_areas_controller.rb
@@ -21,7 +21,7 @@ class AutocompleteStopAreasController < ChouetteController
scope = StopAreaPolicy::Scope.new(current_user, scope).search_scope(search_scope)
end
args = [].tap{|arg| 4.times{arg << "%#{params[:q]}%"}}
- @stop_areas = scope.where("unaccent(name) ILIKE unaccent(?) OR unaccent(city_name) ILIKE unaccent(?) OR registration_number ILIKE ? OR objectid ILIKE ?", *args).limit(50)
+ @stop_areas = scope.where("unaccent(stop_areas.name) ILIKE unaccent(?) OR unaccent(stop_areas.city_name) ILIKE unaccent(?) OR stop_areas.registration_number ILIKE ? OR stop_areas.objectid ILIKE ?", *args).limit(50)
@stop_areas
end
diff --git a/app/controllers/calendars_controller.rb b/app/controllers/calendars_controller.rb
index 5cc7912b7..75d4cbd09 100644
--- a/app/controllers/calendars_controller.rb
+++ b/app/controllers/calendars_controller.rb
@@ -8,14 +8,21 @@ class CalendarsController < ChouetteController
respond_to :json, only: :show
respond_to :js, only: :index
+ belongs_to :workgroup
+
def index
index! do
- @calendars = CalendarDecorator.decorate(@calendars)
+ @calendars = decorate_calendars(@calendars)
end
end
def show
- @year = params[:year] ? params[:year].to_i : Date.today.cwyear
+ show! do
+ @year = params[:year] ? params[:year].to_i : Date.today.cwyear
+ @calendar = @calendar.decorate(context: {
+ workgroup: workgroup
+ })
+ end
end
def month
@@ -45,6 +52,16 @@ class CalendarsController < ChouetteController
end
private
+
+ def decorate_calendars(calendars)
+ CalendarDecorator.decorate(
+ calendars,
+ context: {
+ workgroup: workgroup
+ }
+ )
+ end
+
def calendar_params
permitted_params = [:id, :name, :short_name, :shared, periods_attributes: [:id, :begin, :end, :_destroy], date_values_attributes: [:id, :value, :_destroy]]
permitted_params << :shared if policy(Calendar).share?
@@ -60,25 +77,30 @@ class CalendarsController < ChouetteController
end
protected
+
+ alias_method :workgroup, :parent
+ helper_method :workgroup
+
def resource
- @calendar = Calendar.where('organisation_id = ? OR shared = true', current_organisation.id).find_by_id(params[:id]).decorate
+ @calendar ||= workgroup.calendars.where('(organisation_id = ? OR shared = ?)', current_organisation.id, true).find_by_id(params[:id])
end
def build_resource
super.tap do |calendar|
+ calendar.workgroup = workgroup
calendar.organisation = current_organisation
end
end
def collection
- return @calendars if @calendars
- scope = Calendar.where('organisation_id = ? OR shared = ?', current_organisation.id, true)
- scope = shared_scope(scope)
- @q = scope.ransack(params[:q])
-
- calendars = @q.result
- calendars = calendars.order(sort_column + ' ' + sort_direction) if sort_column && sort_direction
- @calendars = calendars.paginate(page: params[:page])
+ @calendars ||= begin
+ scope = workgroup.calendars.where('(organisation_id = ? OR shared = ?)', current_organisation.id, true)
+ scope = shared_scope(scope)
+ @q = scope.ransack(params[:q])
+ calendars = @q.result
+ calendars = calendars.order(sort_column + ' ' + sort_direction) if sort_column && sort_direction
+ calendars = calendars.paginate(page: params[:page])
+ end
end
def ransack_contains_date
@@ -103,4 +125,4 @@ class CalendarsController < ChouetteController
scope
end
-end
+end \ No newline at end of file
diff --git a/app/controllers/compliance_control_sets_controller.rb b/app/controllers/compliance_control_sets_controller.rb
index ae1d01feb..8f9251155 100644
--- a/app/controllers/compliance_control_sets_controller.rb
+++ b/app/controllers/compliance_control_sets_controller.rb
@@ -7,10 +7,8 @@ class ComplianceControlSetsController < ChouetteController
def index
index! do |format|
- scope = self.ransack_period_range(scope: @compliance_control_sets, error_message: t('imports.filters.error_period_filter'), query: :where_updated_at_between)
- @q_for_form = scope.ransack(params[:q])
format.html {
- @compliance_control_sets = decorate_compliance_control_sets(@q_for_form.result.paginate(page: params[:page], per_page: 30))
+ @compliance_control_sets = decorate_compliance_control_sets(@compliance_control_sets)
}
end
end
@@ -37,6 +35,14 @@ class ComplianceControlSetsController < ChouetteController
private
+ def collection
+ scope = self.ransack_period_range(scope: ComplianceControlSet.all, error_message: t('imports.filters.error_period_filter'), query: :where_updated_at_between)
+ @q_for_form = scope.ransack(params[:q])
+ compliance_control_sets = @q_for_form.result
+ compliance_control_sets = joins_with_associated_objects(compliance_control_sets).order(sort_column + ' ' + sort_direction) if sort_column && sort_direction
+ @compliance_control_sets = compliance_control_sets.paginate(page: params[:page], per_page: 30)
+ end
+
def decorate_compliance_control_sets(compliance_control_sets)
ComplianceControlSetDecorator.decorate(compliance_control_sets)
end
@@ -58,4 +64,32 @@ class ComplianceControlSetsController < ChouetteController
@direct_compliance_controls = compliance_controls.delete nil
@blocks_to_compliance_controls_map = compliance_controls
end
+
+ def sort_column
+ case params[:sort]
+ when 'name' then 'lower(compliance_control_sets.name)'
+ when 'owner_jdc' then 'lower(organisations.name)'
+ when 'control_numbers' then 'COUNT(compliance_controls.id)'
+ else
+ ComplianceControlSet.column_names.include?(params[:sort]) ? params[:sort] : 'lower(compliance_control_sets.name)'
+ end
+ end
+
+ def joins_with_associated_objects(collection)
+
+ # dont know if this is the right way to do it but since we need to join table deoending of the params
+ # it was to avoid loading associated objects if we don't need them
+ case params[:sort]
+ when 'owner_jdc'
+ collection.joins("LEFT JOIN organisations ON compliance_control_sets.organisation_id = organisations.id")
+ when 'control_numbers'
+ collection.joins("LEFT JOIN compliance_controls ON compliance_controls.compliance_control_set_id = compliance_control_sets.id").group(:id)
+ else
+ collection
+ end
+ end
+
+ def sort_direction
+ %w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc'
+ end
end
diff --git a/app/controllers/referential_vehicle_journeys_controller.rb b/app/controllers/referential_vehicle_journeys_controller.rb
index 2ce28a5cc..e36ef8153 100644
--- a/app/controllers/referential_vehicle_journeys_controller.rb
+++ b/app/controllers/referential_vehicle_journeys_controller.rb
@@ -20,11 +20,30 @@ class ReferentialVehicleJourneysController < ChouetteController
@q = ransack_period_range(scope: @q, error_message: t('vehicle_journeys.errors.purchase_window'), query: :in_purchase_window, prefix: :purchase_window)
@q = ransack_period_range(scope: @q, error_message: t('vehicle_journeys.errors.time_table'), query: :with_matching_timetable, prefix: :time_table)
@q = @q.ransack(params[:q])
- @vehicle_journeys ||= @q.result.order(:published_journey_name).includes(:vehicle_journey_at_stops).paginate page: params[:page], per_page: params[:per_page] || 10
+ @vehicle_journeys ||= @q.result
+ @vehicle_journeys = parse_order @vehicle_journeys
+ @vehicle_journeys = @vehicle_journeys.paginate page: params[:page], per_page: params[:per_page] || 10
@all_companies = Chouette::Company.where("id IN (#{@referential.vehicle_journeys.select(:company_id).to_sql})").distinct
@all_stop_areas = Chouette::StopArea.where("id IN (#{@referential.vehicle_journeys.joins(:stop_areas).select("stop_areas.id").to_sql})").distinct
stop_area_ids = params[:q].try(:[], :stop_area_ids).try(:select, &:present?)
@filters_stop_areas = Chouette::StopArea.find(stop_area_ids) if stop_area_ids.present? && stop_area_ids.size <= 2
end
+ def parse_order scope
+ return scope.order(:published_journey_name) unless params[:sort].present?
+ direction = params[:direction] || "asc"
+ attributes = Chouette::VehicleJourney.column_names.map{|n| "vehicle_journeys.#{n}"}.join(',')
+ case params[:sort]
+ when "line"
+ scope.order("lines.name #{direction}").joins(route: :line)
+ when "route"
+ scope.order("routes.name #{direction}").joins(:route)
+ when "departure_time"
+ scope.joins(:vehicle_journey_at_stops).group(attributes).select(attributes).order("MIN(vehicle_journey_at_stops.departure_time) #{direction}")
+ when "arrival_time"
+ scope.joins(:vehicle_journey_at_stops).group(attributes).select(attributes).order("MAX(vehicle_journey_at_stops.departure_time) #{direction}")
+ else
+ scope.order "#{params[:sort]} #{direction}"
+ end
+ end
end
diff --git a/app/controllers/referentials_controller.rb b/app/controllers/referentials_controller.rb
index 09ea35c26..6e3694547 100644
--- a/app/controllers/referentials_controller.rb
+++ b/app/controllers/referentials_controller.rb
@@ -1,5 +1,6 @@
class ReferentialsController < ChouetteController
defaults :resource_class => Referential
+ before_action :load_workbench
include PolicyChecker
respond_to :html
@@ -32,7 +33,7 @@ class ReferentialsController < ChouetteController
def show
resource.switch
show! do |format|
- @referential = @referential.decorate(context: { current_workbench_id: params[:current_workbench_id] } )
+ @referential = @referential.decorate()
@reflines = lines_collection.paginate(page: params[:page], per_page: 10)
@reflines = ReferentialLineDecorator.decorate(
@reflines,
@@ -143,7 +144,6 @@ class ReferentialsController < ChouetteController
if params[:from]
source_referential = Referential.find(params[:from])
@referential = Referential.new_from(source_referential, current_functional_scope)
- @referential.workbench_id = params[:current_workbench_id]
end
@referential.data_format = current_organisation.data_format
@@ -183,4 +183,12 @@ class ReferentialsController < ChouetteController
return user_not_authorized unless current_user.organisation.workgroups.include?(source.workbench.workgroup)
end
+ def load_workbench
+ @workbench ||= Workbench.find(params[:workbench_id]) if params[:workbench_id]
+ @workbench ||= resource&.workbench if params[:id]
+ @workbench
+ end
+
+ alias_method :current_workbench, :load_workbench
+ helper_method :current_workbench
end
diff --git a/app/controllers/snapshots_controller.rb b/app/controllers/snapshots_controller.rb
new file mode 100644
index 000000000..e453b4965
--- /dev/null
+++ b/app/controllers/snapshots_controller.rb
@@ -0,0 +1,14 @@
+class SnapshotsController < ApplicationController
+ if Rails.env.development? || Rails.env.test?
+ layout :which_layout
+ def show
+ tpl = params[:snap]
+ tpl = tpl.gsub Rails.root.to_s, ''
+ render file: tpl
+ end
+
+ def which_layout
+ "snapshots/#{params[:layout] || "default"}"
+ end
+ end
+end
diff --git a/app/controllers/statuses_controller.rb b/app/controllers/statuses_controller.rb
new file mode 100644
index 000000000..e38a92982
--- /dev/null
+++ b/app/controllers/statuses_controller.rb
@@ -0,0 +1,20 @@
+class StatusesController < ChouetteController
+ respond_to :json
+
+ def index
+
+ status = {
+ referentials_blocked: Referential.blocked.count,
+ imports_blocked: Import.blocked.count,
+ compliance_check_sets_blocked: ComplianceCheckSet.blocked.count
+ }
+ status[:status] = global_status status
+ render json: status.to_json
+ end
+
+ private
+
+ def global_status status
+ status.values.all?(&:zero?) ? 'ok' : 'ko'
+ end
+end
diff --git a/app/controllers/vehicle_journeys_controller.rb b/app/controllers/vehicle_journeys_controller.rb
index e031e4952..14795227c 100644
--- a/app/controllers/vehicle_journeys_controller.rb
+++ b/app/controllers/vehicle_journeys_controller.rb
@@ -154,7 +154,7 @@ class VehicleJourneysController < ChouetteController
private
def load_custom_fields
- @custom_fields = current_workgroup.custom_fields_definitions
+ @custom_fields = referential.workgroup&.custom_fields_definitions || {}
end
def map_stop_points points
@@ -185,7 +185,9 @@ class VehicleJourneysController < ChouetteController
:long_lat_type => sp.stop_area.try(:long_lat_type),
:country_code => sp.stop_area.try(:country_code),
:country_name => sp.stop_area.try(:country_name),
- :street_name => sp.stop_area.try(:street_name)
+ :street_name => sp.stop_area.try(:street_name),
+ :waiting_time => sp.stop_area.try(:waiting_time),
+ :waiting_time_text => sp.stop_area.decorate.try(:waiting_time_text),
}
end
end
diff --git a/app/decorators/calendar_decorator.rb b/app/decorators/calendar_decorator.rb
index be1f9e3bf..4c6088e8e 100644
--- a/app/decorators/calendar_decorator.rb
+++ b/app/decorators/calendar_decorator.rb
@@ -1,6 +1,6 @@
class CalendarDecorator < AF83::Decorator
decorates Calendar
-
+ set_scope { context[:workgroup] }
create_action_link
with_instance_decorator do |instance_decorator|
diff --git a/app/decorators/company_decorator.rb b/app/decorators/company_decorator.rb
index aadce68bb..5580e0d4a 100644
--- a/app/decorators/company_decorator.rb
+++ b/app/decorators/company_decorator.rb
@@ -1,34 +1,21 @@
class CompanyDecorator < AF83::Decorator
decorates Chouette::Company
+ set_scope { context[:referential] }
+
create_action_link do |l|
l.content { h.t('companies.actions.new') }
- l.href { [:new, context[:referential], :company] }
end
with_instance_decorator do |instance_decorator|
- instance_decorator.show_action_link do |l|
- l.href { [context[:referential], object] }
- end
+ instance_decorator.show_action_link
instance_decorator.edit_action_link do |l|
l.content {|l| l.action == "show" ? h.t('actions.edit') : h.t('companies.actions.edit') }
- l.href {
- h.edit_line_referential_company_path(
- context[:referential],
- object
- )
- }
end
instance_decorator.destroy_action_link do |l|
l.content { h.destroy_link_content('companies.actions.destroy') }
- l.href {
- h.edit_line_referential_company_path(
- context[:referential],
- object
- )
- }
l.data {{ confirm: h.t('companies.actions.destroy_confirm') }}
end
end
diff --git a/app/decorators/compliance_control_decorator.rb b/app/decorators/compliance_control_decorator.rb
index c57a7ccc7..fd2dbd9ce 100644
--- a/app/decorators/compliance_control_decorator.rb
+++ b/app/decorators/compliance_control_decorator.rb
@@ -1,6 +1,8 @@
class ComplianceControlDecorator < AF83::Decorator
decorates ComplianceControl
+ set_scope { object.compliance_control_set }
+
with_instance_decorator do |instance_decorator|
instance_decorator.show_action_link do |l|
l.content h.t('compliance_control_sets.actions.show')
@@ -12,23 +14,9 @@ class ComplianceControlDecorator < AF83::Decorator
end
end
- instance_decorator.edit_action_link do |l|
- l.href do
- h.edit_compliance_control_set_compliance_control_path(
- object.compliance_control_set_id,
- object.id
- )
- end
- end
+ instance_decorator.edit_action_link
instance_decorator.destroy_action_link do |l|
- l.content h.destroy_link_content
- l.href do
- h.compliance_control_set_compliance_control_path(
- object.compliance_control_set.id,
- object.id
- )
- end
l.data confirm: h.t('compliance_controls.actions.destroy_confirm')
end
end
diff --git a/app/decorators/compliance_control_set_decorator.rb b/app/decorators/compliance_control_set_decorator.rb
index 387822c67..b16a06886 100644
--- a/app/decorators/compliance_control_set_decorator.rb
+++ b/app/decorators/compliance_control_set_decorator.rb
@@ -6,6 +6,8 @@ class ComplianceControlSetDecorator < AF83::Decorator
end
with_instance_decorator do |instance_decorator|
+ instance_decorator.show_action_link
+
instance_decorator.edit_action_link do |l|
l.content t('compliance_control_sets.actions.edit')
end
diff --git a/app/decorators/import_decorator.rb b/app/decorators/import_decorator.rb
index c6b1f2349..1964365ae 100644
--- a/app/decorators/import_decorator.rb
+++ b/app/decorators/import_decorator.rb
@@ -1,6 +1,8 @@
class ImportDecorator < AF83::Decorator
decorates Import
+ set_scope { context[:workbench] }
+
define_instance_method :import_status_css_class do
cls =''
cls = 'overheaded-success' if object.status == 'successful'
@@ -11,13 +13,10 @@ class ImportDecorator < AF83::Decorator
create_action_link do |l|
l.content t('imports.actions.new')
- l.href { h.new_workbench_import_path(workbench_id: context[:workbench]) }
end
with_instance_decorator do |instance_decorator|
- instance_decorator.show_action_link do |l|
- l.href { h.workbench_import_path(context[:workbench], object) }
- end
+ instance_decorator.show_action_link
instance_decorator.action_link secondary: :show do |l|
l.content t('imports.actions.download')
diff --git a/app/decorators/import_resources_decorator.rb b/app/decorators/import_resources_decorator.rb
index 2b1a25ef9..88a8057cf 100644
--- a/app/decorators/import_resources_decorator.rb
+++ b/app/decorators/import_resources_decorator.rb
@@ -1,4 +1,4 @@
-class ImportResourcesDecorator < ModelDecorator
+class ImportResourcesDecorator < AF83::Decorator
delegate :where
def lines_imported
diff --git a/app/decorators/line_decorator.rb b/app/decorators/line_decorator.rb
index adeb89f70..0e7b6b9ae 100644
--- a/app/decorators/line_decorator.rb
+++ b/app/decorators/line_decorator.rb
@@ -1,9 +1,10 @@
class LineDecorator < AF83::Decorator
decorates Chouette::Line
+ set_scope { context[:line_referential] }
+
create_action_link do |l|
l.content t('lines.actions.new')
- l.href { h.new_line_referential_line_path(context[:line_referential]) }
end
with_instance_decorator do |instance_decorator|
@@ -14,18 +15,17 @@ class LineDecorator < AF83::Decorator
instance_decorator.show_action_link do |l|
l.content t('lines.actions.show')
- l.href { [context[:line_referential], object] }
end
instance_decorator.action_link secondary: :show do |l|
l.content t('lines.actions.show_network')
- l.href { [context[:line_referential], object.network] }
+ l.href { [scope, object.network] }
l.disabled { object.network.nil? }
end
instance_decorator.action_link secondary: :show do |l|
l.content t('lines.actions.show_company')
- l.href { [context[:line_referential], object.company] }
+ l.href { [scope, object.company] }
l.disabled { object.company.nil? }
end
@@ -34,7 +34,6 @@ class LineDecorator < AF83::Decorator
instance_decorator.with_condition can_edit_line do
edit_action_link do |l|
l.content {|l| l.primary? ? h.t('actions.edit') : h.t('lines.actions.edit') }
- l.href { h.edit_line_referential_line_path(context[:line_referential], object.id) }
end
action_link on: :index, secondary: :index do |l|
@@ -64,7 +63,6 @@ class LineDecorator < AF83::Decorator
instance_decorator.destroy_action_link do |l|
l.content { h.destroy_link_content('lines.actions.destroy') }
- l.href { h.line_referential_line_path(context[:line_referential], object) }
l.data confirm: h.t('lines.actions.destroy_confirm')
l.add_class "delete-action"
end
diff --git a/app/decorators/network_decorator.rb b/app/decorators/network_decorator.rb
index 90f0d0e82..ea0f73dc2 100644
--- a/app/decorators/network_decorator.rb
+++ b/app/decorators/network_decorator.rb
@@ -1,6 +1,7 @@
class NetworkDecorator < AF83::Decorator
decorates Chouette::Network
+ set_scope { context[:line_referential] }
# Action links require:
# context: {
# line_referential: ,
@@ -8,15 +9,10 @@ class NetworkDecorator < AF83::Decorator
create_action_link do |l|
l.content t('networks.actions.new')
- l.href { h.new_line_referential_network_path(context[:line_referential]) }
end
with_instance_decorator do |instance_decorator|
- instance_decorator.show_action_link do |l|
- l.href do
- h.line_referential_network_path(context[:line_referential], object)
- end
- end
+ instance_decorator.show_action_link
instance_decorator.action_link secondary: true, policy: :edit do |l|
l.content t('networks.actions.edit')
@@ -30,12 +26,6 @@ class NetworkDecorator < AF83::Decorator
instance_decorator.destroy_action_link do |l|
l.content h.destroy_link_content('networks.actions.destroy')
- l.href do
- h.line_referential_network_path(
- context[:line_referential],
- object
- )
- end
l.data confirm: h.t('networks.actions.destroy_confirm')
end
end
diff --git a/app/decorators/purchase_window_decorator.rb b/app/decorators/purchase_window_decorator.rb
index 54b241173..9b58577b2 100644
--- a/app/decorators/purchase_window_decorator.rb
+++ b/app/decorators/purchase_window_decorator.rb
@@ -1,32 +1,20 @@
class PurchaseWindowDecorator < AF83::Decorator
decorates Chouette::PurchaseWindow
+ set_scope { context[:referential] }
+
create_action_link do |l|
l.content t('purchase_windows.actions.new')
- l.href { h.new_referential_purchase_window_path(context[:referential]) }
end
with_instance_decorator do |instance_decorator|
instance_decorator.show_action_link do |l|
l.content t('purchase_windows.actions.show')
- l.href do
- h.referential_purchase_window_path(
- context[:referential],
- object
- )
- end
end
- instance_decorator.edit_action_link do |l|
- l.href do
- h.edit_referential_purchase_window_path(context[:referential].id, object)
- end
- end
+ instance_decorator.edit_action_link
instance_decorator.destroy_action_link do |l|
- l.href do
- h.referential_purchase_window_path(context[:referential].id, object)
- end
l.data confirm: h.t('purchase_windows.actions.destroy_confirm')
end
end
diff --git a/app/decorators/referential_decorator.rb b/app/decorators/referential_decorator.rb
index 3132cbf92..41cad237d 100644
--- a/app/decorators/referential_decorator.rb
+++ b/app/decorators/referential_decorator.rb
@@ -22,12 +22,12 @@ class ReferentialDecorator < AF83::Decorator
instance_decorator.action_link policy: :clone, secondary: :show do |l|
l.content t('actions.clone')
- l.href { h.new_referential_path(from: object.id, current_workbench_id: context[:current_workbench_id]) }
+ l.href { h.duplicate_workbench_referential_path(object) }
end
instance_decorator.action_link policy: :validate, secondary: :show do |l|
l.content t('actions.validate')
- l.href { h.referential_select_compliance_control_set_path(object.id) }
+ l.href { h.select_compliance_control_set_referential_path(object.id) }
end
instance_decorator.action_link policy: :archive, secondary: :show do |l|
diff --git a/app/decorators/referential_line_decorator.rb b/app/decorators/referential_line_decorator.rb
index 8f884a8e0..3ac846d76 100644
--- a/app/decorators/referential_line_decorator.rb
+++ b/app/decorators/referential_line_decorator.rb
@@ -1,6 +1,8 @@
class ReferentialLineDecorator < AF83::Decorator
decorates Chouette::Line
+ set_scope { context[:referential] }
+
# Action links require:
# context: {
# referential: ,
@@ -8,9 +10,7 @@ class ReferentialLineDecorator < AF83::Decorator
# }
with_instance_decorator do |instance_decorator|
- instance_decorator.show_action_link do |l|
- l.href { h.referential_line_path(context[:referential], object) }
- end
+ instance_decorator.show_action_link
instance_decorator.action_link secondary: true do |l|
l.content Chouette::Line.human_attribute_name(:footnotes)
@@ -21,7 +21,7 @@ class ReferentialLineDecorator < AF83::Decorator
l.content h.t('routing_constraint_zones.index.title')
l.href do
h.referential_line_routing_constraint_zones_path(
- context[:referential],
+ scope,
object
)
end
@@ -37,7 +37,7 @@ class ReferentialLineDecorator < AF83::Decorator
secondary: true
) do |l|
l.content h.t('routes.actions.new')
- l.href { h.new_referential_line_route_path(context[:referential], object) }
+ l.href { h.new_referential_line_route_path(scope, object) }
end
end
end
diff --git a/app/decorators/referential_network_decorator.rb b/app/decorators/referential_network_decorator.rb
index ff3467188..c508452c0 100644
--- a/app/decorators/referential_network_decorator.rb
+++ b/app/decorators/referential_network_decorator.rb
@@ -1,6 +1,8 @@
class ReferentialNetworkDecorator < AF83::Decorator
decorates Chouette::Network
+ set_scope { context[:referential] }
+
# Action links require:
# context: {
# referential: ,
@@ -8,33 +10,18 @@ class ReferentialNetworkDecorator < AF83::Decorator
create_action_link do |l|
l.content t('networks.actions.new')
- l.href { h.new_referential_network_path(context[:referential]) }
end
with_instance_decorator do |instance_decorator|
- instance_decorator.show_action_link do |l|
- l.href { h.referential_network_path(context[:referential], object) }
- end
+ instance_decorator.show_action_link
instance_decorator.edit_action_link do |l|
l.content t('networks.actions.edit')
- l.href do
- h.edit_referential_network_path(
- context[:referential],
- object
- )
- end
end
instance_decorator.destroy_action_link do |l|
l.content h.destroy_link_content('networks.actions.destroy')
- l.href do
- h.referential_network_path(
- context[:referential],
- object
- )
- end
l.data confirm: h.t('networks.actions.destroy_confirm')
end
end
-end \ No newline at end of file
+end
diff --git a/app/decorators/route_decorator.rb b/app/decorators/route_decorator.rb
index f9870fbbe..fa6367924 100644
--- a/app/decorators/route_decorator.rb
+++ b/app/decorators/route_decorator.rb
@@ -7,26 +7,12 @@ class RouteDecorator < AF83::Decorator
# line:
# }
+ set_scope { [context[:referential], context[:line]] }
+
with_instance_decorator do |instance_decorator|
- instance_decorator.show_action_link do |l|
- l.href do
- h.referential_line_route_path(
- context[:referential],
- context[:line],
- object
- )
- end
- end
+ instance_decorator.show_action_link
- instance_decorator.edit_action_link do |l|
- l.href do
- h.edit_referential_line_route_path(
- context[:referential],
- context[:line],
- object
- )
- end
- end
+ instance_decorator.edit_action_link
instance_decorator.action_link(
if: ->() { object.stop_points.any? },
@@ -86,13 +72,6 @@ class RouteDecorator < AF83::Decorator
end
instance_decorator.destroy_action_link do |l|
- l.href do
- h.referential_line_route_path(
- context[:referential],
- context[:line],
- object
- )
- end
l.data confirm: h.t('routes.actions.destroy_confirm')
end
end
diff --git a/app/decorators/routing_constraint_zone_decorator.rb b/app/decorators/routing_constraint_zone_decorator.rb
index 962625fa7..de73068be 100644
--- a/app/decorators/routing_constraint_zone_decorator.rb
+++ b/app/decorators/routing_constraint_zone_decorator.rb
@@ -1,6 +1,8 @@
class RoutingConstraintZoneDecorator < AF83::Decorator
decorates Chouette::RoutingConstraintZone
+ set_scope { [context[:referential], context[:line]] }
+
# Action links require:
# context: {
# referential: ,
@@ -12,44 +14,13 @@ class RoutingConstraintZoneDecorator < AF83::Decorator
h.policy(Chouette::RoutingConstraintZone).create? &&
context[:referential].organisation == h.current_organisation
}
- ) do |l|
- l.href do
- h.new_referential_line_routing_constraint_zone_path(
- context[:referential],
- context[:line]
- )
- end
- end
+ )
with_instance_decorator do |instance_decorator|
- instance_decorator.show_action_link do |l|
- l.href do
- h.referential_line_routing_constraint_zone_path(
- context[:referential],
- context[:line],
- object
- )
- end
- end
-
- instance_decorator.edit_action_link do |l|
- l.href do
- h.edit_referential_line_routing_constraint_zone_path(
- context[:referential],
- context[:line],
- object
- )
- end
- end
+ instance_decorator.show_action_link
+ instance_decorator.edit_action_link
instance_decorator.destroy_action_link do |l|
- l.href do
- h.referential_line_routing_constraint_zone_path(
- context[:referential],
- context[:line],
- object
- )
- end
l.data confirm: h.t('routing_constraint_zones.actions.destroy_confirm')
end
end
diff --git a/app/decorators/stop_area_decorator.rb b/app/decorators/stop_area_decorator.rb
index 2e57da0e4..525681971 100644
--- a/app/decorators/stop_area_decorator.rb
+++ b/app/decorators/stop_area_decorator.rb
@@ -7,23 +7,11 @@ class StopAreaDecorator < AF83::Decorator
end
with_instance_decorator do |instance_decorator|
- instance_decorator.show_action_link do |l|
- l.href do
- h.stop_area_referential_stop_area_path(
- object.stop_area_referential,
- object
- )
- end
- end
+ set_scope { object.stop_area_referential }
+ instance_decorator.show_action_link
instance_decorator.edit_action_link do |l|
l.content h.t('stop_areas.actions.edit')
- l.href do
- h.edit_stop_area_referential_stop_area_path(
- object.stop_area_referential,
- object
- )
- end
end
instance_decorator.action_link policy: :deactivate, secondary: true do |l|
@@ -54,12 +42,6 @@ class StopAreaDecorator < AF83::Decorator
instance_decorator.destroy_action_link do |l|
l.content h.destroy_link_content('stop_areas.actions.destroy')
- l.href do
- h.stop_area_referential_stop_area_path(
- object.stop_area_referential,
- object
- )
- end
l.data confirm: h.t('stop_areas.actions.destroy_confirm')
end
end
diff --git a/app/decorators/time_table_decorator.rb b/app/decorators/time_table_decorator.rb
index 95b1fd959..e4f9d7dbc 100644
--- a/app/decorators/time_table_decorator.rb
+++ b/app/decorators/time_table_decorator.rb
@@ -14,7 +14,7 @@ class TimeTableDecorator < AF83::Decorator
l.href { [:edit, context[:referential], object] }
end
- instance_decorator.action_link if: ->{ object.calendar }, secondary: true do |l|
+ instance_decorator.action_link policy: :actualize, if: ->{ object.calendar }, secondary: true do |l|
l.content t('actions.actualize')
l.href do
h.actualize_referential_time_table_path(
diff --git a/app/helpers/referentials_helper.rb b/app/helpers/referentials_helper.rb
index 8251377aa..e464ec8a5 100644
--- a/app/helpers/referentials_helper.rb
+++ b/app/helpers/referentials_helper.rb
@@ -15,4 +15,14 @@ module ReferentialsHelper
service = ReferentialOverview.new referential, self
render partial: "referentials/overview", locals: {referential: referential, overview: service}
end
+
+ def mutual_workbench workbench
+ current_user.organisation.workbenches.where(workgroup_id: workbench.workgroup_id).last
+ end
+
+ def duplicate_workbench_referential_path referential
+ workbench = mutual_workbench referential.workbench
+ raise "Missing workbench for referential #{referential.name}" unless workbench.present?
+ new_workbench_referential_path(workbench, from: referential.id)
+ end
end
diff --git a/app/helpers/table_builder_helper.rb b/app/helpers/table_builder_helper.rb
index 9a255e757..2068dd23c 100644
--- a/app/helpers/table_builder_helper.rb
+++ b/app/helpers/table_builder_helper.rb
@@ -330,7 +330,7 @@ module TableBuilderHelper
else
menu = content_tag :ul, class: 'dropdown-menu' do
(
- CustomLinks.new(item, pundit_user, links, referential).links +
+ CustomLinks.new(item, pundit_user, links, referential, workgroup).links +
action_links.select { |link| link.is_a?(Link) }
).map do |link|
gear_menu_link(link)
@@ -395,7 +395,6 @@ module TableBuilderHelper
klass << link.extra_class if link.extra_class
klass << 'delete-action' if link.method == :delete
klass << 'disabled' if link.disabled
-
content_tag(
:li,
link_to(
@@ -414,4 +413,10 @@ module TableBuilderHelper
# cases, avoid a `NoMethodError`.
@__referential__ ||= try(:current_referential)
end
+
+ def workgroup
+ # Certain controllers don't define a `#current_referential`. In these
+ # cases, avoid a `NoMethodError`.
+ @__workgroup__ ||= try(:current_workgroup)
+ end
end
diff --git a/app/helpers/table_builder_helper/custom_links.rb b/app/helpers/table_builder_helper/custom_links.rb
index b1bb11f10..e09078be0 100644
--- a/app/helpers/table_builder_helper/custom_links.rb
+++ b/app/helpers/table_builder_helper/custom_links.rb
@@ -8,13 +8,14 @@ module TableBuilderHelper
unarchive: :put
}
- attr_reader :actions, :object, :user_context, :referential
+ attr_reader :actions, :object, :user_context, :referential, :workgroup
- def initialize(object, user_context, actions, referential = nil)
+ def initialize(object, user_context, actions, referential = nil, workgroup = nil)
@object = object
@user_context = user_context
@actions = actions
@referential = referential
+ @workgroup = workgroup
end
def links
@@ -34,7 +35,7 @@ module TableBuilderHelper
polymorph_url << action
end
- polymorph_url += URL.polymorphic_url_parts(object, referential)
+ polymorph_url += URL.polymorphic_url_parts(object, referential, workgroup)
end
def method_for_action(action)
diff --git a/app/helpers/table_builder_helper/url.rb b/app/helpers/table_builder_helper/url.rb
index 28f1ade76..0e3dce0aa 100644
--- a/app/helpers/table_builder_helper/url.rb
+++ b/app/helpers/table_builder_helper/url.rb
@@ -1,6 +1,6 @@
module TableBuilderHelper
class URL
- def self.polymorphic_url_parts(item, referential)
+ def self.polymorphic_url_parts(item, referential, workgroup)
polymorph_url = []
unless item.is_a?(Calendar) || item.is_a?(Referential) || item.is_a?(ComplianceControlSet)
@@ -20,6 +20,7 @@ module TableBuilderHelper
end
end
else
+ polymorph_url << item.workgroup if item.respond_to? :workgroup
polymorph_url << item
end
diff --git a/app/javascript/helpers/stop_area_header_manager.js b/app/javascript/helpers/stop_area_header_manager.js
index 5b18e2f63..1003b2cf6 100644
--- a/app/javascript/helpers/stop_area_header_manager.js
+++ b/app/javascript/helpers/stop_area_header_manager.js
@@ -15,11 +15,15 @@ export default class StopAreaHeaderManager {
let index = this.ids_list.indexOf(object_id)
let sp = this.stopPointsList[index]
let showHeadline = this.showHeader(object_id)
+ let title = sp.city_name ? sp.city_name + ' (' + sp.zip_code +')' : ""
+ if(sp.waiting_time > 0){
+ title += " | " + sp.waiting_time_text
+ }
return (
<div
className={(showHeadline) ? 'headlined' : ''}
data-headline={showHeadline}
- title={sp.city_name ? sp.city_name + ' (' + sp.zip_code +')' : ""}
+ title={title}
>
<span>
<span>
diff --git a/app/javascript/routes/components/BSelect2.js b/app/javascript/routes/components/BSelect2.js
index 158deaa17..035bce155 100644
--- a/app/javascript/routes/components/BSelect2.js
+++ b/app/javascript/routes/components/BSelect2.js
@@ -85,7 +85,7 @@ class BSelect2 extends Component{
onSelect={ this.props.onSelect }
ref='newSelect'
options={{
- placeholder: this.context.I18n.routes.edit.select2.placeholder,
+ placeholder: this.context.I18n.t("routes.edit.select2.placeholder"),
allowClear: true,
language: 'fr', /* Doesn't seem to work... :( */
theme: 'bootstrap',
diff --git a/app/javascript/routes/components/OlMap.js b/app/javascript/routes/components/OlMap.js
index 056bddbcb..4beb02872 100644
--- a/app/javascript/routes/components/OlMap.js
+++ b/app/javascript/routes/components/OlMap.js
@@ -115,40 +115,40 @@ export default class OlMap extends Component{
<strong>{this.props.value.olMap.json.name}</strong>
</p>
<p>
- <strong>{this.context.I18n.routes.edit.stop_point_type} : </strong>
+ <strong>{this.context.I18n.t('routes.edit.map.stop_point_type')} : </strong>
{this.props.value.olMap.json.area_type}
</p>
<p>
- <strong>{this.context.I18n.routes.edit.short_name} : </strong>
+ <strong>{this.context.I18n.t('routes.edit.map.short_name')} : </strong>
{this.props.value.olMap.json.short_name}
</p>
<p>
- <strong>{this.context.I18n.id_reflex} : </strong>
+ <strong>{this.context.I18n.t('id_reflex')} : </strong>
{this.props.value.olMap.json.user_objectid}
</p>
- <p><strong>{this.context.I18n.routes.edit.map.coordinates} : </strong></p>
+ <p><strong>{this.context.I18n.t('routes.edit.map.coordinates')} : </strong></p>
<p style={{paddingLeft: 10, marginTop: 0}}>
- <em>{this.context.I18n.routes.edit.map.proj}.: </em>WSG84<br/>
- <em>{this.context.I18n.routes.edit.map.lat}.: </em>{this.props.value.olMap.json.latitude} <br/>
- <em>{this.context.I18n.routes.edit.map.lon}.: </em>{this.props.value.olMap.json.longitude}
+ <em>{this.context.I18n.t('routes.edit.map.proj')}.: </em>WSG84<br/>
+ <em>{this.context.I18n.t('routes.edit.map.lat')}.: </em>{this.props.value.olMap.json.latitude} <br/>
+ <em>{this.context.I18n.t('routes.edit.map.lon')}.: </em>{this.props.value.olMap.json.longitude}
</p>
<p>
- <strong>{this.context.I18n.routes.edit.map.postal_code} : </strong>
+ <strong>{this.context.I18n.t('routes.edit.map.postal_code')} : </strong>
{this.props.value.olMap.json.zip_code}
</p>
<p>
- <strong>{this.context.I18n.routes.edit.map.city} : </strong>
+ <strong>{this.context.I18n.t('routes.edit.map.city')} : </strong>
{this.props.value.olMap.json.city_name}
</p>
<p>
- <strong>{this.context.I18n.routes.edit.map.comment} : </strong>
+ <strong>{this.context.I18n.t('routes.edit.map.comment')} : </strong>
{this.props.value.olMap.json.comment}
</p>
{(this.props.value.stoparea_id != this.props.value.olMap.json.stoparea_id) &&(
<div className='btn btn-outline-primary btn-sm'
onClick= {() => {this.props.onUpdateViaOlMap(this.props.index, this.props.value.olMap.json)}}
- >{this.context.I18n.actions.select}</div>
+ >{this.context.I18n.t('actions.select')}</div>
)}
</div>
<div className='map_content'>
@@ -162,7 +162,7 @@ export default class OlMap extends Component{
}
}
-OlMap.PropTypes = {
+OlMap.propTypes = {
}
OlMap.contextTypes = {
diff --git a/app/javascript/routes/components/StopPoint.js b/app/javascript/routes/components/StopPoint.js
index 2d47e802b..af51a6bb4 100644
--- a/app/javascript/routes/components/StopPoint.js
+++ b/app/javascript/routes/components/StopPoint.js
@@ -18,15 +18,15 @@ export default function StopPoint(props, {I18n}) {
<div>
<select className='form-control' value={props.value.for_boarding} id="for_boarding" onChange={props.onSelectChange}>
- <option value="normal">{I18n.routes.edit.stop_point.boarding.normal}</option>
- <option value="forbidden">{I18n.routes.edit.stop_point.boarding.forbidden}</option>
+ <option value="normal">{I18n.t('routes.edit.stop_point.boarding.normal')}</option>
+ <option value="forbidden">{I18n.t('routes.edit.stop_point.boarding.forbidden')}</option>
</select>
</div>
<div>
<select className='form-control' value={props.value.for_alighting} id="for_alighting" onChange={props.onSelectChange}>
- <option value="normal">{I18n.routes.edit.stop_point.alighting.normal}</option>
- <option value="forbidden">{I18n.routes.edit.stop_point.alighting.forbidden}</option>
+ <option value="normal">{I18n.t('routes.edit.stop_point.alighting.normal')}</option>
+ <option value="forbidden">{I18n.t('routes.edit.stop_point.alighting.forbidden')}</option>
</select>
</div>
@@ -77,7 +77,7 @@ export default function StopPoint(props, {I18n}) {
)
}
-StopPoint.PropTypes = {
+StopPoint.propTypes = {
onToggleMap: PropTypes.func.isRequired,
onToggleEdit: PropTypes.func.isRequired,
onDeleteClick: PropTypes.func.isRequired,
@@ -93,4 +93,4 @@ StopPoint.PropTypes = {
StopPoint.contextTypes = {
I18n: PropTypes.object
-} \ No newline at end of file
+}
diff --git a/app/javascript/routes/components/StopPointList.js b/app/javascript/routes/components/StopPointList.js
index b39fa0c9c..b227abdea 100644
--- a/app/javascript/routes/components/StopPointList.js
+++ b/app/javascript/routes/components/StopPointList.js
@@ -10,22 +10,22 @@ export default function StopPointList({ stopPoints, onDeleteClick, onMoveUpClick
<div className="wrapper">
<div style={{width: 100}}>
<div className="form-group">
- <label className="control-label">{I18n.reflex_id}</label>
+ <label className="control-label">{I18n.t('simple_form.labels.stop_point.reflex_id')}</label>
</div>
</div>
<div>
<div className="form-group">
- <label className="control-label">{I18n.simple_form.labels.stop_point.name}</label>
+ <label className="control-label">{I18n.t('simple_form.labels.stop_point.name')}</label>
</div>
</div>
<div>
<div className="form-group">
- <label className="control-label">{I18n.simple_form.labels.stop_point.for_boarding}</label>
+ <label className="control-label">{I18n.t('simple_form.labels.stop_point.for_boarding')}</label>
</div>
</div>
<div>
<div className="form-group">
- <label className="control-label">{I18n.simple_form.labels.stop_point.for_alighting}</label>
+ <label className="control-label">{I18n.t('simple_form.labels.stop_point.for_alighting')}</label>
</div>
</div>
<div className='actions-5'></div>
diff --git a/app/javascript/time_tables/actions/index.js b/app/javascript/time_tables/actions/index.js
index 4a36ec4e1..98b9eab4b 100644
--- a/app/javascript/time_tables/actions/index.js
+++ b/app/javascript/time_tables/actions/index.js
@@ -8,7 +8,7 @@ const I18n = clone(window, "I18n")
const actions = {
weekDays: (index) => {
- return range(1, 8).map(n => I18n.time_tables.edit.metas.days[n])
+ return range(1, 8).map(n => I18n.t('time_tables.edit.metas.days')[n])
},
strToArrayDayTypes: (str) =>{
return actions.weekDays().map(day => str.indexOf(day) !== -1)
@@ -155,7 +155,7 @@ const actions = {
type : 'CLOSE_MODAL'
}),
monthName(strDate) {
- let monthList = range(1,13).map(n => I18n.calendars.months[n])
+ let monthList = range(1,13).map(n => I18n.t('calendars.months.'+ n ))
let date = new Date(strDate)
return monthList[date.getUTCMonth()]
},
@@ -225,7 +225,7 @@ const actions = {
let period = periods[i]
if (index !== i && !period.deleted) {
if (new Date(period.period_start) <= end && new Date(period.period_end) >= start) {
- error = I18n.time_tables.edit.error_submit.periods_overlaps
+ error = I18n.t('time_tables.edit.error_submit.periods_overlaps')
break
}
}
@@ -239,7 +239,7 @@ const actions = {
for (let day of in_days) {
if (start <= new Date(day.date) && end >= new Date(day.date)) {
- error = I18n.time_tables.edit.error_submit.dates_overlaps
+ error = I18n.t('time_tables.edit.error_submit.dates_overlaps')
break
}
}
@@ -316,9 +316,9 @@ const actions = {
errorModalMessage: (errorKey) => {
switch (errorKey) {
case "withoutPeriodsWithDaysTypes":
- return I18n.time_tables.edit.error_modal.withoutPeriodsWithDaysTypes
+ return I18n.t('time_tables.edit.error_modal.withoutPeriodsWithDaysTypes')
case "withPeriodsWithoutDayTypes":
- return I18n.time_tables.edit.error_modal.withPeriodsWithoutDayTypes
+ return I18n.t('time_tables.edit.error_modal.withPeriodsWithoutDayTypes')
default:
return errorKey
diff --git a/app/javascript/time_tables/components/ConfirmModal.js b/app/javascript/time_tables/components/ConfirmModal.js
index 845e7ed1b..4e8583bc0 100644
--- a/app/javascript/time_tables/components/ConfirmModal.js
+++ b/app/javascript/time_tables/components/ConfirmModal.js
@@ -9,11 +9,11 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan
<div className='modal-dialog'>
<div className='modal-content'>
<div className='modal-header'>
- <h4 className='modal-title'>{I18n.time_tables.edit.confirm_modal.title}</h4>
+ <h4 className='modal-title'>{I18n.t('time_tables.edit.confirm_modal.title')}</h4>
</div>
<div className='modal-body'>
<div className='mt-md mb-md'>
- <p>{I18n.time_tables.edit.confirm_modal.message}</p>
+ <p>{I18n.t('time_tables.edit.confirm_modal.message')}</p>
</div>
</div>
<div className='modal-footer'>
@@ -23,7 +23,7 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan
type='button'
onClick={() => { onModalCancel(modal.confirmModal.callback) }}
>
- {I18n.cancel}
+ {I18n.t('cancel')}
</button>
<button
className='btn btn-primary'
@@ -31,7 +31,7 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan
type='button'
onClick={() => { onModalAccept(modal.confirmModal.callback, timetable, metas) }}
>
- {I18n.actions.submit}
+ {I18n.t('actions.submit')}
</button>
</div>
</div>
@@ -49,4 +49,4 @@ ConfirmModal.propTypes = {
ConfirmModal.contextTypes = {
I18n: PropTypes.object
-} \ No newline at end of file
+}
diff --git a/app/javascript/time_tables/components/ErrorModal.js b/app/javascript/time_tables/components/ErrorModal.js
index 543177e54..8af12f1d1 100644
--- a/app/javascript/time_tables/components/ErrorModal.js
+++ b/app/javascript/time_tables/components/ErrorModal.js
@@ -10,7 +10,7 @@ export default function ErrorModal({dispatch, modal, onModalClose}, {I18n}) {
<div className='modal-dialog'>
<div className='modal-content'>
<div className='modal-header'>
- <h4 className='modal-title'>{I18n.time_tables.edit.error_modal.title}</h4>
+ <h4 className='modal-title'>{I18n.t('time_tables.edit.error_modal.title')}</h4>
</div>
<div className='modal-body'>
<div className='mt-md mb-md'>
@@ -24,7 +24,7 @@ export default function ErrorModal({dispatch, modal, onModalClose}, {I18n}) {
type='button'
onClick={() => { onModalClose() }}
>
- {I18n.back}
+ {I18n.t('back')}
</button>
</div>
</div>
@@ -41,4 +41,4 @@ ErrorModal.propTypes = {
ErrorModal.contextTypes = {
I18n: PropTypes.object
-} \ No newline at end of file
+}
diff --git a/app/javascript/time_tables/components/Metas.js b/app/javascript/time_tables/components/Metas.js
index 3c6848d27..08a6e26fe 100644
--- a/app/javascript/time_tables/components/Metas.js
+++ b/app/javascript/time_tables/components/Metas.js
@@ -13,7 +13,7 @@ export default function Metas({metas, onUpdateDayTypes, onUpdateComment, onUpdat
{/* comment (name) */}
<div className="form-group">
<label htmlFor="" className="control-label col-sm-4 required">
- {I18n.time_tables.edit.metas.name} <abbr title="">*</abbr>
+ {I18n.t('time_tables.edit.metas.name')} <abbr title="">*</abbr>
</label>
<div className="col-sm-8">
<input
@@ -28,7 +28,7 @@ export default function Metas({metas, onUpdateDayTypes, onUpdateComment, onUpdat
{/* color */}
{metas.color !== undefined && <div className="form-group">
- <label htmlFor="" className="control-label col-sm-4">{I18n.activerecord.attributes.time_table.color}</label>
+ <label htmlFor="" className="control-label col-sm-4">{I18n.attribute_name('time_table', 'color')}</label>
<div className="col-sm-8">
<div className="dropdown color_selector">
<button
@@ -73,7 +73,7 @@ export default function Metas({metas, onUpdateDayTypes, onUpdateComment, onUpdat
{/* tags */}
{metas.tags !== undefined && <div className="form-group">
- <label htmlFor="" className="control-label col-sm-4">{I18n.activerecord.attributes.time_table.tag_list}</label>
+ <label htmlFor="" className="control-label col-sm-4">{I18n.attribute_name('time_table', 'tag_list')}</label>
<div className="col-sm-8">
<TagsSelect2
initialTags={metas.initial_tags}
@@ -86,16 +86,16 @@ export default function Metas({metas, onUpdateDayTypes, onUpdateComment, onUpdat
{/* calendar */}
{metas.calendar !== null && <div className="form-group">
- <label htmlFor="" className="control-label col-sm-4">{I18n.activerecord.attributes.time_table.calendar}</label>
+ <label htmlFor="" className="control-label col-sm-4">{I18n.attribute_name('time_table', 'calendar')}</label>
<div className="col-sm-8">
- <span>{metas.calendar ? metas.calendar.name : I18n.time_tables.edit.metas.no_calendar}</span>
+ <span>{metas.calendar ? metas.calendar.name : I18n.t('time_tables.edit.metas.no_calendar')}</span>
</div>
</div>}
{/* day_types */}
<div className="form-group">
<label htmlFor="" className="control-label col-sm-4">
- {I18n.time_tables.edit.metas.day_types}
+ {I18n.t('time_tables.edit.metas.day_types')}
</label>
<div className="col-sm-8">
<div className="form-group labelled-checkbox-group">
diff --git a/app/javascript/time_tables/components/PeriodForm.js b/app/javascript/time_tables/components/PeriodForm.js
index 085654a88..d17a246f7 100644
--- a/app/javascript/time_tables/components/PeriodForm.js
+++ b/app/javascript/time_tables/components/PeriodForm.js
@@ -46,7 +46,7 @@ export default function PeriodForm({modal, timetable, metas, onOpenAddPeriodForm
<div>
<div className="form-group">
<label htmlFor="" className="control-label required">
- {I18n.time_tables.edit.period_form.begin}
+ {I18n.t('time_tables.edit.period_form.begin')}
<abbr title="requis">*</abbr>
</label>
</div>
@@ -54,7 +54,7 @@ export default function PeriodForm({modal, timetable, metas, onOpenAddPeriodForm
<div>
<div className="form-group">
<label htmlFor="" className="control-label required">
- {I18n.time_tables.edit.period_form.end}
+ {I18n.t('time_tables.edit.period_form.end')}
<abbr title="requis">*</abbr>
</label>
</div>
@@ -105,14 +105,14 @@ export default function PeriodForm({modal, timetable, metas, onOpenAddPeriodForm
className='btn btn-link'
onClick={onClosePeriodForm}
>
- {I18n.cancel}
+ {I18n.t('cancel')}
</button>
<button
type='button'
className='btn btn-outline-primary mr-sm'
onClick={() => onValidatePeriodForm(modal.modalProps, timetable.time_table_periods, metas, filter(timetable.time_table_dates, ['in_out', true]))}
>
- {I18n.actions.submit}
+ {I18n.t('actions.submit')}
</button>
</div>
</div>
@@ -124,7 +124,7 @@ export default function PeriodForm({modal, timetable, metas, onOpenAddPeriodForm
className='btn btn-outline-primary'
onClick={onOpenAddPeriodForm}
>
- {I18n.time_tables.actions.add_period}
+ {I18n.t('time_tables.actions.add_period')}
</button>
</div>
}
@@ -132,7 +132,7 @@ export default function PeriodForm({modal, timetable, metas, onOpenAddPeriodForm
</div>
</div>
</div>
- )
+ )
}
PeriodForm.propTypes = {
@@ -147,4 +147,4 @@ PeriodForm.propTypes = {
PeriodForm.contextTypes = {
I18n: PropTypes.object
-} \ No newline at end of file
+}
diff --git a/app/javascript/time_tables/components/TagsSelect2.js b/app/javascript/time_tables/components/TagsSelect2.js
index dc3739d58..43cf59fdf 100644
--- a/app/javascript/time_tables/components/TagsSelect2.js
+++ b/app/javascript/time_tables/components/TagsSelect2.js
@@ -40,7 +40,7 @@ export default class TagsSelect2 extends Component {
allowClear: true,
theme: 'bootstrap',
width: '100%',
- placeholder: this.context.I18n.time_tables.edit.select2.tag.placeholder,
+ placeholder: this.context.I18n.t('time_tables.edit.select2.tag.placeholder'),
ajax: {
url: origin + path + '/tags.json',
dataType: 'json',
diff --git a/app/javascript/time_tables/components/Timetable.js b/app/javascript/time_tables/components/Timetable.js
index c44f2a134..991f31435 100644
--- a/app/javascript/time_tables/components/Timetable.js
+++ b/app/javascript/time_tables/components/Timetable.js
@@ -31,11 +31,11 @@ export default class Timetable extends Component {
<div className="table table-2entries mb-sm">
<div className="t2e-head w20">
<div className="th">
- <div className="strong">{this.context.I18n.time_tables.synthesis}</div>
+ <div className="strong">{this.context.I18n.t('time_tables.edit.synthesis')}</div>
</div>
- <div className="td"><span>{this.context.I18n.time_tables.edit.day_types}</span></div>
- <div className="td"><span>{this.context.I18n.time_tables.edit.periods}</span></div>
- <div className="td"><span>{this.context.I18n.time_tables.edit.exceptions}</span></div>
+ <div className="td"><span>{this.context.I18n.t('time_tables.edit.day_types')}</span></div>
+ <div className="td"><span>{this.context.I18n.t('time_tables.edit.periods')}</span></div>
+ <div className="td"><span>{this.context.I18n.t('time_tables.edit.exceptions')}</span></div>
</div>
<div className="t2e-item-list w80">
<div>
diff --git a/app/javascript/vehicle_journeys/actions/index.js b/app/javascript/vehicle_journeys/actions/index.js
index 4ca8bd73b..b398d78fa 100644
--- a/app/javascript/vehicle_journeys/actions/index.js
+++ b/app/javascript/vehicle_journeys/actions/index.js
@@ -348,21 +348,11 @@ const actions = {
var purchaseWindows = []
let tt
for (tt of val.time_tables){
- timeTables.push({
- objectid: tt.objectid,
- comment: tt.comment,
- id: tt.id,
- color: tt.color
- })
+ timeTables.push(tt)
}
if(val.purchase_windows){
for (tt of val.purchase_windows){
- purchaseWindows.push({
- objectid: tt.objectid,
- name: tt.name,
- id: tt.id,
- color: tt.color
- })
+ purchaseWindows.push(tt)
}
}
let vjasWithDelta = val.vehicle_journey_at_stops.map((vjas, i) => {
@@ -527,6 +517,22 @@ const actions = {
minute: actions.simplePad(newArrivalDT.getUTCMinutes())
}
}
+ },
+ addMinutesToTime: (time, minutes) => {
+ let res = {
+ hour: time.hour,
+ minute: time.minute
+ }
+ let delta_hour = parseInt(minutes/60)
+ let delta_minute = minutes - 60*delta_hour
+ res.hour += delta_hour
+ res.minute += delta_minute
+ let extra_hours = parseInt(res.minute/60)
+ res.hour += extra_hours
+ res.minute -= extra_hours*60
+ res.hour = res.hour % 24
+
+ return res
}
}
diff --git a/app/javascript/vehicle_journeys/components/ConfirmModal.js b/app/javascript/vehicle_journeys/components/ConfirmModal.js
index 3bfc852fb..75e8a3932 100644
--- a/app/javascript/vehicle_journeys/components/ConfirmModal.js
+++ b/app/javascript/vehicle_journeys/components/ConfirmModal.js
@@ -7,7 +7,7 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan
<div className='modal-dialog'>
<div className='modal-content'>
<div className='modal-body'>
- <p> Voulez-vous valider vos modifications avant de changer de page? </p>
+ <p> {I18n.t('vehicle_journeys.vehicle_journeys_matrix.modal_confirm')} </p>
</div>
<div className='modal-footer'>
<button
@@ -31,11 +31,11 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan
</div>
</div>
)
-}
+}
ConfirmModal.propTypes = {
vehicleJourneys: PropTypes.array.isRequired,
modal: PropTypes.object.isRequired,
onModalAccept: PropTypes.func.isRequired,
onModalCancel: PropTypes.func.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/Filters.js b/app/javascript/vehicle_journeys/components/Filters.js
index 2bd912e3e..f8697c930 100644
--- a/app/javascript/vehicle_journeys/components/Filters.js
+++ b/app/javascript/vehicle_journeys/components/Filters.js
@@ -46,10 +46,10 @@ export default function Filters({filters, pagination, missions, onFilter, onRese
<div className='ffg-row'>
{/* Plage horaire */}
<div className='form-group togglable'>
- <label className='control-label'>Plage horaire au départ de la course</label>
+ <label className='control-label'>{I18n.t("vehicle_journeys.form.departure_range.label")}</label>
<div className='filter_menu'>
<div className='form-group time filter_menu-item'>
- <label className='control-label time'>Début</label>
+ <label className='control-label time'>{I18n.t("vehicle_journeys.form.departure_range.start")}</label>
<div className='form-inline'>
<div className='input-group time'>
<input
@@ -73,7 +73,7 @@ export default function Filters({filters, pagination, missions, onFilter, onRese
</div>
</div>
<div className='form-group time filter_menu-item'>
- <label className='control-label time'>Fin</label>
+ <label className='control-label time'>{I18n.t("vehicle_journeys.form.departure_range.end")}</label>
<div className='form-inline'>
<div className='input-group time'>
<input
@@ -101,7 +101,7 @@ export default function Filters({filters, pagination, missions, onFilter, onRese
{/* Switch avec/sans horaires */}
<div className='form-group has_switch'>
- <label className='control-label pull-left'>Afficher les courses sans horaires</label>
+ <label className='control-label pull-left'>{I18n.t("vehicle_journeys.form.show_journeys_without_schedule")}</label>
<div className='form-group pull-left' style={{padding: 0}}>
<div className='checkbox'>
<label>
@@ -110,8 +110,8 @@ export default function Filters({filters, pagination, missions, onFilter, onRese
onChange={onToggleWithoutSchedule}
checked={filters.query.withoutSchedule}
></input>
- <span className='switch-label' data-checkedvalue='Non' data-uncheckedvalue='Oui'>
- {filters.query.withoutSchedule ? 'Oui' : 'Non'}
+ <span className='switch-label' data-checkedvalue={I18n.t("no")} data-uncheckedvalue={I18n.t("yes")}>
+ {filters.query.withoutSchedule ? I18n.t("yes") : I18n.t("no")}
</span>
</label>
</div>
@@ -122,7 +122,7 @@ export default function Filters({filters, pagination, missions, onFilter, onRese
<div className="ffg-row">
{/* Switch avec/sans calendrier */}
<div className='form-group has_switch'>
- <label className='control-label pull-left'>Afficher les courses avec calendrier</label>
+ <label className='control-label pull-left'>{I18n.t("vehicle_journeys.form.show_journeys_with_calendar")}</label>
<div className='form-group pull-left' style={{padding: 0}}>
<div className='checkbox'>
<label>
@@ -131,8 +131,8 @@ export default function Filters({filters, pagination, missions, onFilter, onRese
onChange={onToggleWithoutTimeTable}
checked={filters.query.withoutTimeTable}
></input>
- <span className='switch-label' data-checkedvalue='Non' data-uncheckedvalue='Oui'>
- {filters.query.withoutTimeTable ? 'Oui' : 'Non'}
+ <span className='switch-label' data-checkedvalue={I18n.t("no")} data-uncheckedvalue={I18n.t("yes")}>
+ {filters.query.withoutTimeTable ? I18n.t("yes") : I18n.t("no")}
</span>
</label>
</div>
diff --git a/app/javascript/vehicle_journeys/components/Navigate.js b/app/javascript/vehicle_journeys/components/Navigate.js
index 0158b8392..24843babc 100644
--- a/app/javascript/vehicle_journeys/components/Navigate.js
+++ b/app/javascript/vehicle_journeys/components/Navigate.js
@@ -17,8 +17,7 @@ export default function Navigate({ dispatch, vehicleJourneys, pagination, status
if(status.fetchSuccess == true) {
return (
<div className="pagination">
- Liste des horaires {minVJ} à {maxVJ} sur {pagination.totalCount}
-
+ {I18n.t("vehicle_journeys.vehicle_journeys_matrix.pagination", {minVJ, maxVJ, total:pagination.totalCount})}
<form className='page_links' onSubmit={e => {e.preventDefault()}}>
<button
onClick={e => {
@@ -53,4 +52,4 @@ Navigate.propTypes = {
status: PropTypes.object.isRequired,
pagination: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/ToggleArrivals.js b/app/javascript/vehicle_journeys/components/ToggleArrivals.js
index 9e7089be5..9a2b0097f 100644
--- a/app/javascript/vehicle_journeys/components/ToggleArrivals.js
+++ b/app/javascript/vehicle_journeys/components/ToggleArrivals.js
@@ -5,7 +5,7 @@ import PropTypes from 'prop-types'
export default function ToggleArrivals({filters, onToggleArrivals}) {
return (
<div className='has_switch form-group inline'>
- <label htmlFor='toggleArrivals' className='control-label'>Afficher et éditer les horaires d'arrivée</label>
+ <label htmlFor='toggleArrivals' className='control-label'>{I18n.t('vehicle_journeys.form.show_arrival_time')}</label>
<div className='form-group'>
<div className='checkbox'>
<label>
diff --git a/app/javascript/vehicle_journeys/components/Tools.js b/app/javascript/vehicle_journeys/components/Tools.js
index ee02e5a68..22ea44283 100644
--- a/app/javascript/vehicle_journeys/components/Tools.js
+++ b/app/javascript/vehicle_journeys/components/Tools.js
@@ -44,8 +44,8 @@ export default class Tools extends Component {
<DeleteVehicleJourneys disabled={!this.hasPolicy("destroy") || !editMode}/>
</ul>
- <span className='info-msg'>{actions.getSelected(vehicleJourneys).length} course(s) sélectionnée(s)</span>
- <button className='btn btn-xs btn-link pull-right' onClick={onCancelSelection}>Annuler la sélection</button>
+ <span className='info-msg'>{I18n.t('vehicle_journeys.vehicle_journeys_matrix.selected_journeys', {count: actions.getSelected(vehicleJourneys).length})}</span>
+ <button className='btn btn-xs btn-link pull-right' onClick={onCancelSelection}>{I18n.t('vehicle_journeys.vehicle_journeys_matrix.cancel_selection')}</button>
</div>
)
}
diff --git a/app/javascript/vehicle_journeys/components/VehicleJourney.js b/app/javascript/vehicle_journeys/components/VehicleJourney.js
index 99a458f50..e11e91497 100644
--- a/app/javascript/vehicle_journeys/components/VehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/VehicleJourney.js
@@ -23,7 +23,7 @@ export default class VehicleJourney extends Component {
let ttURL = refURL + '/time_tables/' + tt.id
return (
- <a href={ttURL} title='Voir le calendrier'><span className='fa fa-calendar' style={{ color: (tt.color ? tt.color : '#4B4B4B')}}></span></a>
+ <a href={ttURL} title={I18n.t('vehicle_journeys.vehicle_journeys_matrix.show_timetable')}><span className='fa fa-calendar' style={{ color: (tt.color ? tt.color : '#4B4B4B')}}></span></a>
)
}
@@ -32,7 +32,7 @@ export default class VehicleJourney extends Component {
let ttURL = refURL + '/purchase_windows/' + tt.id
return (
- <a href={ttURL} title='Voir le calendrier commercial'><span className='fa fa-calendar' style={{color: (tt.color ? tt.color : '')}}></span></a>
+ <a href={ttURL} title={I18n.t('vehicle_journeys.vehicle_journeys_matrix.show_purchase_window')}><span className='fa fa-calendar' style={{color: (tt.color ? tt.color : '')}}></span></a>
)
}
@@ -48,12 +48,24 @@ export default class VehicleJourney extends Component {
}
}
+ hasTimeTable(time_tables, tt) {
+ let found = false
+ time_tables.map((t, index) => {
+ if(t.id == tt.id){
+ found = true
+ return
+ }
+ })
+ return found
+ }
+
isDisabled(bool1, bool2) {
return (bool1 || bool2)
}
render() {
this.previousCity = undefined
+ let detailed_calendars = this.hasFeature('detailed_calendars') && !this.disabled
let {time_tables, purchase_windows} = this.props.value
return (
@@ -65,23 +77,23 @@ export default class VehicleJourney extends Component {
}
>
<div className='strong mb-xs'>{this.props.value.short_id || '-'}</div>
- <div>{this.props.value.published_journey_name && this.props.value.published_journey_name != "non renseigné" ? this.props.value.published_journey_name : '-'}</div>
+ <div>{this.props.value.published_journey_name && this.props.value.published_journey_name != I18n.t('undefined') ? this.props.value.published_journey_name : '-'}</div>
<div>{this.props.value.journey_pattern.short_id || '-'}</div>
<div>{this.props.value.company ? this.props.value.company.name : '-'}</div>
+ { this.hasFeature('purchase_windows') &&
+ <div>
+ {purchase_windows.slice(0,3).map((tt, i)=>
+ <span key={i} className='vj_tt'>{this.purchaseWindowURL(tt)}</span>
+ )}
+ {purchase_windows.length > 3 && <span className='vj_tt'> + {purchase_windows.length - 3}</span>}
+ </div>
+ }
<div>
{time_tables.slice(0,3).map((tt, i)=>
<span key={i} className='vj_tt'>{this.timeTableURL(tt)}</span>
)}
{time_tables.length > 3 && <span className='vj_tt'> + {time_tables.length - 3}</span>}
</div>
- { this.hasFeature('purchase_windows') &&
- <div>
- {purchase_windows.slice(0,3).map((tt, i)=>
- <span key={i} className='vj_tt'>{this.purchaseWindowURL(tt)}</span>
- )}
- {purchase_windows.length > 3 && <span className='vj_tt'> + {purchase_windows.length - 3}</span>}
- </div>
- }
{!this.props.disabled && <div className={(this.props.value.deletable ? 'disabled ' : '') + 'checkbox'}>
<input
id={this.props.index}
@@ -94,13 +106,22 @@ export default class VehicleJourney extends Component {
></input>
<label htmlFor={this.props.index}></label>
</div>}
+
{this.props.disabled && <VehicleJourneyInfoButton vehicleJourney={this.props.value} />}
+
+ { detailed_calendars &&
+ <div className="detailed-timetables hidden">
+ {this.props.allTimeTables.map((tt, i) =>
+ <div key={i} className={(this.hasTimeTable(time_tables, tt) ? "active" : "inactive")}></div>
+ )}
+ </div>
+ }
</div>
{this.props.value.vehicle_journey_at_stops.map((vj, i) =>
<div key={i} className='td text-center'>
<div className={'cellwrap' + (this.cityNameChecker(vj) ? ' headlined' : '')}>
{this.props.filters.toggleArrivals &&
- <div data-headline='Arrivée à'>
+ <div data-headline={I18n.t("vehicle_journeys.form.arrival_at")}>
<span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false) ? 'disabled ' : '') + 'input-group time'}>
<input
type='number'
@@ -131,7 +152,7 @@ export default class VehicleJourney extends Component {
<span className='sb sb-chrono sb-lg text-warning' data-textinside={vj.delta}></span>
}
</div>
- <div data-headline='Départ à'>
+ <div data-headline={I18n.t("vehicle_journeys.form.departure_at")}>
<span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false) ? 'disabled ' : '') + 'input-group time'}>
<input
type='number'
@@ -174,4 +195,5 @@ VehicleJourney.propTypes = {
onUpdateTime: PropTypes.func.isRequired,
onSelectVehicleJourney: PropTypes.func.isRequired,
vehicleJourneys: PropTypes.object.isRequired,
+ allTimeTables: PropTypes.array.isRequired,
}
diff --git a/app/javascript/vehicle_journeys/components/VehicleJourneys.js b/app/javascript/vehicle_journeys/components/VehicleJourneys.js
index ae852b35a..843aec1a8 100644
--- a/app/javascript/vehicle_journeys/components/VehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/components/VehicleJourneys.js
@@ -12,6 +12,7 @@ export default class VehicleJourneys extends Component {
this.stopPoints(),
this.props.filters.features
)
+ this.toggleTimetables = this.toggleTimetables.bind(this)
}
isReturn() {
@@ -48,9 +49,35 @@ export default class VehicleJourneys extends Component {
return this.headerManager.showHeader(object_id)
}
+ allTimeTables() {
+ if(this._allTimeTables){
+ return this._allTimeTables
+ }
+ let keys = []
+ this._allTimeTables = []
+ this.vehicleJourneysList().map((vj, index) => {
+ vj.time_tables.map((tt, _) => {
+ if(keys.indexOf(tt.id) < 0){
+ keys.push(tt.id)
+ this._allTimeTables.push(tt)
+ }
+ })
+ })
+ return this._allTimeTables
+ }
+
+ toggleTimetables(e) {
+ $('.table-2entries .detailed-timetables').toggleClass('hidden')
+ $('.table-2entries .detailed-timetables-bt').toggleClass('active')
+ this.componentDidUpdate()
+ e.preventDefault()
+ false
+ }
+
componentDidUpdate(prevProps, prevState) {
if(this.props.status.isFetching == false){
$('.table-2entries').each(function() {
+ $(this).find('.th').css('height', 'auto')
var refH = []
var refCol = []
@@ -91,9 +118,19 @@ export default class VehicleJourneys extends Component {
}
}
+ timeTableURL(tt) {
+ let refURL = window.location.pathname.split('/', 3).join('/')
+ let ttURL = refURL + '/time_tables/' + tt.id
+
+ return (
+ <a href={ttURL} title='Voir le calendrier'><span className='fa fa-calendar' style={{color: (tt.color ? tt.color : '#4B4B4B')}}></span>{tt.days || tt.comment}</a>
+ )
+ }
+
render() {
this.previousBreakpoint = undefined
-
+ this._allTimeTables = null
+ let detailed_calendars = this.hasFeature('detailed_calendars') && !this.isReturn() && (this.allTimeTables().length > 0)
if(this.props.status.isFetching == true) {
return (
<div className="isLoading" style={{marginTop: 80, marginBottom: 80}}>
@@ -106,14 +143,14 @@ export default class VehicleJourneys extends Component {
<div className='col-lg-12'>
{(this.props.status.fetchSuccess == false) && (
<div className='alert alert-danger mt-sm'>
- <strong>Erreur : </strong>
- la récupération des missions a rencontré un problème. Rechargez la page pour tenter de corriger le problème.
+ <strong>{I18n.tc("error")}</strong>
+ {I18n.t("vehicle_journeys.vehicle_journeys_matrix.fetching_error")}
</div>
)}
{ this.vehicleJourneysList().errors && this.vehicleJourneysList().errors.length && _.some(this.vehicleJourneysList(), 'errors') && (
<div className="alert alert-danger mt-sm">
- <strong>Erreur : </strong>
+ <strong>{I18n.tc("error")}</strong>
{this.vehicleJourneysList().map((vj, index) =>
vj.errors && vj.errors.map((err, i) => {
return (
@@ -129,12 +166,32 @@ export default class VehicleJourneys extends Component {
<div className={'table table-2entries mt-sm mb-sm' + ((this.vehicleJourneysList().length > 0) ? '' : ' no_result')}>
<div className='t2e-head w20'>
<div className='th'>
- <div className='strong mb-xs'>ID course</div>
- <div>Nom course</div>
- <div>ID mission</div>
- <div>Transporteur</div>
- <div>Calendriers</div>
- { this.hasFeature('purchase_windows') && <div>Calendriers Commerciaux</div> }
+ <div className='strong mb-xs'>{I18n.attribute_name("vehicle_journey", "id")}</div>
+ <div>{I18n.attribute_name("vehicle_journey", "name")}</div>
+ <div>{I18n.attribute_name("vehicle_journey", "journey_pattern_id")}</div>
+ <div>{I18n.model_name("company")}</div>
+ { this.hasFeature('purchase_windows') && <div>{I18n.model_name("purchase_window", "plural": true)}</div> }
+ <div>
+ { detailed_calendars &&
+ <a href='#' onClick={this.toggleTimetables} className='detailed-timetables-bt'>
+ <span className='fa fa-angle-up'></span>
+ {I18n.model_name("time_table", "plural": true)}
+ </a>
+ }
+ { !detailed_calendars && I18n.model_name("time_table", "plural": true)}
+ </div>
+ { !this.isReturn() &&
+ <div className="detailed-timetables hidden">
+ {this.allTimeTables().map((tt, i)=>
+ <div key={i}>
+ <p>
+ {this.timeTableURL(tt)}
+ </p>
+ <p>{tt.bounding_dates}</p>
+ </div>
+ )}
+ </div>
+ }
</div>
{this.stopPoints().map((sp, i) =>{
return (
@@ -159,6 +216,7 @@ export default class VehicleJourneys extends Component {
onSelectVehicleJourney={this.props.onSelectVehicleJourney}
vehicleJourneys={this}
disabled={this.isReturn()}
+ allTimeTables={this.allTimeTables()}
/>
)}
</div>
diff --git a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js
index f6a0e3c61..d3c01f154 100644
--- a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js
@@ -59,7 +59,7 @@ export default class EditVehicleJourney extends Component {
<div className='modal-dialog'>
<div className='modal-content'>
<div className='modal-header'>
- <h4 className='modal-title'>Informations</h4>
+ <h4 className='modal-title'>{I18n.t('vehicle_journeys.form.infos')}</h4>
<span type="button" className="close modal-close" data-dismiss="modal">&times;</span>
</div>
@@ -69,7 +69,7 @@ export default class EditVehicleJourney extends Component {
<div className='row'>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Nom de la course</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'journey_name')}</label>
<input
type='text'
ref='published_journey_name'
@@ -82,7 +82,7 @@ export default class EditVehicleJourney extends Component {
</div>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Mission</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'journey_pattern')}</label>
<input
type='text'
className='form-control'
@@ -96,7 +96,7 @@ export default class EditVehicleJourney extends Component {
<div className='row'>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Numéro de train</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'company')}</label>
<input
type='text'
ref='published_journey_identifier'
@@ -109,7 +109,7 @@ export default class EditVehicleJourney extends Component {
</div>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Transporteur</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'company')}</label>
<CompanySelect2
editModal={this.props.modal.type == "edit"}
editMode={this.editMode()}
@@ -124,29 +124,29 @@ export default class EditVehicleJourney extends Component {
<div className='row'>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Mode de transport</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'transport_mode')}</label>
<input
type='text'
className='form-control'
- value={window.I18n.fr.enumerize.transport_mode[this.props.modal.modalProps.vehicleJourney.transport_mode]}
+ value={I18n.enumerize('transport_mode', this.props.modal.modalProps.vehicleJourney.transport_mode)}
disabled={true}
/>
</div>
</div>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Sous mode de transport</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'transport_submode')}</label>
<input
type='text'
className='form-control'
- value={window.I18n.fr.enumerize.transport_submode[this.props.modal.modalProps.vehicleJourney.transport_submode]}
+ value={I18n.enumerize('transport_submode', this.props.modal.modalProps.vehicleJourney.transport_submode)}
disabled={true}
/>
</div>
</div>
</div>
<div className='form-group'>
- <label className='control-label'>Signature métier</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'checksum')}</label>
<input
type='text'
ref='checksum'
diff --git a/app/javascript/vehicle_journeys/components/tools/VehicleJourneyInfoButton.js b/app/javascript/vehicle_journeys/components/tools/VehicleJourneyInfoButton.js
index a63a1d701..538bbdbd6 100644
--- a/app/javascript/vehicle_journeys/components/tools/VehicleJourneyInfoButton.js
+++ b/app/javascript/vehicle_journeys/components/tools/VehicleJourneyInfoButton.js
@@ -10,7 +10,7 @@ export default class VehicleJourneyInfoButton extends Component {
render() {
return (
- <li className='st_action'>
+ <div className='info-button'>
<button
type='button'
data-toggle='modal'
@@ -19,7 +19,7 @@ export default class VehicleJourneyInfoButton extends Component {
>
<span className='fa fa-info'></span>
</button>
- </li>
+ </div>
)
}
}
diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js
index 7ab85a1ea..72dbd0152 100644
--- a/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js
+++ b/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js
@@ -29,11 +29,11 @@ export default class BSelect4 extends Component {
val = this.props.selection.selectedJPModal
}
}
- if(this.useAjax()){
- val = val.published_name
- }
- else{
- if(val){
+ if(val){
+ if(this.useAjax()){
+ val = val.published_name
+ }
+ else{
val = val.id
}
}
diff --git a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
index 1a15ec46d..383dea4a0 100644
--- a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
@@ -19,26 +19,17 @@ const vehicleJourney= (state = {}, action, keep) => {
current_time.minute = parseInt(action.data["start_time.minute"].value) || 0
}
_.each(action.stopPointsList, (sp) =>{
+ let inJourney = false
if(action.selectedJourneyPattern.full_schedule && action.selectedJourneyPattern.costs && action.selectedJourneyPattern.costs[prevSp.stop_area_id + "-" + sp.stop_area_id]){
let delta = parseInt(action.selectedJourneyPattern.costs[prevSp.stop_area_id + "-" + sp.stop_area_id].time)
- let delta_hour = parseInt(delta/60)
- let delta_minute = delta - 60*delta_hour
- current_time.hour += delta_hour
- current_time.minute += delta_minute
- let extra_hours = parseInt(current_time.minute/60)
- current_time.hour += extra_hours
- current_time.minute -= extra_hours*60
- current_time.hour = current_time.hour % 24
+ current_time = actions.addMinutesToTime(current_time, delta)
prevSp = sp
+ inJourney = true
}
let offsetHours = sp.time_zone_offset / 3600
let offsetminutes = sp.time_zone_offset/60 - 60*offsetHours
let newVjas = {
delta: 0,
- departure_time:{
- hour: (24 + current_time.hour + offsetHours) % 24,
- minute: current_time.minute + offsetminutes
- },
arrival_time:{
hour: (24 + current_time.hour + offsetHours) % 24,
minute: current_time.minute + offsetminutes
@@ -47,6 +38,16 @@ const vehicleJourney= (state = {}, action, keep) => {
stop_area_cityname: sp.city_name,
dummy: true
}
+
+ if(sp.waiting_time && inJourney){
+ current_time = actions.addMinutesToTime(current_time, parseInt(sp.waiting_time))
+ }
+
+ newVjas.departure_time = {
+ hour: (24 + current_time.hour + offsetHours) % 24,
+ minute: current_time.minute + offsetminutes
+ }
+
if(current_time.hour + offsetHours > 24){
newVjas.departure_day_offset = 1
newVjas.arrival_day_offset = 1
diff --git a/app/models/calendar.rb b/app/models/calendar.rb
index 561a2e3f7..84b569ab4 100644
--- a/app/models/calendar.rb
+++ b/app/models/calendar.rb
@@ -10,8 +10,9 @@ class Calendar < ActiveRecord::Base
has_paper_trail class_name: 'PublicVersion'
belongs_to :organisation
+ belongs_to :workgroup
- validates_presence_of :name, :short_name, :organisation
+ validates_presence_of :name, :short_name, :organisation, :workgroup
validates_uniqueness_of :short_name
has_many :time_tables
diff --git a/app/models/chouette/company.rb b/app/models/chouette/company.rb
index b3d40ab96..53e412600 100644
--- a/app/models/chouette/company.rb
+++ b/app/models/chouette/company.rb
@@ -15,6 +15,5 @@ module Chouette
[:organizational_unit, :operating_department_name, :code, :phone, :fax, :email, :url, :time_zone]
end
-
end
end
diff --git a/app/models/chouette/journey_pattern.rb b/app/models/chouette/journey_pattern.rb
index aa9fdb810..830e985d9 100644
--- a/app/models/chouette/journey_pattern.rb
+++ b/app/models/chouette/journey_pattern.rb
@@ -170,5 +170,21 @@ module Chouette
end
full
end
+
+ def set_distances distances
+ raise "inconsistent data: #{distances.count} values for #{stop_points.count} stops" unless distances.count == stop_points.count
+ prev = distances[0].to_i
+ _costs = self.costs
+ distances[1..-1].each_with_index do |distance, i|
+ distance = distance.to_i
+ relative = distance - prev
+ prev = distance
+ start, stop = stop_points[i..i+1]
+ key = "#{start.stop_area_id}-#{stop.stop_area_id}"
+ _costs[key] ||= {}
+ _costs[key]["distance"] = relative
+ end
+ self.costs = _costs
+ end
end
end
diff --git a/app/models/chouette/line.rb b/app/models/chouette/line.rb
index ba2e2755d..d077d5c9d 100644
--- a/app/models/chouette/line.rb
+++ b/app/models/chouette/line.rb
@@ -41,6 +41,7 @@ module Chouette
validates_presence_of :name
+
scope :by_text, ->(text) { where('lower(name) LIKE :t or lower(published_name) LIKE :t or lower(objectid) LIKE :t or lower(comment) LIKE :t or lower(number) LIKE :t',
t: "%#{text.downcase}%") }
@@ -80,6 +81,14 @@ module Chouette
line_referential.companies.where(id: ([company_id] + Array(secondary_company_ids)).compact)
end
+ def deactivate
+ self.deactivated = true
+ end
+
+ def activate
+ self.deactivated = false
+ end
+
def deactivate!
update_attribute :deactivated, true
end
diff --git a/app/models/chouette/purchase_window.rb b/app/models/chouette/purchase_window.rb
index 334493015..157390a21 100644
--- a/app/models/chouette/purchase_window.rb
+++ b/app/models/chouette/purchase_window.rb
@@ -19,6 +19,7 @@ module Chouette
scope :contains_date, ->(date) { where('date ? <@ any (date_ranges)', date) }
scope :overlap_dates, ->(date_range) { where('daterange(?, ?) && any (date_ranges)', date_range.first, date_range.last + 1.day) }
+ scope :matching_dates, ->(date_range) { where('ARRAY[daterange(?, ?)] = date_ranges', date_range.first, date_range.last + 1.day) }
def self.ransackable_scopes(auth_object = nil)
[:contains_date]
diff --git a/app/models/chouette/route.rb b/app/models/chouette/route.rb
index 47c18af09..3729deb7d 100644
--- a/app/models/chouette/route.rb
+++ b/app/models/chouette/route.rb
@@ -133,7 +133,7 @@ module Chouette
def checksum_attributes
values = self.slice(*['name', 'published_name', 'wayback']).values
values.tap do |attrs|
- attrs << self.stop_points.sort_by(&:position).map{|sp| "#{sp.stop_area.user_objectid}#{sp.for_boarding}#{sp.for_alighting}" }.join
+ attrs << self.stop_points.sort_by(&:position).map{|sp| [sp.stop_area.user_objectid, sp.for_boarding, sp.for_alighting]}
attrs << self.routing_constraint_zones.map(&:checksum)
end
end
@@ -185,6 +185,12 @@ module Chouette
return true
end
+ def full_journey_pattern
+ journey_pattern = journey_patterns.find_or_create_by registration_number: self.number, name: self.name
+ journey_pattern.stop_points = self.stop_points
+ journey_pattern
+ end
+
protected
def self.vehicle_journeys_timeless(stop_point_id)
diff --git a/app/models/chouette/routing_constraint_zone.rb b/app/models/chouette/routing_constraint_zone.rb
index 903922241..58703598e 100644
--- a/app/models/chouette/routing_constraint_zone.rb
+++ b/app/models/chouette/routing_constraint_zone.rb
@@ -25,7 +25,9 @@ module Chouette
end
def checksum_attributes
- self.stop_points.map(&:stop_area).map(&:user_objectid)
+ [
+ self.stop_points.map(&:stop_area).map(&:user_objectid)
+ ]
end
def stop_points_belong_to_route
diff --git a/app/models/chouette/stop_area.rb b/app/models/chouette/stop_area.rb
index bb8747faa..7170dd217 100644
--- a/app/models/chouette/stop_area.rb
+++ b/app/models/chouette/stop_area.rb
@@ -369,6 +369,14 @@ module Chouette
!activated?
end
+ def activate
+ self.deleted_at = nil
+ end
+
+ def deactivate
+ self.deleted_at = Time.now
+ end
+
def activate!
update_attribute :deleted_at, nil
end
@@ -384,8 +392,8 @@ module Chouette
def country_name
return unless country_code
-
country = ISO3166::Country[country_code]
+ return unless country
country.translations[I18n.locale.to_s] || country.name
end
diff --git a/app/models/chouette/time_table.rb b/app/models/chouette/time_table.rb
index 15b22b671..b76de852a 100644
--- a/app/models/chouette/time_table.rb
+++ b/app/models/chouette/time_table.rb
@@ -44,10 +44,10 @@ module Chouette
attrs << self.int_day_types
dates = self.dates
dates += TimeTableDate.where(time_table_id: self.id)
- attrs << dates.map(&:checksum).map(&:to_s).sort
+ attrs << dates.map(&:checksum).map(&:to_s).uniq.sort
periods = self.periods
periods += TimeTablePeriod.where(time_table_id: self.id)
- attrs << periods.map(&:checksum).map(&:to_s).sort
+ attrs << periods.map(&:checksum).map(&:to_s).uniq.sort
end
end
diff --git a/app/models/chouette/vehicle_journey.rb b/app/models/chouette/vehicle_journey.rb
index 4a6ba3f75..1a79db823 100644
--- a/app/models/chouette/vehicle_journey.rb
+++ b/app/models/chouette/vehicle_journey.rb
@@ -105,7 +105,7 @@ module Chouette
attrs << self.try(:company).try(:get_objectid).try(:local_id)
attrs << self.footnotes.map(&:checksum).sort
vjas = self.vehicle_journey_at_stops
- vjas += VehicleJourneyAtStop.where(vehicle_journey_id: self.id)
+ vjas += VehicleJourneyAtStop.where(vehicle_journey_id: self.id) unless self.new_record?
attrs << vjas.uniq.sort_by { |s| s.stop_point&.position }.map(&:checksum).sort
end
end
@@ -381,8 +381,8 @@ module Chouette
end
def self.lines
- lines_query = joins(:route).select("routes.line_id").to_sql
- Chouette::Line.where("id IN (#{lines_query})")
+ lines_query = joins(:route).select("routes.line_id").reorder(nil).except(:group).pluck(:'routes.line_id')
+ Chouette::Line.where(id: lines_query)
end
end
end
diff --git a/app/models/chouette/vehicle_journey_at_stop.rb b/app/models/chouette/vehicle_journey_at_stop.rb
index eda711ade..3b4f35f13 100644
--- a/app/models/chouette/vehicle_journey_at_stop.rb
+++ b/app/models/chouette/vehicle_journey_at_stop.rb
@@ -41,7 +41,7 @@ module Chouette
:arrival_day_offset,
I18n.t(
'vehicle_journey_at_stops.errors.day_offset_must_not_exceed_max',
- short_id: vehicle_journey.get_objectid.short_id,
+ short_id: vehicle_journey&.get_objectid&.short_id,
max: DAY_OFFSET_MAX + 1
)
)
@@ -52,7 +52,7 @@ module Chouette
:departure_day_offset,
I18n.t(
'vehicle_journey_at_stops.errors.day_offset_must_not_exceed_max',
- short_id: vehicle_journey.get_objectid.short_id,
+ short_id: vehicle_journey&.get_objectid&.short_id,
max: DAY_OFFSET_MAX + 1
)
)
@@ -69,8 +69,8 @@ module Chouette
def checksum_attributes
[].tap do |attrs|
- attrs << self.departure_time.try(:to_s, :time)
- attrs << self.arrival_time.try(:to_s, :time)
+ attrs << self.departure_time&.utc.try(:to_s, :time)
+ attrs << self.arrival_time&.utc.try(:to_s, :time)
attrs << self.departure_day_offset.to_s
attrs << self.arrival_day_offset.to_s
end
diff --git a/app/models/chouette/vehicle_journey_at_stops_day_offset.rb b/app/models/chouette/vehicle_journey_at_stops_day_offset.rb
index b2cb90d11..7497cd72c 100644
--- a/app/models/chouette/vehicle_journey_at_stops_day_offset.rb
+++ b/app/models/chouette/vehicle_journey_at_stops_day_offset.rb
@@ -11,13 +11,19 @@ module Chouette
@at_stops.inject(nil) do |prior_stop, stop|
next stop if prior_stop.nil?
- if stop.arrival_time < prior_stop.departure_time ||
- stop.arrival_time < prior_stop.arrival_time
+ # we only compare time of the day, not actual times
+ stop_arrival_time = stop.arrival_time - stop.arrival_time.to_date.to_time
+ stop_departure_time = stop.departure_time - stop.departure_time.to_date.to_time
+ prior_stop_arrival_time = prior_stop.arrival_time - prior_stop.arrival_time.to_date.to_time
+ prior_stop_departure_time = prior_stop.departure_time - prior_stop.departure_time.to_date.to_time
+
+ if stop_arrival_time < prior_stop_departure_time ||
+ stop_arrival_time < prior_stop_arrival_time
arrival_offset += 1
end
- if stop.departure_time < stop.arrival_time ||
- stop.departure_time < prior_stop.departure_time
+ if stop_departure_time < stop_arrival_time ||
+ stop_departure_time < prior_stop_departure_time
departure_offset += 1
end
@@ -39,4 +45,4 @@ module Chouette
save
end
end
-end \ No newline at end of file
+end
diff --git a/app/models/compliance_check_set.rb b/app/models/compliance_check_set.rb
index f4c44d26d..289fc134f 100644
--- a/app/models/compliance_check_set.rb
+++ b/app/models/compliance_check_set.rb
@@ -19,6 +19,20 @@ class ComplianceCheckSet < ActiveRecord::Base
where('created_at BETWEEN :begin AND :end', begin: period_range.begin, end: period_range.end)
end
+ scope :blocked, -> { where('created_at < ? AND status = ?', 4.hours.ago, 'running') }
+
+ def self.finished_statuses
+ %w(successful failed warning aborted canceled)
+ end
+
+ def self.abort_old
+ where(
+ 'created_at < ? AND status NOT IN (?)',
+ 4.hours.ago,
+ finished_statuses
+ ).update_all(status: 'aborted')
+ end
+
def notify_parent
if parent
# parent.child_change
diff --git a/app/models/compliance_control.rb b/app/models/compliance_control.rb
index 2bde5b95a..298a63ab9 100644
--- a/app/models/compliance_control.rb
+++ b/app/models/compliance_control.rb
@@ -3,8 +3,6 @@ class ComplianceControl < ActiveRecord::Base
class << self
def criticities; %i(warning error) end
def default_code; "" end
- def prerequisite; I18n.t('compliance_controls.metas.no_prerequisite'); end
- def predicate; I18n.t("compliance_controls.#{self.name.underscore}.description") end
def dynamic_attributes
stored_attributes[:control_attributes] || []
end
@@ -65,6 +63,9 @@ def initialize(attributes = {})
self.origin_code ||= self.class.default_code
end
+def predicate; I18n.t("compliance_controls.#{self.class.name.underscore}.description") end
+def prerequisite; I18n.t('compliance_controls.metas.no_prerequisite'); end
+
end
# Ensure STI subclasses are loaded
diff --git a/app/models/concerns/checksum_support.rb b/app/models/concerns/checksum_support.rb
index a76995b0f..92103798e 100644
--- a/app/models/concerns/checksum_support.rb
+++ b/app/models/concerns/checksum_support.rb
@@ -24,10 +24,29 @@ module ChecksumSupport
self.attributes.values
end
+ def checksum_replace_nil_or_empty_values values
+ # Replace empty array by nil & nil by VALUE_FOR_NIL_ATTRIBUTE
+ values
+ .map { |x| x.present? && x || VALUE_FOR_NIL_ATTRIBUTE }
+ .map do |item|
+ item =
+ if item.kind_of?(Array)
+ checksum_replace_nil_or_empty_values(item)
+ else
+ item
+ end
+ end
+ end
+
def current_checksum_source
- source = self.checksum_attributes.map{ |x| x unless x.try(:empty?) }
- source = source.map{ |x| x || VALUE_FOR_NIL_ATTRIBUTE }
- source.map(&:to_s).join(SEPARATOR)
+ source = checksum_replace_nil_or_empty_values(self.checksum_attributes)
+ source.map{ |item|
+ if item.kind_of?(Array)
+ item.map{ |x| x.kind_of?(Array) ? "(#{x.join(',')})" : x }.join(',')
+ else
+ item
+ end
+ }.join(SEPARATOR)
end
def set_current_checksum_source
diff --git a/app/models/concerns/min_max_values_validation.rb b/app/models/concerns/min_max_values_validation.rb
index 9b2e0d548..eff779d81 100644
--- a/app/models/concerns/min_max_values_validation.rb
+++ b/app/models/concerns/min_max_values_validation.rb
@@ -2,6 +2,7 @@ module MinMaxValuesValidation
extend ActiveSupport::Concern
included do
+ validates_presence_of :minimum, :maximum
validate :min_max_values_validation
end
diff --git a/app/models/concerns/timetable_support.rb b/app/models/concerns/timetable_support.rb
index d2bc99d51..5242abc33 100644
--- a/app/models/concerns/timetable_support.rb
+++ b/app/models/concerns/timetable_support.rb
@@ -100,6 +100,7 @@ module TimetableSupport
period.period_start = Date.parse(item['period_start'])
period.period_end = Date.parse(item['period_end'])
+
period.save if period.is_a?(ActiveRecord::Base) && period.changed?
item['id'] = period.id
diff --git a/app/models/import.rb b/app/models/import.rb
index 049a65f40..29aadcd56 100644
--- a/app/models/import.rb
+++ b/app/models/import.rb
@@ -13,6 +13,8 @@ class Import < ActiveRecord::Base
where('started_at BETWEEN :begin AND :end', begin: period_range.begin, end: period_range.end)
end
+ scope :blocked, -> { where('created_at < ? AND status = ?', 4.hours.ago, 'running') }
+
extend Enumerize
enumerize :status, in: %w(new pending successful warning failed running aborted canceled), scope: true, default: :new
@@ -42,6 +44,14 @@ class Import < ActiveRecord::Base
%w(successful failed warning aborted canceled)
end
+ def self.abort_old
+ where(
+ 'created_at < ? AND status NOT IN (?)',
+ 4.hours.ago,
+ finished_statuses
+ ).update_all(status: 'aborted')
+ end
+
def notify_parent
parent.child_change
update(notified_parent_at: DateTime.now)
diff --git a/app/models/line_control/route.rb b/app/models/line_control/route.rb
index b4b2bd9d8..b6c1f3630 100644
--- a/app/models/line_control/route.rb
+++ b/app/models/line_control/route.rb
@@ -3,6 +3,6 @@ module LineControl
def self.default_code; "3-Line-1" end
- def self.prerequisite; I18n.t("compliance_controls.#{self.name.underscore}.prerequisite") end
+ def prerequisite; I18n.t("compliance_controls.#{self.class.name.underscore}.prerequisite") end
end
end
diff --git a/app/models/organisation.rb b/app/models/organisation.rb
index 0598bfecf..745bc0d22 100644
--- a/app/models/organisation.rb
+++ b/app/models/organisation.rb
@@ -82,4 +82,8 @@ class Organisation < ActiveRecord::Base
features && features.include?(feature.to_s)
end
+ def default_workbench
+ workbenches.default
+ end
+
end
diff --git a/app/models/referential.rb b/app/models/referential.rb
index baaa354da..09c2e7d34 100644
--- a/app/models/referential.rb
+++ b/app/models/referential.rb
@@ -51,7 +51,9 @@ class Referential < ActiveRecord::Base
belongs_to :stop_area_referential
validates_presence_of :stop_area_referential
has_many :stop_areas, through: :stop_area_referential
+
belongs_to :workbench
+ delegate :workgroup, to: :workbench, allow_nil: true
belongs_to :referential_suite
@@ -62,6 +64,7 @@ class Referential < ActiveRecord::Base
scope :order_by_validity_period, ->(dir) { joins(:metadatas).order("unnest(periodes) #{dir}") }
scope :order_by_lines, ->(dir) { joins(:metadatas).group("referentials.id").order("sum(array_length(referential_metadata.line_ids,1)) #{dir}") }
scope :not_in_referential_suite, -> { where referential_suite_id: nil }
+ scope :blocked, -> { where('ready = ? AND created_at < ?', false, 4.hours.ago) }
def save_with_table_lock_timeout(options = {})
save_without_table_lock_timeout(options)
@@ -153,10 +156,6 @@ class Referential < ActiveRecord::Base
end
end
- def stop_areas
- Chouette::StopArea.all
- end
-
def access_points
Chouette::AccessPoint.all
end
diff --git a/app/models/route_control/opposite_route.rb b/app/models/route_control/opposite_route.rb
index d5616ca6f..e0e9572ce 100644
--- a/app/models/route_control/opposite_route.rb
+++ b/app/models/route_control/opposite_route.rb
@@ -4,6 +4,6 @@ module RouteControl
def self.default_code; "3-Route-2" end
- def self.prerequisite; I18n.t("compliance_controls.#{self.name.underscore}.prerequisite") end
+ def prerequisite; I18n.t("compliance_controls.#{self.class.name.underscore}.prerequisite") end
end
end
diff --git a/app/models/route_control/opposite_route_terminus.rb b/app/models/route_control/opposite_route_terminus.rb
index 24c557734..e70d2c702 100644
--- a/app/models/route_control/opposite_route_terminus.rb
+++ b/app/models/route_control/opposite_route_terminus.rb
@@ -3,6 +3,6 @@ module RouteControl
def self.default_code; "3-Route-5" end
- def self.prerequisite; I18n.t("compliance_controls.#{self.name.underscore}.prerequisite") end
+ def prerequisite; I18n.t("compliance_controls.#{self.class.name.underscore}.prerequisite") end
end
end
diff --git a/app/models/simple_importer.rb b/app/models/simple_importer.rb
new file mode 100644
index 000000000..b824d596d
--- /dev/null
+++ b/app/models/simple_importer.rb
@@ -0,0 +1,422 @@
+class SimpleImporter < ActiveRecord::Base
+ attr_accessor :configuration
+
+ def self.define name
+ @importers ||= {}
+ configuration = Configuration.new name
+ yield configuration
+ configuration.validate!
+ @importers[name.to_sym] = configuration
+ end
+
+ def self.find_configuration name
+ @importers ||= {}
+ configuration = @importers[name.to_sym]
+ raise "Importer not found: #{name}" unless configuration
+ configuration
+ end
+
+ def initialize *args
+ super *args
+ self.configuration = self.class.find_configuration self.configuration_name
+ self.journal ||= []
+ end
+
+ def configure
+ new_config = configuration.duplicate
+ yield new_config
+ new_config.validate!
+ self.configuration = new_config
+ end
+
+ def context
+ self.configuration.context
+ end
+
+ def resolve col_name, value, &block
+ val = block.call(value)
+ return val if val.present?
+ @resolution_queue[[col_name.to_s, value]].push({record: @current_record, attribute: @current_attribute, block: block})
+ nil
+ end
+
+ def import opts={}
+ @verbose = opts.delete :verbose
+
+
+ @resolution_queue = Hash.new{|h,k| h[k] = []}
+ @errors = []
+ @messages = []
+ @number_of_lines = 0
+ @padding = 1
+ @current_line = 0
+ fail_with_error "File not found: #{self.filepath}" do
+ @number_of_lines = CSV.read(self.filepath, self.configuration.csv_options).length
+ @padding = [1, Math.log(@number_of_lines, 10).ceil()].max
+ end
+
+
+ self.configuration.before_actions(:parsing).each do |action| action.call self end
+
+ @statuses = ""
+
+ if ENV["NO_TRANSACTION"]
+ process_csv_file
+ else
+ ActiveRecord::Base.transaction do
+ process_csv_file
+ end
+ end
+ self.status ||= :success
+ rescue FailedImport
+ self.status = :failed
+ ensure
+ self.save!
+ end
+
+ def fail_with_error msg=nil, opts={}
+ begin
+ yield
+ rescue => e
+ msg = msg.call if msg.is_a?(Proc)
+ custom_print "\nFAILED: \n errors: #{msg}\n exception: #{e.message}\n#{e.backtrace.join("\n")}", color: :red unless self.configuration.ignore_failures
+ push_in_journal({message: msg, error: e.message, event: :error, kind: :error})
+ @new_status = colorize("x", :red)
+ if self.configuration.ignore_failures
+ raise FailedRow if opts[:abort_row]
+ else
+ raise FailedImport
+ end
+ end
+ end
+
+ def encode_string s
+ s.encode("utf-8").force_encoding("utf-8")
+ end
+
+ def dump_csv_from_context
+ filepath = "./#{self.configuration_name}_#{Time.now.strftime "%y%m%d%H%M"}.csv"
+ # for some reason, context[:csv].to_csv does not work
+ CSV.open(filepath, 'w') do |csv|
+ header = true
+ context[:csv].each do |row|
+ csv << row.headers if header
+ csv << row.fields
+ header = false
+ end
+ end
+ log "CSV file dumped in #{filepath}"
+ end
+
+ def log msg, opts={}
+ msg = colorize msg, opts[:color] if opts[:color]
+ if opts[:append]
+ @messages[-1] = (@messages[-1] || "") + msg
+ else
+ @messages << msg
+ end
+ print_state
+ end
+
+ protected
+
+ def process_csv_file
+ self.configuration.before_actions(:all).each do |action| action.call self end
+ log "Starting import ...", color: :green
+
+ (context[:csv] || CSV.read(filepath, self.configuration.csv_options)).each do |row|
+ @current_row = row
+ @new_status = nil
+ begin
+ handle_row row
+ fail_with_error ->(){ @current_record.errors.messages } do
+ new_record = @current_record&.new_record?
+ @new_status ||= new_record ? colorize("✓", :green) : colorize("-", :orange)
+ @event = new_record ? :creation : :update
+ self.configuration.before_actions(:each_save).each do |action|
+ action.call self, @current_record
+ end
+ ### This could fail if the record has a mandatory relation which is not yet resolved
+ ### TODO: do not attempt to save if the current record if waiting for resolution
+ ### and fail at the end if there remains unresolved relations
+ if @current_record
+ if self.configuration.ignore_failures
+ unless @current_record.save
+ @new_status = colorize("x", :red)
+ push_in_journal({message: "errors: #{@current_record.errors.messages}", error: "invalid record", event: :error, kind: :error})
+ end
+ else
+ @current_record.save!
+ end
+ end
+ self.configuration.after_actions(:each_save).each do |action|
+ action.call self, @current_record
+ end
+ end
+ rescue FailedRow
+ @new_status = colorize("x", :red)
+ end
+ push_in_journal({event: @event, kind: :log}) if @current_record&.valid?
+ @statuses += @new_status
+ self.configuration.columns.each do |col|
+ if @current_record && col.name && @resolution_queue.any?
+ val = @current_record.send col[:attribute]
+ (@resolution_queue.delete([col.name, val]) || []).each do |res|
+ record = res[:record]
+ attribute = res[:attribute]
+ value = res[:block].call(val, record)
+ record.send "#{attribute}=", value
+ record.save!
+ end
+ end
+ end
+ print_state
+ @current_line += 1
+ end
+
+ begin
+ self.configuration.after_actions(:all).each do |action|
+ action.call self
+ end
+ rescue FailedRow
+ end
+ end
+
+ def handle_row row
+ if self.configuration.get_custom_handler
+ instance_exec(row, &self.configuration.get_custom_handler)
+ else
+ fail_with_error "", abort_row: true do
+ @current_record = self.configuration.find_record row
+ self.configuration.columns.each do |col|
+ @current_attribute = col[:attribute]
+ val = col[:value]
+ if val.nil? || val.is_a?(Proc)
+ if row.has_key? col.name
+ if val.is_a?(Proc)
+ val = instance_exec(row[col.name], &val)
+ else
+ val = row[col.name]
+ end
+ else
+ push_in_journal({event: :column_not_found, message: "Column not found: #{col.name}", kind: :warning})
+ self.status ||= :success_with_warnings
+ end
+ end
+
+ if val.nil? && col.required?
+ raise "MISSING VALUE FOR COLUMN #{col.name}"
+ end
+ val = encode_string(val) if val.is_a?(String)
+ @current_record.send "#{@current_attribute}=", val if val
+ end
+ end
+ end
+ end
+
+ def push_in_journal data
+ line = @current_line + 1
+ line += 1 if configuration.headers
+ self.journal.push data.update(line: line, row: @current_row)
+ if data[:kind] == :error || data[:kind] == :warning
+ @errors.push data
+ end
+ end
+
+ def colorize txt, color
+ color = {
+ red: "31",
+ green: "32",
+ orange: "33",
+ }[color] || "33"
+ "\e[#{color}m#{txt}\e[0m"
+ end
+
+ def print_state
+ return unless @verbose
+
+ @status_width ||= begin
+ term_width = %x(tput cols).to_i
+ term_width - @padding - 10
+ rescue
+ 100
+ end
+
+ @status_height ||= begin
+ term_height = %x(tput lines).to_i
+ term_height - 3
+ rescue
+ 50
+ end
+
+ full_status = @statuses || ""
+ full_status = full_status.last(@status_width*10) || ""
+ padding_size = [(@number_of_lines - @current_line - 1), (@status_width - full_status.size/10)].min
+ full_status = "#{full_status}#{"."*[padding_size, 0].max}"
+
+ msg = "#{"%#{@padding}d" % (@current_line + 1)}/#{@number_of_lines}: #{full_status}"
+
+ lines_count = [(@status_height / 2) - 3, 1].max
+
+ if @messages.any?
+ msg += "\n\n"
+ msg += colorize "=== MESSAGES (#{@messages.count}) ===\n", :green
+ msg += "[...]\n" if @messages.count > lines_count
+ msg += @messages.last(lines_count).join("\n")
+ msg += "\n"*[lines_count-@messages.count, 0].max
+ end
+
+ if @errors.any?
+ msg += "\n\n"
+ msg += colorize "=== ERRORS (#{@errors.count}) ===\n", :red
+ msg += "[...]\n" if @errors.count > lines_count
+ msg += @errors.last(lines_count).map do |j|
+ kind = j[:kind]
+ kind = colorize(kind, kind == :error ? :red : :orange)
+ encode_string "[#{kind}]\t\tL#{j[:line]}\t#{j[:error]}\t\t#{j[:message]}"
+ end.join("\n")
+ end
+ custom_print msg, clear: true
+ end
+
+ def custom_print msg, opts={}
+ return unless @verbose
+ out = ""
+ msg = colorize(msg, opts[:color]) if opts[:color]
+ puts "\e[H\e[2J" if opts[:clear]
+ out += msg
+ print out
+ end
+
+ class FailedImport < RuntimeError
+ end
+
+ class FailedRow < RuntimeError
+ end
+
+ class Configuration
+ attr_accessor :model, :headers, :separator, :key, :context, :encoding, :ignore_failures, :scope
+ attr_reader :columns
+
+ def initialize import_name, opts={}
+ @import_name = import_name
+ @key = opts[:key] || "id"
+ @headers = opts.has_key?(:headers) ? opts[:headers] : true
+ @separator = opts[:separator] || ","
+ @encoding = opts[:encoding]
+ @columns = opts[:columns] || []
+ @model = opts[:model]
+ @custom_handler = opts[:custom_handler]
+ @before = opts[:before]
+ @after = opts[:after]
+ @ignore_failures = opts[:ignore_failures]
+ @context = opts[:context] || {}
+ @scope = opts[:scope]
+ end
+
+ def duplicate
+ Configuration.new @import_name, self.options
+ end
+
+ def options
+ {
+ key: @key,
+ headers: @headers,
+ separator: @separator,
+ encoding: @encoding,
+ columns: @columns.map(&:duplicate),
+ model: model,
+ custom_handler: @custom_handler,
+ before: @before,
+ after: @after,
+ ignore_failures: @ignore_failures,
+ context: @context,
+ scope: @scope
+ }
+ end
+
+ def validate!
+ raise "Incomplete configuration, missing model for #{@import_name}" unless model.present?
+ end
+
+ def attribute_for_col col_name
+ column = self.columns.find{|c| c.name == col_name}
+ column && column[:attribute] || col_name
+ end
+
+ def record_scope
+ _scope = @scope
+ _scope = instance_exec(&_scope) if _scope.is_a?(Proc)
+ _scope || model
+ end
+
+ def find_record attrs
+ record_scope.find_or_initialize_by(attribute_for_col(@key) => attrs[@key.to_s])
+ end
+
+ def csv_options
+ {
+ headers: self.headers,
+ col_sep: self.separator,
+ encoding: self.encoding
+ }
+ end
+
+ def add_column name, opts={}
+ @columns.push Column.new({name: name.to_s}.update(opts))
+ end
+
+ def add_value attribute, value
+ @columns.push Column.new({attribute: attribute, value: value})
+ end
+
+ def before group=:all, &block
+ @before ||= Hash.new{|h, k| h[k] = []}
+ @before[group].push block
+ end
+
+ def after group=:all, &block
+ @after ||= Hash.new{|h, k| h[k] = []}
+ @after[group].push block
+ end
+
+ def before_actions group=:all
+ @before ||= Hash.new{|h, k| h[k] = []}
+ @before[group]
+ end
+
+ def after_actions group=:all
+ @after ||= Hash.new{|h, k| h[k] = []}
+ @after[group]
+ end
+
+ def custom_handler &block
+ @custom_handler = block
+ end
+
+ def get_custom_handler
+ @custom_handler
+ end
+
+ class Column
+ attr_accessor :name
+ def initialize opts={}
+ @name = opts[:name]
+ @options = opts
+ @options[:attribute] ||= @name
+ end
+
+ def duplicate
+ Column.new @options.dup
+ end
+
+ def required?
+ !!@options[:required]
+ end
+
+ def [](key)
+ @options[key]
+ end
+ end
+ end
+end
diff --git a/app/models/user.rb b/app/models/user.rb
index 1342f60ed..31e634415 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -15,6 +15,7 @@ class User < ActiveRecord::Base
# Setup accessible (or protected) attributes for your model
# attr_accessible :email, :password, :current_password, :password_confirmation, :remember_me, :name, :organisation_attributes
belongs_to :organisation
+ has_many :workbenches, through: :organisation
accepts_nested_attributes_for :organisation
validates :organisation, :presence => true
diff --git a/app/models/vehicle_journey_control/delta.rb b/app/models/vehicle_journey_control/delta.rb
index f061b9fdd..737b7d78c 100644
--- a/app/models/vehicle_journey_control/delta.rb
+++ b/app/models/vehicle_journey_control/delta.rb
@@ -4,6 +4,7 @@ module VehicleJourneyControl
store_accessor :control_attributes, :maximum
validates_numericality_of :maximum, allow_nil: true, greater_than_or_equal_to: 0
+ validates_presence_of :maximum
def self.default_code; "3-VehicleJourney-3" end
end
diff --git a/app/models/vehicle_journey_control/waiting_time.rb b/app/models/vehicle_journey_control/waiting_time.rb
index f2666cb72..89a18a5d9 100644
--- a/app/models/vehicle_journey_control/waiting_time.rb
+++ b/app/models/vehicle_journey_control/waiting_time.rb
@@ -3,6 +3,7 @@ module VehicleJourneyControl
store_accessor :control_attributes, :maximum
validates_numericality_of :maximum, allow_nil: true, greater_than_or_equal_to: 0
+ validates_presence_of :maximum
def self.default_code; "3-VehicleJourney-1" end
end
diff --git a/app/models/workbench.rb b/app/models/workbench.rb
index b80fa64ac..eb53af7aa 100644
--- a/app/models/workbench.rb
+++ b/app/models/workbench.rb
@@ -1,4 +1,6 @@
class Workbench < ActiveRecord::Base
+ DEFAULT_WORKBENCH_NAME = "Gestion de l'offre"
+
include ObjectidFormatterSupport
belongs_to :organisation
belongs_to :line_referential
@@ -40,6 +42,11 @@ class Workbench < ActiveRecord::Base
end
end
+ def self.default
+ self.last if self.count == 1
+ where(name: DEFAULT_WORKBENCH_NAME).last
+ end
+
private
def initialize_output
diff --git a/app/models/workgroup.rb b/app/models/workgroup.rb
index 3d761e81f..3af20ae23 100644
--- a/app/models/workgroup.rb
+++ b/app/models/workgroup.rb
@@ -3,6 +3,7 @@ class Workgroup < ActiveRecord::Base
belongs_to :stop_area_referential
has_many :workbenches
+ has_many :calendars
has_many :organisations, through: :workbenches
has_many :referentials, through: :workbenches
diff --git a/app/services/parent_import_notifier.rb b/app/services/parent_import_notifier.rb
deleted file mode 100644
index 47e6755e4..000000000
--- a/app/services/parent_import_notifier.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class ParentImportNotifier
- def self.notify_when_finished(imports = nil)
- imports ||= imports_pending_notification
- imports.each(&:notify_parent)
- end
-
- def self.imports_pending_notification
- Import
- .where(
- notified_parent_at: nil,
- status: Import.finished_statuses
- )
- .where.not(parent: nil)
- end
-end
diff --git a/app/services/parent_notifier.rb b/app/services/parent_notifier.rb
new file mode 100644
index 000000000..653c98aff
--- /dev/null
+++ b/app/services/parent_notifier.rb
@@ -0,0 +1,19 @@
+class ParentNotifier
+ def initialize(klass)
+ @klass = klass
+ end
+
+ def notify_when_finished(collection = nil)
+ collection ||= objects_pending_notification
+ collection.each(&:notify_parent)
+ end
+
+ def objects_pending_notification
+ @klass
+ .where(
+ notified_parent_at: nil,
+ status: @klass.finished_statuses
+ )
+ .where.not(parent: nil)
+ end
+end
diff --git a/app/views/calendar_mailer/created.html.slim b/app/views/calendar_mailer/created.html.slim
index 37b2a86ea..bee071150 100644
--- a/app/views/calendar_mailer/created.html.slim
+++ b/app/views/calendar_mailer/created.html.slim
@@ -1,4 +1,4 @@
-div = t('mailers.calendar_mailer.created.body', cal_name: @calendar.name, cal_index_url: calendars_url)
+div = t('mailers.calendar_mailer.created.body', cal_name: @calendar.name, cal_index_url: workgroup_calendars_url(@calendar.workgroup))
table style="border-collapse:collapse;font-family:'Open Sans', Arial, sans serif;width:550px;margin:0px auto;color:#333333;"
@@ -16,7 +16,7 @@ table style="border-collapse:collapse;font-family:'Open Sans', Arial, sans serif
= t('mailers.calendar_mailer.updated.subject')
p style="font-size:14px;margin:0px 0px 10px 0px;"
- = t('mailers.calendar_mailer.created.body', cal_name: @calendar.name, cal_index_url: calendars_url).html_safe
+ = t('mailers.calendar_mailer.created.body', cal_name: @calendar.name, cal_index_url: workgroup_calendars_url(@calendar.workgroup)).html_safe
tr
td style="text-align:center;padding:20px 0 0 0;border-top:1px solid #007fbb;"
diff --git a/app/views/calendar_mailer/updated.html.slim b/app/views/calendar_mailer/updated.html.slim
index bf128439a..0bdc2e7db 100644
--- a/app/views/calendar_mailer/updated.html.slim
+++ b/app/views/calendar_mailer/updated.html.slim
@@ -14,7 +14,7 @@ table style="border-collapse:collapse;font-family:'Open Sans', Arial, sans serif
= t('mailers.calendar_mailer.updated.subject')
p style="font-size:14px;margin:0px 0px 10px 0px;"
- = t('mailers.calendar_mailer.updated.body', cal_name: @calendar.name, cal_index_url: calendars_url).html_safe
+ = t('mailers.calendar_mailer.updated.body', cal_name: @calendar.name, cal_index_url: workgroup_calendars_url(@calendar.workgroup)).html_safe
tr
td style="text-align:center;padding:20px 0 0 0;border-top:1px solid #007fbb;"
diff --git a/app/views/calendars/_filters.html.slim b/app/views/calendars/_filters.html.slim
index d9c936b64..8bfe1974e 100644
--- a/app/views/calendars/_filters.html.slim
+++ b/app/views/calendars/_filters.html.slim
@@ -1,4 +1,4 @@
-= search_form_for @q, url: calendars_path, builder: SimpleForm::FormBuilder, html: { method: :get, class: 'form form-filter' } do |f|
+= search_form_for @q, url: workgroup_calendars_path(@workgroup), builder: SimpleForm::FormBuilder, html: { method: :get, class: 'form form-filter' } do |f|
.ffg-row
.input-group.search_bar class=filter_item_class(params[:q], :name_or_short_name_cont)
= f.search_field :name_or_short_name_cont, class: 'form-control', placeholder: 'Indiquez un nom/nom court de calendrier...'
@@ -18,5 +18,5 @@
= f.input :contains_date, as: :date, label: false, wrapper_html: { class: 'date smart_date' }, class: 'form-control', include_blank: true
.actions
- = link_to 'Effacer', calendars_path, class: 'btn btn-link'
+ = link_to 'Effacer', workgroup_calendars_path(@workgroup), class: 'btn btn-link'
= f.submit 'Filtrer', id: 'calendar_filter_btn', class: 'btn btn-default'
diff --git a/app/views/calendars/_form_advanced.html.slim b/app/views/calendars/_form_advanced.html.slim
index b4154166b..e796e2e36 100644
--- a/app/views/calendars/_form_advanced.html.slim
+++ b/app/views/calendars/_form_advanced.html.slim
@@ -2,7 +2,7 @@
= javascript_tag do
| window.actionType = "#{raw params[:action]}";
- | window.I18n = #{(I18n.backend.send(:translations)[I18n.locale].to_json).html_safe};
+ // | window.I18n = #{(I18n.backend.send(:translations)[I18n.locale].to_json).html_safe};
| window.timetablesUrl = "#{calendar_url(@calendar).html_safe}";
= javascript_pack_tag 'calendars/edit.js'
diff --git a/app/views/calendars/_form_simple.html.slim b/app/views/calendars/_form_simple.html.slim
index 2f469ada7..ba18c765b 100644
--- a/app/views/calendars/_form_simple.html.slim
+++ b/app/views/calendars/_form_simple.html.slim
@@ -1,6 +1,6 @@
.row
.col-lg-8.col-lg-offset-2.col-md-8.col-md-offset-2.col-sm-10.col-sm-offset-1
- = simple_form_for @calendar, html: { class: 'form-horizontal', id: 'calendar_form' }, wrapper: :horizontal_form do |f|
+ = simple_form_for [@workgroup, @calendar], html: { class: 'form-horizontal', id: 'calendar_form' }, wrapper: :horizontal_form do |f|
.row
.col-lg-12
= f.input :name
diff --git a/app/views/calendars/edit.html.slim b/app/views/calendars/edit.html.slim
index e64790daf..79ab1f5d0 100644
--- a/app/views/calendars/edit.html.slim
+++ b/app/views/calendars/edit.html.slim
@@ -1,4 +1,4 @@
-- breadcrumb :calendar, @calendar
+- breadcrumb :calendar, @workgroup, @calendar
- page_header_content_for @calendar
.page_content
.container-fluid
diff --git a/app/views/calendars/index.html.slim b/app/views/calendars/index.html.slim
index 92c24be5b..0b58c0c72 100644
--- a/app/views/calendars/index.html.slim
+++ b/app/views/calendars/index.html.slim
@@ -1,4 +1,4 @@
-- breadcrumb :calendars
+- breadcrumb :calendars, workgroup
.page_content
.container-fluid
@@ -16,7 +16,7 @@
key: :name, \
attribute: 'name', \
link_to: lambda do |calendar| \
- calendar_path(calendar) \
+ workgroup_calendar_path(workgroup, calendar) \
end \
), \
TableBuilderHelper::Column.new( \
diff --git a/app/views/calendars/new.html.slim b/app/views/calendars/new.html.slim
index b3840b705..5657a0c55 100644
--- a/app/views/calendars/new.html.slim
+++ b/app/views/calendars/new.html.slim
@@ -1,4 +1,4 @@
-- breadcrumb :calendars
+- breadcrumb :calendars, @workgroup
.page_content
.container-fluid
= render 'form_simple'
diff --git a/app/views/calendars/show.html.slim b/app/views/calendars/show.html.slim
index ec53be0ef..cec4f66a5 100644
--- a/app/views/calendars/show.html.slim
+++ b/app/views/calendars/show.html.slim
@@ -1,4 +1,4 @@
-- breadcrumb :calendar, @calendar
+- breadcrumb :calendar, @workgroup, @calendar
- page_header_content_for @calendar
.page_content
diff --git a/app/views/compliance_check_sets/index.html.slim b/app/views/compliance_check_sets/index.html.slim
index ead467174..31ad31e5b 100644
--- a/app/views/compliance_check_sets/index.html.slim
+++ b/app/views/compliance_check_sets/index.html.slim
@@ -23,9 +23,9 @@
), \
TableBuilderHelper::Column.new( \
key: :associated_object, \
- attribute: Proc.new{|n| n.referential.name}, \
+ attribute: Proc.new{|n| n.referential.present? ? n.referential.name : ''}, \
link_to: lambda do |compliance_check_set| \
- referential_path(compliance_check_set.referential_id) \
+ compliance_check_set.referential.present? ? referential_path(compliance_check_set.referential_id) : '#' \
end \
), \
TableBuilderHelper::Column.new( \
diff --git a/app/views/compliance_controls/new.html.slim b/app/views/compliance_controls/new.html.slim
index f7f47fba3..c0abc522f 100644
--- a/app/views/compliance_controls/new.html.slim
+++ b/app/views/compliance_controls/new.html.slim
@@ -6,5 +6,5 @@
= render 'form'
= definition_list t('metadatas'),
- I18n.t('activerecord.attributes.compliance_control.predicate') => @compliance_control.class.predicate,
- I18n.t('activerecord.attributes.compliance_control.prerequisite') => @compliance_control.class.prerequisite
+ I18n.t('activerecord.attributes.compliance_control.predicate') => @compliance_control.predicate,
+ I18n.t('activerecord.attributes.compliance_control.prerequisite') => @compliance_control.prerequisite
diff --git a/app/views/compliance_controls/show.html.slim b/app/views/compliance_controls/show.html.slim
index 8a65bb864..ab25747a9 100644
--- a/app/views/compliance_controls/show.html.slim
+++ b/app/views/compliance_controls/show.html.slim
@@ -13,8 +13,8 @@
ComplianceControl.human_attribute_name(:code) => @compliance_control.code,
ComplianceControl.human_attribute_name(:criticity) => @compliance_control.criticity,
ComplianceControl.human_attribute_name(:comment) => @compliance_control.comment,
- I18n.t('activerecord.attributes.compliance_control.predicate') => @compliance_control.class.predicate,
- I18n.t('activerecord.attributes.compliance_control.prerequisite') => @compliance_control.class.prerequisite,
+ I18n.t('activerecord.attributes.compliance_control.predicate') => @compliance_control.predicate,
+ I18n.t('activerecord.attributes.compliance_control.prerequisite') => @compliance_control.prerequisite,
}.merge( \
{}.tap do |hash| \
@compliance_control.class.dynamic_attributes.each do |attribute| \
diff --git a/app/views/dashboards/_dashboard.html.slim b/app/views/dashboards/_dashboard.html.slim
index 075b94ddc..7f78934a6 100644
--- a/app/views/dashboards/_dashboard.html.slim
+++ b/app/views/dashboards/_dashboard.html.slim
@@ -9,30 +9,30 @@
span.badge.ml-xs = workbench.referentials.count if workbench.referentials.present?
div
- = link_to '', workbench_path(workbench), class: ' fa fa-chevron-right pull-right', title: t('.offers.see')
+ = link_to '', workbench_path(workbench), class: ' fa fa-chevron-right pull-right', title: t('workbenches.index.offers.see')
- if workbench.referentials.present?
.list-group
- workbench.referentials.limit(5).each do |referential|
- = link_to referential.name, referential_path(referential, workbench_id: referential.workbench_id, current_workbench_id: workbench.id), class: 'list-group-item'
+ = link_to referential.name, referential_path(referential), class: 'list-group-item'
- else
.panel-body
- em.small.text-muted = t('.offers.no_content')
+ em.small.text-muted = t('workbenches.index.offers.no_content')
- .panel.panel-default
- .panel-heading
- h3.panel-title.with_actions
- = link_to I18n.t("activerecord.models.calendar", count: @dashboard.current_organisation.calendars.size), calendars_path
- div
- = link_to '', calendars_path, class: ' fa fa-chevron-right pull-right'
- - if @dashboard.current_organisation.calendars.present?
- .list-group
- - @dashboard.current_organisation.calendars.order("updated_at desc").limit(5).each do |calendar|
- = link_to calendar.name, calendar_path(calendar), class: 'list-group-item'
- - else
- .panel-body
- em.small.text-muted
- = t('dasboard.calendars.none')
+ .panel.panel-default
+ .panel-heading
+ h3.panel-title.with_actions
+ = link_to I18n.t("activerecord.models.calendar", count: @dashboard.current_organisation.calendars.size), workgroup_calendars_path(workbench.workgroup)
+ div
+ = link_to '', workgroup_calendars_path(workbench.workgroup), class: ' fa fa-chevron-right pull-right'
+ - if @dashboard.current_organisation.calendars.present?
+ .list-group
+ - @dashboard.current_organisation.calendars.order("updated_at desc").limit(5).each do |calendar|
+ = link_to calendar.name, workgroup_calendars_path(workbench.workgroup, calendar), class: 'list-group-item'
+ - else
+ .panel-body
+ em.small.text-muted
+ = t('dasboard.calendars.none')
.col-lg-6.col-md-6.col-sm-6.col-xs-12
.panel.panel-default
@@ -51,4 +51,4 @@
.list-group
= link_to Chouette::Line.model_name.human.pluralize.capitalize, line_referential_lines_path(referential), class: 'list-group-item'
= link_to Chouette::Company.model_name.human.pluralize.capitalize, line_referential_companies_path(referential), class: 'list-group-item'
- = link_to "Réseaux", line_referential_networks_path(referential), class: 'list-group-item'
+ = link_to Chouette::Network.model_name.human.pluralize.capitalize, line_referential_networks_path(referential), class: 'list-group-item'
diff --git a/app/views/errors/forbidden.html.slim b/app/views/errors/forbidden.html.slim
index 23ea67eff..8c35b46a8 100644
--- a/app/views/errors/forbidden.html.slim
+++ b/app/views/errors/forbidden.html.slim
@@ -9,7 +9,7 @@
p
strong = "Désolé, la page demandée la page n'est pas accessible avec votre profil utilisateur."
- p = "Vous pouvez néanmoins continuer à utiliser l'application IBOO."
+ p = "Vous pouvez néanmoins continuer à utiliser l'application."
- else
p
diff --git a/app/views/errors/server_error.html.slim b/app/views/errors/server_error.html.slim
index 189a48760..529ad73e8 100644
--- a/app/views/errors/server_error.html.slim
+++ b/app/views/errors/server_error.html.slim
@@ -9,7 +9,7 @@
p
strong = "Désolé, une erreur est survenue."
- p = "Vous pouvez néanmoins continuer à utiliser l'application IBOO."
+ p = "Vous pouvez néanmoins continuer à utiliser l'application."
- else
p
diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim
index 34b373295..3921c8701 100644
--- a/app/views/layouts/application.html.slim
+++ b/app/views/layouts/application.html.slim
@@ -13,6 +13,8 @@ html lang=I18n.locale
= javascript_pack_tag 'application'
= javascript_include_tag 'application'
+ = javascript_tag do
+ | I18n.locale = '#{I18n.locale}'
body
= render 'layouts/navigation/main_nav'
diff --git a/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim b/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim
index 3963d4cd4..cb0698cf8 100644
--- a/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim
+++ b/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim
@@ -24,14 +24,14 @@
#miTwo.panel-collapse.collapse
.list-group
- - if current_user
- = link_to workbench_path(current_offer_workbench), class: "list-group-item #{params[:controller] == 'workbenches' ? 'active' : ''}" do
+ - current_user.workbenches.each do |current_workbench|
+ = link_to workbench_path(current_workbench), class: "list-group-item #{params[:controller] == 'workbenches' ? 'active' : ''}" do
span Jeux de données
- = link_to workbench_imports_path(current_offer_workbench), class: "list-group-item #{(params[:controller] == 'imports') ? 'active' : ''}" do
+ = link_to workbench_imports_path(current_workbench), class: "list-group-item #{(params[:controller] == 'imports') ? 'active' : ''}" do
span Import
- = link_to calendars_path, class: 'list-group-item' do
+ = link_to workgroup_calendars_path(current_workbench.workgroup), class: 'list-group-item' do
span Modèles de calendrier
- = link_to workbench_compliance_check_sets_path(current_offer_workbench), class: 'list-group-item' do
+ = link_to workbench_compliance_check_sets_path(current_workbench), class: 'list-group-item' do
span Rapport de contrôle
= link_to compliance_control_sets_path, class: 'list-group-item' do
span Jeux de contrôle
diff --git a/app/views/layouts/snapshots/actions_links.html.slim b/app/views/layouts/snapshots/actions_links.html.slim
new file mode 100644
index 000000000..f1fa55e87
--- /dev/null
+++ b/app/views/layouts/snapshots/actions_links.html.slim
@@ -0,0 +1,21 @@
+doctype html
+html lang=I18n.locale
+ head
+ meta charset="utf-8"
+ meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
+
+ = csrf_meta_tag
+
+ title = t('brandname')
+
+ = stylesheet_link_tag 'base'
+ = stylesheet_link_tag 'application'
+
+ = javascript_pack_tag 'application'
+ = javascript_include_tag 'application'
+
+ body
+ = render 'layouts/navigation/main_nav'
+ = render 'layouts/flash_messages', flash: flash
+ div.page_header
+ = yield
diff --git a/app/views/layouts/snapshots/default.html.slim b/app/views/layouts/snapshots/default.html.slim
new file mode 100644
index 000000000..9e4565dcb
--- /dev/null
+++ b/app/views/layouts/snapshots/default.html.slim
@@ -0,0 +1,19 @@
+doctype html
+html lang=I18n.locale
+ head
+ meta charset="utf-8"
+ meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
+
+ = csrf_meta_tag
+
+ title = t('brandname')
+
+ = stylesheet_link_tag 'base'
+ = stylesheet_link_tag 'application'
+
+ = javascript_pack_tag 'application'
+ = javascript_include_tag 'application'
+
+ body
+ = yield
+
diff --git a/app/views/purchase_windows/show.html.slim b/app/views/purchase_windows/show.html.slim
index 4e836f424..8ed9e393f 100644
--- a/app/views/purchase_windows/show.html.slim
+++ b/app/views/purchase_windows/show.html.slim
@@ -7,6 +7,5 @@
.col-lg-6.col-md-6.col-sm-12.col-xs-12
= definition_list t('metadatas'),
{ Chouette::PurchaseWindow.human_attribute_name(:name) => @purchase_window.try(:name),
- 'Organisation' => @purchase_window.referential.organisation.name,
Chouette::PurchaseWindow.human_attribute_name(:date_ranges) => @purchase_window.periods.map{|d| t('validity_range', debut: l(d.begin, format: :short), end: l(d.end, format: :short))}.join('<br>').html_safe,
Chouette::PurchaseWindow.human_attribute_name(:checksum) => @purchase_window.checksum }
diff --git a/app/views/referential_vehicle_journeys/index.html.slim b/app/views/referential_vehicle_journeys/index.html.slim
index 69e29597c..ca1b1ecd9 100644
--- a/app/views/referential_vehicle_journeys/index.html.slim
+++ b/app/views/referential_vehicle_journeys/index.html.slim
@@ -25,28 +25,28 @@
link_to: lambda do |vehicle_journey| \
vehicle_journey.published_journey_name ? referential_line_route_vehicle_journeys_path(@referential, vehicle_journey.route.line, vehicle_journey.route) : '' \
end, \
- sortable: false \
+ sortable: true \
), \
TableBuilderHelper::Column.new( \
key: :line, \
attribute: Proc.new {|v| v.route.line.name}, \
- sortable: false \
+ sortable: true \
), \
TableBuilderHelper::Column.new( \
key: :route, \
attribute: Proc.new {|v| v.route.name}, \
- sortable: false \
+ sortable: true \
), \
TableBuilderHelper::Column.new( \
key: :departure_time, \
attribute: Proc.new {|v| v.vehicle_journey_at_stops.first&.departure }, \
- sortable: false \
+ sortable: true \
), \
@filters_stop_areas&.map{|s| table_builder_column_for_stop_area(s)},
TableBuilderHelper::Column.new( \
key: :arrival_time, \
attribute: Proc.new {|v| v.vehicle_journey_at_stops.last&.arrival }, \
- sortable: false \
+ sortable: true \
), \
].flatten.compact,
cls: 'table has-filter has-search'
diff --git a/app/views/referentials/_form.html.slim b/app/views/referentials/_form.html.slim
index 9927f05bd..1e59ab566 100644
--- a/app/views/referentials/_form.html.slim
+++ b/app/views/referentials/_form.html.slim
@@ -1,4 +1,6 @@
-= simple_form_for @referential, html: {class: 'form-horizontal', id: 'referential_form'}, wrapper: :horizontal_form do |form|
+- url = @referential.new_record? ? [@workbench, @referential] : [@referential]
+
+= simple_form_for @referential, url: url, html: {class: 'form-horizontal', id: 'referential_form'}, wrapper: :horizontal_form do |form|
.row
.col-lg-12
diff --git a/app/views/referentials/_overview.html.slim b/app/views/referentials/_overview.html.slim
index 143784800..539c25fd4 100644
--- a/app/views/referentials/_overview.html.slim
+++ b/app/views/referentials/_overview.html.slim
@@ -9,7 +9,7 @@
span.fa.fa-search
.form-group.togglable
= f.label Chouette::Line.human_attribute_name(:company_id), required: false, class: 'control-label'
- = f.input :company_id_eq_any, collection: overview.referential_lines.map(&:company).uniq.sort_by(&:name), as: :check_boxes, label: false, label_method: lambda{|l| ("<span>" + l.name + "</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list'}
+ = f.input :company_id_eq_any, collection: overview.referential_lines.map(&:company).compact.uniq.sort_by(&:name), as: :check_boxes, label: false, label_method: lambda{|l| ("<span>" + l.name + "</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list'}
.form-group.togglable
= f.label Chouette::Line.human_attribute_name(:transport_mode), required: false, class: 'control-label'
diff --git a/app/views/referentials/select_compliance_control_set.html.slim b/app/views/referentials/select_compliance_control_set.html.slim
index 87a888c0a..69c87aab2 100644
--- a/app/views/referentials/select_compliance_control_set.html.slim
+++ b/app/views/referentials/select_compliance_control_set.html.slim
@@ -2,7 +2,7 @@
.container-fluid
.row
.col-lg-8.col-lg-offset-2.col-md-8.col-md-offset-2.col-sm-10.col-sm-offset-1
- = form_tag validate_referential_path(params[:referential_id]), {class: 'form-horizontal', id: 'select_compliance_control_set', wrapper: :horizontal_form} do
+ = form_tag validate_referential_path(@referential), {class: 'form-horizontal', id: 'select_compliance_control_set', wrapper: :horizontal_form} do
.row
.col-lg-12
.form-group
diff --git a/app/views/routes/_form.html.slim b/app/views/routes/_form.html.slim
index 29e5be3d2..81f719437 100644
--- a/app/views/routes/_form.html.slim
+++ b/app/views/routes/_form.html.slim
@@ -27,7 +27,7 @@
// Get JSON data for route stop points
= javascript_tag do
| window.itinerary_stop = "#{URI.escape(route_json_for_edit(@route))}";
- | window.I18n = #{(I18n.backend.send(:translations)[I18n.locale].to_json).html_safe};
+ // | window.I18n = #{(I18n.backend.send(:translations)[I18n.locale].to_json).html_safe};
/ StopPoints Reactux component
= javascript_pack_tag 'routes/edit.js'
diff --git a/app/views/stif/dashboards/_dashboard.html.slim b/app/views/stif/dashboards/_dashboard.html.slim
index 64e7d4f96..83a2106bb 100644
--- a/app/views/stif/dashboards/_dashboard.html.slim
+++ b/app/views/stif/dashboards/_dashboard.html.slim
@@ -47,7 +47,7 @@
- if @dashboard.referentials.present?
.list-group
- @dashboard.referentials.first(5).each_with_index do |referential, i|
- = link_to referential.name, referential_path(referential, workbench_id: referential.workbench_id, current_workbench_id: @dashboard.workbench.id), class: 'list-group-item' if i < 6
+ = link_to referential.name, referential_path(referential), class: 'list-group-item' if i < 6
- else
.panel-body
@@ -60,12 +60,12 @@
span.badge.ml-xs = @dashboard.calendars.count if @dashboard.calendars.present?
div
- = link_to '', calendars_path, class: ' fa fa-chevron-right pull-right', title: t('.see')
+ = link_to '', workgroup_calendars_path(@dashboard.workbench.workgroup), class: ' fa fa-chevron-right pull-right', title: t('.see')
- if @dashboard.calendars.present?
.list-group
- @dashboard.calendars.first(5).each_with_index do |calendar, i|
- = link_to calendar.name, calendar_path(calendar), class: 'list-group-item' if i < 6
+ = link_to calendar.name, workgroup_calendar_path(@dashboard.workbench.workgroup, calendar), class: 'list-group-item' if i < 6
- else
.panel-body
diff --git a/app/views/time_tables/_form.html.slim b/app/views/time_tables/_form.html.slim
index d06fdf444..007044e65 100644
--- a/app/views/time_tables/_form.html.slim
+++ b/app/views/time_tables/_form.html.slim
@@ -5,7 +5,7 @@
= form.input :comment, :input_html => { :title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.time_table.comment")}
- if @time_table.new_record? && !@time_table.created_from
- = form.input :calendar_id, as: :select, input_html: { class: 'tt_target', style: "width: 100%", data: { 'select2-ajax': 'true', 'select2ed-placeholder': 'Indiquez un modèle de calendrier...', term: 'name_cont', url: autocomplete_calendars_path}}
+ = form.input :calendar_id, as: :select, input_html: { class: 'tt_target', style: "width: 100%", data: { 'select2-ajax': 'true', 'select2ed-placeholder': 'Indiquez un modèle de calendrier...', term: 'name_cont', url: autocomplete_workgroup_calendars_path(current_workgroup)}}
- if @time_table.created_from
= form.input :created_from, disabled: true, input_html: { value: @time_table.created_from.comment }
diff --git a/app/views/time_tables/edit.html.slim b/app/views/time_tables/edit.html.slim
index e1c566ff4..d8cffb1b0 100644
--- a/app/views/time_tables/edit.html.slim
+++ b/app/views/time_tables/edit.html.slim
@@ -8,6 +8,6 @@
= javascript_tag do
| window.actionType = "#{raw params[:action]}";
- | window.I18n = #{(I18n.backend.send(:translations)[I18n.locale].to_json).html_safe};
+ // | window.I18n = #{(I18n.backend.send(:translations)[I18n.locale].to_json).html_safe};
= javascript_pack_tag 'time_tables/edit.js'
diff --git a/app/views/time_tables/index.html.slim b/app/views/time_tables/index.html.slim
index f58fbb5ea..6913712a0 100644
--- a/app/views/time_tables/index.html.slim
+++ b/app/views/time_tables/index.html.slim
@@ -61,6 +61,6 @@
= replacement_msg t('time_tables.search_no_results')
= javascript_tag do
- | window.I18n = #{(I18n.backend.send(:translations).to_json).html_safe};
+ // | window.I18n = #{(I18n.backend.send(:translations).to_json).html_safe};
= javascript_pack_tag 'date_filters'
diff --git a/app/views/vehicle_journeys/index.html.slim b/app/views/vehicle_journeys/index.html.slim
index caa8450a0..d53d8b50c 100644
--- a/app/views/vehicle_journeys/index.html.slim
+++ b/app/views/vehicle_journeys/index.html.slim
@@ -29,7 +29,7 @@
| window.features = #{raw @features};
| window.all_missions = #{(@all_missions.to_json).html_safe};
| window.custom_fields = #{(@custom_fields.to_json).html_safe};
- | window.I18n = #{(I18n.backend.send(:translations).to_json).html_safe};
+ // | window.I18n = #{(I18n.backend.send(:translations).to_json).html_safe};
- if has_feature?(:vehicle_journeys_return_route)
= javascript_tag do
diff --git a/app/views/vehicle_journeys/show.rabl b/app/views/vehicle_journeys/show.rabl
index dca0866b3..bb26ce797 100644
--- a/app/views/vehicle_journeys/show.rabl
+++ b/app/views/vehicle_journeys/show.rabl
@@ -23,6 +23,12 @@ end
child(:time_tables, :object_root => false) do |time_tables|
attributes :id, :objectid, :comment, :color
+ node(:days) do |tt|
+ tt.display_day_types
+ end
+ node(:bounding_dates) do |tt|
+ tt.presenter.time_table_bounding
+ end
child(:calendar) do
attributes :id, :name, :date_ranges, :dates, :shared
end
@@ -39,10 +45,8 @@ child :footnotes, :object_root => false do |footnotes|
end
child(:vehicle_journey_at_stops_matrix, :object_root => false) do |vehicle_stops|
+ attributes :id, :connecting_service_id, :boarding_alighting_possibility
node do |vehicle_stop|
- [:id, :connecting_service_id, :boarding_alighting_possibility].map do |att|
- node(att) { vehicle_stop.send(att) ? vehicle_stop.send(att) : nil }
- end
node(:dummy) { vehicle_stop.dummy }
node(:area_kind) { vehicle_stop.stop_point.stop_area.kind }
diff --git a/app/views/workbenches/show.html.slim b/app/views/workbenches/show.html.slim
index a162ca334..159aa8ea2 100644
--- a/app/views/workbenches/show.html.slim
+++ b/app/views/workbenches/show.html.slim
@@ -5,7 +5,7 @@
.col-lg-12.text-right
- 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'
+ = link_to t('actions.add'), new_workbench_referential_path(@workbench), class: 'btn btn-primary'
= link_to t('workbenches.actions.show_output'), workbench_output_path(@workbench), class: 'btn btn-primary'
.page_content
@@ -25,7 +25,7 @@
key: :name, \
attribute: 'name', \
link_to: lambda do |referential| \
- referential_path(referential, current_workbench_id: params[:id]) \
+ referential_path(referential) \
end \
), \
TableBuilderHelper::Column.new( \
@@ -72,6 +72,6 @@
= replacement_msg t('referentials.search_no_results')
= javascript_tag do
- | window.I18n = #{(I18n.backend.send(:translations).to_json).html_safe};
+ // | window.I18n = #{(I18n.backend.send(:translations).to_json).html_safe};
= javascript_pack_tag 'date_filters'
diff --git a/config/breadcrumbs.rb b/config/breadcrumbs.rb
index 6da96d73a..00ccf16bd 100644
--- a/config/breadcrumbs.rb
+++ b/config/breadcrumbs.rb
@@ -23,12 +23,12 @@ end
crumb :referential do |referential|
link breadcrumb_name(referential), referential_path(referential)
- parent :workbench, current_offer_workbench
+ parent :workbench, mutual_workbench(referential.workbench)
end
crumb :referentials do |referential|
- link I18n.t('referentials.index.title'), referentials_path()
- parent :workbench, current_offer_workbench
+ link I18n.t('referentials.index.title'), workbench_path(current_workbench)
+ parent :workbench, mutual_workbench(current_workbench)
end
crumb :referential_companies do |referential|
@@ -202,13 +202,13 @@ crumb :purchase_window do |referential, purchase_window|
parent :purchase_windows, referential
end
-crumb :calendars do
- link I18n.t('calendars.index.title'), calendars_path
+crumb :calendars do |workgroup|
+ link I18n.t('calendars.index.title'), workgroup_calendars_path(workgroup)
end
-crumb :calendar do |calendar|
- link breadcrumb_name(calendar), calendar_path(calendar)
- parent :calendars
+crumb :calendar do |workgroup, calendar|
+ link breadcrumb_name(calendar), workgroup_calendar_path(workgroup, calendar)
+ parent :calendars, workgroup
end
crumb :referential_line do |referential, line|
diff --git a/config/deploy.rb b/config/deploy.rb
index 9be023adc..86339d137 100644
--- a/config/deploy.rb
+++ b/config/deploy.rb
@@ -13,7 +13,8 @@ set :group_writable, true
set :bundle_cmd, "/var/lib/gems/#{ruby_version}/bin/bundle"
set :rake, "#{bundle_cmd} exec rake"
set :default_environment, {
- 'PATH' => "/var/lib/gems/#{ruby_version}/bin:$PATH"
+ 'PATH' => "/var/lib/gems/#{ruby_version}/bin:$PATH",
+ 'NODE_ENV' => "production"
}
set :keep_releases, -> { fetch(:kept_releases, 5) }
@@ -79,6 +80,7 @@ namespace :deploy do
end
after 'deploy:update_code', 'deploy:symlink_shared'
before 'deploy:assets:precompile', 'deploy:symlink_shared'
+ after 'deploy:assets:precompile', "deploy:i18n_js_export"
desc "Make group writable all deployed files"
task :group_writable do
@@ -92,8 +94,13 @@ namespace :deploy do
end
after "deploy:restart", "deploy:sidekiq_restart"
+ desc "Run i18n:js:export"
+ task :i18n_js_export do
+ run "cd #{release_path} && RAILS_ENV=#{rails_env} #{rake} i18n:js:export"
+ end
+
desc "Run db:seed"
task :seed do
- run "cd #{current_path} && #{rake} db:seed RAILS_ENV=#{rails_env}"
+ run "cd #{current_path} && RAILS_ENV=#{rails_env} #{rake} db:seed"
end
end
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 1d2fee44f..446e72190 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -95,6 +95,7 @@ Rails.application.configure do
config.i18n.available_locales = [:fr, :en]
config.middleware.insert_after(ActionDispatch::Static, Rack::LiveReload) if ENV['LIVERELOAD']
+ config.middleware.use I18n::JS::Middleware
config.development_toolbar = false
if ENV['TOOLBAR'] && File.exists?("config/development_toolbar.rb")
config.development_toolbar = OpenStruct.new
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 57a8e1483..9a699eb44 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -47,6 +47,7 @@ Rails.application.configure do
# Set to :debug to see everything in the log.
# config.log_level = :info
+ config.log_level = :info
# Prepend all log lines with the following tags.
# config.log_tags = [ :subdomain, :uuid ]
diff --git a/config/initializers/apartment.rb b/config/initializers/apartment.rb
index 2d06fb88b..fc652a2da 100644
--- a/config/initializers/apartment.rb
+++ b/config/initializers/apartment.rb
@@ -81,6 +81,7 @@ Apartment.configure do |config|
'ComplianceCheckMessage',
'Merge',
'CustomField',
+ 'SimpleImporter',
]
# use postgres schemas?
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index a177e7091..2f65b8800 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -14,4 +14,8 @@ Sidekiq.configure_client do |config|
config.redis = { url: ENV.fetch('SIDEKIQ_REDIS_URL', 'redis://localhost:6379/12') }
end
+Sidekiq.configure_client do |config|
+ config.redis = { url: ENV.fetch('SIDEKIQ_REDIS_URL', 'redis://localhost:6379/12') }
+end
+
Sidekiq.default_worker_options = { retry: false }
diff --git a/config/locales/compliance_controls.fr.yml b/config/locales/compliance_controls.fr.yml
index 1448cdbc8..f5f7e351f 100644
--- a/config/locales/compliance_controls.fr.yml
+++ b/config/locales/compliance_controls.fr.yml
@@ -7,8 +7,8 @@ fr:
name: "Chercher le nom ou code d'un contrôle"
subclass: Objet
subclasses:
- generic: 'Généric'
- journey_pattern: 'JourneyPattern'
+ generic: 'Générique'
+ journey_pattern: 'Mission'
line: 'Ligne'
route: 'Itinéraire'
routing_constraint_zone: 'ITL'
diff --git a/config/locales/en.yml b/config/locales/en.yml
index e59960f95..8af8067db 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -3,6 +3,7 @@ en:
"false": "No"
"unknown": "Unknown"
+
time:
formats:
hour: "%Hh%M"
@@ -61,3 +62,7 @@ en:
reflex_data: 'Reflex datas'
objectid: 'ID'
brandname: IBOO
+ error: "Error"
+ undefined: 'undefined'
+ "yes": yes
+ "no": no
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 175b71ebc..e1f52ff55 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -61,3 +61,7 @@ fr:
reflex_data: 'Données Reflex'
objectid: 'ID'
brandname: IBOO
+ error: "Erreur"
+ undefined: 'non renseigné'
+ "yes": oui
+ "no": non
diff --git a/config/locales/imports.en.yml b/config/locales/imports.en.yml
index f843eea47..b0644acd3 100644
--- a/config/locales/imports.en.yml
+++ b/config/locales/imports.en.yml
@@ -17,6 +17,8 @@ en:
warning: ""
new:
title: "Generate a new import"
+ create:
+ title: "Generate a new import"
show:
title: "Import %{name}"
report: "Report"
diff --git a/config/locales/imports.fr.yml b/config/locales/imports.fr.yml
index c24f08e76..2380eac45 100644
--- a/config/locales/imports.fr.yml
+++ b/config/locales/imports.fr.yml
@@ -17,6 +17,8 @@ fr:
warning: ""
new:
title: "Générer un import"
+ create:
+ title: "Générer un import"
show:
title: "Import %{name}"
report: "Rapport"
diff --git a/config/locales/journey_patterns.en.yml b/config/locales/journey_patterns.en.yml
index e5248c29c..9d9bc21e2 100644
--- a/config/locales/journey_patterns.en.yml
+++ b/config/locales/journey_patterns.en.yml
@@ -6,6 +6,7 @@ en:
vehicle_journeys_count: "Vehicle journeys: %{count}"
vehicle_journey_at_stops: "Vehicle journey at stops"
actions:
+ index: "Journey patterns"
new: "Add a new journey_pattern"
edit: "Edit this journey pattern"
destroy: "Remove this journey pattern"
diff --git a/config/locales/stop_areas.en.yml b/config/locales/stop_areas.en.yml
index 09e8d1a82..c1ced1094 100644
--- a/config/locales/stop_areas.en.yml
+++ b/config/locales/stop_areas.en.yml
@@ -48,11 +48,15 @@ en:
area_type: Type an area type...
new:
title: "Add a new stop"
+ update:
+ title: "Add a new stop"
form:
address: "246 Boulevard Saint-Germain, 75007 Paris"
geolocalize: "Pinpoint "
edit:
title: "Update stop %{stop_area}"
+ update:
+ title: "Update stop %{stop_area}"
show:
title: "Stop %{stop_area}"
geographic_data: "Geographic data"
diff --git a/config/locales/stop_areas.fr.yml b/config/locales/stop_areas.fr.yml
index 283000960..ede1aada6 100644
--- a/config/locales/stop_areas.fr.yml
+++ b/config/locales/stop_areas.fr.yml
@@ -49,11 +49,15 @@ fr:
area_type: "Indiquez un type d'arrêt..."
new:
title: "Ajouter un arrêt"
+ create:
+ title: "Ajouter un arrêt"
form:
address: "246 Boulevard Saint-Germain, 75007 Paris"
geolocalize: "Géolocalisez "
edit:
title: "Editer l'arrêt %{name}"
+ update:
+ title: "Editer l'arrêt %{name}"
show:
title: "Arrêt %{name}"
geographic_data: "Données géographiques"
diff --git a/config/locales/stop_points.en.yml b/config/locales/stop_points.en.yml
index d22d85731..72e138270 100644
--- a/config/locales/stop_points.en.yml
+++ b/config/locales/stop_points.en.yml
@@ -55,3 +55,4 @@ en:
name: Stop Point
for_boarding: "Pickup"
for_alighting: "Drop off"
+ reflex_id: ID
diff --git a/config/locales/stop_points.fr.yml b/config/locales/stop_points.fr.yml
index d3c873442..71be684f6 100644
--- a/config/locales/stop_points.fr.yml
+++ b/config/locales/stop_points.fr.yml
@@ -52,6 +52,7 @@ fr:
simple_form:
labels:
stop_point:
- name: Arrêt
+ name: Arrêt
for_boarding: "Montée"
for_alighting: "Descente"
+ reflex_id: ID
diff --git a/config/locales/vehicle_journeys.en.yml b/config/locales/vehicle_journeys.en.yml
index abb1da530..0c8a75b0c 100644
--- a/config/locales/vehicle_journeys.en.yml
+++ b/config/locales/vehicle_journeys.en.yml
@@ -1,7 +1,14 @@
en:
vehicle_journeys:
vehicle_journeys_matrix:
+ cancel_selection: "Cancel Selection"
+ fetching_error: "There has been a problem fetching the data. Please reload the page to try again."
line_routes: "Line's routes"
+ modal_confirm: 'Do you want to save mofications before moving on to the next page ?'
+ pagination: "Schedules %{minVJ} to %{maxVJ} over %{total}"
+ selected_journeys: "%{count} selected journeys"
+ show_purchase_window: 'Show the purchase window'
+ show_timetable: 'Show calendar'
vehicle_journey:
title_stopless: "Vehicle journey %{name}"
title: "Vehicle journey leaving from %{stop} at %{time}"
@@ -25,44 +32,54 @@ en:
title_stopless: "Update vehicle journey %{name}"
title: "Update vehicle journey %{name} leaving from %{stop} at %{time}"
form:
- stop_title: "Stop"
- departure: "Departure"
+ arrival_at: "Arrival at"
arrival: "Arrival"
- to_arrivals: "Copy departures to arrivals"
- to_departures: "Copy arrivals to departures"
- time_tables: "Associated calendars to vehicle journey"
- slide: "Shift"
- slide_title: "Shift all vehicle passing times"
+ departure_at: "Departure at"
+ departure: "Departure"
+ departure_range:
+ label: Journey departure range
+ start: Start
+ end: End
+ infos: Informations
set: "Set"
- to: "at"
- slide_departure: "departure time at first stop"
+ show_arrival_time: "Show and edit arrival times"
+ show_journeys_with_calendar: "Show journeys with calendar"
+ show_journeys_without_schedule: "Show journeys without schedule"
slide_arrival: "arrival time at first stop"
- submit_timed: "Create vehicle journey"
+ slide_departure: "departure time at first stop"
+ slide_title: "Shift all vehicle passing times"
+ slide: "Shift"
+ stop_title: "Stop"
+ submit_frequency_edit: "Edit frequency vehicle journey"
submit_frequency: "Create frequency vehicle journey"
submit_timed_edit: "Edit vehicle journey"
- submit_frequency_edit: "Edit frequency vehicle journey"
+ submit_timed: "Create vehicle journey"
+ time_tables: "Associated calendars to vehicle journey"
+ to_arrivals: "Copy departures to arrivals"
+ to_departures: "Copy arrivals to departures"
+ to: "at"
timeless:
title: "Timeless vehicle journeys"
vehicle_journeys: "Vehicle journeys with times at stop"
vehicles_list: "Vehicle journeys list"
show:
- title: "Vehicle Journey %{vehicle journey}"
- stop_title: "Stop"
- departure: "Departure"
arrival: "Arrival"
- time_tables: "Calendars list"
bounding: "From %{start} to %{end}"
- translation_form: "Vehicle journey translations"
+ departure: "Departure"
journey_frequencies: "Timeband"
+ stop_title: "Stop"
+ time_tables: "Calendars list"
+ title: "Vehicle Journey %{vehicle journey}"
+ translation_form: "Vehicle journey translations"
index:
- title: "Vehicle journeys on route %{route}"
- vehicle_journeys: "Departure's times"
- selection: "Filter on"
- selection_all: "All"
+ advanced_search: "Advanced Search"
select_journey_patterns: "Select journey pattern"
select_time_tables: "Enter a timetable"
+ selection_all: "All"
+ selection: "Filter on"
time_range: "Departure time threshold"
- advanced_search: "Advanced Search"
+ title: "Vehicle journeys on route %{route}"
+ vehicle_journeys: "Departure's times"
time_filter:
time_range_filter: "Filter"
sidebar:
@@ -78,40 +95,47 @@ en:
other: "vehicle journeys"
attributes:
vehicle_journey:
- line: "Line"
- route: "Route"
- journey_pattern: "Journey Pattern"
- time_tables: "Calendars"
- time_slot: "Time Slot"
- company: "Company"
- number: "Number"
+ accessible: "Accessible"
+ arrival_time: "Arrival"
+ checksum: "Checksum"
comment: "Comments"
- status_value: "Status Value"
- transport_mode: "Transport Mode"
- mobility_restricted_suitability: "PRM accessibility"
+ company: "Company"
+ created_at: Created at
+ creator_id: "Created by"
+ departure_time: "Departure"
+ facility: "Facility"
flexible_service: "On demond transportation"
- unspecified_mrs: "Not specified"
- accessible: "Accessible"
+ footnote_ids: "Footnotes"
+ id: "Journey ID"
+ journey_frequency_ids: "Timeband"
+ journey_name: "Name of the journey"
+ journey_pattern_id: "Pattern ID"
+ journey_pattern: "Journey Pattern"
+ line: "Line"
+ mobility_restricted_suitability: "PRM accessibility"
+ name: "Journey Name"
not_accessible: "Not accessible"
- unspecified_fs: "Not specified"
+ number: "Number"
+ object_version: "Version"
+ objectid: "Neptune identifier"
on_demand_fs: "On demand service"
- regular_fs: "Regular service"
- published_journey_name: "Published Name"
published_journey_identifier: "Published Identifier"
- facility: "Facility"
- vehicle_type_identifier: "Vehicle Type Identifier"
+ published_journey_name: "Published Name"
+ purchase_window: "Purchase availability"
+ regular_fs: "Regular service"
+ route: "Route"
+ status_value: "Status Value"
+ time_slot: "Time Slot"
time_table_ids: "Calendar list"
- vehicle_journey_at_stop_ids: "Time list"
- journey_frequency_ids: "Timeband"
- objectid: "Neptune identifier"
- object_version: "Version"
- created_at: Created at
+ time_tables: "Calendars"
+ train_number: "Train number"
+ transport_mode: "Transport Mode"
+ transport_submode: "Transport Submode"
+ unspecified_fs: "Not specified"
+ unspecified_mrs: "Not specified"
updated_at: Updated at
- creator_id: "Created by"
- footnote_ids: "Footnotes"
- departure_time: "Departure"
- arrival_time: "Arrival"
- purchase_window: "Purchase availability"
+ vehicle_journey_at_stop_ids: "Time list"
+ vehicle_type_identifier: "Vehicle Type Identifier"
errors:
models:
vehicle_journey:
diff --git a/config/locales/vehicle_journeys.fr.yml b/config/locales/vehicle_journeys.fr.yml
index ca8475812..1034a3fba 100644
--- a/config/locales/vehicle_journeys.fr.yml
+++ b/config/locales/vehicle_journeys.fr.yml
@@ -1,7 +1,14 @@
fr:
vehicle_journeys:
vehicle_journeys_matrix:
+ cancel_selection: "Annuler la sélection"
+ fetching_error: "La récupération des missions a rencontré un problème. Rechargez la page pour tenter de corriger le problème."
line_routes: "Séquences d'arrêts de la ligne"
+ modal_confirm: 'Voulez-vous valider vos modifications avant de changer de page?'
+ pagination: "Liste des horaires %{minVJ} à %{maxVJ} sur %{total}"
+ selected_journeys: "%{count} course(s) sélectionnée(s)"
+ show_purchase_window: 'Voir le calendrier commercial'
+ show_timetable: 'Voir le calendrier'
vehicle_journey:
title_stopless: "Course %{name}"
title: "Course partant de %{stop} à %{time}"
@@ -25,44 +32,55 @@ fr:
title_stopless: "Editer la course %{name}"
title: "Editer la course partant de %{stop} à %{time}"
form:
- stop_title: "Arrêt"
- departure: "Départ"
+ arrival_at: "Arrivée à"
arrival: "Arrivée"
- to_arrivals: "Copie départs vers arrivées"
- to_departures: "Copie arrivées vers départs"
- time_tables: "Calendriers associés à la course"
- slide: "Décaler"
- slide_title: "Décaler l'ensemble des horaires de course"
+ departure_at: "Départ à"
+ departure: "Départ"
+ departure_range:
+ label: Plage horaire au départ de la course
+ start: Début
+ end: Fin
+ infos: Informations
set: "Fixer"
- to: "à"
- slide_departure: "horaire de départ au 1° arrêt à"
+ show_arrival_time: "Afficher et éditer les horaires d'arrivée"
+ show_journeys_with_calendar: "Afficher les courses avec calendrier"
+ show_journeys_without_schedule: "Afficher les courses sans horaires"
slide_arrival: "horaire d'arrivée au 1° arrêt à"
- submit_timed: "Créer course"
+ slide_departure: "horaire de départ au 1° arrêt à"
+ slide_title: "Décaler l'ensemble des horaires de course"
+ slide: "Décaler"
+ stop_title: "Arrêt"
+ submit_frequency_edit: "Editer course en fréquence"
submit_frequency: "Créer course en fréquence"
submit_timed_edit: "Editer course"
- submit_frequency_edit: "Editer course en fréquence"
+ submit_timed: "Créer course"
+ time_tables: "Calendriers associés à la course"
+ to_arrivals: "Copie départs vers arrivées"
+ to_arrivals: "Copie départs vers arrivées"
+ to_departures: "Copie arrivées vers départs"
+ to: "à"
timeless:
title: "Courses sans horaire"
vehicle_journeys: "Courses ayant des horaires"
vehicles_list: "Liste des courses"
show:
- title: "Course au départ de %{stop} à %{time} sur la séquence %{route}"
- stop_title: "Arrêt"
- departure: "Départ"
arrival: "Arrivée"
- time_tables: "Liste des calendriers"
bounding: "De %{start} à %{end}"
- translation_form: "Cloner la course"
+ departure: "Départ"
journey_frequencies: "Créneau horaire"
+ stop_title: "Arrêt"
+ time_tables: "Liste des calendriers"
+ title: "Course au départ de %{stop} à %{time} sur la séquence %{route}"
+ translation_form: "Cloner la course"
index:
- title: "Horaires de '%{route}'"
- vehicle_journeys: "Horaires de départ aux arrêts"
- selection: "Filtrer sur"
- selection_all: "Tous"
+ advanced_search: "Recherche avancée"
select_journey_patterns: "Sélectionner une mission"
select_time_tables: "Saisir un calendrier"
+ selection_all: "Tous"
+ selection: "Filtrer sur"
time_range: "Seuil horaire au départ"
- advanced_search: "Recherche avancée"
+ title: "Horaires de '%{route}'"
+ vehicle_journeys: "Horaires de départ aux arrêts"
time_filter:
time_range_filter: "Filtrer"
sidebar:
@@ -78,40 +96,47 @@ fr:
other: "courses"
attributes:
vehicle_journey:
- line: "Ligne"
- route: "Séquence d'arrêt"
- journey_pattern: "Mission"
- time_tables: "Calendriers"
- time_slot: "Fréquence"
- company: "Transporteur"
- number: "Numéro"
+ accessible: "Accessible"
+ arrival_time: "Arrivée"
+ checksum: "Signature métier"
comment: "Commentaires"
- status_value: "Etat de trafic"
- transport_mode: "Mode de transport"
- mobility_restricted_suitability: "Accessibilité PMR"
+ company: "Transporteur"
+ created_at: "Créé le"
+ creator_id: "Créé par"
+ departure_time: "Départ"
+ facility: "Equipement"
flexible_service: "Transport à la demande"
- unspecified_mrs: "Non spécifié"
- accessible: "Accessible"
+ footnote_ids: "Notes de bas de page"
+ id: "ID Course"
+ journey_frequency_ids: "Créneau horaire"
+ journey_name: "Nom de la course"
+ journey_pattern_id: "ID Mission"
+ journey_pattern: "Mission"
+ line: "Ligne"
+ mobility_restricted_suitability: "Accessibilité PMR"
+ name: "Nom Course"
not_accessible: "Non accessible"
- unspecified_fs: "Non spécifié"
+ number: "Numéro"
+ object_version: "Version"
+ objectid: "Identifiant Neptune"
on_demand_fs: "Service à la demande"
- regular_fs: "Service régulier"
- published_journey_name: "Nom public"
published_journey_identifier: "Identifiant public"
- facility: "Equipement"
- vehicle_type_identifier: "Type d'identifiant du véhicule"
+ published_journey_name: "Nom public"
+ purchase_window: "Disponibilité commerciale"
+ regular_fs: "Service régulier"
+ route: "Itinéraire"
+ status_value: "Etat de trafic"
+ time_slot: "Fréquence"
time_table_ids: "Liste des calendriers"
- vehicle_journey_at_stop_ids: "Liste des horaires"
- journey_frequency_ids: "Créneau horaire"
- objectid: "Identifiant Neptune"
- object_version: "Version"
- created_at: "Créé le"
+ time_tables: "Calendriers"
+ train_number: "Numéro de train"
+ transport_mode: "Mode de transport"
+ transport_submode: "Sous-mode de transport"
+ unspecified_fs: "Non spécifié"
+ unspecified_mrs: "Non spécifié"
updated_at: "Edité le"
- creator_id: "Créé par"
- footnote_ids: "Notes de bas de page"
- departure_time: "Départ"
- arrival_time: "Arrivée"
- purchase_window: "Disponibilité commerciale"
+ vehicle_journey_at_stop_ids: "Liste des horaires"
+ vehicle_type_identifier: "Type d'identifiant du véhicule"
errors:
models:
vehicle_journey:
diff --git a/config/routes.rb b/config/routes.rb
index fc2807ab1..456cb66f5 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -19,113 +19,32 @@ ChouetteIhm::Application.routes.draw do
resource :output, controller: :workbench_outputs
resources :merges
- end
-
- devise_for :users, :controllers => {
- :registrations => 'users/registrations', :invitations => 'users/invitations'
- }
-
- devise_scope :user do
- authenticated :user do
- root :to => 'workbenches#index', as: :authenticated_root
- end
-
- unauthenticated :user do
- target = 'devise/sessions#new'
- if Rails.application.config.chouette_authentication_settings[:type] == "cas"
- target = 'devise/cas_sessions#new'
- end
-
- root :to => target, as: :unauthenticated_root
- end
+ resources :referentials, only: %w(new create)
end
- mount Sidekiq::Web => '/sidekiq'
-
- namespace :api do
- namespace :v1 do
- resources :workbenches, only: [:index, :show] do
- resources :imports, only: [:index, :show, :create]
- end
- resources :access_links, only: [:index, :show]
- resources :access_points, only: [:index, :show]
- resources :connection_links, only: [:index, :show]
- resources :companies, only: [:index, :show]
- resources :group_of_lines, only: [:index, :show]
- resources :netex_imports, only: :create
- resources :journey_patterns, only: :show
- resources :lines, only: [:index, :show] do
- resources :journey_patterns, only: [:index, :show]
- resources :routes, only: [:index, :show] do
- resources :vehicle_journeys, only: [:index, :show]
- resources :journey_patterns, only: [:index, :show]
- resources :stop_areas, only: [:index, :show]
- end
- end
- resources :networks, only: [:index, :show]
- resources :routes, only: :show
- resources :stop_areas, only: [:index, :show]
- resources :time_tables, only: [:index, :show]
- resources :vehicle_journeys, only: :show
- namespace :internals do
- get 'compliance_check_sets/:id/notify_parent', to: 'compliance_check_sets#notify_parent'
- get 'netex_imports/:id/notify_parent', to: 'netex_imports#notify_parent'
+ resources :workgroups do
+ resources :calendars do
+ get :autocomplete, on: :collection, controller: 'autocomplete_calendars'
+ member do
+ get 'month', defaults: { format: :json }
end
end
end
- resource :organisation, :only => [:show, :edit, :update] do
- resources :users
- end
-
- resources :api_keys, :only => [:edit, :update, :new, :create, :destroy]
-
- resources :compliance_control_sets do
- get :simple, on: :member
- get :clone, on: :member
- resources :compliance_controls, except: :index do
- get :select_type, on: :collection
- end
- resources :compliance_control_blocks, :except => [:show, :index]
- end
-
- deactivable = Proc.new do
- put :deactivate, on: :member
- put :activate, on: :member
- end
-
- resources :stop_area_referentials, :only => [:show] do
- post :sync, on: :member
- resources :stop_areas do
- put :deactivate, on: :member
- put :activate, on: :member
- get :autocomplete, on: :collection
- end
- end
-
- resources :line_referentials, :only => [:show, :edit, :update] do
- post :sync, on: :member
- resources :lines, &deactivable
- resources :group_of_lines
- resources :companies
- resources :networks
- end
+ resources :referentials, except: %w(new create) do
- resources :calendars do
- get :autocomplete, on: :collection, controller: 'autocomplete_calendars'
member do
- get 'month', defaults: { format: :json }
+ put :archive
+ put :unarchive
+ get :select_compliance_control_set
+ post :validate
end
- end
- resources :referentials, except: :index do
resources :autocomplete_stop_areas, only: [:show, :index] do
get 'around', on: :member
end
resources :autocomplete_purchase_windows, only: [:index]
- get :select_compliance_control_set
- post :validate, on: :member
resources :autocomplete_time_tables, only: [:index]
resources :autocomplete_timebands
resources :group_of_lines, controller: "referential_group_of_lines" do
@@ -134,12 +53,6 @@ ChouetteIhm::Application.routes.draw do
end
end
- # Archive/unarchive
- member do
- put :archive
- put :unarchive
- end
-
resources :networks, controller: "referential_networks"
match 'lines' => 'lines#destroy_all', :via => :delete
@@ -237,8 +150,111 @@ ChouetteIhm::Application.routes.draw do
resources :clean_ups
end
+ devise_for :users, :controllers => {
+ :registrations => 'users/registrations', :invitations => 'users/invitations'
+ }
+
+ devise_scope :user do
+ authenticated :user do
+ root :to => 'workbenches#index', as: :authenticated_root
+ end
+
+ unauthenticated :user do
+ target = 'devise/sessions#new'
+
+ if Rails.application.config.chouette_authentication_settings[:type] == "cas"
+ target = 'devise/cas_sessions#new'
+ end
+
+ root :to => target, as: :unauthenticated_root
+ end
+ end
+
+ mount Sidekiq::Web => '/sidekiq'
+
+ namespace :api do
+ namespace :v1 do
+ resources :workbenches, only: [:index, :show] do
+ resources :imports, only: [:index, :show, :create]
+ end
+ resources :access_links, only: [:index, :show]
+ resources :access_points, only: [:index, :show]
+ resources :connection_links, only: [:index, :show]
+ resources :companies, only: [:index, :show]
+ resources :group_of_lines, only: [:index, :show]
+ resources :netex_imports, only: :create
+ resources :journey_patterns, only: :show
+ resources :lines, only: [:index, :show] do
+ resources :journey_patterns, only: [:index, :show]
+ resources :routes, only: [:index, :show] do
+ resources :vehicle_journeys, only: [:index, :show]
+ resources :journey_patterns, only: [:index, :show]
+ resources :stop_areas, only: [:index, :show]
+ end
+ end
+ resources :networks, only: [:index, :show]
+ resources :routes, only: :show
+ resources :stop_areas, only: [:index, :show]
+ resources :time_tables, only: [:index, :show]
+ resources :vehicle_journeys, only: :show
+ namespace :internals do
+ get 'compliance_check_sets/:id/notify_parent', to: 'compliance_check_sets#notify_parent'
+ get 'netex_imports/:id/notify_parent', to: 'netex_imports#notify_parent'
+ end
+ end
+ end
+
+ resource :organisation, :only => [:show, :edit, :update] do
+ resources :users
+ end
+
+ resources :api_keys, :only => [:edit, :update, :new, :create, :destroy]
+
+ resources :compliance_control_sets do
+ get :simple, on: :member
+ get :clone, on: :member
+ resources :compliance_controls, except: :index do
+ get :select_type, on: :collection
+ end
+ resources :compliance_control_blocks, :except => [:show, :index]
+ end
+
+ deactivable = Proc.new do
+ put :deactivate, on: :member
+ put :activate, on: :member
+ end
+
+ resources :stop_area_referentials, :only => [:show] do
+ post :sync, on: :member
+ resources :stop_areas do
+ put :deactivate, on: :member
+ put :activate, on: :member
+ get :autocomplete, on: :collection
+ end
+ end
+
+ resources :line_referentials, :only => [:show, :edit, :update] do
+ post :sync, on: :member
+ resources :lines, &deactivable
+ resources :group_of_lines
+ resources :companies
+ resources :networks
+ end
+
+ resources :calendars do
+ get :autocomplete, on: :collection, controller: 'autocomplete_calendars'
+ member do
+ get 'month', defaults: { format: :json }
+ end
+ end
+
+
root :to => "dashboards#show"
+ if Rails.env.development? || Rails.env.test?
+ get "/snap" => "snapshots#show"
+ end
+
get '/help/(*slug)' => 'help#show'
if Rails.application.config.development_toolbar
@@ -250,4 +266,6 @@ ChouetteIhm::Application.routes.draw do
match '/422', to: 'errors#server_error', via: :all, as: 'unprocessable_entity'
match '/500', to: 'errors#server_error', via: :all, as: 'server_error'
+ match '/status', to: 'statuses#index', via: :get
+
end
diff --git a/config/schedule.rb b/config/schedule.rb
index 08488c255..0d2a24f31 100644
--- a/config/schedule.rb
+++ b/config/schedule.rb
@@ -40,9 +40,15 @@ every :day, :at => '4:00 am' do
end
every 5.minutes do
+ rake "import:netex_abort_old"
rake "import:notify_parent"
end
+every 5.minutes do
+ rake "compliance_check_sets:abort_old"
+ rake "compliance_check_sets:notify_parent"
+end
+
every 1.minute do
command "/bin/echo HeartBeat"
end
diff --git a/config/secrets.yml.docker b/config/secrets.yml.docker
index 1bef794a8..f9bbf5fa0 100644
--- a/config/secrets.yml.docker
+++ b/config/secrets.yml.docker
@@ -14,3 +14,4 @@
secret_key_base: <%= ENV.fetch 'SECRET_KEY_BASE', 'change_this_string_for_something_more_secure' %>
api_endpoint: <%= ENV.fetch 'IEV_API_ENDPOINT', 'http://iev:8080/chouette_iev/' %>
api_token: <%= ENV.fetch 'IEV_API_TOKEN', 'change this according to IEV configuration' %>
+ newrelic_licence_key: <%= ENV.fetch 'NR_LICENCE_KEY', 'will_not_work' %>
diff --git a/config/webpack/environment.js b/config/webpack/environment.js
index 688bcbe8e..743cf66a8 100644
--- a/config/webpack/environment.js
+++ b/config/webpack/environment.js
@@ -14,7 +14,7 @@ let cleanOptions = {
};
-environment.plugins.set(
+environment.plugins.append(
'CleanWebpack',
new CleanWebpackPlugin(pathsToClean, cleanOptions)
)
diff --git a/config/webpack/production.js b/config/webpack/production.js
index 7703f8452..8e30c09ea 100644
--- a/config/webpack/production.js
+++ b/config/webpack/production.js
@@ -2,7 +2,12 @@ const environment = require('./environment')
const webpack = require('webpack')
const UglifyJsPlugin = require('uglify-js')
-environment.plugins.set(
+let plugin = new webpack.EnvironmentPlugin({
+ NODE_ENV: 'production'
+})
+
+environment.plugins.append('EnvironmentPlugin', plugin)
+environment.plugins.append(
'UglifyJs',
new webpack.optimize.UglifyJsPlugin({
compress: {
diff --git a/config/webpack/staging.js b/config/webpack/staging.js
index 7703f8452..82478b156 100644
--- a/config/webpack/staging.js
+++ b/config/webpack/staging.js
@@ -2,7 +2,7 @@ const environment = require('./environment')
const webpack = require('webpack')
const UglifyJsPlugin = require('uglify-js')
-environment.plugins.set(
+environment.plugins.append(
'UglifyJs',
new webpack.optimize.UglifyJsPlugin({
compress: {
diff --git a/db/migrate/20180123174450_add_workgroup_id_to_calendars.rb b/db/migrate/20180123174450_add_workgroup_id_to_calendars.rb
new file mode 100644
index 000000000..64ad1a752
--- /dev/null
+++ b/db/migrate/20180123174450_add_workgroup_id_to_calendars.rb
@@ -0,0 +1,6 @@
+class AddWorkgroupIdToCalendars < ActiveRecord::Migration
+ def change
+ add_column :calendars, :workgroup_id, :integer, limit: 8
+ add_index :calendars, :workgroup_id
+ end
+end
diff --git a/db/migrate/20180129210928_create_simple_importers.rb b/db/migrate/20180129210928_create_simple_importers.rb
new file mode 100644
index 000000000..c2a918900
--- /dev/null
+++ b/db/migrate/20180129210928_create_simple_importers.rb
@@ -0,0 +1,10 @@
+class CreateSimpleImporters < ActiveRecord::Migration
+ def change
+ create_table :simple_importers do |t|
+ t.string :configuration_name
+ t.string :filepath
+ t.string :status
+ t.json :journal
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index cd4d42005..b10fa565c 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -90,12 +90,14 @@ ActiveRecord::Schema.define(version: 20180202170009) do
t.integer "organisation_id", limit: 8
t.datetime "created_at"
t.datetime "updated_at"
+ t.integer "workgroup_id", limit: 8
t.integer "int_day_types"
t.date "excluded_dates", array: true
end
add_index "calendars", ["organisation_id"], name: "index_calendars_on_organisation_id", using: :btree
add_index "calendars", ["short_name"], name: "index_calendars_on_short_name", unique: true, using: :btree
+ add_index "calendars", ["workgroup_id"], name: "index_calendars_on_workgroup_id", using: :btree
create_table "clean_up_results", id: :bigserial, force: :cascade do |t|
t.string "message_key"
@@ -722,6 +724,13 @@ ActiveRecord::Schema.define(version: 20180202170009) do
t.integer "line_id", limit: 8
end
+ create_table "simple_importers", id: :bigserial, force: :cascade do |t|
+ t.string "configuration_name"
+ t.string "filepath"
+ t.string "status"
+ t.json "journal"
+ end
+
create_table "stop_area_referential_memberships", id: :bigserial, force: :cascade do |t|
t.integer "organisation_id", limit: 8
t.integer "stop_area_referential_id", limit: 8
diff --git a/lib/af83/decorator.rb b/lib/af83/decorator.rb
index f990555fe..71cf1170d 100644
--- a/lib/af83/decorator.rb
+++ b/lib/af83/decorator.rb
@@ -2,40 +2,49 @@ class AF83::Decorator < ModelDecorator
include AF83::Decorator::EnhancedDecorator
extend AF83::Decorator::EnhancedDecorator::ClassMethods
- def self.decorates klass
- instance_decorator.decorates klass
- end
+ class << self
+ def decorates klass
+ instance_decorator.decorates klass
+ end
- def self.instance_decorator
- @instance_decorator ||= begin
- klass = Class.new(AF83::Decorator::InstanceDecorator)
- klass.delegate_all
- klass
+ def instance_decorator
+ @instance_decorator ||= begin
+ klass = Class.new(AF83::Decorator::InstanceDecorator)
+ klass.delegate_all
+ klass
+ end
end
- end
- def self.with_instance_decorator
- @_with_instance_decorator = true
- yield instance_decorator
- @_with_instance_decorator = false
- end
+ def with_instance_decorator
+ @_with_instance_decorator = true
+ yield instance_decorator
+ @_with_instance_decorator = false
+ end
+
+ def decorate object, options = {}
+ if object.is_a?(ActiveRecord::Base)
+ return instance_decorator.decorate object, options
+ else
+ self.new object, options.update(with: instance_decorator)
+ end
+ end
- def self.decorate object, options = {}
- if object.is_a?(ActiveRecord::Base)
- return instance_decorator.decorate object, options
- else
- self.new object, options.update(with: instance_decorator)
+ def define_instance_method method_name, &block
+ instance_decorator.send(:define_method, method_name, &block)
end
- end
- def self.define_instance_method method_name, &block
- instance_decorator.send(:define_method, method_name, &block)
- end
+ # Defines a class method on the decorated object's class. These
+ # can be called like `object.class.my_method`.
+ def define_instance_class_method method_name, &block
+ instance_decorator.send(:define_singleton_method, method_name, &block)
+ end
+
+ def set_scope_with_instance_decorator value=nil, &block
+ set_scope_without_instance_decorator value, &block
+ instance_decorator.set_scope value, &block
+ end
- # Defines a class method on the decorated object's class. These
- # can be called like `object.class.my_method`.
- def self.define_instance_class_method method_name, &block
- instance_decorator.send(:define_singleton_method, method_name, &block)
+ alias_method_chain :set_scope, :instance_decorator
end
class ActionLinks
diff --git a/lib/af83/decorator/enhanced_decorator.rb b/lib/af83/decorator/enhanced_decorator.rb
index 904d1b2da..fff8bb8b3 100644
--- a/lib/af83/decorator/enhanced_decorator.rb
+++ b/lib/af83/decorator/enhanced_decorator.rb
@@ -25,7 +25,7 @@ module AF83::Decorator::EnhancedDecorator
policy: :create,
before_block: -> (l){
l.content { h.t('actions.add') }
- l.href { [:new, object.klass.name.underscore.singularize] }
+ l.href { [:new, scope, object.klass.model_name.singular] }
}
}
action_link opts.update(args), &block
@@ -37,7 +37,7 @@ module AF83::Decorator::EnhancedDecorator
primary: :index,
before_block: -> (l){
l.content { h.t('actions.show') }
- l.href { [object] }
+ l.href { [scope, object] }
}
}
action_link opts.update(args), &block
@@ -49,7 +49,7 @@ module AF83::Decorator::EnhancedDecorator
policy: :edit,
before_block: -> (l){
l.content { h.t('actions.edit') }
- l.href { [:edit, object] }
+ l.href { [:edit, scope, object] }
}
}
action_link opts.update(args), &block
@@ -62,7 +62,7 @@ module AF83::Decorator::EnhancedDecorator
secondary: :show,
before_block: -> (l){
l.content { h.destroy_link_content }
- l.href { [object] }
+ l.href { [scope, object] }
l.method :delete
l.data {{ confirm: h.t('actions.destroy_confirm') }}
}
@@ -70,6 +70,14 @@ module AF83::Decorator::EnhancedDecorator
action_link opts.update(args), &block
end
+ def set_scope value=nil, &block
+ @scope = value || block
+ end
+
+ def scope
+ @scope
+ end
+
def t key
eval "-> (l){ h.t('#{key}') }"
end
@@ -142,4 +150,10 @@ module AF83::Decorator::EnhancedDecorator
def check_feature feature
h.has_feature? feature
end
+
+ def scope
+ scope = self.class.scope
+ scope = instance_exec &scope if scope.is_a? Proc
+ scope
+ end
end
diff --git a/lib/af83/decorator/link.rb b/lib/af83/decorator/link.rb
index 7d2896e6a..ee09f80dc 100644
--- a/lib/af83/decorator/link.rb
+++ b/lib/af83/decorator/link.rb
@@ -30,7 +30,8 @@ class AF83::Decorator::Link
@options[name] = block
elsif args.size == 0
out = @options[name]
- out = context.instance_exec(self, &out) if out.is_a?(Proc)
+ out = context.instance_exec(self, &out) if out.is_a?(Proc)
+ out = out.flatten.compact if name.to_s == "href" && out.is_a?(Array)
out
else
# we can use l.foo("bar") or l.foo = "bar"
@@ -129,7 +130,9 @@ class AF83::Decorator::Link
out[:method] = link_method
out[:class] = extra_class
out.delete(:link_class)
+ out.delete(:link_method)
out[:class] += " disabled" if disabled
+ out[:class].strip!
out[:disabled] = !!disabled
out
end
diff --git a/lib/stif/dashboard.rb b/lib/stif/dashboard.rb
index b6b6b8284..46c635091 100644
--- a/lib/stif/dashboard.rb
+++ b/lib/stif/dashboard.rb
@@ -4,12 +4,16 @@ module Stif
@workbench ||= current_organisation.workbenches.find_by(name: "Gestion de l'offre")
end
+ def workgroup
+ workbench.workgroup
+ end
+
def referentials
@referentials ||= self.workbench.all_referentials
end
def calendars
- @calendars ||= Calendar.where('organisation_id = ? OR shared = ?', current_organisation.id, true)
+ @calendars ||= Calendar.where('(organisation_id = ? OR shared = ?) AND workgroup_id = ?', current_organisation.id, true, workgroup.id)
end
end
end
diff --git a/lib/tasks/ci.rake b/lib/tasks/ci.rake
index 13d7b8d73..89f9aa9c8 100644
--- a/lib/tasks/ci.rake
+++ b/lib/tasks/ci.rake
@@ -31,19 +31,22 @@ namespace :ci do
sh "bundle exec bundle-audit check --update"
end
- task :spec => ["ci:assets","spec"]
-
task :assets do
sh "RAILS_ENV=test bundle exec rake assets:precompile"
end
- task :jest => "ci:assets" do
- sh "yarn --no-progress install" # Hack to force install jest after webpack
- sh "node_modules/.bin/jest" unless ["CHOUETTE_JEST_DISABLED"]
+ task :i18n_js_export do
+ sh "RAILS_ENV=test bundle exec rake i18n:js:export"
+ end
+
+ task :jest do
+ sh "node_modules/.bin/jest" unless ENV["CHOUETTE_JEST_DISABLED"]
end
desc "Deploy after CI"
task :deploy do
+ return if ENV["CHOUETTE_DEPLOY_DISABLED"]
+
if deploy_env
sh "cap #{deploy_env} deploy:migrations"
else
@@ -59,4 +62,4 @@ namespace :ci do
end
desc "Run continuous integration tasks (spec, ...)"
-task :ci => ["ci:setup", "ci:spec", "ci:jest", "cucumber", "ci:check_security", "ci:deploy", "ci:clean"]
+task :ci => ["ci:setup", "ci:assets", "ci:i18n_js_export", "spec", "ci:jest", "cucumber", "ci:check_security", "ci:deploy", "ci:clean"]
diff --git a/lib/tasks/compliance_check_sets.rb b/lib/tasks/compliance_check_sets.rb
new file mode 100644
index 000000000..c53c7f9ed
--- /dev/null
+++ b/lib/tasks/compliance_check_sets.rb
@@ -0,0 +1,11 @@
+namespace :compliance_check_sets do
+ desc "Notify parent check sets when children finish"
+ task notify_parent: :environment do
+ ParentNotifier.new(ComplianceCheckSet).notify_when_finished
+ end
+
+ desc "Mark old unfinished check sets as 'aborted'"
+ task abort_old: :environment do
+ ComplianceCheckSet.abort_old
+ end
+end
diff --git a/lib/tasks/imports.rake b/lib/tasks/imports.rake
index 6bc84acc8..b91ff7efb 100644
--- a/lib/tasks/imports.rake
+++ b/lib/tasks/imports.rake
@@ -1,6 +1,108 @@
+require 'csv'
+
namespace :import do
desc "Notify parent imports when children finish"
task notify_parent: :environment do
- ParentImportNotifier.notify_when_finished
+ ParentNotifier.new(Import).notify_when_finished
+ end
+
+ desc "Mark old unfinished Netex imports as 'aborted'"
+ task netex_abort_old: :environment do
+ NetexImport.abort_old
+ end
+
+ def importer_output_to_csv importer
+ filepath = "./#{importer.configuration_name}_#{Time.now.strftime "%y%m%d%H%M"}_out.csv"
+ cols = %w(line kind event message error)
+ if importer.reload.journal.size > 0
+ keys = importer.journal.first["row"].map(&:first)
+ CSV.open(filepath, "w") do |csv|
+ csv << cols + keys
+ importer.journal.each do |j|
+ csv << cols.map{|c| j[c]} + j["row"].map(&:last)
+ end
+ end
+ puts "Import Output written in #{filepath}"
+ end
+ end
+
+ desc "import the given file with the corresponding importer"
+ task :import, [:configuration_name, :filepath, :referential_id] => :environment do |t, args|
+ importer = SimpleImporter.create configuration_name: args[:configuration_name], filepath: args[:filepath]
+ if args[:referential_id].present?
+ referential = Referential.find args[:referential_id]
+ importer.configure do |config|
+ config.add_value :referential, referential
+ config.context = {referential: referential}
+ end
+ end
+ puts "\e[33m***\e[0m Start importing"
+ begin
+ importer.import(verbose: true)
+ rescue Interrupt
+ raise
+ ensure
+ puts "\n\e[33m***\e[0m Import done, status: " + (importer.status == "success" ? "\e[32m" : "\e[31m" ) + (importer.status || "") + "\e[0m"
+ importer_output_to_csv importer
+ end
+ end
+
+ desc "import the given file with the corresponding importer in the given StopAreaReferential"
+ task :import_in_stop_area_referential, [:referential_id, :configuration_name, :filepath] => :environment do |t, args|
+ referential = StopAreaReferential.find args[:referential_id]
+ importer = SimpleImporter.create configuration_name: args[:configuration_name], filepath: args[:filepath]
+ importer.configure do |config|
+ config.add_value :stop_area_referential, referential
+ config.context = {stop_area_referential: referential}
+ end
+ puts "\e[33m***\e[0m Start importing"
+ begin
+ importer.import(verbose: true)
+ rescue Interrupt
+ raise
+ ensure
+ puts "\n\e[33m***\e[0m Import done, status: " + (importer.status == "success" ? "\e[32m" : "\e[31m" ) + (importer.status || "") + "\e[0m"
+ importer_output_to_csv importer
+ end
+ end
+
+ desc "import the given routes files"
+ task :import_routes, [:referential_id, :configuration_name, :mapping_filepath, :filepath] => :environment do |t, args|
+ referential = Referential.find args[:referential_id]
+ referential.switch
+ stop_area_referential = referential.stop_area_referential
+ importer = SimpleImporter.create configuration_name: args[:configuration_name], filepath: args[:filepath]
+ importer.configure do |config|
+ config.add_value :stop_area_referential, referential
+ config.context = {stop_area_referential: stop_area_referential, mapping_filepath: args[:mapping_filepath]}
+ end
+ puts "\e[33m***\e[0m Start importing"
+ begin
+ importer.import(verbose: true)
+ rescue Interrupt
+ raise
+ ensure
+ puts "\n\e[33m***\e[0m Import done, status: " + (importer.status == "success" ? "\e[32m" : "\e[31m" ) + (importer.status || "") + "\e[0m"
+ importer_output_to_csv importer
+ end
+ end
+
+ desc "import the given file with the corresponding importer in the given LineReferential"
+ task :import_in_line_referential, [:referential_id, :configuration_name, :filepath] => :environment do |t, args|
+ referential = LineReferential.find args[:referential_id]
+ importer = SimpleImporter.create configuration_name: args[:configuration_name], filepath: args[:filepath]
+ importer.configure do |config|
+ config.add_value :line_referential, referential
+ config.context = {line_referential: referential}
+ end
+ puts "\e[33m***\e[0m Start importing"
+ begin
+ importer.import(verbose: true)
+ rescue Interrupt
+ raise
+ ensure
+ puts "\n\e[33m***\e[0m Import done, status: " + (importer.status == "success" ? "\e[32m" : "\e[31m" ) + (importer.status || "") + "\e[0m"
+ importer_output_to_csv importer
+ end
end
end
diff --git a/lib/tasks/install.rake b/lib/tasks/install.rake
index 1150825b2..7d8ecdce0 100644
--- a/lib/tasks/install.rake
+++ b/lib/tasks/install.rake
@@ -9,9 +9,11 @@ task :package do
sh "bundle package --all"
sh "bundle exec rake assets:clobber RAILS_ENV=production"
sh "bundle exec rake assets:precompile RAILS_ENV=production"
+ sh "bundle exec rake i18n:js:export RAILS_ENV=production"
sh "tar -rf tmp/package/stif-boiv-release-#{release_name}.tar vendor/cache"
sh "tar -rf tmp/package/stif-boiv-release-#{release_name}.tar public/assets"
sh "tar -rf tmp/package/stif-boiv-release-#{release_name}.tar public/packs"
+ sh "tar -rf tmp/package/stif-boiv-release-#{release_name}.tar public/javascripts"
%w{deploy-helper.sh README sidekiq-stif-boiv.service stif-boiv.conf stif-boiv-setup.sh template-stif-boiv.sql}.each do |f|
cp "install/#{f}", "tmp/package/#{f}"
@@ -37,9 +39,11 @@ task :pkg4docker do
# sh "RAILS_DB_ADAPTER=nulldb bundle exec rake assets:precompile RAILS_ENV=production"
sh "bundle exec rake assets:clobber RAILS_ENV=production"
sh "bundle exec rake assets:precompile RAILS_ENV=production"
+ sh "bundle exec rake i18n:js:export RAILS_ENV=production"
sh "tar -rf tmp/package/stif-boiv-release-#{release_name}.tar vendor/cache"
sh "tar -rf tmp/package/stif-boiv-release-#{release_name}.tar public/assets"
sh "tar -rf tmp/package/stif-boiv-release-#{release_name}.tar public/packs"
+ sh "tar -rf tmp/package/stif-boiv-release-#{release_name}.tar public/javascripts"
sh "gzip -c tmp/package/stif-boiv-release-#{release_name}.tar > tmp/stif-boiv-release.tar.gz"
diff --git a/package.json b/package.json
index e80f5231e..262d80b97 100644
--- a/package.json
+++ b/package.json
@@ -23,11 +23,12 @@
"redux-logger": "3.0.6",
"redux-promise": "0.5.3",
"redux-thunk": "2.2.0",
+ "uglify-js": "3.3.2",
"whatwg-fetch": "2.0.3"
},
"license": "MIT",
"engines": {
- "node": "~6.12.0"
+ "node": "^6.12.3"
},
"devDependencies": {
"es6-object-assign": "1.1.0",
@@ -41,7 +42,6 @@
"react-addons-test-utils": "15.6.2",
"react-test-renderer": "^16.2.0",
"sinon": "4.1.3",
- "uglify-js": "3.3.2",
"webpack-dev-server": "2.9.7"
},
"jest": {
@@ -49,6 +49,10 @@
"roots": [
"<rootDir>/spec/javascript"
],
+ "transform": {
+ "^.+\\.coffee$": "<rootDir>/spec/javascript/preprocessor.js",
+ "^.+\\.jsx?$": "babel-jest"
+ },
"testEnvironment": "jest-environment-jsdom-global",
"setupFiles": [
"<rootDir>/spec/javascript/spec_helper.js",
diff --git a/spec/controllers/api/v1/stop_area_controller_spec.rb b/spec/controllers/api/v1/stop_area_controller_spec.rb
index eb0c87661..1ad71a95a 100644
--- a/spec/controllers/api/v1/stop_area_controller_spec.rb
+++ b/spec/controllers/api/v1/stop_area_controller_spec.rb
@@ -18,16 +18,15 @@ describe Api::V1::StopAreasController, :type => :controller do
end
end
describe "GET #index, :q => { :name_cont => 'aa'}" do
- let!(:sa1) { create(:stop_area, :name => "aaa") }
- let!(:sa2) { create(:stop_area, :name => "aab") }
- let!(:sa3) { create(:stop_area, :name => "abb") }
+ let!(:sa1) { create(:stop_area, :name => "aaa", stop_area_referential: referential.stop_area_referential) }
+ let!(:sa2) { create(:stop_area, :name => "aab", stop_area_referential: referential.stop_area_referential) }
+ let!(:sa3) { create(:stop_area, :name => "abb", stop_area_referential: referential.stop_area_referential) }
before :each do
config_formatted_request_with_authorization( "application/json")
- get :index, :q => { :name_cont => "aa"}
+ get :index, :q => { :name_cont => "aa"}
end
it "should assign expected stop_areas" do
expect(assigns[:stop_areas].map(&:name).sort).to eq([ sa1.name, sa2.name])
end
end
end
-
diff --git a/spec/controllers/autocomplete_stop_areas_controller_spec.rb b/spec/controllers/autocomplete_stop_areas_controller_spec.rb
index 2af471361..e0d1cd714 100644
--- a/spec/controllers/autocomplete_stop_areas_controller_spec.rb
+++ b/spec/controllers/autocomplete_stop_areas_controller_spec.rb
@@ -4,9 +4,11 @@ RSpec.describe AutocompleteStopAreasController, type: :controller do
login_user
let(:referential) { Referential.first }
- let!(:stop_area) { create :stop_area, name: 'écolà militaire' }
- let!(:zdep_stop_area) { create :stop_area, area_type: "zdep" }
- let!(:not_zdep_stop_area) { create :stop_area, area_type: "lda" }
+ let(:other_referential) { create :referential }
+ let!(:stop_area) { create :stop_area, name: 'écolà militaire', referential: referential }
+ let!(:other_referential_stop_area) { create :stop_area, name: 'écolà militaire', referential: other_referential }
+ let!(:zdep_stop_area) { create :stop_area, area_type: "zdep", referential: referential }
+ let!(:not_zdep_stop_area) { create :stop_area, area_type: "lda", referential: referential }
describe 'GET #index' do
it 'should be successful' do
@@ -14,6 +16,12 @@ RSpec.describe AutocompleteStopAreasController, type: :controller do
expect(response).to be_success
end
+ it "should filter stop areas based on referential" do
+ get :index, referential_id: referential.id
+ expect(assigns(:stop_areas)).to include(stop_area)
+ expect(assigns(:stop_areas)).to_not include(other_referential_stop_area)
+ end
+
context 'search by name' do
it 'should be successful' do
get :index, referential_id: referential.id, q: 'écolà', :format => :json
diff --git a/spec/controllers/referentials_controller_spec.rb b/spec/controllers/referentials_controller_spec.rb
index 521856258..ff450c905 100644
--- a/spec/controllers/referentials_controller_spec.rb
+++ b/spec/controllers/referentials_controller_spec.rb
@@ -7,7 +7,7 @@ describe ReferentialsController, :type => :controller do
let(:other_referential) { create :referential, organisation: organisation }
describe "GET new" do
- let(:request){ get :new }
+ let(:request){ get :new, workbench_id: referential.workbench_id }
before{ request }
it 'returns http success' do
@@ -16,7 +16,7 @@ describe ReferentialsController, :type => :controller do
context "when cloning another referential" do
let(:source){ referential }
- let(:request){ get :new, from: source.id }
+ let(:request){ get :new, workbench_id: referential.workbench_id, from: source.id }
it 'returns http success' do
expect(response).to have_http_status(200)
@@ -51,8 +51,7 @@ describe ReferentialsController, :type => :controller do
end
context "user's organisation doesn't match referential's organisation" do
- pending "hotfix opens all unknow actions need to close the uneeded later" do
- #it 'raises a ActiveRecord::RecordNotFound' do
+ it 'raises a ActiveRecord::RecordNotFound' do
expect { put :archive, id: other_referential.id }.to raise_error(ActiveRecord::RecordNotFound)
end
end
@@ -62,7 +61,7 @@ describe ReferentialsController, :type => :controller do
it 'gets compliance control set for current organisation' do
compliance_control_set = create(:compliance_control_set, organisation: @user.organisation)
create(:compliance_control_set)
- get :select_compliance_control_set, referential_id: referential.id
+ get :select_compliance_control_set, id: referential.id
expect(assigns[:compliance_control_sets]).to eq([compliance_control_set])
end
end
@@ -79,16 +78,51 @@ describe ReferentialsController, :type => :controller do
end
end
+ describe "GET #new" do
+ context "when duplicating" do
+ let(:workbench){ create :workbench}
+ let(:request){
+ get :new,
+ workbench_id: workbench.id,
+ from: referential.id
+ }
+
+ it "duplicates the given referential" do
+ request
+ new_referential = assigns(:referential)
+ expect(new_referential.line_referential).to eq referential.line_referential
+ expect(new_referential.stop_area_referential).to eq referential.stop_area_referential
+ expect(new_referential.objectid_format).to eq referential.objectid_format
+ expect(new_referential.prefix).to eq referential.prefix
+ expect(new_referential.slug).to eq "#{referential.slug}_clone"
+ expect(new_referential.workbench).to eq workbench
+ end
+ end
+ end
+
describe "POST #create" do
+ let(:workbench){ create :workbench}
context "when duplicating" do
- it "displays a flash message", pending: 'requires more params to create a valid Referential' do
+ let(:request){
post :create,
- from: referential.id,
- current_workbench_id: referential.workbench_id,
- referential: {
- name: 'Duplicated'
- }
+ workbench_id: workbench.id,
+ referential: {
+ name: 'Duplicated',
+ created_from_id: referential.id,
+ stop_area_referential: referential.stop_area_referential,
+ line_referential: referential.line_referential,
+ objectid_format: referential.objectid_format,
+ workbench_id: referential.workbench_id
+ }
+ }
+
+ it "creates the new referential" do
+ expect{request}.to change{Referential.count}.by 1
+ expect(Referential.last.name).to eq "Duplicated"
+ end
+ it "displays a flash message" do
+ request
expect(controller).to set_flash[:notice].to(
I18n.t('notice.referentials.duplicate')
)
diff --git a/spec/controllers/statuses_controller_spec.rb b/spec/controllers/statuses_controller_spec.rb
new file mode 100644
index 000000000..8a6db8e28
--- /dev/null
+++ b/spec/controllers/statuses_controller_spec.rb
@@ -0,0 +1,50 @@
+RSpec.describe StatusesController, :type => :controller do
+
+ describe "GET index" do
+ login_user
+ render_views
+
+
+ let(:request){ get :index}
+ let(:parsed_response){ JSON.parse response.body }
+ it "should be ok" do
+ request
+ expect(response).to have_http_status 200
+ expect(parsed_response["status"]).to eq "ok"
+ end
+ context "without blocked object" do
+ before do
+ create :referential
+ create :import
+ create :compliance_check_set
+ request
+ end
+
+ it "should be ok" do
+ expect(response).to have_http_status 200
+ expect(parsed_response["status"]).to eq "ok"
+ expect(parsed_response["referentials_blocked"]).to eq 0
+ expect(parsed_response["imports_blocked"]).to eq 0
+ expect(parsed_response["imports_blocked"]).to eq 0
+ end
+ end
+
+ context "with a blocked object" do
+ before do
+ create :referential, created_at: 5.hours.ago, ready: false
+ create :import
+ create :compliance_check_set
+ request
+ end
+
+ it "should be ko" do
+ expect(Referential.blocked.count).to eq 1
+ expect(response).to have_http_status 200
+ expect(parsed_response["status"]).to eq "ko"
+ expect(parsed_response["referentials_blocked"]).to eq 1
+ expect(parsed_response["imports_blocked"]).to eq 0
+ expect(parsed_response["imports_blocked"]).to eq 0
+ end
+ end
+ end
+end
diff --git a/spec/controllers/vehicle_journeys_controller_spec.rb b/spec/controllers/vehicle_journeys_controller_spec.rb
index 416450c21..300684532 100644
--- a/spec/controllers/vehicle_journeys_controller_spec.rb
+++ b/spec/controllers/vehicle_journeys_controller_spec.rb
@@ -26,4 +26,28 @@ RSpec.describe VehicleJourneysController, :type => :controller do
end
end
+ describe "GET index" do
+ login_user
+ render_views
+
+ context "in JSON" do
+ let(:vehicle_journey){ create :vehicle_journey }
+ let(:route){ vehicle_journey.route }
+ let(:line){ route.line }
+ let!(:request){ get :index, referential_id: referential.id, line_id: line.id, route_id: route.id, format: :json}
+ let(:parsed_response){ JSON.parse response.body }
+ it "should have all the attributes" do
+ expect(response).to have_http_status 200
+ vehicle_journey = parsed_response["vehicle_journeys"].first
+ vehicle_journey_at_stops_matrix = vehicle_journey["vehicle_journey_at_stops"]
+ vehicle_journey_at_stops_matrix.each do |received_vjas|
+ expect(received_vjas).to have_key("id")
+ vjas = Chouette::VehicleJourneyAtStop.find received_vjas["id"]
+ [:connecting_service_id, :boarding_alighting_possibility].each do |att|
+ expect(received_vjas[att]).to eq vjas.send(att)
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/decorators/referential_decorator_spec.rb b/spec/decorators/referential_decorator_spec.rb
index efc438132..1224aaf75 100644
--- a/spec/decorators/referential_decorator_spec.rb
+++ b/spec/decorators/referential_decorator_spec.rb
@@ -1,7 +1,8 @@
RSpec.describe ReferentialDecorator, type: [:helper, :decorator] do
include Support::DecoratorHelpers
- let( :object ){ build_stubbed :referential }
+ let( :workbench ){ build_stubbed :workbench }
+ let( :object ){ build_stubbed :referential, workbench: workbench }
let( :referential ){ object }
let( :user ){ build_stubbed :user }
@@ -35,7 +36,7 @@ RSpec.describe ReferentialDecorator, type: [:helper, :decorator] do
expect_action_link_hrefs.to eq([
[object],
referential_time_tables_path(object),
- new_referential_path(from: object)
+ new_workbench_referential_path(referential.workbench, from: object.id)
])
end
end
@@ -50,8 +51,8 @@ RSpec.describe ReferentialDecorator, type: [:helper, :decorator] do
[object],
[:edit, object],
referential_time_tables_path(object),
- new_referential_path(from: object),
- referential_select_compliance_control_set_path(object),
+ new_workbench_referential_path(referential.workbench, from: object.id),
+ select_compliance_control_set_referential_path(object),
archive_referential_path(object),
referential_path(object)
])
@@ -65,8 +66,8 @@ RSpec.describe ReferentialDecorator, type: [:helper, :decorator] do
expect_action_link_hrefs(action).to eq([
[:edit, object],
referential_time_tables_path(object),
- new_referential_path(from: object),
- referential_select_compliance_control_set_path(object),
+ new_workbench_referential_path(referential.workbench, from: object.id),
+ select_compliance_control_set_referential_path(object),
archive_referential_path(object),
"#",
referential_path(object)
@@ -91,7 +92,7 @@ RSpec.describe ReferentialDecorator, type: [:helper, :decorator] do
expect_action_link_hrefs.to eq([
[object],
referential_time_tables_path(object),
- new_referential_path(from: object)
+ new_workbench_referential_path(referential.workbench, from: object.id)
])
end
end
diff --git a/spec/factories/calendars.rb b/spec/factories/calendars.rb
index 5f3188bee..d9fd242d1 100644
--- a/spec/factories/calendars.rb
+++ b/spec/factories/calendars.rb
@@ -6,6 +6,7 @@ FactoryGirl.define do
sequence(:dates) { |n| [ Date.yesterday - n, Date.yesterday - 2*n ] }
shared false
organisation
+ workgroup
end
sequence :date_range do |n|
diff --git a/spec/factories/chouette_routes.rb b/spec/factories/chouette_routes.rb
index 7443d08bc..92a50b924 100644
--- a/spec/factories/chouette_routes.rb
+++ b/spec/factories/chouette_routes.rb
@@ -19,6 +19,7 @@ FactoryGirl.define do
after(:create) do |route, evaluator|
create_list(:stop_point, evaluator.stop_points_count, route: route)
route.reload
+ route.update_checksum!
end
factory :route_with_journey_patterns do
diff --git a/spec/factories/chouette_stop_areas.rb b/spec/factories/chouette_stop_areas.rb
index 9b4764781..dab135ca6 100644
--- a/spec/factories/chouette_stop_areas.rb
+++ b/spec/factories/chouette_stop_areas.rb
@@ -10,6 +10,14 @@ FactoryGirl.define do
association :stop_area_referential
+ transient do
+ referential nil
+ end
+
+ before(:create) do |stop_area, evaluator|
+ stop_area.stop_area_referential = evaluator.referential.stop_area_referential if evaluator.referential
+ end
+
trait :deactivated do
deleted_at { 1.hour.ago }
end
diff --git a/spec/factories/compliance_controls/vehicle_journey_control_factories.rb b/spec/factories/compliance_controls/vehicle_journey_control_factories.rb
index e8f68cbdf..86a335aba 100644
--- a/spec/factories/compliance_controls/vehicle_journey_control_factories.rb
+++ b/spec/factories/compliance_controls/vehicle_journey_control_factories.rb
@@ -1,10 +1,12 @@
FactoryGirl.define do
factory :vehicle_journey_control_wating_time, class: 'VehicleJourneyControl::WaitingTime' do
+ maximum 10
association :compliance_control_set
end
factory :vehicle_journey_control_delta, class: 'VehicleJourneyControl::Delta' do
+ maximum 10
association :compliance_control_set
end
diff --git a/spec/features/access_points_spec.rb b/spec/features/access_points_spec.rb
index c16039d67..890906de7 100644
--- a/spec/features/access_points_spec.rb
+++ b/spec/features/access_points_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
describe "Access points", :type => :feature do
login_user
- let!(:stop_area) { create(:stop_area) }
+ let!(:stop_area) { create(:stop_area, stop_area_referential: referential.stop_area_referential) }
let!(:access_points) { Array.new(2) { create(:access_point, :stop_area => stop_area) } }
subject { access_points.first }
diff --git a/spec/features/calendars_permissions_spec.rb b/spec/features/calendars_permissions_spec.rb
index 9b47ab2bb..4857592d5 100644
--- a/spec/features/calendars_permissions_spec.rb
+++ b/spec/features/calendars_permissions_spec.rb
@@ -2,6 +2,7 @@ RSpec.describe 'Calendars', type: :feature do
login_user
let(:calendar) { create :calendar, organisation_id: 1 }
+ let(:workgroup) { calendar.workgroup }
describe 'permissions' do
before do
@@ -13,7 +14,7 @@ RSpec.describe 'Calendars', type: :feature do
end
context 'on show view' do
- let( :path ){ calendar_path(calendar) }
+ let( :path ){ workgroup_calendar_path(workgroup, calendar) }
context 'if present → ' do
let( :permission ){ true }
@@ -33,7 +34,7 @@ RSpec.describe 'Calendars', type: :feature do
end
context 'on edit view' do
- let( :path ){ edit_calendar_path(calendar) }
+ let( :path ){ edit_workgroup_calendar_path(workgroup, calendar) }
context 'if present → ' do
let( :permission ){ true }
@@ -51,7 +52,7 @@ RSpec.describe 'Calendars', type: :feature do
end
context 'on index view' do
- let( :path ){ calendars_path }
+ let( :path ){ workgroup_calendars_path(workgroup) }
context 'if present → ' do
let( :permission ){ true }
diff --git a/spec/features/referential_stop_areas_spec.rb b/spec/features/referential_stop_areas_spec.rb
index 0dc7951a7..5e70857e7 100644
--- a/spec/features/referential_stop_areas_spec.rb
+++ b/spec/features/referential_stop_areas_spec.rb
@@ -5,7 +5,7 @@ describe 'ReferentialStopAreas', type: :feature do
login_user
let(:referential) { Referential.first }
- let(:stop_area_referential) { create :stop_area_referential }
+ let(:stop_area_referential) { referential.stop_area_referential }
let!(:stop_areas) { Array.new(2) { create :stop_area, stop_area_referential: stop_area_referential } }
describe 'index' do
diff --git a/spec/features/referentials_spec.rb b/spec/features/referentials_spec.rb
index 9af0ed32e..d4890fda4 100644
--- a/spec/features/referentials_spec.rb
+++ b/spec/features/referentials_spec.rb
@@ -55,7 +55,7 @@ describe "Referentials", :type => :feature do
context 'user has the permission to create referentials' do
it 'shows the clone link for referetnial' do
- expect(page).to have_link(I18n.t('actions.clone'), href: new_referential_path(from: referential.id))
+ expect(page).to have_link(I18n.t('actions.clone'), href: new_workbench_referential_path(referential.workbench, from: referential.id))
end
end
@@ -63,7 +63,7 @@ describe "Referentials", :type => :feature do
it 'does not show the clone link for referetnial' do
@user.update_attribute(:permissions, [])
visit referential_path(referential)
- expect(page).not_to have_link(I18n.t('actions.clone'), href: new_referential_path(from: referential.id))
+ expect(page).not_to have_link(I18n.t('actions.clone'), href: new_workbench_referential_path(referential.workbench, from: referential.id))
end
end
@@ -108,8 +108,9 @@ describe "Referentials", :type => :feature do
end
describe "create" do
+ let(:workbench){ @user.organisation.workbenches.last }
it "should" do
- visit new_referential_path
+ visit new_workbench_referential_path(workbench)
fill_in "Nom", :with => "Test"
click_button "Valider"
@@ -132,7 +133,7 @@ describe "Referentials", :type => :feature do
context "when user is from the same organisation" do
xit "should" do
- visit new_referential_path(from: referential.id, current_workbench_id: @user.organisation.workbenches.first.id)
+ visit new_workbench_referential_path(referential.workbench, from: referential.id, current_workbench_id: @user.organisation.workbenches.first.id)
select "2018", :from => "referential_metadatas_attributes_0_periods_attributes_0_begin_1i"
@@ -187,7 +188,8 @@ describe "Referentials", :type => :feature do
end
describe "destroy" do
- let(:referential) { create(:referential, :organisation => @user.organisation) }
+ let(:workbench){ @user.organisation.workbenches.last }
+ let(:referential) { create(:referential, :organisation => @user.organisation, workbench: workbench) }
it "should remove referential" do
visit referential_path(referential)
diff --git a/spec/features/workbenches/workbenches_permissions_spec.rb b/spec/features/workbenches/workbenches_permissions_spec.rb
index d58293538..1c073a4c5 100644
--- a/spec/features/workbenches/workbenches_permissions_spec.rb
+++ b/spec/features/workbenches/workbenches_permissions_spec.rb
@@ -22,7 +22,7 @@ describe 'Workbenches', type: :feature do
let( :permission ){ true }
it 'shows the corresponding button' do
- expected_href = new_referential_path(workbench_id: workbench)
+ expected_href = new_workbench_referential_path(workbench)
expect( page ).to have_link('Créer', href: expected_href)
end
end
diff --git a/spec/features/workbenches/workbenches_show_spec.rb b/spec/features/workbenches/workbenches_show_spec.rb
index 7be813b94..405fdce82 100644
--- a/spec/features/workbenches/workbenches_show_spec.rb
+++ b/spec/features/workbenches/workbenches_show_spec.rb
@@ -232,7 +232,7 @@ RSpec.describe 'Workbenches', type: :feature do
context 'user has the permission to create referentials' do
it 'shows the link for a new referetnial' do
- expect(page).to have_link(I18n.t('actions.add'), href: new_referential_path(workbench_id: workbench.id))
+ expect(page).to have_link(I18n.t('actions.add'), href: new_workbench_referential_path(workbench))
end
end
@@ -240,7 +240,7 @@ RSpec.describe 'Workbenches', type: :feature do
it 'does not show the clone link for referential' do
@user.update_attribute(:permissions, [])
visit referential_path(referential)
- expect(page).not_to have_link(I18n.t('actions.add'), href: new_referential_path(workbench_id: workbench.id))
+ expect(page).not_to have_link(I18n.t('actions.add'), href: new_workbench_referential_path(workbench))
end
end
end
diff --git a/spec/fixtures/simple_importer/lines_mapping.csv b/spec/fixtures/simple_importer/lines_mapping.csv
new file mode 100644
index 000000000..b26d0ab59
--- /dev/null
+++ b/spec/fixtures/simple_importer/lines_mapping.csv
@@ -0,0 +1,11 @@
+id;timetable_route_id;route_name;stop_sequence;stop_distance;station_code;station_name;border;Ligne Chouette;Transporteur
+3354;1136;Paris centre - Bercy > Lille > Londres;1;0;XPB;Paris City Center - Bercy;f;Paris <> Londres - OUIBUS;OUIBUS
+3355;1136;Paris centre - Bercy > Lille > Londres;2;232;XDB;Lille;f;Paris <> Londres - OUIBUS;OUIBUS
+3749;1136;Paris centre - Bercy > Lille > Londres;3;350;COF;Coquelles - France;t;Paris <> Londres - OUIBUS;OUIBUS
+4772;1136;Paris centre - Bercy > Lille > Londres;4;350;COU;Coquelles - UK;t;Paris <> Londres - OUIBUS;OUIBUS
+3357;1136;Paris centre - Bercy > Lille > Londres;5;527;ZEP;London;f;Paris <> Londres - OUIBUS;OUIBUS
+3358;1137;Londres > Lille > Paris centre - Bercy;1;0;ZEP;London;f;Paris <> Londres - OUIBUS;OUIBUS
+3559;1137;Londres > Lille > Paris centre - Bercy;2;177;COU;Coquelles - UK;t;Paris <> Londres - OUIBUS;OUIBUS
+3743;1137;Londres > Lille > Paris centre - Bercy;3;177;COF;Coquelles - France;t;Paris <> Londres - OUIBUS;OUIBUS
+3360;1137;Londres > Lille > Paris centre - Bercy;4;295;XDB;Lille;f;Paris <> Londres - OUIBUS;OUIBUS
+3361;1137;Londres > Lille > Paris centre - Bercy;5;527;XPB;Paris City Center - Bercy;f;Paris <> Londres - OUIBUS;OUIBUS
diff --git a/spec/fixtures/simple_importer/stop_area.csv b/spec/fixtures/simple_importer/stop_area.csv
new file mode 100644
index 000000000..9361d022b
--- /dev/null
+++ b/spec/fixtures/simple_importer/stop_area.csv
@@ -0,0 +1,2 @@
+name;lat;long;type;street_name
+Nom du Stop;45.00;12;ZDEP;99 rue des Poissonieres
diff --git a/spec/fixtures/simple_importer/stop_area_full.csv b/spec/fixtures/simple_importer/stop_area_full.csv
new file mode 100644
index 000000000..250caab30
--- /dev/null
+++ b/spec/fixtures/simple_importer/stop_area_full.csv
@@ -0,0 +1,3 @@
+"id";"station_code";"uic_code";"country_code";"province";"district";"county";"station_name";"inactive";"change_timestamp";"longitude";"latitude";"parent_station_code";"additional_info";"external_reference";"timezone";"address";"postal_code";"city"
+5669;"PAR";"PAR";"FRA";"";"";"";"Paris - All stations";f;"2017-07-17 11:56:53.138";2.35222190000002;48.856614;"";"";"{""Région"":""Ile-de-France""}";"Europe/Paris";"";"";""
+5748;"XED";"XED";"FRA";"";"";"";"Paris MLV";t;"2017-05-29 11:24:34.575";2.783409;48.870569;"PAR";"";"{""Région"":""Ile-de-France""}";"Europe/Paris";"";"";""
diff --git a/spec/fixtures/simple_importer/stop_area_full_reverse.csv b/spec/fixtures/simple_importer/stop_area_full_reverse.csv
new file mode 100644
index 000000000..9ea15f6cc
--- /dev/null
+++ b/spec/fixtures/simple_importer/stop_area_full_reverse.csv
@@ -0,0 +1,3 @@
+"id";"station_code";"uic_code";"country_code";"province";"district";"county";"station_name";"inactive";"change_timestamp";"longitude";"latitude";"parent_station_code";"additional_info";"external_reference";"timezone";"address";"postal_code";"city"
+5748;"XED";"XED";"FRA";"";"";"";"Paris MLV";t;"2017-05-29 11:24:34.575";2.783409;48.870569;"PAR";"";"{""Région"":""Ile-de-France""}";"Europe/Paris";"";"";""
+5669;"PAR";"PAR";"FRA";"";"";"";"Paris - All stations";f;"2017-07-17 11:56:53.138";2.35222190000002;48.856614;"";"";"{""Région"":""Ile-de-France""}";"Europe/Paris";"";"";""
diff --git a/spec/fixtures/simple_importer/stop_area_incomplete.csv b/spec/fixtures/simple_importer/stop_area_incomplete.csv
new file mode 100644
index 000000000..9b11aa02c
--- /dev/null
+++ b/spec/fixtures/simple_importer/stop_area_incomplete.csv
@@ -0,0 +1,3 @@
+name;lat;long;type;street_name
+Foo;45.00;12;ZDEP
+;45.00;12;ZDEP
diff --git a/spec/fixtures/simple_importer/stop_area_missing_street_name.csv b/spec/fixtures/simple_importer/stop_area_missing_street_name.csv
new file mode 100644
index 000000000..aa845c3f5
--- /dev/null
+++ b/spec/fixtures/simple_importer/stop_area_missing_street_name.csv
@@ -0,0 +1,2 @@
+name;lat;long;type;foo
+Nom du Stop;45.00;12;ZDEP;blabla
diff --git a/spec/fixtures/simple_importer/stop_points_full.csv b/spec/fixtures/simple_importer/stop_points_full.csv
new file mode 100644
index 000000000..9c5b3c1b7
--- /dev/null
+++ b/spec/fixtures/simple_importer/stop_points_full.csv
@@ -0,0 +1,11 @@
+"id";"timetable_route_id";"route_name";"stop_sequence";"stop_distance";"station_code";"station_name";"border"
+3354;1136;"Paris centre - Bercy > Lille > Londres";1;0;"XPB";"Paris City Center - Bercy";f
+3355;1136;"Paris centre - Bercy > Lille > Londres";2;232;"XDB";"Lille";f
+3749;1136;"Paris centre - Bercy > Lille > Londres";3;350;"COF";"Coquelles - France";t
+4772;1136;"Paris centre - Bercy > Lille > Londres";4;350;"COU";"Coquelles - UK";t
+3357;1136;"Paris centre - Bercy > Lille > Londres";5;527;"ZEP";"London";f
+3358;1137;"Londres > Lille > Paris centre - Bercy";1;0;"ZEP";"London";f
+3559;1137;"Londres > Lille > Paris centre - Bercy";2;177;"COU";"Coquelles - UK";t
+3743;1137;"Londres > Lille > Paris centre - Bercy";3;177;"COF";"Coquelles - France";t
+3360;1137;"Londres > Lille > Paris centre - Bercy";4;295;"XDB";"Lille";f
+3361;1137;"Londres > Lille > Paris centre - Bercy";5;527;"XPB";"Paris City Center - Bercy";f
diff --git a/spec/helpers/table_builder_helper_spec.rb b/spec/helpers/table_builder_helper_spec.rb
index 5bddbb16f..478875118 100644
--- a/spec/helpers/table_builder_helper_spec.rb
+++ b/spec/helpers/table_builder_helper_spec.rb
@@ -15,8 +15,9 @@ describe TableBuilderHelper, type: :helper do
describe "#table_builder_2" do
it "builds a table" do
- referential = build_stubbed(:workbench_referential)
+ referential = create(:workbench_referential)
workbench = referential.workbench
+ referential.organisation.workbenches << workbench
user_context = UserContext.new(
build_stubbed(
@@ -30,7 +31,8 @@ describe TableBuilderHelper, type: :helper do
),
referential: referential
)
- allow(helper).to receive(:current_user).and_return(user_context)
+ allow(helper).to receive(:pundit_user).and_return(user_context)
+ allow(helper).to receive(:current_user).and_return(user_context.user)
referentials = [referential]
@@ -90,7 +92,7 @@ describe TableBuilderHelper, type: :helper do
</ul>
<ul class="other">
<li class=""><a href="/referentials/#{referential.id}/time_tables">Calendriers</a></li>
- <li class=""><a href="/referentials/new?from=#{referential.id}">Dupliquer</a></li>
+ <li class=""><a href="/workbenches/#{workbench.id}/referentials/new?from=#{referential.id}">Dupliquer</a></li>
<li class=""><a href="/referentials/#{referential.id}/select_compliance_control_set">Valider</a></li>
<li class=""><a rel="nofollow" data-method="put" href="/referentials/#{referential.id}/archive">Conserver</a></li>
</ul>
@@ -193,7 +195,8 @@ describe TableBuilderHelper, type: :helper do
),
referential: referential
)
- allow(helper).to receive(:current_user).and_return(user_context)
+ allow(helper).to receive(:pundit_user).and_return(user_context)
+ allow(helper).to receive(:current_user).and_return(user_context.user)
allow(helper).to receive(:current_referential)
.and_return(referential)
@@ -307,7 +310,8 @@ describe TableBuilderHelper, type: :helper do
),
referential: referential
)
- allow(helper).to receive(:current_user).and_return(user_context)
+ allow(helper).to receive(:pundit_user).and_return(user_context)
+ allow(helper).to receive(:current_user).and_return(user_context.user)
allow(helper).to receive(:current_referential)
.and_return(referential)
@@ -398,8 +402,8 @@ describe TableBuilderHelper, type: :helper do
end
context "on a single row" do
- let(:referential){ build_stubbed :referential }
- let(:other_referential){ build_stubbed :referential }
+ let(:referential){ build_stubbed :workbench_referential }
+ let(:other_referential){ build_stubbed :workbench_referential }
let(:user_context){
UserContext.new(
build_stubbed(
@@ -432,7 +436,9 @@ describe TableBuilderHelper, type: :helper do
let(:items){ [item, other_item] }
before(:each){
- allow(helper).to receive(:current_user).and_return(user_context)
+ allow(helper).to receive(:pundit_user).and_return(user_context)
+ allow(helper).to receive(:current_user).and_return(user_context.user)
+ allow(helper).to receive(:mutual_workbench).and_return(referential.workbench)
}
context "with all rows non-selectable" do
diff --git a/spec/javascript/preprocessor.js b/spec/javascript/preprocessor.js
new file mode 100644
index 000000000..a2de8e4be
--- /dev/null
+++ b/spec/javascript/preprocessor.js
@@ -0,0 +1,15 @@
+'use strict';
+
+var coffee = require('coffeescript');
+
+module.exports = {
+ process: function(src, filename) {
+ if (coffee.helpers.isCoffee(filename)) {
+ return coffee.compile(src, {
+ 'bare': false,
+ 'inlineMap': true
+ })
+ }
+ return src;
+ }
+};
diff --git a/spec/javascript/time_table/actions_spec.js b/spec/javascript/time_table/actions_spec.js
index 9c1a6b6f1..003b7f6b5 100644
--- a/spec/javascript/time_table/actions_spec.js
+++ b/spec/javascript/time_table/actions_spec.js
@@ -61,7 +61,6 @@ describe('actions', () => {
expect(actions.unselect2Tags(selectedItem)).toEqual(expectedAction)
})
-
it('should create an action to go to previous page', () => {
let pagination = {
currentPage: '2017-01-01',
diff --git a/spec/javascript/vehicle_journeys/components/VehicleJourneys_spec.js b/spec/javascript/vehicle_journeys/components/VehicleJourneys_spec.js
index 87151c64b..2a84cb9ca 100644
--- a/spec/javascript/vehicle_journeys/components/VehicleJourneys_spec.js
+++ b/spec/javascript/vehicle_journeys/components/VehicleJourneys_spec.js
@@ -1,6 +1,13 @@
import React, { Component } from 'react'
import VehicleJourneys from '../../../../app/javascript/vehicle_journeys/components/VehicleJourneys'
import renderer from 'react-test-renderer'
+import fs from 'fs'
+
+import I18n from '../../../../public/javascripts/i18n'
+import decorateI18n from '../../../../app/assets/javascripts/i18n/extended.coffee'
+window.I18n = decorateI18n(I18n)
+I18n.locale = "fr"
+eval(fs.readFileSync('./public/javascripts/translations.js')+'')
describe('stopPointHeader', () => {
set('features', () => {
diff --git a/spec/javascript/vehicle_journeys/components/__snapshots__/VehicleJourneys_spec.js.snap b/spec/javascript/vehicle_journeys/components/__snapshots__/VehicleJourneys_spec.js.snap
index 703f727d7..818845ec8 100644
--- a/spec/javascript/vehicle_journeys/components/__snapshots__/VehicleJourneys_spec.js.snap
+++ b/spec/javascript/vehicle_journeys/components/__snapshots__/VehicleJourneys_spec.js.snap
@@ -19,20 +19,23 @@ exports[`stopPointHeader should display the city name 1`] = `
<div
className="strong mb-xs"
>
- ID course
+ ID Course
</div>
<div>
- Nom course
+ Nom Course
</div>
<div>
- ID mission
+ ID Mission
</div>
<div>
- Transporteur
+ transporteur
</div>
<div>
- Calendriers
+ calendrier
</div>
+ <div
+ className="detailed-timetables hidden"
+ />
</div>
<div
className="td"
@@ -109,20 +112,23 @@ exports[`stopPointHeader with the "long_distance_routes" feature should display
<div
className="strong mb-xs"
>
- ID course
+ ID Course
</div>
<div>
- Nom course
+ Nom Course
</div>
<div>
- ID mission
+ ID Mission
</div>
<div>
- Transporteur
+ transporteur
</div>
<div>
- Calendriers
+ calendrier
</div>
+ <div
+ className="detailed-timetables hidden"
+ />
</div>
<div
className="td"
diff --git a/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js b/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js
index 0d7612a80..389c60add 100644
--- a/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js
+++ b/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js
@@ -152,7 +152,7 @@ describe('vehicleJourneys reducer', () => {
},
departure_time : {
hour: 23,
- minute: 2
+ minute: 12
},
departure_day_offset: -1,
arrival_day_offset: -1,
@@ -178,11 +178,11 @@ describe('vehicleJourneys reducer', () => {
delta : 0,
arrival_time : {
hour: 0,
- minute: 32
+ minute: 42
},
departure_time : {
hour: 0,
- minute: 32
+ minute: 42
},
stop_point_objectid: 'test-4',
stop_area_cityname: 'city',
@@ -219,7 +219,7 @@ describe('vehicleJourneys reducer', () => {
type: 'ADD_VEHICLEJOURNEY',
data: fakeData,
selectedJourneyPattern: fakeSelectedJourneyPattern,
- stopPointsList: [{object_id: 'test-1', city_name: 'city', stop_area_id: 1, id: 1, time_zone_offset: 0}, {object_id: 'test-2', city_name: 'city', stop_area_id: 2, id: 2, time_zone_offset: -3600}, {object_id: 'test-3', city_name: 'city', stop_area_id: 3, id: 3, time_zone_offset: 0}, {object_id: 'test-4', city_name: 'city', stop_area_id: 4, id: 4, time_zone_offset: 0}],
+ stopPointsList: [{object_id: 'test-1', city_name: 'city', stop_area_id: 1, id: 1, time_zone_offset: 0, waiting_time: null}, {object_id: 'test-2', city_name: 'city', stop_area_id: 2, id: 2, time_zone_offset: -3600, waiting_time: 10}, {object_id: 'test-3', city_name: 'city', stop_area_id: 3, id: 3, time_zone_offset: 0, waiting_time: 20}, {object_id: 'test-4', city_name: 'city', stop_area_id: 4, id: 4, time_zone_offset: 0}],
selectedCompany: fakeSelectedCompany
})
).toEqual([{
diff --git a/spec/mailers/calendar_mailer_spec.rb b/spec/mailers/calendar_mailer_spec.rb
index 9a2076f64..00d73a58b 100644
--- a/spec/mailers/calendar_mailer_spec.rb
+++ b/spec/mailers/calendar_mailer_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe CalendarMailer, type: :mailer do
end
it 'should have correct body' do
- key = I18n.t("mailers.calendar_mailer.#{type}.body", cal_name: calendar.name, cal_index_url: calendars_url)
+ key = I18n.t("mailers.calendar_mailer.#{type}.body", cal_name: calendar.name, cal_index_url: workgroup_calendars_url(calendar.workgroup))
expect(email).to have_body_text /#{key}/
end
end
diff --git a/spec/models/calendar_spec.rb b/spec/models/calendar_spec.rb
index 3cffd0f8a..a5c0a7471 100644
--- a/spec/models/calendar_spec.rb
+++ b/spec/models/calendar_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe Calendar, :type => :model do
end
it 'validates that dates and date_ranges do not overlap but allow for days not in the list' do
- expect(build(:calendar, dates: [Date.today.beginning_of_week], date_ranges: [Date.today.beginning_of_week..Date.today], int_day_types: Calendar::THURSDAY)).to be_valid
+ expect(build(:calendar, dates: [Date.today.beginning_of_week - 1.week], date_ranges: [(Date.today.beginning_of_week - 1.week)..Date.today], int_day_types: Calendar::THURSDAY)).to be_valid
end
it 'validates that there are no duplicates in dates' do
diff --git a/spec/models/chouette/footnote_spec.rb b/spec/models/chouette/footnote_spec.rb
index fc5e5f306..05f55c2f0 100644
--- a/spec/models/chouette/footnote_spec.rb
+++ b/spec/models/chouette/footnote_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
describe Chouette::Footnote, type: :model do
- let(:footnote) { create(:footnote) }
+ subject { create(:footnote) }
it { should validate_presence_of :line }
describe 'data_source_ref' do
it 'should set default if omitted' do
- expect(footnote.data_source_ref).to eq "DATASOURCEREF_EDITION_BOIV"
+ expect(subject.data_source_ref).to eq "DATASOURCEREF_EDITION_BOIV"
end
it 'should not set default if not omitted' do
@@ -18,16 +18,16 @@ describe Chouette::Footnote, type: :model do
end
describe 'checksum' do
- it_behaves_like 'checksum support', :footnote
+ it_behaves_like 'checksum support'
context '#checksum_attributes' do
it 'should return code and label' do
- expected = [footnote.code, footnote.label]
- expect(footnote.checksum_attributes).to include(*expected)
+ expected = [subject.code, subject.label]
+ expect(subject.checksum_attributes).to include(*expected)
end
it 'should not return other atrributes' do
- expect(footnote.checksum_attributes).to_not include(footnote.updated_at)
+ expect(subject.checksum_attributes).to_not include(subject.updated_at)
end
end
end
diff --git a/spec/models/chouette/journey_pattern_spec.rb b/spec/models/chouette/journey_pattern_spec.rb
index b5eb9004c..7c767e4d1 100644
--- a/spec/models/chouette/journey_pattern_spec.rb
+++ b/spec/models/chouette/journey_pattern_spec.rb
@@ -2,9 +2,10 @@ require 'spec_helper'
describe Chouette::JourneyPattern, :type => :model do
it { is_expected.to be_versioned }
+ subject { create(:journey_pattern) }
describe 'checksum' do
- it_behaves_like 'checksum support', :journey_pattern
+ it_behaves_like 'checksum support'
end
# context 'validate minimum stop_points size' do
@@ -70,6 +71,30 @@ describe Chouette::JourneyPattern, :type => :model do
end
end
+ describe "set_distances" do
+ let(:journey_pattern) { create :journey_pattern }
+ let(:distances){ [] }
+ it "should raise an error" do
+ expect{journey_pattern.set_distances(distances)}.to raise_error
+ end
+
+ context "with consistent data" do
+ let(:distances){ [0, 100, "200", 500, 1000] }
+
+ it "should set costs" do
+ expect{journey_pattern.set_distances(distances)}.to_not raise_error
+ start, stop = journey_pattern.stop_points[0..1]
+ expect(journey_pattern.costs_between(start, stop)[:distance]).to eq 100
+ start, stop = journey_pattern.stop_points[1..2]
+ expect(journey_pattern.costs_between(start, stop)[:distance]).to eq 100
+ start, stop = journey_pattern.stop_points[2..3]
+ expect(journey_pattern.costs_between(start, stop)[:distance]).to eq 300
+ start, stop = journey_pattern.stop_points[3..4]
+ expect(journey_pattern.costs_between(start, stop)[:distance]).to eq 500
+ end
+ end
+ end
+
describe "state_update" do
def journey_pattern_to_state jp
jp.attributes.slice('name', 'published_name', 'registration_number').tap do |item|
diff --git a/spec/models/chouette/route/route_base_spec.rb b/spec/models/chouette/route/route_base_spec.rb
index 26f57eae5..98cb3e358 100644
--- a/spec/models/chouette/route/route_base_spec.rb
+++ b/spec/models/chouette/route/route_base_spec.rb
@@ -1,8 +1,8 @@
RSpec.describe Chouette::Route, :type => :model do
-
subject { create(:route) }
+
describe 'checksum' do
- it_behaves_like 'checksum support', :route
+ it_behaves_like 'checksum support'
end
it { is_expected.to enumerize(:direction).in(:straight_forward, :backward, :clockwise, :counter_clockwise, :north, :north_west, :west, :south_west, :south, :south_east, :east, :north_east) }
diff --git a/spec/models/chouette/routing_constraint_zone_spec.rb b/spec/models/chouette/routing_constraint_zone_spec.rb
index 0282cb8b1..bda6bb04a 100644
--- a/spec/models/chouette/routing_constraint_zone_spec.rb
+++ b/spec/models/chouette/routing_constraint_zone_spec.rb
@@ -11,7 +11,7 @@ describe Chouette::RoutingConstraintZone, type: :model do
it { is_expected.to be_versioned }
describe 'checksum' do
- it_behaves_like 'checksum support', :routing_constraint_zone
+ it_behaves_like 'checksum support'
end
describe 'validations' do
diff --git a/spec/models/chouette/time_table_period_spec.rb b/spec/models/chouette/time_table_period_spec.rb
index cc1a3ae09..e14d38ade 100644
--- a/spec/models/chouette/time_table_period_spec.rb
+++ b/spec/models/chouette/time_table_period_spec.rb
@@ -10,7 +10,7 @@ describe Chouette::TimeTablePeriod, :type => :model do
it { is_expected.to validate_presence_of :period_end }
describe 'checksum' do
- it_behaves_like 'checksum support', :time_table_period
+ it_behaves_like 'checksum support'
end
describe "#overlap" do
diff --git a/spec/models/chouette/time_table_spec.rb b/spec/models/chouette/time_table_spec.rb
index a501f234a..bb88877b9 100644
--- a/spec/models/chouette/time_table_spec.rb
+++ b/spec/models/chouette/time_table_spec.rb
@@ -1049,7 +1049,7 @@ end
# it { is_expected.to validate_uniqueness_of :objectid }
describe 'checksum' do
- it_behaves_like 'checksum support', :time_table
+ it_behaves_like 'checksum support'
it "handles newly built dates and periods" do
time_table = build(:time_table)
diff --git a/spec/models/chouette/vehicle_journey_at_stop_spec.rb b/spec/models/chouette/vehicle_journey_at_stop_spec.rb
index 02306883c..f79d19c88 100644
--- a/spec/models/chouette/vehicle_journey_at_stop_spec.rb
+++ b/spec/models/chouette/vehicle_journey_at_stop_spec.rb
@@ -1,14 +1,16 @@
require 'spec_helper'
RSpec.describe Chouette::VehicleJourneyAtStop, type: :model do
+ subject { create(:vehicle_journey_at_stop) }
+
describe 'checksum' do
let(:at_stop) { build_stubbed(:vehicle_journey_at_stop) }
- it_behaves_like 'checksum support', :vehicle_journey_at_stop
+ it_behaves_like 'checksum support'
context '#checksum_attributes' do
it 'should return attributes' do
- expected = [at_stop.departure_time.to_s(:time), at_stop.arrival_time.to_s(:time)]
+ expected = [at_stop.departure_time.utc.to_s(:time), at_stop.arrival_time.utc.to_s(:time)]
expected << at_stop.departure_day_offset.to_s
expected << at_stop.arrival_day_offset.to_s
expect(at_stop.checksum_attributes).to include(*expected)
diff --git a/spec/models/chouette/vehicle_journey_spec.rb b/spec/models/chouette/vehicle_journey_spec.rb
index 7279980a3..76e73d9cf 100644
--- a/spec/models/chouette/vehicle_journey_spec.rb
+++ b/spec/models/chouette/vehicle_journey_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe Chouette::VehicleJourney, :type => :model do
+ subject { create(:vehicle_journey) }
+
it { is_expected.to be_versioned }
it { should have_and_belong_to_many(:purchase_windows) }
@@ -21,7 +23,7 @@ describe Chouette::VehicleJourney, :type => :model do
end
describe 'checksum' do
- it_behaves_like 'checksum support', :vehicle_journey
+ it_behaves_like 'checksum support'
it "changes when a vjas is updated" do
vehicle_journey = create(:vehicle_journey)
expect{vehicle_journey.vehicle_journey_at_stops.last.update_attribute(:departure_time, Time.now)}.to change{vehicle_journey.reload.checksum}
diff --git a/spec/models/compliance_check_spec.rb b/spec/models/compliance_check_spec.rb
index f83d78c29..ffa59245c 100644
--- a/spec/models/compliance_check_spec.rb
+++ b/spec/models/compliance_check_spec.rb
@@ -15,4 +15,36 @@ RSpec.describe ComplianceCheck, type: :model do
it { should validate_presence_of :name }
it { should validate_presence_of :code }
it { should validate_presence_of :origin_code }
+
+ describe ".abort_old" do
+ it "changes check sets older than 4 hours to aborted" do
+ Timecop.freeze(Time.now) do
+ old_check_set = create(
+ :compliance_check_set,
+ status: 'pending',
+ created_at: 4.hours.ago - 1.minute
+ )
+ current_check_set = create(:compliance_check_set, status: 'pending')
+
+ ComplianceCheckSet.abort_old
+
+ expect(current_check_set.reload.status).to eq('pending')
+ expect(old_check_set.reload.status).to eq('aborted')
+ end
+ end
+
+ it "doesn't work on check sets with a `finished_status`" do
+ Timecop.freeze(Time.now) do
+ check_set = create(
+ :compliance_check_set,
+ status: 'successful',
+ created_at: 4.hours.ago - 1.minute
+ )
+
+ ComplianceCheckSet.abort_old
+
+ expect(check_set.reload.status).to eq('successful')
+ end
+ end
+ end
end
diff --git a/spec/models/import_spec.rb b/spec/models/import_spec.rb
index ffb2360c2..8b85f151b 100644
--- a/spec/models/import_spec.rb
+++ b/spec/models/import_spec.rb
@@ -29,6 +29,58 @@ RSpec.describe Import, type: :model do
)
end
+ describe ".abort_old" do
+ it "changes imports older than 4 hours to aborted" do
+ Timecop.freeze(Time.now) do
+ old_import = create(
+ :workbench_import,
+ status: 'pending',
+ created_at: 4.hours.ago - 1.minute
+ )
+ current_import = create(:workbench_import, status: 'pending')
+
+ Import.abort_old
+
+ expect(current_import.reload.status).to eq('pending')
+ expect(old_import.reload.status).to eq('aborted')
+ end
+ end
+
+ it "doesn't work on imports with a `finished_status`" do
+ Timecop.freeze(Time.now) do
+ import = create(
+ :workbench_import,
+ status: 'successful',
+ created_at: 4.hours.ago - 1.minute
+ )
+
+ Import.abort_old
+
+ expect(import.reload.status).to eq('successful')
+ end
+ end
+
+ it "only works on the caller type" do
+ Timecop.freeze(Time.now) do
+ workbench_import = create(
+ :workbench_import,
+ status: 'pending',
+ created_at: 4.hours.ago - 1.minute
+ )
+ netex_import = create(
+ :netex_import,
+ status: 'pending',
+ created_at: 4.hours.ago - 1.minute
+ )
+
+ NetexImport.abort_old
+
+ expect(workbench_import.reload.status).to eq('pending')
+ expect(netex_import.reload.status).to eq('aborted')
+ end
+ end
+ end
+
describe "#destroy" do
it "must destroy all child imports" do
netex_import = create(:netex_import)
diff --git a/spec/models/simple_importer_spec.rb b/spec/models/simple_importer_spec.rb
new file mode 100644
index 000000000..60d7b7882
--- /dev/null
+++ b/spec/models/simple_importer_spec.rb
@@ -0,0 +1,394 @@
+RSpec.describe SimpleImporter do
+ describe "#define" do
+ context "with an incomplete configuration" do
+
+ it "should raise an error" do
+ expect do
+ SimpleImporter.define :foo
+ end.to raise_error
+ end
+ end
+ context "with a complete configuration" do
+ before do
+ SimpleImporter.define :foo do |config|
+ config.model = "example"
+ end
+ end
+
+ it "should define an importer" do
+ expect{SimpleImporter.find_configuration(:foo)}.to_not raise_error
+ expect{SimpleImporter.new(configuration_name: :foo, filepath: "")}.to_not raise_error
+ expect{SimpleImporter.find_configuration(:bar)}.to raise_error
+ expect{SimpleImporter.new(configuration_name: :bar, filepath: "")}.to raise_error
+ expect{SimpleImporter.create(configuration_name: :foo, filepath: "")}.to change{SimpleImporter.count}.by 1
+ end
+ end
+ end
+
+ describe "#import" do
+ let(:importer){ importer = SimpleImporter.new(configuration_name: :test, filepath: filepath) }
+ let(:filepath){ fixtures_path 'simple_importer', filename }
+ let(:filename){ "stop_area.csv" }
+ let(:stop_area_referential){ create(:stop_area_referential, objectid_format: :stif_netex) }
+
+ before(:each) do
+ SimpleImporter.define :test do |config|
+ config.model = Chouette::StopArea
+ config.separator = ";"
+ config.key = "name"
+ config.add_column :name
+ config.add_column :lat, attribute: :latitude
+ config.add_column :lat, attribute: :longitude, value: ->(raw){ raw.to_f + 1 }
+ config.add_column :type, attribute: :area_type, value: ->(raw){ raw&.downcase }
+ config.add_column :street_name
+ config.add_column :stop_area_referential, value: stop_area_referential
+ config.add_value :kind, :commercial
+ end
+ end
+
+ it "should import the given file" do
+ expect{importer.import verbose: false}.to change{Chouette::StopArea.count}.by 1
+ expect(importer.status).to eq "success"
+ stop = Chouette::StopArea.last
+ expect(stop.name).to eq "Nom du Stop"
+ expect(stop.latitude).to eq 45.00
+ expect(stop.longitude).to eq 46.00
+ expect(stop.area_type).to eq "zdep"
+ expect(importer.reload.journal.last["event"]).to eq("creation")
+ end
+
+ context "when overriding configuration" do
+ before(:each){
+ importer.configure do |config|
+ config.add_value :latitude, 88
+ end
+ }
+
+ it "should import the given file and not mess with the global configuration" do
+ expect{importer.import}.to change{Chouette::StopArea.count}.by 1
+ expect(importer.status).to eq "success"
+ stop = Chouette::StopArea.last
+ expect(stop.latitude).to eq 88
+ importer = SimpleImporter.new(configuration_name: :test, filepath: filepath)
+ expect{importer.import}.to change{Chouette::StopArea.count}.by 0
+ expect(stop.reload.latitude).to eq 45
+ end
+ end
+
+ context "with an already existing record" do
+ let(:filename){ "stop_area.csv" }
+ before(:each){
+ create :stop_area, name: "Nom du Stop"
+ }
+ it "should only update the record" do
+ expect{importer.import}.to change{Chouette::StopArea.count}.by 0
+ expect(importer.status).to eq "success"
+ stop = Chouette::StopArea.last
+ expect(stop.name).to eq "Nom du Stop"
+ expect(stop.latitude).to eq 45.00
+ expect(stop.longitude).to eq 46.00
+ expect(stop.area_type).to eq "zdep"
+ expect(importer.reload.journal.last["event"]).to eq("update")
+ end
+
+ context "in another scope" do
+ before(:each) do
+ ref = create(:stop_area_referential)
+ importer.configure do |config|
+ config.context = { stop_area_referential: ref }
+ config.scope = ->{ context[:stop_area_referential].stop_areas }
+ end
+ end
+
+ it "should create the record" do
+ expect{importer.import verbose: false}.to change{Chouette::StopArea.count}.by 1
+ expect(importer.status).to eq "success"
+ end
+ end
+ end
+
+ context "with a missing column" do
+ let(:filename){ "stop_area_missing_street_name.csv" }
+ it "should set an error message" do
+ expect{importer.import(verbose: false)}.to_not raise_error
+ expect(importer.status).to eq "success_with_warnings"
+ expect(importer.reload.journal.first["event"]).to eq("column_not_found")
+ end
+ end
+
+ context "with an incomplete dataset" do
+ let(:filename){ "stop_area_incomplete.csv" }
+ it "should fail" do
+ expect{importer.import}.to_not raise_error
+ expect(importer.status).to eq "failed"
+ expect(importer.reload.journal.last["message"]).to eq({"name" => ["doit être rempli(e)"]})
+ end
+
+ it "should be transactional" do
+ expect{importer.import}.to_not change {Chouette::StopArea.count}
+ end
+ end
+
+ context "with a wrong filepath" do
+ let(:filename){ "not_found.csv" }
+ it "should fail" do
+ expect{importer.import}.to_not raise_error
+ expect(importer.status).to eq "failed"
+ expect(importer.reload.journal.first["message"]).to eq "File not found: #{importer.filepath}"
+ end
+ end
+
+ context "with a custom behaviour" do
+ let!(:present){ create :stop_area, name: "Nom du Stop", stop_area_referential: stop_area_referential }
+ let!(:missing){ create :stop_area, name: "Another", stop_area_referential: stop_area_referential }
+ before(:each){
+ importer.configure do |config|
+ config.before do |importer|
+ stop_area_referential.stop_areas.each &:deactivate!
+ end
+
+ config.before(:each_save) do |importer, stop_area|
+ stop_area.activate!
+ end
+ end
+ }
+
+ it "should disable all missing areas" do
+ expect{importer.import}.to change{Chouette::StopArea.count}.by 0
+ expect(present.reload.activated?).to be_truthy
+ expect(missing.reload.activated?).to be_falsy
+ end
+
+ context "with an error" do
+ let(:filename){ "stop_area_incomplete.csv" }
+ it "should do nothing" do
+ expect{importer.import}.to_not change {Chouette::StopArea.count}
+ expect(present.reload.activated?).to be_truthy
+ expect(missing.reload.activated?).to be_truthy
+ end
+ end
+ end
+
+ context "with a full file" do
+ let(:filename){ "stop_area_full.csv" }
+ let!(:missing){ create :stop_area, name: "Another", stop_area_referential: stop_area_referential }
+
+ before(:each) do
+ SimpleImporter.define :test do |config|
+ config.model = Chouette::StopArea
+ config.separator = ";"
+ config.key = "station_code"
+ config.add_column :station_code, attribute: :registration_number
+ config.add_column :country_code
+ config.add_column :station_name, attribute: :name
+ config.add_column :inactive, attribute: :deleted_at, value: ->(raw){ raw == "t" ? Time.now : nil }
+ config.add_column :change_timestamp, attribute: :updated_at
+ config.add_column :longitude
+ config.add_column :latitude
+ config.add_column :parent_station_code, attribute: :parent, value: ->(raw){ raw.present? && resolve(:station_code, raw){|value| Chouette::StopArea.find_by(registration_number: value) } }
+ config.add_column :parent_station_code, attribute: :area_type, value: ->(raw){ raw.present? ? "zdep" : "gdl" }
+ config.add_column :timezone, attribute: :time_zone
+ config.add_column :address, attribute: :street_name
+ config.add_column :postal_code, attribute: :zip_code
+ config.add_column :city, attribute: :city_name
+ config.add_value :stop_area_referential_id, stop_area_referential.id
+ config.add_value :long_lat_type, "WGS84"
+ config.add_value :kind, :commercial
+ config.before do |importer|
+ stop_area_referential.stop_areas.each &:deactivate!
+ end
+
+ config.before(:each_save) do |importer, stop_area|
+ stop_area.activate
+ end
+ end
+ end
+
+ it "should import the given file" do
+ expect{importer.import(verbose: false)}.to change{Chouette::StopArea.count}.by 2
+ expect(importer.status).to eq "success"
+ first = Chouette::StopArea.find_by registration_number: "PAR"
+ last = Chouette::StopArea.find_by registration_number: "XED"
+
+ expect(last.parent).to eq first
+ expect(first.area_type).to eq "gdl"
+ expect(last.area_type).to eq "zdep"
+ expect(first.long_lat_type).to eq "WGS84"
+ expect(first.activated?).to be_truthy
+ expect(last.activated?).to be_truthy
+ expect(missing.reload.activated?).to be_falsy
+ end
+
+ context "with a relation in reverse order" do
+ let(:filename){ "stop_area_full_reverse.csv" }
+
+ it "should import the given file" do
+ expect{importer.import}.to change{Chouette::StopArea.count}.by 2
+ expect(importer.status).to eq "success"
+ first = Chouette::StopArea.find_by registration_number: "XED"
+ last = Chouette::StopArea.find_by registration_number: "PAR"
+ expect(first.parent).to eq last
+ end
+ end
+ end
+
+ context "with a specific importer" do
+ let(:filename){ "stop_points_full.csv" }
+
+ before(:each) do
+ create :line, name: "Paris <> Londres - OUIBUS"
+
+ SimpleImporter.define :test do |config|
+ config.model = Chouette::Route
+ config.separator = ";"
+ config.context = {stop_area_referential: stop_area_referential}
+
+ config.before do |importer|
+ mapping = {}
+ path = Rails.root + "spec/fixtures/simple_importer/lines_mapping.csv"
+ CSV.foreach(path, importer.configuration.csv_options) do |row|
+ if row["Ligne Chouette"].present?
+ mapping[row["timetable_route_id"]] ||= Chouette::Line.find_by(name: importer.encode_string(row["Ligne Chouette"]))
+ end
+ end
+ importer.context[:mapping] = mapping
+ end
+
+ config.custom_handler do |row|
+ line = nil
+ fail_with_error "MISSING LINE FOR ROUTE: #{encode_string row["route_name"]}" do
+ line = context[:mapping][row["timetable_route_id"]]
+ raise unless line
+ end
+ @current_record = Chouette::Route.find_or_initialize_by number: row["timetable_route_id"]
+ @current_record.name = encode_string row["route_name"]
+ @current_record.published_name = encode_string row["route_name"]
+
+ @current_record.line = line
+ if @prev_route != @current_record
+ if @prev_route && @prev_route.valid?
+ journey_pattern = @prev_route.full_journey_pattern
+ fail_with_error "WRONG DISTANCES FOR ROUTE #{@prev_route.name} (#{@prev_route.number}): #{@distances.count} distances for #{@prev_route.stop_points.count} stops" do
+ journey_pattern.stop_points = @prev_route.stop_points
+ journey_pattern.set_distances @distances
+ end
+ fail_with_error ->(){ journey_pattern.errors.messages } do
+ journey_pattern.save!
+ end
+ end
+ @distances = []
+ end
+ @distances.push row["stop_distance"]
+ position = row["stop_sequence"].to_i - 1
+
+ stop_area = context[:stop_area_referential].stop_areas.where(registration_number: row["station_code"]).last
+ unless stop_area
+ stop_area = Chouette::StopArea.new registration_number: row["station_code"]
+ stop_area.name = row["station_name"]
+ stop_area.kind = row["border"] == "f" ? :commercial : :non_commercial
+ stop_area.area_type = row["border"] == "f" ? :zdep : :border
+ stop_area.stop_area_referential = context[:stop_area_referential]
+ fail_with_error ->{p stop_area; "UNABLE TO CREATE STOP_AREA: #{stop_area.errors.messages}" }, abort_row: true do
+ stop_area.save!
+ end
+ end
+ stop_point = @current_record.stop_points.find_by(stop_area_id: stop_area.id)
+ if stop_point
+ stop_point.set_list_position position
+ else
+ stop_point = @current_record.stop_points.build(stop_area_id: stop_area.id, position: position)
+ stop_point.for_boarding = :normal
+ stop_point.for_alighting = :normal
+ end
+
+ @prev_route = @current_record
+ end
+
+ config.after(:each_save) do |importer, route|
+ opposite_route_name = route.name.split(" > ").reverse.join(' > ')
+ opposite_route = Chouette::Route.where(name: opposite_route_name).where('id < ?', route.id).last
+ if opposite_route && opposite_route.line == route.line
+ route.update_attribute :wayback, :inbound
+ opposite_route.update_attribute :wayback, :outbound
+ route.update_attribute :opposite_route_id, opposite_route.id
+ opposite_route.update_attribute :opposite_route_id, route.id
+ end
+ end
+
+ config.after do |importer|
+ prev_route = importer.instance_variable_get "@prev_route"
+ if prev_route && prev_route.valid?
+ journey_pattern = prev_route.full_journey_pattern
+ importer.fail_with_error "WRONG DISTANCES FOR ROUTE #{prev_route.name}: #{importer.instance_variable_get("@distances").count} distances for #{prev_route.stop_points.count} stops" do
+ journey_pattern.set_distances importer.instance_variable_get("@distances")
+ journey_pattern.stop_points = prev_route.stop_points
+ end
+ importer.fail_with_error ->(){ journey_pattern.errors.messages } do
+ journey_pattern.save!
+ end
+ end
+ end
+ end
+ end
+
+ it "should import the given file" do
+ routes_count = Chouette::Route.count
+ journey_pattern_count = Chouette::JourneyPattern.count
+ stop_areas_count = Chouette::StopArea.count
+
+ expect{importer.import(verbose: false)}.to change{Chouette::StopPoint.count}.by 10
+ expect(importer.status).to eq "success"
+ expect(Chouette::Route.count).to eq routes_count + 2
+ expect(Chouette::JourneyPattern.count).to eq journey_pattern_count + 2
+ expect(Chouette::StopArea.count).to eq stop_areas_count + 5
+ route = Chouette::Route.find_by number: 1136
+ expect(route.stop_areas.count).to eq 5
+ expect(route.opposite_route).to eq Chouette::Route.find_by(number: 1137)
+ journey_pattern = route.full_journey_pattern
+ expect(journey_pattern.stop_areas.count).to eq 5
+ start, stop = journey_pattern.stop_points[0..1]
+ expect(journey_pattern.costs_between(start, stop)[:distance]).to eq 232
+ start, stop = journey_pattern.stop_points[1..2]
+ expect(journey_pattern.costs_between(start, stop)[:distance]).to eq 118
+ start, stop = journey_pattern.stop_points[2..3]
+ expect(journey_pattern.costs_between(start, stop)[:distance]).to eq 0
+ start, stop = journey_pattern.stop_points[3..4]
+ expect(journey_pattern.costs_between(start, stop)[:distance]).to eq 177
+
+ route = Chouette::Route.find_by number: 1137
+ expect(route.opposite_route).to eq Chouette::Route.find_by(number: 1136)
+ expect(route.stop_areas.count).to eq 5
+ journey_pattern = route.full_journey_pattern
+ expect(journey_pattern.stop_areas.count).to eq 5
+ start, stop = journey_pattern.stop_points[0..1]
+ expect(journey_pattern.costs_between(start, stop)[:distance]).to eq 177
+ start, stop = journey_pattern.stop_points[1..2]
+ expect(journey_pattern.costs_between(start, stop)[:distance]).to eq 0
+ start, stop = journey_pattern.stop_points[2..3]
+ expect(journey_pattern.costs_between(start, stop)[:distance]).to eq 118
+ start, stop = journey_pattern.stop_points[3..4]
+ expect(journey_pattern.costs_between(start, stop)[:distance]).to eq 232
+
+ stop_area = Chouette::StopArea.where(registration_number: "XPB").last
+ expect(stop_area.kind).to eq :commercial
+ expect(stop_area.area_type).to eq :zdep
+
+ stop_area = Chouette::StopArea.where(registration_number: "XDB").last
+ expect(stop_area.kind).to eq :commercial
+ expect(stop_area.area_type).to eq :zdep
+
+ stop_area = Chouette::StopArea.where(registration_number: "COF").last
+ expect(stop_area.kind).to eq :non_commercial
+ expect(stop_area.area_type).to eq :border
+
+ stop_area = Chouette::StopArea.where(registration_number: "COU").last
+ expect(stop_area.kind).to eq :non_commercial
+ expect(stop_area.area_type).to eq :border
+
+ stop_area = Chouette::StopArea.where(registration_number: "ZEP").last
+ expect(stop_area.kind).to eq :commercial
+ expect(stop_area.area_type).to eq :zdep
+ end
+ end
+ end
+end
diff --git a/spec/services/parent_import_notifier_spec.rb b/spec/services/parent_notifier_spec.rb
index 3ab505f88..ecf508fcd 100644
--- a/spec/services/parent_import_notifier_spec.rb
+++ b/spec/services/parent_notifier_spec.rb
@@ -1,4 +1,4 @@
-RSpec.describe ParentImportNotifier do
+RSpec.describe ParentNotifier do
let(:workbench_import) { create(:workbench_import) }
describe ".notify_when_finished" do
@@ -20,7 +20,7 @@ RSpec.describe ParentImportNotifier do
expect(netex_import).to receive(:notify_parent)
end
- ParentImportNotifier.notify_when_finished(netex_imports)
+ ParentNotifier.new(Import).notify_when_finished(netex_imports)
end
it "doesn't call #notify_parent if its `notified_parent_at` is set" do
@@ -33,11 +33,11 @@ RSpec.describe ParentImportNotifier do
expect(netex_import).not_to receive(:notify_parent)
- ParentImportNotifier.notify_when_finished
+ ParentNotifier.new(Import).notify_when_finished
end
end
- describe ".imports_pending_notification" do
+ describe ".objects_pending_notification" do
it "includes imports with a parent and `notified_parent_at` unset" do
netex_import = create(
:netex_import,
@@ -47,7 +47,7 @@ RSpec.describe ParentImportNotifier do
)
expect(
- ParentImportNotifier.imports_pending_notification
+ ParentNotifier.new(Import).objects_pending_notification
).to eq([netex_import])
end
@@ -55,7 +55,7 @@ RSpec.describe ParentImportNotifier do
create(:import, parent: nil)
expect(
- ParentImportNotifier.imports_pending_notification
+ ParentNotifier.new(Import).objects_pending_notification
).to be_empty
end
@@ -70,7 +70,7 @@ RSpec.describe ParentImportNotifier do
end
expect(
- ParentImportNotifier.imports_pending_notification
+ ParentNotifier.new(Import).objects_pending_notification
).to be_empty
end
@@ -83,7 +83,7 @@ RSpec.describe ParentImportNotifier do
)
expect(
- ParentImportNotifier.imports_pending_notification
+ ParentNotifier.new(Import).objects_pending_notification
).to be_empty
end
end
diff --git a/spec/support/checksum_support.rb b/spec/support/checksum_support.rb
index e02d9f9f3..f8dffb1b7 100644
--- a/spec/support/checksum_support.rb
+++ b/spec/support/checksum_support.rb
@@ -1,25 +1,23 @@
-shared_examples 'checksum support' do |factory_name|
- let(:instance) { create(factory_name) }
-
+shared_examples 'checksum support' do
describe '#current_checksum_source' do
let(:attributes) { ['code_value', 'label_value'] }
- let(:seperator) { ChecksumSupport::SEPARATOR }
+ let(:separator) { ChecksumSupport::SEPARATOR }
let(:nil_value) { ChecksumSupport::VALUE_FOR_NIL_ATTRIBUTE }
before do
- allow_any_instance_of(instance.class).to receive(:checksum_attributes).and_return(attributes)
+ allow_any_instance_of(subject.class).to receive(:checksum_attributes).and_return(attributes)
end
- it 'should separate attribute by seperator' do
- expect(instance.current_checksum_source).to eq("code_value#{seperator}label_value")
+ it 'should separate attribute by separator' do
+ expect(subject.current_checksum_source).to eq("code_value#{separator}label_value")
end
context 'nil value' do
let(:attributes) { ['code_value', nil] }
it 'should replace nil attributes by default value' do
- source = "code_value#{seperator}#{nil_value}"
- expect(instance.current_checksum_source).to eq(source)
+ source = "code_value#{separator}#{nil_value}"
+ expect(subject.current_checksum_source).to eq(source)
end
end
@@ -27,27 +25,62 @@ shared_examples 'checksum support' do |factory_name|
let(:attributes) { ['code_value', []] }
it 'should convert to nil' do
- source = "code_value#{seperator}#{nil_value}"
- expect(instance.current_checksum_source).to eq(source)
+ source = "code_value#{separator}#{nil_value}"
+ expect(subject.current_checksum_source).to eq(source)
+ end
+ end
+
+ context 'array value' do
+ let(:attributes) { [['v1', 'v2', 'v3'], 'code_value'] }
+
+ it 'should convert to list' do
+ source = "v1,v2,v3#{separator}code_value"
+ expect(subject.current_checksum_source).to eq(source)
+ end
+ end
+
+ context 'array of array value' do
+ let(:attributes) { [[['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']], 'code_value'] }
+
+ it 'should convert to list' do
+ source = "(a1,a2,a3),(b1,b2,b3)#{separator}code_value"
+ expect(subject.current_checksum_source).to eq(source)
+ end
+ end
+
+ context 'array of array value, with empty array' do
+ let(:attributes) { [[['a1', 'a2', 'a3'], []], 'code_value'] }
+
+ it 'should convert to list' do
+ source = "(a1,a2,a3),-#{separator}code_value"
+ expect(subject.current_checksum_source).to eq(source)
end
end
end
it 'should save checksum on create' do
- expect(instance.checksum).to_not be_nil
+ expect(subject.checksum).to_not be_nil
end
it 'should save checksum_source' do
- expect(instance.checksum_source).to_not be_nil
+ expect(subject.checksum_source).to_not be_nil
end
it 'should trigger set_current_checksum_source on save' do
- expect(instance).to receive(:set_current_checksum_source).at_least(:once)
- instance.save
+ expect(subject).to receive(:set_current_checksum_source).at_least(:once)
+ subject.save
end
it 'should trigger update_checksum on save' do
- expect(instance).to receive(:update_checksum).at_least(:once)
- instance.save
+ expect(subject).to receive(:update_checksum).at_least(:once)
+ subject.save
+ end
+
+ it "doesn't change the checksum on save if the source hasn't been changed" do
+ checksum = subject.checksum
+
+ subject.save
+
+ expect(subject.checksum).to eq(checksum)
end
end
diff --git a/spec/support/decorator_helpers.rb b/spec/support/decorator_helpers.rb
index b2c41e842..544604f61 100644
--- a/spec/support/decorator_helpers.rb
+++ b/spec/support/decorator_helpers.rb
@@ -8,6 +8,7 @@ module Support
let( :features ){ [] }
let( :filtered_action_links){}
before do
+ allow(subject.h).to receive(:duplicate_workbench_referential_path).and_return new_workbench_referential_path(referential.workbench, from: referential.id)
allow_any_instance_of(Draper::HelperProxy).to receive(:policy).and_return policy
allow_any_instance_of(AF83::Decorator::Link).to receive(:check_feature){|f|
features.include?(f)
diff --git a/spec/support/integration_spec_helper.rb b/spec/support/integration_spec_helper.rb
index 36306559d..7ba7e9f92 100644
--- a/spec/support/integration_spec_helper.rb
+++ b/spec/support/integration_spec_helper.rb
@@ -3,7 +3,11 @@ module IntegrationSpecHelper
def paginate_collection klass, decorator, page=1, context={}
collection = klass.page(page)
if decorator
- collection = ModelDecorator.decorate(collection, with: decorator, context: context)
+ if decorator < AF83::Decorator
+ collection = decorator.decorate(collection, context: context)
+ else
+ collection = ModelDecorator.decorate(collection, with: decorator, context: context)
+ end
end
collection
end
@@ -24,6 +28,13 @@ module IntegrationSpecHelper
context('', &block) if block_given?
end
end
+
+ def with_feature feature, &block
+ context "with feature #{feature}" do
+ let(:features){ [feature] }
+ context('', &block) if block_given?
+ end
+ end
end
def self.included into
@@ -48,7 +59,7 @@ RSpec::Matchers.define :have_link_for_each_item do |collection, name, opts|
end
description { "have #{name} link for each item" }
failure_message do
- "expected view to have #{name} link for each item, failed with selector: \"#{@selector}\""
+ "expected view to have one #{name} link for each item, failed with selector: \"#{@selector}\""
end
end
diff --git a/spec/support/pundit/pundit_view_policy.rb b/spec/support/pundit/pundit_view_policy.rb
index 91be0624c..63970de02 100644
--- a/spec/support/pundit/pundit_view_policy.rb
+++ b/spec/support/pundit/pundit_view_policy.rb
@@ -2,13 +2,18 @@ module Pundit
module PunditViewPolicy
def self.included into
into.let(:permissions){ nil }
- into.let(:organisation){ referential.try(:organisation) }
- into.let(:current_referential){ referential || build_stubbed(:referential) }
- into.let(:current_user){ build_stubbed :user, permissions: permissions, organisation: organisation }
+ into.let(:current_referential){ referential || build_stubbed(:referential, organisation: organisation) }
+ into.let(:current_user){ create :user, permissions: permissions, organisation: organisation }
into.let(:pundit_user){ UserContext.new(current_user, referential: current_referential) }
+ into.let(:current_offer_workbench) { create :workbench, organisation: organisation}
into.before do
allow(view).to receive(:pundit_user) { pundit_user }
-
+ allow(view).to receive(:current_user) { current_user }
+ allow(view).to receive(:current_organisation).and_return(organisation)
+ allow(view).to receive(:current_offer_workbench).and_return(current_offer_workbench)
+ allow(view).to receive(:current_workgroup).and_return(current_offer_workbench.workgroup)
+ allow(view).to receive(:has_feature?){ |f| features.include?(f)}
+ allow(view).to receive(:user_signed_in?).and_return true
allow(view).to receive(:policy) do |instance|
::Pundit.policy pundit_user, instance
end
diff --git a/spec/support/referential.rb b/spec/support/referential.rb
index 497ff47a8..9acdce73a 100644
--- a/spec/support/referential.rb
+++ b/spec/support/referential.rb
@@ -11,8 +11,8 @@ module ReferentialHelper
def self.included(base)
base.class_eval do
extend ClassMethods
- alias_method :referential, :first_referential
- alias_method :organisation, :first_organisation
+ base.let(:referential){ first_referential }
+ base.let(:organisation){ first_organisation }
end
end
diff --git a/spec/support/snapshot_support.rb b/spec/support/snapshot_support.rb
new file mode 100644
index 000000000..b1ade5288
--- /dev/null
+++ b/spec/support/snapshot_support.rb
@@ -0,0 +1,60 @@
+module SnaphostSpecHelper
+
+ module Methods
+ def set_invariant expr, val=nil
+ val ||= expr
+ chain = expr.split(".")
+ method = chain.pop
+
+ before(:each) do
+ allow(eval(chain.join('.'))).to receive(method){ val }
+ end
+ end
+ end
+
+ def self.included into
+ into.extend Methods
+ end
+end
+
+RSpec.configure do |config|
+ config.include SnaphostSpecHelper, type: :view
+end
+
+
+RSpec::Matchers.define :match_actions_links_snapshot do |name|
+ match do |actual|
+ @content = Capybara::Node::Simple.new(rendered).find('.page_header').native.inner_html
+ expect(@content).to match_snapshot(name)
+ end
+
+ failure_message do |actual|
+ out = ["Snapshots did not match."]
+ snap_path = File.dirname(method_missing(:class).metadata[:file_path]) + "/__snapshots__/#{name}.snap"
+ temp_path = Pathname.new "#{Rails.root}/tmp/__snapshots__/#{name}.failed.snap"
+ FileUtils.mkdir_p temp_path.dirname
+ tmp = File.new temp_path, "w"
+ tmp.write @content
+ tmp.close()
+ expected = File.read snap_path
+ out << "Expected: #{expected}"
+ out << "Actual: #{@content}"
+ out << "\n\n --- DIFF ---"
+ out << differ.diff_as_string(@content, expected)
+ out << "\n\n --- Previews : ---"
+ out << "Expected: \n" + snapshot_url(snap: snap_path, layout: :actions_links)
+ out << " \nActual: \n" + snapshot_url(snap: tmp.path, layout: :actions_links)
+ out.join("\n")
+ end
+
+ def snapshot_url snap:, layout:
+ "http://localhost:3000/snap/?snap=#{URI.encode(snap.to_s)}&layout=#{URI.encode(layout.to_s)}"
+ end
+
+ def differ
+ RSpec::Support::Differ.new(
+ :object_preparer => lambda { |object| RSpec::Matchers::Composable.surface_descriptions_in(object) },
+ :color => RSpec::Matchers.configuration.color?
+ )
+ end
+end
diff --git a/spec/views/companies/__snapshots__/companies/index.snap b/spec/views/companies/__snapshots__/companies/index.snap
new file mode 100644
index 000000000..2c5c23400
--- /dev/null
+++ b/spec/views/companies/__snapshots__/companies/index.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/companies/__snapshots__/companies/index_create.snap b/spec/views/companies/__snapshots__/companies/index_create.snap
new file mode 100644
index 000000000..df36d5f49
--- /dev/null
+++ b/spec/views/companies/__snapshots__/companies/index_create.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><a class="btn btn-default" href="/line_referentials/99/companies/new">Ajouter un transporteur</a></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/companies/__snapshots__/companies/index_destroy.snap b/spec/views/companies/__snapshots__/companies/index_destroy.snap
new file mode 100644
index 000000000..2c5c23400
--- /dev/null
+++ b/spec/views/companies/__snapshots__/companies/index_destroy.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/companies/__snapshots__/companies/index_update.snap b/spec/views/companies/__snapshots__/companies/index_update.snap
new file mode 100644
index 000000000..2c5c23400
--- /dev/null
+++ b/spec/views/companies/__snapshots__/companies/index_update.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/companies/__snapshots__/companies/show.snap b/spec/views/companies/__snapshots__/companies/show.snap
new file mode 100644
index 000000000..8fe847427
--- /dev/null
+++ b/spec/views/companies/__snapshots__/companies/show.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>Transporteur Company Name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 23/01/2018 <br> Par web service</div></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/companies/__snapshots__/companies/show_create.snap b/spec/views/companies/__snapshots__/companies/show_create.snap
new file mode 100644
index 000000000..8fe847427
--- /dev/null
+++ b/spec/views/companies/__snapshots__/companies/show_create.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>Transporteur Company Name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 23/01/2018 <br> Par web service</div></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/companies/__snapshots__/companies/show_destroy.snap b/spec/views/companies/__snapshots__/companies/show_destroy.snap
new file mode 100644
index 000000000..5d574e460
--- /dev/null
+++ b/spec/views/companies/__snapshots__/companies/show_destroy.snap
@@ -0,0 +1,7 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>Transporteur Company Name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 23/01/2018 <br> Par web service</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right"><a data-confirm="Etes vous sûr de supprimer ce transporteur ?" class="btn btn-primary" rel="nofollow" data-method="delete" href="/line_referentials/99/companies/909"><span class="fa fa-trash mr-xs"></span>Supprimer ce transporteur</a></div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/companies/__snapshots__/companies/show_update.snap b/spec/views/companies/__snapshots__/companies/show_update.snap
new file mode 100644
index 000000000..c2fbd3297
--- /dev/null
+++ b/spec/views/companies/__snapshots__/companies/show_update.snap
@@ -0,0 +1,7 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>Transporteur Company Name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action">
+<div class="small last-update">Dernière mise à jour le 23/01/2018 <br> Par web service</div>
+<a class="btn btn-default" href="/line_referentials/99/companies/909/edit">Editer ce transporteur</a>
+</div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/companies/index.html.erb_spec.rb b/spec/views/companies/index.html.erb_spec.rb
index 9db689ba6..8ed5f2c21 100644
--- a/spec/views/companies/index.html.erb_spec.rb
+++ b/spec/views/companies/index.html.erb_spec.rb
@@ -3,7 +3,10 @@ require 'spec_helper'
RSpec.describe "/companies/index", :type => :view do
let!(:line_referential) { assign :line_referential, create(:line_referential) }
- let!(:companies) { assign :companies, CompanyDecorator.decorate_collection(Array.new(2) { create(:company, line_referential: line_referential) }.paginate) }
+ let(:context){{referential: line_referential}}
+ let!(:companies) do
+ assign :companies, build_paginated_collection(:company, CompanyDecorator, line_referential: line_referential, context: context)
+ end
let!(:search) { assign :q, Ransack::Search.new(Chouette::Company) }
# Fixme #1795
@@ -22,4 +25,28 @@ RSpec.describe "/companies/index", :type => :view do
# expect(view.content_for(:sidebar)).to have_selector(".actions a[href='#{new_line_referential_company_path(line_referential)}']")
# end
+ before(:each) do
+ allow(view).to receive(:collection).and_return(companies)
+ allow(view).to receive(:decorated_collection).and_return(companies)
+ allow(view).to receive(:current_referential).and_return(line_referential)
+ controller.request.path_parameters[:line_referential_id] = line_referential.id
+ allow(view).to receive(:params).and_return({action: :index})
+ end
+
+ describe "action links" do
+ set_invariant "line_referential.id", "99"
+
+ before(:each){
+ render template: "companies/index", layout: "layouts/application"
+ }
+
+ it { should match_actions_links_snapshot "companies/index" }
+
+ %w(create update destroy).each do |p|
+ with_permission "companies.#{p}" do
+ it { should match_actions_links_snapshot "companies/index_#{p}" }
+ end
+ end
+ end
+
end
diff --git a/spec/views/companies/show.html.erb_spec.rb b/spec/views/companies/show.html.erb_spec.rb
index aeb93aebb..b127bdf44 100644
--- a/spec/views/companies/show.html.erb_spec.rb
+++ b/spec/views/companies/show.html.erb_spec.rb
@@ -2,11 +2,38 @@ require 'spec_helper'
describe "/companies/show", :type => :view do
- let!(:company) { assign(:company, create(:company)) }
+ let!(:company) { c = create(:company); assign(:company, c.decorate(context: {referential: c.line_referential})) }
let!(:line_referential) { assign :line_referential, company.line_referential }
# it "should display a map with class 'company'" do
# render
# expect(rendered).to have_selector("#map", :class => 'company')
# end
+
+ before(:each) do
+ allow(view).to receive(:current_referential).and_return(line_referential)
+ allow(view).to receive(:resource).and_return(company)
+ controller.request.path_parameters[:line_referential_id] = line_referential.id
+ controller.request.path_parameters[:id] = company.id
+ allow(view).to receive(:params).and_return({action: :show})
+ end
+
+ describe "action links" do
+ set_invariant "line_referential.id", "99"
+ set_invariant "company.object.id", "909"
+ set_invariant "company.object.name", "Company Name"
+ set_invariant "company.object.updated_at", "2018/01/23".to_time
+
+ before(:each){
+ render template: "companies/show", layout: "layouts/application"
+ }
+
+ it { should match_actions_links_snapshot "companies/show" }
+
+ %w(create update destroy).each do |p|
+ with_permission "companies.#{p}" do
+ it { should match_actions_links_snapshot "companies/show_#{p}" }
+ end
+ end
+ end
end
diff --git a/spec/views/lines/__snapshots__/lines/index.snap b/spec/views/lines/__snapshots__/lines/index.snap
new file mode 100644
index 000000000..2c5c23400
--- /dev/null
+++ b/spec/views/lines/__snapshots__/lines/index.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/lines/__snapshots__/lines/index_create.snap b/spec/views/lines/__snapshots__/lines/index_create.snap
new file mode 100644
index 000000000..4e4f54e7f
--- /dev/null
+++ b/spec/views/lines/__snapshots__/lines/index_create.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><a class="btn btn-default" href="/line_referentials/99/lines/new">Ajouter une ligne</a></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/lines/__snapshots__/lines/index_destroy.snap b/spec/views/lines/__snapshots__/lines/index_destroy.snap
new file mode 100644
index 000000000..2c5c23400
--- /dev/null
+++ b/spec/views/lines/__snapshots__/lines/index_destroy.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/lines/__snapshots__/lines/index_update.snap b/spec/views/lines/__snapshots__/lines/index_update.snap
new file mode 100644
index 000000000..2c5c23400
--- /dev/null
+++ b/spec/views/lines/__snapshots__/lines/index_update.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/lines/__snapshots__/lines/show.snap b/spec/views/lines/__snapshots__/lines/show.snap
new file mode 100644
index 000000000..30eb6786e
--- /dev/null
+++ b/spec/views/lines/__snapshots__/lines/show.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>Ligne Name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 23/01/2018 <br> Par web service</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/line_referentials/99/networks/99">Voir le réseau</a><a class="btn btn-primary" href="/line_referentials/99/companies/99">Voir le transporteur principal</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/lines/__snapshots__/lines/show_create.snap b/spec/views/lines/__snapshots__/lines/show_create.snap
new file mode 100644
index 000000000..30eb6786e
--- /dev/null
+++ b/spec/views/lines/__snapshots__/lines/show_create.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>Ligne Name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 23/01/2018 <br> Par web service</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/line_referentials/99/networks/99">Voir le réseau</a><a class="btn btn-primary" href="/line_referentials/99/companies/99">Voir le transporteur principal</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/lines/__snapshots__/lines/show_destroy.snap b/spec/views/lines/__snapshots__/lines/show_destroy.snap
new file mode 100644
index 000000000..8ed08a90d
--- /dev/null
+++ b/spec/views/lines/__snapshots__/lines/show_destroy.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>Ligne Name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 23/01/2018 <br> Par web service</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/line_referentials/99/networks/99">Voir le réseau</a><a class="btn btn-primary" href="/line_referentials/99/companies/99">Voir le transporteur principal</a><a data-confirm="Etes vous sûr de supprimer cette ligne ?" class="btn btn-primary" rel="nofollow" data-method="delete" href="/line_referentials/99/lines/99"><span class="fa fa-trash mr-xs"></span>Supprimer cette ligne</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/lines/__snapshots__/lines/show_update.snap b/spec/views/lines/__snapshots__/lines/show_update.snap
new file mode 100644
index 000000000..30eb6786e
--- /dev/null
+++ b/spec/views/lines/__snapshots__/lines/show_update.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>Ligne Name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 23/01/2018 <br> Par web service</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/line_referentials/99/networks/99">Voir le réseau</a><a class="btn btn-primary" href="/line_referentials/99/companies/99">Voir le transporteur principal</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/lines/index.html.slim_spec.rb b/spec/views/lines/index.html.slim_spec.rb
index fb436c545..20e1783e3 100644
--- a/spec/views/lines/index.html.slim_spec.rb
+++ b/spec/views/lines/index.html.slim_spec.rb
@@ -13,11 +13,12 @@ describe "/lines/index", :type => :view do
let(:lines) do
assign :lines, build_paginated_collection(:line, LineDecorator, line_referential: line_referential, context: context)
end
- let!(:q) { assign :q, Ransack::Search.new(Chouette::Line) }
+ let!(:q) { assign :q, Ransack::Search.new(Chouette::Line) }
before :each do
deactivated_line
allow(view).to receive(:collection).and_return(lines)
+ allow(view).to receive(:decorated_collection).and_return(lines)
allow(view).to receive(:current_referential).and_return(line_referential)
allow(view).to receive(:params).and_return({action: :index})
controller.request.path_parameters[:line_referential_id] = line_referential.id
@@ -25,49 +26,68 @@ describe "/lines/index", :type => :view do
render
end
- common_items = ->{
- it { should have_link_for_each_item(lines, "show", -> (line){ view.line_referential_line_path(line_referential, line) }) }
- it { should have_link_for_each_item(lines, "network", -> (line){ view.line_referential_network_path(line_referential, line.network) }) }
- it { should have_link_for_each_item(lines, "company", -> (line){ view.line_referential_company_path(line_referential, line.company) }) }
- }
+ describe "action links" do
+ set_invariant "line_referential.id", "99"
+ set_invariant "line_referential.name", "Name"
- common_items.call()
- it { should have_the_right_number_of_links(lines, 3) }
+ before(:each){
+ render template: "lines/index", layout: "layouts/application"
+ }
- with_permission "lines.change_status" do
- common_items.call()
- it { should have_link_for_each_item(lines, "deactivate", -> (line){ view.deactivate_line_referential_line_path(line_referential, line) }) }
- it { should have_the_right_number_of_links(lines, 4) }
+ it { should match_actions_links_snapshot "lines/index" }
+
+ %w(create update destroy).each do |p|
+ with_permission "lines.#{p}" do
+ it { should match_actions_links_snapshot "lines/index_#{p}" }
+ end
+ end
end
- with_permission "lines.destroy" do
- common_items.call()
- it {
- should have_link_for_each_item(lines, "destroy", {
- href: ->(line){ view.line_referential_line_path(line_referential, line)},
- method: :delete
- })
+ context "links" do
+ common_items = ->{
+ it { should have_link_for_each_item(lines, "show", -> (line){ view.line_referential_line_path(line_referential, line) }) }
+ it { should have_link_for_each_item(lines, "network", -> (line){ view.line_referential_network_path(line_referential, line.network) }) }
+ it { should have_link_for_each_item(lines, "company", -> (line){ view.line_referential_company_path(line_referential, line.company) }) }
}
- it { should have_the_right_number_of_links(lines, 4) }
- end
- context "with a deactivated item" do
+ common_items.call()
+ it { should have_the_right_number_of_links(lines, 3) }
+
with_permission "lines.change_status" do
- let(:deactivated_line){ create :line, deactivated: true }
+ common_items.call()
+ it { should have_link_for_each_item(lines, "deactivate", -> (line){ view.deactivate_line_referential_line_path(line_referential, line) }) }
+ it { should have_the_right_number_of_links(lines, 4) }
+ end
+ with_permission "lines.destroy" do
common_items.call()
- it "should display an activate link for the deactivated one" do
- lines.each do |line|
- if line == deactivated_line
- href = view.activate_line_referential_line_path(line_referential, line)
- else
- href = view.deactivate_line_referential_line_path(line_referential, line)
+ it {
+ should have_link_for_each_item(lines, "destroy", {
+ href: ->(line){ view.line_referential_line_path(line_referential, line)},
+ method: :delete
+ })
+ }
+ it { should have_the_right_number_of_links(lines, 4) }
+ end
+
+ context "with a deactivated item" do
+ with_permission "lines.change_status" do
+ let(:deactivated_line){ create :line, deactivated: true }
+
+ common_items.call()
+ it "should display an activate link for the deactivated one" do
+ lines.each do |line|
+ if line == deactivated_line
+ href = view.activate_line_referential_line_path(line_referential, line)
+ else
+ href = view.deactivate_line_referential_line_path(line_referential, line)
+ end
+ selector = "tr.#{TableBuilderHelper.item_row_class_name(lines)}-#{line.id} .actions a[href='#{href}']"
+ expect(rendered).to have_selector(selector, count: 1)
end
- selector = "tr.#{TableBuilderHelper.item_row_class_name(lines)}-#{line.id} .actions a[href='#{href}']"
- expect(rendered).to have_selector(selector, count: 1)
end
+ it { should have_the_right_number_of_links(lines, 4) }
end
- it { should have_the_right_number_of_links(lines, 4) }
end
end
end
diff --git a/spec/views/lines/show.html.erb_spec.rb b/spec/views/lines/show.html.erb_spec.rb
index 9649d9c8e..effdcd014 100644
--- a/spec/views/lines/show.html.erb_spec.rb
+++ b/spec/views/lines/show.html.erb_spec.rb
@@ -15,6 +15,30 @@ describe "/lines/show", :type => :view do
let!(:map) { assign(:map, double(:to_html => '<div id="map"/>'.html_safe)) }
before do
- allow(view).to receive_messages(current_organisation: referential.organisation)
+ allow(view).to receive_messages(current_organisation: referential.organisation, resource: line)
+ controller.request.path_parameters[:line_referential_id] = line_referential.id
+ controller.request.path_parameters[:id] = line.id
+ allow(view).to receive(:params).and_return({action: :show})
+ end
+
+ describe "action links" do
+ set_invariant "line_referential.id", "99"
+ set_invariant "line.object.id", "99"
+ set_invariant "line.object.name", "Name"
+ set_invariant "line.company.id", "99"
+ set_invariant "line.network.id", "99"
+ set_invariant "line.updated_at", "2018/01/23".to_time
+
+ before(:each){
+ render template: "lines/show", layout: "layouts/application"
+ }
+
+ it { should match_actions_links_snapshot "lines/show" }
+
+ %w(create update destroy).each do |p|
+ with_permission "lines.#{p}" do
+ it { should match_actions_links_snapshot "lines/show_#{p}" }
+ end
+ end
end
end
diff --git a/spec/views/networks/__snapshots__/networks/index.snap b/spec/views/networks/__snapshots__/networks/index.snap
new file mode 100644
index 000000000..2c5c23400
--- /dev/null
+++ b/spec/views/networks/__snapshots__/networks/index.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/networks/__snapshots__/networks/index_create.snap b/spec/views/networks/__snapshots__/networks/index_create.snap
new file mode 100644
index 000000000..afd4aa41b
--- /dev/null
+++ b/spec/views/networks/__snapshots__/networks/index_create.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><a class="btn btn-default" href="/line_referentials/99/networks/new">Ajouter un réseau</a></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/networks/__snapshots__/networks/index_destroy.snap b/spec/views/networks/__snapshots__/networks/index_destroy.snap
new file mode 100644
index 000000000..2c5c23400
--- /dev/null
+++ b/spec/views/networks/__snapshots__/networks/index_destroy.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/networks/__snapshots__/networks/index_update.snap b/spec/views/networks/__snapshots__/networks/index_update.snap
new file mode 100644
index 000000000..2c5c23400
--- /dev/null
+++ b/spec/views/networks/__snapshots__/networks/index_update.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/networks/__snapshots__/networks/show.snap b/spec/views/networks/__snapshots__/networks/show.snap
new file mode 100644
index 000000000..8f2992065
--- /dev/null
+++ b/spec/views/networks/__snapshots__/networks/show.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>Réseau Name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 23/01/2018 <br> Par web service</div></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/networks/__snapshots__/networks/show_create.snap b/spec/views/networks/__snapshots__/networks/show_create.snap
new file mode 100644
index 000000000..8f2992065
--- /dev/null
+++ b/spec/views/networks/__snapshots__/networks/show_create.snap
@@ -0,0 +1,4 @@
+<div class="container-fluid"><div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>Réseau Name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 23/01/2018 <br> Par web service</div></div></div>
+</div></div> \ No newline at end of file
diff --git a/spec/views/networks/__snapshots__/networks/show_destroy.snap b/spec/views/networks/__snapshots__/networks/show_destroy.snap
new file mode 100644
index 000000000..c525c05b7
--- /dev/null
+++ b/spec/views/networks/__snapshots__/networks/show_destroy.snap
@@ -0,0 +1,7 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>Réseau Name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 23/01/2018 <br> Par web service</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right"><a data-confirm="Etes vous sûr de supprimer ce réseau ?" class="btn btn-primary" rel="nofollow" data-method="delete" href="/line_referentials/99/networks/909"><span class="fa fa-trash mr-xs"></span>Supprimer ce réseau</a></div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/networks/__snapshots__/networks/show_update.snap b/spec/views/networks/__snapshots__/networks/show_update.snap
new file mode 100644
index 000000000..35f8ee9ac
--- /dev/null
+++ b/spec/views/networks/__snapshots__/networks/show_update.snap
@@ -0,0 +1,7 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>Réseau Name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 23/01/2018 <br> Par web service</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right"><a class="btn btn-primary" href="/line_referentials/99/networks/909/edit">Editer ce réseau</a></div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/networks/index.html.erb_spec.rb b/spec/views/networks/index.html.erb_spec.rb
index d2dde7f87..80e755163 100644
--- a/spec/views/networks/index.html.erb_spec.rb
+++ b/spec/views/networks/index.html.erb_spec.rb
@@ -3,7 +3,11 @@ require 'spec_helper'
describe "/networks/index", :type => :view do
let!(:line_referential) { assign :line_referential, create(:line_referential) }
- let!(:networks) { assign :networks, Array.new(2){ create(:network, line_referential: line_referential) }.paginate }
+ let(:context){{line_referential: line_referential}}
+ let!(:networks) do
+ assign :networks, build_paginated_collection(:network, NetworkDecorator, line_referential: line_referential, context: context)
+ end
+
let!(:search) { assign :q, Ransack::Search.new(Chouette::Network) }
# it "should render a show link for each group" do
@@ -18,5 +22,27 @@ describe "/networks/index", :type => :view do
# render
# expect(view.content_for(:sidebar)).to have_selector("a[href='#{new_line_referential_network_path(line_referential)}']")
# end
+ before(:each) do
+ allow(view).to receive(:collection).and_return(networks)
+ allow(view).to receive(:decorated_collection).and_return(networks)
+ allow(view).to receive(:current_referential).and_return(line_referential)
+ controller.request.path_parameters[:line_referential_id] = line_referential.id
+ allow(view).to receive(:params).and_return({action: :index})
+ end
+
+ describe "action links" do
+ set_invariant "line_referential.id", "99"
+
+ before(:each){
+ render template: "networks/index", layout: "layouts/application"
+ }
+
+ it { should match_actions_links_snapshot "networks/index" }
+ %w(create update destroy).each do |p|
+ with_permission "networks.#{p}" do
+ it { should match_actions_links_snapshot "networks/index_#{p}" }
+ end
+ end
+ end
end
diff --git a/spec/views/networks/show.html.erb_spec.rb b/spec/views/networks/show.html.erb_spec.rb
index 3926ead14..998e8ac44 100644
--- a/spec/views/networks/show.html.erb_spec.rb
+++ b/spec/views/networks/show.html.erb_spec.rb
@@ -11,8 +11,30 @@ describe "/networks/show", :type => :view do
let!(:map) { assign(:map, double(:to_html => '<div id="map"/>'.html_safe)) }
let!(:line_referential) { assign :line_referential, network.line_referential }
- # it "should display a map with class 'network'" do
- # render
- # expect(rendered).to have_selector("#map")
- # end
+ before(:each) do
+ allow(view).to receive(:current_referential).and_return(line_referential)
+ allow(view).to receive(:resource).and_return(network)
+ controller.request.path_parameters[:line_referential_id] = line_referential.id
+ controller.request.path_parameters[:id] = network.id
+ allow(view).to receive(:params).and_return({action: :show})
+ end
+
+ describe "action links" do
+ set_invariant "line_referential.id", "99"
+ set_invariant "network.object.id", "909"
+ set_invariant "network.object.updated_at", "2018/01/23".to_time
+ set_invariant "network.object.name", "Name"
+
+ before(:each){
+ render template: "networks/show", layout: "layouts/application"
+ }
+
+ it { should match_actions_links_snapshot "networks/show" }
+
+ %w(create update destroy).each do |p|
+ with_permission "networks.#{p}" do
+ it { should match_actions_links_snapshot "networks/show_#{p}" }
+ end
+ end
+ end
end
diff --git a/spec/views/referentials/__snapshots__/referentials/show.snap b/spec/views/referentials/__snapshots__/referentials/show.snap
new file mode 100644
index 000000000..83531ac0e
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 01/01/2000</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/__snapshots__/referentials/show_create.snap b/spec/views/referentials/__snapshots__/referentials/show_create.snap
new file mode 100644
index 000000000..e5d309b96
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show_create.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 01/01/2000</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a><a class="btn btn-primary" href="/referentials/new?from=99">Dupliquer</a><a class="btn btn-primary" href="/referentials/99/select_compliance_control_set">Valider</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/__snapshots__/referentials/show_destroy.snap b/spec/views/referentials/__snapshots__/referentials/show_destroy.snap
new file mode 100644
index 000000000..d90198391
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show_destroy.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 01/01/2000</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a><a data-confirm="Etes vous sûr de vouloir supprimer ce jeu de données ?" class="btn btn-primary" rel="nofollow" data-method="delete" href="/referentials/99"><span class="fa fa-trash mr-xs"></span>Supprimer</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/__snapshots__/referentials/show_purchase_windows.snap b/spec/views/referentials/__snapshots__/referentials/show_purchase_windows.snap
new file mode 100644
index 000000000..83531ac0e
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show_purchase_windows.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 01/01/2000</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/__snapshots__/referentials/show_purchase_windows_create.snap b/spec/views/referentials/__snapshots__/referentials/show_purchase_windows_create.snap
new file mode 100644
index 000000000..e5d309b96
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show_purchase_windows_create.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 01/01/2000</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a><a class="btn btn-primary" href="/referentials/new?from=99">Dupliquer</a><a class="btn btn-primary" href="/referentials/99/select_compliance_control_set">Valider</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/__snapshots__/referentials/show_purchase_windows_destroy.snap b/spec/views/referentials/__snapshots__/referentials/show_purchase_windows_destroy.snap
new file mode 100644
index 000000000..d90198391
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show_purchase_windows_destroy.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 01/01/2000</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a><a data-confirm="Etes vous sûr de vouloir supprimer ce jeu de données ?" class="btn btn-primary" rel="nofollow" data-method="delete" href="/referentials/99"><span class="fa fa-trash mr-xs"></span>Supprimer</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/__snapshots__/referentials/show_purchase_windows_update.snap b/spec/views/referentials/__snapshots__/referentials/show_purchase_windows_update.snap
new file mode 100644
index 000000000..32d46beda
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show_purchase_windows_update.snap
@@ -0,0 +1,12 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action">
+<div class="small last-update">Dernière mise à jour le 01/01/2000</div>
+<a class="btn btn-default" href="/referentials/99/edit">Editer</a>
+</div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a><a class="btn btn-primary" rel="nofollow" data-method="put" href="/referentials/99/archive">Conserver</a><button type="button" data-toggle="modal" data-target="#purgeModal" class="btn btn-primary">Purger</button>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/__snapshots__/referentials/show_readonly.snap b/spec/views/referentials/__snapshots__/referentials/show_readonly.snap
new file mode 100644
index 000000000..83531ac0e
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show_readonly.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 01/01/2000</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/__snapshots__/referentials/show_readonly_create.snap b/spec/views/referentials/__snapshots__/referentials/show_readonly_create.snap
new file mode 100644
index 000000000..82a77521a
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show_readonly_create.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 01/01/2000</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a><a class="btn btn-primary" href="/referentials/new?from=99">Dupliquer</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/__snapshots__/referentials/show_readonly_destroy.snap b/spec/views/referentials/__snapshots__/referentials/show_readonly_destroy.snap
new file mode 100644
index 000000000..83531ac0e
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show_readonly_destroy.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 01/01/2000</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/__snapshots__/referentials/show_readonly_update.snap b/spec/views/referentials/__snapshots__/referentials/show_readonly_update.snap
new file mode 100644
index 000000000..83531ac0e
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show_readonly_update.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 01/01/2000</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys.snap b/spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys.snap
new file mode 100644
index 000000000..83531ac0e
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 01/01/2000</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys_create.snap b/spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys_create.snap
new file mode 100644
index 000000000..e5d309b96
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys_create.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 01/01/2000</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a><a class="btn btn-primary" href="/referentials/new?from=99">Dupliquer</a><a class="btn btn-primary" href="/referentials/99/select_compliance_control_set">Valider</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys_destroy.snap b/spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys_destroy.snap
new file mode 100644
index 000000000..d90198391
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys_destroy.snap
@@ -0,0 +1,9 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action"><div class="small last-update">Dernière mise à jour le 01/01/2000</div></div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a><a data-confirm="Etes vous sûr de vouloir supprimer ce jeu de données ?" class="btn btn-primary" rel="nofollow" data-method="delete" href="/referentials/99"><span class="fa fa-trash mr-xs"></span>Supprimer</a>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys_update.snap b/spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys_update.snap
new file mode 100644
index 000000000..32d46beda
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show_referential_vehicle_journeys_update.snap
@@ -0,0 +1,12 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action">
+<div class="small last-update">Dernière mise à jour le 01/01/2000</div>
+<a class="btn btn-default" href="/referentials/99/edit">Editer</a>
+</div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a><a class="btn btn-primary" rel="nofollow" data-method="put" href="/referentials/99/archive">Conserver</a><button type="button" data-toggle="modal" data-target="#purgeModal" class="btn btn-primary">Purger</button>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/__snapshots__/referentials/show_update.snap b/spec/views/referentials/__snapshots__/referentials/show_update.snap
new file mode 100644
index 000000000..32d46beda
--- /dev/null
+++ b/spec/views/referentials/__snapshots__/referentials/show_update.snap
@@ -0,0 +1,12 @@
+<div class="container-fluid">
+<div class="row">
+<div class="col-lg-9 col-md-8 col-sm-7 col-xs-7"><div class="page-title"><h1>referential_full_name</h1></div></div>
+<div class="col-lg-3 col-md-4 col-sm-5 col-xs-5 text-right"><div class="page-action">
+<div class="small last-update">Dernière mise à jour le 01/01/2000</div>
+<a class="btn btn-default" href="/referentials/99/edit">Editer</a>
+</div></div>
+</div>
+<div class="row mb-sm"><div class="col-lg-12 text-right">
+<a class="btn btn-primary" href="/referentials/99/vehicle_journeys">Courses</a><a class="btn btn-primary" href="/referentials/99/purchase_windows">Calendriers commerciaux</a><a class="btn btn-primary" href="/referentials/99/time_tables">Calendriers</a><a class="btn btn-primary" rel="nofollow" data-method="put" href="/referentials/99/archive">Conserver</a><button type="button" data-toggle="modal" data-target="#purgeModal" class="btn btn-primary">Purger</button>
+</div></div>
+</div> \ No newline at end of file
diff --git a/spec/views/referentials/show.html.erb_spec.rb b/spec/views/referentials/show.html.erb_spec.rb
index 21d296441..82328cb8e 100644
--- a/spec/views/referentials/show.html.erb_spec.rb
+++ b/spec/views/referentials/show.html.erb_spec.rb
@@ -3,26 +3,25 @@ require 'spec_helper'
describe "referentials/show", type: :view do
let!(:referential) do
- referential = create(:referential)
+ referential = create(:workbench_referential)
assign :referential, referential.decorate(context: {
current_organisation: referential.organisation
})
end
+ let(:organisation){ referential.try(:organisation) }
let(:permissions){ [] }
let(:current_organisation) { organisation }
let(:organisation) { referential.organisation }
- let(:current_offer_workbench) { create :workbench, organisation: current_organisation}
let(:readonly){ false }
before :each do
assign :reflines, []
- allow(view).to receive(:current_offer_workbench).and_return(current_offer_workbench)
allow(view).to receive(:current_organisation).and_return(current_organisation)
allow(view).to receive(:current_user).and_return(current_user)
-
allow(view).to receive(:resource).and_return(referential)
allow(view).to receive(:has_feature?).and_return(true)
allow(view).to receive(:user_signed_in?).and_return true
+ allow(view).to receive(:mutual_workbench).and_return referential.workbench
controller.request.path_parameters[:id] = referential.id
allow(view).to receive(:params).and_return({action: :show})