aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Gemfile3
-rw-r--r--Gemfile.lock3
-rw-r--r--app/assets/stylesheets/components/_main_nav.sass13
-rw-r--r--app/assets/stylesheets/components/_referential_overview.sass4
-rw-r--r--app/controllers/compliance_control_sets_controller.rb18
-rw-r--r--app/controllers/concerns/feature_checker.rb2
-rw-r--r--app/javascript/vehicle_journeys/actions/index.js4
-rw-r--r--app/javascript/vehicle_journeys/components/VehicleJourney.js3
-rw-r--r--app/javascript/vehicle_journeys/components/VehicleJourneys.js2
-rw-r--r--app/javascript/vehicle_journeys/components/tools/CreateModal.js5
-rw-r--r--app/javascript/vehicle_journeys/reducers/vehicleJourneys.js94
-rw-r--r--app/models/chouette/vehicle_journey.rb2
-rw-r--r--app/models/merge.rb6
-rw-r--r--app/models/referential.rb18
-rw-r--r--app/models/simple_importer.rb9
-rw-r--r--app/policies/application_policy.rb1
-rw-r--r--app/policies/compliance_control_set_policy.rb4
-rw-r--r--app/views/compliance_controls/_filters.html.slim4
-rw-r--r--app/views/layouts/navigation/_main_nav_top.html.slim12
-rw-r--r--app/views/referential_vehicle_journeys/index.html.slim17
-rw-r--r--app/views/referentials/_overview.html.slim4
-rw-r--r--app/views/time_tables/_form.html.slim2
-rw-r--r--app/workers/workbench_import_worker.rb26
-rw-r--r--config/breadcrumbs.rb2
-rw-r--r--config/initializers/apartment.rb2
-rw-r--r--config/locales/area_types.fr.yml2
-rw-r--r--db/schema.rb1
-rw-r--r--lib/tasks/imports.rake37
-rw-r--r--lib/tasks/seeds.rake19
-rw-r--r--spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js188
-rw-r--r--spec/models/referential_spec.rb28
-rw-r--r--spec/support/pundit/pundit_view_policy.rb2
33 files changed, 437 insertions, 101 deletions
diff --git a/.gitignore b/.gitignore
index dd4d057ef..28960565b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,7 @@
# Ignore all logfiles and tempfiles.
/log/*.log
+/log/importers
/tmp
*~
public/assets/
diff --git a/Gemfile b/Gemfile
index 75298659f..5ec53aee4 100644
--- a/Gemfile
+++ b/Gemfile
@@ -66,7 +66,6 @@ end
gem 'activerecord-postgis-adapter', "~> 3.0.0"
gem 'polylines'
-gem 'activerecord-nulldb-adapter', require: false
# Codifligne API
gem 'codifligne', af83: 'stif-codifline-api'
@@ -142,7 +141,7 @@ gem 'rake'
gem 'devise-async'
gem 'apartment', '~> 1.0.0'
gem 'aasm'
-gem 'activerecord-nulldb-adapter'
+gem 'activerecord-nulldb-adapter' if ENV['RAILS_DB_ADAPTER'] == 'nulldb'
gem 'puma', '~> 3.10.0'
gem 'newrelic_rpm'
diff --git a/Gemfile.lock b/Gemfile.lock
index 046167e69..63d78f9cd 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -76,8 +76,6 @@ GEM
activemodel (= 4.2.8)
activesupport (= 4.2.8)
arel (~> 6.0)
- activerecord-nulldb-adapter (0.3.7)
- activerecord (>= 2.0.0)
activerecord-postgis-adapter (3.0.0)
activerecord (~> 4.2)
rgeo-activerecord (~> 4.0)
@@ -597,7 +595,6 @@ DEPENDENCIES
SyslogLogger
aasm
active_attr
- activerecord-nulldb-adapter
activerecord-postgis-adapter (~> 3.0.0)
acts-as-taggable-on (~> 4.0.0)
acts_as_list (~> 0.6.0)
diff --git a/app/assets/stylesheets/components/_main_nav.sass b/app/assets/stylesheets/components/_main_nav.sass
index 2af070389..8e164fa01 100644
--- a/app/assets/stylesheets/components/_main_nav.sass
+++ b/app/assets/stylesheets/components/_main_nav.sass
@@ -375,3 +375,16 @@ $menuW: 300px
+ .btn
margin-left: 10px
+
+ .languages
+ .dropdown-menu
+ top: 0
+ right: 0
+ left: auto
+ white-space: nowrap
+ line-height: 11px
+ min-width: 0
+ li
+ display: inline-block
+ a
+ padding: 2px 10px
diff --git a/app/assets/stylesheets/components/_referential_overview.sass b/app/assets/stylesheets/components/_referential_overview.sass
index 0beb8ab67..fc48411a3 100644
--- a/app/assets/stylesheets/components/_referential_overview.sass
+++ b/app/assets/stylesheets/components/_referential_overview.sass
@@ -22,7 +22,7 @@
box-shadow: 0 0 10px rgba(0,0,0,0.5)
z-index: 1
.time-travel
- padding-top: 4px
+ padding-top: 3px
padding-bottom: 4px
a.btn:first-child
margin-right: 1px
@@ -61,7 +61,7 @@
border-color: $grey
width: auto
flex: 1 1
- padding: 4px 11px 5px
+ padding: 6px 11px
.input-group-btn
right: 10px
&.togglable
diff --git a/app/controllers/compliance_control_sets_controller.rb b/app/controllers/compliance_control_sets_controller.rb
index 8f9251155..6461b38c8 100644
--- a/app/controllers/compliance_control_sets_controller.rb
+++ b/app/controllers/compliance_control_sets_controller.rb
@@ -36,11 +36,15 @@ 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)
+ @compliance_control_sets ||= begin
+ scope = end_of_association_chain.all
+ scope = self.ransack_period_range(scope: scope, 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
+
end
def decorate_compliance_control_sets(compliance_control_sets)
@@ -82,9 +86,9 @@ class ComplianceControlSetsController < ChouetteController
case params[:sort]
when 'owner_jdc'
collection.joins("LEFT JOIN organisations ON compliance_control_sets.organisation_id = organisations.id")
- when 'control_numbers'
+ when 'control_numbers'
collection.joins("LEFT JOIN compliance_controls ON compliance_controls.compliance_control_set_id = compliance_control_sets.id").group(:id)
- else
+ else
collection
end
end
diff --git a/app/controllers/concerns/feature_checker.rb b/app/controllers/concerns/feature_checker.rb
index 9ca5ed0a7..5e102ef1b 100644
--- a/app/controllers/concerns/feature_checker.rb
+++ b/app/controllers/concerns/feature_checker.rb
@@ -27,6 +27,8 @@ module FeatureChecker
protected
def has_feature?(*features)
+ return false unless current_organisation
+
features.all? do |feature|
current_organisation.has_feature? feature
end
diff --git a/app/javascript/vehicle_journeys/actions/index.js b/app/javascript/vehicle_journeys/actions/index.js
index b398d78fa..e67753e4b 100644
--- a/app/javascript/vehicle_journeys/actions/index.js
+++ b/app/javascript/vehicle_journeys/actions/index.js
@@ -92,7 +92,9 @@ const actions = {
id: selectedTT.id,
comment: selectedTT.comment,
objectid: selectedTT.objectid,
- color: selectedTT.color
+ color: selectedTT.color,
+ bounding_dates: selectedTT.time_table_bounding,
+ days: selectedTT.day_types
}
}),
addSelectedTimetable: () => ({
diff --git a/app/javascript/vehicle_journeys/components/VehicleJourney.js b/app/javascript/vehicle_journeys/components/VehicleJourney.js
index e11e91497..7db0cee1c 100644
--- a/app/javascript/vehicle_journeys/components/VehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/VehicleJourney.js
@@ -66,6 +66,7 @@ export default class VehicleJourney extends Component {
render() {
this.previousCity = undefined
let detailed_calendars = this.hasFeature('detailed_calendars') && !this.disabled
+ let detailed_calendars_shown = $('.detailed-timetables-bt').hasClass('active')
let {time_tables, purchase_windows} = this.props.value
return (
@@ -110,7 +111,7 @@ export default class VehicleJourney extends Component {
{this.props.disabled && <VehicleJourneyInfoButton vehicleJourney={this.props.value} />}
{ detailed_calendars &&
- <div className="detailed-timetables hidden">
+ <div className={"detailed-timetables" + (detailed_calendars_shown ? "" : " hidden")}>
{this.props.allTimeTables.map((tt, i) =>
<div key={i} className={(this.hasTimeTable(time_tables, tt) ? "active" : "inactive")}></div>
)}
diff --git a/app/javascript/vehicle_journeys/components/VehicleJourneys.js b/app/javascript/vehicle_journeys/components/VehicleJourneys.js
index 843aec1a8..384afba17 100644
--- a/app/javascript/vehicle_journeys/components/VehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/components/VehicleJourneys.js
@@ -187,7 +187,7 @@ export default class VehicleJourneys extends Component {
<p>
{this.timeTableURL(tt)}
</p>
- <p>{tt.bounding_dates}</p>
+ <p>{tt.bounding_dates.split(' ').join(' > ')}</p>
</div>
)}
</div>
diff --git a/app/javascript/vehicle_journeys/components/tools/CreateModal.js b/app/javascript/vehicle_journeys/components/tools/CreateModal.js
index 8536f66e6..24d9a23c2 100644
--- a/app/javascript/vehicle_journeys/components/tools/CreateModal.js
+++ b/app/javascript/vehicle_journeys/components/tools/CreateModal.js
@@ -117,6 +117,11 @@ export default class CreateModal extends Component {
className='form-control'
onKeyDown={(e) => actions.resetValidation(e.currentTarget)}
/>
+ <input
+ type='hidden'
+ ref='tz_offset'
+ value={new Date().getTimezoneOffset()}
+ />
</div>
</div>
</div>
diff --git a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
index 383dea4a0..8705b3cf2 100644
--- a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
@@ -14,47 +14,73 @@ const vehicleJourney= (state = {}, action, keep) => {
hour: 0,
minute: 0
}
- if(action.data["start_time.hour"] && action.data["start_time.minute"] && action.selectedJourneyPattern.full_schedule){
- current_time.hour = parseInt(action.data["start_time.hour"].value)
- current_time.minute = parseInt(action.data["start_time.minute"].value) || 0
+ let computeSchedule = false
+ let userTZOffet = 0
+ if(action.data["start_time.hour"] && action.data["start_time.hour"].value && action.data["start_time.hour"].value.length > 0 && action.data["start_time.minute"] && action.selectedJourneyPattern.full_schedule && action.selectedJourneyPattern.costs){
+ computeSchedule = true
+ userTZOffet = action.data["tz_offset"] && parseInt(action.data["tz_offset"].value) || 0
+ current_time.hour = parseInt(action.data["start_time.hour"].value) + parseInt(userTZOffet / 60)
+ current_time.minute = 0
+ if(action.data["start_time.minute"].value){
+ current_time.minute = parseInt(action.data["start_time.minute"].value) + (userTZOffet - 60 * parseInt(userTZOffet / 60))
+ }
}
_.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)
- 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,
- arrival_time:{
- hour: (24 + current_time.hour + offsetHours) % 24,
- minute: current_time.minute + offsetminutes
- },
- stop_point_objectid: sp.object_id,
- stop_area_cityname: sp.city_name,
- dummy: true
- }
+ let newVjas
+ if(computeSchedule){
+ if(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)
+ 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
+ newVjas = {
+ delta: 0,
+ arrival_time:{
+ hour: (24 + current_time.hour + offsetHours) % 24,
+ minute: current_time.minute + offsetminutes
+ },
+ stop_point_objectid: sp.object_id,
+ stop_area_cityname: sp.city_name,
+ dummy: true
+ }
- if(sp.waiting_time && inJourney){
- current_time = actions.addMinutesToTime(current_time, parseInt(sp.waiting_time))
- }
+ 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
- }
+ 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
+ if(current_time.hour + offsetHours > 24){
+ newVjas.departure_day_offset = 1
+ newVjas.arrival_day_offset = 1
+ }
+ if(current_time.hour + offsetHours < 0){
+ newVjas.departure_day_offset = -1
+ newVjas.arrival_day_offset = -1
+ }
}
- if(current_time.hour + offsetHours < 0){
- newVjas.departure_day_offset = -1
- newVjas.arrival_day_offset = -1
+ else{
+ newVjas = {
+ delta: 0,
+ arrival_time: {
+ hour: 0,
+ minute: 0
+ },
+ departure_time: {
+ hour: 0,
+ minute: 0
+ },
+ stop_point_objectid: sp.object_id,
+ stop_area_cityname: sp.city_name,
+ dummy: true
+ }
}
_.each(action.selectedJourneyPattern.stop_areas, (jp) =>{
diff --git a/app/models/chouette/vehicle_journey.rb b/app/models/chouette/vehicle_journey.rb
index 6209993de..9b94f7f0e 100644
--- a/app/models/chouette/vehicle_journey.rb
+++ b/app/models/chouette/vehicle_journey.rb
@@ -93,7 +93,7 @@ module Chouette
scope :in_purchase_window, ->(range){
purchase_windows = Chouette::PurchaseWindow.overlap_dates(range)
sql = purchase_windows.joins(:vehicle_journeys).select('vehicle_journeys.id').uniq.to_sql
- where("id IN (#{sql})")
+ where("vehicle_journeys.id IN (#{sql})")
}
# We need this for the ransack object in the filters
diff --git a/app/models/merge.rb b/app/models/merge.rb
index 62bf581d6..d42d882ac 100644
--- a/app/models/merge.rb
+++ b/app/models/merge.rb
@@ -152,7 +152,7 @@ class Merge < ActiveRecord::Base
route_stop_points = referential_stop_points_by_route[route.id]
# Stop Points
- route_stop_points.each do |stop_point|
+ route_stop_points.sort_by(&:position).each do |stop_point|
objectid = Chouette::StopPoint.where(objectid: stop_point.objectid).exists? ? nil : stop_point.objectid
attributes = stop_point.attributes.merge(
id: nil,
@@ -166,7 +166,7 @@ class Merge < ActiveRecord::Base
new_route.save!
if new_route.checksum != route.checksum
- raise "Checksum has changed: #{route.inspect} #{new_route.inspect}"
+ raise "Checksum has changed: \"#{route.checksum}\", \"#{route.checksum_source}\" -> \"#{new_route.checksum}\", \"#{new_route.checksum_source}\""
end
end
end
@@ -221,7 +221,7 @@ class Merge < ActiveRecord::Base
new_journey_pattern = new.journey_patterns.create! attributes
if new_journey_pattern.checksum != journey_pattern.checksum
- raise "Checksum has changed for #{journey_pattern.inspect}: #{journey_pattern.checksum_source} #{new_journey_pattern.checksum_source} "
+ raise "Checksum has changed for #{journey_pattern.inspect}: \"#{journey_pattern.checksum_source}\" -> \"#{new_journey_pattern.checksum_source}\""
end
end
end
diff --git a/app/models/referential.rb b/app/models/referential.rb
index 09c2e7d34..91a88d02d 100644
--- a/app/models/referential.rb
+++ b/app/models/referential.rb
@@ -408,6 +408,7 @@ class Referential < ActiveRecord::Base
end
check_migration_count(report)
+ # raise "Wrong migration count: #{migration_count}" if migration_count < 300
end
end
@@ -417,13 +418,20 @@ class Referential < ActiveRecord::Base
end
def migration_count
- if self.class.connection.table_exists?("#{slug}.schema_migrations")
- self.class.connection.select_value("select count(*) from #{slug}.schema_migrations;")
- end
+ raw_value =
+ if self.class.connection.table_exists?("#{slug}.schema_migrations")
+ self.class.connection.select_value("select count(*) from #{slug}.schema_migrations;")
+ end
+
+ raw_value.to_i
end
- def assign_slug
- self.slug ||= "#{name.parameterize.gsub('-', '_')}_#{Time.now.to_i}" if name
+ def assign_slug(time_reference = Time)
+ self.slug ||= begin
+ prefix = name.parameterize.gsub('-','_').gsub(/[^a-zA-Z_]/,'').gsub(/^_/,'')
+ prefix = "referential" if prefix.blank?
+ "#{prefix}_#{time_reference.now.to_i}"
+ end if name
end
def assign_prefix
diff --git a/app/models/simple_importer.rb b/app/models/simple_importer.rb
index b824d596d..d6ba64494 100644
--- a/app/models/simple_importer.rb
+++ b/app/models/simple_importer.rb
@@ -95,7 +95,8 @@ class SimpleImporter < ActiveRecord::Base
end
def dump_csv_from_context
- filepath = "./#{self.configuration_name}_#{Time.now.strftime "%y%m%d%H%M"}.csv"
+ dir = context[:output_dir] || "log/importers"
+ filepath = File.join dir, "#{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
@@ -262,7 +263,7 @@ class SimpleImporter < ActiveRecord::Base
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 += @messages.last(lines_count).map{|m| m.truncate(@status_width)}.join("\n")
msg += "\n"*[lines_count-@messages.count, 0].max
end
@@ -273,7 +274,9 @@ class SimpleImporter < ActiveRecord::Base
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]}"
+ kind = "[#{kind}]"
+ kind += " "*(25 - kind.size)
+ encode_string("#{kind}L#{j[:line]}\t#{j[:error]}\t\t#{j[:message]}").truncate(@status_width)
end.join("\n")
end
custom_print msg, clear: true
diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb
index c44937c9e..33d88660c 100644
--- a/app/policies/application_policy.rb
+++ b/app/policies/application_policy.rb
@@ -95,7 +95,6 @@ class ApplicationPolicy
referential.try(:organisation_id) || record.try(:organisation_id)
end
-
#
# Helpers
# -------
diff --git a/app/policies/compliance_control_set_policy.rb b/app/policies/compliance_control_set_policy.rb
index 011f6c0c7..55507ffd9 100644
--- a/app/policies/compliance_control_set_policy.rb
+++ b/app/policies/compliance_control_set_policy.rb
@@ -5,6 +5,10 @@ class ComplianceControlSetPolicy < ApplicationPolicy
end
end
+ def show?
+ organisation_match?
+ end
+
def destroy?
user.has_permission?('compliance_control_sets.destroy')
end
diff --git a/app/views/compliance_controls/_filters.html.slim b/app/views/compliance_controls/_filters.html.slim
index f6b9970f2..a16d2c33d 100644
--- a/app/views/compliance_controls/_filters.html.slim
+++ b/app/views/compliance_controls/_filters.html.slim
@@ -5,8 +5,8 @@
class: 'form form-filter' do |f|
.ffg-row
- .input-group.search_bar class=filter_item_class(params[:q], :name_cont)
- = f.search_field :name_cont,
+ .input-group.search_bar class=filter_item_class(params[:q], :name_or_code_cont)
+ = f.search_field :name_or_code_cont,
class: 'form-control',
placeholder: t('compliance_controls.filters.name')
span.input-group-btn
diff --git a/app/views/layouts/navigation/_main_nav_top.html.slim b/app/views/layouts/navigation/_main_nav_top.html.slim
index f664d5416..12355dfb7 100644
--- a/app/views/layouts/navigation/_main_nav_top.html.slim
+++ b/app/views/layouts/navigation/_main_nav_top.html.slim
@@ -21,6 +21,18 @@
= link_to destroy_user_session_path, method: :delete, class: 'menu-item', title: 'Se déconnecter' do
span.fa.fa-lg.fa-sign-out
+ - if has_feature?(:change_locale)
+ .menu-item-group.pull-right
+ .dropdown.languages
+ a href="#" class="dropdown-toggle" data-toggle="dropdown"
+ = image_tag("language_engine/#{selected_language}_flag.png", { :'data-locale' => "#{selected_language}" } )
+ b.caret
+
+ ul.dropdown-menu
+ - I18n.available_locales.each do |locale|
+ li= link_to_language locale, { :class => language_class( locale ) }
+
+
= render 'layouts/navigation/nav_panel_operations'
= render 'layouts/navigation/nav_panel_profile' if user_signed_in?
diff --git a/app/views/referential_vehicle_journeys/index.html.slim b/app/views/referential_vehicle_journeys/index.html.slim
index 04c01cc12..00f63cb65 100644
--- a/app/views/referential_vehicle_journeys/index.html.slim
+++ b/app/views/referential_vehicle_journeys/index.html.slim
@@ -39,15 +39,20 @@
), \
TableBuilderHelper::Column.new( \
key: :departure_time, \
- attribute: Proc.new {|v| v.vehicle_journey_at_stops.first&.departure }, \
- sortable: false, \
- name: @starting_stop&.name, \
+ attribute: Proc.new {|v| v.vehicle_journey_at_stops.first&.departure_local }, \
+ sortable: true \
), \
+ [@starting_stop, @ending_stop].compact.map{|stop| \
+ TableBuilderHelper::Column.new( \
+ attribute: Proc.new {|v| v.vehicle_journey_at_stops.where("stop_points.stop_area_id" => stop.id).last&.arrival_local }, \
+ sortable: false, \
+ name: stop.name \
+ )\
+ }, \
TableBuilderHelper::Column.new( \
key: :arrival_time, \
- attribute: Proc.new {|v| v.vehicle_journey_at_stops.last&.arrival }, \
- sortable: false, \
- name: @ending_stop&.name, \
+ attribute: Proc.new {|v| v.vehicle_journey_at_stops.last&.arrival_local }, \
+ sortable: true, \
), \
].flatten.compact,
cls: 'table has-filter has-search'
diff --git a/app/views/referentials/_overview.html.slim b/app/views/referentials/_overview.html.slim
index 539c25fd4..870f642d4 100644
--- a/app/views/referentials/_overview.html.slim
+++ b/app/views/referentials/_overview.html.slim
@@ -13,7 +13,7 @@
.form-group.togglable
= f.label Chouette::Line.human_attribute_name(:transport_mode), required: false, class: 'control-label'
- = f.input :transport_mode_eq_any, collection: overview.referential_lines.map(&:transport_mode).uniq.sort, as: :check_boxes, label: false, label_method: lambda{|l| ("<span>" + t("enumerize.transport_mode.#{l}") + "</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list'}
+ = f.input :transport_mode_eq_any, collection: overview.referential_lines.map(&:transport_mode).compact.uniq.sort, as: :check_boxes, label: false, label_method: lambda{|l| ("<span>" + t("enumerize.transport_mode.#{l}") + "</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list'}
.actions
= link_to 'Effacer', url_for() + "##{overview.pagination_param_name}", class: 'btn btn-link'
@@ -39,7 +39,7 @@
a.number style="background-color: #{line.color.present? ? "##{line.color}" : 'whitesmoke'}" title=line.name
= line.number
.company= line.company&.name
- .mode= t("enumerize.transport_mode.#{line.transport_mode}")
+ .mode= line.transport_mode.present? ? t("enumerize.transport_mode.#{line.transport_mode}") : ""
.right
.inner
.head
diff --git a/app/views/time_tables/_form.html.slim b/app/views/time_tables/_form.html.slim
index 007044e65..000da870e 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_workgroup_calendars_path(current_workgroup)}}
+ = 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(@referential.workgroup)}}
- if @time_table.created_from
= form.input :created_from, disabled: true, input_html: { value: @time_table.created_from.comment }
diff --git a/app/workers/workbench_import_worker.rb b/app/workers/workbench_import_worker.rb
index 6420be835..53cbb222a 100644
--- a/app/workers/workbench_import_worker.rb
+++ b/app/workers/workbench_import_worker.rb
@@ -53,17 +53,20 @@ class WorkbenchImportWorker
end
def upload_entry_group_stream eg_name, eg_stream
- FileUtils.mkdir_p(Rails.root.join('tmp', 'imports'))
+ FileUtils.mkdir_p(temp_directory)
- File.open(Rails.root.join('tmp', 'imports', "WorkbenchImport_#{eg_name}_#{$$}.zip"), 'wb') do |file|
+ eg_file_path = Tempfile.open(
+ ["WorkbenchImport_#{eg_name}_", '.zip'],
+ temp_directory
+ ) do |f|
eg_stream.rewind
- file.write eg_stream.read
+ f.write eg_stream.read
+
+ f.path
end
- upload_entry_group_tmpfile eg_name, File.new(Rails.root.join('tmp', 'imports', "WorkbenchImport_#{eg_name}_#{$$}.zip"))
- end
-
- def upload_entry_group_tmpfile eg_name, eg_file
+ eg_file = File.open(eg_file_path)
+
result = execute_post eg_name, eg_file
if result && result.status < 400
@entries += 1
@@ -73,8 +76,8 @@ class WorkbenchImportWorker
raise StopIteration, result.body
end
ensure
- eg_file.close rescue nil
- eg_file.unlink rescue nil
+ eg_file.close
+ File.unlink(eg_file.path)
end
@@ -117,6 +120,11 @@ class WorkbenchImportWorker
file: HTTPService.upload(file, 'application/zip', "#{name}.zip") } }
end
+ def temp_directory
+ Rails.application.config.try(:import_temporary_directory) ||
+ Rails.root.join('tmp', 'imports')
+ end
+
# Lazy Values
# ===========
diff --git a/config/breadcrumbs.rb b/config/breadcrumbs.rb
index 00ccf16bd..a7cdb4313 100644
--- a/config/breadcrumbs.rb
+++ b/config/breadcrumbs.rb
@@ -8,7 +8,7 @@ end
crumb :workbench_output do |workbench|
link I18n.t('workbench_outputs.show.title'), workbench_output_path(workbench)
- parent :workbench, current_offer_workbench
+ parent :workbench, mutual_workbench(workbench)
end
crumb :merges do |workbench|
diff --git a/config/initializers/apartment.rb b/config/initializers/apartment.rb
index fc652a2da..a996549fd 100644
--- a/config/initializers/apartment.rb
+++ b/config/initializers/apartment.rb
@@ -98,7 +98,7 @@ Apartment.configure do |config|
# config.append_environment = true
# supply list of database names for migrations to run on
- config.tenant_names = lambda{ Referential.order("created_from_id asc").pluck(:slug) }
+ config.tenant_names = lambda{ Referential.where(ready: true).order("created_from_id asc").pluck(:slug) }
end
##
diff --git a/config/locales/area_types.fr.yml b/config/locales/area_types.fr.yml
index bb249c235..71c26df92 100644
--- a/config/locales/area_types.fr.yml
+++ b/config/locales/area_types.fr.yml
@@ -10,5 +10,5 @@ fr:
deposit: Dépôt
border: Frontière
service_area: Aire de service / Pause
- relief: Point de releve
+ relief: Point de relève
other: Autre
diff --git a/db/schema.rb b/db/schema.rb
index f77961f8d..c709290f5 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -18,7 +18,6 @@ ActiveRecord::Schema.define(version: 20180202170009) do
enable_extension "hstore"
enable_extension "postgis"
enable_extension "unaccent"
- enable_extension "objectid"
create_table "access_links", id: :bigserial, force: :cascade do |t|
t.integer "access_point_id", limit: 8
diff --git a/lib/tasks/imports.rake b/lib/tasks/imports.rake
index b91ff7efb..f01d3f34f 100644
--- a/lib/tasks/imports.rake
+++ b/lib/tasks/imports.rake
@@ -11,8 +11,8 @@ namespace :import 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"
+ def importer_output_to_csv importer, output_dir
+ filepath = File.join output_dir, + "#{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)
@@ -27,13 +27,17 @@ namespace :import do
end
desc "import the given file with the corresponding importer"
- task :import, [:configuration_name, :filepath, :referential_id] => :environment do |t, args|
+ task :import, [:configuration_name, :filepath, :referential_id, :output_dir] => :environment do |t, args|
+ args.with_defaults(output_dir: "./log/importers/")
+ FileUtils.mkdir_p args[:output_dir]
+
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}
+ config.context = {referential: referential, output_dir: args[:output_dir]}
end
end
puts "\e[33m***\e[0m Start importing"
@@ -43,17 +47,20 @@ namespace :import do
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
+ importer_output_to_csv importer, args[:output_dir]
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|
+ args.with_defaults(output_dir: "./log/importers/")
+ FileUtils.mkdir_p args[:output_dir]
+
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}
+ config.context = {stop_area_referential: referential, output_dir: args[:output_dir]}
end
puts "\e[33m***\e[0m Start importing"
begin
@@ -62,19 +69,22 @@ namespace :import do
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
+ importer_output_to_csv importer, args[:output_dir]
end
end
desc "import the given routes files"
task :import_routes, [:referential_id, :configuration_name, :mapping_filepath, :filepath] => :environment do |t, args|
+ args.with_defaults(output_dir: "./log/importers/")
+ FileUtils.mkdir_p args[:output_dir]
+
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]}
+ config.context = {stop_area_referential: stop_area_referential, mapping_filepath: args[:mapping_filepath], output_dir: args[:output_dir]}
end
puts "\e[33m***\e[0m Start importing"
begin
@@ -83,17 +93,20 @@ namespace :import do
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
+ importer_output_to_csv importer, args[:output_dir]
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|
+ task :import_in_line_referential, [:referential_id, :configuration_name, :filepath, :output_dir] => :environment do |t, args|
+ args.with_defaults(output_dir: "./log/importers/")
+ FileUtils.mkdir_p args[:output_dir]
+
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}
+ config.context = {line_referential: referential, output_dir: args[:output_dir]}
end
puts "\e[33m***\e[0m Start importing"
begin
@@ -102,7 +115,7 @@ namespace :import do
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
+ importer_output_to_csv importer, args[:output_dir]
end
end
end
diff --git a/lib/tasks/seeds.rake b/lib/tasks/seeds.rake
new file mode 100644
index 000000000..9038b64f9
--- /dev/null
+++ b/lib/tasks/seeds.rake
@@ -0,0 +1,19 @@
+namespace :db do
+
+ include Seedbank::DSL
+
+ base_dependencies = ['db:seed:original']
+ override_dependency = ['db:seed:common']
+
+ namespace :seed do
+ seeds_environment = ENV.fetch("SEED_ENV", Rails.env)
+ glob_seed_files_matching('/*/').each do |directory|
+ environment = File.basename(directory)
+ override_dependency << "db:seed:#{environment}" if defined?(Rails) && seeds_environment == environment
+ end
+ end
+
+ # Override db:seed to run all the common and environments seeds plus the original db:seed.
+ desc 'Load the seed data from db/seeds.rb, db/seeds/*.seeds.rb and db/seeds/ENVIRONMENT/*.seeds.rb. ENVIRONMENT is the env var SEED_ENV or the current environment in Rails.env.'
+ override_seed_task :seed => override_dependency
+end
diff --git a/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js b/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js
index 389c60add..608115727 100644
--- a/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js
+++ b/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js
@@ -241,6 +241,194 @@ describe('vehicleJourneys reducer', () => {
}, ...state])
})
+ it('should handle ADD_VEHICLEJOURNEY with a start time and a fully timed JP, and use user\'s TZ', () => {
+ let pristineVjasList = [{
+ delta : 0,
+ arrival_time : {
+ hour: 21,
+ minute: 54
+ },
+ departure_time : {
+ hour: 21,
+ minute: 54
+ },
+ stop_point_objectid: 'test-1',
+ stop_area_cityname: 'city',
+ dummy: false
+ },
+ {
+ delta : 0,
+ arrival_time : {
+ hour: 21,
+ minute: 57
+ },
+ departure_time : {
+ hour: 22,
+ minute: 7
+ },
+ stop_point_objectid: 'test-2',
+ stop_area_cityname: 'city',
+ dummy: false
+ },
+ {
+ delta : 0,
+ arrival_time : {
+ hour: "00",
+ minute: "00"
+ },
+ departure_time : {
+ hour: "00",
+ minute: "00"
+ },
+ stop_point_objectid: 'test-3',
+ stop_area_cityname: 'city',
+ dummy: true
+ },
+ {
+ delta : 0,
+ arrival_time : {
+ hour: 23,
+ minute: 37
+ },
+ departure_time : {
+ hour: 23,
+ minute: 37
+ },
+ stop_point_objectid: 'test-4',
+ stop_area_cityname: 'city',
+ dummy: false
+ }]
+ let fakeData = {
+ published_journey_name: {value: 'test'},
+ published_journey_identifier: {value : ''},
+ "start_time.hour": {value : '22'},
+ "start_time.minute": {value : '59'},
+ "tz_offset": {value : '-65'}
+ }
+ let fakeSelectedJourneyPattern = {
+ id: "1",
+ full_schedule: true,
+ stop_areas: [
+ {stop_area_short_description: {id: 1}},
+ {stop_area_short_description: {id: 2}},
+ {stop_area_short_description: {id: 4}},
+ ],
+ costs: {
+ "1-2": {
+ distance: 10,
+ time: 63
+ },
+ "2-4": {
+ distance: 10,
+ time: 30
+ }
+ }
+ }
+ let fakeSelectedCompany = {name: "ALBATRANS"}
+ expect(
+ vjReducer(state, {
+ 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, 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([{
+ journey_pattern: fakeSelectedJourneyPattern,
+ company: fakeSelectedCompany,
+ published_journey_name: 'test',
+ published_journey_identifier: '',
+ short_id: '',
+ objectid: '',
+ footnotes: [],
+ time_tables: [],
+ purchase_windows: [],
+ vehicle_journey_at_stops: pristineVjasList,
+ selected: false,
+ custom_fields: undefined,
+ deletable: false,
+ transport_mode: 'undefined',
+ transport_submode: 'undefined'
+ }, ...state])
+ })
+
+ it('should handle ADD_VEHICLEJOURNEY with a start time and a fully timed JP but no time is set', () => {
+ let pristineVjasList = [{
+ delta : 0,
+ arrival_time : {
+ hour: 0,
+ minute: 0
+ },
+ departure_time : {
+ hour: 0,
+ minute: 0
+ },
+ stop_point_objectid: 'test-1',
+ stop_area_cityname: 'city',
+ dummy: false
+ },
+ {
+ delta : 0,
+ arrival_time : {
+ hour: 0,
+ minute: 0
+ },
+ departure_time : {
+ hour: 0,
+ minute: 0
+ },
+ stop_point_objectid: 'test-2',
+ stop_area_cityname: 'city',
+ dummy: false
+ }]
+ let fakeData = {
+ published_journey_name: {value: 'test'},
+ published_journey_identifier: {value : ''},
+ "start_time.hour": {value : ''},
+ "start_time.minute": {value : ''}
+ }
+ let fakeSelectedJourneyPattern = {
+ id: "1",
+ full_schedule: true,
+ stop_areas: [
+ {stop_area_short_description: {id: 1}},
+ {stop_area_short_description: {id: 2}},
+ ],
+ costs: {
+ "1-2": {
+ distance: 10,
+ time: 63
+ },
+ }
+ }
+ let fakeSelectedCompany = {name: "ALBATRANS"}
+ expect(
+ vjReducer(state, {
+ 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}],
+ selectedCompany: fakeSelectedCompany
+ })
+ ).toEqual([{
+ journey_pattern: fakeSelectedJourneyPattern,
+ company: fakeSelectedCompany,
+ published_journey_name: 'test',
+ published_journey_identifier: '',
+ short_id: '',
+ objectid: '',
+ footnotes: [],
+ time_tables: [],
+ purchase_windows: [],
+ vehicle_journey_at_stops: pristineVjasList,
+ selected: false,
+ custom_fields: undefined,
+ deletable: false,
+ transport_mode: 'undefined',
+ transport_submode: 'undefined'
+ }, ...state])
+ })
+
it('should handle ADD_VEHICLEJOURNEY with a start time and a fully timed JP but the minutes are not set', () => {
let pristineVjasList = [{
delta : 0,
diff --git a/spec/models/referential_spec.rb b/spec/models/referential_spec.rb
index 6d699f759..025ad80f9 100644
--- a/spec/models/referential_spec.rb
+++ b/spec/models/referential_spec.rb
@@ -9,6 +9,24 @@ describe Referential, :type => :model do
subject { build_stubbed(:referential) }
it { should validate_presence_of(:objectid_format) }
+
+ it "assign slug with a good format" do
+ time_reference = double(now: 1234567890)
+
+ conditions = {
+ "2018-Hiver-Jezequel-MM-Lyon-Nice": "hiver_jezequel_mm_lyon_nice_1234567890",
+ "2018-Hiver-Jezequel-23293MM-Lyon-Nice": "hiver_jezequel_mm_lyon_nice_1234567890",
+ "-Hiver-Jezequel-MM-Lyon-Nice": "hiver_jezequel_mm_lyon_nice_1234567890",
+ "Hiver-Jezequel-MM-Lyon-Nice": "hiver_jezequel_mm_lyon_nice_1234567890",
+ "20179282": "referential_1234567890"
+ }
+
+ conditions.each do |name, expected_slug|
+ ref = Referential.new name: name
+ ref.assign_slug time_reference
+ expect(ref.slug).to eq(expected_slug)
+ end
+ end
end
context ".referential_ids_in_periode" do
@@ -25,6 +43,16 @@ describe Referential, :type => :model do
end
end
+ context "schema creation" do
+
+ it "should create a schema named as the slug" do
+ referential = FactoryGirl.create :referential
+ expect(referential.migration_count).to be ActiveRecord::Migrator.get_all_versions.count
+ expect(referential.migration_count).to be > 300
+ end
+
+ end
+
context "Cloning referential" do
let(:clone) do
Referential.new_from(ref, [])
diff --git a/spec/support/pundit/pundit_view_policy.rb b/spec/support/pundit/pundit_view_policy.rb
index 63970de02..316ff6718 100644
--- a/spec/support/pundit/pundit_view_policy.rb
+++ b/spec/support/pundit/pundit_view_policy.rb
@@ -12,7 +12,7 @@ module Pundit
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(:has_feature?){ |f| respond_to?(:features) && 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