From 6825da55473c6fddabb550a14043ac9fb92de92a Mon Sep 17 00:00:00 2001 From: Jacob Cody Wimer Date: Tue, 6 May 2025 20:58:45 -0400 Subject: [PATCH] Added a daily recurring job to cleanup tournaments . --- app/jobs/tournament_cleanup_job.rb | 43 ++++++++++++++++ config/recurring.yml | 21 ++++---- .../cypress/e2e/02-create_tournament.cy.js | 8 ++- db/seeds.rb | 13 +++-- test/fixtures/tournaments.yml | 11 +++++ test/jobs/tournament_cleanup_job_test.rb | 49 +++++++++++++++++++ 6 files changed, 129 insertions(+), 16 deletions(-) create mode 100644 app/jobs/tournament_cleanup_job.rb create mode 100644 test/jobs/tournament_cleanup_job_test.rb diff --git a/app/jobs/tournament_cleanup_job.rb b/app/jobs/tournament_cleanup_job.rb new file mode 100644 index 0000000..c9a2a4f --- /dev/null +++ b/app/jobs/tournament_cleanup_job.rb @@ -0,0 +1,43 @@ +class TournamentCleanupJob < ApplicationJob + queue_as :default + + def perform + # Task 1: Remove tournaments that are 1 week old and have 0 matches finished + remove_empty_old_tournaments + + # Task 2: Cleanup tournaments that are a week old with at least 1 finished match + cleanup_active_old_tournaments + end + + private + + def remove_empty_old_tournaments + # Find tournaments older than 1 week with no finished matches + Tournament.where('date < ?', 1.week.ago.to_date) + .joins('LEFT JOIN matches ON matches.tournament_id = tournaments.id AND matches.finished = 1') + .group('tournaments.id') + .having('COUNT(matches.id) = 0') + .destroy_all + end + + def cleanup_active_old_tournaments + # Find tournaments older than 1 week with at least 1 finished match + old_active_tournaments = Tournament.where('date < ?', 1.week.ago.to_date) + .joins('INNER JOIN matches ON matches.tournament_id = tournaments.id AND matches.finished = 1') + .group('tournaments.id') + .having('COUNT(matches.id) > 0') + + old_active_tournaments.each do |tournament| + # 1. Remove all school delegates + tournament.schools.each do |school| + school.delegates.destroy_all + end + + # 2. Remove all tournament delegates + tournament.delegates.destroy_all + + # 3. Set user_id to null + tournament.update(user_id: nil) + end + end +end \ No newline at end of file diff --git a/config/recurring.yml b/config/recurring.yml index d045b19..3a6845a 100644 --- a/config/recurring.yml +++ b/config/recurring.yml @@ -1,10 +1,11 @@ -# production: -# periodic_cleanup: -# class: CleanSoftDeletedRecordsJob -# queue: background -# args: [ 1000, { batch_size: 500 } ] -# schedule: every hour -# periodic_command: -# command: "SoftDeletedRecord.due.delete_all" -# priority: 2 -# schedule: at 5am every day +production: + tournament_cleanup_job: + class: TournamentCleanupJob + schedule: every day at 3am + queue: default + +development: + tournament_cleanup_job: + class: TournamentCleanupJob + schedule: every day at 3am + queue: default \ No newline at end of file diff --git a/cypress-tests/cypress/e2e/02-create_tournament.cy.js b/cypress-tests/cypress/e2e/02-create_tournament.cy.js index 15dc4de..eb33501 100644 --- a/cypress-tests/cypress/e2e/02-create_tournament.cy.js +++ b/cypress-tests/cypress/e2e/02-create_tournament.cy.js @@ -27,7 +27,13 @@ describe('Create a tournament', () => { cy.get('input[name="tournament[address]"]').type('123 Wrestling Way'); cy.get('input[name="tournament[director]"]').type('John Doe'); cy.get('input[name="tournament[director_email]"]').type('john.doe@example.com'); - cy.get('input[name="tournament[date]"]').type('2024-12-31'); + + // Set date to 1 month from today dynamically + const futureDate = new Date(); + futureDate.setMonth(futureDate.getMonth() + 1); + const formattedDate = futureDate.toISOString().split('T')[0]; // Format as YYYY-MM-DD + cy.get('input[name="tournament[date]"]').type(formattedDate); + cy.get('select[name="tournament[tournament_type]"]').select('Pool to bracket'); // cy.get('input[name="tournament[is_public]"]').check(); diff --git a/db/seeds.rb b/db/seeds.rb index fadf44c..3cb76de 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -30,8 +30,11 @@ User.create(id: 1, email: 'test@test.com', password: 'password', password_confirmation: 'password') + # Set tournament date to a month from today + future_date = 1.month.from_now.to_date + # Pool to bracket - tournament = Tournament.create(id: 200, name: 'Pool to bracket', address: 'some place', director: 'some guy', director_email: 'their@email.com', tournament_type: 'Pool to bracket', user_id: 1, date: Date.today, is_public: true) + tournament = Tournament.create(id: 200, name: 'Pool to bracket', address: 'some place', director: 'some guy', director_email: 'their@email.com', tournament_type: 'Pool to bracket', user_id: 1, date: future_date, is_public: true) create_schools(tournament, 24) weight_classes=Weight::HS_WEIGHT_CLASSES.split(",") tournament.create_pre_defined_weights(weight_classes) @@ -58,7 +61,7 @@ end # Modified 16 Man Double Elimination 1-6 - tournament = Tournament.create(id: 201, name: 'Modified 16 Man Double Elimination 1-6', address: 'some place', director: 'some guy', director_email: 'their@email.com', tournament_type: 'Modified 16 Man Double Elimination 1-6', user_id: 1, date: Date.today, is_public: true) + tournament = Tournament.create(id: 201, name: 'Modified 16 Man Double Elimination 1-6', address: 'some place', director: 'some guy', director_email: 'their@email.com', tournament_type: 'Modified 16 Man Double Elimination 1-6', user_id: 1, date: future_date, is_public: true) create_schools(tournament, 16) weight_classes=Weight::HS_WEIGHT_CLASSES.split(",") tournament.create_pre_defined_weights(weight_classes) @@ -69,7 +72,7 @@ end # Modified 16 Man Double Elimination 1-8 - tournament = Tournament.create(id: 202, name: 'Modified 16 Man Double Elimination 1-8', address: 'some place', director: 'some guy', director_email: 'their@email.com', tournament_type: 'Modified 16 Man Double Elimination 1-8', user_id: 1, date: Date.today, is_public: true) + tournament = Tournament.create(id: 202, name: 'Modified 16 Man Double Elimination 1-8', address: 'some place', director: 'some guy', director_email: 'their@email.com', tournament_type: 'Modified 16 Man Double Elimination 1-8', user_id: 1, date: future_date, is_public: true) create_schools(tournament, 16) weight_classes=Weight::HS_WEIGHT_CLASSES.split(",") tournament.create_pre_defined_weights(weight_classes) @@ -86,7 +89,7 @@ end # Regular Double Elimination 1-6 - tournament = Tournament.create(id: 203, name: 'Regular Double Elimination 1-6', address: 'some place', director: 'some guy', director_email: 'their@email.com', tournament_type: 'Regular Double Elimination 1-6', user_id: 1, date: Date.today, is_public: true) + tournament = Tournament.create(id: 203, name: 'Regular Double Elimination 1-6', address: 'some place', director: 'some guy', director_email: 'their@email.com', tournament_type: 'Regular Double Elimination 1-6', user_id: 1, date: future_date, is_public: true) create_schools(tournament, 32) weight_classes=Weight::HS_WEIGHT_CLASSES.split(",") tournament.create_pre_defined_weights(weight_classes) @@ -109,7 +112,7 @@ end # Regular Double Elimination 1-8 - tournament = Tournament.create(id: 204, name: 'Regular Double Elimination 1-8', address: 'some place', director: 'some guy', director_email: 'their@email.com', tournament_type: 'Regular Double Elimination 1-8', user_id: 1, date: Date.today, is_public: true) + tournament = Tournament.create(id: 204, name: 'Regular Double Elimination 1-8', address: 'some place', director: 'some guy', director_email: 'their@email.com', tournament_type: 'Regular Double Elimination 1-8', user_id: 1, date: future_date, is_public: true) create_schools(tournament, 32) weight_classes=Weight::HS_WEIGHT_CLASSES.split(",") tournament.create_pre_defined_weights(weight_classes) diff --git a/test/fixtures/tournaments.yml b/test/fixtures/tournaments.yml index 2287e6d..9f1175a 100644 --- a/test/fixtures/tournaments.yml +++ b/test/fixtures/tournaments.yml @@ -9,4 +9,15 @@ one: tournament_type: Pool to bracket user_id: 1 date: 2015-12-30 + is_public: true + +two: + id: 2 + name: Test Tournament 2 + address: Some Place + director: Jacob Cody Wimer + director_email: jacob.wimer@gmail.com + tournament_type: Pool to bracket + user_id: 1 + date: 2015-12-30 is_public: true \ No newline at end of file diff --git a/test/jobs/tournament_cleanup_job_test.rb b/test/jobs/tournament_cleanup_job_test.rb new file mode 100644 index 0000000..f6d999b --- /dev/null +++ b/test/jobs/tournament_cleanup_job_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class TournamentCleanupJobTest < ActiveJob::TestCase + setup do + # Create an old empty tournament (1 week old, 0 finished matches) + @old_empty_tournament = tournaments(:one) + @old_empty_tournament.update(date: 2.weeks.ago.to_date) + + # Create an old active tournament (1 week old, with finished matches) + @old_active_tournament = tournaments(:two) + @old_active_tournament.update(date: 2.weeks.ago.to_date) + + # Add a finished match to the active tournament + match = matches(:one) + match.update(tournament_id: @old_active_tournament.id, finished: 1, winner_id: wrestlers(:one).id) + + # Add delegates to test removal + tournament_delegate = TournamentDelegate.create(tournament: @old_active_tournament, user: users(:one)) + school = schools(:one) + school.update(tournament_id: @old_active_tournament.id) + school_delegate = SchoolDelegate.create(school: school, user: users(:one)) + end + + test "removes old empty tournaments" do + assert_difference 'Tournament.count', -1 do + TournamentCleanupJob.perform_now + end + + assert_raises(ActiveRecord::RecordNotFound) { @old_empty_tournament.reload } + end + + test "cleans up old active tournaments" do + TournamentCleanupJob.perform_now + + # Tournament should still exist + @old_active_tournament.reload + + # User association should be removed + assert_nil @old_active_tournament.user_id + + # Tournament delegates should be removed + assert_equal 0, @old_active_tournament.delegates.count + + # School delegates should be removed + @old_active_tournament.schools.each do |school| + assert_equal 0, school.delegates.count + end + end +end \ No newline at end of file