diff --git a/app/controllers/training_controller.rb b/app/controllers/training_controller.rb index f92afcc69e..569ca835ed 100644 --- a/app/controllers/training_controller.rb +++ b/app/controllers/training_controller.rb @@ -59,6 +59,15 @@ def reload render plain: e.message end + def find_slide + training_slide = TrainingSlide.find(params[:slide_id]) + training_module = training_slide.find_module_by_slug + raise ActionController::RoutingError, 'module not found' unless training_module + # Use a specific training library for the module, or a default library if it is not found + training_library = training_module.find_or_default_library + redirect_to "/training/#{training_library.slug}/#{training_module.slug}/#{training_slide.slug}" + end + private def add_training_root_breadcrumb diff --git a/app/controllers/training_modules_controller.rb b/app/controllers/training_modules_controller.rb index a921fe962b..f7677658a7 100644 --- a/app/controllers/training_modules_controller.rb +++ b/app/controllers/training_modules_controller.rb @@ -11,4 +11,11 @@ def index def show @training_module = TrainingModule.find_by(slug: params[:module_id]) end + + def find + training_module = TrainingModule.find(params[:module_id]) + # Use a specific training library for the module, or a default library if it is not found + training_library = training_module.find_or_default_library + redirect_to "/training/#{training_library.slug}/#{training_module.slug}" + end end diff --git a/app/models/training_library.rb b/app/models/training_library.rb index 8df5f82ad4..2cc1240039 100644 --- a/app/models/training_library.rb +++ b/app/models/training_library.rb @@ -97,4 +97,10 @@ def translated_categories def translated(key) translations.dig(I18n.locale.to_s, key) end + + def training_module_slugs + categories.map do |cat| + cat['modules'].map { |mod| mod['slug'] } + end.flatten + end end diff --git a/app/models/training_module.rb b/app/models/training_module.rb index 1826bae857..e6280a50bf 100644 --- a/app/models/training_module.rb +++ b/app/models/training_module.rb @@ -153,5 +153,17 @@ def sandbox_location settings['sandbox_location'] end + # Returns the first library that has a category including the module slug. + # It returns nil if no such library is found. + def find_library_by_slug + TrainingLibrary.all.detect { |tl| tl.training_module_slugs.include? slug } + end + + # Returns a specific training library for the module, + # or a default library if it is not found. + def find_or_default_library + find_library_by_slug || TrainingLibrary.first + end + class ModuleNotFound < StandardError; end end diff --git a/app/models/training_slide.rb b/app/models/training_slide.rb index 071fa815b8..42a59a05db 100644 --- a/app/models/training_slide.rb +++ b/app/models/training_slide.rb @@ -65,4 +65,10 @@ def self.inflate(all_content, slug, wiki_page = nil) puts "There's a problem with file '#{slug}'" raise e end + + # Returns the first module including the slide slug. + # It returns nil if no such module is found. + def find_module_by_slug + TrainingModule.all.detect { |tm| tm.slide_slugs.include? slug } + end end diff --git a/config/routes.rb b/config/routes.rb index 71de99b67e..c705fdf84c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -328,6 +328,11 @@ get 'training_modules' => 'training_modules#index' get 'training_module' => 'training_modules#show' + # To find training modules by id + get 'find_training_module/:module_id' => 'training_modules#find' + + # To find individual slides by id + get 'find_training_slide/:slide_id' => 'training#find_slide' # Misc # get 'courses' => 'courses#index' diff --git a/spec/controllers/training_controller_spec.rb b/spec/controllers/training_controller_spec.rb index 9e3ba520ab..2bed9106ac 100644 --- a/spec/controllers/training_controller_spec.rb +++ b/spec/controllers/training_controller_spec.rb @@ -140,4 +140,73 @@ end end end + + describe '#find' do + subject { get "/find_training_module/#{module_id}" } + + context 'module_id is found' do + let(:module_id) { 12 } + + it 'redirects to a training module page' do + subject + expect(response).to redirect_to('/training/students/peer-review') + end + end + + context 'module_id is found but it is in no library' do + let(:module_id) { 2 } + + it 'uses a default library to build the route' do + subject + expect(response).to redirect_to('/training/instructors/editing-basics') + end + end + + context 'module_id is not found' do + let(:module_id) { 128456 } + + it 'raises a module not found error' do + expect { subject }.to raise_error ActiveRecord::RecordNotFound + end + end + end + + describe '#find_slide' do + subject { get "/find_training_slide/#{slide_id}" } + + context 'slide_id is found' do + let(:slide_id) { 103 } + + it 'redirects to a training slide page' do + subject + expect(response).to redirect_to('/training/students/wikipedia-essentials/five-pillars') + end + end + + context 'slide_id is found but it is in no module' do + let(:slide) { create(:training_slide) } + let(:slide_id) { slide.id } + + it 'raises a routing error' do + expect { subject }.to raise_error ActionController::RoutingError, 'module not found' + end + end + + context 'slide_id is found but its module is in no library' do + let(:slide_id) { 201 } + + it 'uses a default library to build the route' do + subject + expect(response).to redirect_to('/training/instructors/editing-basics/welcome-students') + end + end + + context 'slide_id is not found' do + let(:slide_id) { 128456 } + + it 'raises a module not found error' do + expect { subject }.to raise_error ActiveRecord::RecordNotFound + end + end + end end diff --git a/spec/factories/training_slides.rb b/spec/factories/training_slides.rb index 113e1682c3..128f720502 100644 --- a/spec/factories/training_slides.rb +++ b/spec/factories/training_slides.rb @@ -19,5 +19,8 @@ FactoryBot.define do factory :training_slide do + id { 456875 } + title { 'How to create a slide' } + slug { 'how-to-create-a-slide' } end end