aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuc Donnet2017-09-27 09:56:59 +0200
committerLuc Donnet2017-09-27 09:56:59 +0200
commit16fc6a184311c0ab5e1463398b91f8a716bcf4db (patch)
treeeea2b4b703c6e7960077a0ad1f1b61e079822950
parent7ec5867ec7bd7365bb4c97d7d4c1bdc2cf580bc2 (diff)
parent28a42fb19174eafee38fe3c5f8fa58f89991f44a (diff)
downloadchouette-core-16fc6a184311c0ab5e1463398b91f8a716bcf4db.tar.bz2
Merge branch 'master' of github.com:AF83/stif-boiv
-rw-r--r--Gemfile.lock6
-rw-r--r--INSTALL.md14
-rw-r--r--app/assets/javascripts/es6_browserified/helpers/clone.js14
-rw-r--r--app/assets/javascripts/es6_browserified/itineraries/components/App.js28
-rw-r--r--app/assets/javascripts/es6_browserified/itineraries/components/BSelect2.js16
-rw-r--r--app/assets/javascripts/es6_browserified/itineraries/components/OlMap.js35
-rw-r--r--app/assets/javascripts/es6_browserified/itineraries/components/StopPoint.js14
-rw-r--r--app/assets/javascripts/es6_browserified/itineraries/components/StopPointList.js14
-rw-r--r--app/assets/javascripts/es6_browserified/itineraries/form_helper.js62
-rw-r--r--app/assets/javascripts/es6_browserified/itineraries/index.js23
-rw-r--r--app/assets/javascripts/es6_browserified/itineraries/reducers/stopPoints.js2
-rw-r--r--app/assets/javascripts/es6_browserified/itineraries/show.js3
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/actions/index.js116
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/ConfirmModal.js17
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/ErrorModal.js15
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js30
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/Metas.js24
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js18
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/PeriodManager.js11
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js2
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/TagsSelect2.js10
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/TimeTableDay.js3
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js29
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/containers/App.js13
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js12
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/index.js5
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js6
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js6
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js79
-rw-r--r--app/assets/stylesheets/modules/_timetables.sass9
-rw-r--r--app/controllers/compliance_control_sets_controller.rb37
-rw-r--r--app/controllers/imports_controller.rb2
-rw-r--r--app/decorators/company_decorator.rb2
-rw-r--r--app/helpers/compliance_control_sets_helper.rb5
-rw-r--r--app/models/chouette/stif_netex_objectid.rb2
-rw-r--r--app/models/chouette/vehicle_journey_at_stop.rb4
-rw-r--r--app/models/compliance_control_set.rb4
-rw-r--r--app/models/concerns/stif_netex_attributes_support.rb2
-rw-r--r--app/models/referential.rb2
-rw-r--r--app/models/referential_suite.rb6
-rw-r--r--app/models/vehicle_journey_import.rb2
-rw-r--r--app/policies/import_policy.rb12
-rw-r--r--app/views/compliance_control_sets/_filters.html.slim14
-rw-r--r--app/views/compliance_control_sets/index.html.slim3
-rw-r--r--app/views/routes/_form.html.slim3
-rw-r--r--app/views/time_tables/edit.html.slim2
-rw-r--r--config/locales/actions.en.yml2
-rw-r--r--config/locales/actions.fr.yml2
-rw-r--r--config/locales/compliance_control_sets.en.yml24
-rw-r--r--config/locales/compliance_control_sets.fr.yml4
-rw-r--r--config/locales/routes.en.yml19
-rw-r--r--config/locales/routes.fr.yml19
-rw-r--r--config/locales/stop_points.en.yml1
-rw-r--r--config/locales/stop_points.fr.yml1
-rw-r--r--config/locales/time_tables.en.yml31
-rw-r--r--config/locales/time_tables.fr.yml31
-rw-r--r--config/locales/vehicle_journey_at_stops.en.yml2
-rw-r--r--config/locales/vehicle_journey_at_stops.fr.yml2
-rw-r--r--db/migrate/20170922161352_create_referential_suites.rb10
-rw-r--r--db/migrate/20170922165315_add_referential_suite_to_referentials.rb8
-rw-r--r--db/schema.rb15
-rw-r--r--lib/model_attribute.rb101
-rw-r--r--lib/stif/permission_translator.rb2
-rw-r--r--spec/controllers/imports_controller_spec.rb9
-rw-r--r--spec/javascripts/time_table/actions_spec.js36
-rw-r--r--spec/javascripts/time_table/reducers/modal_spec.js8
-rw-r--r--spec/javascripts/time_table/reducers/pagination_spec.js26
-rw-r--r--spec/javascripts/time_table/reducers/timetable_spec.js147
-rw-r--r--spec/lib/model_attribute_spec.rb111
-rw-r--r--spec/models/chouette/vehicle_journey_at_stop_spec.rb2
-rw-r--r--spec/models/referential_spec.rb1
-rw-r--r--spec/models/referential_suite_spec.rb5
-rw-r--r--spec/policies/api_key_policy_spec.rb4
-rw-r--r--spec/policies/import_policy_spec.rb41
-rw-r--r--spec/policies/referential_policy_spec.rb8
-rw-r--r--spec/support/permissions.rb1
-rw-r--r--spec/support/pundit/policies.rb17
-rw-r--r--spec/support/pundit/shared_examples.rb8
78 files changed, 1134 insertions, 302 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index 9a7be2d84..62b7e3c99 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -305,7 +305,7 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mimemagic (0.3.2)
- mini_portile2 (2.2.0)
+ mini_portile2 (2.3.0)
minitest (5.10.3)
multi_json (1.12.1)
multi_test (0.1.2)
@@ -319,8 +319,8 @@ GEM
net-ssh-gateway (2.0.0)
net-ssh (>= 4.0.0)
newrelic_rpm (4.0.0.332)
- nokogiri (1.8.0)
- mini_portile2 (~> 2.2.0)
+ nokogiri (1.8.1)
+ mini_portile2 (~> 2.3.0)
open4 (1.3.4)
orm_adapter (0.5.0)
parser (2.4.0.0)
diff --git a/INSTALL.md b/INSTALL.md
index ea6fbd6ab..899654a25 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -128,8 +128,22 @@ To create `Referential` objects with some data (`Route`, `JourneyPattern`, `Vehi
# Troubleshooting
+## Postgres
+
If Postgres complains about illegal type `hstore` in your tests that is probably because the shared extension is not installed, here is what to do:
bundle exec rake db:test:purge
Thanks to `lib/tasks/extensions.rake`.
+
+## macOS
+
+### Nokogiri
+
+http://www.nokogiri.org/tutorials/installing_nokogiri.html tells us that `xz` can cause troubles, here is what to do
+
+```
+brew unlink xz
+gem install nokogiri # or bundle install
+brew link xz
+```
diff --git a/app/assets/javascripts/es6_browserified/helpers/clone.js b/app/assets/javascripts/es6_browserified/helpers/clone.js
new file mode 100644
index 000000000..c3b627858
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/helpers/clone.js
@@ -0,0 +1,14 @@
+const _ = require("lodash")
+
+/* This function helps having a bit more security when we pass data from the backend to the React parts
+ It clones the obj (window variable) and then conditionnaly delete the window variable
+*/
+
+const clone = (window, key, deletable = false) => {
+ let obj = _.cloneDeep(window[key])
+
+ if (deletable) delete window[key]
+ return obj
+}
+
+module.exports = clone \ No newline at end of file
diff --git a/app/assets/javascripts/es6_browserified/itineraries/components/App.js b/app/assets/javascripts/es6_browserified/itineraries/components/App.js
index e662d140c..f4cc5e4a6 100644
--- a/app/assets/javascripts/es6_browserified/itineraries/components/App.js
+++ b/app/assets/javascripts/es6_browserified/itineraries/components/App.js
@@ -1,12 +1,28 @@
var React = require('react')
+var { Component, PropTypes } = require('react')
var AddStopPoint = require('../containers/AddStopPoint')
var VisibleStopPoints = require('../containers/VisibleStopPoints')
+const clone = require('../../helpers/clone')
+const I18n = clone(window , "I18n", true)
-const App = () => (
- <div>
- <VisibleStopPoints />
- <AddStopPoint />
- </div>
-)
+class App extends Component {
+
+ getChildContext() {
+ return { I18n }
+ }
+
+ render() {
+ return (
+ <div>
+ <VisibleStopPoints />
+ <AddStopPoint />
+ </div>
+ )
+ }
+}
+
+App.childContextTypes = {
+ I18n: PropTypes.object
+}
module.exports = App
diff --git a/app/assets/javascripts/es6_browserified/itineraries/components/BSelect2.js b/app/assets/javascripts/es6_browserified/itineraries/components/BSelect2.js
index 64c6d3ac7..9a82b7925 100644
--- a/app/assets/javascripts/es6_browserified/itineraries/components/BSelect2.js
+++ b/app/assets/javascripts/es6_browserified/itineraries/components/BSelect2.js
@@ -1,6 +1,6 @@
var _ = require('lodash')
var React = require('react')
-var PropTypes = require('react').PropTypes
+var { Component, PropTypes } = require('react')
var Select2 = require('react-select2')
@@ -9,9 +9,9 @@ var origin = window.location.origin
var path = window.location.pathname.split('/', 3).join('/')
-class BSelect3 extends React.Component{
- constructor(props) {
- super(props)
+class BSelect3 extends Component{
+ constructor(props, context) {
+ super(props, context)
}
onChange(e) {
this.props.onChange(this.props.index, {
@@ -73,7 +73,7 @@ class BSelect3 extends React.Component{
}
}
-class BSelect2 extends React.Component{
+class BSelect2 extends Component{
componentDidMount() {
this.refs.newSelect.el.select2('open')
}
@@ -85,7 +85,7 @@ class BSelect2 extends React.Component{
onSelect={ this.props.onSelect }
ref='newSelect'
options={{
- placeholder: 'Sélectionnez un arrêt existant...',
+ placeholder: this.context.I18n.routes.edit.select2.placeholder,
allowClear: true,
language: 'fr', /* Doesn't seem to work... :( */
theme: 'bootstrap',
@@ -121,4 +121,8 @@ class BSelect2 extends React.Component{
}
}
+BSelect2.contextTypes = {
+ I18n: PropTypes.object
+}
+
module.exports = BSelect3
diff --git a/app/assets/javascripts/es6_browserified/itineraries/components/OlMap.js b/app/assets/javascripts/es6_browserified/itineraries/components/OlMap.js
index b9e106c1a..937871346 100644
--- a/app/assets/javascripts/es6_browserified/itineraries/components/OlMap.js
+++ b/app/assets/javascripts/es6_browserified/itineraries/components/OlMap.js
@@ -1,11 +1,10 @@
var _ = require('lodash')
var React = require('react')
-var Component = require('react').Component
-var PropTypes = require('react').PropTypes
+var { Component, PropTypes } = require('react')
class OlMap extends Component{
- constructor(props){
- super(props)
+ constructor(props, context){
+ super(props, context)
}
fetchApiURL(id){
@@ -116,40 +115,40 @@ class OlMap extends Component{
<strong>{this.props.value.olMap.json.name}</strong>
</p>
<p>
- <strong>Type d'arrêt : </strong>
+ <strong>{this.context.I18n.routes.edit.stop_point_type} : </strong>
{this.props.value.olMap.json.area_type}
</p>
<p>
- <strong>Nom court : </strong>
+ <strong>{this.context.I18n.routes.edit.short_name} : </strong>
{this.props.value.olMap.json.short_name}
</p>
<p>
- <strong>ID Reflex : </strong>
+ <strong>{this.context.I18n.id_reflex} : </strong>
{this.props.value.olMap.json.user_objectid}
</p>
- <p><strong>Coordonnées : </strong></p>
+ <p><strong>{this.context.I18n.routes.edit.map.coordinates} : </strong></p>
<p style={{paddingLeft: 10, marginTop: 0}}>
- <em>Proj.: </em>WSG84<br/>
- <em>Lat.: </em>{this.props.value.olMap.json.latitude} <br/>
- <em>Lon.: </em>{this.props.value.olMap.json.longitude}
+ <em>{this.context.I18n.routes.edit.map.proj}.: </em>WSG84<br/>
+ <em>{this.context.I18n.routes.edit.map.lat}.: </em>{this.props.value.olMap.json.latitude} <br/>
+ <em>{this.context.I18n.routes.edit.map.lon}.: </em>{this.props.value.olMap.json.longitude}
</p>
<p>
- <strong>Code Postal : </strong>
+ <strong>{this.context.I18n.routes.edit.map.postal_code} : </strong>
{this.props.value.olMap.json.zip_code}
</p>
<p>
- <strong>Commune : </strong>
+ <strong>{this.context.I18n.routes.edit.map.city} : </strong>
{this.props.value.olMap.json.city_name}
</p>
<p>
- <strong>Commentaire : </strong>
+ <strong>{this.context.I18n.routes.edit.map.comment} : </strong>
{this.props.value.olMap.json.comment}
</p>
{(this.props.value.stoparea_id != this.props.value.olMap.json.stoparea_id) &&(
<div className='btn btn-outline-primary btn-sm'
onClick= {() => {this.props.onUpdateViaOlMap(this.props.index, this.props.value.olMap.json)}}
- >Sélectionner</div>
+ >{this.context.I18n.actions.select}</div>
)}
</div>
<div className='map_content'>
@@ -163,7 +162,11 @@ class OlMap extends Component{
}
}
-OlMap.propTypes = {
+OlMap.PropTypes = {
+}
+
+OlMap.contextTypes = {
+ I18n: PropTypes.object
}
module.exports = OlMap
diff --git a/app/assets/javascripts/es6_browserified/itineraries/components/StopPoint.js b/app/assets/javascripts/es6_browserified/itineraries/components/StopPoint.js
index 48f77b8e9..c3996f5b3 100644
--- a/app/assets/javascripts/es6_browserified/itineraries/components/StopPoint.js
+++ b/app/assets/javascripts/es6_browserified/itineraries/components/StopPoint.js
@@ -3,7 +3,7 @@ var PropTypes = require('react').PropTypes
var BSelect2 = require('./BSelect2')
var OlMap = require('./OlMap')
-const StopPoint = (props) => {
+const StopPoint = (props, {I18n}) => {
return (
<div className='nested-fields'>
<div className='wrapper'>
@@ -17,15 +17,15 @@ const StopPoint = (props) => {
<div>
<select className='form-control' value={props.value.for_boarding} id="for_boarding" onChange={props.onSelectChange}>
- <option value="normal">Montée autorisée</option>
- <option value="forbidden">Montée interdite</option>
+ <option value="normal">{I18n.routes.edit.stop_point.boarding.normal}</option>
+ <option value="forbidden">{I18n.routes.edit.stop_point.boarding.forbidden}</option>
</select>
</div>
<div>
<select className='form-control' value={props.value.for_alighting} id="for_alighting" onChange={props.onSelectChange}>
- <option value="normal">Descente autorisée</option>
- <option value="forbidden">Descente interdite</option>
+ <option value="normal">{I18n.routes.edit.stop_point.alighting.normal}</option>
+ <option value="forbidden">{I18n.routes.edit.stop_point.alighting.forbidden}</option>
</select>
</div>
@@ -90,4 +90,8 @@ StopPoint.propTypes = {
value: PropTypes.object
}
+StopPoint.contextTypes = {
+ I18n: PropTypes.object
+}
+
module.exports = StopPoint
diff --git a/app/assets/javascripts/es6_browserified/itineraries/components/StopPointList.js b/app/assets/javascripts/es6_browserified/itineraries/components/StopPointList.js
index 77077dbd8..37a480fca 100644
--- a/app/assets/javascripts/es6_browserified/itineraries/components/StopPointList.js
+++ b/app/assets/javascripts/es6_browserified/itineraries/components/StopPointList.js
@@ -2,29 +2,29 @@ var React = require('react')
var PropTypes = require('react').PropTypes
var StopPoint = require('./StopPoint')
-const StopPointList = ({ stopPoints, onDeleteClick, onMoveUpClick, onMoveDownClick, onChange, onSelectChange, onToggleMap, onToggleEdit, onSelectMarker, onUnselectMarker, onUpdateViaOlMap }) => {
+const StopPointList = ({ stopPoints, onDeleteClick, onMoveUpClick, onMoveDownClick, onChange, onSelectChange, onToggleMap, onToggleEdit, onSelectMarker, onUnselectMarker, onUpdateViaOlMap }, {I18n}) => {
return (
<div className='subform'>
<div className='nested-head'>
<div className="wrapper">
<div style={{width: 100}}>
<div className="form-group">
- <label className="control-label">ID Reflex</label>
+ <label className="control-label">{I18n.reflex_id}</label>
</div>
</div>
<div>
<div className="form-group">
- <label className="control-label">Arrêt</label>
+ <label className="control-label">{I18n.simple_form.labels.stop_point.name}</label>
</div>
</div>
<div>
<div className="form-group">
- <label className="control-label">Montée</label>
+ <label className="control-label">{I18n.simple_form.labels.stop_point.for_boarding}</label>
</div>
</div>
<div>
<div className="form-group">
- <label className="control-label">Descente</label>
+ <label className="control-label">{I18n.simple_form.labels.stop_point.for_alighting}</label>
</div>
</div>
<div className='actions-5'></div>
@@ -65,4 +65,8 @@ StopPointList.propTypes = {
onUnselectMarker : PropTypes.func.isRequired
}
+StopPointList.contextTypes = {
+ I18n: PropTypes.object
+}
+
module.exports = StopPointList
diff --git a/app/assets/javascripts/es6_browserified/itineraries/form_helper.js b/app/assets/javascripts/es6_browserified/itineraries/form_helper.js
index 0baba27ef..f682e39c0 100644
--- a/app/assets/javascripts/es6_browserified/itineraries/form_helper.js
+++ b/app/assets/javascripts/es6_browserified/itineraries/form_helper.js
@@ -1,11 +1,55 @@
-const addInput = (name, value, index) => {
- let form = document.querySelector('form')
- let input = document.createElement('input')
- let formatedName = 'route[stop_points_attributes]['+ index.toString()+']['+name+']'
- input.setAttribute('type', 'hidden')
- input.setAttribute('name', formatedName)
- input.setAttribute('value', value)
- form.appendChild(input)
+const formHelper = {
+ addInput: (name, value, index) => {
+ let form = document.querySelector('form')
+ let input = document.createElement('input')
+ let formatedName = `route[stop_points_attributes][${index.toString()}][${name}]`
+ input.setAttribute('type', 'hidden')
+ input.setAttribute('name', formatedName)
+ input.setAttribute('value', value)
+ form.appendChild(input)
+ },
+ addError: (ids) => {
+ ids.forEach((id) => {
+ if (!$(id).parents('.form-group').hasClass('has-error')) {
+ $(id).parents('.form-group').addClass('has-error')
+ $(id).parent().append(`<span class='help-block small'>${'doit être rempli(e)'}</span>`)
+ }
+ })
+ },
+ cleanInputs: (ids) => {
+ ids.forEach((id) =>{
+ $(id).parents('.form-group').removeClass('has-error')
+ $(id).siblings('span').remove()
+ })
+ },
+ handleForm: (...ids) => {
+ let filledInputs = []
+ let blankInputs = []
+ ids.forEach(id => {
+ $(id).val() == "" ? blankInputs.push(id) : filledInputs.push(id)
+ })
+
+ if (filledInputs.length > 0) formHelper.cleanInputs(filledInputs)
+ if (blankInputs.length > 0) formHelper.addError(blankInputs)
+ },
+ handleStopPoints: (event, state) => {
+ if (state.stopPoints.length >= 2) {
+ state.stopPoints.map((stopPoint, i) => {
+ formHelper.addInput('id', stopPoint.stoppoint_id ? stopPoint.stoppoint_id : '', i)
+ formHelper.addInput('stop_area_id', stopPoint.stoparea_id, i)
+ formHelper.addInput('position', i, i)
+ formHelper.addInput('for_boarding', stopPoint.for_boarding, i)
+ formHelper.addInput('for_alighting', stopPoint.for_alighting, i)
+ })
+ if ($('.alert.alert-danger').length > 0) $('.alert.alert-danger').remove()
+ } else {
+ event.preventDefault()
+ let msg = "L'itinéraire doit comporter au moins deux arrêts"
+ if ($('.alert.alert-danger').length == 0) {
+ $('#stop_points').find('.subform').after(`<div class='alert alert-danger'><span class='fa fa-lg fa-exclamation-circle'></span><span>" ${msg} "</span></div>`)
+ }
+ }
+ }
}
-module.exports = addInput
+module.exports = formHelper \ No newline at end of file
diff --git a/app/assets/javascripts/es6_browserified/itineraries/index.js b/app/assets/javascripts/es6_browserified/itineraries/index.js
index ad32b9519..13d89bec5 100644
--- a/app/assets/javascripts/es6_browserified/itineraries/index.js
+++ b/app/assets/javascripts/es6_browserified/itineraries/index.js
@@ -4,8 +4,10 @@ var Provider = require('react-redux').Provider
var createStore = require('redux').createStore
var reducers = require('./reducers')
var App = require('./components/App')
-var addInput = require('./form_helper')
-let datas = JSON.parse(decodeURIComponent(window.itinerary_stop))
+var { handleForm, handleStopPoints } = require('./form_helper')
+let clone = require('../helpers/clone')
+let datas = clone(window, "itinerary_stop", true)
+datas = JSON.parse(decodeURIComponent(datas))
// logger, DO NOT REMOVE
// var applyMiddleware = require('redux').applyMiddleware
@@ -67,17 +69,12 @@ render(
document.querySelector('input[name=commit]').addEventListener('click', (event)=>{
let state = store.getState()
- if(state.stopPoints.length >= 2) {
- state.stopPoints.map((stopPoint, i) => {
- addInput('id', stopPoint.stoppoint_id ? stopPoint.stoppoint_id : '', i)
- addInput('stop_area_id',stopPoint.stoparea_id, i)
- addInput('position',i, i)
- addInput('for_boarding',stopPoint.for_boarding, i)
- addInput('for_alighting',stopPoint.for_alighting, i)
- })
- } else {
+ let name = $("#route_name").val()
+ let publicName = $("#route_published_name").val()
+ if (name == "" || publicName == "") {
event.preventDefault()
- let msg = "L'itinéraire doit comporter au moins deux arrêts"
- $('#stop_points').find('.subform').after("<div class='alert alert-danger'><span class='fa fa-lg fa-exclamation-circle'></span><span>" + msg + "</span></div>")
+ handleForm("#route_name", "#route_published_name")
}
+
+ handleStopPoints(event, state)
})
diff --git a/app/assets/javascripts/es6_browserified/itineraries/reducers/stopPoints.js b/app/assets/javascripts/es6_browserified/itineraries/reducers/stopPoints.js
index a3b8accb3..f3a26b8d7 100644
--- a/app/assets/javascripts/es6_browserified/itineraries/reducers/stopPoints.js
+++ b/app/assets/javascripts/es6_browserified/itineraries/reducers/stopPoints.js
@@ -1,5 +1,5 @@
var _ = require('lodash')
-var addInput = require('../form_helper')
+var { addInput } = require('../form_helper')
const stopPoint = (state = {}, action, length) => {
switch (action.type) {
diff --git a/app/assets/javascripts/es6_browserified/itineraries/show.js b/app/assets/javascripts/es6_browserified/itineraries/show.js
index 79a11701f..e88469900 100644
--- a/app/assets/javascripts/es6_browserified/itineraries/show.js
+++ b/app/assets/javascripts/es6_browserified/itineraries/show.js
@@ -1,4 +1,7 @@
+const clone = require('../helpers/clone')
+let route = clone(window, "route", true)
route = JSON.parse(decodeURIComponent(route))
+
const geoColPts = []
const geoColLns= []
const geoColEdges = [
diff --git a/app/assets/javascripts/es6_browserified/time_tables/actions/index.js b/app/assets/javascripts/es6_browserified/time_tables/actions/index.js
index 02ece1654..a421a8ed6 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/actions/index.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/actions/index.js
@@ -1,19 +1,21 @@
const _ = require('lodash')
+const clone = require('../../helpers/clone')
+const I18n = clone(window, "I18n")
const actions = {
+ weekDays: (index) => {
+ return _.range(1, 8).map(n => I18n.time_tables.edit.metas.days[n])
+ },
strToArrayDayTypes: (str) =>{
- let weekDays = ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa']
- return weekDays.map((day, i) => str.indexOf(day) !== -1)
+ return actions.weekDays().map(day => str.indexOf(day) !== -1)
},
- arrayToStrDayTypes: (arr) => {
- let weekDays = ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa']
- let str = []
- arr.map((dayActive, i) => {
- if(dayActive){
- str.push(weekDays[i])
- }
- })
- return str.join(',')
+ arrayToStrDayTypes: (dayTypes) => {
+ let newDayTypes = dayTypes.reduce((arr, dayActive, i) => {
+ if (dayActive) arr.push(actions.weekDays()[i])
+ return arr
+ }, [])
+
+ return newDayTypes.join(',')
},
fetchingApi: () =>({
type: 'FETCH_API'
@@ -113,14 +115,26 @@ const actions = {
timetableInDates,
error
}),
- includeDateInPeriod: (index, dayTypes, date) => ({
- type: 'INCLUDE_DATE_IN_PERIOD',
+ addIncludedDate: (index, dayTypes, date) => ({
+ type: 'ADD_INCLUDED_DATE',
index,
dayTypes,
date
}),
- excludeDateFromPeriod: (index, dayTypes, date) => ({
- type: 'EXCLUDE_DATE_FROM_PERIOD',
+ removeIncludedDate: (index, dayTypes, date) => ({
+ type: 'REMOVE_INCLUDED_DATE',
+ index,
+ dayTypes,
+ date
+ }),
+ addExcludedDate: (index, dayTypes, date) => ({
+ type: 'ADD_EXCLUDED_DATE',
+ index,
+ dayTypes,
+ date
+ }),
+ removeExcludedDate: (index, dayTypes, date) => ({
+ type: 'REMOVE_EXCLUDED_DATE',
index,
dayTypes,
date
@@ -137,8 +151,8 @@ const actions = {
type : 'CLOSE_MODAL'
}),
monthName(strDate) {
- let monthList = ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"]
- var date = new Date(strDate)
+ let monthList = _.range(1,13).map(n => I18n.calendars.months[n])
+ let date = new Date(strDate)
return monthList[date.getMonth()]
},
getHumanDate(strDate, mLimit) {
@@ -157,43 +171,31 @@ const actions = {
let date = new Date(strDate)
return date.toLocaleDateString()
},
+ updateSynthesis: ({current_month, time_table_dates: dates, time_table_periods: periods}) => {
+ let newPeriods = _.reject(periods, 'deleted')
+ let improvedCM = current_month.map((d, i) => {
+ let isInPeriod = actions.isInPeriod(newPeriods, d.date)
+ let isIncluded = _.some(dates, {'date': d.date, 'in_out': true})
- updateSynthesis: (state, daytypes) => {
- let periods = state.time_table_periods
-
- let isInPeriod = function(d){
- let currentMonth = state.current_periode_range.split('-')
- let twodigitsDay = d.mday < 10 ? ('0' + d.mday) : d.mday
- let currentDate = new Date(currentMonth[0] + '-' + currentMonth[1] + '-' + twodigitsDay)
-
- // We compare periods & currentDate, to determine if it is included or not
- let testDate = false
- periods.map((p, i) => {
- if (p.deleted) return false
-
- let begin = new Date(p.period_start)
- let end = new Date(p.period_end)
-
- if(testDate === false){
- if(currentDate >= begin && currentDate <= end) {
- testDate = true
- // p.include_date = false
- }
- }
- })
- return testDate
- }
-
- let improvedCM = state.current_month.map((d, i) => {
- let bool = isInPeriod(state.current_month[i])
- return _.assign({}, state.current_month[i], {
- in_periods: bool,
- include_date: bool ? false : state.current_month[i].include_date,
- excluded_date: !bool ? false : state.current_month[i].excluded_date
+ return _.assign({}, current_month[i], {
+ in_periods: isInPeriod,
+ include_date: isIncluded,
+ excluded_date: !isInPeriod ? false : current_month[i].excluded_date
})
})
return improvedCM
},
+ isInPeriod: (periods, date) => {
+ date = new Date(date)
+
+ for (let period of periods) {
+ let begin = new Date(period.period_start)
+ let end = new Date(period.period_end)
+ if (date >= begin && date <= end) return true
+ }
+
+ return false
+ },
checkConfirmModal: (event, callback, stateChanged, dispatch, metas, timetable) => {
if(stateChanged){
const error = actions.errorModalKey(timetable.time_table_periods, metas.day_types)
@@ -219,7 +221,7 @@ const actions = {
let period = periods[i]
if (index !== i && !period.deleted) {
if (new Date(period.period_start) <= end && new Date(period.period_end) >= start) {
- error = 'Les périodes ne peuvent pas se chevaucher'
+ error = I18n.time_tables.edit.error_submit.periods_overlaps
break
}
}
@@ -233,7 +235,7 @@ const actions = {
for (let day of in_days) {
if (start <= new Date(day.date) && end >= new Date(day.date)) {
- error = 'Une période ne peut chevaucher une date dans un calendrier'
+ error = I18n.time_tables.edit.error_submit.dates_overlaps
break
}
}
@@ -241,7 +243,6 @@ const actions = {
},
fetchTimeTables: (dispatch, nextPage) => {
let urlJSON = window.location.pathname.split('/', 5).join('/')
- // console.log(nextPage)
if(nextPage) {
urlJSON += "/month.json?date=" + nextPage
}else{
@@ -310,21 +311,14 @@ const actions = {
errorModalMessage: (errorKey) => {
switch (errorKey) {
case "withoutPeriodsWithDaysTypes":
- return window.I18n.fr.time_tables.edit.error_modal.withoutPeriodsWithDaysTypes
+ return I18n.time_tables.edit.error_modal.withoutPeriodsWithDaysTypes
case "withPeriodsWithoutDayTypes":
- return window.I18n.fr.time_tables.edit.error_modal.withPeriodsWithoutDayTypes
+ return I18n.time_tables.edit.error_modal.withPeriodsWithoutDayTypes
default:
return errorKey
}
},
- checkIfTTHasDate: (dates, date) => {
- if (_.some(dates, date)) {
- return _.reject(dates, ['date', date.date])
- } else {
- return dates.concat(date)
- }
- }
}
module.exports = actions
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/ConfirmModal.js b/app/assets/javascripts/es6_browserified/time_tables/components/ConfirmModal.js
index 40ae0eccf..674a03296 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/components/ConfirmModal.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/ConfirmModal.js
@@ -1,18 +1,17 @@
var React = require('react')
-var Component = require('react').Component
-var PropTypes = require('react').PropTypes
+var { PropTypes } = require('react')
-const ConfirmModal = ({dispatch, modal, onModalAccept, onModalCancel, timetable, metas}) => (
+const ConfirmModal = ({dispatch, modal, onModalAccept, onModalCancel, timetable, metas}, {I18n}) => (
<div className={ 'modal fade ' + ((modal.type == 'confirm') ? 'in' : '') } id='ConfirmModal'>
<div className='modal-container'>
<div className='modal-dialog'>
<div className='modal-content'>
<div className='modal-header'>
- <h4 className='modal-title'>Confirmation</h4>
+ <h4 className='modal-title'>{I18n.time_tables.edit.confirm_modal.title}</h4>
</div>
<div className='modal-body'>
<div className='mt-md mb-md'>
- <p>Vous vous apprêtez à changer de page. Voulez-vous valider vos modifications avant cela ?</p>
+ <p>{I18n.time_tables.edit.confirm_modal.message}</p>
</div>
</div>
<div className='modal-footer'>
@@ -22,7 +21,7 @@ const ConfirmModal = ({dispatch, modal, onModalAccept, onModalCancel, timetable,
type='button'
onClick= {() => {onModalCancel(modal.confirmModal.callback)}}
>
- Ne pas valider
+ {I18n.cancel}
</button>
<button
className='btn btn-primary'
@@ -30,7 +29,7 @@ const ConfirmModal = ({dispatch, modal, onModalAccept, onModalCancel, timetable,
type='button'
onClick = {() => {onModalAccept(modal.confirmModal.callback, timetable, metas)}}
>
- Valider
+ {I18n.actions.submit}
</button>
</div>
</div>
@@ -45,4 +44,8 @@ ConfirmModal.propTypes = {
onModalCancel: PropTypes.func.isRequired
}
+ConfirmModal.contextTypes = {
+ I18n: PropTypes.object
+}
+
module.exports = ConfirmModal
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/ErrorModal.js b/app/assets/javascripts/es6_browserified/time_tables/components/ErrorModal.js
index 4e8f7e363..2597a4870 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/components/ErrorModal.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/ErrorModal.js
@@ -1,15 +1,14 @@
var React = require('react')
-var Component = require('react').Component
-var PropTypes = require('react').PropTypes
-var errorModalMessage = require('../actions').errorModalMessage
+var { PropTypes } = require('react')
+var { errorModalMessage } = require('../actions')
-const ErrorModal = ({dispatch, modal, I18n, onModalClose}) => (
+const ErrorModal = ({dispatch, modal, onModalClose}, {I18n}) => (
<div className={ 'modal fade ' + ((modal.type == 'error') ? 'in' : '') } id='ErrorModal'>
<div className='modal-container'>
<div className='modal-dialog'>
<div className='modal-content'>
<div className='modal-header'>
- <h4 className='modal-title'>{window.I18n.fr.time_tables.edit.error_modal.title}</h4>
+ <h4 className='modal-title'>{I18n.time_tables.edit.error_modal.title}</h4>
</div>
<div className='modal-body'>
<div className='mt-md mb-md'>
@@ -23,7 +22,7 @@ const ErrorModal = ({dispatch, modal, I18n, onModalClose}) => (
type='button'
onClick= {() => {onModalClose()}}
>
- Retour
+ {I18n.back}
</button>
</div>
</div>
@@ -37,4 +36,8 @@ ErrorModal.propTypes = {
onModalClose: PropTypes.func.isRequired
}
+ErrorModal.contextTypes = {
+ I18n: PropTypes.object
+}
+
module.exports = ErrorModal
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js b/app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js
index 4879e537f..80c2e4b7a 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js
@@ -8,6 +8,15 @@ class ExceptionsInDay extends Component {
super(props)
}
+ handleClick() {
+ const {index, day, metas: {day_types} } = this.props
+ if (day.in_periods && day_types[day.wday]) {
+ day.excluded_date ? this.props.onRemoveExcludedDate(index, day_types, day.date) : this.props.onAddExcludedDate(index, day_types, day.date)
+ } else {
+ day.include_date ? this.props.onRemoveIncludedDate(index, day_types, day.date) : this.props.onAddIncludedDate(index, day_types, day.date)
+ }
+ }
+
render() {
{/* display add or remove link, only if true in daytypes */}
{/* display add or remove link, according to context (presence in period, or not) */}
@@ -20,14 +29,14 @@ class ExceptionsInDay extends Component {
data-actiontype='remove'
onClick={(e) => {
$(e.currentTarget).toggleClass('active')
- this.props.onExcludeDateFromPeriod(this.props.index, this.props.metas.day_types, this.props.currentDate)
+ this.handleClick()
}}
>
<span className='fa fa-times'></span>
</button>
</div>
)
- } else if(this.props.value.current_month[this.props.index].in_periods == false) {
+ } else {
return (
<div className='td'>
<button
@@ -36,20 +45,21 @@ class ExceptionsInDay extends Component {
data-actiontype='add'
onClick={(e) => {
$(e.currentTarget).toggleClass('active')
- this.props.onIncludeDateInPeriod(this.props.index, this.props.metas.day_types, this.props.currentDate)
+ this.handleClick()
}}
>
<span className='fa fa-plus'></span>
</button>
</div>
)
- } else if(this.props.value.current_month[this.props.index].in_periods == true && this.props.blueDaytype == false){
- return (
- <div className='td'></div>
- )
- } else{
- return false
- }
+ // } else if(this.props.value.current_month[this.props.index].in_periods == true && this.props.blueDaytype == false){
+ // return (
+ // <div className='td'></div>
+ // )
+ // } else{
+ // return false
+ // }
+ }
}
}
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/Metas.js b/app/assets/javascripts/es6_browserified/time_tables/components/Metas.js
index a0fac84f3..26a96e4a6 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/components/Metas.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/Metas.js
@@ -1,9 +1,9 @@
var React = require('react')
-var PropTypes = require('react').PropTypes
-let weekDays = ['D', 'L', 'Ma', 'Me', 'J', 'V', 'S']
+var { PropTypes } = require('react')
+const { weekDays } = require('../actions')
var TagsSelect2 = require('./TagsSelect2')
-const Metas = ({metas, onUpdateDayTypes, onUpdateComment, onUpdateColor, onSelect2Tags, onUnselect2Tags}) => {
+const Metas = ({metas, onUpdateDayTypes, onUpdateComment, onUpdateColor, onSelect2Tags, onUnselect2Tags}, {I18n}) => {
let colorList = ["", "#9B9B9B", "#FFA070", "#C67300", "#7F551B", "#41CCE3", "#09B09C", "#3655D7", "#6321A0", "#E796C6", "#DD2DAA"]
return (
<div className='form-horizontal'>
@@ -12,7 +12,7 @@ const Metas = ({metas, onUpdateDayTypes, onUpdateComment, onUpdateColor, onSelec
{/* comment (name) */}
<div className="form-group">
<label htmlFor="" className="control-label col-sm-4 required">
- Nom <abbr title="Champ requis">*</abbr>
+ {I18n.time_tables.edit.metas.name} <abbr title="">*</abbr>
</label>
<div className="col-sm-8">
<input
@@ -27,7 +27,7 @@ const Metas = ({metas, onUpdateDayTypes, onUpdateComment, onUpdateColor, onSelec
{/* color */}
<div className="form-group">
- <label htmlFor="" className="control-label col-sm-4">Couleur associée</label>
+ <label htmlFor="" className="control-label col-sm-4">{I18n.activerecord.attributes.time_table.color}</label>
<div className="col-sm-8">
<div className="dropdown color_selector">
<button
@@ -72,7 +72,7 @@ const Metas = ({metas, onUpdateDayTypes, onUpdateComment, onUpdateColor, onSelec
{/* tags */}
<div className="form-group">
- <label htmlFor="" className="control-label col-sm-4">Etiquettes</label>
+ <label htmlFor="" className="control-label col-sm-4">{I18n.activerecord.attributes.time_table.tag_list}</label>
<div className="col-sm-8">
<TagsSelect2
initialTags={metas.initial_tags}
@@ -85,16 +85,16 @@ const Metas = ({metas, onUpdateDayTypes, onUpdateComment, onUpdateColor, onSelec
{/* calendar */}
<div className="form-group">
- <label htmlFor="" className="control-label col-sm-4">Modèle de calendrier associé</label>
+ <label htmlFor="" className="control-label col-sm-4">{I18n.activerecord.attributes.time_table.calendar}</label>
<div className="col-sm-8">
- <span>{metas.calendar ? metas.calendar.name : 'Aucun'}</span>
+ <span>{metas.calendar ? metas.calendar.name : I18n.time_tables.edit.metas.no_calendar}</span>
</div>
</div>
{/* day_types */}
<div className="form-group">
<label htmlFor="" className="control-label col-sm-4">
- Journées d'applications pour les périodes ci-dessous
+ {I18n.time_tables.edit.metas.day_types}
</label>
<div className="col-sm-8">
<div className="form-group labelled-checkbox-group">
@@ -112,7 +112,7 @@ const Metas = ({metas, onUpdateDayTypes, onUpdateComment, onUpdateColor, onSelec
type="checkbox"
checked={day ? 'checked' : ''}
/>
- <span className='lcbx-group-item-label'>{weekDays[i]}</span>
+ <span className='lcbx-group-item-label'>{weekDays()[i]}</span>
</label>
</div>
</div>
@@ -135,4 +135,8 @@ Metas.propTypes = {
onUnselect2Tags: PropTypes.func.isRequired
}
+Metas.contextTypes = {
+ I18n: PropTypes.object
+}
+
module.exports = Metas
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js
index 3234a3fd7..d494109cc 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js
@@ -1,5 +1,5 @@
var React = require('react')
-var PropTypes = require('react').PropTypes
+var { PropTypes } = require('react')
var _ = require('lodash')
let monthsArray = ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre']
@@ -32,7 +32,7 @@ const makeYearsOptions = (yearSelected) => {
return arr
}
-const PeriodForm = ({modal, timetable, metas, onOpenAddPeriodForm, onClosePeriodForm, onUpdatePeriodForm, onValidatePeriodForm}) => (
+const PeriodForm = ({modal, timetable, metas, onOpenAddPeriodForm, onClosePeriodForm, onUpdatePeriodForm, onValidatePeriodForm}, {I18n}) => (
<div className="container-fluid">
<div className="row">
<div className="col lg-6 col-lg-offset-3">
@@ -44,7 +44,7 @@ const PeriodForm = ({modal, timetable, metas, onOpenAddPeriodForm, onClosePeriod
<div>
<div className="form-group">
<label htmlFor="" className="control-label required">
- Début de période
+ {I18n.time_tables.edit.period_form.begin}
<abbr title="requis">*</abbr>
</label>
</div>
@@ -52,7 +52,7 @@ const PeriodForm = ({modal, timetable, metas, onOpenAddPeriodForm, onClosePeriod
<div>
<div className="form-group">
<label htmlFor="" className="control-label required">
- Fin de période
+ {I18n.time_tables.edit.period_form.end}
<abbr title="requis">*</abbr>
</label>
</div>
@@ -103,14 +103,14 @@ const PeriodForm = ({modal, timetable, metas, onOpenAddPeriodForm, onClosePeriod
className='btn btn-link'
onClick={onClosePeriodForm}
>
- Annuler
+ {I18n.cancel}
</button>
<button
type='button'
className='btn btn-outline-primary mr-sm'
onClick={() => onValidatePeriodForm(modal.modalProps, timetable.time_table_periods, metas, _.filter(timetable.time_table_dates, ['in_out', true]))}
>
- Valider
+ {I18n.actions.submit}
</button>
</div>
</div>
@@ -122,7 +122,7 @@ const PeriodForm = ({modal, timetable, metas, onOpenAddPeriodForm, onClosePeriod
className='btn btn-outline-primary'
onClick={onOpenAddPeriodForm}
>
- Ajouter une période
+ {I18n.time_tables.actions.add_period}
</button>
</div>
}
@@ -142,4 +142,8 @@ PeriodForm.propTypes = {
timetable: PropTypes.object.isRequired
}
+PeriodForm.contextTypes = {
+ I18n: PropTypes.object
+}
+
module.exports = PeriodForm
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodManager.js b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodManager.js
index cf4cbfb32..704e21331 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodManager.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodManager.js
@@ -1,11 +1,10 @@
var React = require('react')
-var Component = require('react').Component
-var PropTypes = require('react').PropTypes
+var { Component, PropTypes } = require('react')
var actions = require('../actions')
class PeriodManager extends Component {
- constructor(props) {
- super(props)
+ constructor(props, context) {
+ super(props, context)
}
toEndPeriod(curr, end) {
@@ -82,4 +81,8 @@ PeriodManager.propTypes = {
onOpenEditPeriodForm: PropTypes.func.isRequired
}
+PeriodManager.contextTypes = {
+ I18n: PropTypes.object
+}
+
module.exports = PeriodManager
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js
index ca44d3a07..f56509b99 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js
@@ -35,7 +35,7 @@ class PeriodsInDay extends Component {
render() {
return (
<div
- className={this.isIn(this.props.currentDate)}
+ className={this.isIn(this.props.currentDate) + (this.props.metas.day_types[this.props.day.wday] || !this.props.day.in_periods ? '' : ' out_from_daytypes')}
>
{this.props.value.map((p, i) => {
if(!p.deleted){
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/TagsSelect2.js b/app/assets/javascripts/es6_browserified/time_tables/components/TagsSelect2.js
index a1f41a693..46188cdd1 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/components/TagsSelect2.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/TagsSelect2.js
@@ -9,8 +9,8 @@ var path = window.location.pathname.split('/', 4).join('/')
var _ = require('lodash')
class TagsSelect2 extends React.Component{
- constructor(props) {
- super(props)
+ constructor(props, context) {
+ super(props, context)
}
mapKeys(array){
@@ -38,7 +38,7 @@ class TagsSelect2 extends React.Component{
allowClear: true,
theme: 'bootstrap',
width: '100%',
- placeholder: 'Ajoutez ou cherchez une étiquette...',
+ placeholder: this.context.I18n.time_tables.edit.select2.tag.placeholder,
ajax: {
url: origin + path + '/tags.json',
dataType: 'json',
@@ -74,4 +74,8 @@ const formatRepo = (props) => {
if(props.name) return props.name
}
+TagsSelect2.contextTypes = {
+ I18n: PropTypes.object
+}
+
module.exports = TagsSelect2
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/TimeTableDay.js b/app/assets/javascripts/es6_browserified/time_tables/components/TimeTableDay.js
index 71621c874..93a0a90fe 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/components/TimeTableDay.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/TimeTableDay.js
@@ -1,6 +1,5 @@
var React = require('react')
-var Component = require('react').Component
-var PropTypes = require('react').PropTypes
+var { Component, PropTypes } = require('react')
class TimeTableDay extends Component {
constructor(props) {
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js b/app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js
index 3af1a11a4..22e971c6b 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js
@@ -1,14 +1,13 @@
var React = require('react')
-var Component = require('react').Component
-var PropTypes = require('react').PropTypes
+var { Component, PropTypes} = require('react')
var TimeTableDay = require('./TimeTableDay')
var PeriodsInDay = require('./PeriodsInDay')
var ExceptionsInDay = require('./ExceptionsInDay')
var actions = require('../actions')
class Timetable extends Component{
- constructor(props){
- super(props)
+ constructor(props, context){
+ super(props, context)
}
currentDate(mFirstday, day) {
@@ -31,11 +30,11 @@ class Timetable extends Component{
<div className="table table-2entries mb-sm">
<div className="t2e-head w20">
<div className="th">
- <div className="strong">Synthèse</div>
+ <div className="strong">{this.context.I18n.time_tables.synthesis}</div>
</div>
- <div className="td"><span>Journées d'application</span></div>
- <div className="td"><span>Périodes</span></div>
- <div className="td"><span>Exceptions</span></div>
+ <div className="td"><span>{this.context.I18n.time_tables.edit.day_types}</span></div>
+ <div className="td"><span>{this.context.I18n.time_tables.edit.periods}</span></div>
+ <div className="td"><span>{this.context.I18n.time_tables.edit.exceptions}</span></div>
</div>
<div className="t2e-item-list w80">
<div>
@@ -60,13 +59,14 @@ class Timetable extends Component{
{this.props.timetable.current_month.map((d, i) =>
<div
key={i}
- className={'td-group' + (this.props.metas.day_types[d.wday] || !d.in_periods ? '' : ' out_from_daytypes') + (d.wday == 0 ? ' last_wday' : '')}
+ className={'td-group'+ (d.wday == 0 ? ' last_wday' : '')}
>
{/* day_types */}
- <div className="td"></div>
+ <div className={"td" + (this.props.metas.day_types[d.wday] || !d.in_periods ? '' : ' out_from_daytypes') }></div>
{/* periods */}
<PeriodsInDay
+ day={d}
index={i}
value={this.props.timetable.time_table_periods}
currentDate={this.currentDate(this.props.timetable.current_periode_range, d.mday)}
@@ -77,11 +77,16 @@ class Timetable extends Component{
{/* exceptions */}
<ExceptionsInDay
+ day={d}
index={i}
value={this.props.timetable}
currentDate={d.date}
metas={this.props.metas}
blueDaytype={this.props.metas.day_types[d.wday]}
+ onAddIncludedDate={this.props.onAddIncludedDate}
+ onRemoveIncludedDate={this.props.onRemoveIncludedDate}
+ onAddExcludedDate={this.props.onAddExcludedDate}
+ onRemoveExcludedDate={this.props.onRemoveExcludedDate}
onExcludeDateFromPeriod={this.props.onExcludeDateFromPeriod}
onIncludeDateInPeriod={this.props.onIncludeDateInPeriod}
/>
@@ -105,4 +110,8 @@ Timetable.propTypes = {
onIncludeDateInPeriod: PropTypes.func.isRequired
}
+Timetable.contextTypes = {
+ I18n: PropTypes.object
+}
+
module.exports = Timetable
diff --git a/app/assets/javascripts/es6_browserified/time_tables/containers/App.js b/app/assets/javascripts/es6_browserified/time_tables/containers/App.js
index 02f0ddbd8..f12fb8a71 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/containers/App.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/containers/App.js
@@ -1,6 +1,6 @@
var React = require('react')
var connect = require('react-redux').connect
-var Component = require('react').Component
+var { Component, PropTypes} = require('react')
var actions = require('../actions')
var Metas = require('./Metas')
var Timetable = require('./Timetable')
@@ -10,11 +10,18 @@ var SaveTimetable = require('./SaveTimetable')
var ConfirmModal = require('./ConfirmModal')
var ErrorModal = require('./ErrorModal')
+const clone = require('../../helpers/clone')
+const I18n = clone(window, "I18n", true)
+
class App extends Component {
componentDidMount(){
this.props.onLoadFirstPage()
}
+ getChildContext() {
+ return { I18n }
+ }
+
render(){
return(
<div className='row'>
@@ -41,6 +48,10 @@ const mapDispatchToProps = (dispatch) => {
}
}
+App.childContextTypes = {
+ I18n: PropTypes.object
+}
+
const timeTableApp = connect(null, mapDispatchToProps)(App)
module.exports = timeTableApp
diff --git a/app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js b/app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js
index 639a1e2ab..a37e99982 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js
@@ -15,6 +15,18 @@ const mapDispatchToProps = (dispatch) => {
onDeletePeriod: (index, dayTypes) =>{
dispatch(actions.deletePeriod(index, dayTypes))
},
+ onAddIncludedDate: (index, dayTypes, date) => {
+ dispatch(actions.addIncludedDate(index, dayTypes, date))
+ },
+ onRemoveIncludedDate: (index, dayTypes, date) => {
+ dispatch(actions.removeIncludedDate(index, dayTypes, date))
+ },
+ onAddExcludedDate: (index, dayTypes, date) => {
+ dispatch(actions.addExcludedDate(index, dayTypes, date))
+ },
+ onRemoveExcludedDate: (index, dayTypes, date) => {
+ dispatch(actions.removeExcludedDate(index, dayTypes, date))
+ },
onExcludeDateFromPeriod: (index, dayTypes, date) => {
dispatch(actions.excludeDateFromPeriod(index, dayTypes, date))
},
diff --git a/app/assets/javascripts/es6_browserified/time_tables/index.js b/app/assets/javascripts/es6_browserified/time_tables/index.js
index a91747991..6c352df6b 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/index.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/index.js
@@ -5,6 +5,9 @@ var createStore = require('redux').createStore
var timeTablesApp = require('./reducers')
var App = require('./containers/App')
+const clone = require('../helpers/clone')
+const actionType = clone(window, "actionType", true)
+
// logger, DO NOT REMOVE
// var applyMiddleware = require('redux').applyMiddleware
// var createLogger = require('redux-logger')
@@ -13,7 +16,7 @@ var App = require('./containers/App')
var initialState = {
status: {
- actionType: window.actionType,
+ actionType: actionType,
policy: window.perms,
fetchSuccess: true,
isFetching: false
diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js
index 2ce084efd..ab5ed3d91 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js
@@ -15,8 +15,10 @@ const metas = (state = {}, action) => {
case 'RECEIVE_MONTH':
let dt = (typeof state.day_types === 'string') ? actions.strToArrayDayTypes(state.day_types) : state.day_types
return _.assign({}, state, {day_types: dt})
- case 'INCLUDE_DATE_IN_PERIOD':
- case 'EXCLUDE_DATE_FROM_PERIOD':
+ case 'ADD_INCLUDED_DATE':
+ case 'REMOVE_INCLUDED_DATE':
+ case 'ADD_EXCLUDED_DATE':
+ case 'REMOVE_EXCLUDED_DATE':
case 'DELETE_PERIOD':
case 'VALIDATE_PERIOD_FORM':
return _.assign({}, state, {calendar: null})
diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js
index 45fec6b5f..f38b124d9 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js
@@ -20,8 +20,10 @@ const pagination = (state = {}, action) => {
case 'CHANGE_PAGE':
toggleOnConfirmModal()
return _.assign({}, state, {currentPage : action.page, stateChanged: false})
- case 'INCLUDE_DATE_IN_PERIOD':
- case 'EXCLUDE_DATE_FROM_PERIOD':
+ case 'ADD_INCLUDED_DATE':
+ case 'REMOVE_INCLUDED_DATE':
+ case 'ADD_EXCLUDED_DATE':
+ case 'REMOVE_EXCLUDED_DATE':
case 'DELETE_PERIOD':
case 'VALIDATE_PERIOD_FORM':
case 'UPDATE_COMMENT':
diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js
index 390bdffb0..712808abd 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js
@@ -1,7 +1,6 @@
const _ = require('lodash')
var actions = require('../actions')
-let newState = {}
-let newDates = []
+let newState, newPeriods, newDates, newCM
const timetable = (state = {}, action) => {
switch (action.type) {
@@ -11,14 +10,14 @@ const timetable = (state = {}, action) => {
current_periode_range: action.json.current_periode_range,
periode_range: action.json.periode_range,
time_table_periods: action.json.time_table_periods,
- time_table_dates: action.json.time_table_dates
+ time_table_dates: _.sortBy(action.json.time_table_dates, ['date'])
})
- return _.assign({}, fetchedState, {current_month: actions.updateSynthesis(fetchedState, actions.strToArrayDayTypes(action.json.day_types))})
+ return _.assign({}, fetchedState, {current_month: actions.updateSynthesis(fetchedState)})
case 'RECEIVE_MONTH':
newState = _.assign({}, state, {
current_month: action.json.days
})
- return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, actions.strToArrayDayTypes(action.json.day_types))})
+ return _.assign({}, newState, {current_month: actions.updateSynthesis(newState)})
case 'GO_TO_PREVIOUS_PAGE':
case 'GO_TO_NEXT_PAGE':
let nextPage = action.nextPage ? 1 : -1
@@ -31,34 +30,44 @@ const timetable = (state = {}, action) => {
actions.fetchTimeTables(action.dispatch, action.page)
return _.assign({}, state, {current_periode_range: action.page})
case 'DELETE_PERIOD':
- let ttperiods = state.time_table_periods.map((period, i) =>{
+ newPeriods = state.time_table_periods.map((period, i) =>{
if(i == action.index){
period.deleted = true
}
return period
})
- newState = _.assign({}, state, {time_table_periods : ttperiods})
- return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, action.dayTypes)})
- case 'INCLUDE_DATE_IN_PERIOD':
- newDates = actions.checkIfTTHasDate(state.time_table_dates, {date: action.date, in_out: true})
- let newCMi = state.current_month.map((d, i) => {
- if(i == action.index){
- d.include_date = !d.include_date
- }
+ let deletedPeriod = Array.of(state.time_table_periods[action.index])
+ newDates = _.reject(state.time_table_dates, d => actions.isInPeriod(deletedPeriod, d.date) && !d.in_out)
+ newState = _.assign({}, state, {time_table_periods : newPeriods, time_table_dates: newDates})
+ return _.assign({}, newState, { current_month: actions.updateSynthesis(newState)})
+ case 'ADD_INCLUDED_DATE':
+ newDates = state.time_table_dates.concat({date: action.date, in_out: true})
+ newCM = state.current_month.map((d, i) => {
+ if (i == action.index) d.include_date = true
return d
})
- newState = _.assign({}, state, {current_month: newCMi, time_table_dates: newDates})
- return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, action.dayTypes)})
- case 'EXCLUDE_DATE_FROM_PERIOD':
- newDates = actions.checkIfTTHasDate(state.time_table_dates, {date: action.date, in_out: false})
- let newCMe = state.current_month.map((d, i) => {
- if(i == action.index){
- d.excluded_date = !d.excluded_date
- }
+ return _.assign({}, state, {current_month: newCM, time_table_dates: newDates})
+ case 'REMOVE_INCLUDED_DATE':
+ newDates = _.reject(state.time_table_dates, ['date', action.date])
+ newCM = state.current_month.map((d, i) => {
+ if (i == action.index) d.include_date = false
+ return d
+ })
+ return _.assign({}, state, {current_month: newCM, time_table_dates: newDates})
+ case 'ADD_EXCLUDED_DATE':
+ newDates = state.time_table_dates.concat({date: action.date, in_out: false})
+ newCM = state.current_month.map((d, i) => {
+ if (i == action.index) d.excluded_date = true
+ return d
+ })
+ return _.assign({}, state, {current_month: newCM, time_table_dates: newDates})
+ case 'REMOVE_EXCLUDED_DATE':
+ newDates = _.reject(state.time_table_dates, ['date', action.date])
+ newCM = state.current_month.map((d, i) => {
+ if (i == action.index) d.excluded_date = false
return d
})
- newState = _.assign({}, state, {current_month: newCMe, time_table_dates: newDates})
- return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, action.dayTypes)})
+ return _.assign({}, state, {current_month: newCM, time_table_dates: newDates})
case 'UPDATE_DAY_TYPES':
// We get the week days of the activated day types to reject the out_dates that that are out of newDayTypes
let weekDays = _.reduce(action.dayTypes, (array, dt, i) => {
@@ -67,11 +76,17 @@ const timetable = (state = {}, action) => {
}, [])
newDates = _.reject(state.time_table_dates, (d) => {
- return d.in_out == false && !weekDays.includes(new Date(d.date).getDay())
+ let weekDay = new Date(d.date).getDay()
+
+ if (d.in_out) {
+ return actions.isInPeriod(state.time_table_periods, d.date) && weekDays.includes(weekDay)
+ } else {
+ return !weekDays.includes(weekDay)
+ }
})
return _.assign({}, state, {time_table_dates: newDates})
case 'UPDATE_CURRENT_MONTH_FROM_DAYTYPES':
- return _.assign({}, state, {current_month: actions.updateSynthesis(state, action.dayTypes)})
+ return _.assign({}, state, {current_month: actions.updateSynthesis(state)})
case 'VALIDATE_PERIOD_FORM':
if (action.error != '') return state
@@ -81,8 +96,10 @@ const timetable = (state = {}, action) => {
let newPeriods = JSON.parse(JSON.stringify(action.timeTablePeriods))
if (action.modalProps.index !== false){
- newPeriods[action.modalProps.index].period_start = period_start
- newPeriods[action.modalProps.index].period_end = period_end
+ let updatedPeriod = newPeriods[action.modalProps.index]
+ updatedPeriod.period_start = period_start
+ updatedPeriod.period_end = period_end
+ newDates = _.reject(state.time_table_dates, d => actions.isInPeriod(newPeriods, d.date) && !d.in_out)
}else{
let newPeriod = {
period_start: period_start,
@@ -90,8 +107,10 @@ const timetable = (state = {}, action) => {
}
newPeriods.push(newPeriod)
}
- newState =_.assign({}, state, {time_table_periods: newPeriods})
- return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, action.metas.day_types)})
+
+ newDates = newDates || state.time_table_dates
+ newState =_.assign({}, state, {time_table_periods: newPeriods, time_table_dates: newDates})
+ return _.assign({}, newState, {current_month: actions.updateSynthesis(newState)})
default:
return state
}
diff --git a/app/assets/stylesheets/modules/_timetables.sass b/app/assets/stylesheets/modules/_timetables.sass
index 84f1af043..b06972ef9 100644
--- a/app/assets/stylesheets/modules/_timetables.sass
+++ b/app/assets/stylesheets/modules/_timetables.sass
@@ -85,11 +85,14 @@
&:not(:last-child) > .td
border-right: 2px solid $darkgrey
- &.out_from_daytypes
- background-image: linear-gradient(45deg, rgba($grey, 0.15) 0%, rgba($grey, 0.15) 49%, rgba($grey, 0.5) 50%, rgba($grey, 0.15) 51%, rgba($grey, 0.15) 99%, rgba($grey, 0.15) 100%)
- background-size: 25px 25px
+ // &.out_from_daytypes
+ // background-image: linear-gradient(45deg, rgba($grey, 0.15) 0%, rgba($grey, 0.15) 49%, rgba($grey, 0.5) 50%, rgba($grey, 0.15) 51%, rgba($grey, 0.15) 99%, rgba($grey, 0.15) 100%)
+ // background-size: 25px 25px
> .td
+ &.out_from_daytypes
+ background-image: linear-gradient(45deg, rgba($grey, 0.15) 0%, rgba($grey, 0.15) 49%, rgba($grey, 0.5) 50%, rgba($grey, 0.15) 51%, rgba($grey, 0.15) 99%, rgba($grey, 0.15) 100%)
+ background-size: 25px 25px
&.in_periods
background-color: rgba($gold, 0.5)
border-left-color: rgba($gold, 0.5)
diff --git a/app/controllers/compliance_control_sets_controller.rb b/app/controllers/compliance_control_sets_controller.rb
index 6edfa3fcc..20ddcbe97 100644
--- a/app/controllers/compliance_control_sets_controller.rb
+++ b/app/controllers/compliance_control_sets_controller.rb
@@ -1,10 +1,12 @@
class ComplianceControlSetsController < BreadcrumbController
defaults resource_class: ComplianceControlSet
+ before_action :ransack_updated_at_params, only: [:index]
respond_to :html
def index
index! do |format|
- @q_for_form = @compliance_control_sets.ransack(params[:q])
+ scope = ransack_period @compliance_control_sets
+ @q_for_form = scope.ransack(params[:q])
format.html {
@compliance_control_sets = decorate_compliance_control_sets(@q_for_form.result)
}
@@ -24,8 +26,41 @@ class ComplianceControlSetsController < BreadcrumbController
)
end
+ protected
+
+ # def begin_of_association_chain
+ # current_organisation
+ # end
+
private
+ def ransack_updated_at_params
+ start_date = []
+ end_date = []
+
+ if params[:q] && params[:q][:updated_at] && !params[:q][:updated_at].has_value?(nil) && !params[:q][:updated_at].has_value?("")
+ [1, 2, 3].each do |key|
+ start_date << params[:q][:updated_at]["begin(#{key}i)"].to_i
+ end_date << params[:q][:updated_at]["end(#{key}i)"].to_i
+ end
+ params[:q].delete([:updated_at])
+ @begin_range = DateTime.new(*start_date,0,0,0) rescue nil
+ @end_range = DateTime.new(*end_date,23,59,59) rescue nil
+ end
+ end
+
+ # Fake ransack filter
+ def ransack_period scope
+ return scope unless !!@begin_range && !!@end_range
+
+ if @begin_range > @end_range
+ flash.now[:error] = t('imports.filters.error_period_filter')
+ else
+ scope = scope.where_updated_at_between(@begin_range, @end_range)
+ end
+ scope
+ end
+
def compliance_control_set_params
params.require(:compliance_control_set).permit(:name, :id)
end
diff --git a/app/controllers/imports_controller.rb b/app/controllers/imports_controller.rb
index fa8919f20..f2e65e445 100644
--- a/app/controllers/imports_controller.rb
+++ b/app/controllers/imports_controller.rb
@@ -1,4 +1,5 @@
class ImportsController < BreadcrumbController
+ include PolicyChecker
skip_before_action :authenticate_user!, only: [:download]
defaults resource_class: Import, collection_name: 'imports', instance_name: 'import'
before_action :ransack_started_at_params, only: [:index]
@@ -89,7 +90,6 @@ class ImportsController < BreadcrumbController
def ransack_status_params
if params[:q]
- binding.pry
return params[:q].delete(:status_eq_any) if params[:q][:status_eq_any].empty? || ( (Import.status.values & params[:q][:status_eq_any]).length >= 4 )
params[:q][:status_eq_any].push("new", "running") if params[:q][:status_eq_any].include?("pending")
params[:q][:status_eq_any].push("aborted", "canceled") if params[:q][:status_eq_any].include?("failed")
diff --git a/app/decorators/company_decorator.rb b/app/decorators/company_decorator.rb
index 402bd3ab6..764cce3a0 100644
--- a/app/decorators/company_decorator.rb
+++ b/app/decorators/company_decorator.rb
@@ -19,8 +19,6 @@ class CompanyDecorator < Draper::Decorator
links = []
if h.policy(Chouette::Company).create?
- require 'pry'
- binding.pry
links << Link.new(
content: h.t('companies.actions.new'),
href: h.new_line_referential_company_path(context[:referential])
diff --git a/app/helpers/compliance_control_sets_helper.rb b/app/helpers/compliance_control_sets_helper.rb
index 3e02e0ef7..6ba4bed4f 100644
--- a/app/helpers/compliance_control_sets_helper.rb
+++ b/app/helpers/compliance_control_sets_helper.rb
@@ -1,2 +1,7 @@
module ComplianceControlSetsHelper
+
+ def organisations_filters_values
+ [current_organisation, Organisation.find_by_name("STIF")].uniq
+ end
+
end
diff --git a/app/models/chouette/stif_netex_objectid.rb b/app/models/chouette/stif_netex_objectid.rb
index a0a91668a..93e7a1e85 100644
--- a/app/models/chouette/stif_netex_objectid.rb
+++ b/app/models/chouette/stif_netex_objectid.rb
@@ -3,7 +3,7 @@ class Chouette::StifNetexObjectid < String
parts.present?
end
- @@format = /^([A-Za-z_]+):([A-Za-z]+):([0-9A-Za-z_-]+):([A-Za-z]+)$/
+ @@format = /^([A-Za-z_-]+):([A-Za-z]+):([0-9A-Za-z_-]+):([A-Za-z]+)$/
cattr_reader :format
def parts
diff --git a/app/models/chouette/vehicle_journey_at_stop.rb b/app/models/chouette/vehicle_journey_at_stop.rb
index 156cc761f..a4a4a02c8 100644
--- a/app/models/chouette/vehicle_journey_at_stop.rb
+++ b/app/models/chouette/vehicle_journey_at_stop.rb
@@ -41,7 +41,7 @@ module Chouette
:arrival_day_offset,
I18n.t(
'vehicle_journey_at_stops.errors.day_offset_must_not_exceed_max',
- local_id: vehicle_journey.objectid.local_id,
+ short_id: vehicle_journey.objectid.short_id,
max: DAY_OFFSET_MAX + 1
)
)
@@ -52,7 +52,7 @@ module Chouette
:departure_day_offset,
I18n.t(
'vehicle_journey_at_stops.errors.day_offset_must_not_exceed_max',
- local_id: vehicle_journey.objectid.local_id,
+ short_id: vehicle_journey.objectid.short_id,
max: DAY_OFFSET_MAX + 1
)
)
diff --git a/app/models/compliance_control_set.rb b/app/models/compliance_control_set.rb
index cefdfbf1f..4dafd48c7 100644
--- a/app/models/compliance_control_set.rb
+++ b/app/models/compliance_control_set.rb
@@ -4,4 +4,8 @@ class ComplianceControlSet < ActiveRecord::Base
validates :name, presence: true
+ scope :where_updated_at_between, ->(start_date, end_date) do
+ where('updated_at BETWEEN ? AND ?', start_date, end_date)
+ end
+
end
diff --git a/app/models/concerns/stif_netex_attributes_support.rb b/app/models/concerns/stif_netex_attributes_support.rb
index 795872755..0d569b613 100644
--- a/app/models/concerns/stif_netex_attributes_support.rb
+++ b/app/models/concerns/stif_netex_attributes_support.rb
@@ -49,7 +49,7 @@ module StifNetexAttributesSupport
end
def provider_id
- self.referential.workbench.organisation.name.parameterize
+ self.referential.workbench.organisation.name.parameterize.underscore
end
def boiv_id
diff --git a/app/models/referential.rb b/app/models/referential.rb
index af08aa868..c7b52ddf8 100644
--- a/app/models/referential.rb
+++ b/app/models/referential.rb
@@ -45,6 +45,8 @@ class Referential < ActiveRecord::Base
has_many :stop_areas, through: :stop_area_referential
belongs_to :workbench
+ belongs_to :referential_suite
+
scope :ready, -> { where(ready: true) }
scope :in_periode, ->(periode) { where(id: referential_ids_in_periode(periode)) }
scope :include_metadatas_lines, ->(line_ids) { where('referential_metadata.line_ids && ARRAY[?]::bigint[]', line_ids) }
diff --git a/app/models/referential_suite.rb b/app/models/referential_suite.rb
new file mode 100644
index 000000000..9fd25ef3f
--- /dev/null
+++ b/app/models/referential_suite.rb
@@ -0,0 +1,6 @@
+class ReferentialSuite < ActiveRecord::Base
+ belongs_to :new, class_name: 'Referential'
+ belongs_to :current, class_name: 'Referential'
+
+ has_many :referentials
+end
diff --git a/app/models/vehicle_journey_import.rb b/app/models/vehicle_journey_import.rb
index 44a6d457e..250f3a9e9 100644
--- a/app/models/vehicle_journey_import.rb
+++ b/app/models/vehicle_journey_import.rb
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
class VehicleJourneyImport
include ActiveModel::Validations
include ActiveModel::Conversion
diff --git a/app/policies/import_policy.rb b/app/policies/import_policy.rb
index 9e1d99a66..b12dcc167 100644
--- a/app/policies/import_policy.rb
+++ b/app/policies/import_policy.rb
@@ -4,4 +4,16 @@ class ImportPolicy < ApplicationPolicy
scope
end
end
+
+ def create?
+ !archived? && user.has_permission?('imports.create')
+ end
+
+ def destroy?
+ !archived? && user.has_permission?('imports.destroy')
+ end
+
+ def update?
+ !archived? && user.has_permission?('imports.update')
+ end
end
diff --git a/app/views/compliance_control_sets/_filters.html.slim b/app/views/compliance_control_sets/_filters.html.slim
index 7ee050636..56cac8bd2 100644
--- a/app/views/compliance_control_sets/_filters.html.slim
+++ b/app/views/compliance_control_sets/_filters.html.slim
@@ -5,6 +5,18 @@
span.input-group-btn
button.btn.btn-default type='submit'
span.fa.fa-search
+ .ffg-row
+ .form-group.togglable
+ = f.label t('activerecord.models.organisation.one'), required: false, class: 'control-label'
+ = f.input :organisation_name_eq_any, collection: organisations_filters_values, as: :check_boxes, label: false, label_method: lambda {|w| ("<span>#{w.name}</span>").html_safe}, required: false, wrapper_html: {class: 'checkbox_list'}
+
+ .form-group.togglable
+ = f.label Import.human_attribute_name(:updated_at), required: false, class: 'control-label'
+ .filter_menu
+ = f.simple_fields_for :updated_at do |p|
+ = p.input :begin, as: :date, label: false, wrapper_html: {class: 'date smart_date filter_menu-item'}, default: @begin_range, include_blank: @begin_range ? false : true
+ = p.input :end, as: :date, label: false, wrapper_html: {class: 'date smart_date filter_menu-item'}, default: @end_range, include_blank: @end_range ? false : true
+
.actions
= link_to t('actions.erase'), @compliance_control_set, class: 'btn btn-link'
- = f.submit t('actions.filter'), class: 'btn btn-default', id: 'referential_filter_btn'
+ = f.submit t('actions.filter'), class: 'btn btn-default', id: 'referential_filter_btn' \ No newline at end of file
diff --git a/app/views/compliance_control_sets/index.html.slim b/app/views/compliance_control_sets/index.html.slim
index 95833a01c..aee1595ef 100644
--- a/app/views/compliance_control_sets/index.html.slim
+++ b/app/views/compliance_control_sets/index.html.slim
@@ -24,7 +24,7 @@
key: :name, \
attribute: 'name', \
link_to: lambda do |compliance_control_set| \
- compliance_control_set_path(@compliance_control_sets, compliance_control_set) \
+ compliance_control_set_path(compliance_control_set) \
end \
), \
TableBuilderHelper::Column.new( \
@@ -45,6 +45,7 @@
) \
],
sortable: true,
+ links: [:show],
cls: 'table has-filter has-search'
- unless @compliance_control_sets.any?
.row.mt-xs
diff --git a/app/views/routes/_form.html.slim b/app/views/routes/_form.html.slim
index 244b427dc..24c0d3c4a 100644
--- a/app/views/routes/_form.html.slim
+++ b/app/views/routes/_form.html.slim
@@ -26,7 +26,8 @@
// Get JSON data for route stop points
= javascript_tag do
- | window.itinerary_stop = "#{URI.escape(route_json_for_edit(@route))}"
+ | window.itinerary_stop = "#{URI.escape(route_json_for_edit(@route))}";
+ | window.I18n = #{(I18n.backend.send(:translations)[I18n.locale].to_json).html_safe};
/ StopPoints Reactux component
= javascript_include_tag 'es6_browserified/itineraries/index.js'
diff --git a/app/views/time_tables/edit.html.slim b/app/views/time_tables/edit.html.slim
index ed55dc4e3..cc6f31489 100644
--- a/app/views/time_tables/edit.html.slim
+++ b/app/views/time_tables/edit.html.slim
@@ -11,6 +11,6 @@
= javascript_tag do
| window.actionType = "#{raw params[:action]}";
- | window.I18n = #{(I18n.backend.send(:translations).to_json).html_safe};
+ | window.I18n = #{(I18n.backend.send(:translations)[I18n.locale].to_json).html_safe};
= javascript_include_tag 'es6_browserified/time_tables/index.js'
diff --git a/config/locales/actions.en.yml b/config/locales/actions.en.yml
index 8dea51ca3..c34462d0d 100644
--- a/config/locales/actions.en.yml
+++ b/config/locales/actions.en.yml
@@ -20,8 +20,10 @@ en:
filter: 'Filter'
erase: 'Erase'
create_api_key: "Create an API key"
+ select: Select
or: "or"
cancel: "Cancel"
+ back: "Go Back"
search_hint: "Type in a search term"
no_result_text: "No Results"
searching_term: "Searching..."
diff --git a/config/locales/actions.fr.yml b/config/locales/actions.fr.yml
index 01fc06326..df16d2aab 100644
--- a/config/locales/actions.fr.yml
+++ b/config/locales/actions.fr.yml
@@ -20,8 +20,10 @@ fr:
filter: 'Filtrer'
erase: 'Effacer'
create_api_key: "Créer une clé d'API"
+ select: Sélectionner
or: "ou"
cancel: "Annuler"
+ back: "Retour"
search_hint: "Entrez un texte à rechercher"
no_result_text: "Aucun résultat"
searching_term: "Recherche en cours..."
diff --git a/config/locales/compliance_control_sets.en.yml b/config/locales/compliance_control_sets.en.yml
new file mode 100644
index 000000000..497ca50c3
--- /dev/null
+++ b/config/locales/compliance_control_sets.en.yml
@@ -0,0 +1,24 @@
+fr:
+ compliance_control_sets:
+ index:
+ title: Control games
+ new: Creating a control set
+ edit: Editing a Control Game
+ actions:
+ new: Add
+ edit: Edit
+ destroy: Delete
+ destroy_confirm: Are you sure to remove the control games ?
+ filters:
+ name: Specify a control game name...
+ search_no_results: No control game matches your search
+ activerecord:
+ models:
+ compliance_control_set: Calendar
+ attributes:
+ compliance_control_set:
+ name: Name
+ assignment: Affectation
+ owner_jdc: Owner of the control game
+ control_numbers: Nb contrôle
+ updated_at: Update \ No newline at end of file
diff --git a/config/locales/compliance_control_sets.fr.yml b/config/locales/compliance_control_sets.fr.yml
index fedfeede7..f5bb7c67b 100644
--- a/config/locales/compliance_control_sets.fr.yml
+++ b/config/locales/compliance_control_sets.fr.yml
@@ -10,8 +10,8 @@ fr:
destroy: Supprimer
destroy_confirm: Etes vous sûr de supprimer ce jeux de contrôle ?
filters:
- name: 'Indiquez un nom de jeux de contrôle...'
- search_no_results: 'Aucun jeu de contrôle ne correspond à votre recherche'
+ name: Indiquez un nom de jeux de contrôle...
+ search_no_results: Aucun jeu de contrôle ne correspond à votre recherche
activerecord:
models:
compliance_control_set: Calendrier
diff --git a/config/locales/routes.en.yml b/config/locales/routes.en.yml
index 63d7b198c..3b1fd85cc 100644
--- a/config/locales/routes.en.yml
+++ b/config/locales/routes.en.yml
@@ -17,6 +17,25 @@ en:
title: "Add a new route"
edit:
title: "Update route %{route}"
+ select2:
+ placeholder: "Select a stop point..."
+ map:
+ stop_point_type: Stop point type
+ short_name: Short name
+ coordinates: Coordinates
+ proj: Proj
+ lat: Lat
+ lon: Lon
+ postal_code: Zip Code
+ city: City
+ comment: Comment
+ stop_point:
+ boarding:
+ normal: Normal boarding
+ forbidden: Forbidden boarding
+ alighting:
+ normal: Normal alighting
+ forbidden: Forbidden alighting
show:
title: "Route %{route}"
stop_points: "Stop point on route list"
diff --git a/config/locales/routes.fr.yml b/config/locales/routes.fr.yml
index a494e60ec..43c40645d 100644
--- a/config/locales/routes.fr.yml
+++ b/config/locales/routes.fr.yml
@@ -17,6 +17,25 @@ fr:
title: "Ajouter un itinéraire"
edit:
title: "Editer l'itinéraire %{route}"
+ select2:
+ placeholder: "Sélectionnez un arrêt existant..."
+ map:
+ stop_point_type: Type d'arrêt
+ short_name: Nom court
+ coordinates: Coordonnées
+ proj: Proj
+ lat: Lat
+ lon: Lon
+ postal_code: Code Postal
+ city: Commune
+ comment: Commentaire
+ stop_point:
+ boarding:
+ normal: Montée autorisée
+ forbidden: Montée interdite
+ alighting:
+ normal: Descente autorisée
+ forbidden: Descente interdite
show:
title: "Itinéraire %{route} de la ligne %{line}"
stop_points: "Liste des arrêts de l'itinéraire"
diff --git a/config/locales/stop_points.en.yml b/config/locales/stop_points.en.yml
index 1ef8002d0..d22d85731 100644
--- a/config/locales/stop_points.en.yml
+++ b/config/locales/stop_points.en.yml
@@ -52,5 +52,6 @@ en:
simple_form:
labels:
stop_point:
+ name: Stop Point
for_boarding: "Pickup"
for_alighting: "Drop off"
diff --git a/config/locales/stop_points.fr.yml b/config/locales/stop_points.fr.yml
index d90041945..d3c873442 100644
--- a/config/locales/stop_points.fr.yml
+++ b/config/locales/stop_points.fr.yml
@@ -52,5 +52,6 @@ fr:
simple_form:
labels:
stop_point:
+ name: Arrêt
for_boarding: "Montée"
for_alighting: "Descente"
diff --git a/config/locales/time_tables.en.yml b/config/locales/time_tables.en.yml
index d67e30edb..e68836f99 100644
--- a/config/locales/time_tables.en.yml
+++ b/config/locales/time_tables.en.yml
@@ -29,10 +29,39 @@ en:
title: "Duplicate timetable"
edit:
title: "Update timetable %{time_table}"
+ day_types: Day types
+ periods: Periods
+ exceptions: Exceptions
+ synthesis: Synthesis
error_modal:
title: "Error"
withoutPeriodsWithDaysTypes: "A timetable can't have day type(s) without period(s)."
- withPeriodsWithoutDayTypes: "A tiemetable can't have period(s) swithout day type(s)."
+ withPeriodsWithoutDayTypes: "A tiemetable can't have period(s) swithout day type(s)."
+ error_submit:
+ periods_overlaps: "Periods cannot overlap in a timetable"
+ dates_overlaps: "A period cannot overlap a date in a timetable"
+ confirm_modal:
+ title: "Confirm"
+ message: "You are about to change pages. Do you want to validate your changes before this?"
+ metas:
+ name: Name
+ calendar: Associated calendar
+ no_calendar: None
+ day_types: Periods day tpes
+ days:
+ 1: Su
+ 2: Mo
+ 3: Tu
+ 4: We
+ 5: Th
+ 6: Fr
+ 7: Sa
+ select2:
+ tag:
+ placeholder: Add or search a tag...
+ period_form:
+ begin: Period start
+ end: Period end
show:
title: "Timetable %{time_table}"
dates: "Application dates"
diff --git a/config/locales/time_tables.fr.yml b/config/locales/time_tables.fr.yml
index 06d1d59e8..b85f7ca33 100644
--- a/config/locales/time_tables.fr.yml
+++ b/config/locales/time_tables.fr.yml
@@ -29,10 +29,39 @@ fr:
title: "Dupliquer un calendrier"
edit:
title: "Editer le calendrier %{time_table}"
+ day_types: Journées d'application
+ periods: Périodes
+ exceptions: Exceptions
+ synthesis: Synthèse
error_modal:
title: "Erreur"
withoutPeriodsWithDaysTypes: "Un calendrier d'application ne peut pas avoir de journée(s) d'application sans période(s)."
- withPeriodsWithoutDayTypes: "Un calendrier d'application ne peut pas avoir de période(s) sans journée(s) d'application."
+ withPeriodsWithoutDayTypes: "Un calendrier d'application ne peut pas avoir de période(s) sans journée(s) d'application."
+ error_submit:
+ periods_overlaps: "Les périodes ne peuvent pas se chevaucher"
+ dates_overlaps: "Une période ne peut chevaucher une date dans un calendrier"
+ confirm_modal:
+ title: "Confirmation"
+ message: "Vous vous apprêtez à changer de page. Voulez-vous valider vos modifications avant cela ?"
+ metas:
+ name: Nom
+ calendar: Modèle de calendrier associée
+ no_calendar: Aucun
+ day_types: Journées d'applications pour les périodes ci-dessous
+ days:
+ 1: Di
+ 2: Lu
+ 3: Ma
+ 4: Me
+ 5: Je
+ 6: Ve
+ 7: Sa
+ select2:
+ tag:
+ placeholder: Ajoutez ou cherchez une étiquette...
+ period_form:
+ begin: Début de période
+ end: Fin de période
show:
title: Calendrier %{time_table}
dates: "Dates d'application"
diff --git a/config/locales/vehicle_journey_at_stops.en.yml b/config/locales/vehicle_journey_at_stops.en.yml
index a96effa2b..8a3bd9394 100644
--- a/config/locales/vehicle_journey_at_stops.en.yml
+++ b/config/locales/vehicle_journey_at_stops.en.yml
@@ -1,4 +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"
+ day_offset_must_not_exceed_max: "The vehicle journey with ID %{short_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
index 3eff79cf4..f5139fb79 100644
--- a/config/locales/vehicle_journey_at_stops.fr.yml
+++ b/config/locales/vehicle_journey_at_stops.fr.yml
@@ -1,4 +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"
+ day_offset_must_not_exceed_max: "La course avec l'identifiant %{short_id} ne peut pas avoir des horaires sur plus de %{max} jours"
diff --git a/db/migrate/20170922161352_create_referential_suites.rb b/db/migrate/20170922161352_create_referential_suites.rb
new file mode 100644
index 000000000..5a8693d01
--- /dev/null
+++ b/db/migrate/20170922161352_create_referential_suites.rb
@@ -0,0 +1,10 @@
+class CreateReferentialSuites < ActiveRecord::Migration
+ def change
+ create_table :referential_suites do |t|
+ t.bigint :new_id, index: true
+ t.bigint :current_id, index: true
+
+ t.timestamps null: false
+ end
+ end
+end
diff --git a/db/migrate/20170922165315_add_referential_suite_to_referentials.rb b/db/migrate/20170922165315_add_referential_suite_to_referentials.rb
new file mode 100644
index 000000000..a01ba4d40
--- /dev/null
+++ b/db/migrate/20170922165315_add_referential_suite_to_referentials.rb
@@ -0,0 +1,8 @@
+class AddReferentialSuiteToReferentials < ActiveRecord::Migration
+ def change
+ add_reference :referentials, :referential_suite,
+ index: true,
+ foreign_key: true,
+ type: :bigint
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 2b62fa7f1..89f002aee 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20170918103913) do
+ActiveRecord::Schema.define(version: 20170922165315) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -602,6 +602,16 @@ ActiveRecord::Schema.define(version: 20170918103913) do
add_index "referential_metadata", ["referential_id"], name: "index_referential_metadata_on_referential_id", using: :btree
add_index "referential_metadata", ["referential_source_id"], name: "index_referential_metadata_on_referential_source_id", using: :btree
+ create_table "referential_suites", id: :bigserial, force: :cascade do |t|
+ t.integer "new_id", limit: 8
+ t.integer "current_id", limit: 8
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+ add_index "referential_suites", ["current_id"], name: "index_referential_suites_on_current_id", using: :btree
+ add_index "referential_suites", ["new_id"], name: "index_referential_suites_on_new_id", using: :btree
+
create_table "referentials", id: :bigserial, force: :cascade do |t|
t.string "name"
t.string "slug"
@@ -622,9 +632,11 @@ ActiveRecord::Schema.define(version: 20170918103913) do
t.datetime "archived_at"
t.integer "created_from_id", limit: 8
t.boolean "ready", default: false
+ t.integer "referential_suite_id", limit: 8
end
add_index "referentials", ["created_from_id"], name: "index_referentials_on_created_from_id", using: :btree
+ add_index "referentials", ["referential_suite_id"], name: "index_referentials_on_referential_suite_id", using: :btree
create_table "route_sections", id: :bigserial, force: :cascade do |t|
t.integer "departure_id", limit: 8
@@ -987,6 +999,7 @@ ActiveRecord::Schema.define(version: 20170918103913) do
add_foreign_key "journey_patterns", "stop_points", column: "departure_stop_point_id", name: "departure_point_fkey", on_delete: :nullify
add_foreign_key "journey_patterns_stop_points", "journey_patterns", name: "jpsp_jp_fkey", on_delete: :cascade
add_foreign_key "journey_patterns_stop_points", "stop_points", name: "jpsp_stoppoint_fkey", on_delete: :cascade
+ add_foreign_key "referentials", "referential_suites"
add_foreign_key "route_sections", "stop_areas", column: "arrival_id"
add_foreign_key "route_sections", "stop_areas", column: "departure_id"
add_foreign_key "routes", "routes", column: "opposite_route_id", name: "route_opposite_route_fkey"
diff --git a/lib/model_attribute.rb b/lib/model_attribute.rb
new file mode 100644
index 000000000..4d246853a
--- /dev/null
+++ b/lib/model_attribute.rb
@@ -0,0 +1,101 @@
+class ModelAttribute
+ attr_reader :klass, :name, :data_type
+
+ def self.all
+ @__all__ ||= []
+ end
+
+ def self.define(klass, name, data_type)
+ all << new(klass, name, data_type)
+ end
+
+ def self.classes
+ all
+ .map(&:klass)
+ .uniq
+ .map(&:to_s)
+ .map(&:camelize)
+ end
+
+ def self.group_by_class
+ all.group_by(&:klass)
+ end
+
+ def self.from_code(code)
+ klass, name = code.split('#').map(&:to_sym)
+
+ methods_by_class(klass).select do |model_attr|
+ model_attr.name == name
+ end.first
+ end
+
+ def self.methods_by_class(klass)
+ all.select do |model_attr|
+ model_attr.klass == klass
+ end
+ end
+
+ def self.methods_by_class_and_type(klass, type)
+ methods_by_class(klass).select do |model_attr|
+ model_attr.data_type == type
+ end
+ end
+
+ def initialize(klass, name, data_type)
+ @klass = klass
+ @name = name
+ @data_type = data_type
+ end
+
+ # Chouette::Route
+ define :route, :name, :string
+ define :route, :published_name, :string
+ define :route, :comment, :string
+ define :route, :number, :string
+ define :route, :direction, :string
+ define :route, :wayback, :string
+
+ # Chouette::JourneyPattern
+ define :journey_pattern, :name, :string
+ define :journey_pattern, :published_name, :string
+ define :journey_pattern, :comment, :string
+ define :journey_pattern, :registration_number, :string
+ define :journey_pattern, :section_status, :integer
+
+ # Chouette::VehicleJourney
+ define :vehicle_journey, :comment, :string
+ define :vehicle_journey, :status_value, :string
+ define :vehicle_journey, :transport_mode, :string
+ define :vehicle_journey, :facility, :string
+ define :vehicle_journey, :published_journey_name, :string
+ define :vehicle_journey, :published_journey_identifier, :string
+ define :vehicle_journey, :vehicle_type_identifier, :string
+ define :vehicle_journey, :number, :integer
+ define :vehicle_journey, :mobility_restricted_suitability, :boolean
+ define :vehicle_journey, :flexible_service, :boolean
+
+ # Chouette::Footnote
+ define :footnote, :code, :string
+ define :footnote, :label, :string
+
+ # Chouette::TimeTable
+ define :time_table, :version, :string
+ define :time_table, :comment, :string
+ define :time_table, :start_date, :date
+ define :time_table, :end_date, :date
+ define :time_table, :color, :string
+
+ # Chouette::RoutingConstraintZone
+ define :routing_constraint_zone, :name, :string
+
+ def code
+ "#{@klass}##{@name}"
+ end
+
+ def ==(other)
+ self.class === other &&
+ klass == other.klass &&
+ name == other.name &&
+ data_type == other.data_type
+ end
+end
diff --git a/lib/stif/permission_translator.rb b/lib/stif/permission_translator.rb
index 2bc565968..15d5ffc89 100644
--- a/lib/stif/permission_translator.rb
+++ b/lib/stif/permission_translator.rb
@@ -19,6 +19,7 @@ module Stif
access_points
connection_links calendars
footnotes
+ imports
journey_patterns
referentials routes routing_constraint_zones
time_tables
@@ -29,7 +30,6 @@ module Stif
end
def destructive_permissions_for(models)
- @__destructive_permissions_for__ ||=
models.product( %w{create destroy update} ).map{ |model_action| model_action.join('.') }
end
diff --git a/spec/controllers/imports_controller_spec.rb b/spec/controllers/imports_controller_spec.rb
index f07190496..22be9f6ed 100644
--- a/spec/controllers/imports_controller_spec.rb
+++ b/spec/controllers/imports_controller_spec.rb
@@ -5,10 +5,16 @@ RSpec.describe ImportsController, :type => :controller do
let(:import) { create :import, workbench: workbench }
describe 'GET #new' do
- it 'should be successful' do
+ it 'should be successful if authorized' do
get :new, workbench_id: workbench.id
expect(response).to be_success
end
+
+ it 'should be unsuccessful unless authorized' do
+ remove_permissions('imports.create', from_user: @user, save: true)
+ get :new, workbench_id: workbench.id
+ expect(response).not_to be_success
+ end
end
describe 'GET #download' do
@@ -18,4 +24,5 @@ RSpec.describe ImportsController, :type => :controller do
expect( response.body ).to eq(import.file.read)
end
end
+
end
diff --git a/spec/javascripts/time_table/actions_spec.js b/spec/javascripts/time_table/actions_spec.js
index f052aeece..a7344586d 100644
--- a/spec/javascripts/time_table/actions_spec.js
+++ b/spec/javascripts/time_table/actions_spec.js
@@ -171,28 +171,52 @@ describe('actions', () => {
expect(actions.validatePeriodForm(modalProps, timeTablePeriods, metas, timetableInDates, error)).toEqual(expectedAction)
})
- it('should create an action to include date in period', () => {
+ it('should create an action to add an included date', () => {
let index = 1
let date = actions.formatDate(new Date)
const expectedAction = {
- type: 'INCLUDE_DATE_IN_PERIOD',
+ type: 'ADD_INCLUDED_DATE',
index,
dayTypes,
date
}
- expect(actions.includeDateInPeriod(index, dayTypes, date)).toEqual(expectedAction)
+ expect(actions.addIncludedDate(index, dayTypes, date)).toEqual(expectedAction)
})
- it('should create an action to exclude date from period', () => {
+ it('should create an action to remove an included dat', () => {
let index = 1
let date = actions.formatDate(new Date)
const expectedAction = {
- type: 'EXCLUDE_DATE_FROM_PERIOD',
+ type: 'REMOVE_INCLUDED_DATE',
index,
dayTypes,
date
}
- expect(actions.excludeDateFromPeriod(index, dayTypes, date)).toEqual(expectedAction)
+ expect(actions.removeIncludedDate(index, dayTypes, date)).toEqual(expectedAction)
+ })
+
+ it('should create an action to add an excluded date in period', () => {
+ let index = 1
+ let date = actions.formatDate(new Date)
+ const expectedAction = {
+ type: 'ADD_EXCLUDED_DATE',
+ index,
+ dayTypes,
+ date
+ }
+ expect(actions.addExcludedDate(index, dayTypes, date)).toEqual(expectedAction)
+ })
+
+ it('should create an action to remove an excluded date from period', () => {
+ let index = 1
+ let date = actions.formatDate(new Date)
+ const expectedAction = {
+ type: 'REMOVE_EXCLUDED_DATE',
+ index,
+ dayTypes,
+ date
+ }
+ expect(actions.removeExcludedDate(index, dayTypes, date)).toEqual(expectedAction)
})
it('should create an action to open confirm modal', () => {
diff --git a/spec/javascripts/time_table/reducers/modal_spec.js b/spec/javascripts/time_table/reducers/modal_spec.js
index 570eb85ed..05d58a138 100644
--- a/spec/javascripts/time_table/reducers/modal_spec.js
+++ b/spec/javascripts/time_table/reducers/modal_spec.js
@@ -171,12 +171,14 @@ describe('modal reducer', () => {
let ttperiods = []
let ttdates = []
+ let metas = []
expect(
modalReducer(state, {
type: 'VALIDATE_PERIOD_FORM',
modalProps : modProps,
timeTablePeriods: ttperiods,
+ metas: metas,
timetableInDates: ttdates,
error: 'La date de départ doit être antérieure à la date de fin'
})
@@ -289,9 +291,12 @@ describe('modal reducer', () => {
index: false,
error: ''
}
- let ttperiods3 = []
+ let ttperiods3 = []
let ttdates3 = [{date: "2017-08-04", include_date: true}]
+ let metas = {
+ day_types: [true,true,true,true,true,true,true]
+ }
let newModalProps3 = {
active: true,
@@ -315,6 +320,7 @@ describe('modal reducer', () => {
modalProps : modProps3,
timeTablePeriods: ttperiods3,
timetableInDates: ttdates3,
+ metas: metas,
error: "Une période ne peut chevaucher une date dans un calendrier"
})
).toEqual(Object.assign({}, state3, {modalProps: newModalProps3}))
diff --git a/spec/javascripts/time_table/reducers/pagination_spec.js b/spec/javascripts/time_table/reducers/pagination_spec.js
index 5da58427e..3c1edb9c5 100644
--- a/spec/javascripts/time_table/reducers/pagination_spec.js
+++ b/spec/javascripts/time_table/reducers/pagination_spec.js
@@ -76,20 +76,38 @@ describe('pagination reducer', () => {
).toEqual(Object.assign({}, state, {currentPage : page, stateChanged: false}))
})
- it('should handle INCLUDE_DATE_IN_PERIOD', () => {
+ it('should handle ADD_INCLUDED_DATE', () => {
expect(
paginationReducer(state, {
- type: 'INCLUDE_DATE_IN_PERIOD'
+ type: 'ADD_INCLUDED_DATE'
})
).toEqual(Object.assign({}, state, {stateChanged: true}))
})
- it('should handle EXCLUDE_DATE_FROM_PERIOD', () => {
+
+ it('should handle REMOVE_INCLUDED_DATE', () => {
+ expect(
+ paginationReducer(state, {
+ type: 'REMOVE_INCLUDED_DATE'
+ })
+ ).toEqual(Object.assign({}, state, {stateChanged: true}))
+ })
+
+ it('should handle ADD_EXCLUDED_DATE', () => {
expect(
paginationReducer(state, {
- type: 'EXCLUDE_DATE_FROM_PERIOD'
+ type: 'ADD_EXCLUDED_DATE'
})
).toEqual(Object.assign({}, state, {stateChanged: true}))
})
+
+ it('should handle REMOVE_EXCLUDED_DATE', () => {
+ expect(
+ paginationReducer(state, {
+ type: 'REMOVE_EXCLUDED_DATE'
+ })
+ ).toEqual(Object.assign({}, state, {stateChanged: true}))
+ })
+
it('should handle DELETE_PERIOD', () => {
expect(
paginationReducer(state, {
diff --git a/spec/javascripts/time_table/reducers/timetable_spec.js b/spec/javascripts/time_table/reducers/timetable_spec.js
index 6585a78a0..21f6d236d 100644
--- a/spec/javascripts/time_table/reducers/timetable_spec.js
+++ b/spec/javascripts/time_table/reducers/timetable_spec.js
@@ -6,14 +6,13 @@ const dispatch = function(){}
let arrDayTypes = [true, true, true, true, true, true, true]
let strDayTypes = 'LuMaMeJeVeSaDi'
let time_table_periods = [{"id":261,"period_start":"2017-02-23","period_end":"2017-03-05"},{"id":262,"period_start":"2017-03-15","period_end":"2017-03-25"},{"id":263,"period_start":"2017-04-04","period_end":"2017-04-14"},{"id":264,"period_start":"2017-04-24","period_end":"2017-05-04"},{"id":265,"period_start":"2017-05-14","period_end":"2017-05-24"}]
+let time_table_dates = []
let current_periode_range = "2017-05-01"
let periode_range = ["2014-05-01","2014-06-01","2014-07-01","2014-08-01","2014-09-01","2014-10-01","2014-11-01","2014-12-01","2015-01-01","2015-02-01","2015-03-01","2015-04-01","2015-05-01","2015-06-01","2015-07-01","2015-08-01","2015-09-01","2015-10-01","2015-11-01","2015-12-01","2016-01-01","2016-02-01","2016-03-01","2016-04-01","2016-05-01","2016-06-01","2016-07-01","2016-08-01","2016-09-01","2016-10-01","2016-11-01","2016-12-01","2017-01-01","2017-02-01","2017-03-01","2017-04-01","2017-05-01","2017-06-01","2017-07-01","2017-08-01","2017-09-01","2017-10-01","2017-11-01","2017-12-01","2018-01-01","2018-02-01","2018-03-01","2018-04-01","2018-05-01","2018-06-01","2018-07-01","2018-08-01","2018-09-01","2018-10-01","2018-11-01","2018-12-01","2019-01-01","2019-02-01","2019-03-01","2019-04-01","2019-05-01","2019-06-01","2019-07-01","2019-08-01","2019-09-01","2019-10-01","2019-11-01","2019-12-01","2020-01-01","2020-02-01","2020-03-01","2020-04-01","2020-05-01"]
let current_month = [{"day":"lundi","date":"2017-05-01","wday":1,"wnumber":"18","mday":1,"include_date":false,"excluded_date":false},{"day":"mardi","date":"2017-05-02","wday":2,"wnumber":"18","mday":2,"include_date":false,"excluded_date":false},{"day":"mercredi","date":"2017-05-03","wday":3,"wnumber":"18","mday":3,"include_date":false,"excluded_date":false},{"day":"jeudi","date":"2017-05-04","wday":4,"wnumber":"18","mday":4,"include_date":false,"excluded_date":false},{"day":"vendredi","date":"2017-05-05","wday":5,"wnumber":"18","mday":5,"include_date":false,"excluded_date":false},{"day":"samedi","date":"2017-05-06","wday":6,"wnumber":"18","mday":6,"include_date":false,"excluded_date":false},{"day":"dimanche","date":"2017-05-07","wday":0,"wnumber":"18","mday":7,"include_date":false,"excluded_date":false},{"day":"lundi","date":"2017-05-08","wday":1,"wnumber":"19","mday":8,"include_date":false,"excluded_date":false},{"day":"mardi","date":"2017-05-09","wday":2,"wnumber":"19","mday":9,"include_date":false,"excluded_date":false},{"day":"mercredi","date":"2017-05-10","wday":3,"wnumber":"19","mday":10,"include_date":false,"excluded_date":false},{"day":"jeudi","date":"2017-05-11","wday":4,"wnumber":"19","mday":11,"include_date":false,"excluded_date":false},{"day":"vendredi","date":"2017-05-12","wday":5,"wnumber":"19","mday":12,"include_date":false,"excluded_date":false},{"day":"samedi","date":"2017-05-13","wday":6,"wnumber":"19","mday":13,"include_date":false,"excluded_date":false},{"day":"dimanche","date":"2017-05-14","wday":0,"wnumber":"19","mday":14,"include_date":false,"excluded_date":false},{"day":"lundi","date":"2017-05-15","wday":1,"wnumber":"20","mday":15,"include_date":false,"excluded_date":false},{"day":"mardi","date":"2017-05-16","wday":2,"wnumber":"20","mday":16,"include_date":false,"excluded_date":false},{"day":"mercredi","date":"2017-05-17","wday":3,"wnumber":"20","mday":17,"include_date":false,"excluded_date":false},{"day":"jeudi","date":"2017-05-18","wday":4,"wnumber":"20","mday":18,"include_date":false,"excluded_date":false},{"day":"vendredi","date":"2017-05-19","wday":5,"wnumber":"20","mday":19,"include_date":false,"excluded_date":false},{"day":"samedi","date":"2017-05-20","wday":6,"wnumber":"20","mday":20,"include_date":false,"excluded_date":false},{"day":"dimanche","date":"2017-05-21","wday":0,"wnumber":"20","mday":21,"include_date":false,"excluded_date":false},{"day":"lundi","date":"2017-05-22","wday":1,"wnumber":"21","mday":22,"include_date":false,"excluded_date":false},{"day":"mardi","date":"2017-05-23","wday":2,"wnumber":"21","mday":23,"include_date":false,"excluded_date":false},{"day":"mercredi","date":"2017-05-24","wday":3,"wnumber":"21","mday":24,"include_date":false,"excluded_date":false},{"day":"jeudi","date":"2017-05-25","wday":4,"wnumber":"21","mday":25,"include_date":false,"excluded_date":false},{"day":"vendredi","date":"2017-05-26","wday":5,"wnumber":"21","mday":26,"include_date":false,"excluded_date":false},{"day":"samedi","date":"2017-05-27","wday":6,"wnumber":"21","mday":27,"include_date":false,"excluded_date":false},{"day":"dimanche","date":"2017-05-28","wday":0,"wnumber":"21","mday":28,"include_date":false,"excluded_date":false},{"day":"lundi","date":"2017-05-29","wday":1,"wnumber":"22","mday":29,"include_date":false,"excluded_date":false},{"day":"mardi","date":"2017-05-30","wday":2,"wnumber":"22","mday":30,"include_date":false,"excluded_date":false},{"day":"mercredi","date":"2017-05-31","wday":3,"wnumber":"22","mday":31,"include_date":false,"excluded_date":false}]
let newCurrentMonth = [{"day":"lundi","date":"2017-05-01","wday":1,"wnumber":"18","mday":1,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"mardi","date":"2017-05-02","wday":2,"wnumber":"18","mday":2,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"mercredi","date":"2017-05-03","wday":3,"wnumber":"18","mday":3,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"jeudi","date":"2017-05-04","wday":4,"wnumber":"18","mday":4,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"vendredi","date":"2017-05-05","wday":5,"wnumber":"18","mday":5,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"samedi","date":"2017-05-06","wday":6,"wnumber":"18","mday":6,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"dimanche","date":"2017-05-07","wday":0,"wnumber":"18","mday":7,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"lundi","date":"2017-05-08","wday":1,"wnumber":"19","mday":8,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"mardi","date":"2017-05-09","wday":2,"wnumber":"19","mday":9,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"mercredi","date":"2017-05-10","wday":3,"wnumber":"19","mday":10,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"jeudi","date":"2017-05-11","wday":4,"wnumber":"19","mday":11,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"vendredi","date":"2017-05-12","wday":5,"wnumber":"19","mday":12,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"samedi","date":"2017-05-13","wday":6,"wnumber":"19","mday":13,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"dimanche","date":"2017-05-14","wday":0,"wnumber":"19","mday":14,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"lundi","date":"2017-05-15","wday":1,"wnumber":"20","mday":15,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"mardi","date":"2017-05-16","wday":2,"wnumber":"20","mday":16,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"mercredi","date":"2017-05-17","wday":3,"wnumber":"20","mday":17,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"jeudi","date":"2017-05-18","wday":4,"wnumber":"20","mday":18,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"vendredi","date":"2017-05-19","wday":5,"wnumber":"20","mday":19,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"samedi","date":"2017-05-20","wday":6,"wnumber":"20","mday":20,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"dimanche","date":"2017-05-21","wday":0,"wnumber":"20","mday":21,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"lundi","date":"2017-05-22","wday":1,"wnumber":"21","mday":22,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"mardi","date":"2017-05-23","wday":2,"wnumber":"21","mday":23,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"mercredi","date":"2017-05-24","wday":3,"wnumber":"21","mday":24,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"jeudi","date":"2017-05-25","wday":4,"wnumber":"21","mday":25,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"vendredi","date":"2017-05-26","wday":5,"wnumber":"21","mday":26,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"samedi","date":"2017-05-27","wday":6,"wnumber":"21","mday":27,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"dimanche","date":"2017-05-28","wday":0,"wnumber":"21","mday":28,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"lundi","date":"2017-05-29","wday":1,"wnumber":"22","mday":29,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"mardi","date":"2017-05-30","wday":2,"wnumber":"22","mday":30,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"mercredi","date":"2017-05-31","wday":3,"wnumber":"22","mday":31,"include_date":false,"excluded_date":false,"in_periods":false}]
-let time_table_dates = []
-
let json = {
current_month: current_month,
current_periode_range: current_periode_range,
@@ -46,7 +45,7 @@ describe('timetable reducer with empty state', () => {
current_periode_range: current_periode_range,
periode_range: periode_range,
time_table_periods: time_table_periods,
- time_table_dates: time_table_dates
+ time_table_dates: []
}
expect(
timetableReducer(state, {
@@ -125,24 +124,46 @@ describe('timetable reducer with filled state', () => {
).toEqual(Object.assign({}, state, {current_periode_range: newPage}))
})
- it('should handle DELETE_PERIOD', () => {
- state.time_table_periods[0].deleted = true
+ it('should handle DELETE_PERIOD and remove excluded days that were in period', () => {
+ state.time_table_dates.push({date: "2017-05-01", in_out: false})
+ state.current_month[0].excluded_date = true
+ state.time_table_periods[3].deleted = true
+
+ let begin = new Date(state.time_table_periods[3].period_start)
+ let end = new Date(state.time_table_periods[3].period_end)
+
+ let newState = Object.assign({}, state, {
+ time_table_dates: [],
+ current_month: state.current_month.map((d, i) => {
+ if (new Date(d.date) >= begin && new Date(d.date) <= end) {
+ d.excluded_date = false
+ d.in_periods = false
+ }
+ return d
+ })
+ })
expect(
timetableReducer(state, {
type: 'DELETE_PERIOD',
- index: 0,
+ index: 3,
dayTypes: arrDayTypes
})
- ).toEqual(state)
+ ).toEqual(newState)
})
- it('should handle INCLUDE_DATE_IN_PERIOD and add in_day if TT doesnt have it', () => {
+ it('should handle ADD_INCLUDED_DATE', () => {
let newDates = state.time_table_dates.concat({date: "2017-05-05", in_out: true})
- let newState = Object.assign({}, state, {time_table_dates: newDates})
- state.current_month[4].include_date = true
+
+ let newCM = newCurrentMonth.map((d,i) => {
+ if (i == 4) d.include_date = true
+ return d
+ })
+
+ let newState = Object.assign({}, state, {time_table_dates: newDates, current_month: newCM})
+
expect(
timetableReducer(state, {
- type: 'INCLUDE_DATE_IN_PERIOD',
+ type: 'ADD_INCLUDED_DATE',
index: 4,
dayTypes: arrDayTypes,
date: "2017-05-05"
@@ -150,13 +171,20 @@ describe('timetable reducer with filled state', () => {
).toEqual(newState)
})
- it('should handle INCLUDE_DATE_IN_PERIOD and remove in_day if TT has it', () => {
+ it('should handle REMOVE_INCLUDED_DATE', () => {
state.current_month[4].include_date = true
state.time_table_dates.push({date: "2017-05-05", in_out: true})
- let newState = Object.assign({}, state, {time_table_dates: []})
+
+ let newCM = newCurrentMonth.map((d,i) => {
+ if (i == 4) d.include_date = false
+ return d
+ })
+
+ let newDates = state.time_table_dates.filter(d => d.date != "2017-05-05" && d.in_out != true )
+ let newState = Object.assign({}, state, {time_table_dates: newDates, current_month: newCM})
expect(
timetableReducer(state, {
- type: 'INCLUDE_DATE_IN_PERIOD',
+ type: 'REMOVE_INCLUDED_DATE',
index: 4,
dayTypes: arrDayTypes,
date: "2017-05-05"
@@ -164,13 +192,22 @@ describe('timetable reducer with filled state', () => {
).toEqual(newState)
})
- it('should handle EXCLUDE_DATE_FROM_PERIOD and add out_day if TT doesnt have it', () => {
+ it('should handle ADD_EXCLUDED_DATE', () => {
let newDates = state.time_table_dates.concat({date: "2017-05-01", in_out: false})
- let newState = Object.assign({}, state, {time_table_dates: newDates})
- state.current_month[0].excluded_date = true
+
+ let newCM = newCurrentMonth.map((d,i) => {
+ if (i == 0){
+ d.include_date = false
+ d.excluded_date = true
+ }
+ return d
+ })
+
+ let newState = Object.assign({}, state, {time_table_dates: newDates, current_month: newCM})
+
expect(
timetableReducer(state, {
- type: 'EXCLUDE_DATE_FROM_PERIOD',
+ type: 'ADD_EXCLUDED_DATE',
index: 0,
dayTypes: arrDayTypes,
date: "2017-05-01"
@@ -178,13 +215,13 @@ describe('timetable reducer with filled state', () => {
).toEqual(newState)
})
- it('should handle EXCLUDE_DATE_FROM_PERIOD and remove out_day if TT has it', () => {
+ it('should handle REMOVE_EXCLUDED_DATE', () => {
state.time_table_dates = [{date: "2017-05-01", in_out: false}]
- state.current_month[0].excluded_date = true
+ state.current_month[0].excluded_date = false
let newState = Object.assign({}, state, {time_table_dates: []})
expect(
timetableReducer(state, {
- type: 'EXCLUDE_DATE_FROM_PERIOD',
+ type: 'REMOVE_EXCLUDED_DATE',
index: 0,
dayTypes: arrDayTypes,
date: "2017-05-01"
@@ -194,9 +231,10 @@ describe('timetable reducer with filled state', () => {
it('should handle UPDATE_DAY_TYPES and remove out_day that are out of day types', () => {
state.time_table_dates = [{date: "2017-05-01", in_out: false}]
- let newArrDayTypes = arrDayTypes.slice(0)
- newArrDayTypes[1] = false
- let newState = Object.assign({}, state, {time_table_dates: []})
+ let newArrDayTypes = Array.from(arrDayTypes, (dt, i) => {
+ if (i == 1) dt = false
+ return dt
+ })
expect(
timetableReducer(state, {
type: 'UPDATE_DAY_TYPES',
@@ -205,9 +243,19 @@ describe('timetable reducer with filled state', () => {
).toEqual([])
})
+ it('should handle UPDATE_DAY_TYPES and remove in_day that are in day types and in period', () => {
+ state.time_table_dates = [{ date: "2017-05-16", in_out: true }]
+ expect(
+ timetableReducer(state, {
+ type: 'UPDATE_DAY_TYPES',
+ dayTypes: arrDayTypes
+ }).time_table_dates
+ ).toEqual([])
+ })
+
it('should handle VALIDATE_PERIOD_FORM and add period if modalProps index = false', () => {
let newPeriods = state.time_table_periods.concat({"period_start": "2018-05-15", "period_end": "2018-05-24"})
- let newState = Object.assign({}, state, {time_table_periods: newPeriods})
+ let newState = Object.assign({}, state, {time_table_periods: newPeriods, time_table_dates: []})
let modalProps = {
active: false,
begin: {
@@ -236,4 +284,53 @@ describe('timetable reducer with filled state', () => {
})
).toEqual(newState)
})
+
+ it('should handle VALIDATE_PERIOD_FORM and update period if modalProps index != false', () => {
+
+ let begin = new Date(state.time_table_periods[0].period_start)
+ let end = new Date(state.time_table_periods[0].period_end)
+ let newCM = newCurrentMonth.map((d) => {
+ if (new Date (d.date) >= begin && new Date(d.date) <= end) {
+ d.in_periods = false
+ d.excluded_date = false
+ }
+ return d
+ })
+
+ let newPeriods = state.time_table_periods.map( (p,i) => {
+ if (i == 0) {
+ p.period_start = "2018-05-15"
+ p.period_end = "2018-05-24"
+ }
+ return p
+ })
+ let newState = Object.assign({}, state, {time_table_periods: newPeriods})
+
+ let modalProps = {
+ active: false,
+ begin: {
+ day: '15',
+ month: '05',
+ year: '2018'
+ },
+ end: {
+ day: '24',
+ month: '05',
+ year: '2018'
+ },
+ error: '',
+ index: 0
+ }
+ expect(
+ timetableReducer(state, {
+ type: 'VALIDATE_PERIOD_FORM',
+ modalProps: modalProps,
+ timeTablePeriods: state.time_table_periods,
+ metas: {
+ day_types: arrDayTypes
+ },
+ timetableInDates: state.time_table_dates.filter(d => d.in_out == true)
+ })
+ ).toEqual(newState)
+ })
})
diff --git a/spec/lib/model_attribute_spec.rb b/spec/lib/model_attribute_spec.rb
new file mode 100644
index 000000000..cdba87a90
--- /dev/null
+++ b/spec/lib/model_attribute_spec.rb
@@ -0,0 +1,111 @@
+RSpec.describe ModelAttribute do
+ before(:each) do
+ ModelAttribute.instance_variable_set(:@__all__, [])
+ end
+
+ describe ".define" do
+ it "adds a new instance of ModelAttribute to .all" do
+ expect do
+ ModelAttribute.define(:route, :name, :string)
+ end.to change { ModelAttribute.all.length }.by(1)
+
+ model_attr = ModelAttribute.all.last
+
+ expect(model_attr).to be_an_instance_of(ModelAttribute)
+ expect(model_attr.klass).to eq(:route)
+ expect(model_attr.name).to eq(:name)
+ expect(model_attr.data_type).to eq(:string)
+ end
+ end
+
+ describe ".classes" do
+ it "returns the list of classes of ModelAttributes in .all" do
+ ModelAttribute.define(:route, :name, :string)
+ ModelAttribute.define(:journey_pattern, :name, :string)
+ ModelAttribute.define(:time_table, :start_date, :date)
+
+ expect(ModelAttribute.classes).to match_array([
+ 'Route',
+ 'JourneyPattern',
+ 'TimeTable'
+ ])
+ end
+ end
+
+ describe ".from_code" do
+ it "returns a ModelAttribute from a given code" do
+ ModelAttribute.define(:journey_pattern, :name, :string)
+
+ expect(ModelAttribute.from_code('journey_pattern#name')).to eq(
+ ModelAttribute.new(:journey_pattern, :name, :string)
+ )
+ end
+ end
+
+ describe ".group_by_class" do
+ it "returns all ModelAttributes grouped by klass" do
+ ModelAttribute.define(:route, :name, :string)
+ ModelAttribute.define(:route, :published_name, :string)
+ ModelAttribute.define(:journey_pattern, :name, :string)
+ ModelAttribute.define(:vehicle_journey, :number, :integer)
+
+ expect(ModelAttribute.group_by_class).to eq({
+ route: [
+ ModelAttribute.new(:route, :name, :string),
+ ModelAttribute.new(:route, :published_name, :string),
+ ],
+ journey_pattern: [
+ ModelAttribute.new(:journey_pattern, :name, :string),
+ ],
+ vehicle_journey: [
+ ModelAttribute.new(:vehicle_journey, :number, :integer)
+ ]
+ })
+ end
+ end
+
+ describe ".methods_by_class" do
+ it "returns all ModelAttributes for a given class" do
+ ModelAttribute.define(:route, :name, :string)
+ ModelAttribute.define(:route, :published_name, :string)
+ ModelAttribute.define(:route, :direction, :string)
+ ModelAttribute.define(:journey_pattern, :name, :string)
+
+ expect(ModelAttribute.methods_by_class(:route)).to match_array([
+ ModelAttribute.new(:route, :name, :string),
+ ModelAttribute.new(:route, :published_name, :string),
+ ModelAttribute.new(:route, :direction, :string)
+ ])
+ end
+ end
+
+ describe ".methods_by_class_and_type" do
+ it "returns ModelAttributes of a certain class and type" do
+ ModelAttribute.define(:route, :name, :string)
+ ModelAttribute.define(:route, :checked_at, :date)
+ ModelAttribute.define(:journey_pattern, :name, :string)
+ ModelAttribute.define(:journey_pattern, :section_status, :integer)
+
+ expect(ModelAttribute.methods_by_class_and_type(:route, :string)).to match_array([
+ ModelAttribute.new(:route, :name, :string)
+ ])
+ end
+ end
+
+ describe "#code" do
+ it "returns a string representation of the attribute" do
+ model_attr = ModelAttribute.new(:route, :name, :string)
+
+ expect(model_attr.code).to eq('route#name')
+ end
+ end
+
+ describe "#==" do
+ it "returns true when :klass, :name, and :data_type attributes match" do
+ route_name = ModelAttribute.new(:route, :name, :string)
+ other_route_name = ModelAttribute.new(:route, :name, :string)
+
+ expect(route_name == other_route_name).to be true
+ end
+ end
+end
diff --git a/spec/models/chouette/vehicle_journey_at_stop_spec.rb b/spec/models/chouette/vehicle_journey_at_stop_spec.rb
index 4f9d12730..03e6fcb7d 100644
--- a/spec/models/chouette/vehicle_journey_at_stop_spec.rb
+++ b/spec/models/chouette/vehicle_journey_at_stop_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe Chouette::VehicleJourneyAtStop, type: :model do
)
error_message = I18n.t(
'vehicle_journey_at_stops.errors.day_offset_must_not_exceed_max',
- local_id: at_stop.vehicle_journey.objectid.local_id,
+ short_id: at_stop.vehicle_journey.objectid.short_id,
max: bad_offset
)
diff --git a/spec/models/referential_spec.rb b/spec/models/referential_spec.rb
index f9ace08cc..bb8fabb2e 100644
--- a/spec/models/referential_spec.rb
+++ b/spec/models/referential_spec.rb
@@ -10,6 +10,7 @@ describe Referential, :type => :model do
it { should have_many(:metadatas) }
it { should belong_to(:workbench) }
+ it { should belong_to(:referential_suite) }
context ".referential_ids_in_periode" do
it 'should retrieve referential id in periode range' do
diff --git a/spec/models/referential_suite_spec.rb b/spec/models/referential_suite_spec.rb
new file mode 100644
index 000000000..771187b55
--- /dev/null
+++ b/spec/models/referential_suite_spec.rb
@@ -0,0 +1,5 @@
+RSpec.describe ReferentialSuite, type: :model do
+ it { should belong_to(:new).class_name('Referential') }
+ it { should belong_to(:current).class_name('Referential') }
+ it { should have_many(:referentials) }
+end
diff --git a/spec/policies/api_key_policy_spec.rb b/spec/policies/api_key_policy_spec.rb
index f0242978e..3638a05b2 100644
--- a/spec/policies/api_key_policy_spec.rb
+++ b/spec/policies/api_key_policy_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe ApiKeyPolicy do
end
context 'permission present → ' do
it 'allows a user with a different organisation' do
- add_permissions('api_keys.create', for_user: user)
+ add_permissions('api_keys.create', to_user: user)
expect_it.to permit(user_context, record)
end
end
@@ -40,7 +40,7 @@ RSpec.describe ApiKeyPolicy do
context 'permission present → ' do
before do
- add_permissions('api_keys.update', for_user: user)
+ add_permissions('api_keys.update', to_user: user)
end
it 'denies a user with a different organisation' do
diff --git a/spec/policies/import_policy_spec.rb b/spec/policies/import_policy_spec.rb
new file mode 100644
index 000000000..fd9f3172c
--- /dev/null
+++ b/spec/policies/import_policy_spec.rb
@@ -0,0 +1,41 @@
+RSpec.describe ImportPolicy, type: :policy do
+
+ let( :record ){ build_stubbed :import }
+ before { stub_policy_scope(record) }
+
+ #
+ # Non Destructive
+ # ---------------
+
+ context 'Non Destructive actions →' do
+ permissions :index? do
+ it_behaves_like 'always allowed', 'anything', archived: true
+ end
+ permissions :show? do
+ it_behaves_like 'always allowed', 'anything', archived: true
+ end
+ end
+
+
+ #
+ # Destructive
+ # -----------
+
+ context 'Destructive actions →' do
+ permissions :create? do
+ it_behaves_like 'permitted policy', 'imports.create', archived: true
+ end
+ permissions :destroy? do
+ it_behaves_like 'permitted policy', 'imports.destroy', archived: true
+ end
+ permissions :edit? do
+ it_behaves_like 'permitted policy', 'imports.update', archived: true
+ end
+ permissions :new? do
+ it_behaves_like 'permitted policy', 'imports.create', archived: true
+ end
+ permissions :update? do
+ it_behaves_like 'permitted policy', 'imports.update', archived: true
+ end
+ end
+end
diff --git a/spec/policies/referential_policy_spec.rb b/spec/policies/referential_policy_spec.rb
index 69d0eb17b..d00415fc6 100644
--- a/spec/policies/referential_policy_spec.rb
+++ b/spec/policies/referential_policy_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe ReferentialPolicy, type: :policy do
permissions :create? do
it 'permissions present → allowed' do
- add_permissions('referentials.create', for_user: user)
+ add_permissions('referentials.create', to_user: user)
expect_it.to permit(user_context, record)
end
it 'permissions absent → forbidden' do
@@ -19,7 +19,7 @@ RSpec.describe ReferentialPolicy, type: :policy do
permissions :new? do
it 'permissions present → allowed' do
- add_permissions('referentials.create', for_user: user)
+ add_permissions('referentials.create', to_user: user)
expect_it.to permit(user_context, record)
end
it 'permissions absent → forbidden' do
@@ -53,7 +53,7 @@ RSpec.describe ReferentialPolicy, type: :policy do
context 'permission present →' do
before do
- add_permissions('referentials.update', for_user: user)
+ add_permissions('referentials.update', to_user: user)
end
context 'same organisation →' do
@@ -108,7 +108,7 @@ RSpec.describe ReferentialPolicy, type: :policy do
context 'permission present →' do
before do
- add_permissions('referentials.update', for_user: user)
+ add_permissions('referentials.update', to_user: user)
end
context 'same organisation →' do
diff --git a/spec/support/permissions.rb b/spec/support/permissions.rb
index 467c07a32..13666aca3 100644
--- a/spec/support/permissions.rb
+++ b/spec/support/permissions.rb
@@ -18,6 +18,7 @@ module Support
connection_links
calendars
footnotes
+ imports
journey_patterns
referentials
routes
diff --git a/spec/support/pundit/policies.rb b/spec/support/pundit/policies.rb
index d5bb63243..a3489d9db 100644
--- a/spec/support/pundit/policies.rb
+++ b/spec/support/pundit/policies.rb
@@ -3,18 +3,18 @@ require 'pundit/rspec'
module Support
module Pundit
module Policies
- def add_permissions(*permissions, for_user:)
- for_user.permissions ||= []
- for_user.permissions += permissions.flatten
+ def add_permissions(*permissions, to_user:)
+ to_user.permissions ||= []
+ to_user.permissions += permissions.flatten
end
def create_user_context(user:, referential:)
UserContext.new(user, referential: referential)
end
- def add_permissions(*permissions, for_user:)
- for_user.permissions ||= []
- for_user.permissions += permissions.flatten
+ def remove_permissions(*permissions, from_user:, save: false)
+ from_user.permissions -= permissions.flatten
+ from_user.save! if save
end
end
@@ -30,7 +30,7 @@ module Support
end
def with_user_permission(permission, &blk)
it "with user permission #{permission.inspect}" do
- add_permissions(permission, for_user: user)
+ add_permissions(permission, to_user: user)
blk.()
end
end
@@ -41,7 +41,7 @@ module Support
perms, options = permissions.partition{|x| String === x}
context "with permissions #{perms.inspect}...", *options do
before do
- add_permissions(*permissions, for_user: @user)
+ add_permissions(*permissions, to_user: @user)
end
instance_eval(&blk)
end
@@ -51,6 +51,7 @@ module Support
end
RSpec.configure do | c |
+ c.include Support::Pundit::Policies, type: :controller
c.include Support::Pundit::Policies, type: :policy
c.extend Support::Pundit::PoliciesMacros, type: :policy
c.include Support::Pundit::Policies, type: :feature
diff --git a/spec/support/pundit/shared_examples.rb b/spec/support/pundit/shared_examples.rb
index 63a106759..49c6845da 100644
--- a/spec/support/pundit/shared_examples.rb
+++ b/spec/support/pundit/shared_examples.rb
@@ -18,7 +18,7 @@ RSpec.shared_examples 'always allowed' do
context 'different organisations →' do
before do
- add_permissions(permission, for_user: user)
+ add_permissions(permission, to_user: user)
end
it "allows a user with a different organisation" do
expect_it.to permit(user_context, record)
@@ -51,7 +51,7 @@ RSpec.shared_examples 'always forbidden' do
context 'different organisations →' do
before do
- add_permissions(permission, for_user: user)
+ add_permissions(permission, to_user: user)
end
it "denies a user with a different organisation" do
expect_it.not_to permit(user_context, record)
@@ -80,7 +80,7 @@ RSpec.shared_examples 'permitted policy and same organisation' do
context 'permission present → ' do
before do
- add_permissions(permission, for_user: user)
+ add_permissions(permission, to_user: user)
end
it 'denies a user with a different organisation' do
@@ -113,7 +113,7 @@ RSpec.shared_examples 'permitted policy' do
context 'permission present → ' do
before do
- add_permissions(permission, for_user: user)
+ add_permissions(permission, to_user: user)
end
it 'allows user' do