Compare commits

...

109 Commits

Author SHA1 Message Date
db5b0809fa Merge pull request 'Update dependency annotaterb to v4.19.0' (#317) from renovate/annotaterb-4.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 4m14s
Run unit tests / build-static-assets (push) Successful in 23m42s
Reviewed-on: #317
2025-09-17 19:21:32 +00:00
feb6dc6b6c Merge pull request 'Update dependency pg to v1.6.2' (#312) from renovate/pg-1.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 2m49s
Run unit tests / build-static-assets (push) Successful in 20m33s
Reviewed-on: #312
2025-09-17 18:53:12 +00:00
3c4c347217 Merge pull request 'Update actions/checkout action to v5' (#321) from renovate/actions-checkout-5.x into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 1m13s
Run unit tests / build-static-assets (push) Successful in 11m24s
Reviewed-on: #321
2025-09-17 18:09:59 +00:00
b1a2484a88 Merge pull request 'Update dependency rails to v8.0.2.1' (#313) from renovate/rails-8.x-lockfile into main
Some checks failed
Run unit tests / build-static-assets (push) Blocked by required conditions
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / rubocop (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Has been cancelled
Reviewed-on: #313
2025-09-17 18:09:04 +00:00
b0c9c6ad87 Merge pull request 'Update dependency rubocop-rails to v2.33.3' (#319) from renovate/rubocop-rails-2.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 1m18s
Run unit tests / build-static-assets (push) Successful in 13m36s
Reviewed-on: #319
2025-09-17 07:11:43 +00:00
Renovate Bot
7c593e2342 Update actions/checkout action to v5
All checks were successful
Run unit tests / copyright_notice (pull_request) Successful in 2m35s
Run unit tests / check-licenses (pull_request) Successful in 3m10s
Run unit tests / rubocop (pull_request) Successful in 31s
Run unit tests / unit_tests (pull_request) Successful in 4m1s
Run unit tests / build-static-assets (pull_request) Successful in 22m6s
2025-09-16 22:18:25 +00:00
Renovate Bot
838e52a0a0 Update dependency rubocop-rails to v2.33.3
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 3m49s
Run unit tests / copyright_notice (pull_request) Successful in 4m18s
Run unit tests / check-licenses (pull_request) Successful in 4m25s
Run unit tests / unit_tests (pull_request) Successful in 8m37s
Run unit tests / build-static-assets (pull_request) Successful in 11m44s
2025-09-16 22:17:39 +00:00
Renovate Bot
990d51f786 Update dependency annotaterb to v4.19.0
All checks were successful
Run unit tests / check-licenses (pull_request) Successful in 2m8s
Run unit tests / rubocop (pull_request) Successful in 2m14s
Run unit tests / copyright_notice (pull_request) Successful in 3m6s
Run unit tests / unit_tests (pull_request) Successful in 4m40s
Run unit tests / build-static-assets (pull_request) Successful in 22m12s
2025-09-16 22:16:33 +00:00
Renovate Bot
de878594ea Update dependency rails to v8.0.2.1
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 1m9s
Run unit tests / copyright_notice (pull_request) Successful in 2m6s
Run unit tests / check-licenses (pull_request) Successful in 2m32s
Run unit tests / unit_tests (pull_request) Successful in 4m11s
Run unit tests / build-static-assets (pull_request) Successful in 21m23s
2025-09-16 22:16:11 +00:00
Renovate Bot
06c103e617 Update dependency pg to v1.6.2
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 56s
Run unit tests / copyright_notice (pull_request) Successful in 1m23s
Run unit tests / check-licenses (pull_request) Successful in 1m35s
Run unit tests / unit_tests (pull_request) Successful in 5m56s
Run unit tests / build-static-assets (pull_request) Successful in 22m22s
2025-09-16 22:15:44 +00:00
e28751521d Merge pull request 'Persist and expose via API the progress of the tables arrangement simulations' (#316) from arrangements-status into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 9m29s
Run unit tests / build-static-assets (push) Successful in 22m38s
Reviewed-on: #316
2025-09-16 00:39:40 +00:00
0502bc4552
Disable a rubocop alert
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 3m14s
Run unit tests / check-licenses (pull_request) Successful in 5m37s
Run unit tests / copyright_notice (pull_request) Successful in 7m13s
Run unit tests / unit_tests (pull_request) Successful in 30m24s
Run unit tests / build-static-assets (pull_request) Successful in 2h21m47s
2025-09-15 23:17:00 +02:00
1760149fbb Merge pull request 'Update dependency factory_bot_rails to v6.5.1' (#314) from renovate/factory_bot_rails-6.x-lockfile into main
Some checks failed
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 7m59s
Run unit tests / build-static-assets (push) Failing after 29m25s
Reviewed-on: #314
2025-09-15 21:10:10 +00:00
7d8ecfd0e3
Refactor class to reduce complexity of #run method
Some checks failed
Run unit tests / rubocop (pull_request) Failing after 2m17s
Run unit tests / check-licenses (pull_request) Successful in 3m51s
Run unit tests / copyright_notice (pull_request) Successful in 4m4s
Run unit tests / unit_tests (pull_request) Successful in 10m37s
Run unit tests / build-static-assets (pull_request) Failing after 56s
2025-09-15 23:04:02 +02:00
78ab27a697
Fix specs
Some checks failed
Run unit tests / copyright_notice (pull_request) Successful in 1m50s
Run unit tests / rubocop (pull_request) Failing after 2m12s
Run unit tests / check-licenses (pull_request) Successful in 2m50s
Run unit tests / unit_tests (pull_request) Successful in 3m48s
Run unit tests / build-static-assets (pull_request) Successful in 1h45m6s
2025-09-15 22:52:41 +02:00
4afd40b02a Merge pull request 'Update dependency rspec-rails to v8.0.2' (#315) from renovate/rspec-rails-8.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 3m19s
Run unit tests / build-static-assets (push) Successful in 38m52s
Reviewed-on: #315
2025-09-11 17:19:06 +00:00
Renovate Bot
43ba96868d Update dependency rspec-rails to v8.0.2
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 1m35s
Run unit tests / check-licenses (pull_request) Successful in 2m18s
Run unit tests / copyright_notice (pull_request) Successful in 3m44s
Run unit tests / unit_tests (pull_request) Successful in 5m30s
Run unit tests / build-static-assets (pull_request) Successful in 2h21m40s
2025-09-11 14:14:21 +00:00
Renovate Bot
00b4e8edfc Update dependency factory_bot_rails to v6.5.1
All checks were successful
Run unit tests / check-licenses (pull_request) Successful in 1m49s
Run unit tests / copyright_notice (pull_request) Successful in 3m50s
Run unit tests / unit_tests (pull_request) Successful in 4m8s
Run unit tests / build-static-assets (pull_request) Successful in 2h25m20s
Run unit tests / rubocop (pull_request) Successful in 4m8s
2025-09-11 14:14:10 +00:00
12174b6f20 Persist VNS calculation progress whenever an improvement has been made
Some checks failed
Run unit tests / check-licenses (pull_request) Failing after 1m44s
Run unit tests / rubocop (pull_request) Failing after 1m46s
Run unit tests / copyright_notice (pull_request) Successful in 2m8s
Run unit tests / unit_tests (pull_request) Failing after 3m30s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-09-08 22:44:54 +02:00
0d1b64256d Provide notification callbacks for progress and new solutions 2025-09-08 16:32:13 +02:00
ac659bef86 Update Tables::Distribution#save! to consider that the distribution may already be persisted 2025-09-08 15:51:43 +02:00
5e06c2acca Merge pull request 'Update dependency puma to v6.6.1' (#308) from renovate/puma-6.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 1m8s
Run unit tests / build-static-assets (push) Successful in 10m36s
Reviewed-on: #308
2025-08-07 13:50:21 +00:00
Renovate Bot
9d656d3759 Update dependency puma to v6.6.1
All checks were successful
Run unit tests / copyright_notice (pull_request) Successful in 3m7s
Run unit tests / rubocop (pull_request) Successful in 3m33s
Run unit tests / check-licenses (pull_request) Successful in 3m36s
Run unit tests / unit_tests (pull_request) Successful in 4m35s
Run unit tests / build-static-assets (pull_request) Successful in 8m44s
2025-08-07 02:04:50 +00:00
4475fc126d Merge pull request 'Update dependency importmap-rails to v2.2.2' (#303) from renovate/importmap-rails-2.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 1m1s
Run unit tests / build-static-assets (push) Successful in 10m25s
Reviewed-on: #303
2025-08-06 15:11:22 +00:00
d7cf620d0a Merge pull request 'Update dependency annotaterb to v4.18.0' (#309) from renovate/annotaterb-4.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 2m19s
Run unit tests / build-static-assets (push) Successful in 18m45s
Reviewed-on: #309
2025-08-06 14:14:16 +00:00
de198e2978 Merge pull request 'Update dependency rubocop to v1.79.2' (#310) from renovate/rubocop-1.x-lockfile into main
Some checks failed
Run unit tests / build-static-assets (push) Blocked by required conditions
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Has been cancelled
Reviewed-on: #310
2025-08-06 14:14:10 +00:00
Renovate Bot
5e69d170a2 Update dependency importmap-rails to v2.2.2
All checks were successful
Run unit tests / check-licenses (pull_request) Successful in 1m33s
Run unit tests / copyright_notice (pull_request) Successful in 2m11s
Run unit tests / rubocop (pull_request) Successful in 41s
Run unit tests / unit_tests (pull_request) Successful in 1m58s
Run unit tests / build-static-assets (pull_request) Successful in 18m12s
2025-08-06 02:05:25 +00:00
Renovate Bot
e1bf362467 Update dependency annotaterb to v4.18.0
All checks were successful
Run unit tests / check-licenses (pull_request) Successful in 2m4s
Run unit tests / rubocop (pull_request) Successful in 2m42s
Run unit tests / copyright_notice (pull_request) Successful in 3m14s
Run unit tests / unit_tests (pull_request) Successful in 5m33s
Run unit tests / build-static-assets (pull_request) Successful in 19m19s
2025-08-06 02:05:16 +00:00
Renovate Bot
c6ce5d62c0 Update dependency rubocop to v1.79.2
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 2m1s
Run unit tests / check-licenses (pull_request) Successful in 2m25s
Run unit tests / copyright_notice (pull_request) Successful in 4m8s
Run unit tests / unit_tests (pull_request) Successful in 7m12s
Run unit tests / build-static-assets (pull_request) Successful in 19m44s
2025-08-06 02:05:04 +00:00
afc147643b Merge pull request 'Update dependency rubocop to v1.79.1' (#306) from renovate/rubocop-1.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 6m19s
Run unit tests / build-static-assets (push) Successful in 24m31s
Reviewed-on: #306
2025-08-05 14:48:16 +00:00
Renovate Bot
d5bd6d865e Update dependency rubocop to v1.79.1
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 1m38s
Run unit tests / check-licenses (pull_request) Successful in 2m4s
Run unit tests / copyright_notice (pull_request) Successful in 48s
Run unit tests / unit_tests (pull_request) Successful in 1m35s
Run unit tests / build-static-assets (pull_request) Successful in 9m10s
2025-08-05 02:06:41 +00:00
9c0b64f427 Merge pull request 'Update dependency pg to v1.6.1' (#307) from renovate/pg-1.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 4m44s
Run unit tests / build-static-assets (push) Successful in 9m55s
2025-08-05 02:06:13 +00:00
Renovate Bot
edd56d46f7 Update dependency pg to v1.6.1
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 2m53s
Run unit tests / copyright_notice (pull_request) Successful in 1m2s
Run unit tests / check-licenses (pull_request) Successful in 1m31s
Run unit tests / unit_tests (pull_request) Successful in 4m50s
Run unit tests / build-static-assets (pull_request) Successful in 10m28s
2025-08-04 02:08:37 +00:00
dd14a96e98 Expose and document the new status attribute in the tables arrangements controller 2025-08-01 12:29:13 +02:00
75a0191d40 Add a new status column to tables arrangements table 2025-08-01 12:25:43 +02:00
8662652e1a Merge pull request 'Add a perturbation step to the VNS engine' (#305) from vns-perturbations into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 1m13s
Run unit tests / build-static-assets (push) Successful in 10m9s
Reviewed-on: #305
2025-07-24 12:21:01 +00:00
3260b0b422 Add copyright notice
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 2m24s
Run unit tests / check-licenses (pull_request) Successful in 2m32s
Run unit tests / copyright_notice (pull_request) Successful in 2m56s
Run unit tests / unit_tests (pull_request) Successful in 5m22s
Run unit tests / build-static-assets (pull_request) Successful in 29m2s
2025-07-24 11:46:28 +00:00
81f1e79b6d Merge branch 'main' into vns-perturbations
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 1m4s
Run unit tests / check-licenses (pull_request) Successful in 1m28s
Run unit tests / copyright_notice (pull_request) Successful in 3m7s
Run unit tests / unit_tests (pull_request) Successful in 5m28s
Run unit tests / build-static-assets (pull_request) Successful in 30m6s
2025-07-24 11:45:19 +00:00
d18bddb31a Remove commented-out code
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 41s
Run unit tests / check-licenses (pull_request) Successful in 1m5s
Run unit tests / copyright_notice (pull_request) Successful in 2m0s
Run unit tests / unit_tests (pull_request) Successful in 7m15s
Run unit tests / build-static-assets (pull_request) Successful in 28m52s
2025-07-24 13:42:47 +02:00
3f158d7906 Merge pull request 'Update dependency solid_queue to v1.2.1' (#304) from renovate/solid_queue-1.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 36s
Run unit tests / build-static-assets (push) Successful in 35m9s
Reviewed-on: #304
2025-07-24 11:41:15 +00:00
db85580c1f Introduce a wheel swap perturbation as part of the VNS engine process 2025-07-24 13:41:01 +02:00
Renovate Bot
76ed4229ea Update dependency solid_queue to v1.2.1
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 3m39s
Run unit tests / check-licenses (pull_request) Successful in 3m7s
Run unit tests / copyright_notice (pull_request) Successful in 2m55s
Run unit tests / unit_tests (pull_request) Successful in 5m5s
Run unit tests / build-static-assets (pull_request) Successful in 9m2s
2025-07-24 02:04:54 +00:00
4befb8505b Run perturbation on top of the best solution so far 2025-07-23 11:02:32 +02:00
b1df5d2f53 Shuffle guests in WheelSwap before assigning them to new tables 2025-07-23 11:01:38 +02:00
a1f06dae5b Define a WheelSwap class that randomly swaps one guest from each table 2025-07-23 10:22:41 +02:00
e8a88b50e2 Initialize Tables::WheelSwap class 2025-07-22 16:26:28 +02:00
185f359942 Include additional debugging messages 2025-07-22 15:56:25 +02:00
543b53d938 Initialize empty set of perturbations and add debug messages 2025-07-22 15:53:06 +02:00
c8b88ab3b1 Merge pull request 'Introduce an invitations penalty for solutions that split guests in the same invitation' (#302) from invitations-penalty into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 58s
Run unit tests / build-static-assets (push) Successful in 8m33s
Reviewed-on: #302
2025-07-22 13:49:28 +00:00
e1a5e4f73e Rename perturbation -> optimization to reflect the nature of swap and shift operations 2025-07-22 15:39:30 +02:00
036cc57aa2 Introduce an invitations penalty for solutions that split guests in the same invitation
All checks were successful
Run unit tests / check-licenses (pull_request) Successful in 1m8s
Run unit tests / rubocop (pull_request) Successful in 1m38s
Run unit tests / copyright_notice (pull_request) Successful in 2m23s
Run unit tests / unit_tests (pull_request) Successful in 4m39s
Run unit tests / build-static-assets (pull_request) Successful in 9m51s
2025-07-22 15:33:13 +02:00
4dfd428ce4 Merge pull request 'Remove deprecation warning by renaming swagger_endpoint -> openapi_endpoint' (#301) from deprecation-warning-swagger into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 1m32s
Run unit tests / build-static-assets (push) Successful in 9m36s
Reviewed-on: #301
2025-07-22 08:09:50 +00:00
51922b4f15 Merge pull request 'Introduce specs for the method Tables::DiscomfortCalculator#cohesion_penalty' (#300) from specs-cohesion_penalty into main
Some checks failed
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 1m43s
Run unit tests / build-static-assets (push) Has been cancelled
Reviewed-on: #300
2025-07-22 07:53:06 +00:00
1e3a49adb8 Remove deprecation warning by renaming swagger_endpoint -> openapi_endpoint
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 48s
Run unit tests / copyright_notice (pull_request) Successful in 1m25s
Run unit tests / check-licenses (pull_request) Successful in 1m30s
Run unit tests / unit_tests (pull_request) Successful in 3m34s
Run unit tests / build-static-assets (pull_request) Successful in 16m19s
2025-07-22 09:49:33 +02:00
7596032284 Introduce specs for the method Tables::DiscomfortCalculator#cohesion_penalty
All checks were successful
Run unit tests / copyright_notice (pull_request) Successful in 50s
Run unit tests / rubocop (pull_request) Successful in 1m24s
Run unit tests / unit_tests (pull_request) Successful in 1m57s
Run unit tests / check-licenses (pull_request) Successful in 49s
Run unit tests / build-static-assets (pull_request) Successful in 10m35s
2025-07-22 09:40:05 +02:00
5dce77c29d Merge pull request 'Define a benchmark to measure the VNS performance and prevent redundant hierarchy calculations' (#298) from benchmark into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 54s
Run unit tests / build-static-assets (push) Successful in 9m27s
Reviewed-on: #298
2025-07-18 14:26:10 +00:00
03e09c74a0 Rubocop fixes
All checks were successful
Run unit tests / copyright_notice (pull_request) Successful in 54s
Run unit tests / check-licenses (pull_request) Successful in 1m14s
Run unit tests / rubocop (pull_request) Successful in 1m24s
Run unit tests / unit_tests (pull_request) Successful in 4m10s
Run unit tests / build-static-assets (pull_request) Successful in 12m27s
2025-07-18 16:09:28 +02:00
da51a073cc Define a benchmark to measure the VNS performance and prevent redundant hierarchy calculations
Some checks failed
Run unit tests / copyright_notice (pull_request) Successful in 38s
Run unit tests / rubocop (pull_request) Failing after 58s
Run unit tests / check-licenses (pull_request) Successful in 1m0s
Run unit tests / unit_tests (pull_request) Successful in 1m14s
Run unit tests / build-static-assets (pull_request) Successful in 14m33s
2025-07-18 16:05:02 +02:00
1953ba9d7f Merge pull request 'Update dependency redis to v5.4.1' (#297) from renovate/redis-5.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 1m20s
Run unit tests / build-static-assets (push) Successful in 9m34s
Reviewed-on: #297
2025-07-18 12:15:14 +00:00
Renovate Bot
bea90af59d Update dependency redis to v5.4.1
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 6m14s
Run unit tests / copyright_notice (pull_request) Successful in 7m19s
Run unit tests / check-licenses (pull_request) Successful in 8m28s
Run unit tests / unit_tests (pull_request) Successful in 16m8s
Run unit tests / build-static-assets (pull_request) Successful in 40m14s
2025-07-18 02:06:51 +00:00
c1c90f4db1 Merge pull request 'Update dependency annotaterb to v4.17.0' (#296) from renovate/annotaterb-4.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 26m22s
Run unit tests / build-static-assets (push) Successful in 37m23s
2025-07-17 02:06:40 +00:00
Renovate Bot
bcddb802b7 Update dependency annotaterb to v4.17.0
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 1m59s
Run unit tests / check-licenses (pull_request) Successful in 1m48s
Run unit tests / copyright_notice (pull_request) Successful in 2m37s
Run unit tests / unit_tests (pull_request) Successful in 14m31s
Run unit tests / build-static-assets (pull_request) Successful in 9m26s
2025-07-15 02:04:13 +00:00
edfb7227cf Merge pull request 'Update dependency solid_queue to v1.2.0' (#295) from renovate/solid_queue-1.x-lockfile into main
Some checks failed
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 14m46s
Run unit tests / build-static-assets (push) Failing after 7s
2025-07-15 02:04:00 +00:00
Renovate Bot
b20078a115 Update dependency solid_queue to v1.2.0
All checks were successful
Run unit tests / copyright_notice (pull_request) Successful in 1m41s
Run unit tests / rubocop (pull_request) Successful in 4m15s
Run unit tests / check-licenses (pull_request) Successful in 4m51s
Run unit tests / unit_tests (pull_request) Successful in 14m20s
Run unit tests / build-static-assets (pull_request) Successful in 14m8s
2025-07-12 02:06:34 +00:00
71562e8143 Merge pull request 'Update dependency rubocop to v1.78.0' (#294) from renovate/rubocop-1.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 1m39s
Run unit tests / build-static-assets (push) Successful in 10m22s
Reviewed-on: #294
2025-07-09 13:19:30 +00:00
Renovate Bot
6478760b8d Update dependency rubocop to v1.78.0
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 2m11s
Run unit tests / check-licenses (pull_request) Successful in 1m39s
Run unit tests / copyright_notice (pull_request) Successful in 1m38s
Run unit tests / unit_tests (pull_request) Successful in 5m57s
Run unit tests / build-static-assets (pull_request) Successful in 8m54s
2025-07-09 02:04:57 +00:00
5cb4d14343 Merge pull request 'Define a worker process and endpoint to send invitations PDF via email' (#293) from qr-doc-background-job into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 2m30s
Run unit tests / build-static-assets (push) Successful in 8m43s
Reviewed-on: #293
2025-07-08 17:37:09 +00:00
397a0f34ff Define a worker process and endpoint to send invitations PDF via email
All checks were successful
Run unit tests / copyright_notice (pull_request) Successful in 56s
Run unit tests / rubocop (pull_request) Successful in 1m10s
Run unit tests / check-licenses (pull_request) Successful in 1m20s
Run unit tests / unit_tests (pull_request) Successful in 2m3s
Run unit tests / build-static-assets (pull_request) Successful in 9m10s
2025-07-08 19:23:16 +02:00
4496deeef5 Merge pull request 'Update FROM address for email delivery' (#292) from update-from into main
All checks were successful
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / rubocop (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 2m53s
Run unit tests / build-static-assets (push) Successful in 10m20s
Reviewed-on: #292
2025-07-06 17:57:48 +00:00
de87b6c46b Merge pull request 'Enable TLS in email delivery' (#291) from tls-email into main
Some checks failed
Run unit tests / rubocop (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 2m42s
Run unit tests / build-static-assets (push) Has been cancelled
Reviewed-on: #291
2025-07-06 17:46:08 +00:00
eabba2109a Update FROM address for email delivery
All checks were successful
Run unit tests / check-licenses (pull_request) Successful in 35s
Run unit tests / copyright_notice (pull_request) Successful in 40s
Run unit tests / rubocop (pull_request) Successful in 1m10s
Run unit tests / unit_tests (pull_request) Successful in 1m47s
Run unit tests / build-static-assets (pull_request) Successful in 14m53s
2025-07-06 19:40:47 +02:00
1586f88986 Enable TLS in email delivery
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 27s
Run unit tests / check-licenses (pull_request) Successful in 41s
Run unit tests / copyright_notice (pull_request) Successful in 45s
Run unit tests / unit_tests (pull_request) Successful in 1m14s
Run unit tests / build-static-assets (pull_request) Successful in 12m2s
2025-07-06 19:32:31 +02:00
c42eb4e576 Merge pull request 'Send email to organizers whenever a guest changes their attendance status' (#290) from status-change-email into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 45s
Run unit tests / build-static-assets (push) Successful in 10m33s
Reviewed-on: #290
2025-07-06 16:53:49 +00:00
29b3fca80c Add copyright notice
All checks were successful
Run unit tests / copyright_notice (pull_request) Successful in 1m25s
Run unit tests / rubocop (pull_request) Successful in 1m46s
Run unit tests / check-licenses (pull_request) Successful in 2m9s
Run unit tests / unit_tests (pull_request) Successful in 2m56s
Run unit tests / build-static-assets (pull_request) Successful in 18m42s
2025-07-06 16:32:02 +00:00
d236e459cd Send an email whenever an anonymous session updates the attendance status of a guest
All checks were successful
Run unit tests / copyright_notice (pull_request) Successful in 29s
Run unit tests / rubocop (pull_request) Successful in 2m13s
Run unit tests / check-licenses (pull_request) Successful in 2m35s
Run unit tests / unit_tests (pull_request) Successful in 3m23s
Run unit tests / build-static-assets (pull_request) Successful in 18m43s
2025-07-06 18:30:35 +02:00
ff8918a1d4 Define a new email that will be sent to admins when a guest changes their attendance status 2025-07-06 18:11:08 +02:00
45313daba2 Merge pull request 'Configure SMTP settings' (#289) from smtp-settings into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 55s
Run unit tests / build-static-assets (push) Successful in 11m9s
Reviewed-on: #289
2025-07-05 11:56:23 +00:00
ba97a3155a Fix syntax error
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 34s
Run unit tests / check-licenses (pull_request) Successful in 36s
Run unit tests / copyright_notice (pull_request) Successful in 51s
Run unit tests / unit_tests (pull_request) Successful in 1m29s
Run unit tests / build-static-assets (pull_request) Successful in 9m53s
2025-07-05 13:44:54 +02:00
b3f339a02b Avoid error in case SMTP configuration is not present
Some checks failed
Run unit tests / check-licenses (pull_request) Successful in 31s
Run unit tests / copyright_notice (pull_request) Successful in 42s
Run unit tests / unit_tests (pull_request) Successful in 1m10s
Run unit tests / rubocop (pull_request) Successful in 23s
Run unit tests / build-static-assets (pull_request) Failing after 3m4s
2025-07-05 13:33:56 +02:00
d6607cd997 Fix location of SMTP secrets
Some checks failed
Run unit tests / rubocop (pull_request) Successful in 42s
Run unit tests / check-licenses (pull_request) Successful in 45s
Run unit tests / copyright_notice (pull_request) Successful in 1m4s
Run unit tests / unit_tests (pull_request) Successful in 1m50s
Run unit tests / build-static-assets (pull_request) Failing after 2m15s
2025-07-05 13:27:04 +02:00
ba8eb8b85e Configure SMTP settings
Some checks failed
Run unit tests / rubocop (pull_request) Successful in 35s
Run unit tests / check-licenses (pull_request) Successful in 41s
Run unit tests / copyright_notice (pull_request) Successful in 45s
Run unit tests / unit_tests (pull_request) Successful in 2m16s
Run unit tests / build-static-assets (pull_request) Failing after 6m28s
2025-07-05 13:16:27 +02:00
717ee35015 Merge pull request 'Update dependency faker to v3.5.2' (#288) from renovate/faker-3.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 2m40s
Run unit tests / build-static-assets (push) Successful in 13m40s
Reviewed-on: #288
2025-07-02 05:48:15 +00:00
Renovate Bot
1626056456 Update dependency faker to v3.5.2
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 9m49s
Run unit tests / check-licenses (pull_request) Successful in 4m39s
Run unit tests / unit_tests (pull_request) Successful in 29m16s
Run unit tests / build-static-assets (pull_request) Successful in 43m44s
Run unit tests / copyright_notice (pull_request) Successful in 11m4s
2025-07-02 02:06:43 +00:00
f46f25b799 Merge pull request 'Extend the invitations index endpoint to return a PDF file with QRs for invitations' (#287) from invitations-pdf into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 55s
Run unit tests / build-static-assets (push) Successful in 23m10s
Reviewed-on: #287
2025-06-30 22:58:06 +00:00
beda9ff870 Add copyright notice
All checks were successful
Run unit tests / copyright_notice (pull_request) Successful in 1m27s
Run unit tests / rubocop (pull_request) Successful in 1m46s
Run unit tests / check-licenses (pull_request) Successful in 1m56s
Run unit tests / unit_tests (pull_request) Successful in 3m14s
Run unit tests / build-static-assets (pull_request) Successful in 40m16s
2025-06-30 22:14:30 +00:00
f3c9d82074 Extend the invitations index endpoint to return a PDF file with QRs for invitations
All checks were successful
Run unit tests / copyright_notice (pull_request) Successful in 33s
Run unit tests / rubocop (pull_request) Successful in 2m14s
Run unit tests / check-licenses (pull_request) Successful in 2m25s
Run unit tests / unit_tests (pull_request) Successful in 3m42s
Run unit tests / build-static-assets (pull_request) Successful in 40m28s
2025-07-01 00:12:56 +02:00
de92ec0469 Merge pull request 'Update dependency rubocop to v1.77.0' (#283) from renovate/rubocop-1.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 1m12s
Run unit tests / build-static-assets (push) Successful in 9m28s
Reviewed-on: #283
2025-06-22 19:07:22 +00:00
Renovate Bot
6a36a2bda3 Update dependency rubocop to v1.77.0
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 2m9s
Run unit tests / copyright_notice (pull_request) Successful in 2m25s
Run unit tests / check-licenses (pull_request) Successful in 2m56s
Run unit tests / unit_tests (pull_request) Successful in 8m17s
Run unit tests / build-static-assets (pull_request) Successful in 8m42s
2025-06-21 02:06:01 +00:00
c30bdbd513 Merge pull request 'Update dependency rspec-rails to v8.0.1' (#286) from renovate/rspec-rails-8.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 6m34s
Run unit tests / build-static-assets (push) Successful in 9m54s
Reviewed-on: #286
2025-06-20 09:13:11 +00:00
Renovate Bot
a1ed94794a Update dependency rspec-rails to v8.0.1
All checks were successful
Run unit tests / check-licenses (pull_request) Successful in 2m27s
Run unit tests / rubocop (pull_request) Successful in 2m38s
Run unit tests / copyright_notice (pull_request) Successful in 2m32s
Run unit tests / unit_tests (pull_request) Successful in 7m55s
Run unit tests / build-static-assets (pull_request) Successful in 30m56s
2025-06-20 02:05:35 +00:00
9505b6d801 Merge pull request 'Update dependency debug to v1.11.0' (#284) from renovate/debug-1.x-lockfile into main
All checks were successful
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / rubocop (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 3m18s
Run unit tests / build-static-assets (push) Successful in 12m4s
Reviewed-on: #284
2025-06-19 06:59:19 +00:00
f1ba084e04 Merge pull request 'Update dependency annotaterb to v4.16.0' (#285) from renovate/annotaterb-4.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 1m16s
Run unit tests / build-static-assets (push) Successful in 9m12s
Reviewed-on: #285
2025-06-19 06:33:47 +00:00
Renovate Bot
4c262b3ddd Update dependency annotaterb to v4.16.0
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 2m21s
Run unit tests / check-licenses (pull_request) Successful in 2m6s
Run unit tests / copyright_notice (pull_request) Successful in 4m17s
Run unit tests / unit_tests (pull_request) Successful in 8m13s
Run unit tests / build-static-assets (pull_request) Successful in 40m38s
2025-06-19 02:06:48 +00:00
Renovate Bot
9f05d74bb4 Update dependency debug to v1.11.0
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 7m54s
Run unit tests / check-licenses (pull_request) Successful in 6m27s
Run unit tests / unit_tests (pull_request) Successful in 21m27s
Run unit tests / build-static-assets (pull_request) Successful in 46m41s
Run unit tests / copyright_notice (pull_request) Successful in 27s
2025-06-18 02:06:39 +00:00
54d891070c Merge pull request 'Update dependency factory_bot_rails to v6.5.0' (#281) from renovate/factory_bot_rails-6.x-lockfile into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 1m10s
Run unit tests / build-static-assets (push) Successful in 9m7s
Reviewed-on: #281
2025-06-15 10:59:23 +00:00
b32af61358 Merge pull request 'Return guests ordered by invitation within same group' (#282) from guests-order into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 56s
Run unit tests / build-static-assets (push) Successful in 8m45s
Reviewed-on: #282
2025-06-15 09:35:43 +00:00
7f4bd8a8df Return guests ordered by invitation within same group
All checks were successful
Run unit tests / copyright_notice (pull_request) Successful in 53s
Run unit tests / rubocop (pull_request) Successful in 1m4s
Run unit tests / unit_tests (pull_request) Successful in 1m50s
Run unit tests / check-licenses (pull_request) Successful in 43s
Run unit tests / build-static-assets (pull_request) Successful in 8m26s
2025-06-15 11:24:57 +02:00
Renovate Bot
46b59ac617 Update dependency factory_bot_rails to v6.5.0
All checks were successful
Run unit tests / copyright_notice (pull_request) Successful in 2m33s
Run unit tests / rubocop (pull_request) Successful in 3m49s
Run unit tests / check-licenses (pull_request) Successful in 4m17s
Run unit tests / unit_tests (pull_request) Successful in 13m40s
Run unit tests / build-static-assets (pull_request) Successful in 12m30s
2025-06-14 02:04:16 +00:00
f02a6b6a3d Merge pull request 'Allow updating the status of guests from unauthenticated sessions' (#280) from guest-update-from-invitation into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 54s
Run unit tests / build-static-assets (push) Successful in 8m32s
Reviewed-on: #280
2025-06-12 21:26:00 +00:00
efb5cf64f5 Minor changes
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 1m27s
Run unit tests / copyright_notice (pull_request) Successful in 2m45s
Run unit tests / check-licenses (pull_request) Successful in 2m46s
Run unit tests / unit_tests (pull_request) Successful in 4m26s
Run unit tests / build-static-assets (pull_request) Successful in 20m24s
2025-06-12 23:01:03 +02:00
9a99981f67 Allow updating the status of guests from unauthenticated sessions
Some checks failed
Run unit tests / rubocop (pull_request) Failing after 1m4s
Run unit tests / check-licenses (pull_request) Successful in 1m7s
Run unit tests / copyright_notice (pull_request) Successful in 1m38s
Run unit tests / unit_tests (pull_request) Successful in 3m57s
Run unit tests / build-static-assets (pull_request) Successful in 26m1s
2025-06-12 22:53:50 +02:00
9e9ee0c995 Merge pull request 'Define a new public endpoint to get information about an invitation' (#279) from invitations-show-endpoint into main
All checks were successful
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 56s
Run unit tests / build-static-assets (push) Successful in 8m15s
Reviewed-on: #279
2025-06-12 17:32:27 +00:00
82a39bce82 Define a new public endpoint to get information about an invitation
All checks were successful
Run unit tests / copyright_notice (pull_request) Successful in 40s
Run unit tests / rubocop (pull_request) Successful in 52s
Run unit tests / check-licenses (pull_request) Successful in 56s
Run unit tests / unit_tests (pull_request) Successful in 1m38s
Run unit tests / build-static-assets (pull_request) Successful in 8m29s
2025-06-12 19:21:53 +02:00
d953e7c4a2 Merge pull request 'Update dependency ruby to v3.4.3' (#254) from renovate/ruby-3.x into main
All checks were successful
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 52s
Run unit tests / build-static-assets (push) Successful in 17m25s
Reviewed-on: #254
2025-06-11 19:27:11 +00:00
4e4845a8c3 Merge pull request 'Build docker image in the main branch' (#277) from run-build into main
All checks were successful
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / rubocop (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 2m30s
Run unit tests / build-static-assets (push) Successful in 17m0s
Reviewed-on: #277
2025-06-11 19:03:20 +00:00
60436caf5b Merge branch 'main' into renovate/ruby-3.x
All checks were successful
Run unit tests / copyright_notice (pull_request) Successful in 52s
Run unit tests / rubocop (pull_request) Successful in 1m28s
Run unit tests / check-licenses (pull_request) Successful in 1m27s
Run unit tests / unit_tests (pull_request) Successful in 2m34s
Run unit tests / build-static-assets (pull_request) Successful in 25m34s
2025-06-11 18:58:58 +00:00
4efb912e38 Merge branch 'main' into renovate/ruby-3.x
Some checks failed
Run unit tests / check-licenses (pull_request) Failing after 1m6s
Run unit tests / rubocop (pull_request) Failing after 1m11s
Run unit tests / copyright_notice (pull_request) Successful in 2m47s
Run unit tests / unit_tests (pull_request) Failing after 3m3s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-06-01 18:03:21 +00:00
bf35ca5f6e Upgrade to ruby 3.4.3
Some checks failed
Run unit tests / rubocop (pull_request) Failing after 37s
Run unit tests / check-licenses (pull_request) Failing after 37s
Run unit tests / copyright_notice (pull_request) Successful in 1m3s
Run unit tests / unit_tests (pull_request) Failing after 1m24s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-04-25 07:39:13 +02:00
Renovate Bot
8cd4efc6f5 Update dependency ruby to v3.4.3
Some checks failed
Run unit tests / check-licenses (pull_request) Failing after 2m11s
Run unit tests / rubocop (pull_request) Failing after 2m22s
Run unit tests / copyright_notice (pull_request) Successful in 2m43s
Run unit tests / unit_tests (pull_request) Failing after 2m46s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-04-24 02:06:21 +00:00
47 changed files with 851 additions and 239 deletions

View File

@ -19,7 +19,7 @@ jobs:
ports: ports:
- 5432 - 5432
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.head_ref }} # Checkout the actual branch, not the result if merged into the base ref: ${{ github.head_ref }} # Checkout the actual branch, not the result if merged into the base
@ -68,7 +68,7 @@ jobs:
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
- uses: ruby/setup-ruby@v1 - uses: ruby/setup-ruby@v1
@ -78,7 +78,7 @@ jobs:
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
- uses: ruby/setup-ruby@v1 - uses: ruby/setup-ruby@v1
@ -90,7 +90,7 @@ jobs:
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
token: ${{ secrets.ACTIONS_TOKEN }} token: ${{ secrets.ACTIONS_TOKEN }}
ref: ${{ github.head_ref }} ref: ${{ github.head_ref }}
@ -125,7 +125,7 @@ jobs:
needs: needs:
- unit_tests - unit_tests
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1 +1 @@
ruby-3.4.2 ruby-3.4.3

View File

@ -1,7 +1,7 @@
# syntax = docker/dockerfile:1 # syntax = docker/dockerfile:1
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile # Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.4.2 ARG RUBY_VERSION=3.4.3
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim AS base FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim AS base
# Rails app lives here # Rails app lives here
@ -13,7 +13,7 @@ ENV RAILS_ENV="production" \
BUNDLE_PATH="/usr/local/bundle" \ BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development" BUNDLE_WITHOUT="development"
RUN apt-get update && apt-get install -y nodejs RUN apt-get update && apt-get install -y nodejs wkhtmltopdf
# Throw-away build stage to reduce size of final image # Throw-away build stage to reduce size of final image
FROM base AS build FROM base AS build

View File

@ -1,13 +1,13 @@
# syntax = docker/dockerfile:1 # syntax = docker/dockerfile:1
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile # Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.4.2 ARG RUBY_VERSION=3.4.3
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
# Rails app lives here # Rails app lives here
WORKDIR /rails WORKDIR /rails
RUN apt-get update && apt-get install -y nodejs RUN apt-get update && apt-get install -y nodejs wkhtmltopdf
FROM base as build FROM base as build

View File

@ -2,7 +2,7 @@
source 'https://rubygems.org' source 'https://rubygems.org'
ruby '3.4.2' ruby '3.4.3'
gem 'bootsnap', require: false gem 'bootsnap', require: false
gem 'csv' gem 'csv'
gem 'importmap-rails' gem 'importmap-rails'
@ -51,3 +51,7 @@ gem 'chroma'
gem 'solid_queue', '~> 1.0' gem 'solid_queue', '~> 1.0'
gem 'devise', '~> 4.9' gem 'devise', '~> 4.9'
gem 'wicked_pdf', '~> 2.8'
gem 'rqrcode', '~> 3.1'

View File

@ -1,29 +1,29 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (8.0.2) actioncable (8.0.2.1)
actionpack (= 8.0.2) actionpack (= 8.0.2.1)
activesupport (= 8.0.2) activesupport (= 8.0.2.1)
nio4r (~> 2.0) nio4r (~> 2.0)
websocket-driver (>= 0.6.1) websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
actionmailbox (8.0.2) actionmailbox (8.0.2.1)
actionpack (= 8.0.2) actionpack (= 8.0.2.1)
activejob (= 8.0.2) activejob (= 8.0.2.1)
activerecord (= 8.0.2) activerecord (= 8.0.2.1)
activestorage (= 8.0.2) activestorage (= 8.0.2.1)
activesupport (= 8.0.2) activesupport (= 8.0.2.1)
mail (>= 2.8.0) mail (>= 2.8.0)
actionmailer (8.0.2) actionmailer (8.0.2.1)
actionpack (= 8.0.2) actionpack (= 8.0.2.1)
actionview (= 8.0.2) actionview (= 8.0.2.1)
activejob (= 8.0.2) activejob (= 8.0.2.1)
activesupport (= 8.0.2) activesupport (= 8.0.2.1)
mail (>= 2.8.0) mail (>= 2.8.0)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
actionpack (8.0.2) actionpack (8.0.2.1)
actionview (= 8.0.2) actionview (= 8.0.2.1)
activesupport (= 8.0.2) activesupport (= 8.0.2.1)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
rack (>= 2.2.4) rack (>= 2.2.4)
rack-session (>= 1.0.1) rack-session (>= 1.0.1)
@ -31,35 +31,35 @@ GEM
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6) rails-html-sanitizer (~> 1.6)
useragent (~> 0.16) useragent (~> 0.16)
actiontext (8.0.2) actiontext (8.0.2.1)
actionpack (= 8.0.2) actionpack (= 8.0.2.1)
activerecord (= 8.0.2) activerecord (= 8.0.2.1)
activestorage (= 8.0.2) activestorage (= 8.0.2.1)
activesupport (= 8.0.2) activesupport (= 8.0.2.1)
globalid (>= 0.6.0) globalid (>= 0.6.0)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
actionview (8.0.2) actionview (8.0.2.1)
activesupport (= 8.0.2) activesupport (= 8.0.2.1)
builder (~> 3.1) builder (~> 3.1)
erubi (~> 1.11) erubi (~> 1.11)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6) rails-html-sanitizer (~> 1.6)
activejob (8.0.2) activejob (8.0.2.1)
activesupport (= 8.0.2) activesupport (= 8.0.2.1)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (8.0.2) activemodel (8.0.2.1)
activesupport (= 8.0.2) activesupport (= 8.0.2.1)
activerecord (8.0.2) activerecord (8.0.2.1)
activemodel (= 8.0.2) activemodel (= 8.0.2.1)
activesupport (= 8.0.2) activesupport (= 8.0.2.1)
timeout (>= 0.4.0) timeout (>= 0.4.0)
activestorage (8.0.2) activestorage (8.0.2.1)
actionpack (= 8.0.2) actionpack (= 8.0.2.1)
activejob (= 8.0.2) activejob (= 8.0.2.1)
activerecord (= 8.0.2) activerecord (= 8.0.2.1)
activesupport (= 8.0.2) activesupport (= 8.0.2.1)
marcel (~> 1.0) marcel (~> 1.0)
activesupport (8.0.2) activesupport (8.0.2.1)
base64 base64
benchmark (>= 0.3) benchmark (>= 0.3)
bigdecimal bigdecimal
@ -76,7 +76,9 @@ GEM
rails (>= 6.0) rails (>= 6.0)
addressable (2.8.7) addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0) public_suffix (>= 2.0.2, < 7.0)
annotaterb (4.15.0) annotaterb (4.19.0)
activerecord (>= 6.0.0)
activesupport (>= 6.0.0)
ast (2.4.3) ast (2.4.3)
babel-source (5.8.35) babel-source (5.8.35)
babel-transpiler (0.7.0) babel-transpiler (0.7.0)
@ -85,7 +87,7 @@ GEM
base64 (0.3.0) base64 (0.3.0)
bcrypt (3.1.20) bcrypt (3.1.20)
benchmark (0.4.1) benchmark (0.4.1)
bigdecimal (3.2.1) bigdecimal (3.2.3)
bindex (0.8.1) bindex (0.8.1)
bootsnap (1.18.6) bootsnap (1.18.6)
msgpack (~> 1.2) msgpack (~> 1.2)
@ -93,13 +95,14 @@ GEM
childprocess (5.1.0) childprocess (5.1.0)
logger (~> 1.5) logger (~> 1.5)
chroma (0.2.0) chroma (0.2.0)
chunky_png (1.4.0)
coderay (1.1.3) coderay (1.1.3)
concurrent-ruby (1.3.5) concurrent-ruby (1.3.5)
connection_pool (2.5.3) connection_pool (2.5.4)
crass (1.0.6) crass (1.0.6)
csv (3.3.5) csv (3.3.5)
date (3.4.1) date (3.4.1)
debug (1.10.0) debug (1.11.0)
irb (~> 1.10) irb (~> 1.10)
reline (>= 0.3.8) reline (>= 0.3.8)
devise (4.9.4) devise (4.9.4)
@ -110,17 +113,17 @@ GEM
warden (~> 1.2.3) warden (~> 1.2.3)
diff-lcs (1.6.2) diff-lcs (1.6.2)
drb (2.2.3) drb (2.2.3)
erb (5.0.1) erb (5.0.2)
erubi (1.13.1) erubi (1.13.1)
et-orbi (1.2.11) et-orbi (1.2.11)
tzinfo tzinfo
execjs (2.9.1) execjs (2.9.1)
factory_bot (6.4.6) factory_bot (6.5.5)
activesupport (>= 5.0.0) activesupport (>= 6.1.0)
factory_bot_rails (6.4.3) factory_bot_rails (6.5.1)
factory_bot (~> 6.4) factory_bot (~> 6.5)
railties (>= 5.0.0) railties (>= 6.1.0)
faker (3.5.1) faker (3.5.2)
i18n (>= 1.8.11, < 2) i18n (>= 1.8.11, < 2)
fugit (1.11.1) fugit (1.11.1)
et-orbi (~> 1, >= 1.2.11) et-orbi (~> 1, >= 1.2.11)
@ -133,11 +136,11 @@ GEM
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
i18n (1.14.7) i18n (1.14.7)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
importmap-rails (2.1.0) importmap-rails (2.2.2)
actionpack (>= 6.0.0) actionpack (>= 6.0.0)
activesupport (>= 6.0.0) activesupport (>= 6.0.0)
railties (>= 6.0.0) railties (>= 6.0.0)
io-console (0.8.0) io-console (0.8.1)
irb (1.15.2) irb (1.15.2)
pp (>= 0.6.0) pp (>= 0.6.0)
rdoc (>= 4.0.0) rdoc (>= 4.0.0)
@ -145,7 +148,7 @@ GEM
jbuilder (2.13.0) jbuilder (2.13.0)
actionview (>= 5.0.0) actionview (>= 5.0.0)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
json (2.12.2) json (2.13.2)
json-schema (5.0.1) json-schema (5.0.1)
addressable (~> 2.8) addressable (~> 2.8)
jsonapi-deserializable (0.2.0) jsonapi-deserializable (0.2.0)
@ -198,7 +201,7 @@ GEM
msgpack (1.7.5) msgpack (1.7.5)
multi_xml (0.7.1) multi_xml (0.7.1)
bigdecimal (~> 3.1) bigdecimal (~> 3.1)
net-imap (0.5.6) net-imap (0.5.10)
date date
net-protocol net-protocol
net-pop (0.1.2) net-pop (0.1.2)
@ -208,32 +211,37 @@ GEM
net-smtp (0.5.1) net-smtp (0.5.1)
net-protocol net-protocol
nio4r (2.7.4) nio4r (2.7.4)
nokogiri (1.18.8) nokogiri (1.18.10)
mini_portile2 (~> 2.8.2) mini_portile2 (~> 2.8.2)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.8-aarch64-linux-gnu) nokogiri (1.18.10-aarch64-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.8-arm-linux-gnu) nokogiri (1.18.10-arm-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.8-arm64-darwin) nokogiri (1.18.10-arm64-darwin)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.8-x86_64-darwin) nokogiri (1.18.10-x86_64-darwin)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.8-x86_64-linux-gnu) nokogiri (1.18.10-x86_64-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
orm_adapter (0.5.0) orm_adapter (0.5.0)
ostruct (0.6.2)
parallel (1.27.0) parallel (1.27.0)
parser (3.3.8.0) parser (3.3.9.0)
ast (~> 2.4.1) ast (~> 2.4.1)
racc racc
pg (1.5.9) pg (1.6.2)
pg (1.6.2-aarch64-linux)
pg (1.6.2-arm64-darwin)
pg (1.6.2-x86_64-darwin)
pg (1.6.2-x86_64-linux)
pluck_to_hash (1.0.2) pluck_to_hash (1.0.2)
activerecord (>= 4.0.2) activerecord (>= 4.0.2)
activesupport (>= 4.0.2) activesupport (>= 4.0.2)
pp (0.6.2) pp (0.6.2)
prettyprint prettyprint
prettyprint (0.2.0) prettyprint (0.2.0)
prism (1.4.0) prism (1.5.1)
pry (0.15.2) pry (0.15.2)
coderay (~> 1.1) coderay (~> 1.1)
method_source (~> 1.0) method_source (~> 1.0)
@ -241,11 +249,11 @@ GEM
date date
stringio stringio
public_suffix (6.0.1) public_suffix (6.0.1)
puma (6.6.0) puma (6.6.1)
nio4r (~> 2.0) nio4r (~> 2.0)
raabro (1.4.0) raabro (1.4.0)
racc (1.8.1) racc (1.8.1)
rack (3.1.15) rack (3.2.1)
rack-cors (3.0.0) rack-cors (3.0.0)
logger logger
rack (>= 3.0.14) rack (>= 3.0.14)
@ -256,20 +264,20 @@ GEM
rack (>= 1.3) rack (>= 1.3)
rackup (2.2.1) rackup (2.2.1)
rack (>= 3) rack (>= 3)
rails (8.0.2) rails (8.0.2.1)
actioncable (= 8.0.2) actioncable (= 8.0.2.1)
actionmailbox (= 8.0.2) actionmailbox (= 8.0.2.1)
actionmailer (= 8.0.2) actionmailer (= 8.0.2.1)
actionpack (= 8.0.2) actionpack (= 8.0.2.1)
actiontext (= 8.0.2) actiontext (= 8.0.2.1)
actionview (= 8.0.2) actionview (= 8.0.2.1)
activejob (= 8.0.2) activejob (= 8.0.2.1)
activemodel (= 8.0.2) activemodel (= 8.0.2.1)
activerecord (= 8.0.2) activerecord (= 8.0.2.1)
activestorage (= 8.0.2) activestorage (= 8.0.2.1)
activesupport (= 8.0.2) activesupport (= 8.0.2.1)
bundler (>= 1.15.0) bundler (>= 1.15.0)
railties (= 8.0.2) railties (= 8.0.2.1)
rails-dom-testing (2.3.0) rails-dom-testing (2.3.0)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
minitest minitest
@ -277,9 +285,9 @@ GEM
rails-html-sanitizer (1.6.2) rails-html-sanitizer (1.6.2)
loofah (~> 2.21) loofah (~> 2.21)
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
railties (8.0.2) railties (8.0.2.1)
actionpack (= 8.0.2) actionpack (= 8.0.2.1)
activesupport (= 8.0.2) activesupport (= 8.0.2.1)
irb (~> 1.13) irb (~> 1.13)
rackup (>= 1.0.0) rackup (>= 1.0.0)
rake (>= 12.2) rake (>= 12.2)
@ -287,7 +295,7 @@ GEM
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
rainbow (3.1.1) rainbow (3.1.1)
rake (13.3.0) rake (13.3.0)
rdoc (6.14.0) rdoc (6.14.2)
erb erb
psych (>= 4.0.0) psych (>= 4.0.0)
react-rails (3.2.1) react-rails (3.2.1)
@ -296,18 +304,22 @@ GEM
execjs execjs
railties (>= 3.2) railties (>= 3.2)
tilt tilt
redis (5.4.0) redis (5.4.1)
redis-client (>= 0.22.0) redis-client (>= 0.22.0)
redis-client (0.23.2) redis-client (0.23.2)
connection_pool connection_pool
regexp_parser (2.10.0) regexp_parser (2.11.3)
reline (0.6.1) reline (0.6.2)
io-console (~> 0.5) io-console (~> 0.5)
responders (3.1.1) responders (3.1.1)
actionpack (>= 5.2) actionpack (>= 5.2)
railties (>= 5.2) railties (>= 5.2)
rexml (3.3.9) rexml (3.3.9)
rspec-core (3.13.4) rqrcode (3.1.0)
chunky_png (~> 1.0)
rqrcode_core (~> 2.0)
rqrcode_core (2.0.0)
rspec-core (3.13.5)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
rspec-expectations (3.13.5) rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
@ -315,7 +327,7 @@ GEM
rspec-mocks (3.13.5) rspec-mocks (3.13.5)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
rspec-rails (8.0.0) rspec-rails (8.0.2)
actionpack (>= 7.2) actionpack (>= 7.2)
activesupport (>= 7.2) activesupport (>= 7.2)
railties (>= 7.2) railties (>= 7.2)
@ -323,7 +335,7 @@ GEM
rspec-expectations (~> 3.13) rspec-expectations (~> 3.13)
rspec-mocks (~> 3.13) rspec-mocks (~> 3.13)
rspec-support (~> 3.13) rspec-support (~> 3.13)
rspec-support (3.13.4) rspec-support (3.13.5)
rswag (2.16.0) rswag (2.16.0)
rswag-api (= 2.16.0) rswag-api (= 2.16.0)
rswag-specs (= 2.16.0) rswag-specs (= 2.16.0)
@ -339,7 +351,7 @@ GEM
rswag-ui (2.16.0) rswag-ui (2.16.0)
actionpack (>= 5.2, < 8.1) actionpack (>= 5.2, < 8.1)
railties (>= 5.2, < 8.1) railties (>= 5.2, < 8.1)
rubocop (1.76.1) rubocop (1.80.2)
json (~> 2.3) json (~> 2.3)
language_server-protocol (~> 3.17.0.2) language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0) lint_roller (~> 1.1.0)
@ -347,16 +359,16 @@ GEM
parser (>= 3.3.0.2) parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0) regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.45.0, < 2.0) rubocop-ast (>= 1.46.0, < 2.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0) unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.45.1) rubocop-ast (1.46.0)
parser (>= 3.3.7.2) parser (>= 3.3.7.2)
prism (~> 1.4) prism (~> 1.4)
rubocop-factory_bot (2.27.1) rubocop-factory_bot (2.27.1)
lint_roller (~> 1.1) lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1) rubocop (~> 1.72, >= 1.72.1)
rubocop-rails (2.32.0) rubocop-rails (2.33.3)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
lint_roller (~> 1.1) lint_roller (~> 1.1)
rack (>= 1.1) rack (>= 1.1)
@ -376,13 +388,13 @@ GEM
securerandom (0.4.1) securerandom (0.4.1)
shoulda-matchers (6.5.0) shoulda-matchers (6.5.0)
activesupport (>= 5.2.0) activesupport (>= 5.2.0)
solid_queue (1.1.5) solid_queue (1.2.1)
activejob (>= 7.1) activejob (>= 7.1)
activerecord (>= 7.1) activerecord (>= 7.1)
concurrent-ruby (>= 1.3.1) concurrent-ruby (>= 1.3.1)
fugit (~> 1.11.0) fugit (~> 1.11.0)
railties (>= 7.1) railties (>= 7.1)
thor (~> 1.3.1) thor (>= 1.3.1)
sprockets (4.2.1) sprockets (4.2.1)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
rack (>= 2.2.4, < 4) rack (>= 2.2.4, < 4)
@ -393,7 +405,7 @@ GEM
stimulus-rails (1.3.4) stimulus-rails (1.3.4)
railties (>= 6.0.0) railties (>= 6.0.0)
stringio (3.1.7) stringio (3.1.7)
thor (1.3.2) thor (1.4.0)
tilt (2.4.0) tilt (2.4.0)
timeout (0.4.3) timeout (0.4.3)
tomlrb (2.0.3) tomlrb (2.0.3)
@ -416,6 +428,9 @@ GEM
base64 base64
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5) websocket-extensions (0.1.5)
wicked_pdf (2.8.2)
activesupport
ostruct
with_env (1.1.0) with_env (1.1.0)
xml-simple (1.1.9) xml-simple (1.1.9)
rexml rexml
@ -454,6 +469,7 @@ DEPENDENCIES
rails (~> 8.0.0, >= 8.0.0) rails (~> 8.0.0, >= 8.0.0)
react-rails react-rails
redis (>= 4.0.1) redis (>= 4.0.1)
rqrcode (~> 3.1)
rspec-rails (~> 8.0.0) rspec-rails (~> 8.0.0)
rswag rswag
rubocop rubocop
@ -469,60 +485,62 @@ DEPENDENCIES
turbo-rails turbo-rails
tzinfo-data tzinfo-data
web-console web-console
wicked_pdf (~> 2.8)
CHECKSUMS CHECKSUMS
actioncable (8.0.2) sha256=7bcce2df62e91a80143592600e16583c273e98aab50ae40a9f6a2604bb3289a0 actioncable (8.0.2.1) sha256=6f1cb20db39fba28a93569e8d5dab42b2749d7ddd4baebb5bbecd4217e49d6a2
actionmailbox (8.0.2) sha256=3d8fb3453913e6257da4d02004bbfa2b997dfd10672f8d990e95013983e2cedb actionmailbox (8.0.2.1) sha256=8ea8c6e31e448961c06fc1d6282775b32aff1c009f232d4564e07e54850a6cad
actionmailer (8.0.2) sha256=b0c968b38576ec56a3dc2795931818e0aaae6a18cc9801f53f175c12d4b277d0 actionmailer (8.0.2.1) sha256=0de14d8d04541eab130858cb2f0697266be42de1afe1104bc43d7998137ddb9c
actionpack (8.0.2) sha256=93e703064f3815295ccf820f57acbca719aec836749597da9262781c9b2f4b78 actionpack (8.0.2.1) sha256=61e7e11a31dbe5152ca57221788bdca42ef302c4cc53b4c8993d68dce8982b0a
actiontext (8.0.2) sha256=a40db32032ee2fbb479d5d69318c4284344c1cda73836fd73ffcdb917d203abf actiontext (8.0.2.1) sha256=0cc4b3b5cfb9d915c6697b05b013dad7f4eaf074d9989700b6a0a55cf620d6b8
actionview (8.0.2) sha256=e038e1405cdfc18f04f17243da4fb8eeda3a4992f63a6d70a7281d255cf7cebb actionview (8.0.2.1) sha256=2ea6d20ccb0b7b84a221a940ac06853ce99235e4ecb4947815839c7c5ecbf347
activejob (8.0.2) sha256=b0228b45e36b1ef3a081c684e81494147e094a6baf729018756ccf125b1853ca activejob (8.0.2.1) sha256=d6e5f2da07ec8efac13a38af1752416770dc74e95783f7b252506d707aa32b89
activemodel (8.0.2) sha256=0ae1fb7fa1fae0699ba041a9e97702df42ea3b13f2d39f2d0fde51fca5f0656c activemodel (8.0.2.1) sha256=17bab6cdb86531844113df22f864480a89a276bf0318246e628f99e0ac077ec4
activerecord (8.0.2) sha256=793470b92c44e4198d0262ac60086b7822f0ea585079ad67e32a6e4c86f2d90a activerecord (8.0.2.1) sha256=a6556e7bdd53f3889d18d2aa3a7ff115fd6c5e1463dd06f97fb88d06b58c6df1
activestorage (8.0.2) sha256=f83d221e0f06ae38f2200e55490bd155c76d0add330f6e300e8646048d672977 activestorage (8.0.2.1) sha256=43bb3d9e115471e201e6a66813810c1d15b607a321f29d62efdf9d90ffaf76f8
activesupport (8.0.2) sha256=8565cddba31b900cdc17682fd66ecd020441e3eef320a9930285394e8c07a45e activesupport (8.0.2.1) sha256=0405a76fd1ca989975d9ae00d46a4d3979bdf3817482d846b63affa84bd561c6
acts_as_tenant (1.0.1) sha256=6944e4d64533337938a8817a6b4ff9b11189c9dcc0b1333bb89f3821a4c14c53 acts_as_tenant (1.0.1) sha256=6944e4d64533337938a8817a6b4ff9b11189c9dcc0b1333bb89f3821a4c14c53
addressable (2.8.7) sha256=462986537cf3735ab5f3c0f557f14155d778f4b43ea4f485a9deb9c8f7c58232 addressable (2.8.7) sha256=462986537cf3735ab5f3c0f557f14155d778f4b43ea4f485a9deb9c8f7c58232
annotaterb (4.15.0) sha256=fb871b5a3f96d1a3195ab0f0f51adb9105ab00492f10e97dd6f35d321e3410b0 annotaterb (4.19.0) sha256=c951df62059b3ac1ae383f4140bf935a140a15b6461f8d9a97d34b38ce2c7208
ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383 ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
babel-source (5.8.35) sha256=79ef222a9dcb867ac2efa3b0da35b4bcb15a4bfa67b6b2dcbf1e9a29104498d9 babel-source (5.8.35) sha256=79ef222a9dcb867ac2efa3b0da35b4bcb15a4bfa67b6b2dcbf1e9a29104498d9
babel-transpiler (0.7.0) sha256=4c06f4ad9e8e1cabe94f99e11df2f140bb72aca9ba067dbb49dc14d9b98d1570 babel-transpiler (0.7.0) sha256=4c06f4ad9e8e1cabe94f99e11df2f140bb72aca9ba067dbb49dc14d9b98d1570
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
bcrypt (3.1.20) sha256=8410f8c7b3ed54a3c00cd2456bf13917d695117f033218e2483b2e40b0784099 bcrypt (3.1.20) sha256=8410f8c7b3ed54a3c00cd2456bf13917d695117f033218e2483b2e40b0784099
benchmark (0.4.1) sha256=d4ef40037bba27f03b28013e219b950b82bace296549ec15a78016552f8d2cce benchmark (0.4.1) sha256=d4ef40037bba27f03b28013e219b950b82bace296549ec15a78016552f8d2cce
bigdecimal (3.2.1) sha256=1f68631e876c6aba8fe9b84b36983c55ad3293ff2d1ad4c6f115bde1e9d802e3 bigdecimal (3.2.3) sha256=ffd11d1ac67a0d3b2f44aec0a6487210b3f813f363dd11f1fcccf5ba00da4e1b
bindex (0.8.1) sha256=7b1ecc9dc539ed8bccfc8cb4d2732046227b09d6f37582ff12e50a5047ceb17e bindex (0.8.1) sha256=7b1ecc9dc539ed8bccfc8cb4d2732046227b09d6f37582ff12e50a5047ceb17e
bootsnap (1.18.6) sha256=0ae2393c1e911e38be0f24e9173e7be570c3650128251bf06240046f84a07d00 bootsnap (1.18.6) sha256=0ae2393c1e911e38be0f24e9173e7be570c3650128251bf06240046f84a07d00
builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
childprocess (5.1.0) sha256=9a8d484be2fd4096a0e90a0cd3e449a05bc3aa33f8ac9e4d6dcef6ac1455b6ec childprocess (5.1.0) sha256=9a8d484be2fd4096a0e90a0cd3e449a05bc3aa33f8ac9e4d6dcef6ac1455b6ec
chroma (0.2.0) sha256=64bdcd36a4765fbcd45adc64960cc153101300b4918f90ffdd89f4e2eb954b54 chroma (0.2.0) sha256=64bdcd36a4765fbcd45adc64960cc153101300b4918f90ffdd89f4e2eb954b54
chunky_png (1.4.0) sha256=89d5b31b55c0cf4da3cf89a2b4ebc3178d8abe8cbaf116a1dba95668502fdcfe
coderay (1.1.3) sha256=dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b coderay (1.1.3) sha256=dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b
concurrent-ruby (1.3.5) sha256=813b3e37aca6df2a21a3b9f1d497f8cbab24a2b94cab325bffe65ee0f6cbebc6 concurrent-ruby (1.3.5) sha256=813b3e37aca6df2a21a3b9f1d497f8cbab24a2b94cab325bffe65ee0f6cbebc6
connection_pool (2.5.3) sha256=cfd74a82b9b094d1ce30c4f1a346da23ee19dc8a062a16a85f58eab1ced4305b connection_pool (2.5.4) sha256=e9e1922327416091f3f6542f5f4446c2a20745276b9aa796dd0bb2fd0ea1e70a
crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d
csv (3.3.5) sha256=6e5134ac3383ef728b7f02725d9872934f523cb40b961479f69cf3afa6c8e73f csv (3.3.5) sha256=6e5134ac3383ef728b7f02725d9872934f523cb40b961479f69cf3afa6c8e73f
date (3.4.1) sha256=bf268e14ef7158009bfeaec40b5fa3c7271906e88b196d958a89d4b408abe64f date (3.4.1) sha256=bf268e14ef7158009bfeaec40b5fa3c7271906e88b196d958a89d4b408abe64f
debug (1.10.0) sha256=11e28ca74875979e612444104f3972bd5ffb9e79179907d7ad46dba44bd2e7a4 debug (1.11.0) sha256=1425db64cfa0130c952684e3dc974985be201dd62899bf4bbe3f8b5d6cf1aef2
devise (4.9.4) sha256=920042fe5e704c548aa4eb65ebdd65980b83ffae67feb32c697206bfd975a7f8 devise (4.9.4) sha256=920042fe5e704c548aa4eb65ebdd65980b83ffae67feb32c697206bfd975a7f8
diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962 diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373 drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
erb (5.0.1) sha256=760439803b36cc93eca8a266aab614614e588024a89bc30a62e78d98ff452c23 erb (5.0.2) sha256=d30f258143d4300fb4ecf430042ac12970c9bb4b33c974a545b8f58c1ec26c0f
erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9 erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9
et-orbi (1.2.11) sha256=d26e868cc21db88280a9ec1a50aa3da5d267eb9b2037ba7b831d6c2731f5df64 et-orbi (1.2.11) sha256=d26e868cc21db88280a9ec1a50aa3da5d267eb9b2037ba7b831d6c2731f5df64
execjs (2.9.1) sha256=e8fd066f6df60c8e8fbebc32c6fb356b5212c77374e8416a9019ca4bb154dcfb execjs (2.9.1) sha256=e8fd066f6df60c8e8fbebc32c6fb356b5212c77374e8416a9019ca4bb154dcfb
factory_bot (6.4.6) sha256=1a9486ce98d318d740d8f5804b885a8265a28f326ecf2bcd4ce9fb27a71a6e04 factory_bot (6.5.5) sha256=ce59295daee1b4704dab8a2fee6816f513d467c6aa3bc587860767d74a66efbe
factory_bot_rails (6.4.3) sha256=ea73ceac1c0ff3dc11fff390bf2ea8a2604066525ed8ecd3b3bc2c267226dcc8 factory_bot_rails (6.5.1) sha256=d3cc4851eae4dea8a665ec4a4516895045e710554d2b5ac9e68b94d351bc6d68
faker (3.5.1) sha256=1ad1fbea279d882f486059c23fe3ddb816ccd1d7052c05a45014b4450d859bfc faker (3.5.2) sha256=f9a80291b2e3f259801d1dd552f0732fe04dce5d1f74e798365bc0413789c473
fugit (1.11.1) sha256=e89485e7be22226d8e9c6da411664d0660284b4b1c08cacb540f505907869868 fugit (1.11.1) sha256=e89485e7be22226d8e9c6da411664d0660284b4b1c08cacb540f505907869868
globalid (1.2.1) sha256=70bf76711871f843dbba72beb8613229a49429d1866828476f9c9d6ccc327ce9 globalid (1.2.1) sha256=70bf76711871f843dbba72beb8613229a49429d1866828476f9c9d6ccc327ce9
httparty (0.23.1) sha256=3ac1dd62f2010f6ece551716f5ceec2b2012011d89f1751917ab7f724e966b55 httparty (0.23.1) sha256=3ac1dd62f2010f6ece551716f5ceec2b2012011d89f1751917ab7f724e966b55
i18n (1.14.7) sha256=ceba573f8138ff2c0915427f1fc5bdf4aa3ab8ae88c8ce255eb3ecf0a11a5d0f i18n (1.14.7) sha256=ceba573f8138ff2c0915427f1fc5bdf4aa3ab8ae88c8ce255eb3ecf0a11a5d0f
importmap-rails (2.1.0) sha256=9f10c67d60651a547579f448100d033df311c5d5db578301374aeb774faae741 importmap-rails (2.2.2) sha256=729f5b1092f832780829ade1d0b46c7e53d91c556f06da7254da2977e93fe614
io-console (0.8.0) sha256=cd6a9facbc69871d69b2cb8b926fc6ea7ef06f06e505e81a64f14a470fddefa2 io-console (0.8.1) sha256=1e15440a6b2f67b6ea496df7c474ed62c860ad11237f29b3bd187f054b925fcb
irb (1.15.2) sha256=222f32952e278da34b58ffe45e8634bf4afc2dc7aa9da23fed67e581aa50fdba irb (1.15.2) sha256=222f32952e278da34b58ffe45e8634bf4afc2dc7aa9da23fed67e581aa50fdba
jbuilder (2.13.0) sha256=7200a38a1c0081aa81b7a9757e7a299db75bc58cf1fd45ca7919a91627d227d6 jbuilder (2.13.0) sha256=7200a38a1c0081aa81b7a9757e7a299db75bc58cf1fd45ca7919a91627d227d6
json (2.12.2) sha256=ba94a48ad265605c8fa9a50a5892f3ba6a02661aa010f638211f3cb36f44abf4 json (2.13.2) sha256=02e1f118d434c6b230a64ffa5c8dee07e3ec96244335c392eaed39e1199dbb68
json-schema (5.0.1) sha256=bef71a82c600a42594911553522e143f7634affc198ed507ef3ded2f920a74a9 json-schema (5.0.1) sha256=bef71a82c600a42594911553522e143f7634affc198ed507ef3ded2f920a74a9
jsonapi-deserializable (0.2.0) sha256=5f0ca2d3f8404cce1584a314e8a3753be32a56054c942adfe997b87e92bce147 jsonapi-deserializable (0.2.0) sha256=5f0ca2d3f8404cce1584a314e8a3753be32a56054c942adfe997b87e92bce147
jsonapi-parser (0.1.1) sha256=9ee0dc031e88fc7548d56fab66f9716d1e1c06f972b529b8c4617bc42a097020 jsonapi-parser (0.1.1) sha256=9ee0dc031e88fc7548d56fab66f9716d1e1c06f972b529b8c4617bc42a097020
@ -547,63 +565,70 @@ CHECKSUMS
money (6.19.0) sha256=ec936fa1e42f2783719241ed9fd52725d0efa628f928feea1eb5c37d5de7daf3 money (6.19.0) sha256=ec936fa1e42f2783719241ed9fd52725d0efa628f928feea1eb5c37d5de7daf3
msgpack (1.7.5) sha256=ffb04979f51e6406823c03abe50e1da2c825c55a37dee138518cdd09d9d3aea8 msgpack (1.7.5) sha256=ffb04979f51e6406823c03abe50e1da2c825c55a37dee138518cdd09d9d3aea8
multi_xml (0.7.1) sha256=4fce100c68af588ff91b8ba90a0bb3f0466f06c909f21a32f4962059140ba61b multi_xml (0.7.1) sha256=4fce100c68af588ff91b8ba90a0bb3f0466f06c909f21a32f4962059140ba61b
net-imap (0.5.6) sha256=1ede8048ee688a14206060bf37a716d18cb6ea00855f6c9b15daee97ee51fbe5 net-imap (0.5.10) sha256=f84d206a296bff48a3a10507567fc38b050d2a40c92ea0d448164f64e60d6205
net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3 net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3
net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8 net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736 net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736
nio4r (2.7.4) sha256=d95dee68e0bb251b8ff90ac3423a511e3b784124e5db7ff5f4813a220ae73ca9 nio4r (2.7.4) sha256=d95dee68e0bb251b8ff90ac3423a511e3b784124e5db7ff5f4813a220ae73ca9
nokogiri (1.18.8) sha256=8c7464875d9ca7f71080c24c0db7bcaa3940e8be3c6fc4bcebccf8b9a0016365 nokogiri (1.18.10) sha256=d5cc0731008aa3b3a87b361203ea3d19b2069628cb55e46ac7d84a0445e69cc1
nokogiri (1.18.8-aarch64-linux-gnu) sha256=36badd2eb281fca6214a5188e24a34399b15d89730639a068d12931e2adc210e nokogiri (1.18.10-aarch64-linux-gnu) sha256=7fb87235d729c74a2be635376d82b1d459230cc17c50300f8e4fcaabc6195344
nokogiri (1.18.8-arm-linux-gnu) sha256=17de01ca3adf9f8e187883ed73c672344d3dbb3c260f88ffa1008e8dc255a28e nokogiri (1.18.10-arm-linux-gnu) sha256=51f4f25ab5d5ba1012d6b16aad96b840a10b067b93f35af6a55a2c104a7ee322
nokogiri (1.18.8-arm64-darwin) sha256=483b5b9fb33653f6f05cbe00d09ea315f268f0e707cfc809aa39b62993008212 nokogiri (1.18.10-arm64-darwin) sha256=c2b0de30770f50b92c9323fa34a4e1cf5a0af322afcacd239cd66ee1c1b22c85
nokogiri (1.18.8-x86_64-darwin) sha256=024cdfe7d9ae3466bba6c06f348fb2a8395d9426b66a3c82f1961b907945cc0c nokogiri (1.18.10-x86_64-darwin) sha256=536e74bed6db2b5076769cab5e5f5af0cd1dccbbd75f1b3e1fa69d1f5c2d79e2
nokogiri (1.18.8-x86_64-linux-gnu) sha256=4a747875db873d18a2985ee2c320a6070c4a414ad629da625fbc58d1a20e5ecc nokogiri (1.18.10-x86_64-linux-gnu) sha256=ff5ba26ba2dbce5c04b9ea200777fd225061d7a3930548806f31db907e500f72
orm_adapter (0.5.0) sha256=aa5d0be5d540cbb46d3a93e88061f4ece6a25f6e97d6a47122beb84fe595e9b9 orm_adapter (0.5.0) sha256=aa5d0be5d540cbb46d3a93e88061f4ece6a25f6e97d6a47122beb84fe595e9b9
ostruct (0.6.2) sha256=6d7302a299e400a2c248d6ce0dad18fc3a5714e8096facc25ffd0c54ee57cfc0
parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130 parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
parser (3.3.8.0) sha256=2476364142b307fa5a1b1ece44f260728be23858a9c71078e956131a75453c45 parser (3.3.9.0) sha256=94d6929354b1a6e3e1f89d79d4d302cc8f5aa814431a6c9c7e0623335d7687f2
pg (1.5.9) sha256=761efbdf73b66516f0c26fcbe6515dc7500c3f0aa1a1b853feae245433c64fdc pg (1.6.2) sha256=58614afd405cc9c2c9e15bffe8432e0d6cfc58b722344ad4a47c73a85189c875
pg (1.6.2-aarch64-linux) sha256=0503c6be5b0ca5ca3aaf91f2ed638f90843313cb81e8e7d7b60ad4bb62c3d131
pg (1.6.2-arm64-darwin) sha256=4d44500b28d5193b26674583d199a6484f80f1f2ea9cf54f7d7d06a1b7e316b6
pg (1.6.2-x86_64-darwin) sha256=c441a55723584e2ae41749bf26024d7ffdfe1841b442308ed50cd6b7fda04115
pg (1.6.2-x86_64-linux) sha256=525f438137f2d1411a1ebcc4208ec35cb526b5a3b285a629355c73208506a8ea
pluck_to_hash (1.0.2) sha256=1599906239716f98262a41493dd7d4cb72e8d83ad3d76d666deacfc5de50a47e pluck_to_hash (1.0.2) sha256=1599906239716f98262a41493dd7d4cb72e8d83ad3d76d666deacfc5de50a47e
pp (0.6.2) sha256=947ec3120c6f92195f8ee8aa25a7b2c5297bb106d83b41baa02983686577b6ff pp (0.6.2) sha256=947ec3120c6f92195f8ee8aa25a7b2c5297bb106d83b41baa02983686577b6ff
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193 prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
prism (1.4.0) sha256=dc0e3e00e93160213dc2a65519d9002a4a1e7b962db57d444cf1a71565bb703e prism (1.5.1) sha256=b40c1b76ccb9fcccc3d1553967cda6e79fa7274d8bfea0d98b15d27a6d187134
pry (0.15.2) sha256=12d54b8640d3fa29c9211dd4ffb08f3fd8bf7a4fd9b5a73ce5b59c8709385b6b pry (0.15.2) sha256=12d54b8640d3fa29c9211dd4ffb08f3fd8bf7a4fd9b5a73ce5b59c8709385b6b
psych (5.2.6) sha256=814328aa5dcb6d604d32126a20bc1cbcf05521a5b49dbb1a8b30a07e580f316e psych (5.2.6) sha256=814328aa5dcb6d604d32126a20bc1cbcf05521a5b49dbb1a8b30a07e580f316e
public_suffix (6.0.1) sha256=61d44e1cab5cbbbe5b31068481cf16976dd0dc1b6b07bd95617ef8c5e3e00c6f public_suffix (6.0.1) sha256=61d44e1cab5cbbbe5b31068481cf16976dd0dc1b6b07bd95617ef8c5e3e00c6f
puma (6.6.0) sha256=f25c06873eb3d5de5f0a4ebc783acc81a4ccfe580c760cfe323497798018ad87 puma (6.6.1) sha256=b9b56e4a4ea75d1bfa6d9e1972ee2c9f43d0883f011826d914e8e37b3694ea1e
raabro (1.4.0) sha256=d4fa9ff5172391edb92b242eed8be802d1934b1464061ae5e70d80962c5da882 raabro (1.4.0) sha256=d4fa9ff5172391edb92b242eed8be802d1934b1464061ae5e70d80962c5da882
racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
rack (3.1.15) sha256=d12b3e9960d18a26ded961250f2c0e3b375b49ff40dbe6786e9c3b160cbffca4 rack (3.2.1) sha256=30af3f7e5ec21b0d14d822cf24446048dba5f651b617c7e97405b604f20a9e33
rack-cors (3.0.0) sha256=7b95be61db39606906b61b83bd7203fa802b0ceaaad8fcb2fef39e097bf53f68 rack-cors (3.0.0) sha256=7b95be61db39606906b61b83bd7203fa802b0ceaaad8fcb2fef39e097bf53f68
rack-session (2.1.1) sha256=0b6dc07dea7e4b583f58a48e8b806d4c9f1c6c9214ebc202ec94562cbea2e4e9 rack-session (2.1.1) sha256=0b6dc07dea7e4b583f58a48e8b806d4c9f1c6c9214ebc202ec94562cbea2e4e9
rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463 rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463
rackup (2.2.1) sha256=f737191fd5c5b348b7f0a4412a3b86383f88c43e13b8217b63d4c8d90b9e798d rackup (2.2.1) sha256=f737191fd5c5b348b7f0a4412a3b86383f88c43e13b8217b63d4c8d90b9e798d
rails (8.0.2) sha256=fdfaa5a83ec0388e02864e88d515959caedc88053b5f701c4deb1652d8f164c6 rails (8.0.2.1) sha256=13ab95615569e74e364384b346b1d83e4795dbde83d9edf584e8768e8049b3ac
rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d
rails-html-sanitizer (1.6.2) sha256=35fce2ca8242da8775c83b6ba9c1bcaad6751d9eb73c1abaa8403475ab89a560 rails-html-sanitizer (1.6.2) sha256=35fce2ca8242da8775c83b6ba9c1bcaad6751d9eb73c1abaa8403475ab89a560
railties (8.0.2) sha256=0d7c3f40c49ba74980f1bac1d4bb153a9331c5ee8a9631d89c7bf79db82e5cf9 railties (8.0.2.1) sha256=54e40e1771fc2878f572d5a4e076cddb057ba8d4d471f8b7d9bfc61bc1301d4c
rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
rake (13.3.0) sha256=96f5092d786ff412c62fde76f793cc0541bd84d2eb579caa529aa8a059934493 rake (13.3.0) sha256=96f5092d786ff412c62fde76f793cc0541bd84d2eb579caa529aa8a059934493
rdoc (6.14.0) sha256=2c46de58d7129b8743fcf6d76e3db971bdc914150e15ac06b386549bd82ed7db rdoc (6.14.2) sha256=9fdd44df130f856ae70cc9a264dfd659b9b40de369b16581f4ab746e42439226
react-rails (3.2.1) sha256=2235db0b240517596b1cb3e26177ab5bc64d3a56579b0415ee242b1691f81f64 react-rails (3.2.1) sha256=2235db0b240517596b1cb3e26177ab5bc64d3a56579b0415ee242b1691f81f64
redis (5.4.0) sha256=798900d869418a9fc3977f916578375b45c38247a556b61d58cba6bb02f7d06b redis (5.4.1) sha256=b5e675b57ad22b15c9bcc765d5ac26f60b675408af916d31527af9bd5a81faae
redis-client (0.23.2) sha256=e33bab6682c8155cfef95e6dd296936bb9c2981a89fb578ace27a076fa2836fa redis-client (0.23.2) sha256=e33bab6682c8155cfef95e6dd296936bb9c2981a89fb578ace27a076fa2836fa
regexp_parser (2.10.0) sha256=cb6f0ddde88772cd64bff1dbbf68df66d376043fe2e66a9ef77fcb1b0c548c61 regexp_parser (2.11.3) sha256=ca13f381a173b7a93450e53459075c9b76a10433caadcb2f1180f2c741fc55a4
reline (0.6.1) sha256=1afcc9d7cb1029cdbe780d72f2f09251ce46d3780050f3ec39c3ccc6b60675fb reline (0.6.2) sha256=1dad26a6008872d59c8e05244b119347c9f2ddaf4a53dce97856cd5f30a02846
responders (3.1.1) sha256=92f2a87e09028347368639cfb468f5fefa745cb0dc2377ef060db1cdd79a341a responders (3.1.1) sha256=92f2a87e09028347368639cfb468f5fefa745cb0dc2377ef060db1cdd79a341a
rexml (3.3.9) sha256=d71875b85299f341edf47d44df0212e7658cbdf35aeb69cefdb63f57af3137c9 rexml (3.3.9) sha256=d71875b85299f341edf47d44df0212e7658cbdf35aeb69cefdb63f57af3137c9
rspec-core (3.13.4) sha256=f9da156b7b775c82610a7b580624df51a55102f8c8e4a103b98f5d7a9fa23958 rqrcode (3.1.0) sha256=e2d5996375f6e9a013823c289ed575dbea678b8e0388574302c1fac563f098af
rqrcode_core (2.0.0) sha256=1e40b823ab57a96482a417fff5dd5c33645a00cea6ef5d9e342fecc5ef91d9ab
rspec-core (3.13.5) sha256=ab3f682897c6131c67f9a17cfee5022a597f283aebe654d329a565f9937a4fa3
rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836 rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
rspec-mocks (3.13.5) sha256=e4338a6f285ada9fe56f5893f5457783af8194f5d08884d17a87321d5195ea81 rspec-mocks (3.13.5) sha256=e4338a6f285ada9fe56f5893f5457783af8194f5d08884d17a87321d5195ea81
rspec-rails (8.0.0) sha256=977a508cd94d152db2068c6585470db5d0cd47eef56d5410b9531034fb9d97bf rspec-rails (8.0.2) sha256=113139a53f5d068d4f48d1c29ad5f982013ed9b0daa69d7f7b266eda5d433ace
rspec-support (3.13.4) sha256=184b1814f6a968102b57df631892c7f1990a91c9a3b9e80ef892a0fc2a71a3f7 rspec-support (3.13.5) sha256=add745af535dd14b18f1209ab41ef987fdfad12786176b6a3b3619b9a7279fbf
rswag (2.16.0) sha256=f07ce41548b9bb51464c38bc7b95af22fee84b90f2d1197a515a623906353086 rswag (2.16.0) sha256=f07ce41548b9bb51464c38bc7b95af22fee84b90f2d1197a515a623906353086
rswag-api (2.16.0) sha256=b653f7bd92e98be18b01ab4525d88950d7b0960e293a99f856b9efcee3ae6074 rswag-api (2.16.0) sha256=b653f7bd92e98be18b01ab4525d88950d7b0960e293a99f856b9efcee3ae6074
rswag-specs (2.16.0) sha256=8ba26085c408b0bd2ed21dc8015c80f417c7d34c63720ab7133c2549b5bd2a91 rswag-specs (2.16.0) sha256=8ba26085c408b0bd2ed21dc8015c80f417c7d34c63720ab7133c2549b5bd2a91
rswag-ui (2.16.0) sha256=a1f49e927dceda92e6e6e7c1000f1e217ee66c565f69e28131dc98b33cd3a04f rswag-ui (2.16.0) sha256=a1f49e927dceda92e6e6e7c1000f1e217ee66c565f69e28131dc98b33cd3a04f
rubocop (1.76.1) sha256=e15a2d750794cf2157d2de8b1b403dfa71b8dc3957a22ae6043b1bdf21e7e0e7 rubocop (1.80.2) sha256=6485f30fefcf5c199db3b91e5e253b1ef43f7e564784e2315255809a3dd9abf4
rubocop-ast (1.45.1) sha256=94042e49adc17f187ba037b33f941ba7398fede77cdf4bffafba95190a473a3e rubocop-ast (1.46.0) sha256=0da7f6ad5b98614f89b74f11873c191059c823eae07d6ffd40a42a3338f2232b
rubocop-factory_bot (2.27.1) sha256=9d744b5916778c1848e5fe6777cc69855bd96548853554ec239ba9961b8573fe rubocop-factory_bot (2.27.1) sha256=9d744b5916778c1848e5fe6777cc69855bd96548853554ec239ba9961b8573fe
rubocop-rails (2.32.0) sha256=9fcc623c8722fe71e835e99c4a18b740b5b0d3fb69915d7f0777f00794b30490 rubocop-rails (2.33.3) sha256=848c011b58c1292f3066246c9eb18abf6ffcfbce28bc57c4ab888bbec79af74b
rubocop-rspec (3.6.0) sha256=c0e4205871776727e54dee9cc91af5fd74578001551ba40e1fe1a1ab4b404479 rubocop-rspec (3.6.0) sha256=c0e4205871776727e54dee9cc91af5fd74578001551ba40e1fe1a1ab4b404479
rubocop-rspec_rails (2.31.0) sha256=775375e18a26a1184a812ef3054b79d218e85601b9ae897f38f8be24dddf1f45 rubocop-rspec_rails (2.31.0) sha256=775375e18a26a1184a812ef3054b79d218e85601b9ae897f38f8be24dddf1f45
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33 ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
@ -611,12 +636,12 @@ CHECKSUMS
rubyzip (2.3.2) sha256=3f57e3935dc2255c414484fbf8d673b4909d8a6a57007ed754dde39342d2373f rubyzip (2.3.2) sha256=3f57e3935dc2255c414484fbf8d673b4909d8a6a57007ed754dde39342d2373f
securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1 securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
shoulda-matchers (6.5.0) sha256=ef6b572b2bed1ac4aba6ab2c5ff345a24b6d055a93a3d1c3bfc86d9d499e3f44 shoulda-matchers (6.5.0) sha256=ef6b572b2bed1ac4aba6ab2c5ff345a24b6d055a93a3d1c3bfc86d9d499e3f44
solid_queue (1.1.5) sha256=bae0c9d76310f4953ebc57466f2e8c78703a0fbf4b89d25756c23c88f9b6df9b solid_queue (1.2.1) sha256=7976b3690a08080ef63d1b11281f0b77398f7697dbeda0e2c5532682639d4b15
sprockets (4.2.1) sha256=951b13dd2f2fcae840a7184722689a803e0ff9d2702d902bd844b196da773f97 sprockets (4.2.1) sha256=951b13dd2f2fcae840a7184722689a803e0ff9d2702d902bd844b196da773f97
sprockets-rails (3.5.2) sha256=a9e88e6ce9f8c912d349aa5401509165ec42326baf9e942a85de4b76dbc4119e sprockets-rails (3.5.2) sha256=a9e88e6ce9f8c912d349aa5401509165ec42326baf9e942a85de4b76dbc4119e
stimulus-rails (1.3.4) sha256=765676ffa1f33af64ce026d26b48e8ffb2e0b94e0f50e9119e11d6107d67cb06 stimulus-rails (1.3.4) sha256=765676ffa1f33af64ce026d26b48e8ffb2e0b94e0f50e9119e11d6107d67cb06
stringio (3.1.7) sha256=5b78b7cb242a315fb4fca61a8255d62ec438f58da2b90be66048546ade4507fa stringio (3.1.7) sha256=5b78b7cb242a315fb4fca61a8255d62ec438f58da2b90be66048546ade4507fa
thor (1.3.2) sha256=eef0293b9e24158ccad7ab383ae83534b7ad4ed99c09f96f1a6b036550abbeda thor (1.4.0) sha256=8763e822ccb0f1d7bee88cde131b19a65606657b847cc7b7b4b82e772bcd8a3d
tilt (2.4.0) sha256=df74f29a451daed26591a85e8e0cebb198892cb75b6573394303acda273fba4d tilt (2.4.0) sha256=df74f29a451daed26591a85e8e0cebb198892cb75b6573394303acda273fba4d
timeout (0.4.3) sha256=9509f079b2b55fe4236d79633bd75e34c1c1e7e3fb4b56cb5fda61f80a0fe30e timeout (0.4.3) sha256=9509f079b2b55fe4236d79633bd75e34c1c1e7e3fb4b56cb5fda61f80a0fe30e
tomlrb (2.0.3) sha256=c2736acf24919f793334023a4ff396c0647d93fce702a73c9d348deaa815d4f7 tomlrb (2.0.3) sha256=c2736acf24919f793334023a4ff396c0647d93fce702a73c9d348deaa815d4f7
@ -629,12 +654,13 @@ CHECKSUMS
web-console (4.2.1) sha256=e7bcf37a10ea2b4ec4281649d1cee461b32232d0a447e82c786e6841fd22fe20 web-console (4.2.1) sha256=e7bcf37a10ea2b4ec4281649d1cee461b32232d0a447e82c786e6841fd22fe20
websocket-driver (0.7.7) sha256=056d99f2cd545712cfb1291650fde7478e4f2661dc1db6a0fa3b966231a146b4 websocket-driver (0.7.7) sha256=056d99f2cd545712cfb1291650fde7478e4f2661dc1db6a0fa3b966231a146b4
websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241 websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241
wicked_pdf (2.8.2) sha256=648d9b0cec5a34adbc9bbf809731052a78119e2d6d323b9e4aa1383e1d683824
with_env (1.1.0) sha256=50b3e4f0a6cda8f90d8a6bd87a6261f6c381429abafb161c4c69ad4a0cd0b6e4 with_env (1.1.0) sha256=50b3e4f0a6cda8f90d8a6bd87a6261f6c381429abafb161c4c69ad4a0cd0b6e4
xml-simple (1.1.9) sha256=d21131e519c86f1a5bc2b6d2d57d46e6998e47f18ed249b25cad86433dbd695d xml-simple (1.1.9) sha256=d21131e519c86f1a5bc2b6d2d57d46e6998e47f18ed249b25cad86433dbd695d
zeitwerk (2.7.3) sha256=b2e86b4a9b57d26ba68a15230dcc7fe6f040f06831ce64417b0621ad96ba3e85 zeitwerk (2.7.3) sha256=b2e86b4a9b57d26ba68a15230dcc7fe6f040f06831ce64417b0621ad96ba3e85
RUBY VERSION RUBY VERSION
ruby 3.4.2p28 ruby 3.4.3p32
BUNDLED WITH BUNDLED WITH
2.6.1 2.6.1

View File

@ -6,10 +6,13 @@ require 'csv'
class GuestsController < ApplicationController class GuestsController < ApplicationController
GUEST_PARAMS = { only: %i[id name status], include: { group: { only: %i[id name] } } }.freeze GUEST_PARAMS = { only: %i[id name status], include: { group: { only: %i[id name] } } }.freeze
skip_before_action :authenticate_user!, only: :update
def index def index
render json: Guest.includes(:group) render json: Guest.includes(:group)
.left_joins(:group) .left_joins(:group)
.order('groups.name' => :asc, name: :asc) .order('groups.name' => :asc, invitation_id: :asc, name: :asc)
.as_json(GUEST_PARAMS) .as_json(GUEST_PARAMS)
end end
@ -19,7 +22,13 @@ class GuestsController < ApplicationController
end end
def update def update
guest = Guest.find(params[:id]).update!(guest_params) guest = Guest.find(params[:id])
guest.update!(guest_params)
if !user_signed_in? && guest.saved_change_to_status?
AdminMailer.with(guest_id: guest.id).attendance_change_email.deliver_later
end
render json: guest.as_json(GUEST_PARAMS), status: :ok render json: guest.as_json(GUEST_PARAMS), status: :ok
end end
@ -31,6 +40,6 @@ class GuestsController < ApplicationController
private private
def guest_params def guest_params
params.expect(guest: %i[name group_id status]) user_signed_in? ? params.expect(guest: %i[name group_id status]) : params.expect(guest: %i[status])
end end
end end

View File

@ -2,19 +2,47 @@
# frozen_string_literal: true # frozen_string_literal: true
# Copyright (C) 2024-2025 LibreWeddingPlanner contributors
class InvitationsController < ApplicationController class InvitationsController < ApplicationController
skip_before_action :authenticate_user!, only: :show
def index def index
render json: Invitation.includes(:guests).as_json( @invitations = Invitation.includes(:guests).all
respond_to do |format|
format.json do
render json: @invitations.as_json(
only: :id, only: :id,
include: { include: { guests: { only: %i[id name] } }
guests: {
only: %i[id name]
}
}
) )
end end
format.pdf do
pdf_html = ActionController::Base.new.render_to_string(
template: 'invitations/sheet',
layout: 'pdf',
locals: { invitations: @invitations }
)
pdf = WickedPdf.new.pdf_from_string(pdf_html)
send_data pdf, filename: "invitations_#{Time.current.strftime('%Y%m%d_%H%M%S')}.pdf"
end
end
end
def email
AdminMailer.with(wedding_id: ActsAsTenant.current_tenant.id).invitations_pdf_email.deliver_later
head :ok
end
def sheet; end
def show
invitation = Invitation.includes(:guests).find(params[:id])
if invitation
render json: invitation, only: :id, include: { guests: { only: %i[id name status] } }, status: :ok
else
render json: { error: 'Invitation not found' }, status: :not_found
end
end
def create def create
invitation = Invitation.create invitation = Invitation.create

View File

@ -9,10 +9,10 @@ class TablesArrangementsController < ApplicationController
render json: TablesArrangement render json: TablesArrangement
.order(valid: :desc) .order(valid: :desc)
.order(discomfort: :asc) .order(discomfort: :asc)
.select(:id, :name, :discomfort) .select(:id, :name, :discomfort, :status, :progress)
.select("digest = '#{current_digest}'::uuid as valid") .select("digest = '#{current_digest}'::uuid OR discomfort IS NULL as valid")
.limit(20) .limit(20)
.as_json(only: %i[id name discomfort valid]) .as_json(only: %i[id name discomfort valid status progress])
end end
def show def show
@ -25,7 +25,10 @@ class TablesArrangementsController < ApplicationController
end end
def create def create
TableSimulatorJob.perform_later(current_tenant.id) ActiveRecord::Base.transaction do
tables_arrangement = TablesArrangement.create!(status: :not_started)
TableSimulatorJob.perform_later(current_tenant.id, tables_arrangement.id)
end
render json: {}, status: :created render json: {}, status: :created
end end

View File

@ -8,16 +8,35 @@ class TableSimulatorJob < ApplicationJob
MIN_PER_TABLE = 8 MIN_PER_TABLE = 8
MAX_PER_TABLE = 10 MAX_PER_TABLE = 10
def perform(wedding_id) def perform(wedding_id, tables_arrangement_id) # rubocop:disable Metrics/MethodLength
Rails.logger.info "Starting table simulation #{tables_arrangement_id} for wedding #{wedding_id}"
ActsAsTenant.with_tenant(Wedding.find(wedding_id)) do ActsAsTenant.with_tenant(Wedding.find(wedding_id)) do
engine = VNS::Engine.new engine = VNS::Engine.new
engine.add_perturbation(Tables::Swap) engine.add_optimization(Tables::Swap)
engine.add_perturbation(Tables::Shift) engine.add_optimization(Tables::Shift)
tables_arrangement = TablesArrangement.find(tables_arrangement_id)
initial_solution = Tables::Distribution.new(
min_per_table: MIN_PER_TABLE,
max_per_table: MAX_PER_TABLE,
tables_arrangement_id:
)
initial_solution = Tables::Distribution.new(min_per_table: MIN_PER_TABLE, max_per_table: MAX_PER_TABLE)
initial_solution.random_distribution(Guest.potential.shuffle) initial_solution.random_distribution(Guest.potential.shuffle)
initial_solution.save!
engine.notify_progress do |current_progress|
tables_arrangement.update_columns(status: :in_progress, progress: current_progress)
end
engine.on_better_solution do |better_solution|
better_solution.save!
tables_arrangement.update_columns(discomfort: better_solution.discomfort) # TODO: remove?
end
engine.initial_solution = initial_solution engine.initial_solution = initial_solution
engine.target_function(&:discomfort) engine.target_function(&:discomfort)
@ -25,6 +44,8 @@ class TableSimulatorJob < ApplicationJob
best_solution = engine.run best_solution = engine.run
best_solution.save! best_solution.save!
tables_arrangement.update_columns(status: :completed)
end end
end end
end end

View File

@ -0,0 +1,45 @@
# Copyright (C) 2024-2025 LibreWeddingPlanner contributors
# frozen_string_literal: true
class AdminMailer < ApplicationMailer
def attendance_change_email
@guest = Guest.find(params[:guest_id])
ActsAsTenant.with_tenant(@guest.wedding) do
mail(
to: recipients,
subject: I18n.t(
'admin_mailer.attendance_change_email.subject',
name: @guest.name,
status: I18n.t("active_record.attributes.guest/status.#{@guest.status}")
)
)
end
end
def invitations_pdf_email
ActsAsTenant.with_tenant(Wedding.find(params[:wedding_id])) do
invitations = Invitation.includes(:guests).all
pdf_html = ActionController::Base.new.render_to_string(
template: 'invitations/sheet',
layout: 'pdf',
locals: { invitations: }
)
pdf = WickedPdf.new.pdf_from_string(pdf_html)
attachments["invitations_#{Time.current.strftime('%Y%m%d_%H%M%S')}.pdf"] = pdf
mail(
to: recipients,
subject: I18n.t('admin_mailer.invitations_pdf_email.subject')
)
end
end
private
def recipients
ActsAsTenant.current_tenant.users.pluck(:email)
end
end

View File

@ -3,6 +3,16 @@
# frozen_string_literal: true # frozen_string_literal: true
class ApplicationMailer < ActionMailer::Base class ApplicationMailer < ActionMailer::Base
default from: 'from@example.com' class << self
private
def default_from
File.read('/run/secrets/smtp_user_name').strip
rescue Errno::ENOENT
'development@example.com'
end
end
default from: default_from
layout 'mailer' layout 'mailer'
end end

View File

@ -22,4 +22,8 @@
class Invitation < ApplicationRecord class Invitation < ApplicationRecord
acts_as_tenant :wedding acts_as_tenant :wedding
has_many :guests, dependent: :nullify has_many :guests, dependent: :nullify
def url
"#{Rails.application.routes.url_helpers.root_url(slug: ActsAsTenant.current_tenant.slug)}/site/invitation/#{id}"
end
end end

View File

@ -29,5 +29,5 @@
class Seat < ApplicationRecord class Seat < ApplicationRecord
acts_as_tenant :wedding acts_as_tenant :wedding
belongs_to :guest belongs_to :guest
belongs_to :table_arrangement belongs_to :tables_arrangement
end end

View File

@ -10,6 +10,8 @@
# digest :uuid not null # digest :uuid not null
# discomfort :integer # discomfort :integer
# name :string not null # name :string not null
# progress :float default(0.0), not null
# status :string default("complete"), not null
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# wedding_id :uuid not null # wedding_id :uuid not null

View File

@ -23,5 +23,6 @@ class Wedding < ApplicationRecord
has_many :guests, dependent: :delete_all has_many :guests, dependent: :delete_all
has_many :groups, dependent: :delete_all has_many :groups, dependent: :delete_all
has_many :invitations, dependent: :delete_all has_many :invitations, dependent: :delete_all
has_many :users, dependent: :delete_all
has_one :website, dependent: :destroy has_one :website, dependent: :destroy
end end

View File

@ -16,6 +16,7 @@ class AffinityGroupsHierarchy < Array
end end
discomforts discomforts
invitation_counts
freeze freeze
end end
@ -54,8 +55,16 @@ class AffinityGroupsHierarchy < Array
Rational(dist, dist + 1) Rational(dist, dist + 1)
end end
def guest_count(invitation_id)
@invitation_counts[invitation_id] || 0
end
private private
def invitation_counts
@invitation_counts = Guest.where.not(invitation_id: nil).group(:invitation_id).count
end
def discomforts def discomforts
@discomforts ||= GroupAffinity.pluck(:group_a_id, :group_b_id, @discomforts ||= GroupAffinity.pluck(:group_a_id, :group_b_id,
:discomfort).each_with_object({}) do |(id_a, id_b, discomfort), acc| :discomfort).each_with_object({}) do |(id_a, id_b, discomfort), acc|

View File

@ -15,7 +15,7 @@ module Tables
end end
def breakdown def breakdown
@breakdown ||= { table_size_penalty:, cohesion_penalty: } @breakdown ||= { table_size_penalty:, cohesion_penalty:, invitations_penalty: }
end end
private private
@ -39,6 +39,12 @@ module Tables
10 * (cohesion_discomfort * 1.0 / table.size) 10 * (cohesion_discomfort * 1.0 / table.size)
end end
def invitations_penalty
2 * table.map(&:invitation_id)
.tally
.sum { |invitation_id, guests_in_table| hierarchy.guest_count(invitation_id) - guests_in_table }
end
# #
# Calculates the discomfort of the table based on the cohesion of the guests. The total discomfort # Calculates the discomfort of the table based on the cohesion of the guests. The total discomfort
# is calculated as the sum of the discomfort of each pair of guests. The discomfort of a pair of # is calculated as the sum of the discomfort of each pair of guests. The discomfort of a pair of

View File

@ -12,19 +12,21 @@ module Tables
end end
end end
attr_accessor :tables, :min_per_table, :max_per_table, :hierarchy attr_accessor :tables, :min_per_table, :max_per_table, :hierarchy, :tables_arrangement_id
def initialize(min_per_table:, max_per_table:) def initialize(min_per_table:, max_per_table:, tables_arrangement_id:, hierarchy: AffinityGroupsHierarchy.new)
@min_per_table = min_per_table @min_per_table = min_per_table
@max_per_table = max_per_table @max_per_table = max_per_table
@hierarchy = AffinityGroupsHierarchy.new @hierarchy = hierarchy
@tables = [] @tables = []
@tables_arrangement_id = tables_arrangement_id
end end
def random_distribution(people) def random_distribution(people, random: Random.new)
min_tables = (people.count * 1.0 / @max_per_table).ceil min_tables = (people.count * 1.0 / @max_per_table).ceil
max_tables = (people.count * 1.0 / @min_per_table).ceil max_tables = (people.count * 1.0 / @min_per_table).ceil
@tables = people.in_groups(rand(min_tables..max_tables), false) table_size = random.rand(min_tables..max_tables)
@tables = people.in_groups(table_size, false)
.map { |group| Table.new(group) } .map { |group| Table.new(group) }
.each { |table| table.min_per_table = @min_per_table } .each { |table| table.min_per_table = @min_per_table }
.each { |table| table.max_per_table = @max_per_table } .each { |table| table.max_per_table = @max_per_table }
@ -41,14 +43,23 @@ module Tables
end end
def deep_dup def deep_dup
self.class.new(min_per_table: @min_per_table, max_per_table: @max_per_table).tap do |new_distribution| self.class.new(
min_per_table: @min_per_table,
max_per_table: @max_per_table,
hierarchy: @hierarchy,
tables_arrangement_id: @tables_arrangement_id
).tap do |new_distribution|
new_distribution.tables = @tables.map(&:dup) new_distribution.tables = @tables.map(&:dup)
end end
end end
def save! def save!
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
arrangement = TablesArrangement.create! arrangement = TablesArrangement.find(tables_arrangement_id)
self.tables_arrangement_id = arrangement.id
arrangement.seats.delete_all
records_to_store = [] records_to_store = []

View File

@ -0,0 +1,33 @@
# Copyright (C) 2024-2025 LibreWeddingPlanner contributors
# frozen_string_literal: true
module Tables
class WheelSwap
private attr_reader :initial_solution
def initialize(initial_solution)
@initial_solution = initial_solution
end
def call(size = 1)
Rails.logger.debug { "WheelSwap with size: #{size}" }
new_solution = @initial_solution.deep_dup
selected_guests = []
size.times do
selected_guests += new_solution.tables.map(&:pop)
end
selected_guests.shuffle!
tables = new_solution.tables.cycle
tables.next << selected_guests.pop while selected_guests.any?
new_solution.tables.each(&:reset)
new_solution
end
end
end

View File

@ -4,6 +4,8 @@
module VNS module VNS
class Engine class Engine
PERTURBATION_SIZES = [1, 1, 1, 2, 2, 3].freeze
ITERATIONS = 50
class << self class << self
def sequence(elements) def sequence(elements)
elements = elements.to_a elements = elements.to_a
@ -11,45 +13,95 @@ module VNS
end end
end end
def initialize
@perturbations = Set.new
end
def target_function(&function) def target_function(&function)
@target_function = function @target_function = function
end end
def add_optimization(klass)
@optimizations ||= Set.new
@optimizations << klass
end
def add_perturbation(klass) def add_perturbation(klass)
@perturbations ||= Set.new
@perturbations << klass @perturbations << klass
end end
def notify_progress(&block)
@progress_notifier = block
end
def on_better_solution(&block)
@better_solution_notifier = block
end
attr_writer :initial_solution attr_writer :initial_solution
def run def run
raise 'No target function defined' unless @target_function check_preconditions!
raise 'No perturbations defined' unless @perturbations
raise 'No initial solution defined' unless @initial_solution
@best_solution = @initial_solution @current_solution = @initial_solution
@best_score = @target_function.call(@best_solution) @best_score = @target_function.call(@current_solution)
self.class.sequence(@perturbations).each do |perturbation| run_all_optimizations
optimize(perturbation)
@progress_notifier&.call(Rational(1, ITERATIONS + 1))
best_solution = @current_solution
(1..ITERATIONS).each do |iteration|
@current_solution = Tables::WheelSwap.new(best_solution).call(PERTURBATION_SIZES.sample)
@best_score = @target_function.call(@current_solution)
Rails.logger.debug { "After perturbation: #{@best_score}" }
run_all_optimizations
@progress_notifier&.call(Rational(iteration + 1, ITERATIONS + 1))
next unless best_solution.discomfort > @current_solution.discomfort
best_solution = @current_solution
@better_solution_notifier&.call(best_solution)
Rails.logger.debug do
"Found better solution after perturbation optimization: #{@current_solution.discomfort}"
end
end end
@best_solution best_solution
end end
private private
def optimize(perturbation_klass) def check_preconditions!
raise 'No target function defined' unless @target_function
raise 'No optimizations defined' unless @optimizations
raise 'No initial solution defined' unless @initial_solution
end
def run_all_optimizations
self.class.sequence(@optimizations).each do |optimization|
optimize(optimization)
Rails.logger.debug { "Finished optimization phase: #{optimization}" }
end
Rails.logger.debug { 'Finished all optimization phases' }
end
def optimize(optimization_klass)
loop do loop do
optimized = false optimized = false
perturbation_klass.new(@best_solution).each do |alternative_solution| optimization_klass.new(@current_solution).each do |alternative_solution|
score = @target_function.call(alternative_solution) score = @target_function.call(alternative_solution)
next if score >= @best_score next if score >= @best_score
@best_solution = alternative_solution.deep_dup @current_solution = alternative_solution.deep_dup
@best_score = score @best_score = score
optimized = true optimized = true
Rails.logger.debug { "[#{optimization_klass}] Found better solution with score: #{score}" }
break break
end end

View File

@ -0,0 +1,17 @@
<%# Copyright (C) 2024-2025 LibreWeddingPlanner contributors %>
<p><%= I18n.t('admin_mailer.greeting') %>,</p>
<p>
<%= I18n.t('admin_mailer.attendance_change_email.paragraph_1', name: @guest.name) %>
</p>
<ul>
<li>
<strong><%= I18n.t("active_record.attributes.guest.status") %>:</strong> <%= I18n.t("active_record.attributes.guest/status.#{@guest.status}") %>
</li>
</ul>
<p>
<%= I18n.t("admin_mailer.attendance_change_email.notify_on_updates") %>
</p>

View File

@ -0,0 +1,9 @@
<%# Copyright (C) 2024-2025 LibreWeddingPlanner contributors %>
<%= I18n.t('admin_mailer.greeting') %>,
<%= I18n.t('admin_mailer.attendance_change_email.paragraph_1', name: @guest.name) %>
- <%= I18n.t("active_record.attributes.guest.status") %>: <%= I18n.t("active_record.attributes.guest/status.#{@guest.status}") %>
<%= I18n.t("admin_mailer.attendance_change_email.notify_on_updates") %>

View File

@ -0,0 +1,7 @@
<%# Copyright (C) 2024-2025 LibreWeddingPlanner contributors %>
<p><%= I18n.t('admin_mailer.greeting') %>,</p>
<p>
<%= I18n.t('admin_mailer.invitations_pdf_email.paragraph_1') %>
</p>

View File

@ -0,0 +1,5 @@
<%# Copyright (C) 2024-2025 LibreWeddingPlanner contributors %>
<%= I18n.t('admin_mailer.greeting') %>,
<%= I18n.t('admin_mailer.invitations_pdf_email.paragraph_1') %>

View File

@ -0,0 +1,33 @@
<%# Copyright (C) 2024-2025 LibreWeddingPlanner contributors %>
<% invitations.each_slice(4) do |invitation_group| %>
<table style="width: 100%; border-collapse: separate; border-spacing: 0 20px; margin-bottom: 40px;">
<% invitation_group.each do |invitation| %>
<tr>
<td style="width: 270px; height: 270px; text-align: center; vertical-align: middle; padding: 10px;">
<%= image_tag(RQRCode::QRCode.new(invitation.url).as_png(
bit_depth: 1,
border_modules: 4,
color_mode: ChunkyPNG::COLOR_GRAYSCALE,
color: "black",
file: nil,
fill: "white",
module_px_size: 6,
resize_exactly_to: false,
resize_gte_to: false,
size: 250
).to_data_url)
%>
</td>
<td style="vertical-align: middle; padding: 10px;">
<ul style="margin: 0; padding-left: 20px;">
<% invitation.guests.each do |guest| %>
<%= content_tag(:li, guest.name) %>
<% end %>
</ul>
</td>
</tr>
<% end %>
</table>
<div style="page-break-after: always;"></div>
<% end %>

View File

@ -0,0 +1,12 @@
<%# Copyright (C) 2024-2025 LibreWeddingPlanner contributors %>
<!doctype html>
<html>
<head>
<meta charset='utf-8' />
</head>
<div id="content">
<%= yield %>
</div>
</body>
</html>

View File

@ -3,4 +3,5 @@
require_relative "../config/environment" require_relative "../config/environment"
require "solid_queue/cli" require "solid_queue/cli"
SolidQueue.logger = ActiveSupport::Logger.new($stdout)
SolidQueue::Cli.start(ARGV) SolidQueue::Cli.start(ARGV)

View File

@ -79,4 +79,5 @@ Rails.application.configure do
config.action_controller.raise_on_missing_callback_actions = true config.action_controller.raise_on_missing_callback_actions = true
config.hosts << "libre-wedding-planner.app.localhost" config.hosts << "libre-wedding-planner.app.localhost"
Rails.application.routes.default_url_options[:host] = "libre-wedding-planner.app.localhost"
end end

View File

@ -72,6 +72,20 @@ Rails.application.configure do
# config.active_job.queue_name_prefix = "wedding_planner_production" # config.active_job.queue_name_prefix = "wedding_planner_production"
config.action_mailer.perform_caching = false config.action_mailer.perform_caching = false
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = begin
{
address: File.read("/run/secrets/smtp_address").strip,
port: File.read("/run/secrets/smtp_port").strip.to_i,
user_name: File.read("/run/secrets/smtp_user_name").strip,
password: File.read("/run/secrets/smtp_password").strip,
authentication: File.read("/run/secrets/smtp_authentication").strip.to_sym,
tls: true
}
rescue Errno::ENOENT
{}
end
# Ignore bad email addresses and do not raise email delivery errors. # Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors.
@ -94,6 +108,7 @@ Rails.application.configure do
# ] # ]
config.hosts << "app.libreweddingplanner.org" config.hosts << "app.libreweddingplanner.org"
Rails.application.routes.default_url_options[:host] = "app.libreweddingplanner.org"
# Skip DNS rebinding protection for the default health check endpoint. # Skip DNS rebinding protection for the default health check endpoint.
config.host_authorization = { exclude: ->(request) { request.path == "/up" } } config.host_authorization = { exclude: ->(request) { request.path == "/up" } }

View File

@ -10,7 +10,7 @@ Rswag::Ui.configure do |c|
# (under openapi_root) as JSON or YAML endpoints, then the list below should # (under openapi_root) as JSON or YAML endpoints, then the list below should
# correspond to the relative paths for those endpoints. # correspond to the relative paths for those endpoints.
c.swagger_endpoint '/api/api-docs/v1/swagger.yaml', 'API V1 Docs' c.openapi_endpoint '/api/api-docs/v1/swagger.yaml', 'API V1 Docs'
# Add Basic Auth in case your API is private # Add Basic Auth in case your API is private
# c.basic_auth_enabled = true # c.basic_auth_enabled = true

View File

@ -10,4 +10,10 @@ class Set
def to_table def to_table
Tables::Table.new(self) Tables::Table.new(self)
end end
def pop
element = self.to_a.sample
self.delete(element)
element
end
end end

View File

@ -0,0 +1,32 @@
# Copyright (C) 2024-2025 LibreWeddingPlanner contributors
# WickedPDF Global Configuration
#
# Use this to set up shared configuration options for your entire application.
# Any of the configuration options shown here can also be applied to single
# models by passing arguments to the `render :pdf` call.
#
# To learn more, check out the README:
#
# https://github.com/mileszs/wicked_pdf/blob/master/README.md
WickedPdf.configure do |config|
# Path to the wkhtmltopdf executable: This usually isn't needed if using
# one of the wkhtmltopdf-binary family of gems.
# config.exe_path = '/usr/local/bin/wkhtmltopdf'
# or
# config.exe_path = Gem.bin_path('wkhtmltopdf-binary', 'wkhtmltopdf')
# Needed for wkhtmltopdf 0.12.6+ to use many wicked_pdf asset helpers
# config.enable_local_file_access = true
# Layout file to be used for all PDFs
# (but can be overridden in `render :pdf` calls)
# config.layout = 'pdf.html'
# Using wkhtmltopdf without an X server can be achieved by enabling the
# 'use_xvfb' flag. This will wrap all wkhtmltopdf commands around the
# 'xvfb-run' command, in order to simulate an X server.
#
# config.use_xvfb = true
end

View File

@ -1,31 +1,22 @@
# Files in the config/locales directory are used for internationalization and
# are automatically loaded by Rails. If you want to use locales other than
# English, add the necessary files in this directory.
#
# To use the locales, use `I18n.t`:
#
# I18n.t "hello"
#
# In views, this is aliased to just `t`:
#
# <%= t("hello") %>
#
# To use a different locale, set it with `I18n.locale`:
#
# I18n.locale = :es
#
# This would use the information in config/locales/es.yml.
#
# To learn more about the API, please read the Rails Internationalization guide
# at https://guides.rubyonrails.org/i18n.html.
#
# Be aware that YAML interprets the following case-insensitive strings as
# booleans: `true`, `false`, `on`, `off`, `yes`, `no`. Therefore, these strings
# must be quoted to be interpreted as strings. For example:
#
# en:
# "yes": yup
# enabled: "ON"
en: en:
hello: "Hello world" hello: "Hello world"
active_record:
attributes:
guest:
status: Status
guest/status:
considered: Considered
invited: Invited
confirmed: Confirmed
declined: Declined
tentative: Tentative
admin_mailer:
greeting: "Dear user"
attendance_change_email:
subject: "%{name} has changed their attendance status: %{status}"
paragraph_1: "The guest %{name} has changed their attendance for the wedding."
notify_on_updates: "You will be notified of any further changes to their attendance status."
invitations_pdf_email:
subject: "Your wedding invitations are ready"
paragraph_1: "Your wedding invitations are ready. Please, find them attached to this email."

View File

@ -42,7 +42,9 @@ Rails.application.routes.draw do
resources :tables_arrangements, only: %i[index show create] resources :tables_arrangements, only: %i[index show create]
resources :summary, only: :index resources :summary, only: :index
resources :invitations, only: %i[index create update destroy] resources :invitations, only: %i[show index create update destroy] do
post :email, on: :collection
end
root to: redirect("/%{slug}") root to: redirect("/%{slug}")
end end

View File

@ -0,0 +1,5 @@
class AddStatusColumnToTablesArrangements < ActiveRecord::Migration[8.0]
def change
add_column :tables_arrangements, :status, :string, default: :complete, null: false
end
end

View File

@ -0,0 +1,5 @@
class AddProgressToTablesArrangements < ActiveRecord::Migration[8.0]
def change
add_column :tables_arrangements, :progress, :float, default: 0, null: false
end
end

4
db/schema.rb generated
View File

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.0].define(version: 2025_06_08_181054) do ActiveRecord::Schema[8.0].define(version: 2025_09_08_145119) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "pg_catalog.plpgsql" enable_extension "pg_catalog.plpgsql"
@ -216,6 +216,8 @@ ActiveRecord::Schema[8.0].define(version: 2025_06_08_181054) do
t.string "name", null: false t.string "name", null: false
t.uuid "wedding_id", null: false t.uuid "wedding_id", null: false
t.uuid "digest", default: -> { "gen_random_uuid()" }, null: false t.uuid "digest", default: -> { "gen_random_uuid()" }, null: false
t.string "status", default: "complete", null: false
t.float "progress", default: 0.0, null: false
t.index ["wedding_id"], name: "index_tables_arrangements_on_wedding_id" t.index ["wedding_id"], name: "index_tables_arrangements_on_wedding_id"
end end

View File

@ -86,7 +86,9 @@ ActsAsTenant.with_tenant(wedding) do
# TODO: Clean up invitations with no guests # TODO: Clean up invitations with no guests
ActiveJob.perform_all_later(3.times.map { TableSimulatorJob.new(wedding.id) }) 3.times { TablesArrangement.create! }
.map { |arrangement| TableSimulatorJob.new(wedding.id, arrangement.id) }
.then { |jobs| ActiveJob.perform_all_later }
"red".dup.paint.palette.triad(as: :hex).zip(Group.roots).each { |(color, group)| group.update!(color: color.paint.desaturate(40)) } "red".dup.paint.palette.triad(as: :hex).zip(Group.roots).each { |(color, group)| group.update!(color: color.paint.desaturate(40)) }

37
lib/tasks/vns.rake Normal file
View File

@ -0,0 +1,37 @@
# frozen_string_literal: true
namespace :vns do
desc 'Benchmarks the efficiency of the VNS implementation'
task benchmark: :environment do
ActsAsTenant.with_tenant(Wedding.first) do
Rails.logger.info "There are #{Guest.potential.count} potential guests"
engine = VNS::Engine.new
engine.add_optimization(Tables::Swap)
engine.add_optimization(Tables::Shift)
hierarchy = AffinityGroupsHierarchy.new
initial_solution = Tables::Distribution.new(min_per_table: 8, max_per_table: 10, hierarchy:)
random = Random.new(561_163)
initial_solution.random_distribution(Guest.potential.shuffle(random:), random:)
engine.initial_solution = initial_solution
engine.target_function(&:discomfort)
engine.notify_progress do |current_progress|
Rails.logger.info "Progress: #{(current_progress * 100.0).round(2)}%"
end
engine.on_better_solution do |better_solution|
Rails.logger.info "New best solution found with discomfort: #{better_solution.discomfort}"
end
solution = Rails.benchmark('VNS Benchmarking') { engine.run }
Rails.logger.info "Best solution found with discomfort: #{solution.discomfort}"
end
end
end

View File

@ -12,6 +12,11 @@ server {
proxy_set_header Host $http_host; proxy_set_header Host $http_host;
} }
location /jobs/ {
proxy_pass http://backend:3000/jobs/;
proxy_set_header Host $http_host;
}
location /captcha/v2/media/ { location /captcha/v2/media/ {
proxy_pass http://libre-captcha:8888/v2/media/; proxy_pass http://libre-captcha:8888/v2/media/;
proxy_set_header Host $http_host; proxy_set_header Host $http_host;

View File

@ -19,7 +19,8 @@ RSpec.describe 'tables_arrangements' do
id: { type: :string, format: :uuid }, id: { type: :string, format: :uuid },
name: { type: :string }, name: { type: :string },
discomfort: { type: :integer }, discomfort: { type: :integer },
valid: { type: :boolean } valid: { type: :boolean },
status: { type: :string, enum: %w[complete in_progress] }
} }
} }
xit xit

View File

@ -14,14 +14,14 @@ module Tables
describe '#calculate' do describe '#calculate' do
before do before do
allow(calculator).to receive_messages(table_size_penalty: 2, cohesion_discomfort: 3) allow(calculator).to receive_messages(table_size_penalty: 2, cohesion_penalty: 5, invitations_penalty: 4)
end end
let(:table) { Table.new(create_list(:guest, 6)) } let(:table) { Table.new(create_list(:guest, 6)) }
it 'returns the sum of the table size penalty and the average cohesion penalty', :aggregate_failures do it 'returns the sum of the table size penalty and the average cohesion penalty', :aggregate_failures do
expect(calculator.calculate).to eq(7) expect(calculator.calculate).to eq(11)
expect(calculator.breakdown).to eq(table_size_penalty: 2, cohesion_penalty: 5) expect(calculator.breakdown).to eq(table_size_penalty: 2, cohesion_penalty: 5, invitations_penalty: 4)
end end
end end
@ -73,5 +73,102 @@ module Tables
it { expect(calculator.send(:table_size_penalty)).to eq(10) } it { expect(calculator.send(:table_size_penalty)).to eq(10) }
end end
end end
describe '#cohesion_penalty' do
let(:calculator) { described_class.new(table:, hierarchy:) }
let(:table) { Table.new(guests) }
context 'when all guests belong to the same group' do
let(:guests) { create_list(:guest, 6, group: family) }
let(:hierarchy) { instance_double(AffinityGroupsHierarchy, discomfort: 0) }
it 'returns 0 as cohesion penalty' do
expect(calculator.send(:cohesion_penalty)).to eq(0)
end
end
context 'when guests belong to two different groups with discomfort 1' do
let(:guests) do
create_list(:guest, 3, group: family) +
create_list(:guest, 3, group: friends)
end
let(:hierarchy) do
instance_double(AffinityGroupsHierarchy, discomfort: 1)
end
it 'calculates the correct cohesion penalty' do
# 3 from family, 3 from friends: 3*3*1 = 9 discomfort
expect(calculator.send(:cohesion_penalty)).to eq(10 * (9.0 / 6))
end
end
context 'when guests belong to three groups with different discomforts' do
let(:guests) do
create_list(:guest, 2, group: family) +
create_list(:guest, 2, group: friends) +
create_list(:guest, 2, group: work)
end
let(:hierarchy) do
instance_double(AffinityGroupsHierarchy)
end
before do
allow(hierarchy).to receive(:discomfort).with(family.id, friends.id).and_return(0.5)
allow(hierarchy).to receive(:discomfort).with(family.id, work.id).and_return(1)
allow(hierarchy).to receive(:discomfort).with(friends.id, work.id).and_return(0.2)
allow(hierarchy).to receive(:discomfort).with(friends.id, family.id).and_return(0.5)
allow(hierarchy).to receive(:discomfort).with(work.id, family.id).and_return(1)
allow(hierarchy).to receive(:discomfort).with(work.id, friends.id).and_return(0.2)
end
it 'calculates the correct cohesion penalty' do
# pairs: (family, friends): 2*2*0.5 = 2
# (family, work): 2*2*1 = 4
# (friends, work): 2*2*0.2 = 0.8
# total discomfort = 2 + 4 + 0.8 = 6.8
expect(calculator.send(:cohesion_penalty)).to eq(10 * (6.8 / 6))
end
end
end
describe '#invitations_penalty' do
let(:invitation_a) { create(:invitation) }
let(:invitation_b) { create(:invitation) }
let(:invitation_c) { create(:invitation) }
let(:table) do
create_list(:guest, 2, invitation: invitation_a) +
create_list(:guest, 3, invitation: invitation_b) +
create_list(:guest, 4, invitation: invitation_c)
end
context 'when the table contains all members of an invitation' do
it 'returns 0 as penalty' do
expect(calculator.send(:invitations_penalty)).to eq(0)
end
end
context 'when there is an additional guest of one of the invitations that is not included' do
before do
create(:guest, invitation: invitation_a)
end
it 'returns the penalty for the missing guest' do
expect(calculator.send(:invitations_penalty)).to eq(2)
end
end
context 'when there are multiple guests missing from different invitations' do
before do
create(:guest, invitation: invitation_b)
create(:guest, invitation: invitation_c)
end
it 'returns 2x # of guests left out as the total penalty for all missing guests' do
expect(calculator.send(:invitations_penalty)).to eq(4)
end
end
end
end end
end end

View File

@ -6,8 +6,43 @@ require 'rails_helper'
module Tables module Tables
RSpec.describe Distribution do RSpec.describe Distribution do
let(:tables_arrangement) { TablesArrangement.create! }
around do |example|
ActsAsTenant.with_tenant(create(:wedding)) do
example.run
end
end
describe '#save!' do
let(:people) { create_list(:guest, 2, status: :invited) }
let(:distribution) do
described_class.new(min_per_table: 5, max_per_table: 10, tables_arrangement_id: tables_arrangement.id)
.tap { |d| d.random_distribution(people) }
end
context 'when tables_arrangement_id is nil' do
it { expect { distribution.save! }.to change(TablesArrangement, :count).by(1) }
it { expect { distribution.save! }.to change(Seat, :count).by(2) }
end
context 'when tables_arrangement_id is set' do
before do
existing_arrangement = TablesArrangement.create!
existing_arrangement.seats.create!(guest: people.first, table_number: 1)
distribution.tables_arrangement_id = existing_arrangement.id
end
it { expect { distribution.save! }.not_to(change(TablesArrangement, :count)) }
it { expect { distribution.save! }.to change(Seat, :count).by(1) }
end
end
describe '#random_distribution' do describe '#random_distribution' do
subject(:distribution) { described_class.new(min_per_table: 5, max_per_table: 10) } subject(:distribution) do
described_class.new(min_per_table: 5, max_per_table: 10, tables_arrangement_id: tables_arrangement.id)
end
context 'when there are fewer people than the minimum per table' do context 'when there are fewer people than the minimum per table' do
it 'creates one table' do it 'creates one table' do

View File

@ -17,7 +17,7 @@ module Tables
context 'when there are two tables with two people each' do context 'when there are two tables with two people each' do
let(:initial_solution) do let(:initial_solution) do
Distribution.new(min_per_table: 2, max_per_table: 2).tap do |distribution| Distribution.new(min_per_table: 2, max_per_table: 2, tables_arrangement_id: nil).tap do |distribution|
distribution.tables << Set[:a, :b].to_table distribution.tables << Set[:a, :b].to_table
distribution.tables << Set[:c, :d].to_table distribution.tables << Set[:c, :d].to_table
end end
@ -35,7 +35,7 @@ module Tables
context 'when there are two tables with three people each' do context 'when there are two tables with three people each' do
let(:initial_solution) do let(:initial_solution) do
Distribution.new(min_per_table: 3, max_per_table: 3).tap do |distribution| Distribution.new(min_per_table: 3, max_per_table: 3, tables_arrangement_id: nil).tap do |distribution|
distribution.tables << Set[:a, :b, :c].to_table distribution.tables << Set[:a, :b, :c].to_table
distribution.tables << Set[:d, :e, :f].to_table distribution.tables << Set[:d, :e, :f].to_table
end end

View File

@ -17,7 +17,7 @@ module Tables
context 'when there are two tables with two people each' do context 'when there are two tables with two people each' do
let(:initial_solution) do let(:initial_solution) do
Distribution.new(min_per_table: 2, max_per_table: 2).tap do |distribution| Distribution.new(min_per_table: 2, max_per_table: 2, tables_arrangement_id: nil).tap do |distribution|
distribution.tables << Set[:a, :b].to_table distribution.tables << Set[:a, :b].to_table
distribution.tables << Set[:c, :d].to_table distribution.tables << Set[:c, :d].to_table
end end
@ -35,7 +35,7 @@ module Tables
context 'when there are two tables with three people each' do context 'when there are two tables with three people each' do
let(:initial_solution) do let(:initial_solution) do
Distribution.new(min_per_table: 3, max_per_table: 3).tap do |distribution| Distribution.new(min_per_table: 3, max_per_table: 3, tables_arrangement_id: nil).tap do |distribution|
distribution.tables << Set[:a, :b, :c].to_table distribution.tables << Set[:a, :b, :c].to_table
distribution.tables << Set[:d, :e, :f].to_table distribution.tables << Set[:d, :e, :f].to_table
end end
@ -58,7 +58,7 @@ module Tables
context 'when there are three tables with two people each' do context 'when there are three tables with two people each' do
let(:initial_solution) do let(:initial_solution) do
Distribution.new(min_per_table: 2, max_per_table: 2).tap do |distribution| Distribution.new(min_per_table: 2, max_per_table: 2, tables_arrangement_id: nil).tap do |distribution|
distribution.tables << Set[:a, :b].to_table distribution.tables << Set[:a, :b].to_table
distribution.tables << Set[:c, :d].to_table distribution.tables << Set[:c, :d].to_table
distribution.tables << Set[:e, :f].to_table distribution.tables << Set[:e, :f].to_table

View File

@ -0,0 +1,28 @@
# Copyright (C) 2024-2025 LibreWeddingPlanner contributors
# frozen_string_literal: true
require 'rails_helper'
module Tables
RSpec.describe WheelSwap do
context 'when the solution has three tables' do
let(:initial_solution) do
Distribution.new(min_per_table: 3, max_per_table: 3, tables_arrangement_id: nil).tap do |distribution|
distribution.tables << Set[:a, :b, :c].to_table
distribution.tables << Set[:d, :e, :f].to_table
distribution.tables << Set[:g, :h, :i].to_table
end
end
it 'swaps a random guest from each table with a guest from another table', :aggregate_failures do
result = described_class.new(initial_solution).call
expect(result.tables.size).to eq(3)
expect(result.tables.map(&:size)).to all(eq(3))
expect(result.tables.map(&:to_a).flatten).to match_array((:a..:i).to_a)
end
end
end
end