diff options
| author | Luc Donnet | 2017-07-25 22:15:35 +0200 |
|---|---|---|
| committer | Luc Donnet | 2017-07-25 22:15:35 +0200 |
| commit | cbfe9501f2d2cfc38cbe6ac12180e372dd78eca7 (patch) | |
| tree | dbe70647c87af0d779dbba06e20d0f0c2b4a294a | |
| parent | ea3ad8d1f9db76e3d2dfc5f96c930af8db074690 (diff) | |
| parent | cada0f02d732dce25492d7f7eb6d6232d56188dd (diff) | |
| download | chouette-core-cbfe9501f2d2cfc38cbe6ac12180e372dd78eca7.tar.bz2 | |
Merge branch 'master' into staging
88 files changed, 947 insertions, 335 deletions
diff --git a/.erdconfig b/.erdconfig new file mode 100644 index 000000000..9d1618ffd --- /dev/null +++ b/.erdconfig @@ -0,0 +1,23 @@ +attributes: + - content + - foreign_key + - primary_key + - inheritance + - timestamps +disconnected: true +filename: erd +filetype: png +indirect: true +inheritance: false +markup: true +notation: uml +orientation: vertical +polymorphism: false +sort: true +warn: true +title: sample title +exclude: null +only: null +only_recursion_depth: null +prepend_primary: true +cluster: false diff --git a/Gemfile.lock b/Gemfile.lock index 41ae70f56..2239cf853 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -267,8 +267,8 @@ GEM htmlbeautifier (1.3.1) httparty (0.14.0) multi_xml (>= 0.5.2) - i18n (0.8.1) - i18n-tasks (0.9.13) + i18n (0.8.6) + i18n-tasks (0.9.15) activesupport (>= 4.0.2) ast (>= 2.1.0) easy_translate (>= 0.5.0) @@ -313,7 +313,7 @@ GEM mime-types-data (3.2016.0521) mimemagic (0.3.2) mini_portile2 (2.2.0) - minitest (5.10.1) + minitest (5.10.2) multi_json (1.12.1) multi_test (0.1.2) multi_xml (0.6.0) @@ -406,7 +406,8 @@ GEM activesupport (= 4.2.8) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rainbow (2.2.1) + rainbow (2.2.2) + rake rake (12.0.0) ransack (1.6.5) actionpack (>= 3.0) @@ -515,8 +516,8 @@ GEM teaspoon-jasmine (2.3.4) teaspoon (>= 1.0.0) temple (0.7.7) - terminal-table (1.7.3) - unicode-display_width (~> 1.1.1) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) therubyracer (0.12.3) libv8 (~> 3.16.14.15) ref @@ -536,7 +537,7 @@ GEM uglifier (2.7.2) execjs (>= 0.3.0) json (>= 1.8.0) - unicode-display_width (1.1.3) + unicode-display_width (1.3.0) warden (1.2.7) rack (>= 1.0) webmock (3.0.1) diff --git a/app/assets/javascripts/cleanup.coffee b/app/assets/javascripts/cleanup.coffee index 7e291aa9e..41aa1ff15 100644 --- a/app/assets/javascripts/cleanup.coffee +++ b/app/assets/javascripts/cleanup.coffee @@ -4,11 +4,16 @@ $(document).on("change", 'input[name="clean_up[date_type]"]', (e) -> if type == 'before' end_date.hide() - $("label[for='clean_up_begin_date_3i']").html("Date de fin de la purge"); + $('label.begin_date').addClass 'hidden' + $('label.end_date').removeClass 'hidden' + else if type == 'after' end_date.hide() - $("label[for='clean_up_begin_date_3i']").html("Date de début de la purge"); + $('label.begin_date').removeClass 'hidden' + $('label.end_date').addClass 'hidden' + else - $("label[for='clean_up_begin_date_3i']").html("Date de début de la purge"); + $('label.begin_date').removeClass 'hidden' + $('label.end_date').addClass 'hidden' end_date.show() ) diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/CompanySelect2.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/CompanySelect2.js index a6b8dcfa1..d277be003 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/CompanySelect2.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/CompanySelect2.js @@ -51,7 +51,7 @@ class BSelect4 extends React.Component{ }, cache: true }, - minimumInputLength: 3, + minimumInputLength: 1, templateResult: formatRepo }} /> diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/MissionSelect2.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/MissionSelect2.js index b3df767ab..c04a1d642 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/MissionSelect2.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/MissionSelect2.js @@ -43,14 +43,14 @@ class BSelect4 extends React.Component{ item => _.assign( {}, item, - { text: '<small><em>Nom: </em></small>' + item.published_name + '<br/><small><em>Code: </em></small>' + item.registration_number + '<br/><small><em>ID: </em></small>' + _.last(_.split(item.object_id, ':')) } + { text: "<strong>" + item.published_name + _.last(_.split(item.object_id, ':')) + "</strong><br/><small>" + item.registration_number + "</small>" } ) ) }; }, cache: true }, - minimumInputLength: 0, + minimumInputLength: 1, escapeMarkup: function (markup) { return markup; }, templateResult: formatRepo }} diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/TimetableSelect2.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/TimetableSelect2.js index b236e7d94..3e81290f5 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/TimetableSelect2.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/TimetableSelect2.js @@ -2,6 +2,7 @@ var _ = require('lodash') var React = require('react') var PropTypes = require('react').PropTypes var Select2 = require('react-select2') +var actions = require('../../../actions') // get JSON full path var origin = window.location.origin @@ -37,20 +38,20 @@ class BSelect4 extends React.Component{ }; }, processResults: function(data, params) { - return { results: data.map( item => _.assign( {}, item, - {text: item.comment} + {text: '<strong>' + (item.color ? "<span class='fa fa-circle' style='color:" + item.color + "'></span> " : '') + item.comment + ' - ' + item.short_id + '</strong><br/><small>' + item.day_types.match(/[A-Z]?[a-z]+/g).join(', ') + '</small>'} ) ) }; }, cache: true }, - minimumInputLength: 3, + minimumInputLength: 1, + escapeMarkup: function (markup) { return markup; }, templateResult: formatRepo }} /> diff --git a/app/assets/stylesheets/_layout.sass b/app/assets/stylesheets/_layout.sass index c19d9b054..b6b91b2a5 100644 --- a/app/assets/stylesheets/_layout.sass +++ b/app/assets/stylesheets/_layout.sass @@ -28,3 +28,13 @@ body // width: 75% border-bottom: 1px solid rgba($blue, 0.5) margin: 30px auto 45px auto + +.content_header + font-size: 2.2rem + font-weight: normal + margin: 40px 0 + padding: 0px 15px 9px 15px + border-bottom: 1px solid #eee + + &:first-child + margin-top: 0 diff --git a/app/assets/stylesheets/components/_panels.sass b/app/assets/stylesheets/components/_panels.sass index ff384faf9..e9f615081 100644 --- a/app/assets/stylesheets/components/_panels.sass +++ b/app/assets/stylesheets/components/_panels.sass @@ -17,9 +17,31 @@ border-bottom: 2px solid $darkgrey padding: 5px 15px + .badge + color: #fff + background-color: $grey + > h3, > h4 margin: 0 + > .panel-title.with_actions + display: table + width: 100% + + .badge + vertical-align: top + + a + text-decoration: none + color: $blue + + &:hover, &:focus + color: $darkblue + + > div + display: table-cell + vertical-align: middle + .panel-footer padding: 5px 15px background-color: transparent diff --git a/app/assets/stylesheets/components/_select2.sass b/app/assets/stylesheets/components/_select2.sass index 960e8b10b..332af16cd 100644 --- a/app/assets/stylesheets/components/_select2.sass +++ b/app/assets/stylesheets/components/_select2.sass @@ -7,6 +7,10 @@ // .select2-results__message, .loading-results // display: none +.select2-container, .select2-container--bootstrap + .select2-selection--single .select2-selection__rendered + height: 100% + .select2-selection__placeholder color: rgba($grey, 0.65) font-style: italic diff --git a/app/assets/stylesheets/old_application.sass.erb b/app/assets/stylesheets/old_application.sass.erb deleted file mode 100644 index 3443a035d..000000000 --- a/app/assets/stylesheets/old_application.sass.erb +++ /dev/null @@ -1,62 +0,0 @@ -// First import journal variables -$brand-primary: <%= ChouetteIhm::Application.config.company_theme %> -$navbar-default-bg: $brand-primary -$navbar-default-link-color: white -$body-bg: #eee - -// Then bootstrap itself -@import 'bootstrap-sass-official/_bootstrap-sprockets.scss' -@import 'bootstrap-sass-official' - -// Whatever application styles you have go last -// Modules and Variables -@import 'modules/search' -@import 'modules/index_item' -@import 'modules/icons' -@import 'modules/devise' -@import 'modules/progress_bars' - -// Partials -@import 'partials/base' -@import 'partials/header' -@import 'partials/footer' - -// Third-party -@import 'tagmanager/tagmanager' -@import 'font-awesome-sprockets' -@import 'font-awesome' -@import 'jquery-ui' -@import 'formtastic' -@import 'eonasdan-bootstrap-datetimepicker' -@import 'footable' -@import 'OpenLayers/ol' -@import 'OpenLayers/custom' - -// Select2, themed w. Bootstrap -@import 'select2' -@import 'select2-bootstrap' - -@import 'vendor/openlayers_style' -@import 'vendor/openlayers_ie6-style' -@import 'vendor/openlayers_google' -@import 'vendor/openlayers_framedCloud' -@import 'vendor/formtastic_changes' -@import 'vendor/pagination' -@import 'vendor/map_layers' -@import 'vendor/token-input' -@import 'vendor/typeahead' -@import 'vendor/bootstrap_changes' -@import 'vendor/simple_form' -// Select2 -@import 'vendor/select2' -@import 'vendor/select2-bootstrap' - -// Main css -@import 'main/*' - -// Components -@import 'components/*' - -// Hack to make li simple -li - list-style: none diff --git a/app/controllers/companies_controller.rb b/app/controllers/companies_controller.rb index 07a732fc9..cf27c39cf 100644 --- a/app/controllers/companies_controller.rb +++ b/app/controllers/companies_controller.rb @@ -16,14 +16,13 @@ class CompaniesController < BreadcrumbController redirect_to params.merge(:page => 1) end - @companies = ModelDecorator.decorate( - @companies, - with: CompanyDecorator, - context: { - referential: line_referential - } - ) + @companies = decorate_companies(@companies) } + + format.json { + @companies = decorate_companies(@companies) + } + build_breadcrumb :index end end @@ -77,4 +76,14 @@ class CompaniesController < BreadcrumbController %w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc' end + def decorate_companies(companies) + ModelDecorator.decorate( + companies, + with: CompanyDecorator, + context: { + referential: line_referential + } + ) + end + end diff --git a/app/controllers/networks_controller.rb b/app/controllers/networks_controller.rb index d1f83340e..5dae1ba3f 100644 --- a/app/controllers/networks_controller.rb +++ b/app/controllers/networks_controller.rb @@ -37,14 +37,13 @@ class NetworksController < BreadcrumbController redirect_to params.merge(:page => 1) end - @networks = ModelDecorator.decorate( - @networks, - with: NetworkDecorator, - context: { - line_referential: line_referential - } - ) + @networks = decorate_networks(@networks) } + + format.js { + @networks = decorate_networks(@networks) + } + build_breadcrumb :index end end @@ -87,4 +86,14 @@ class NetworksController < BreadcrumbController %w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc' end + def decorate_networks(networks) + ModelDecorator.decorate( + networks, + with: NetworkDecorator, + context: { + line_referential: line_referential + } + ) + end + end diff --git a/app/controllers/referential_companies_controller.rb b/app/controllers/referential_companies_controller.rb index 53dde93bb..482f74ea0 100644 --- a/app/controllers/referential_companies_controller.rb +++ b/app/controllers/referential_companies_controller.rb @@ -14,14 +14,13 @@ class ReferentialCompaniesController < ChouetteController redirect_to params.merge(:page => 1) end - @companies = ModelDecorator.decorate( - @companies, - with: CompanyDecorator, - context: { - referential: referential - } - ) + @companies = decorate_companies(@companies) } + + format.js { + @companies = decorate_companies(@companies) + } + build_breadcrumb :index end end @@ -70,4 +69,14 @@ class ReferentialCompaniesController < ChouetteController %w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc' end + def decorate_companies(companies) + ModelDecorator.decorate( + companies, + with: CompanyDecorator, + context: { + referential: referential + } + ) + end + end diff --git a/app/controllers/referential_networks_controller.rb b/app/controllers/referential_networks_controller.rb index e0ce71ce4..ee2db8008 100644 --- a/app/controllers/referential_networks_controller.rb +++ b/app/controllers/referential_networks_controller.rb @@ -30,14 +30,13 @@ class ReferentialNetworksController < ChouetteController redirect_to params.merge(:page => 1) end - @networks = ModelDecorator.decorate( - @networks, - with: ReferentialNetworkDecorator, - context: { - referential: referential - } - ) + @networks = decorate_networks(@networks) } + + format.js { + @networks = decorate_networks(@networks) + } + build_breadcrumb :index end end @@ -81,4 +80,14 @@ class ReferentialNetworksController < ChouetteController %w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc' end + def decorate_networks(networks) + ModelDecorator.decorate( + networks, + with: ReferentialNetworkDecorator, + context: { + referential: referential + } + ) + end + end diff --git a/app/controllers/referentials_controller.rb b/app/controllers/referentials_controller.rb index 838c46168..afd376092 100644 --- a/app/controllers/referentials_controller.rb +++ b/app/controllers/referentials_controller.rb @@ -9,7 +9,7 @@ class ReferentialsController < BreadcrumbController def new if params[:from] source_referential = Referential.find(params[:from]) - @referential = Referential.new_from(source_referential, organisation: current_organisation) + @referential = Referential.new_from(source_referential) end new! do @@ -118,7 +118,7 @@ class ReferentialsController < BreadcrumbController end def create_resource(referential) - referential.organisation = current_organisation unless referential.created_from + referential.organisation = current_organisation referential.ready = true super end diff --git a/app/controllers/time_tables_controller.rb b/app/controllers/time_tables_controller.rb index 20d500ea9..0054963c9 100644 --- a/app/controllers/time_tables_controller.rb +++ b/app/controllers/time_tables_controller.rb @@ -35,9 +35,9 @@ class TimeTablesController < ChouetteController def create tt_params = time_table_params - if tt_params[:calendar_id] + if tt_params[:calendar_id] && tt_params[:calendar_id] != "" %i(monday tuesday wednesday thursday friday saturday sunday).map { |d| tt_params[d] = true } - calendar = current_organisation.calendars.find_by_id(tt_params[:calendar_id]) + calendar = Calendar.find(tt_params[:calendar_id]) tt_params[:calendar_id] = nil if tt_params.has_key?(:dates_attributes) || tt_params.has_key?(:periods_attributes) end @@ -86,16 +86,14 @@ class TimeTablesController < ChouetteController redirect_to params.merge(:page => 1) end - @time_tables = ModelDecorator.decorate( - @time_tables, - with: TimeTableDecorator, - context: { - referential: @referential - } - ) + @time_tables = decorate_time_tables(@time_tables) build_breadcrumb :index } + + format.js { + @time_tables = decorate_time_tables(@time_tables) + } end end @@ -117,7 +115,8 @@ class TimeTablesController < ChouetteController end def tags - @tags = ActsAsTaggableOn::Tag.where("tags.name = ?", "%#{params[:tag]}%") + # @tags = ActsAsTaggableOn::Tag.where("tags.name = ?", "%#{params[:tag]}%") + @tags = Chouette::TimeTable.tags_on(:tags) respond_to do |format| format.json { render :json => @tags.map{|t| {:id => t.id, :name => t.name }} } end @@ -195,6 +194,16 @@ class TimeTablesController < ChouetteController Chouette::TimeTable.find(from_id) if from_id end + def decorate_time_tables(time_tables) + ModelDecorator.decorate( + time_tables, + with: TimeTableDecorator, + context: { + referential: @referential + } + ) + end + def time_table_params params.require(:time_table).permit( :objectid, diff --git a/app/controllers/workbenches_controller.rb b/app/controllers/workbenches_controller.rb index 22a71863a..19af28a98 100644 --- a/app/controllers/workbenches_controller.rb +++ b/app/controllers/workbenches_controller.rb @@ -2,7 +2,14 @@ class WorkbenchesController < BreadcrumbController before_action :query_params, only: [:show] defaults resource_class: Workbench - respond_to :html, only: [:show] + respond_to :html, only: [:show, :index] + + def index + # Only display Wb with selected name, according to #4108 + @workbench = current_organisation.workbenches.find_by(name: "Gestion de l'offre") + @referentials = @workbench.all_referentials + @calendars = Calendar.where('organisation_id = ? OR shared = ?', current_organisation.id, true) + end def show scope = resource.all_referentials diff --git a/app/helpers/breadcrumb_helper.rb b/app/helpers/breadcrumb_helper.rb index 1f8690f38..55031d4f3 100644 --- a/app/helpers/breadcrumb_helper.rb +++ b/app/helpers/breadcrumb_helper.rb @@ -73,13 +73,13 @@ module BreadcrumbHelper end def calendar_breadcrumb(action) - add_breadcrumb I18n.t('breadcrumbs.referentials'), referentials_path + add_breadcrumb I18n.t('breadcrumbs.referentials'), workbenches_path add_breadcrumb I18n.t('calendars.index.title'), calendars_path add_breadcrumb @calendar.name if %i(show edit).include? action end def workbench_breadcrumb(action) - add_breadcrumb I18n.t("breadcrumbs.referentials"), referentials_path + add_breadcrumb I18n.t("breadcrumbs.referentials"), workbenches_path add_breadcrumb breadcrumb_label(@workbench), workbench_path(@workbench), :title => breadcrumb_tooltip(@workbench) end @@ -215,7 +215,7 @@ module BreadcrumbHelper end def import_breadcrumb (action) - add_breadcrumb I18n.t("breadcrumbs.referentials"), referentials_path + add_breadcrumb I18n.t("breadcrumbs.referentials"), workbenches_path add_breadcrumb breadcrumb_label(@workbench), workbench_path(@workbench), :title => breadcrumb_tooltip(@workbench) add_breadcrumb I18n.t("breadcrumbs.imports"), workbench_imports_path(@workbench) @@ -257,7 +257,7 @@ module BreadcrumbHelper end def organisation_breadcrumb (action = :index) - add_breadcrumb I18n.t("breadcrumbs.referentials"), referentials_path + add_breadcrumb I18n.t("breadcrumbs.referentials"), workbenches_path add_breadcrumb breadcrumb_label(@organisation), organisation_path,:title => breadcrumb_tooltip(@organisation) unless action == :index end diff --git a/app/jobs/mailer_job.rb b/app/jobs/mailer_job.rb index 761a29cd6..3918745b8 100644 --- a/app/jobs/mailer_job.rb +++ b/app/jobs/mailer_job.rb @@ -1,5 +1,5 @@ class MailerJob < ActiveJob::Base - queue_as :mail + # No need to specify queue it's already used mailers queue def perform klass, action, params klass.constantize.public_send(action, *params).deliver_later diff --git a/app/mailers/calendar_mailer.rb b/app/mailers/calendar_mailer.rb index cc8175a07..e2a368c6c 100644 --- a/app/mailers/calendar_mailer.rb +++ b/app/mailers/calendar_mailer.rb @@ -1,11 +1,13 @@ class CalendarMailer < ApplicationMailer - def updated calendar, user - @calendar = calendar + def updated calendar_id, user_id + @calendar = Calendar.find(calendar_id) + user = User.find(user_id) mail to: user.email, subject: t('mailers.calendar_mailer.updated.subject') end - def created calendar, user - @calendar = calendar + def created calendar_id, user_id + @calendar = Calendar.find(calendar_id) + user = User.find(user_id) mail to: user.email, subject: t('mailers.calendar_mailer.created.subject') end end diff --git a/app/models/calendar_observer.rb b/app/models/calendar_observer.rb index 789805356..c81addff4 100644 --- a/app/models/calendar_observer.rb +++ b/app/models/calendar_observer.rb @@ -4,7 +4,7 @@ class CalendarObserver < ActiveRecord::Observer return unless calendar.shared User.with_organisation.each do |user| - MailerJob.perform_later('CalendarMailer', 'updated', [calendar, user]) + MailerJob.perform_later('CalendarMailer', 'updated', [calendar.id, user.id]) end end @@ -12,7 +12,7 @@ class CalendarObserver < ActiveRecord::Observer return unless calendar.shared User.with_organisation.each do |user| - MailerJob.perform_later('CalendarMailer', 'created', [calendar, user]) + MailerJob.perform_later('CalendarMailer', 'created', [calendar.id, user.id]) end end end diff --git a/app/models/chouette/line.rb b/app/models/chouette/line.rb index 33a2fbb00..63d2d1606 100644 --- a/app/models/chouette/line.rb +++ b/app/models/chouette/line.rb @@ -1,5 +1,5 @@ class Chouette::Line < Chouette::ActiveRecord - include DefaultNetexAttributesSupport + include StifCodifligneAttributesSupport include LineRestrictions include LineReferentialSupport include StifTransportModeEnumerations diff --git a/app/models/chouette/stif_codifligne_objectid.rb b/app/models/chouette/stif_codifligne_objectid.rb new file mode 100644 index 000000000..46109e24f --- /dev/null +++ b/app/models/chouette/stif_codifligne_objectid.rb @@ -0,0 +1,18 @@ +class Chouette::StifCodifligneObjectid < String + + @@format = /^([A-Za-z_]+):([A-Za-z]+):([A-Za-z]+):([0-9A-Za-z_-]+)$/ + cattr_reader :format + + def parts + match(format).try(:captures) + end + + def object_type + parts.try(:third) + end + + def local_id + parts.try(:fourth) + end + +end diff --git a/app/models/chouette/stif_reflex_objectid.rb b/app/models/chouette/stif_reflex_objectid.rb new file mode 100644 index 000000000..c41a9325a --- /dev/null +++ b/app/models/chouette/stif_reflex_objectid.rb @@ -0,0 +1,18 @@ +class Chouette::StifReflexObjectid < String + + @@format = /^([A-Za-z_]+):([0-9A-Za-z_-]+):([A-Za-z]+):([0-9A-Za-z_-]+):([A-Za-z]+)$/ + cattr_reader :format + + def parts + match(format).try(:captures) + end + + def object_type + parts.try(:third) + end + + def local_id + parts.try(:fourth) + end + +end diff --git a/app/models/chouette/stop_area.rb b/app/models/chouette/stop_area.rb index 4d98027d6..43bc82f7f 100644 --- a/app/models/chouette/stop_area.rb +++ b/app/models/chouette/stop_area.rb @@ -4,20 +4,16 @@ require 'geo_ruby' class Chouette::StopArea < Chouette::ActiveRecord # FIXME http://jira.codehaus.org/browse/JRUBY-6358 self.primary_key = "id" + include Geokit::Mappable + include StifReflexAttributesSupport include ProjectionFields include StopAreaRestrictions + include StopAreaReferentialSupport extend Enumerize enumerize :area_type, in: %i(zdep zder zdlp zdlr lda) - def self.model_name - ActiveModel::Name.new self, Chouette, self.name.demodulize - end - # Refs #1627 - # include DefaultAttributesSupport - include StopAreaReferentialSupport - with_options dependent: :destroy do |assoc| assoc.has_many :stop_points assoc.has_many :access_points @@ -57,13 +53,6 @@ class Chouette::StopArea < Chouette::ActiveRecord after_update :clean_invalid_access_links before_save :coordinates_to_lat_lng - # Refs #1627 - before_validation :prepare_auto_columns - def prepare_auto_columns - self.object_version = 1 - self.creator_id = 'chouette' - end - def combine_lat_lng if self.latitude.nil? || self.longitude.nil? "" diff --git a/app/models/chouette/stop_point.rb b/app/models/chouette/stop_point.rb index 3dbf6be0d..8fe79dc0c 100644 --- a/app/models/chouette/stop_point.rb +++ b/app/models/chouette/stop_point.rb @@ -36,12 +36,12 @@ module Chouette def stop_area_id_validation if stop_area_id.nil? - errors.add(:stop_area_id, I18n.t("errors.messages.empty")) + errors.add(:stop_area_id, I18n.t("stop_areas.errors.empty")) end end def self.area_candidates - Chouette::StopArea.where( :area_type => ['Quay', 'BoardingPosition']) + Chouette::StopArea.where(:area_type => ['Quay', 'BoardingPosition']) end end diff --git a/app/models/chouette/time_table.rb b/app/models/chouette/time_table.rb index d907d797e..713ce0b21 100644 --- a/app/models/chouette/time_table.rb +++ b/app/models/chouette/time_table.rb @@ -38,26 +38,26 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord validates_associated :periods def continuous_dates + in_days = self.dates.where(in_out: true).sort_by(&:date) chunk = {} group = nil - self.dates.where(in_out: true).each_with_index do |date, index| + in_days.each_with_index do |date, index| group ||= index - group = (date.date == dates[index - 1].date + 1.day) ? group : group + 1 + group = (date.date == in_days[index - 1].date + 1.day) ? group : group + 1 chunk[group] ||= [] chunk[group] << date end - chunk.values + # Remove less than 2 continuous day chunk + chunk.values.delete_if {|dates| dates.count < 2} end def convert_continuous_dates_to_periods chunks = self.continuous_dates - # Remove less than 3 continuous day chunk - chunks.delete_if {|chunk| chunk.count < 3} transaction do chunks.each do |chunk| self.periods.create!(period_start: chunk.first.date, period_end: chunk.last.date) - chunk.map(&:destroy) + self.dates.delete(chunk) end end end @@ -415,7 +415,7 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord def clone_periods periods = [] self.periods.each { |p| periods << p.copy} - periods + periods.sort_by(&:period_start) end def included_days @@ -436,7 +436,7 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord # produce a copy of periods without anyone overlapping or including another - def optimize_periods + def optimize_overlapping_periods periods = self.clone_periods optimized = [] i=0 @@ -461,6 +461,59 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord optimized.sort { |a,b| a.period_start <=> b.period_start} end + def continuous_periods + periods = self.periods.sort_by(&:period_start) + chunk = {} + group = nil + periods.each_with_index do |period, index| + group ||= index + group = (period.period_start - 1.day == periods[index - 1].period_end) ? group : group + 1 + chunk[group] ||= [] + chunk[group] << period + end + chunk.values.delete_if {|periods| periods.count < 2} + end + + def convert_continuous_periods_into_one + chunks = self.continuous_periods + + transaction do + chunks.each do |chunk| + self.periods.create!(period_start: chunk.first.period_start, period_end: chunk.last.period_end) + self.periods.delete chunk + end + end + end + + #update a period if a in_day is just before or after + def optimize_continuous_dates_and_periods + return self.periods if self.included_days.empty? || periods.empty? + + periods = self.clone_periods + optimized = [] + + i = 0 + while i < periods.length + period = periods[i] + j = 0 + in_days = self.reload.dates.where(in_out: true).sort_by(&:date) + while j < in_days.length + day = in_days[j] + if period.period_start - 1.day === day.date + period.period_start = day.date + self.dates.delete day + elsif period.period_end + 1.day === day.date + period.period_end = day.date + self.dates.delete day + end + j += 1 + end + i += 1 + optimized << period + end + optimized + end + # add a peculiar day or switch it from excluded to included def add_included_day(d) if self.excluded_date?(d) @@ -478,22 +531,27 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord def merge!(another_tt) transaction do self.periods = another_tt.clone_periods + self.periods - self.periods = self.optimize_periods # For included dates another_tt.included_days.map{ |d| add_included_day(d) } # For excluded dates - existing_out_date = self.dates.where(in_out: false).map(&:date) - another_tt.dates.where(in_out: false).each do |d| - unless existing_out_date.include?(d.date) - self.dates << Chouette::TimeTableDate.new(:date => d.date, :in_out => false) + self.dates.where(in_out: false).each do |d| + self.dates.delete d if another_tt.include_in_periods?(d.date) && !another_tt.excluded_date?(d.date) + end + + another_tt.excluded_days.each do |d| + unless self.reload.excluded_date?(d) + self.dates << Chouette::TimeTableDate.new(date: d, in_out: false) end + self.save! end - self.save! - end - self.convert_continuous_dates_to_periods + self.convert_continuous_dates_to_periods + self.periods = self.optimize_continuous_dates_and_periods + self.convert_continuous_periods_into_one + self.periods = self.optimize_overlapping_periods + end end def included_days_in_dates_and_periods diff --git a/app/models/chouette/vehicle_journey.rb b/app/models/chouette/vehicle_journey.rb index 71c339780..bc2713973 100644 --- a/app/models/chouette/vehicle_journey.rb +++ b/app/models/chouette/vehicle_journey.rb @@ -23,7 +23,10 @@ module Chouette validates_presence_of :route validates_presence_of :journey_pattern - validates :vehicle_journey_at_stops, :vjas_departure_time_must_be_before_next_stop_arrival_time, + validates :vehicle_journey_at_stops, + # Validation temporarily removed for day offsets + # :vjas_departure_time_must_be_before_next_stop_arrival_time, + vehicle_journey_at_stops_are_in_increasing_time_order: true validates_presence_of :number @@ -34,6 +37,12 @@ module Chouette before_validation :set_default_values, :calculate_vehicle_journey_at_stop_day_offset + # TODO: Remove this validator + # We've eliminated this validation because it prevented vehicle journeys + # from being saved with at-stops having a day offset greater than 0, + # because these would have times that were "earlier" than the previous + # at-stop. TBD by Luc whether we're deleting this validation altogether or + # instead rejiggering it to work with day offsets. def vjas_departure_time_must_be_before_next_stop_arrival_time notice = 'departure time must be before next stop arrival time' vehicle_journey_at_stops.each_with_index do |current_stop, index| @@ -142,7 +151,7 @@ module Chouette vj.update_attributes(state_permited_attributes(item)) vj.update_has_and_belongs_to_many_from_state(item) - item['errors'] = vj.errors if vj.errors.any? + item['errors'] = vj.errors.full_messages.uniq if vj.errors.any? end # Delete ids of new object from state if we had to rollback diff --git a/app/models/chouette/vehicle_journey_at_stop.rb b/app/models/chouette/vehicle_journey_at_stop.rb index 5dfec8352..35d94aa75 100644 --- a/app/models/chouette/vehicle_journey_at_stop.rb +++ b/app/models/chouette/vehicle_journey_at_stop.rb @@ -3,6 +3,8 @@ module Chouette include ForBoardingEnumerations include ForAlightingEnumerations + DAY_OFFSET_MAX = 1 + # FIXME http://jira.codehaus.org/browse/JRUBY-6358 self.primary_key = "id" @@ -24,11 +26,46 @@ module Chouette end end + validate :day_offset_must_be_within_range + after_initialize :set_virtual_attributes def set_virtual_attributes @_destroy = false @dummy = false end + def day_offset_must_be_within_range + if day_offset_outside_range?(arrival_day_offset) + errors.add( + :arrival_day_offset, + I18n.t( + 'vehicle_journey_at_stops.errors.day_offset_must_not_exceed_max', + local_id: vehicle_journey.objectid.local_id, + max: DAY_OFFSET_MAX + 1 + ) + ) + end + + if day_offset_outside_range?(departure_day_offset) + errors.add( + :departure_day_offset, + I18n.t( + 'vehicle_journey_at_stops.errors.day_offset_must_not_exceed_max', + local_id: vehicle_journey.objectid.local_id, + max: DAY_OFFSET_MAX + 1 + ) + ) + end + end + + def day_offset_outside_range?(offset) + # At-stops that were created before the database-default of 0 will have + # nil offsets. Handle these gracefully by forcing them to a 0 offset. + offset ||= 0 + + offset < 0 || offset > DAY_OFFSET_MAX + end + + end end diff --git a/app/models/clean_up.rb b/app/models/clean_up.rb index cdbf6c00a..b1135a155 100644 --- a/app/models/clean_up.rb +++ b/app/models/clean_up.rb @@ -14,7 +14,7 @@ class CleanUp < ActiveRecord::Base def end_date_must_be_greater_that_begin_date if self.end_date && self.date_type == 'between' && self.begin_date >= self.end_date - errors.add(:base, I18n.t('clean_ups.activerecord.errors.invalid_period')) + errors.add(:base, I18n.t('activerecord.errors.models.clean_up.invalid_period')) end end diff --git a/app/models/concerns/default_attributes_support.rb b/app/models/concerns/default_attributes_support.rb index 7928093e6..e85a59160 100644 --- a/app/models/concerns/default_attributes_support.rb +++ b/app/models/concerns/default_attributes_support.rb @@ -77,7 +77,8 @@ module DefaultAttributesSupport def build_objectid if objectid.include? ':__pending_id__' fix_uniq_objectid - update_attributes( :objectid => objectid, :object_version => (object_version - 1) ) + self.object_version = object_version - 1 + self.save(validate: false) end end diff --git a/app/models/concerns/stif_codifligne_attributes_support.rb b/app/models/concerns/stif_codifligne_attributes_support.rb new file mode 100644 index 000000000..d4370e505 --- /dev/null +++ b/app/models/concerns/stif_codifligne_attributes_support.rb @@ -0,0 +1,21 @@ +module StifCodifligneAttributesSupport + extend ActiveSupport::Concern + + included do + validates_presence_of :objectid + end + + module ClassMethods + def object_id_key + model_name + end + + def model_name + ActiveModel::Name.new self, Chouette, self.name.demodulize + end + end + + def objectid + Chouette::StifCodifligneObjectid.new read_attribute(:objectid).to_s + end +end diff --git a/app/models/concerns/stif_reflex_attributes_support.rb b/app/models/concerns/stif_reflex_attributes_support.rb new file mode 100644 index 000000000..e6236a146 --- /dev/null +++ b/app/models/concerns/stif_reflex_attributes_support.rb @@ -0,0 +1,21 @@ +module StifReflexAttributesSupport + extend ActiveSupport::Concern + + included do + validates_presence_of :objectid + end + + module ClassMethods + def object_id_key + model_name + end + + def model_name + ActiveModel::Name.new self, Chouette, self.name.demodulize + end + end + + def objectid + Chouette::StifReflexObjectid.new read_attribute(:objectid).to_s + end +end diff --git a/app/models/referential.rb b/app/models/referential.rb index ed23e2e51..cb2c7b23b 100644 --- a/app/models/referential.rb +++ b/app/models/referential.rb @@ -130,14 +130,13 @@ class Referential < ActiveRecord::Base self end - def self.new_from(from, organisation:) + def self.new_from(from) Referential.new( name: I18n.t("activerecord.copy", :name => from.name), slug: "#{from.slug}_clone", prefix: from.prefix, time_zone: from.time_zone, bounds: from.bounds, - organisation: organisation, line_referential: from.line_referential, stop_area_referential: from.stop_area_referential, workbench: from.workbench, @@ -186,7 +185,7 @@ class Referential < ActiveRecord::Base before_validation :clone_associations, :on => :create, if: :created_from before_validation :assign_slug, :on => :create before_validation :assign_prefix, :on => :create - before_create :create_schema, unless: :created_from + before_create :create_schema after_create :clone_schema, if: :created_from @@ -206,7 +205,6 @@ class Referential < ActiveRecord::Base end def clone_associations - self.organisation = created_from.organisation self.line_referential = created_from.line_referential self.stop_area_referential = created_from.stop_area_referential self.workbench = created_from.workbench diff --git a/app/models/user.rb b/app/models/user.rb index 64d66883f..c2aa14bda 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -29,29 +29,6 @@ class User < ActiveRecord::Base scope :with_organisation, -> { where.not(organisation_id: nil) } - def self.destructive_permissions_for(models) - models.product( %w{create destroy update} ).map{ |model_action| model_action.join('.') } - end - - @@edit_offer_permissions = - destructive_permissions_for( %w[ - access_points - connection_links - calendars - footnotes - journey_patterns - referentials - routes - routing_constraint_zones - time_tables - vehicle_journeys - ]) << 'boiv:edit-offer' - - mattr_reader :edit_offer_permissions - - def self.all_permissions - edit_offer_permissions - end # Callback invoked by DeviseCasAuthenticable::Model#authernticate_with_cas_ticket def cas_extra_attributes=(extra_attributes) @@ -59,7 +36,7 @@ class User < ActiveRecord::Base self.name = extra[:full_name] self.email = extra[:email] self.organisation = Organisation.sync_update extra[:organisation_code], extra[:organisation_name], extra[:functional_scope] - self.permissions = extra[:permissions].include?('boiv:edit-offer') ? @@edit_offer_permissions : [] + self.permissions = Stif::PermissionTranslator.translate(extra[:permissions]) end def self.portail_api_request @@ -87,7 +64,7 @@ class User < ActiveRecord::Base user.locked_at = el['locked_at'] user.organisation = Organisation.sync_update el['organization_code'], el['organization_name'], el['functional_scope'] user.synced_at = Time.now - user.permissions = el['permissions'].include?('boiv:edit-offer') ? @@edit_offer_permissions : [] + user.permissions = Stif::PermissionTranslator.translate(el['permissions']) user.save end end diff --git a/app/policies/login_policy.rb b/app/policies/login_policy.rb index 3364c37ac..5b07b97f3 100644 --- a/app/policies/login_policy.rb +++ b/app/policies/login_policy.rb @@ -7,7 +7,7 @@ class LoginPolicy end def boiv? - !(user.permissions || []).grep(%r{\Aboiv:.}).empty? + (user.permissions || []).include?('sessions:create') end end diff --git a/app/policies/referential_policy.rb b/app/policies/referential_policy.rb index 9d0a92093..fdc80516c 100644 --- a/app/policies/referential_policy.rb +++ b/app/policies/referential_policy.rb @@ -20,7 +20,7 @@ class ReferentialPolicy < ApplicationPolicy def clone? - !archived? && organisation_match? && create? + !archived? && create? end def archive? @@ -37,7 +37,3 @@ class ReferentialPolicy < ApplicationPolicy end end - - - - diff --git a/app/views/compliance_checks/detailed_errors_index.csv.slim b/app/views/compliance_checks/detailed_errors_index.csv.slim index 0b2c3f24f..7fe20e282 100644 --- a/app/views/compliance_checks/detailed_errors_index.csv.slim +++ b/app/views/compliance_checks/detailed_errors_index.csv.slim @@ -29,7 +29,7 @@ = error["source"]["file"]["line_number"] - else - = I18n.t("activemodel.attributes.compliance_check_result."+r.test_id); + = I18n.t("activemodel.attributes.compliance_check_result.#{r.test_id}"); = I18n.t("compliance_check_result.details.detail_#{error['error_id']}", object_labels_hash(error) ) = "\n" diff --git a/app/views/compliance_checks/summary_errors_index.csv.slim b/app/views/compliance_checks/summary_errors_index.csv.slim index bbb2c8c88..8c88d5cf6 100644 --- a/app/views/compliance_checks/summary_errors_index.csv.slim +++ b/app/views/compliance_checks/summary_errors_index.csv.slim @@ -16,7 +16,7 @@ = r.result; = r.test_id; - = I18n.t("activemodel.attributes.compliance_check_result." + r.test_id); + = I18n.t("activemodel.attributes.compliance_check_result.#{r.test_id}"); = Rails.application.config.validation_spec + I18n.locale.to_s + "/" + r.test_id + ".html"; = r.error_count diff --git a/app/views/layouts/navigation/_main_nav_left.html.slim b/app/views/layouts/navigation/_main_nav_left.html.slim index 3cf6428af..9dfc828c0 100644 --- a/app/views/layouts/navigation/_main_nav_left.html.slim +++ b/app/views/layouts/navigation/_main_nav_left.html.slim @@ -16,7 +16,7 @@ #miOne.panel-collapse.collapse .list-group - = link_to root_path, class: "list-group-item #{(@localizationUrl == 'referentials#index') ? 'active' : ''}" do + = link_to root_path, class: "list-group-item #{(@localizationUrl == 'workbenches#index') ? 'active' : ''}" do span Tableau de bord = link_to '#', class: 'list-group-item' do span Offre de mon organisation diff --git a/app/views/referential_stop_areas/index.html.slim b/app/views/referential_stop_areas/index.html.slim index 1cbe1945f..7bf39eabd 100644 --- a/app/views/referential_stop_areas/index.html.slim +++ b/app/views/referential_stop_areas/index.html.slim @@ -4,7 +4,7 @@ .panel.panel-default .panel-heading .input-group.col-md-9.col-sm-9 - = f.text_field :name_or_objectid_cont, placeholder: t('.name_or_objectid'), class: 'form-control' + = f.text_field :name_or_objectid_cont, placeholder: t('stop_areas.filters.name_or_objectid'), class: 'form-control' .input-group-btn button.btn.btn-primary#search-btn type="submit" span.fa.fa-search diff --git a/app/views/referentials/show.html.slim b/app/views/referentials/show.html.slim index d3687c3a7..425f8014a 100644 --- a/app/views/referentials/show.html.slim +++ b/app/views/referentials/show.html.slim @@ -91,9 +91,13 @@ .row .col-lg-8.col-ld-offset-2.col-md-8.col-md-offset-2.col-sm-8.col-sm-offset-2.col-xs-12 = f.input :date_type, as: :radio_buttons, label: false - = f.input :begin_date, as: :date, label: t('titles.clean_up.begin_date'),:wrapper_html => { class: 'date smart_date', title: t('titles.clean_up.begin_date') } - = f.input :end_date, as: :date, label: t('titles.clean_up.end_date'), :wrapper_html => { class: 'date cleanup_end_date_wrapper smart_date', title: t('titles.clean_up.end_date'), id: "end_date" } + .col-lg-8.col-ld-offset-2.col-md-8.col-md-offset-2.col-sm-8.col-sm-offset-2.col-xs-12 + label.control-label.begin_date = t('titles.clean_up.begin_date') + label.control-label.end_date.hidden = t('titles.clean_up.end_date') + = f.input :begin_date, as: :date, label: false, wrapper_html: { class: 'date smart_date' } + + = f.input :end_date, as: :date, label: t('titles.clean_up.end_date'), wrapper_html: { class: 'date cleanup_end_date_wrapper smart_date', id: "end_date" } .modal-footer button.btn.btn-link type='button' data-dismiss='modal' Annuler diff --git a/app/views/stop_area_copies/new.html.slim b/app/views/stop_area_copies/new.html.slim index 1a8764cbc..b506d35f4 100644 --- a/app/views/stop_area_copies/new.html.slim +++ b/app/views/stop_area_copies/new.html.slim @@ -1,4 +1,4 @@ -= title_tag t("stop_area_copies.new.title."+@stop_area_copy.hierarchy) += title_tag t("stop_area_copies.new.title.#{@stop_area_copy.hierarchy}") = semantic_form_for [@referential, @stop_area, @stop_area_copy] do |form| br diff --git a/app/views/time_tables/_filter.html.slim b/app/views/time_tables/_filter.html.slim index 1015eca31..392dc4f50 100644 --- a/app/views/time_tables/_filter.html.slim +++ b/app/views/time_tables/_filter.html.slim @@ -7,10 +7,6 @@ span.fa.fa-search .ffg-row - / .form-group.togglable - / = f.label Chouette::TimeTable.human_attribute_name(:color), required: false, class: 'control-label' - / = f.input :color_cont_any, collection: ["#9B9B9B", "#FFA070", "#C67300", "#7F551B", "#41CCE3", "#09B09C", "#3655D7", "#6321A0", "#E796C6", "#DD2DAA"], as: :check_boxes, label: false, label_method: lambda{|tt| ("<span style='height:19px;'><span class='fa fa-circle' style='position:relative;top:0;margin-top:0;color:" + tt + "'></span></span>").html_safe }, required: false, wrapper_html: { class: 'checkbox_list' } - .form-group = f.label Chouette::TimeTable.human_attribute_name(:tag_search), required: false, class: 'control-label' = f.input :tag_search, as: :tags, collection: Chouette::TimeTable.tags_on(:tags).pluck(:name), label: false, input_html: { 'data-select2ed': 'true', 'data-select2ed-placeholder': 'Indiquez une étiquette...' }, wrapper_html: { class: 'select2ed'}, include_blank: false diff --git a/app/views/time_tables/time_tables.json.rabl b/app/views/time_tables/time_tables.json.rabl index dec29cb69..b91ca9ae9 100644 --- a/app/views/time_tables/time_tables.json.rabl +++ b/app/views/time_tables/time_tables.json.rabl @@ -2,4 +2,4 @@ collection @time_tables, :object_root => false node do |time_table| { :id => time_table.id, :comment => time_table.comment, :time_table_bounding => time_table_bounding( time_table), :composition_info => composition_info(time_table) } -end +end diff --git a/app/views/workbenches/index.html.slim b/app/views/workbenches/index.html.slim new file mode 100644 index 000000000..ca61d439d --- /dev/null +++ b/app/views/workbenches/index.html.slim @@ -0,0 +1,67 @@ +/ PageHeader += pageheader 'map-marker', + t('.title', organisation: current_organisation.name) + +/ PageContent +.page_content + .container-fluid + .row + .col-lg-12 + h2.content_header = t('.offers.title') + + .row + .col-lg-6.col-md-6.col-sm-6.col-xs-12 + .panel.panel-default + .panel-heading + h3.panel-title + = t('.offers.organisation') + + .panel-body + em.small.text-muted = t('.offers.no_content') + + .panel.panel-default + .panel-heading + h3.panel-title + = t('.offers.idf') + + .panel-body + em.small.text-muted = t('.offers.no_content') + + .col-lg-6.col-md-6.col-sm-6.col-xs-12 + .panel.panel-default + .panel-heading + h3.panel-title.with_actions + div + = t('.offers.referentials') + span.badge.ml-xs = @referentials.count if @referentials.any? + + div + = link_to '', workbench_path(@workbench), class: ' fa fa-chevron-right pull-right', title: t('.offers.see') + + - if @referentials.any? + .list-group + - @referentials.each_with_index do |referential, i| + = link_to referential.name, referential_path(referential), class: 'list-group-item' if i < 6 + + - else + .panel-body + em.small.text-muted = t('.offers.no_content') + + .panel.panel-default + .panel-heading + h3.panel-title.with_actions + div + = t('.offers.calendars') + span.badge.ml-xs = @calendars.count if @calendars.any? + + div + = link_to '', calendars_path, class: ' fa fa-chevron-right pull-right', title: t('.offers.see') + + - if @calendars.any? + .list-group + - @calendars.each_with_index do |calendar, i| + = link_to calendar.name, calendar_path(calendar), class: 'list-group-item' if i < 6 + + - else + .panel-body + em.small.text-muted = t('.offers.no_content') diff --git a/app/views/workbenches/show.html.slim b/app/views/workbenches/show.html.slim index bb8b71ab2..a9ce2f704 100644 --- a/app/views/workbenches/show.html.slim +++ b/app/views/workbenches/show.html.slim @@ -7,8 +7,8 @@ / Below is secundary actions & optional contents (filters, ...) .row.mb-sm .col-lg-12.text-right - = link_to t('actions.import'), workbench_imports_path(@workbench), class: 'btn btn-primary' - if policy(Referential).create? + = link_to t('actions.import'), workbench_imports_path(@workbench), class: 'btn btn-primary' = link_to t('actions.add'), new_referential_path(workbench_id: @workbench), class: 'btn btn-primary' / PageContent diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index 88c02341b..19a919cc2 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -1,9 +1,9 @@ # i18n-tasks finds and manages missing and unused translations: https://github.com/glebm/i18n-tasks # The "main" locale. -base_locale: en +base_locale: fr ## All available locales are inferred from the data by default. Alternatively, specify them explicitly: -# locales: [es, fr] +locales: [en, fr] ## Reporting locale, default: en. Available: en, ru. # internal_locale: en @@ -18,7 +18,6 @@ data: ## Default: - config/locales/%{locale}.yml ## More files: - - config/locales/*.%{locale}.yml - config/locales/**/*.%{locale}.yml ## Another gem (replace %#= with %=): # - "<%#= %x[bundle show vagrant].chomp %>/templates/locales/%{locale}.yml" @@ -27,13 +26,12 @@ data: # `i18n-tasks normalize -p` will force move the keys according to these rules write: ## For example, write devise and simple form keys to their respective files: - - ['{devise}.*', 'config/locales/devise.%{locale}.yml'] - - ['{simple_form}.*', 'config/locales/simple_form.%{locale}.yml'] + - ['{devise, simple_form}.*', 'config/locales/\1.%{locale}.yml'] ## Catch-all default: - config/locales/%{locale}.yml ## Specify the router (see Readme for details). Valid values: conservative_router, pattern_router, or a custom class. - # router: convervative_router + # router: conservative_router yaml: write: @@ -68,13 +66,18 @@ search: - app/assets/images - app/assets/fonts - app/assets/javascripts + - app/assets/videos ## Alternatively, the only files or `File.fnmatch patterns` to search in `paths`: ## If specified, this settings takes priority over `exclude`, but `exclude` still applies. - # include: ["*.rb", "*.html.slim"] + # only: ["*.rb", "*.html.slim"] - ## Default scanner finds t() and I18n.t() calls. - # scanner: I18n::Tasks::Scanners::PatternWithScopeScanner + ## If `strict` is `false`, guess usages such as t("categories.#{category}.title"). The default is `true`. + # strict: true + + ## Multiple scanners can be used. Their results are merged. + ## The options specified above are passed down to each scanner. Per-scanner options can be specified as well. + ## See this example of a custom scanner: https://github.com/glebm/i18n-tasks/wiki/A-custom-scanner-example ## Google Translate # translation: @@ -104,3 +107,16 @@ search: ## Ignore these keys completely: # ignore: # - kaminari.* + +## Sometimes, it isn't possible for i18n-tasks to match the key correctly, +## e.g. in case of a relative key defined in a helper method. +## In these cases you can use the built-in PatternMapper to map patterns to keys, e.g.: +# +# <%# I18n::Tasks.add_scanner 'I18n::Tasks::Scanners::PatternMapper', +# only: %w(*.html.haml *.html.slim), +# patterns: [['= title\b', '.page_title']] %> +# +# The PatternMapper can also match key literals via a special %{key} interpolation, e.g.: +# +# <%# I18n::Tasks.add_scanner 'I18n::Tasks::Scanners::PatternMapper', +# patterns: [['\bSpree\.t[( ]\s*%{key}', 'spree.%{key}']] %> diff --git a/config/locales/actions.en.yml b/config/locales/actions.en.yml index cffd04fcf..f6979136a 100644 --- a/config/locales/actions.en.yml +++ b/config/locales/actions.en.yml @@ -4,6 +4,7 @@ en: destroy: "Destroy" delete: "Delete" search: "Search" + submit: "Submit" add: "Add new" new: "Add new" show: "See" diff --git a/config/locales/calendars.en.yml b/config/locales/calendars.en.yml index f6c5ba852..cb1ede4c7 100644 --- a/config/locales/calendars.en.yml +++ b/config/locales/calendars.en.yml @@ -9,6 +9,19 @@ en: friday: F saturday: Sa sunday: Su + months: + 1: January + 2: February + 3: March + 4: April + 5: May + 6: June + 7: July + 8: August + 9: September + 10: October + 11: November + 12: December standard_calendars: Standard calendars standard_calendar: Standard calendar actions: diff --git a/config/locales/clean_ups.en.yml b/config/locales/clean_ups.en.yml index a05750f6d..fcfcfec7b 100644 --- a/config/locales/clean_ups.en.yml +++ b/config/locales/clean_ups.en.yml @@ -24,9 +24,9 @@ en: end_date: "End date of clean up" activerecord: errors: - invalid_period: "Invalid period : the end date must be strictly greater than the begin date" models: clean_up: + invalid_period: "Invalid period : the end date must be strictly greater than the begin date" attributes: date_type: presence: "A clean up must have a date type" diff --git a/config/locales/clean_ups.fr.yml b/config/locales/clean_ups.fr.yml index 77e07591b..e2db82998 100644 --- a/config/locales/clean_ups.fr.yml +++ b/config/locales/clean_ups.fr.yml @@ -23,9 +23,9 @@ fr: end_date: "Date de fin de la purge" activerecord: errors: - invalid_period: "Période invalide : tLa date de fin doit être strictement supérieure à la date de début" models: clean_up: + invalid_period: "Période invalide : La date de fin doit être strictement supérieure à la date de début" attributes: date_type: presence: "Une purge doit avoir un type de renseigné" diff --git a/config/locales/en.yml b/config/locales/en.yml index 0a6002175..b25f5fd7f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -14,6 +14,38 @@ en: formats: short: "%Y/%m/%d" short_with_time: "%Y/%m/%d at %Hh%M" + abbr_day_names: + - Sun + - Mon + - Tue + - Wed + - Thu + - Fri + - Sat + day_names: + - Sunday + - Monday + - Tuesday + - Wednesday + - Thursday + - Friday + - Saturday + month_names: + - + - January + - February + - March + - April + - May + - June + - July + - August + - September + - October + - November + - December + errors: + format: "%{message}" last_update: 'Last update on<br>%{time}' last_sync: 'Last sync on %{time}' diff --git a/config/locales/enumerize.en.yml b/config/locales/enumerize.en.yml index f76237288..0bc3e5edc 100644 --- a/config/locales/enumerize.en.yml +++ b/config/locales/enumerize.en.yml @@ -114,6 +114,7 @@ en: transport_mode: interchange: Interchange unknown: "unknown" + undefined: "undefined" air: "Air" train: "Train" long_distance_train: "Long distance train" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 3d5dc4c2c..8ef183d91 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -14,6 +14,36 @@ fr: formats: short: "%d/%m/%Y" short_with_time: "%d/%m/%Y à %Hh%M" + abbr_day_names: + - dim + - lun + - mar + - mer + - jeu + - ven + - sam + day_names: + - dimanche + - lundi + - mardi + - mercredi + - jeudi + - vendredi + - samedi + month_names: + - + - janvier + - février + - mars + - avril + - mai + - juin + - juillet + - août + - septembre + - octobre + - novembre + - décembre errors: format: "%{message}" @@ -25,3 +55,4 @@ fr: id_codif: 'ID Codifligne' id_reflex: 'ID Reflex' + objectid: 'ID' diff --git a/config/locales/imports.en.yml b/config/locales/imports.en.yml index a5eb0f969..b20f0f1da 100644 --- a/config/locales/imports.en.yml +++ b/config/locales/imports.en.yml @@ -7,6 +7,8 @@ en: index: title: "Imports" warning: "" + new: + title: "Imports" show: report: "Report" imported_file: "Original file" diff --git a/config/locales/imports.fr.yml b/config/locales/imports.fr.yml index 8fe8817f5..933025c82 100644 --- a/config/locales/imports.fr.yml +++ b/config/locales/imports.fr.yml @@ -7,6 +7,8 @@ fr: index: title: "Imports" warning: "" + new: + title: "Imports" show: report: "Rapport" imported_file: "Fichier source" diff --git a/config/locales/mailers.en.yml b/config/locales/mailers.en.yml index d4bd45129..9f89c9d46 100644 --- a/config/locales/mailers.en.yml +++ b/config/locales/mailers.en.yml @@ -4,6 +4,6 @@ en: created: subject: A new shared calendar has been created body: A new shared calendar% {cal_name} has been added by STIF. You can now view it in the list of shared calendars %{cal_index_url} - created: + updated: subject: A shared calendar has been updated body: A new shared calendar% {cal_name} has been updated by STIF. You can now view it in the list of shared calendars %{cal_index_url} diff --git a/config/locales/referentials.en.yml b/config/locales/referentials.en.yml index 7a4c60869..5f39f03f4 100644 --- a/config/locales/referentials.en.yml +++ b/config/locales/referentials.en.yml @@ -1,6 +1,6 @@ en: referentials: - filter: + filters: name_or_number_or_objectid: 'Search by name, number or objectid' search_no_results: 'No data space matching your query' index: @@ -41,6 +41,7 @@ en: user_excluded: "%{user} is a reserved value" overlapped_referential: "%{referential} cover the same perimeter" overlapped_period: "Another period is on the same period" + short_period: Min period length is two days activerecord: models: referential: diff --git a/config/locales/routes.en.yml b/config/locales/routes.en.yml index d8160772f..3099d4ab1 100644 --- a/config/locales/routes.en.yml +++ b/config/locales/routes.en.yml @@ -84,9 +84,3 @@ en: hub: route: objectid: "[prefix]:Route:[unique_key] : prefix contains only alphanumerical or underscore characters, unique_key accepts also minus character. Maximum length of the unique key = 8." - - # simpleform - helpers: - submit: - route: - create: 'Create route' diff --git a/config/locales/routing_constraint_zones.en.yml b/config/locales/routing_constraint_zones.en.yml index 59d4484a8..836705a6a 100644 --- a/config/locales/routing_constraint_zones.en.yml +++ b/config/locales/routing_constraint_zones.en.yml @@ -24,9 +24,6 @@ en: routing_constraint_zones: search_no_results: "No ITL matches your query" actions: - new: New routing constraint zone - edit: Edit this routing constraint zone - destroy: Delete this routing constraint zone destroy_confirm: Are you sure you want to delete this routing constraint zone? new: title: Add a new routings constraint zone diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index f6c0079ee..ad722312e 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -7,21 +7,11 @@ en: required: text: 'Required field' mark: '*' - # You can uncomment the line below if you need to overwrite the whole required html. - # When using html, text and mark won't be used. - # html: '<abbr title="required">*</abbr>' error_notification: default_message: "Please review the problems below:" - # Labels and hints examples - # labels: - # defaults: - # password: 'Password' - # user: - # new: - # email: 'E-mail to sign in.' - # edit: - # email: 'E-mail.' - # hints: - # defaults: - # username: 'User name to sign in.' - # password: 'No special characters, please.' + + helpers: + submit: + create: Submit + edit: Edit + update: Edit diff --git a/config/locales/simple_form.fr.yml b/config/locales/simple_form.fr.yml index 2a6893595..cd5dd1fbe 100644 --- a/config/locales/simple_form.fr.yml +++ b/config/locales/simple_form.fr.yml @@ -15,16 +15,3 @@ fr: create: Valider edit: Editer update: Editer - # Labels and hints examples - # labels: - # defaults: - # password: 'Password' - # user: - # new: - # email: 'E-mail to sign in.' - # edit: - # email: 'E-mail.' - # hints: - # defaults: - # username: 'User name to sign in.' - # password: 'No special characters, please.' diff --git a/config/locales/stop_areas.en.yml b/config/locales/stop_areas.en.yml index 3d6b65350..324294892 100644 --- a/config/locales/stop_areas.en.yml +++ b/config/locales/stop_areas.en.yml @@ -1,6 +1,8 @@ en: stop_areas: &en_stop_areas search_no_results: "No stop area matching your query" + errors: + empty: Aucun stop_area_id default_geometry_success: "%{count} modified stop areas" stop_area: no_position: "No Position" @@ -90,6 +92,7 @@ en: registration_number: "Registration number" published_name: "Published name" deleted: "Deleted" + deleted_at: "Deleted at" comment: "Description" stop_area_type: "Area type" area_type: "Area type" @@ -179,5 +182,6 @@ en: comment: "Maximum length = 255." coordinates: "Coordinates are mandatory." projection_xy: "x,y in secondary referential, dot for decimal separator" + referential_stop_areas: <<: *en_stop_areas diff --git a/config/locales/stop_areas.fr.yml b/config/locales/stop_areas.fr.yml index 3e49cdf7c..216516e5b 100644 --- a/config/locales/stop_areas.fr.yml +++ b/config/locales/stop_areas.fr.yml @@ -1,6 +1,8 @@ fr: stop_areas: &fr_stop_areas search_no_results: "Aucun arrêt ne correspond à votre recherche" + errors: + empty: Aucun stop_area_id default_geometry_success: "%{count} arrêts édités" stop_area: no_position: "Pas de position" @@ -14,6 +16,7 @@ fr: new: "Ajouter un arrêt" edit: "Editer cet arrêt" destroy: "Supprimer cet arrêt" + deleted_at: "Activé" destroy_confirm: "Etes vous sûr de supprimer cet arrêt ainsi que tous ses fils?" select_parent: "Créer ou éditer la relation enfant -> parent" add_children: "Créer ou éditer la relation parent -> enfants" diff --git a/config/locales/time_tables.en.yml b/config/locales/time_tables.en.yml index dc6c6d9f4..24750f0af 100644 --- a/config/locales/time_tables.en.yml +++ b/config/locales/time_tables.en.yml @@ -24,6 +24,8 @@ en: success: "Actualize succeded" new: title: "Add a new timetable" + duplicate: + title: "Duplicate timetable" edit: title: "Update timetable %{time_table}" show: diff --git a/config/locales/vehicle_journey_at_stops.en.yml b/config/locales/vehicle_journey_at_stops.en.yml new file mode 100644 index 000000000..a96effa2b --- /dev/null +++ b/config/locales/vehicle_journey_at_stops.en.yml @@ -0,0 +1,4 @@ +en: + vehicle_journey_at_stops: + errors: + day_offset_must_not_exceed_max: "The vehicle journey with ID %{local_id} cannot have times exceeding %{max} days" diff --git a/config/locales/vehicle_journey_at_stops.fr.yml b/config/locales/vehicle_journey_at_stops.fr.yml new file mode 100644 index 000000000..3eff79cf4 --- /dev/null +++ b/config/locales/vehicle_journey_at_stops.fr.yml @@ -0,0 +1,4 @@ +fr: + vehicle_journey_at_stops: + errors: + day_offset_must_not_exceed_max: "La course avec l'identifiant %{local_id} ne peut pas avoir des horaires sur plus de %{max} jours" diff --git a/config/locales/workbenches.en.yml b/config/locales/workbenches.en.yml new file mode 100644 index 000000000..8525a4b9f --- /dev/null +++ b/config/locales/workbenches.en.yml @@ -0,0 +1,12 @@ +en: + workbenches: + index: + title: "%{organisation} dashboard" + offers: + title: "Transport offers" + organisation: "Organisation offers" + idf: "IDF offers" + referentials: "Referentials" + calendars: "Calendars" + see: "See the list" + no_content: "No content yet." diff --git a/config/locales/workbenches.fr.yml b/config/locales/workbenches.fr.yml new file mode 100644 index 000000000..1cdc19a13 --- /dev/null +++ b/config/locales/workbenches.fr.yml @@ -0,0 +1,12 @@ +fr: + workbenches: + index: + title: "Tableau de bord %{organisation}" + offers: + title: "Offres de transport" + organisation: "Offres de mon organisation" + idf: "Offres IDF" + referentials: "Jeux de données" + calendars: "Calendriers" + see: "Voir la liste" + no_content: "Aucun contenu pour le moment" diff --git a/config/routes.rb b/config/routes.rb index aa6713857..28c092e6a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,7 @@ require 'sidekiq/web' ChouetteIhm::Application.routes.draw do - resources :workbenches, :only => [:show] do + resources :workbenches, only: [:show, :index] do delete :referentials, on: :member, action: :delete_referentials resources :imports do get :download, on: :member @@ -14,7 +14,7 @@ ChouetteIhm::Application.routes.draw do devise_scope :user do authenticated :user do - root :to => 'referentials#index', as: :authenticated_root + root :to => 'workbenches#index', as: :authenticated_root end unauthenticated :user do @@ -76,7 +76,7 @@ ChouetteIhm::Application.routes.draw do get :autocomplete, on: :collection, controller: 'autocomplete_calendars' end - resources :referentials do + resources :referentials, except: :index do resources :api_keys resources :autocomplete_stop_areas, only: [:show, :index] do get 'around', on: :member @@ -213,7 +213,8 @@ ChouetteIhm::Application.routes.draw do end end end - root :to => "referentials#index" + + root :to => "workbenches#index" get '/help/(*slug)' => 'help#show' diff --git a/config/sidekiq.yml b/config/sidekiq.yml new file mode 100644 index 000000000..be0fceb30 --- /dev/null +++ b/config/sidekiq.yml @@ -0,0 +1,5 @@ +:concurrency: 5 +:pidfile: tmp/pids/sidekiq.pid +:queues: + - default + - mailers diff --git a/lib/stif/permission_translator.rb b/lib/stif/permission_translator.rb index 7032f910a..afe69756e 100644 --- a/lib/stif/permission_translator.rb +++ b/lib/stif/permission_translator.rb @@ -1,7 +1,45 @@ module Stif module PermissionTranslator extend self + def translate(sso_extra_permissions) - %w{sessions:create} + sso_extra_permissions + .sort + .flat_map(&method(:extra_permission_translation)) + .uniq + end + + private + + def all_destructive_permissions + destructive_permissions_for( all_resources ) + end + + def all_resources + %w[ + access_points + connection_links calendars + footnotes + journey_patterns + referentials routes routing_constraint_zones + time_tables + vehicle_journeys + ] + end + + def destructive_permissions_for(models) + @__destructive_permissions_for__ ||= + models.product( %w{create destroy update} ).map{ |model_action| model_action.join('.') } + end + + def extra_permission_translation extra_permission + translation_table.fetch(extra_permission, []) + end + + def translation_table + { + "boiv:read-offer" => %w{sessions:create}, + "boiv:edit-offer" => all_destructive_permissions + %w{sessions:create}, + } end end end diff --git a/lib/tasks/generate.rake b/lib/tasks/generate.rake index 4b1e98ca4..f02a75cc2 100644 --- a/lib/tasks/generate.rake +++ b/lib/tasks/generate.rake @@ -1,12 +1,9 @@ namespace :generate do - + desc "Create model diagrams for Chouette" task :model_diagram => :environment do - sh "bundle exec rake erd orientation=horizontal title='Chouette v2.5.2 model diagram (part 1)' only='Organisation,Referential,Export,Api::V1::ApiKey,ExportLogMessage,Import,RuleParameterSet,Validation,User' filename='model-diagram-part-1'" - - sh "bundle exec rake erd:generate orientation=horizontal title='Chouette v2.5.2 model diagram (part 2)' exclude='Organisation,Referential,Export,Api::V1::ApiKey,ExportLogMessage,Import,RuleParameterSet, Validation,User,NetexImport,NeptuneImport,GtfsImport,CsvImport,Delayed::Backend::ActiveRecord::Job' filename='model-diagram-part-2'" - - sh "bundle exec rake erd:generate orientation=horizontal title='Chouette v2.5.2 model diagram (part 3)' only='NetexImport,NeptuneImport,GtfsImport,CsvImport,Delayed::Backend::ActiveRecord::Job' filename='model-diagram-part-3'" + sh "bundle exec rake erd only='Calendar,Referential,Chouette::Line,Chouette::Route,Chouette::JourneyPattern,Chouette::VehicleJourney,Chouette::VehicleJourneyAtStop,Chouette::TimeTable,Chouette::TimeTableDate,Chouette::TimeTablePeriod,Chouette::Footnote,Chouette::Network,Chouette::Company,Chouette::StopPoint,Chouette::StopArea' filename='offer_datas' title='Offer Datas'" + sh "bundle exec rake erd only='Organisation,Referential,User,Workbench' filename='organisation' title='Organisation'" end - + end diff --git a/spec/controllers/devise/cas_sessions_controller_spec.rb b/spec/controllers/devise/cas_sessions_controller_spec.rb index 950d141fd..c82fd2cdb 100644 --- a/spec/controllers/devise/cas_sessions_controller_spec.rb +++ b/spec/controllers/devise/cas_sessions_controller_spec.rb @@ -1,25 +1,37 @@ RSpec.describe Devise::CasSessionsController, type: :controller do - login_user + before do + @user = signed_in_user + allow_any_instance_of(Warden::Proxy).to receive(:authenticate).and_return @user + allow_any_instance_of(Warden::Proxy).to receive(:authenticate!).and_return @user + @request.env["devise.mapping"] = Devise.mappings[:user] + end + context 'login is correctly redirected' do + let( :signed_in_user ){ build_stubbed :user } it 'to #service' do get :new - expect(response).to redirect_to(unauthenticated_root_path) + expect( response ).to be_redirect + expect( response.redirect_url ).to eq("http://stif-portail-dev.af83.priv/sessions/login?service=http%3A%2F%2Ftest.host%2Fusers%2Fservice") end end - context 'user does not have any boiv:.+ permission' do - xit 'cannot login and will be redirected to the login page, with a corresponding message' do + context 'user does not have permission sessions:create' do + let( :signed_in_user ){ build_stubbed :user } + + it 'cannot login and will be redirected to the login page, with a corresponding message' do get :service expect(controller).to set_flash[:alert].to(%r{IBOO}) - expect(response).to redirect_to("http://stif-portail-dev.af83.priv/sessions/login?service=http%3A%2F%2Ftest.host%2Fusers%2Fservice") + expect(response).to redirect_to "http://stif-portail-dev.af83.priv/sessions/logout?service=http%3A%2F%2Ftest.host%2Fusers%2Fservice" end end - context 'user does have a boiv:.+ permission' do + context 'user does have permission sessions:create' do + let( :signed_in_user ){ build_stubbed :allmighty_user } + it 'can login and will be redirected to the referentials page' do - @user.update_attribute :permissions, (@user.permissions << 'boiv:UnameIt') + @user.permissions << 'sessions:create' get :service expect(response).to redirect_to(authenticated_root_path) end diff --git a/spec/decorators/referential_decorator_spec.rb b/spec/decorators/referential_decorator_spec.rb index 5de6b7e95..16da8d30b 100644 --- a/spec/decorators/referential_decorator_spec.rb +++ b/spec/decorators/referential_decorator_spec.rb @@ -25,7 +25,7 @@ RSpec.describe ReferentialDecorator, type: [:helper, :decorator] do end end - context 'all rights and different organisation' do + context 'all rights and different organisation' do let( :user ){ build_stubbed :allmighty_user } @@ -33,10 +33,11 @@ RSpec.describe ReferentialDecorator, type: [:helper, :decorator] do expect_action_link_elements.to be_empty expect_action_link_hrefs.to eq([ referential_time_tables_path(object), + new_referential_path(from: object), ]) end end - context 'all rights and same organisation' do + context 'all rights and same organisation' do let( :user ){ build_stubbed :allmighty_user, organisation: referential.organisation } diff --git a/spec/lib/stif/permission_translator_spec.rb b/spec/lib/stif/permission_translator_spec.rb index 3672c7937..1af21364c 100644 --- a/spec/lib/stif/permission_translator_spec.rb +++ b/spec/lib/stif/permission_translator_spec.rb @@ -1,10 +1,45 @@ RSpec.describe Stif::PermissionTranslator do - context "SSO Permission boiv:read:offer →" do + context "No SSO Permissions" do + it { expect(described_class.translate([])).to be_empty } + end + + context "SSO Permission boiv:read-offer →" do it "sessions:create only" do - expect( described_class.translate(%w{boiv:read:offer}) ).to eq(%w{sessions:create}) + expect( described_class.translate(%w{boiv:read-offer}) ).to eq(%w{sessions:create}) + end + + end + + context "SSO Permission boiv:edit-offer →" do + + it "all permissions" do + expect( described_class.translate(%w{boiv:edit-offer}) ).to eq(Support::Permissions.all_permissions) + end + + it "all permissions, no doubletons" do + expect( described_class.translate(%w{boiv:edit-offer boiv:read-offer}) ).to eq(Support::Permissions.all_permissions) end + it "all permissions, input order agnostic" do + expect( described_class.translate(%w{boiv:read-offer boiv:edit-offer}) ).to eq(Support::Permissions.all_permissions) + end + end + + context "SSO Permission ignores garbage (no injection) →" do + it "remains empty" do + expect( described_class.translate(%w{referentials.create}) ).to be_empty + end + + it "remains at boiv:read-offer level" do + expect( described_class.translate(%w{referentials.create boiv:read-offer calendars.delete}) ).to eq(%w{sessions:create}) + end + + it "does not add garbage or doubletons for boiv:edit-offer level" do + expect( + described_class.translate(%w{xxx boiv:read-offer lines.delete boiv:edit-offer footnotes.update}) + ).to eq(Support::Permissions.all_permissions) + end end end diff --git a/spec/models/calendar_observer_spec.rb b/spec/models/calendar_observer_spec.rb index abb462d25..4fba02bef 100644 --- a/spec/models/calendar_observer_spec.rb +++ b/spec/models/calendar_observer_spec.rb @@ -12,14 +12,14 @@ RSpec.describe CalendarObserver, type: :observer do it 'should schedule mailer on calendar update' do calendar.name = 'edited_name' - expect(MailerJob).to receive(:perform_later).with 'CalendarMailer', 'updated', [calendar, user] + expect(MailerJob).to receive(:perform_later).with 'CalendarMailer', 'updated', [calendar.id, user.id] calendar.save end it 'should not schedule mailer for none shared calendar on update' do calendar = create(:calendar, shared: false) calendar.name = 'edited_name' - expect(MailerJob).to_not receive(:perform_later).with 'CalendarMailer', 'updated', [calendar, user] + expect(MailerJob).to_not receive(:perform_later).with 'CalendarMailer', 'updated', [calendar.id, user.id] calendar.save end end @@ -31,12 +31,12 @@ RSpec.describe CalendarObserver, type: :observer do end it 'should schedule mailer on calendar create' do - expect(MailerJob).to receive(:perform_later).with 'CalendarMailer', 'created', [anything, user] + expect(MailerJob).to receive(:perform_later).with 'CalendarMailer', 'created', [anything, user.id] build(:calendar, shared: true).save end it 'should not schedule mailer for none shared calendar on create' do - expect(MailerJob).to_not receive(:perform_later).with 'CalendarMailer', 'created', [anything, user] + expect(MailerJob).to_not receive(:perform_later).with 'CalendarMailer', 'created', [anything, user.id] build(:calendar, shared: false).save end end diff --git a/spec/models/chouette/line_spec.rb b/spec/models/chouette/line_spec.rb index 5a339e7ed..2e5882012 100644 --- a/spec/models/chouette/line_spec.rb +++ b/spec/models/chouette/line_spec.rb @@ -1,17 +1,12 @@ require 'spec_helper' describe Chouette::Line, :type => :model do - subject { create(:line) } - it { is_expected.to belong_to(:line_referential) } + it { should belong_to(:line_referential) } # it { is_expected.to validate_presence_of :network } # it { is_expected.to validate_presence_of :company } - - it { is_expected.to validate_presence_of :name } - - # it { should validate_presence_of :objectid } - it { is_expected.to validate_uniqueness_of :objectid } + it { should validate_presence_of :name } describe '#display_name' do it 'should display local_id, number, name and company name' do @@ -22,7 +17,7 @@ describe Chouette::Line, :type => :model do describe '#objectid' do subject { super().objectid } - it { is_expected.to be_kind_of(Chouette::NetexObjectId) } + it { is_expected.to be_kind_of(Chouette::StifCodifligneObjectid) } end # it { should validate_numericality_of :objectversion } diff --git a/spec/models/chouette/stop_area_spec.rb b/spec/models/chouette/stop_area_spec.rb index 1a2ff8ede..293ae5202 100644 --- a/spec/models/chouette/stop_area_spec.rb +++ b/spec/models/chouette/stop_area_spec.rb @@ -7,16 +7,15 @@ describe Chouette::StopArea, :type => :model do let!(:commercial_stop_point) { create :stop_area, :area_type => "lda" } let!(:stop_place) { create :stop_area, :area_type => "zdlp" } - # Refs #1627 - # describe '#objectid' do - # subject { super().objectid } - # it { is_expected.to be_kind_of(Chouette::ObjectId) } - # end - - it { is_expected.to belong_to(:stop_area_referential) } - it { is_expected.to validate_presence_of :name } - it { is_expected.to validate_numericality_of :latitude } - it { is_expected.to validate_numericality_of :longitude } + describe '#objectid' do + subject { super().objectid } + it { should be_kind_of(Chouette::StifReflexObjectid) } + end + + it { should belong_to(:stop_area_referential) } + it { should validate_presence_of :name } + it { should validate_numericality_of :latitude } + it { should validate_numericality_of :longitude } # describe ".latitude" do # it "should accept -90 value" do diff --git a/spec/models/chouette/time_table_spec.rb b/spec/models/chouette/time_table_spec.rb index bd74a2d4c..304cb0184 100644 --- a/spec/models/chouette/time_table_spec.rb +++ b/spec/models/chouette/time_table_spec.rb @@ -14,6 +14,8 @@ describe Chouette::TimeTable, :type => :model do describe "#merge! with time_table" do let(:another_tt) { create(:time_table) } let(:another_tt_periods_to_range) { another_tt.periods.map{|p| p.period_start..p.period_end } } + let(:dates) { another_tt.dates.map(&:date) } + let(:continuous_dates) { another_tt.continuous_dates.flatten.map(&:date) } # Make sur we don't have overlapping periods or dates before do @@ -22,12 +24,19 @@ describe Chouette::TimeTable, :type => :model do p.period_end = p.period_end + 1.year end another_tt.dates.each{| d| d.date = d.date + 1.year } + another_tt.save end it 'should merge dates' do subject.dates.clear subject.merge!(another_tt) - expect(subject.dates.map(&:date)).to include(*another_tt.dates.map(&:date)) + expect(subject.dates.map(&:date)).to match_array(dates - continuous_dates) + end + + it 'should not merge continuous dates' do + subject.dates.clear + subject.merge!(another_tt) + expect(subject.dates.map(&:date)).not_to include(*continuous_dates) end it 'should merge periods' do @@ -50,28 +59,42 @@ describe Chouette::TimeTable, :type => :model do subject.merge!(another_tt) expect(subject.dates.map(&:date)).to include(another_tt.dates.last.date) end + + it 'should remove date in_out false if other tt doesnt have them' do + subject.dates.create(in_out: false, date: Date.today + 5.day + 1.year) + + expect { + subject.merge!(another_tt) + }.to change {subject.reload.excluded_days.count}.by(-1) + end end context "#merge! with calendar" do let(:calendar) { create(:calendar, date_ranges: [Date.today + 1.year..Date.tomorrow + 1.year]) } + let(:another_tt) { calendar.convert_to_time_table } + let(:dates) { subject.dates.map(&:date) } + let(:continuous_dates) { subject.continuous_dates.flatten.map(&:date) } it 'should merge calendar dates' do subject.dates.clear - subject.merge!(calendar.convert_to_time_table) - expect(subject.dates.map(&:date)).to include(*calendar.dates) + subject.merge!(another_tt) + expect(subject.dates.map(&:date)).to match_array(dates - continuous_dates) + end + + it 'should not merge calendar continuous dates' do + subject.dates.clear + subject.merge!(another_tt) + expect(subject.dates.map(&:date)).not_to include(*continuous_dates) end it 'should merge calendar periods with no periods in source' do subject.periods.clear - another_tt = calendar.convert_to_time_table subject.merge!(another_tt) expect(subject_periods_to_range).to include(*calendar.date_ranges) end it 'should add calendar periods with existing periods in source' do - another_tt = calendar.convert_to_time_table subject.merge!(another_tt) - expect(subject_periods_to_range).to include(*calendar.date_ranges) end end @@ -1109,7 +1132,7 @@ end - describe "#optimize_periods" do + describe "#optimize_overlapping_periods" do before do subject.periods.clear subject.periods << Chouette::TimeTablePeriod.new( @@ -1127,7 +1150,7 @@ end subject.int_day_types = 4|8|16 end it "should return 2 ordered periods" do - periods = subject.optimize_periods + periods = subject.optimize_overlapping_periods expect(periods.size).to eq(2) expect(periods[0].period_start).to eq(Date.new(2014, 6, 1)) expect(periods[0].period_end).to eq(Date.new(2014, 6, 14)) diff --git a/spec/models/chouette/vehicle_journey_at_stop_spec.rb b/spec/models/chouette/vehicle_journey_at_stop_spec.rb new file mode 100644 index 000000000..d999ed1a8 --- /dev/null +++ b/spec/models/chouette/vehicle_journey_at_stop_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +RSpec.describe Chouette::VehicleJourneyAtStop, type: :model do + describe "#day_offset_outside_range?" do + let (:at_stop) { build_stubbed(:vehicle_journey_at_stop) } + + it "disallows negative offsets" do + expect(at_stop.day_offset_outside_range?(-1)).to be true + end + + it "disallows offsets greater than DAY_OFFSET_MAX" do + expect(at_stop.day_offset_outside_range?( + Chouette::VehicleJourneyAtStop::DAY_OFFSET_MAX + 1 + )).to be true + end + + it "allows offsets between 0 and DAY_OFFSET_MAX inclusive" do + expect(at_stop.day_offset_outside_range?( + Chouette::VehicleJourneyAtStop::DAY_OFFSET_MAX + )).to be false + end + + it "forces a nil offset to 0" do + expect(at_stop.day_offset_outside_range?(nil)).to be false + end + end + + describe "#validate" do + it "displays the proper error message when day offset exceeds the max" do + bad_offset = Chouette::VehicleJourneyAtStop::DAY_OFFSET_MAX + 1 + + at_stop = build_stubbed( + :vehicle_journey_at_stop, + arrival_day_offset: bad_offset, + departure_day_offset: bad_offset + ) + error_message = I18n.t( + 'vehicle_journey_at_stops.errors.day_offset_must_not_exceed_max', + local_id: at_stop.vehicle_journey.objectid.local_id, + max: bad_offset + ) + + at_stop.validate + + expect(at_stop.errors[:arrival_day_offset]).to include(error_message) + expect(at_stop.errors[:departure_day_offset]).to include(error_message) + end + end +end diff --git a/spec/models/chouette/vehicle_journey_spec.rb b/spec/models/chouette/vehicle_journey_spec.rb index c78ef5b33..645513735 100644 --- a/spec/models/chouette/vehicle_journey_spec.rb +++ b/spec/models/chouette/vehicle_journey_spec.rb @@ -1,7 +1,24 @@ require 'spec_helper' describe Chouette::VehicleJourney, :type => :model do - describe "vjas_departure_time_must_be_before_next_stop_arrival_time" do + it "must be valid with an at-stop day offset of 1" do + vehicle_journey = create( + :vehicle_journey, + stop_arrival_time: '23:00:00', + stop_departure_time: '23:00:00' + ) + vehicle_journey.vehicle_journey_at_stops.last.update( + arrival_time: '00:30:00', + departure_time: '00:30:00', + arrival_day_offset: 1, + departure_day_offset: 1 + ) + + expect(vehicle_journey).to be_valid + end + + describe "vjas_departure_time_must_be_before_next_stop_arrival_time", + skip: "Validation currently commented out because it interferes with day offsets" do let(:vehicle_journey) { create :vehicle_journey } let(:vjas) { vehicle_journey.vehicle_journey_at_stops } @@ -10,7 +27,7 @@ describe Chouette::VehicleJourney, :type => :model do vehicle_journey.validate expect(vjas[0].errors[:departure_time]).not_to be_blank - expect(vehicle_journey.errors[:vehicle_journey_at_stops].count).to eq(1) + expect(vehicle_journey.errors.count).to eq(1) expect(vehicle_journey).not_to be_valid end @@ -19,7 +36,7 @@ describe Chouette::VehicleJourney, :type => :model do vehicle_journey.validate expect(vjas[0].errors[:departure_time]).to be_blank - expect(vehicle_journey.errors[:vehicle_journey_at_stops]).to be_empty + expect(vehicle_journey.errors).to be_empty expect(vehicle_journey).to be_valid end diff --git a/spec/models/referential_spec.rb b/spec/models/referential_spec.rb index 2390cc470..53eaa60a3 100644 --- a/spec/models/referential_spec.rb +++ b/spec/models/referential_spec.rb @@ -27,11 +27,12 @@ describe Referential, :type => :model do context "Cloning referential" do let(:clone) do - Referential.new_from(ref, organisation: ref.organisation) + Referential.new_from(ref) end let(:saved_clone) do clone.tap do |clone| + clone.organisation = ref.organisation clone.metadatas.each do |metadata| metadata.periodes = metadata.periodes.map { |period| Range.new(period.end+1, period.end+10) } end diff --git a/spec/models/time_table_combination_spec.rb b/spec/models/time_table_combination_spec.rb index 3e60fa444..ee934f50d 100644 --- a/spec/models/time_table_combination_spec.rb +++ b/spec/models/time_table_combination_spec.rb @@ -8,30 +8,93 @@ describe TimeTableCombination, :type => :model do describe '#continuous_dates' do it 'should group continuous dates' do dates = source.dates.where(in_out: true) - expect(source.continuous_dates[0].count).to eq(dates.count) + expect(source.continuous_dates.flatten.count).to eq(dates.count) - # 6 more continuous date, 1 isolated date + # 6 more continuous dates, 2 isolated dates (10..15).each do |n| source.dates.create(date: Date.today + n.day, in_out: true) end - source.dates.create(date: Date.today + 1.year, in_out: true) + + (1..2).each do |n| + source.dates.create(date: Date.today + n.day + 1.year, in_out: true) + end + expect(source.reload.continuous_dates[1].count).to eq(6) - expect(source.reload.continuous_dates[2].count).to eq(1) + expect(source.reload.continuous_dates[2].count).to eq(2) end end describe '#convert_continuous_dates_to_periods' do it 'should convert continuous dates to periods' do + source.dates.clear + (10..12).each do |n| source.dates.create(date: Date.today + n.day, in_out: true) end - source.dates.create(date: Date.today + 1.year, in_out: true) + + (1..3).each do |n| + source.dates.create(date: Date.today + n.day + 1.year, in_out: true) + end expect { source.reload.convert_continuous_dates_to_periods }.to change {source.periods.count}.by(2) - expect(source.reload.dates.where(in_out: true).count).to eq(1) + expect(source.reload.dates.where(in_out: true).count).to eq(0) + end + end + + describe '#continuous_periods' do + it 'should group continuous periods' do + source.periods.clear + + start_date = Date.today + 1.year + end_date = start_date + 10 + + # 6 more continuous dates, 2 isolated dates + 0.upto(4) do |i| + source.periods.create(period_start: start_date, period_end: end_date) + start_date = end_date + 1 + end_date = start_date + 10 + end + + expect(source.reload.continuous_periods.flatten.count).to eq(5) + end + end + + describe '#convert_continuous_periods_into_one' do + it 'should convert continuous periods into one' do + source.periods.clear + + start_date = Date.today + 1.year + end_date = start_date + 10 + + # 6 more continuous dates, 2 isolated dates + 0.upto(4) do |i| + source.periods.create(period_start: start_date, period_end: end_date) + start_date = end_date + 1 + end_date = start_date + 10 + end + + expect { + source.reload.convert_continuous_periods_into_one + }.to change {source.periods.count}.by(-4) + end + end + + describe '#optimize_continuous_dates_and_periods' do + it 'should update period if timetable has in_date just before or after ' do + source.dates.clear + source.periods.clear + + source.periods.create(period_start: Date.today, period_end: Date.today + 10.day) + source.dates.create(date: Date.today - 1.day, in_out: true) + + expect { + source.periods = source.optimize_continuous_dates_and_periods + }.to change {source.dates.count}.by(-1) + + expect(source.reload.periods.first.period_start).to eq(Date.today - 1.day) end end @@ -129,4 +192,3 @@ describe TimeTableCombination, :type => :model do end end end - diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 6f98e5ce7..3a9ae37e9 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,6 +1,4 @@ -require 'spec_helper' - -describe User, :type => :model do +RSpec.describe User, :type => :model do # it { should validate_uniqueness_of :email } # it { should validate_presence_of :name } @@ -116,9 +114,11 @@ describe User, :type => :model do end context 'permissions' do + let( :all_permissions ){ Stif::PermissionTranslator.translate(%w{boiv:edit-offer}) } + it 'should give edit permissions to user if user has "edit offer" permission in portail' do User.portail_sync - expect(User.find_by(username: 'vlatka.pavisic').permissions).to include_all(User.edit_offer_permissions) + expect(User.find_by(username: 'vlatka.pavisic').permissions).to eq(all_permissions) expect(User.find_by(username: 'pierre.vabre').permissions).to be_empty end end diff --git a/spec/policies/referential_policy_spec.rb b/spec/policies/referential_policy_spec.rb index 33d8e13e8..69d0eb17b 100644 --- a/spec/policies/referential_policy_spec.rb +++ b/spec/policies/referential_policy_spec.rb @@ -46,7 +46,7 @@ RSpec.describe ReferentialPolicy, type: :policy do # ------------------ permissions :clone? do - it_behaves_like 'permitted policy and same organisation', 'referentials.create', archived: true + it_behaves_like 'permitted policy', 'referentials.create', archived: true end permissions :archive? do diff --git a/spec/support/permissions.rb b/spec/support/permissions.rb index a13010f65..fcf9ae9c4 100644 --- a/spec/support/permissions.rb +++ b/spec/support/permissions.rb @@ -15,6 +15,7 @@ module Support %w[ access_points connection_links + calendars footnotes journey_patterns referentials |
