diff options
| author | Florent Peyraud | 2017-07-11 10:48:15 +0200 |
|---|---|---|
| committer | Florent Peyraud | 2017-07-11 10:48:15 +0200 |
| commit | 4db6d356602660bdf1fd02e713beaa068cb0fa0b (patch) | |
| tree | 9c44c8fa9dc6c4c4aa284490ab17c87565833986 | |
| parent | 485adab2f70fb071f936bb32f05fe6e0f88b6231 (diff) | |
| parent | ade9962a6de04a0b033c060c859a0676869db43f (diff) | |
| download | chouette-core-4db6d356602660bdf1fd02e713beaa068cb0fa0b.tar.bz2 | |
Merge branch 'master' of github.com:AF83/stif-boiv
41 files changed, 374 insertions, 139 deletions
diff --git a/Gemfile.lock b/Gemfile.lock index 256967c04..41ae70f56 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -261,7 +261,7 @@ GEM has_scope (0.7.0) actionpack (>= 4.1, < 5.1) activesupport (>= 4.1, < 5.1) - hashdiff (0.3.2) + hashdiff (0.3.4) highline (1.7.8) hike (1.2.3) htmlbeautifier (1.3.1) @@ -539,7 +539,7 @@ GEM unicode-display_width (1.1.3) warden (1.2.7) rack (>= 1.0) - webmock (3.0.0) + webmock (3.0.1) addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js index 5aade3348..b446e2b37 100644 --- a/app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js +++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js @@ -17,7 +17,7 @@ class CreateModal extends Component { } render() { - if(this.props.status.isFetching == true || this.props.status.policy['journey_patterns.edit'] == false) { + if(this.props.status.isFetching == true || this.props.status.policy['journey_patterns.update'] == false) { return false } if(this.props.status.fetchSuccess == true) { diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js index 18ed5f889..286cfc454 100644 --- a/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js +++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js @@ -34,7 +34,7 @@ class JourneyPattern extends Component{ type='checkbox' id={sp.id} checked={sp.checked} - disabled={(this.props.value.deletable || this.props.status.policy['journey_patterns.edit'] == false) ? 'disabled' : ''} + disabled={(this.props.value.deletable || this.props.status.policy['journey_patterns.update'] == false) ? 'disabled' : ''} > </input> <span className='radio-label'></span> @@ -78,7 +78,7 @@ class JourneyPattern extends Component{ <span className='fa fa-cog'></span> </div> <ul className='dropdown-menu'> - <li className={(this.props.value.deletable || this.props.status.policy['journey_patterns.edit'] == false) ? 'disabled' : ''}> + <li className={(this.props.value.deletable || this.props.status.policy['journey_patterns.update'] == false) ? 'disabled' : ''}> <button type='button' onClick={this.props.onOpenEditModal} @@ -91,10 +91,10 @@ class JourneyPattern extends Component{ <li className={this.props.value.object_id ? '' : 'disabled'}> {this.vehicleJourneyURL(this.props.value.object_id)} </li> - <li className={'delete-action' + ((this.props.status.policy['journey_patterns.edit'] == false)? ' disabled' : '')}> + <li className={'delete-action' + ((this.props.status.policy['journey_patterns.update'] == false)? ' disabled' : '')}> <button type='button' - disabled={(this.props.status.policy['journey_patterns.edit'] == false)? 'disabled' : ''} + disabled={(this.props.status.policy['journey_patterns.update'] == false)? 'disabled' : ''} onClick={(e) => { e.preventDefault() this.props.onDeleteJourneyPattern(this.props.index)} diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/SaveJourneyPattern.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/SaveJourneyPattern.js index ca266af08..871ba00e1 100644 --- a/app/assets/javascripts/es6_browserified/journey_patterns/components/SaveJourneyPattern.js +++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/SaveJourneyPattern.js @@ -9,7 +9,7 @@ class SaveJourneyPattern extends Component{ } render() { - if(this.props.status.policy['journey_patterns.edit'] == false) { + if(this.props.status.policy['journey_patterns.update'] == false) { return false }else{ return ( diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/SaveVehicleJourneys.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/SaveVehicleJourneys.js index 27a82cf48..05dda976d 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/SaveVehicleJourneys.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/SaveVehicleJourneys.js @@ -9,7 +9,7 @@ class SaveVehicleJourneys extends Component{ } render() { - if(this.props.filters.policy['vehicle_journeys.edit'] == false) { + if(this.props.filters.policy['vehicle_journeys.update'] == false) { return false }else{ return ( diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/VehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/VehicleJourney.js index de370ac1b..f2bd0c3cd 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/VehicleJourney.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/VehicleJourney.js @@ -58,7 +58,7 @@ class VehicleJourney extends Component { )} </div> - {(this.props.filters.policy['vehicle_journeys.edit'] == true) && + {(this.props.filters.policy['vehicle_journeys.update'] == true) && <div className={(this.props.value.deletable ? 'disabled ' : '') + 'checkbox'}> <input id={this.props.index} @@ -79,13 +79,13 @@ class VehicleJourney extends Component { <div className={'cellwrap' + (this.cityNameChecker(vj) ? ' headlined' : '')}> {this.props.filters.toggleArrivals && <div data-headline='Arrivée à'> - <span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false) ? 'disabled ' : '') + 'input-group time'}> + <span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false) ? 'disabled ' : '') + 'input-group time'}> <input type='number' min='00' max='23' className='form-control' - disabled={(this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false)} + disabled={(this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false)} onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'hour', false, false)}} value={vj.arrival_time['hour']} /> @@ -95,7 +95,7 @@ class VehicleJourney extends Component { min='00' max='59' className='form-control' - disabled={((this.isDisabled(this.props.value.deletable), vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false)} + disabled={((this.isDisabled(this.props.value.deletable), vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false)} onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'minute', false, false)}} value={vj.arrival_time['minute']} /> @@ -108,13 +108,13 @@ class VehicleJourney extends Component { } </div> <div data-headline='Départ à'> - <span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false) ? 'disabled ' : '') + 'input-group time'}> + <span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false) ? 'disabled ' : '') + 'input-group time'}> <input type='number' min='00' max='23' className='form-control' - disabled={(this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false)} + disabled={(this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false)} onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'hour', true, this.props.filters.toggleArrivals)}} value={vj.departure_time['hour']} /> @@ -124,7 +124,7 @@ class VehicleJourney extends Component { min='00' max='59' className='form-control' - disabled={(this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false)} + disabled={(this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false)} onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, "minute", true, this.props.filters.toggleArrivals)}} value={vj.departure_time['minute']} /> diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CreateModal.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CreateModal.js index c1e40b3bc..6a1e8ffb9 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CreateModal.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CreateModal.js @@ -27,7 +27,7 @@ class CreateModal extends Component { <li className='st_action'> <button type='button' - disabled={((this.props.filters.policy['vehicle_journeys.edit'] == true) ? '' : 'disabled')} + disabled={((this.props.filters.policy['vehicle_journeys.update'] == true) ? '' : 'disabled')} data-toggle='modal' data-target='#NewVehicleJourneyModal' onClick={this.props.onOpenCreateModal} diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DuplicateVehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DuplicateVehicleJourney.js index aa1a13b11..34463600a 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DuplicateVehicleJourney.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DuplicateVehicleJourney.js @@ -38,7 +38,7 @@ class DuplicateVehicleJourney extends Component { <li className='st_action'> <button type='button' - disabled={((actions.getSelected(this.props.vehicleJourneys).length >= 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled')} + disabled={((actions.getSelected(this.props.vehicleJourneys).length >= 1 && this.props.filters.policy['vehicle_journeys.update']) ? '' : 'disabled')} data-toggle='modal' data-target='#DuplicateVehicleJourneyModal' onClick={this.props.onOpenDuplicateModal} diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/EditVehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/EditVehicleJourney.js index 9919ee9dd..d49ea578a 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/EditVehicleJourney.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/EditVehicleJourney.js @@ -32,7 +32,7 @@ class EditVehicleJourney extends Component { <li className='st_action'> <button type='button' - disabled={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'} + disabled={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.update']) ? '' : 'disabled'} data-toggle='modal' data-target='#EditVehicleJourneyModal' onClick={() => this.props.onOpenEditModal(actions.getSelected(this.props.vehicleJourneys)[0])} diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/NotesEditVehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/NotesEditVehicleJourney.js index 4c18ef96f..df6c311e6 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/NotesEditVehicleJourney.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/NotesEditVehicleJourney.js @@ -59,7 +59,7 @@ class NotesEditVehicleJourney extends Component { <li className='st_action'> <button type='button' - disabled={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'} + disabled={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.update']) ? '' : 'disabled'} data-toggle='modal' data-target='#NotesEditVehicleJourneyModal' onClick={() => this.props.onOpenNotesEditModal(actions.getSelected(this.props.vehicleJourneys)[0])} diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/ShiftVehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/ShiftVehicleJourney.js index 2164344c2..269bb1b8c 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/ShiftVehicleJourney.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/ShiftVehicleJourney.js @@ -25,7 +25,7 @@ class ShiftVehicleJourney extends Component { <li className='st_action'> <button type='button' - disabled={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'} + disabled={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.update']) ? '' : 'disabled'} data-toggle='modal' data-target='#ShiftVehicleJourneyModal' onClick={this.props.onOpenShiftModal} diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js index 82fed23d9..a26a9b805 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js @@ -24,7 +24,7 @@ class TimetablesEditVehicleJourney extends Component { <li className='st_action'> <button type='button' - disabled={(actions.getSelected(this.props.vehicleJourneys).length > 0 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'} + disabled={(actions.getSelected(this.props.vehicleJourneys).length > 0 && this.props.filters.policy['vehicle_journeys.update']) ? '' : 'disabled'} data-toggle='modal' data-target='#CalendarsEditVehicleJourneyModal' onClick={() => this.props.onOpenCalendarsEditModal(actions.getSelected(this.props.vehicleJourneys))} diff --git a/app/controllers/referentials_controller.rb b/app/controllers/referentials_controller.rb index 31b953ace..9505a47f3 100644 --- a/app/controllers/referentials_controller.rb +++ b/app/controllers/referentials_controller.rb @@ -26,6 +26,7 @@ class ReferentialsController < BreadcrumbController resource.switch show! do |format| @referential = @referential.decorate + @reflines = lines_collection.paginate(page: params[:page], per_page: 10) format.json { render :json => { :lines_count => resource.lines.count, @@ -36,8 +37,6 @@ class ReferentialsController < BreadcrumbController } format.html { build_breadcrumb :show} end - - @reflines = lines_collection.paginate(page: params[:page], per_page: 10) end def edit diff --git a/app/decorators/referential_decorator.rb b/app/decorators/referential_decorator.rb index b95b04f9f..ccb47a654 100644 --- a/app/decorators/referential_decorator.rb +++ b/app/decorators/referential_decorator.rb @@ -2,6 +2,7 @@ class ReferentialDecorator < Draper::Decorator delegate_all def action_links + policy = h.policy(object) links = [ Link.new( content: h.t('time_tables.index.title'), @@ -9,40 +10,41 @@ class ReferentialDecorator < Draper::Decorator ) ] - if h.policy(object).clone? + if policy.clone? links << Link.new( content: h.t('actions.clone'), href: h.new_referential_path(from: object.id) ) end + if policy.archive? + links << Link.new( + content: h.t('actions.archive'), + href: h.archive_referential_path(object.id), + method: :put + ) + end - if h.policy(object).edit? + if policy.unarchive? + links << Link.new( + content: h.t('actions.unarchive'), + href: h.unarchive_referential_path(object.id), + method: :put + ) + end - if object.archived? - links << Link.new( - content: h.t('actions.unarchive'), - href: h.unarchive_referential_path(object.id), - method: :put - ) - else - links << HTMLElement.new( - :button, - 'Purger', - type: 'button', - data: { - toggle: 'modal', - target: '#purgeModal' - } - ) - links << Link.new( - content: h.t('actions.archive'), - href: h.archive_referential_path(object.id), - method: :put - ) - end + if policy.edit? + links << HTMLElement.new( + :button, + 'Purger', + type: 'button', + data: { + toggle: 'modal', + target: '#purgeModal' + } + ) end - if h.policy(object).destroy? && !object.archived? + if policy.destroy? links << Link.new( content: h.destroy_link_content, href: h.referential_path(object), diff --git a/app/jobs/mailer_job.rb b/app/jobs/mailer_job.rb index 6d3dc642d..761a29cd6 100644 --- a/app/jobs/mailer_job.rb +++ b/app/jobs/mailer_job.rb @@ -2,6 +2,6 @@ class MailerJob < ActiveJob::Base queue_as :mail def perform klass, action, params - klass.constantize.public_send(action, *params).deliver + klass.constantize.public_send(action, *params).deliver_later end end diff --git a/app/mailers/calendar_mailer.rb b/app/mailers/calendar_mailer.rb index 44dcaea88..cc8175a07 100644 --- a/app/mailers/calendar_mailer.rb +++ b/app/mailers/calendar_mailer.rb @@ -1,9 +1,11 @@ class CalendarMailer < ApplicationMailer def updated calendar, user + @calendar = calendar mail to: user.email, subject: t('mailers.calendar_mailer.updated.subject') end def created calendar, user + @calendar = calendar mail to: user.email, subject: t('mailers.calendar_mailer.created.subject') end end diff --git a/app/models/user.rb b/app/models/user.rb index 5a2e4d3ca..64d66883f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -35,6 +35,9 @@ class User < ActiveRecord::Base @@edit_offer_permissions = destructive_permissions_for( %w[ + access_points + connection_links + calendars footnotes journey_patterns referentials @@ -42,7 +45,7 @@ class User < ActiveRecord::Base routing_constraint_zones time_tables vehicle_journeys - ]) + ]) << 'boiv:edit-offer' mattr_reader :edit_offer_permissions diff --git a/app/policies/calendar_policy.rb b/app/policies/calendar_policy.rb index d3c715d70..074c41d8d 100644 --- a/app/policies/calendar_policy.rb +++ b/app/policies/calendar_policy.rb @@ -6,10 +6,10 @@ class CalendarPolicy < ApplicationPolicy end def create? - !archived? && organisation_match? && user.has_permission?('calendars.create') + !archived? && user.has_permission?('calendars.create') end def destroy? - !archived? && organisation_match? && user.has_permission?('calendars.destroy') + !archived? & organisation_match? && user.has_permission?('calendars.destroy') end def update? !archived? && organisation_match? && user.has_permission?('calendars.update') diff --git a/app/policies/referential_policy.rb b/app/policies/referential_policy.rb index bf970c2b8..9d0a92093 100644 --- a/app/policies/referential_policy.rb +++ b/app/policies/referential_policy.rb @@ -24,11 +24,11 @@ class ReferentialPolicy < ApplicationPolicy end def archive? - record.archived_at.nil? && user.has_permission?('referentials.update') + record.archived_at.nil? && organisation_match? && user.has_permission?('referentials.update') end def unarchive? - !record.archived_at.nil? && user.has_permission?('referentials.update') + !record.archived_at.nil? && organisation_match? && user.has_permission?('referentials.update') end def common_lines? diff --git a/app/views/calendar_mailer/created.html.slim b/app/views/calendar_mailer/created.html.slim index 621796d34..da15b7189 100644 --- a/app/views/calendar_mailer/created.html.slim +++ b/app/views/calendar_mailer/created.html.slim @@ -1,2 +1 @@ -div = t('mailers.calendar_mailer.created.body') - +div = t('mailers.calendar_mailer.created.body', cal_name: @calendar.name, cal_index_url: calendars_url) diff --git a/app/views/calendar_mailer/updated.html.slim b/app/views/calendar_mailer/updated.html.slim index 7f6deda07..f70480107 100644 --- a/app/views/calendar_mailer/updated.html.slim +++ b/app/views/calendar_mailer/updated.html.slim @@ -1,2 +1,2 @@ -div = t('mailers.calendar_mailer.updated.body') +div = t('mailers.calendar_mailer.updated.body', cal_name: @calendar.name, cal_index_url: calendars_url) diff --git a/app/views/calendars/index.html.slim b/app/views/calendars/index.html.slim index 843ec1256..e3ac16505 100644 --- a/app/views/calendars/index.html.slim +++ b/app/views/calendars/index.html.slim @@ -1,8 +1,10 @@ / PageHeader -= pageheader 'map-marker', - t('.title'), - '', - link_to(t('actions.add'), new_calendar_path, class: 'btn btn-default') do + +- header_params = ['map-marker', + t('.title'), + ''] +- header_params << link_to(t('actions.add'), new_calendar_path, class: 'btn btn-default') if policy(Calendar).create? += pageheader(*header_params) do / PageContent .page_content diff --git a/config/application.rb b/config/application.rb index 02d2b4fc2..910ddd983 100644 --- a/config/application.rb +++ b/config/application.rb @@ -33,6 +33,8 @@ module ChouetteIhm config.active_record.observers = [:route_observer, :calendar_observer] config.active_record.raise_in_transactional_callbacks = true + config.active_job.queue_adapter = :sidekiq + unless Rails.env.production? # Work around sprockets+teaspoon mismatch: Rails.application.config.assets.precompile += %w(spec_helper.js) diff --git a/config/locales/mailers.en.yml b/config/locales/mailers.en.yml index 72fd0d725..d4bd45129 100644 --- a/config/locales/mailers.en.yml +++ b/config/locales/mailers.en.yml @@ -3,7 +3,7 @@ en: calendar_mailer: created: subject: A new shared calendar has been created - body: body created + body: A new shared calendar% {cal_name} has been added by STIF. You can now view it in the list of shared calendars %{cal_index_url} created: subject: A shared calendar has been updated - body: body updated + body: A new shared calendar% {cal_name} has been updated by STIF. You can now view it in the list of shared calendars %{cal_index_url} diff --git a/config/locales/mailers.fr.yml b/config/locales/mailers.fr.yml index 8c399b6e0..a448f13d9 100644 --- a/config/locales/mailers.fr.yml +++ b/config/locales/mailers.fr.yml @@ -3,7 +3,7 @@ fr: calendar_mailer: created: subject: Un nouveau calendrier partagé à été ajouté - body: body created + body: 'Un calendrier partagé %{cal_name} a été ajouté par le STIF. Vous pouvez maintenant le consulter dans la liste des calendriers partagés : %{cal_index_url}' updated: subject: Un nouveau calendrier partagé à été mise à jour - body: body updated + body: 'Un calendrier partagé %{cal_name} a été mis à jour par le STIF. Vous pouvez maintenant le consulter dans la liste des calendriers partagés : %{cal_index_url}' diff --git a/lib/html_element.rb b/lib/html_element.rb index 469fd7565..57b08eb52 100644 --- a/lib/html_element.rb +++ b/lib/html_element.rb @@ -1,4 +1,6 @@ class HTMLElement + attr_reader :content, :options, :tag_name + def initialize(tag_name, content = nil, options = nil) @tag_name = tag_name @content = content diff --git a/lib/stif/permission_translator.rb b/lib/stif/permission_translator.rb new file mode 100644 index 000000000..7032f910a --- /dev/null +++ b/lib/stif/permission_translator.rb @@ -0,0 +1,7 @@ +module Stif + module PermissionTranslator extend self + def translate(sso_extra_permissions) + %w{sessions:create} + end + end +end diff --git a/spec/decorators/referential_decorator_spec.rb b/spec/decorators/referential_decorator_spec.rb new file mode 100644 index 000000000..5de6b7e95 --- /dev/null +++ b/spec/decorators/referential_decorator_spec.rb @@ -0,0 +1,76 @@ +RSpec.describe ReferentialDecorator, type: [:helper, :decorator] do + + let( :object ){ build_stubbed :referential } + let( :referential ){ object } + let( :user ){ build_stubbed :user } + + describe 'delegation' do + it 'delegates all' do + %i{xx xxx anything save!}.each do |method| + expect( object ).to receive(method) + end + # Almost as powerful as Quicktest :P + %i{xx xxx anything save!}.each do |method| + subject.send method + end + end + end + + describe 'action links for' do + + context 'unarchived referential' do + context 'no rights' do + it 'has only a Calendar action' do + expect_action_link_hrefs.to eq([referential_time_tables_path(object)]) + end + end + + context 'all rights and different organisation' do + + let( :user ){ build_stubbed :allmighty_user } + + it 'has only default actions' do + expect_action_link_elements.to be_empty + expect_action_link_hrefs.to eq([ + referential_time_tables_path(object), + ]) + end + end + context 'all rights and same organisation' do + + let( :user ){ build_stubbed :allmighty_user, organisation: referential.organisation } + + it 'has all actions' do + expect_action_link_elements.to eq(%w{Purger}) + expect_action_link_hrefs.to eq([ + referential_time_tables_path(object), + new_referential_path(from: object), + archive_referential_path(object), + referential_path(object) + ]) + end + end + end + + context 'archived referential' do + before { referential.archived_at = 42.seconds.ago } + context 'no rights' do + it 'has only a Calendar action' do + expect_action_link_hrefs.to eq([referential_time_tables_path(object)]) + end + end + + context 'all rights and different organisation' do + let( :user ){ build_stubbed :allmighty_user } + it 'has only default actions' do + expect_action_link_elements.to be_empty + expect_action_link_hrefs.to eq([ + referential_time_tables_path(object), + ]) + end + end + end + end + + +end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index d532cbafc..8f620c3a1 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -1,12 +1,4 @@ -all_permissions = %w[ - footnotes - journey_patterns - referentials - routes - routing_constraint_zones - time_tables - vehicle_journeys - ].product( %w{create destroy update} ).map{ |model_action| model_action.join('.') } +require_relative '../support/permissions' FactoryGirl.define do factory :user do @@ -17,7 +9,7 @@ FactoryGirl.define do password "secret" password_confirmation "secret" factory :allmighty_user do - permissions all_permissions + permissions Support::Permissions.all_permissions end end end diff --git a/spec/features/calendars_permissions_spec.rb b/spec/features/calendars_permissions_spec.rb index 6eb0ea08e..9b47ab2bb 100644 --- a/spec/features/calendars_permissions_spec.rb +++ b/spec/features/calendars_permissions_spec.rb @@ -1,15 +1,13 @@ -# -*- coding: utf-8 -*- -require 'spec_helper' - -describe 'Calendars', type: :feature do +RSpec.describe 'Calendars', type: :feature do login_user let(:calendar) { create :calendar, organisation_id: 1 } describe 'permissions' do before do - allow_any_instance_of(CalendarPolicy).to receive(:edit?).and_return permission + allow_any_instance_of(CalendarPolicy).to receive(:create?).and_return permission allow_any_instance_of(CalendarPolicy).to receive(:destroy?).and_return permission + allow_any_instance_of(CalendarPolicy).to receive(:edit?).and_return permission allow_any_instance_of(CalendarPolicy).to receive(:share?).and_return permission visit path end @@ -51,5 +49,23 @@ describe 'Calendars', type: :feature do end end end + + context 'on index view' do + let( :path ){ calendars_path } + + context 'if present → ' do + let( :permission ){ true } + it 'index shows an edit button' do + expect(page).to have_css('a.btn.btn-default', text: 'Créer') + end + end + + context 'if absent → ' do + let( :permission ){ false } + it 'index does not show any edit button' do + expect(page).not_to have_css('a.btn.btn-default', text: 'Créer') + end + end + end end end diff --git a/spec/features/connection_links_spec.rb b/spec/features/connection_links_spec.rb index 524fbb89a..0325e6e1c 100644 --- a/spec/features/connection_links_spec.rb +++ b/spec/features/connection_links_spec.rb @@ -1,7 +1,4 @@ -# -*- coding: utf-8 -*- -require 'spec_helper' - -describe "ConnectionLinks", :type => :feature do +RSpec.describe "ConnectionLinks", :type => :feature do login_user let!(:connection_links) { Array.new(2) { create(:connection_link) } } diff --git a/spec/jobs/mailer_job_spec.rb b/spec/jobs/mailer_job_spec.rb deleted file mode 100644 index 363b8724a..000000000 --- a/spec/jobs/mailer_job_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'rails_helper' - -RSpec.describe MailerJob, type: :job do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/lib/stif/permission_translator_spec.rb b/spec/lib/stif/permission_translator_spec.rb new file mode 100644 index 000000000..3672c7937 --- /dev/null +++ b/spec/lib/stif/permission_translator_spec.rb @@ -0,0 +1,10 @@ +RSpec.describe Stif::PermissionTranslator do + + context "SSO Permission boiv:read:offer →" do + + it "sessions:create only" do + expect( described_class.translate(%w{boiv:read:offer}) ).to eq(%w{sessions:create}) + end + + end +end diff --git a/spec/mailers/calendar_mailer_spec.rb b/spec/mailers/calendar_mailer_spec.rb index d41092461..49cc3cce8 100644 --- a/spec/mailers/calendar_mailer_spec.rb +++ b/spec/mailers/calendar_mailer_spec.rb @@ -20,7 +20,7 @@ RSpec.describe CalendarMailer, type: :mailer do end it 'should have correct body' do - key = I18n.t("mailers.calendar_mailer.#{type}.body") + key = I18n.t("mailers.calendar_mailer.#{type}.body", cal_name: calendar.name, cal_index_url: calendars_url) expect(email).to have_body_text /#{key}/ end end diff --git a/spec/mailers/previews/calendar_mailer_preview.rb b/spec/mailers/previews/calendar_mailer_preview.rb index 572c6c667..5fa108924 100644 --- a/spec/mailers/previews/calendar_mailer_preview.rb +++ b/spec/mailers/previews/calendar_mailer_preview.rb @@ -1,4 +1,13 @@ # Preview all emails at http://localhost:3000/rails/mailers/calendar_mailer class CalendarMailerPreview < ActionMailer::Preview + def created + cal = Calendar.new(name: 'test calendar', shared: true) + CalendarMailer.created(cal, User.take) + end + + def updated + cal = Calendar.new(name: 'test calendar', shared: true) + CalendarMailer.updated(cal, User.take) + end end diff --git a/spec/policies/calendar_policy_spec.rb b/spec/policies/calendar_policy_spec.rb index 57f771c54..294be8198 100644 --- a/spec/policies/calendar_policy_spec.rb +++ b/spec/policies/calendar_policy_spec.rb @@ -5,7 +5,7 @@ RSpec.describe CalendarPolicy, type: :policy do permissions :create? do - it_behaves_like 'permitted policy and same organisation', 'calendars.create', archived: true + it_behaves_like 'permitted policy', 'calendars.create', archived: true end permissions :destroy? do it_behaves_like 'permitted policy and same organisation', 'calendars.destroy', archived: true @@ -14,7 +14,7 @@ RSpec.describe CalendarPolicy, type: :policy do it_behaves_like 'permitted policy and same organisation', 'calendars.update', archived: true end permissions :new? do - it_behaves_like 'permitted policy and same organisation', 'calendars.create', archived: true + it_behaves_like 'permitted policy', 'calendars.create', archived: true end permissions :update? do it_behaves_like 'permitted policy and same organisation', 'calendars.update', archived: true diff --git a/spec/policies/referential_policy_spec.rb b/spec/policies/referential_policy_spec.rb index d060317f9..33d8e13e8 100644 --- a/spec/policies/referential_policy_spec.rb +++ b/spec/policies/referential_policy_spec.rb @@ -56,22 +56,52 @@ RSpec.describe ReferentialPolicy, type: :policy do add_permissions('referentials.update', for_user: user) end - it 'allowed for unarchived referentials' do - expect_it.to permit(user_context, record) + context 'same organisation →' do + before do + user.organisation_id = referential.organisation_id + end + it "allows a user with the same organisation" do + expect_it.to permit(user_context, record) + end + describe "archived" do + let( :record ){ build_stubbed :referential, archived_at: 2.minutes.ago } + it 'does remove permission for archived referentials' do + expect_it.not_to permit(user_context, record) + end + end end - it 'forbidden for archived referentials' do - record.archived_at = 1.second.ago - expect_it.not_to permit(user_context, record) + context 'different organisations →' do + it "forbids a user with a different organisation" do + expect_it.not_to permit(user_context, record) + end + + describe "archived" do + let( :record ){ build_stubbed :referential, archived_at: 2.minutes.ago } + it 'forbids for archived referentials' do + expect_it.not_to permit(user_context, record) + end + end + end end - context 'permission absent →' do - it 'is forbidden' do - expect_it.not_to permit(user_context, record) + context 'permission absent →' do + context 'same organisation →' do + before do + user.organisation_id = referential.organisation_id + end + it "forbids a user with the same organisation" do + expect_it.not_to permit(user_context, record) + end + describe "archived" do + let( :record ){ build_stubbed :referential, archived_at: 2.minutes.ago } + it 'forbids for archived referentials' do + expect_it.not_to permit(user_context, record) + end + end end end - end permissions :unarchive? do @@ -81,22 +111,51 @@ RSpec.describe ReferentialPolicy, type: :policy do add_permissions('referentials.update', for_user: user) end - it 'forbidden for unarchived referentials' do - expect_it.not_to permit(user_context, record) + context 'same organisation →' do + before do + user.organisation_id = referential.organisation_id + end + it "forbids a user with the same organisation" do + expect_it.not_to permit(user_context, record) + end + describe "archived" do + let( :record ){ build_stubbed :referential, archived_at: 2.minutes.ago } + it 'adds permission for archived referentials' do + expect_it.to permit(user_context, record) + end + end end - it 'allowed for archived referentials' do - record.archived_at = 1.second.ago - expect_it.to permit(user_context, record) + context 'different organisations →' do + it "forbids a user with a different organisation" do + expect_it.not_to permit(user_context, record) + end + + describe "archived" do + let( :record ){ build_stubbed :referential, archived_at: 2.minutes.ago } + it 'still forbids for archived referentials' do + expect_it.not_to permit(user_context, record) + end + end + end end - context 'permission absent →' do - it 'is forbidden' do - record.archived_at = 1.second.ago - expect_it.not_to permit(user_context, record) + context 'permission absent →' do + context 'same organisation →' do + before do + user.organisation_id = referential.organisation_id + end + it "forbids a user with a different rganisation" do + expect_it.not_to permit(user_context, record) + end + describe "archived" do + let( :record ){ build_stubbed :referential, archived_at: 2.minutes.ago } + it 'still forbids for archived referentials' do + expect_it.not_to permit(user_context, record) + end + end end end - end end diff --git a/spec/support/decorator_helpers.rb b/spec/support/decorator_helpers.rb new file mode 100644 index 000000000..ffedd479b --- /dev/null +++ b/spec/support/decorator_helpers.rb @@ -0,0 +1,27 @@ +module Support + + module DecoratorHelpers + def self.included(into) + into.instance_eval do + subject{ object.decorate } + let( :policy ){ ::Pundit.policy(user_context, object) } + let( :user_context ){ UserContext.new(user, referential: referential) } + + before do + allow_any_instance_of(Draper::HelperProxy).to receive(:policy).and_return policy + end + end + end + + def expect_action_link_hrefs + expect( subject.action_links.select(&Link.method(:===)).map(&:href) ) + end + def expect_action_link_elements + expect( subject.action_links.select(&HTMLElement.method(:===)).map(&:content) ) + end + end +end + +RSpec.configure do | c | + c.include Support::DecoratorHelpers, type: :decorator +end diff --git a/spec/support/devise.rb b/spec/support/devise.rb index 28703c072..46249fef2 100644 --- a/spec/support/devise.rb +++ b/spec/support/devise.rb @@ -3,13 +3,11 @@ module DeviseRequestHelper def login_user organisation = Organisation.where(:code => "first").first_or_create(attributes_for(:organisation)) - @user ||= create(:user, :organisation => organisation, - :permissions => ['routes.create', 'routes.update', 'routes.destroy', 'journey_patterns.create', 'journey_patterns.update', 'journey_patterns.destroy', - 'vehicle_journeys.create', 'vehicle_journeys.update', 'vehicle_journeys.destroy', 'time_tables.create', 'time_tables.update', 'time_tables.destroy', - 'footnotes.update', 'footnotes.create', 'footnotes.destroy', 'routing_constraint_zones.create', 'routing_constraint_zones.update', 'routing_constraint_zones.destroy', - 'access_points.create', 'access_points.update', 'access_points.destroy', 'access_links.create', 'access_links.update', 'access_links.destroy', - 'connection_links.create', 'connection_links.update', 'connection_links.destroy', 'route_sections.create', 'route_sections.update', 'route_sections.destroy', - 'referentials.create', 'referentials.update', 'referentials.destroy']) + @user ||= + create(:user, + :organisation => organisation, + :permissions => Support::Permissions.all_permissions) + login_as @user, :scope => :user # post_via_redirect user_session_path, 'user[email]' => @user.email, 'user[password]' => @user.password end @@ -38,28 +36,12 @@ end module DeviseControllerHelper def setup_user - _all_actions = %w{create destroy update} - _all_resources = %w{ access_links - access_points - connection_links - footnotes - journey_patterns - referentials - route_sections - routes - routing_constraint_zones - time_tables - vehicle_journeys } - join_with = -> (separator) do - -> (ary) { ary.join(separator) } - end - before do @request.env["devise.mapping"] = Devise.mappings[:user] organisation = Organisation.where(:code => "first").first_or_create(attributes_for(:organisation)) @user = create(:user, organisation: organisation, - permissions: _all_resources.product( _all_actions ).map(&join_with.('.'))) + permissions: Support::Permissions.all_permissions) end end @@ -70,8 +52,6 @@ module DeviseControllerHelper end end - private - end RSpec.configure do |config| diff --git a/spec/support/permissions.rb b/spec/support/permissions.rb new file mode 100644 index 000000000..a13010f65 --- /dev/null +++ b/spec/support/permissions.rb @@ -0,0 +1,28 @@ +module Support + module Permissions extend self + + def all_permissions + @__all_permissions__ ||= _destructive_permissions << 'sessions:create' + end + + private + + def _destructive_permissions + _permitted_resources.product( %w{create destroy update} ).map{ |model_action| model_action.join('.') } + end + + def _permitted_resources + %w[ + access_points + connection_links + footnotes + journey_patterns + referentials + routes + routing_constraint_zones + time_tables + vehicle_journeys + ] + end + end +end diff --git a/spec/support/pundit/shared_examples.rb b/spec/support/pundit/shared_examples.rb index b91caa479..63a106759 100644 --- a/spec/support/pundit/shared_examples.rb +++ b/spec/support/pundit/shared_examples.rb @@ -64,7 +64,7 @@ RSpec.shared_examples 'always forbidden' do end end end -j + RSpec.shared_examples 'permitted policy and same organisation' do | permission, archived: false| @@ -101,3 +101,31 @@ RSpec.shared_examples 'permitted policy and same organisation' do end end end + +RSpec.shared_examples 'permitted policy' do + | permission, archived: false| + + context 'permission absent → ' do + it "denies user" do + expect_it.not_to permit(user_context, record) + end + end + + context 'permission present → ' do + before do + add_permissions(permission, for_user: user) + end + + it 'allows user' do + expect_it.to permit(user_context, record) + end + + if archived + it 'removes the permission for archived referentials' do + user.organisation_id = referential.organisation_id + referential.archived_at = 42.seconds.ago + expect_it.not_to permit(user_context, record) + end + end + end +end |
