Compare commits

...

166 Commits

Author SHA1 Message Date
Renovate Bot
5ac9506cb3 Update dependency rubocop to v1.69.0
Some checks failed
Check usage of free licenses / check-licenses (pull_request) Failing after 3m6s
Add copyright notice / copyright_notice (pull_request) Successful in 4m26s
Run unit tests / unit_tests (pull_request) Failing after 6m4s
2024-11-27 01:08:08 +00:00
515d841c11 Merge pull request 'Update dependency factory_bot_rails to v6.4.4' (#143) from renovate/factory_bot_rails-6.x-lockfile into main
Some checks failed
Run unit tests / unit_tests (push) Successful in 9m33s
Check usage of free licenses / check-licenses (push) Successful in 42s
Build Nginx-based docker image / build-static-assets (push) Failing after 20m28s
Reviewed-on: #143
2024-11-26 06:26:17 +00:00
Renovate Bot
d2eaa21df2 Update dependency factory_bot_rails to v6.4.4
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 2m53s
Check usage of free licenses / check-licenses (pull_request) Successful in 3m19s
Run unit tests / unit_tests (pull_request) Successful in 10m45s
2024-11-25 01:08:54 +00:00
Renovate Bot
3bde27ddce Update dependency puma to v6.5.0
Some checks failed
Check usage of free licenses / check-licenses (pull_request) Successful in 2m43s
Add copyright notice / copyright_notice (pull_request) Successful in 7m55s
Run unit tests / unit_tests (pull_request) Successful in 13m21s
Check usage of free licenses / check-licenses (push) Successful in 8m7s
Build Nginx-based docker image / build-static-assets (push) Failing after 1h32m32s
Run unit tests / unit_tests (push) Failing after 3h10m32s
2024-11-24 01:05:23 +00:00
300524956b Merge pull request 'Refine guest controller' (#140) from refine-guest-controller into main
Some checks failed
Check usage of free licenses / check-licenses (push) Successful in 1m57s
Run unit tests / unit_tests (push) Successful in 3m0s
Build Nginx-based docker image / build-static-assets (push) Failing after 12m9s
Reviewed-on: #140
2024-11-17 19:05:59 +00:00
80c1c9b99d Refine guest controller
All checks were successful
Check usage of free licenses / check-licenses (pull_request) Successful in 1m26s
Add copyright notice / copyright_notice (pull_request) Successful in 2m19s
Run unit tests / unit_tests (pull_request) Successful in 3m39s
2024-11-17 20:02:08 +01:00
1f81dabff4 Merge pull request 'Define an endpoint to remove guests' (#139) from delete-guest-endpoint into main
Some checks failed
Check usage of free licenses / check-licenses (push) Successful in 1m4s
Run unit tests / unit_tests (push) Successful in 3m42s
Build Nginx-based docker image / build-static-assets (push) Failing after 17m24s
Reviewed-on: #139
2024-11-17 17:28:13 +00:00
f1d1ea825c Recalculate simulations after removing a guest
All checks were successful
Check usage of free licenses / check-licenses (pull_request) Successful in 56s
Add copyright notice / copyright_notice (pull_request) Successful in 1m20s
Run unit tests / unit_tests (pull_request) Successful in 2m4s
2024-11-17 18:25:38 +01:00
7542c6361c Define an endpoint to destroy guests 2024-11-17 18:24:43 +01:00
7bdfb4f789 Merge pull request 'Remove unused bulk update endpoint' (#138) from remove-guest-bulk-update into main
Some checks failed
Check usage of free licenses / check-licenses (push) Successful in 52s
Run unit tests / unit_tests (push) Successful in 2m7s
Build Nginx-based docker image / build-static-assets (push) Failing after 11m29s
Reviewed-on: #138
2024-11-17 16:11:53 +00:00
31d41ea2ea Remove unused bulk update endpoint
All checks were successful
Check usage of free licenses / check-licenses (pull_request) Successful in 1m39s
Add copyright notice / copyright_notice (pull_request) Successful in 2m48s
Run unit tests / unit_tests (pull_request) Successful in 3m46s
2024-11-17 17:07:29 +01:00
29c9764450 Merge pull request 'Define an endpoint to create new guests' (#137) from api-create-guest into main
Some checks failed
Check usage of free licenses / check-licenses (push) Successful in 1m1s
Run unit tests / unit_tests (push) Successful in 2m54s
Build Nginx-based docker image / build-static-assets (push) Failing after 15m35s
Reviewed-on: #137
2024-11-17 10:51:01 +00:00
1b2c0f0d0a Define an endpoint to create new guests
All checks were successful
Check usage of free licenses / check-licenses (pull_request) Successful in 1m36s
Add copyright notice / copyright_notice (pull_request) Successful in 2m17s
Run unit tests / unit_tests (pull_request) Successful in 3m32s
2024-11-17 11:47:12 +01:00
08f7c1e584 Merge pull request 'Merge docker compose up and build into a single command' (#136) from readme-change into main
Some checks failed
Check usage of free licenses / check-licenses (push) Successful in 1m22s
Run unit tests / unit_tests (push) Successful in 3m43s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #136
2024-11-17 10:32:14 +00:00
b3cfde445c Merge docker compose up and build into a single command
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 1m54s
Check usage of free licenses / check-licenses (pull_request) Successful in 2m41s
Run unit tests / unit_tests (pull_request) Successful in 4m7s
2024-11-17 11:27:38 +01:00
Renovate Bot
b008777c20 Update dependency solid_queue to v1.0.2
Some checks failed
Check usage of free licenses / check-licenses (pull_request) Successful in 2m57s
Run unit tests / unit_tests (pull_request) Successful in 4m39s
Add copyright notice / copyright_notice (pull_request) Successful in 26s
Check usage of free licenses / check-licenses (push) Successful in 42s
Run unit tests / unit_tests (push) Successful in 1m42s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
2024-11-17 01:08:15 +00:00
b0ee052b64 Merge pull request 'Remove / server from Swagger configuration' (#133) from remove-localhost-swagger-server into main
Some checks failed
Check usage of free licenses / check-licenses (push) Successful in 1m2s
Run unit tests / unit_tests (push) Successful in 3m0s
Build Nginx-based docker image / build-static-assets (push) Failing after 13m43s
Reviewed-on: #133
2024-11-16 11:32:32 +00:00
5f47b923d5 Remove / server from Swagger configuration
All checks were successful
Check usage of free licenses / check-licenses (pull_request) Successful in 51s
Add copyright notice / copyright_notice (pull_request) Successful in 1m41s
Run unit tests / unit_tests (pull_request) Successful in 2m14s
2024-11-16 12:30:05 +01:00
17c796c375 Merge pull request 'Document expenses endpoint and add some specs' (#132) from document-expenses-controller into main
Some checks failed
Check usage of free licenses / check-licenses (push) Successful in 2m28s
Run unit tests / unit_tests (push) Successful in 6m46s
Build Nginx-based docker image / build-static-assets (push) Failing after 19m30s
Reviewed-on: #132
2024-11-16 09:32:36 +00:00
73e02a9d95 Add copyright notice
All checks were successful
Check usage of free licenses / check-licenses (pull_request) Successful in 1m58s
Add copyright notice / copyright_notice (pull_request) Successful in 6m38s
Run unit tests / unit_tests (pull_request) Successful in 8m40s
2024-11-16 09:23:51 +00:00
86b9d0b56c Document expenses endpoint and add some specs
All checks were successful
Check usage of free licenses / check-licenses (pull_request) Successful in 1m5s
Add copyright notice / copyright_notice (pull_request) Successful in 1m49s
Run unit tests / unit_tests (pull_request) Successful in 8m24s
2024-11-16 10:22:10 +01:00
8e799bfd2b Merge pull request 'Remove leftover code from Swagger-CSRF experiment' (#131) from remove-swagger-csrf into main
Some checks failed
Check usage of free licenses / check-licenses (push) Successful in 1m19s
Run unit tests / unit_tests (push) Successful in 2m58s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #131
2024-11-16 09:12:35 +00:00
6e5bbb7b1b Remove leftover code from Swagger-CSRF experiment
All checks were successful
Check usage of free licenses / check-licenses (pull_request) Successful in 2m25s
Run unit tests / unit_tests (pull_request) Successful in 4m54s
Add copyright notice / copyright_notice (pull_request) Successful in 1m16s
2024-11-16 09:59:19 +01:00
d73f59b05c Merge pull request 'Update format of guests API and document endpoints' (#130) from guests-api-changes into main
Some checks failed
Check usage of free licenses / check-licenses (push) Successful in 3m20s
Run unit tests / unit_tests (push) Successful in 8m10s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #130
2024-11-16 08:56:38 +00:00
5ba1591b02 Merge branch 'main' into guests-api-changes
All checks were successful
Check usage of free licenses / check-licenses (pull_request) Successful in 2m32s
Add copyright notice / copyright_notice (pull_request) Successful in 3m51s
Run unit tests / unit_tests (pull_request) Successful in 5m13s
2024-11-16 08:51:21 +00:00
b7714051e4 Merge pull request 'Update dependency pry to v0.15.0' (#129) from renovate/pry-0.x-lockfile into main
Some checks failed
Check usage of free licenses / check-licenses (push) Successful in 2m19s
Run unit tests / unit_tests (push) Successful in 4m34s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #129
2024-11-16 08:51:02 +00:00
a8c9c051f0 Add copyright notice
Some checks failed
Add copyright notice / copyright_notice (pull_request) Failing after 8m14s
Check usage of free licenses / check-licenses (pull_request) Failing after 7m54s
Run unit tests / unit_tests (pull_request) Failing after 6m48s
2024-11-16 01:52:48 +00:00
6f6a6aaabf Update format of guests API and document endpoints
All checks were successful
Check usage of free licenses / check-licenses (pull_request) Successful in 4m31s
Add copyright notice / copyright_notice (pull_request) Successful in 18m9s
Run unit tests / unit_tests (pull_request) Successful in 17m2s
2024-11-16 02:16:19 +01:00
Renovate Bot
6709c6b1f1 Update dependency pry to v0.15.0
All checks were successful
Check usage of free licenses / check-licenses (pull_request) Successful in 8m43s
Add copyright notice / copyright_notice (pull_request) Successful in 11m8s
Run unit tests / unit_tests (pull_request) Successful in 15m23s
2024-11-16 01:08:16 +00:00
21d3aa5f4b Merge pull request 'Document the API using OpenAPI' (#127) from rswag-documentation into main
Some checks failed
Check usage of free licenses / check-licenses (push) Successful in 1m5s
Run unit tests / unit_tests (push) Successful in 3m9s
Build Nginx-based docker image / build-static-assets (push) Failing after 12m50s
Reviewed-on: #127
2024-11-15 18:49:11 +00:00
cc3c8fdd63 Improve documentation of groups endpoint
All checks were successful
Check usage of free licenses / check-licenses (pull_request) Successful in 39s
Add copyright notice / copyright_notice (pull_request) Successful in 1m26s
Run unit tests / unit_tests (pull_request) Successful in 1m54s
2024-11-15 19:46:47 +01:00
94b1066c17 Include OpenAPI information in the README
All checks were successful
Check usage of free licenses / check-licenses (pull_request) Successful in 55s
Add copyright notice / copyright_notice (pull_request) Successful in 1m58s
Run unit tests / unit_tests (pull_request) Successful in 2m34s
2024-11-15 19:09:55 +01:00
ca0b1b18d3 Use different server URLs for development and testing
All checks were successful
Check usage of free licenses / check-licenses (pull_request) Successful in 41s
Add copyright notice / copyright_notice (pull_request) Successful in 1m33s
Run unit tests / unit_tests (pull_request) Successful in 2m9s
2024-11-15 19:04:30 +01:00
41cb719bf4 Add copyright notice
Some checks failed
Check usage of free licenses / check-licenses (pull_request) Successful in 1m38s
Add copyright notice / copyright_notice (pull_request) Successful in 2m0s
Run unit tests / unit_tests (pull_request) Failing after 2m39s
2024-11-15 17:29:56 +00:00
bcbcf9b469 MVP of swagger documentation
Some checks failed
Check usage of free licenses / check-licenses (pull_request) Successful in 40s
Add copyright notice / copyright_notice (pull_request) Successful in 1m23s
Run unit tests / unit_tests (pull_request) Failing after 3m5s
2024-11-15 18:28:45 +01:00
2bbcdfbd98 Merge pull request 'Update dependency factory_bot_rails to v6.4.4' (#125) from renovate/factory_bot_rails-6.x-lockfile into main
All checks were successful
Check usage of free licenses / check-licenses (push) Successful in 1m14s
Run unit tests / unit_tests (push) Successful in 2m26s
Build Nginx-based docker image / build-static-assets (push) Successful in 24m23s
Reviewed-on: #125
2024-11-15 07:47:45 +00:00
8a3469447b Install rswag gem with default configuration 2024-11-15 08:45:56 +01:00
Renovate Bot
c37713af8f Update dependency factory_bot_rails to v6.4.4
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 4m26s
Check usage of free licenses / check-licenses (pull_request) Successful in 5m11s
Run unit tests / unit_tests (pull_request) Successful in 10m21s
2024-11-15 07:43:39 +00:00
b8484edf26 Merge pull request 'Fix ruby version used to run license finder' (#126) from fix-ruby-version into main
Some checks failed
Check usage of free licenses / check-licenses (push) Successful in 42s
Run unit tests / unit_tests (push) Successful in 3m45s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #126
2024-11-15 07:43:31 +00:00
4cd3f24032 Fix ruby version used to run license finder
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 4m6s
Check usage of free licenses / check-licenses (pull_request) Successful in 4m28s
Run unit tests / unit_tests (pull_request) Successful in 6m5s
2024-11-15 08:33:31 +01:00
891741d740 Merge pull request 'Update dependency ruby to v3.3.6' (#97) from renovate/ruby-3.x into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Failing after 39s
Run unit tests / unit_tests (push) Successful in 2m11s
Build Nginx-based docker image / build-static-assets (push) Failing after 22m23s
Reviewed-on: #97
2024-11-14 08:43:13 +00:00
2fc4e2debd Use a setup-ruby version that has ruby 3.3.6
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m27s
Add copyright notice / copyright_notice (pull_request) Successful in 1m41s
Run unit tests / unit_tests (pull_request) Successful in 2m13s
2024-11-14 09:40:53 +01:00
8d746e21b9 Merge pull request 'Merge pull request 'Introduce endpoint to retrieve a summary of groups and invite attendance' (#122) from groups-index-stats into main' (#124) from annotate-gem into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 1m29s
Run unit tests / unit_tests (push) Successful in 3m17s
Build Nginx-based docker image / build-static-assets (push) Successful in 40m36s
Reviewed-on: #124
2024-11-14 07:39:04 +00:00
42f5f7b246 Add copyright notice
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m32s
Add copyright notice / copyright_notice (pull_request) Successful in 3m46s
Run unit tests / unit_tests (pull_request) Successful in 5m33s
2024-11-14 07:33:24 +00:00
d75b117c60 Merge pull request 'Introduce endpoint to retrieve a summary of groups and invite attendance' (#122) from groups-index-stats into main
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m39s
Add copyright notice / copyright_notice (pull_request) Successful in 2m20s
Run unit tests / unit_tests (pull_request) Successful in 5m23s
Reviewed-on: #122
2024-11-14 08:30:27 +01:00
c64c440272 Merge pull request 'Update dependency factory_bot_rails to v6.4.4' (#123) from renovate/factory_bot_rails-6.x-lockfile into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 3m3s
Run unit tests / unit_tests (push) Successful in 6m40s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #123
2024-11-14 07:28:05 +00:00
Renovate Bot
1a4067859d Update dependency factory_bot_rails to v6.4.4
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 8m33s
Check usage of free licenses / build-static-assets (pull_request) Successful in 7m8s
Run unit tests / unit_tests (pull_request) Successful in 7m52s
2024-11-14 01:06:51 +00:00
f15545d13a Merge pull request 'Introduce endpoint to retrieve a summary of groups and invite attendance' (#122) from groups-index-stats into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 45s
Run unit tests / unit_tests (push) Successful in 2m10s
Build Nginx-based docker image / build-static-assets (push) Successful in 19m58s
Reviewed-on: #122
2024-11-13 08:12:46 +00:00
4be1fc6cad Add copyright notice
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m24s
Add copyright notice / copyright_notice (pull_request) Successful in 5m47s
Run unit tests / unit_tests (pull_request) Successful in 4m14s
2024-11-13 07:59:07 +00:00
452b5b2040 Introduce endpoint to retrieve a summary of groups and invite attendance
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 45s
Add copyright notice / copyright_notice (pull_request) Successful in 1m47s
Run unit tests / unit_tests (pull_request) Successful in 5m4s
2024-11-13 08:57:20 +01:00
ef10fafae8 Merge pull request 'Update dependency factory_bot_rails to v6.4.4' (#120) from renovate/factory_bot_rails-6.x-lockfile into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 2m33s
Run unit tests / unit_tests (push) Successful in 4m47s
Build Nginx-based docker image / build-static-assets (push) Successful in 24m22s
Reviewed-on: #120
2024-11-12 08:49:27 +00:00
Renovate Bot
94bf707723 Update dependency factory_bot_rails to v6.4.4
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m31s
Add copyright notice / copyright_notice (pull_request) Successful in 2m49s
Run unit tests / unit_tests (pull_request) Successful in 4m26s
2024-11-12 01:07:37 +00:00
402a4a3e5e Merge pull request 'Define endpoint to update expenses' (#119) from update-expenses into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 1m46s
Run unit tests / unit_tests (push) Successful in 4m28s
Build Nginx-based docker image / build-static-assets (push) Successful in 33m9s
Reviewed-on: #119
2024-11-11 07:23:40 +00:00
88a7785b46 Define endpoint to update expenses
All checks were successful
Run unit tests / unit_tests (pull_request) Successful in 4m56s
Check usage of free licenses / build-static-assets (pull_request) Successful in 38s
Add copyright notice / copyright_notice (pull_request) Successful in 1m28s
2024-11-11 08:08:49 +01:00
f7c0fc91b1 Merge pull request 'Merge first and last name and expose guest update endpoint' (#118) from update-guests into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 2m41s
Run unit tests / unit_tests (push) Successful in 9m26s
Build Nginx-based docker image / build-static-assets (push) Failing after 15m48s
Reviewed-on: #118
2024-11-11 07:02:47 +00:00
3b9ca24bcd Add copyright notice
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m27s
Add copyright notice / copyright_notice (pull_request) Successful in 3m5s
Run unit tests / unit_tests (pull_request) Successful in 5m2s
2024-11-11 06:57:39 +00:00
bd5c4f5482 Merge first and last name and expose guest update endpoint
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m42s
Add copyright notice / copyright_notice (pull_request) Successful in 3m5s
Run unit tests / unit_tests (pull_request) Successful in 5m4s
2024-11-11 07:55:03 +01:00
d2974edcc1 Merge pull request 'Define an endpoint to expose the list of expenses' (#116) from expenses-list-endpoints into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 2m17s
Run unit tests / unit_tests (push) Successful in 5m23s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #116
2024-11-11 06:50:18 +00:00
810d0740f3 Define an endpoint to expose the list of expenses
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 44s
Add copyright notice / copyright_notice (pull_request) Successful in 2m30s
Run unit tests / unit_tests (pull_request) Successful in 6m1s
2024-11-10 20:40:37 +01:00
b1ec1281b5 Merge pull request 'Remove rake task leftover' (#115) from remove-rake into main
Some checks failed
Build Nginx-based docker image / build-static-assets (push) Failing after 12s
Check usage of free licenses / build-static-assets (push) Successful in 49s
Run unit tests / unit_tests (push) Successful in 1m41s
Reviewed-on: #115
2024-11-10 19:39:55 +00:00
6f19e4f1bd Remove rake task leftover
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 39s
Add copyright notice / copyright_notice (pull_request) Successful in 1m8s
Run unit tests / unit_tests (pull_request) Successful in 1m46s
2024-11-10 20:37:58 +01:00
8d74d25574 Merge pull request 'Increase penalty for tables under minimum capacity' (#113) from increase-penalty-undercapacity-tables into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 52s
Build Nginx-based docker image / build-static-assets (push) Failing after 1m55s
Run unit tests / unit_tests (push) Successful in 2m17s
Reviewed-on: #113
2024-11-10 18:01:16 +00:00
b389ae0a41 Merge pull request 'Run perturbations in both orders' (#114) from vns-combinations into main
Some checks failed
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Check usage of free licenses / build-static-assets (push) Has been cancelled
Run unit tests / unit_tests (push) Has been cancelled
Reviewed-on: #114
2024-11-10 18:01:15 +00:00
fe91f75ec0 Add copyright notice
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m30s
Add copyright notice / copyright_notice (pull_request) Successful in 2m18s
Run unit tests / unit_tests (pull_request) Successful in 3m38s
2024-11-10 17:57:29 +00:00
f2e91c8d7a Run perturbations in both orders
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m27s
Add copyright notice / copyright_notice (pull_request) Successful in 2m13s
Run unit tests / unit_tests (pull_request) Successful in 4m44s
2024-11-10 18:55:04 +01:00
5b36526c59 Increase penalty for tables under minimum capacity
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 56s
Add copyright notice / copyright_notice (pull_request) Successful in 2m1s
Run unit tests / unit_tests (pull_request) Successful in 3m44s
2024-11-10 18:40:26 +01:00
b084328d79 Merge pull request 'Implement shift operation for VNS algorithm' (#111) from shift into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 50s
Run unit tests / unit_tests (push) Successful in 2m5s
Build Nginx-based docker image / build-static-assets (push) Successful in 24m44s
Reviewed-on: #111
2024-11-10 17:12:04 +00:00
bcf00fabf0 Add copyright notice
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m9s
Add copyright notice / copyright_notice (pull_request) Successful in 1m7s
Run unit tests / unit_tests (pull_request) Successful in 1m57s
2024-11-10 17:01:57 +00:00
1fcca38576 Implement shift perturbation
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 51s
Run unit tests / unit_tests (pull_request) Successful in 2m11s
Add copyright notice / copyright_notice (pull_request) Successful in 56s
2024-11-10 17:53:52 +01:00
c16e8f564c Merge pull request 'Use sets instead of arrays to represent tables' (#112) from table-set into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 39s
Run unit tests / unit_tests (push) Successful in 3m26s
Build Nginx-based docker image / build-static-assets (push) Successful in 31m37s
Reviewed-on: #112
2024-11-10 16:31:49 +00:00
29d9d21916 Use sets instead of arrays to represent tables
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 44s
Add copyright notice / copyright_notice (pull_request) Successful in 59s
Run unit tests / unit_tests (pull_request) Successful in 1m33s
2024-11-10 17:30:01 +01:00
aef55abe54 Merge pull request 'Assign similar colors to child groups' (#110) from chosen-colors into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 57s
Build Nginx-based docker image / build-static-assets (push) Failing after 1m59s
Run unit tests / unit_tests (push) Successful in 2m18s
Reviewed-on: #110
2024-11-10 11:26:54 +00:00
4089ff63ba Add copyright notice
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m10s
Add copyright notice / copyright_notice (pull_request) Successful in 1m45s
Run unit tests / unit_tests (pull_request) Successful in 2m42s
2024-11-10 11:24:07 +00:00
fa3d3cf13b Assign similar colors to child groups
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 35s
Add copyright notice / copyright_notice (pull_request) Successful in 55s
Run unit tests / unit_tests (pull_request) Successful in 3m11s
2024-11-10 12:22:58 +01:00
172193b0dc Merge pull request 'Use average discomfort instead of sum' (#109) from fix/discomfort-average into main
Some checks failed
Build Nginx-based docker image / build-static-assets (push) Failing after 1m19s
Check usage of free licenses / build-static-assets (push) Successful in 1m29s
Run unit tests / unit_tests (push) Successful in 1m52s
Reviewed-on: #109
2024-11-10 10:38:35 +00:00
021b82b28e Use average discomfort instead of sum
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m1s
Add copyright notice / copyright_notice (pull_request) Successful in 1m29s
Run unit tests / unit_tests (pull_request) Successful in 2m14s
2024-11-10 11:34:26 +01:00
2d96f1c7c2 Merge pull request 'Apply a penalty if table sizes are not honored' (#108) from table-size-discomfort into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 35s
Run unit tests / unit_tests (push) Successful in 1m27s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #108
2024-11-10 10:25:37 +00:00
f3b70f5a31 Apply a penalty if table sizes are not honored
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 33s
Add copyright notice / copyright_notice (pull_request) Successful in 47s
Run unit tests / unit_tests (pull_request) Successful in 1m18s
2024-11-10 11:22:51 +01:00
2deaaa64a5 Merge pull request 'Modify initial distribution of tables to guarantee there is no single-person table' (#107) from fix/initial-group-creation into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 31s
Run unit tests / unit_tests (push) Successful in 1m25s
Build Nginx-based docker image / build-static-assets (push) Failing after 3m58s
Reviewed-on: #107
2024-11-10 09:46:53 +00:00
c12e2fc6a4 Add copyright notice
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 48s
Run unit tests / unit_tests (pull_request) Successful in 1m22s
Add copyright notice / copyright_notice (pull_request) Successful in 20s
2024-11-10 09:17:34 +00:00
19d309a2cf Modify initial distribution of tables to guarantee there is no single-person table
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 35s
Add copyright notice / copyright_notice (pull_request) Successful in 1m7s
Run unit tests / unit_tests (pull_request) Successful in 1m44s
2024-11-10 10:16:22 +01:00
Renovate Bot
9190348ff2 Update dependency rspec-rails to '~> 7.1.0'
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 1m10s
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m15s
Run unit tests / unit_tests (pull_request) Successful in 1m46s
Check usage of free licenses / build-static-assets (push) Successful in 36s
Run unit tests / unit_tests (push) Successful in 1m51s
Build Nginx-based docker image / build-static-assets (push) Successful in 25m9s
2024-11-10 01:24:55 +00:00
b3bbeff739 Merge pull request 'Update dependency rails to v8' (#99) from renovate/rails-8.x into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 50s
Build Nginx-based docker image / build-static-assets (push) Failing after 2m13s
Run unit tests / unit_tests (push) Successful in 2m45s
Reviewed-on: #99
2024-11-09 16:56:10 +00:00
ffc7fa3801 Update dependency rails to v8
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 1m54s
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m55s
Run unit tests / unit_tests (pull_request) Successful in 1m30s
2024-11-09 17:51:12 +01:00
91ebb9afee Merge pull request 'Install shoulda matchers, improve guests specs and change enum syntax' (#104) from deprecation-warning-rails-8 into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 47s
Run unit tests / unit_tests (push) Successful in 2m10s
Build Nginx-based docker image / build-static-assets (push) Failing after 3m27s
Reviewed-on: #104
2024-11-09 16:48:32 +00:00
9035df5178 Install shoulda matchers, improve guests specs and change enum syntax
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 1m18s
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m28s
Run unit tests / unit_tests (pull_request) Successful in 1m0s
2024-11-09 17:45:23 +01:00
60a7b1342f Add license finder as a development dependency
Some checks failed
Add copyright notice / copyright_notice (pull_request) Successful in 1m0s
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m28s
Run unit tests / unit_tests (pull_request) Successful in 2m11s
Check usage of free licenses / build-static-assets (push) Successful in 45s
Run unit tests / unit_tests (push) Successful in 2m33s
Build Nginx-based docker image / build-static-assets (push) Failing after 20s
2024-11-09 08:52:40 +01:00
Renovate Bot
d04f7211e7 Update dependency solid_queue to v1.0.1
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Failing after 2m53s
Add copyright notice / copyright_notice (pull_request) Successful in 3m17s
Run unit tests / unit_tests (pull_request) Successful in 3m45s
2024-11-09 07:44:14 +00:00
61cfdd2424 Merge pull request 'Install project dependencies before running license finder' (#102) from fix-license-finder-action into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 3m57s
Build Nginx-based docker image / build-static-assets (push) Failing after 7m34s
Run unit tests / unit_tests (push) Successful in 5m6s
Reviewed-on: #102
2024-11-09 07:43:41 +00:00
004624687a Update dockerfile
Some checks failed
Add copyright notice / copyright_notice (pull_request) Failing after 26s
Check usage of free licenses / build-static-assets (pull_request) Failing after 22s
Run unit tests / unit_tests (pull_request) Failing after 3m47s
2024-11-09 08:39:57 +01:00
f7b227bc97 Update ruby version in Gemfile and .ruby-version
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m23s
Run unit tests / unit_tests (pull_request) Failing after 3m58s
Add copyright notice / copyright_notice (pull_request) Successful in 7m26s
2024-11-09 08:39:17 +01:00
9856974684 Install project dependencies before running license finder
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m21s
Add copyright notice / copyright_notice (pull_request) Successful in 5m15s
Run unit tests / unit_tests (pull_request) Successful in 6m57s
2024-11-09 08:35:57 +01:00
c23ecfbbad Merge pull request 'Update dependency factory_bot_rails to v6.4.4' (#100) from renovate/factory_bot_rails-6.x-lockfile into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 1m46s
Run unit tests / unit_tests (push) Successful in 5m1s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #100
2024-11-09 07:30:46 +00:00
Renovate Bot
b4664c5e1d Update dependency ruby to v3.3.6
Some checks failed
Add copyright notice / copyright_notice (pull_request) Failing after 11s
Check usage of free licenses / build-static-assets (pull_request) Failing after 9s
Run unit tests / unit_tests (pull_request) Failing after 1m17s
2024-11-09 01:08:10 +00:00
Renovate Bot
c70c0c5f60 Update dependency factory_bot_rails to v6.4.4
Some checks failed
renovate/artifacts Artifact file update failure
Check usage of free licenses / build-static-assets (pull_request) Successful in 3m6s
Add copyright notice / copyright_notice (pull_request) Successful in 7m45s
Run unit tests / unit_tests (pull_request) Successful in 10m41s
2024-11-09 01:07:47 +00:00
Renovate Bot
7a4aad29c1 Update dependency factory_bot_rails to v6.4.4
All checks were successful
Run unit tests / unit_tests (pull_request) Successful in 11m24s
Add copyright notice / copyright_notice (pull_request) Successful in 23s
Check usage of free licenses / build-static-assets (pull_request) Successful in 36s
Check usage of free licenses / build-static-assets (push) Successful in 59s
Run unit tests / unit_tests (push) Successful in 1m40s
Build Nginx-based docker image / build-static-assets (push) Successful in 20m53s
2024-11-08 01:08:59 +00:00
cded122f22 Merge pull request 'Choose light colors for the groups' (#96) from light-colors into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 48s
Run unit tests / unit_tests (push) Successful in 1m38s
Build Nginx-based docker image / build-static-assets (push) Failing after 2m18s
Reviewed-on: #96
2024-11-04 22:46:08 +00:00
5cceb1e6ed Choose light colors for the groups
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 1m13s
Run unit tests / unit_tests (pull_request) Successful in 1m54s
Check usage of free licenses / build-static-assets (pull_request) Successful in 27s
2024-11-04 23:39:44 +01:00
1a39364322 Merge pull request 'Initial version of the README' (#95) from documentation-setup into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 43s
Build Nginx-based docker image / build-static-assets (push) Failing after 1m58s
Run unit tests / unit_tests (push) Successful in 2m24s
Reviewed-on: #95
2024-11-04 22:21:54 +00:00
ca1a8a499f Initial version of the README
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 46s
Add copyright notice / copyright_notice (pull_request) Successful in 1m8s
Run unit tests / unit_tests (pull_request) Successful in 2m6s
2024-11-04 23:18:44 +01:00
231ea3fda8 Merge pull request 'Assign a color to every group and expose it via API' (#94) from group-color into main
All checks were successful
Check usage of free licenses / build-static-assets (push) Successful in 41s
Run unit tests / unit_tests (push) Successful in 1m40s
Build Nginx-based docker image / build-static-assets (push) Successful in 25m17s
Reviewed-on: #94
2024-11-03 13:50:56 +00:00
1e23ad8e50 Order guests within same table by color
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 39s
Add copyright notice / copyright_notice (pull_request) Successful in 1m2s
Run unit tests / unit_tests (pull_request) Successful in 1m56s
2024-11-03 14:48:54 +01:00
3ae90bfc4e Add copyright notice
Some checks failed
Add copyright notice / copyright_notice (pull_request) Failing after 17s
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m14s
Run unit tests / unit_tests (pull_request) Successful in 2m7s
2024-11-03 13:43:32 +00:00
a42f938530 Assign a color to every group and expose it via API
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 55s
Add copyright notice / copyright_notice (pull_request) Successful in 1m28s
Run unit tests / unit_tests (pull_request) Successful in 1m57s
2024-11-03 14:41:09 +01:00
01a00cf35f Merge pull request 'Enqueue some simulations after running the seed file' (#93) from seed-executions into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 34s
Run unit tests / unit_tests (push) Successful in 1m20s
Build Nginx-based docker image / build-static-assets (push) Failing after 1m56s
Reviewed-on: #93
2024-11-03 13:30:34 +00:00
a67696747b Enqueue some simulations after running the seed file
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 56s
Run unit tests / unit_tests (pull_request) Successful in 1m25s
Check usage of free licenses / build-static-assets (pull_request) Successful in 2m1s
2024-11-03 14:18:30 +01:00
ed0e307e33 Merge pull request 'compose-development' (#92) from compose-development into main
Some checks failed
Build Nginx-based docker image / build-static-assets (push) Failing after 1m5s
Check usage of free licenses / build-static-assets (push) Successful in 1m29s
Run unit tests / unit_tests (push) Successful in 2m30s
Reviewed-on: #92
2024-11-03 13:16:29 +00:00
da8086605d Enable hot reload in the frontend
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 59s
Add copyright notice / copyright_notice (pull_request) Successful in 1m42s
Run unit tests / unit_tests (pull_request) Successful in 3m9s
2024-11-03 14:13:13 +01:00
0d122b39d3 Merge pull request 'Fix undefined method' (#91) from fix/undefined-method into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 1m22s
Run unit tests / unit_tests (push) Failing after 1m51s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #91
2024-11-03 13:00:11 +00:00
a9016ed352 Enable hot reloading of modified code
Some checks failed
Check usage of free licenses / build-static-assets (pull_request) Failing after 35s
Add copyright notice / copyright_notice (pull_request) Failing after 35s
Run unit tests / unit_tests (pull_request) Successful in 3m4s
2024-11-03 13:59:35 +01:00
94d0a42ac1 Fix undefined method
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 54s
Add copyright notice / copyright_notice (pull_request) Successful in 1m31s
Run unit tests / unit_tests (pull_request) Successful in 3m42s
2024-11-03 13:56:10 +01:00
c2398c0d80 Avoid exposing internal ports
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m54s
Add copyright notice / copyright_notice (pull_request) Successful in 2m32s
Run unit tests / unit_tests (pull_request) Successful in 4m0s
2024-11-03 13:53:36 +01:00
c2989b216f Merge pull request 'Recreate simulations whenever a guest changes their attendance' (#85) from simulations-lifecycle into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 43s
Run unit tests / unit_tests (push) Successful in 1m46s
Build Nginx-based docker image / build-static-assets (push) Failing after 2m54s
Reviewed-on: #85
2024-11-03 12:51:13 +00:00
95651ee942 Merge remote-tracking branch 'origin/simulations-lifecycle' into compose-development 2024-11-03 13:50:19 +01:00
bae70b9884 Initial version 2024-11-03 13:40:50 +01:00
865e86e659 Merge branch 'main' into simulations-lifecycle
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 4m50s
Add copyright notice / copyright_notice (pull_request) Successful in 14m0s
Run unit tests / unit_tests (pull_request) Successful in 1m6s
2024-11-03 11:23:38 +00:00
47c6fc7568 Merge pull request 'Include a step to verify nonfree dependencies are not committed' (#87) from license_checks into main
Some checks failed
Check usage of free licenses / build-static-assets (push) Successful in 2m12s
Build Nginx-based docker image / build-static-assets (push) Failing after 13m54s
Run unit tests / unit_tests (push) Successful in 14m20s
Reviewed-on: #87
2024-11-03 11:23:27 +00:00
ba4384307d Merge remote-tracking branch 'origin/main' into simulations-lifecycle
Some checks failed
Add copyright notice / copyright_notice (pull_request) Failing after 10m12s
Run unit tests / unit_tests (pull_request) Successful in 11m32s
2024-11-03 12:04:54 +01:00
0d7f602441 Merge pull request 'Assign a name to every tables arrangement' (#83) from arrangement-names into main
Some checks failed
Run unit tests / unit_tests (push) Successful in 10m57s
Build Nginx-based docker image / build-static-assets (push) Failing after 13m23s
Reviewed-on: #83
2024-11-03 11:04:07 +00:00
956863a496 Merge pull request 'Install solid queues framework' (#84) from solid-queue-vns into main
Some checks failed
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Run unit tests / unit_tests (push) Has been cancelled
Reviewed-on: #84
2024-11-03 11:00:54 +00:00
89d9f722e1 Add ruby to the list of permitted licenses
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 3m40s
Run unit tests / unit_tests (pull_request) Successful in 11m43s
Add copyright notice / copyright_notice (pull_request) Successful in 6m20s
2024-11-03 11:58:53 +01:00
2fd4549b00 Add copyright notice
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 6m31s
Run unit tests / unit_tests (pull_request) Successful in 10m41s
2024-11-03 10:47:26 +00:00
a5c6def0b6 Merge branch 'main' into solid-queue-vns
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 8m59s
Run unit tests / unit_tests (pull_request) Successful in 12m12s
2024-11-03 11:43:39 +01:00
eb2b111472 Merge branch 'main' into arrangement-names
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 3m43s
Run unit tests / unit_tests (pull_request) Successful in 13m1s
2024-11-03 11:42:28 +01:00
3a8a83e60e Merge pull request 'Remove the email property from the guest model' (#90) from remove-emails into main
Some checks failed
Run unit tests / unit_tests (push) Successful in 6m40s
Build Nginx-based docker image / build-static-assets (push) Failing after 8m28s
Reviewed-on: #90
2024-11-03 10:41:52 +00:00
dacc0aa74e Merge pull request 'Stop redundant builds' (#86) from actions-concurrency into main
Some checks failed
Build Nginx-based docker image / build-static-assets (push) Failing after 3m19s
Run unit tests / unit_tests (push) Successful in 3m44s
Reviewed-on: #86
2024-11-03 10:31:34 +00:00
f0e8c570c9 Merge pull request 'Configure a build timeout of 30 minutes' (#88) from build-timeout into main
Some checks failed
Run unit tests / unit_tests (push) Has been cancelled
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
Reviewed-on: #88
2024-11-03 10:29:07 +00:00
c08f7bd37c Add copyright notice
All checks were successful
Run unit tests / unit_tests (pull_request) Successful in 7m30s
Add copyright notice / copyright_notice (pull_request) Successful in 9m10s
2024-11-03 10:03:47 +00:00
f21aaa3723 Remove the email property from the guest model
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 9m38s
Run unit tests / unit_tests (pull_request) Successful in 15m56s
2024-11-03 10:43:06 +01:00
b78165fb08 Merge remote-tracking branch 'origin/main' into actions-concurrency
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 23m44s
Run unit tests / unit_tests (pull_request) Successful in 17m5s
2024-11-03 10:17:55 +01:00
d3d1e2c821 Merge branch 'main' into license_checks
Some checks failed
Add copyright notice / copyright_notice (pull_request) Failing after 13m49s
Check usage of free licenses / build-static-assets (pull_request) Failing after 9m16s
Run unit tests / unit_tests (pull_request) Successful in 16m22s
2024-11-03 09:16:30 +00:00
7a1a2f7107 Merge branch 'main' into build-timeout
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 10m17s
Run unit tests / unit_tests (pull_request) Successful in 16m4s
2024-11-03 09:16:20 +00:00
44972b7972 Merge pull request 'Stop building docker images on PR' (#89) from build-main-only into main
Some checks failed
Run unit tests / unit_tests (push) Successful in 3m56s
Build Nginx-based docker image / build-static-assets (push) Failing after 26m44s
Reviewed-on: #89
2024-11-03 09:13:29 +00:00
22fbdf5ca3 Stop building docker images on PR
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 3m12s
Run unit tests / unit_tests (pull_request) Successful in 5m6s
2024-11-03 10:07:08 +01:00
4f133ac3f5 Configure a build timeout of 30 minutes
Some checks failed
Build Nginx-based docker image / build-static-assets (pull_request) Has been cancelled
Add copyright notice / copyright_notice (pull_request) Failing after 36s
Run unit tests / unit_tests (pull_request) Failing after 30s
2024-11-03 09:40:57 +01:00
56a8be21cc Include a step to verify nonfree dependencies are not committed
Some checks failed
Build Nginx-based docker image / build-static-assets (pull_request) Has been cancelled
Add copyright notice / copyright_notice (pull_request) Failing after 44s
Check usage of free licenses / build-static-assets (pull_request) Failing after 18s
Run unit tests / unit_tests (pull_request) Failing after 44s
2024-11-03 09:38:51 +01:00
86e982164d Add copyright notice
Some checks failed
Build Nginx-based docker image / build-static-assets (pull_request) Waiting to run
Run unit tests / unit_tests (pull_request) Failing after 16m52s
Add copyright notice / copyright_notice (pull_request) Failing after 17m30s
2024-11-03 08:31:58 +00:00
33434db3f2 Stop redundant builds
Some checks failed
Build Nginx-based docker image / build-static-assets (pull_request) Waiting to run
Add copyright notice / copyright_notice (pull_request) Failing after 19m31s
Run unit tests / unit_tests (pull_request) Failing after 18m49s
2024-11-03 09:31:10 +01:00
35bf272ac8 Restart simulations whenever a guest changes their invitation status
Some checks failed
Build Nginx-based docker image / build-static-assets (pull_request) Waiting to run
Add copyright notice / copyright_notice (pull_request) Successful in 4m39s
Run unit tests / unit_tests (pull_request) Failing after 22m29s
2024-11-03 09:26:25 +01:00
50a5c90728 Only include potential guests in the simulation 2024-11-03 09:15:48 +01:00
15a5c51fb6 Add copyright notice
Some checks are pending
Build Nginx-based docker image / build-static-assets (pull_request) Waiting to run
Add copyright notice / copyright_notice (pull_request) Successful in 6m50s
Run unit tests / unit_tests (pull_request) Successful in 10m9s
2024-11-03 08:12:24 +00:00
8d09fd733f Define a job to generate table simulations 2024-11-03 09:06:45 +01:00
3be71406f8 Add copyright notice 2024-11-03 09:06:45 +01:00
d15096b3a7 Install solid queues framework 2024-11-03 09:06:42 +01:00
1f919644a3 Define a job to generate table simulations
Some checks are pending
Build Nginx-based docker image / build-static-assets (pull_request) Waiting to run
Add copyright notice / copyright_notice (pull_request) Successful in 6m46s
Run unit tests / unit_tests (pull_request) Successful in 9m49s
2024-11-03 09:06:17 +01:00
8d83c63fa6 Add copyright notice
Some checks are pending
Build Nginx-based docker image / build-static-assets (pull_request) Waiting to run
Add copyright notice / copyright_notice (pull_request) Successful in 4m10s
Run unit tests / unit_tests (pull_request) Successful in 8m20s
2024-11-03 08:01:59 +00:00
a1b5e55b39 Install solid queues framework
Some checks are pending
Build Nginx-based docker image / build-static-assets (pull_request) Waiting to run
Add copyright notice / copyright_notice (pull_request) Successful in 2m3s
Run unit tests / unit_tests (pull_request) Successful in 5m23s
2024-11-03 08:59:56 +01:00
066fdea504 Assign a name to every tables arrangement
Some checks failed
Add copyright notice / copyright_notice (pull_request) Successful in 3m52s
Run unit tests / unit_tests (pull_request) Successful in 7m40s
Build Nginx-based docker image / build-static-assets (pull_request) Failing after 1h10m25s
2024-11-03 08:44:31 +01:00
f75f903363 Merge pull request 'Expose tables via API' (#80) from arrangements-api into main
All checks were successful
Run unit tests / unit_tests (push) Successful in 1m29s
Build Nginx-based docker image / build-static-assets (push) Successful in 34m23s
Reviewed-on: #80
2024-11-02 12:19:16 +00:00
d6182392f6 Return only the top 3 arrangements
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 1m9s
Run unit tests / unit_tests (pull_request) Successful in 2m29s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 28m27s
2024-11-02 12:50:45 +01:00
612cb9a789 Refine arrangement detail endpoint
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 1m21s
Run unit tests / unit_tests (pull_request) Successful in 2m17s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 25m8s
2024-11-02 11:23:00 +01:00
d4c1e5aab0 Rewrite table arrangements endpoints 2024-11-02 10:40:43 +01:00
83fbac76f6 Merge pull request 'Remove acts_as_taggable_on gem' (#82) from remove-acts-as-taggable into main
All checks were successful
Run unit tests / unit_tests (push) Successful in 2m14s
Build Nginx-based docker image / build-static-assets (push) Successful in 25m23s
Reviewed-on: #82
2024-11-02 08:54:23 +00:00
bf970af2c5 Remove tags table as well
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 2m40s
Run unit tests / unit_tests (pull_request) Successful in 4m16s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 47m21s
2024-11-01 19:55:39 +00:00
eb85028eea Add copyright notice 2024-11-01 19:55:39 +00:00
5fef6f1011 Remove references to acts_as_taggable_on gem 2024-11-01 19:55:39 +00:00
ea129602b5 Uninstall acts as taggable on gem 2024-11-01 19:55:39 +00:00
7bb9d83c6e Merge pull request 'Remove HTML views and non-JSON endpoints' (#81) from remove-html-views into main
All checks were successful
Run unit tests / unit_tests (push) Successful in 4m1s
Build Nginx-based docker image / build-static-assets (push) Successful in 49m11s
Reviewed-on: #81
2024-11-01 19:54:15 +00:00
db644c85be Remove HTML views
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 1m31s
Run unit tests / unit_tests (pull_request) Successful in 2m49s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 31m42s
2024-11-01 19:08:01 +01:00
1f93fe42c5 Clean up unused methods and non-API endpoints from controllers 2024-11-01 19:07:12 +01:00
62a7af6db3 Merge pull request 'Adapt discomfort calculator to use groups instead of affinity tags' (#79) from fix-hiearhy-load into main
All checks were successful
Run unit tests / unit_tests (push) Successful in 1m11s
Build Nginx-based docker image / build-static-assets (push) Successful in 23m29s
Reviewed-on: #79
2024-11-01 11:22:13 +00:00
d37dd44cd3 Update discomfort calculator to use group ids
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 52s
Run unit tests / unit_tests (pull_request) Successful in 1m23s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 16m27s
2024-11-01 12:04:15 +01:00
b5693f549e Load groups hierarchy from data in DB 2024-11-01 11:55:32 +01:00
Renovate Bot
c1575bb7e1 Update dependency rubocop to v1.68.0
All checks were successful
Run unit tests / unit_tests (push) Successful in 3m9s
Build Nginx-based docker image / build-static-assets (push) Successful in 23m22s
2024-11-01 01:40:11 +00:00
7c0a525c64 Add copyright notice
Some checks failed
Add copyright notice / copyright_notice (pull_request) Successful in 1m41s
Run unit tests / unit_tests (pull_request) Successful in 6m7s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 48m54s
Run unit tests / unit_tests (push) Successful in 2m24s
Build Nginx-based docker image / build-static-assets (push) Has been cancelled
2024-10-31 23:34:15 +00:00
Renovate Bot
d8ef1f179c Update dependency rails to v7.2.2
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 4m38s
Run unit tests / unit_tests (pull_request) Successful in 11m45s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 1h57m15s
2024-10-31 23:08:25 +00:00
90 changed files with 1897 additions and 745 deletions

58
.annotaterb.yml Normal file
View File

@ -0,0 +1,58 @@
---
:position: before
:position_in_additional_file_patterns: before
:position_in_class: before
:position_in_factory: before
:position_in_fixture: before
:position_in_routes: before
:position_in_serializer: before
:position_in_test: before
:classified_sort: true
:exclude_controllers: true
:exclude_factories: true
:exclude_fixtures: false
:exclude_helpers: true
:exclude_scaffolds: true
:exclude_serializers: false
:exclude_sti_subclasses: false
:exclude_tests: true
:force: false
:format_markdown: false
:format_rdoc: false
:format_yard: false
:frozen: false
:ignore_model_sub_dir: false
:ignore_unknown_models: false
:include_version: false
:show_check_constraints: false
:show_complete_foreign_keys: false
:show_foreign_keys: true
:show_indexes: true
:simple_indexes: false
:sort: false
:timestamp: false
:trace: false
:with_comment: true
:with_column_comments: true
:with_table_comments: true
:active_admin: false
:command:
:debug: false
:hide_default_column_types: ''
:hide_limit_column_types: ''
:ignore_columns:
:ignore_routes:
:models: true
:routes: false
:skip_on_db_migrate: false
:target_action: :do_annotations
:wrapper:
:wrapper_close:
:wrapper_open:
:classes_default_to_s: []
:additional_file_patterns: []
:model_dir:
- app/models
:require: []
:root_dir:
- ''

View File

@ -35,3 +35,4 @@
/app/assets/builds/* /app/assets/builds/*
!/app/assets/builds/.keep !/app/assets/builds/.keep
/public/assets /public/assets
.docker-compose.yml

View File

@ -3,10 +3,13 @@ on:
push: push:
branches: branches:
- main - main
pull_request: concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
build-static-assets: build-static-assets:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 30
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:

View File

@ -3,6 +3,9 @@ on:
pull_request: pull_request:
permissions: permissions:
contents: write contents: write
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
copyright_notice: copyright_notice:
runs-on: ubuntu-latest runs-on: ubuntu-latest

23
.github/workflows/license_finder.yml vendored Normal file
View File

@ -0,0 +1,23 @@
name: Check usage of free licenses
on:
push:
branches:
- main
pull_request:
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
jobs:
check-licenses:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: ruby/setup-ruby@v1.202.0
with:
ruby-version: '3.3.6'
- name: Install project dependencies
run: bundle install --jobs `getconf _NPROCESSORS_ONLN`
- name: Run license finder
run: license_finder

View File

@ -4,6 +4,9 @@ on:
branches: branches:
- main - main
pull_request: pull_request:
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
unit_tests: unit_tests:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -19,7 +22,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
- uses: ruby/setup-ruby@v1 - uses: ruby/setup-ruby@v1.202.0
- run: bundle install - run: bundle install
- name: Wait until Postgres is ready to accept connections - name: Wait until Postgres is ready to accept connections
run: | run: |

3
.gitignore vendored
View File

@ -33,3 +33,6 @@
# Ignore master key for decrypting credentials and more. # Ignore master key for decrypting credentials and more.
/config/master.key /config/master.key
# Ignore swagger generated documentation
swagger/v1/swagger.yaml

View File

@ -1 +1 @@
ruby-3.3.5 ruby-3.3.6

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.3.5 ARG RUBY_VERSION=3.3.6
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

42
Dockerfile.dev Normal file
View File

@ -0,0 +1,42 @@
# syntax = docker/dockerfile:1
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.3.6
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
# Rails app lives here
WORKDIR /rails
RUN apt-get update && apt-get install -y nodejs
FROM base as build
# Install packages needed to build gems
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libpq-dev libvips pkg-config
# Install application gems
COPY Gemfile Gemfile.lock ./
RUN bundle install
# Copy application code
COPY . .
# Final stage for app image
FROM base
# Install packages needed for deployment
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libvips postgresql-client && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Copy built artifacts: gems, application
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build /rails /rails
# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server", "--binding=0.0.0.0"]

View File

@ -1,29 +1,29 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (7.2.1.2) actioncable (7.2.2)
actionpack (= 7.2.1.2) actionpack (= 7.2.2)
activesupport (= 7.2.1.2) activesupport (= 7.2.2)
nio4r (~> 2.0) nio4r (~> 2.0)
websocket-driver (>= 0.6.1) websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
actionmailbox (7.2.1.2) actionmailbox (7.2.2)
actionpack (= 7.2.1.2) actionpack (= 7.2.2)
activejob (= 7.2.1.2) activejob (= 7.2.2)
activerecord (= 7.2.1.2) activerecord (= 7.2.2)
activestorage (= 7.2.1.2) activestorage (= 7.2.2)
activesupport (= 7.2.1.2) activesupport (= 7.2.2)
mail (>= 2.8.0) mail (>= 2.8.0)
actionmailer (7.2.1.2) actionmailer (7.2.2)
actionpack (= 7.2.1.2) actionpack (= 7.2.2)
actionview (= 7.2.1.2) actionview (= 7.2.2)
activejob (= 7.2.1.2) activejob (= 7.2.2)
activesupport (= 7.2.1.2) activesupport (= 7.2.2)
mail (>= 2.8.0) mail (>= 2.8.0)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
actionpack (7.2.1.2) actionpack (7.2.2)
actionview (= 7.2.1.2) actionview (= 7.2.2)
activesupport (= 7.2.1.2) activesupport (= 7.2.2)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
racc racc
rack (>= 2.2.4, < 3.2) rack (>= 2.2.4, < 3.2)
@ -32,36 +32,37 @@ 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 (7.2.1.2) actiontext (7.2.2)
actionpack (= 7.2.1.2) actionpack (= 7.2.2)
activerecord (= 7.2.1.2) activerecord (= 7.2.2)
activestorage (= 7.2.1.2) activestorage (= 7.2.2)
activesupport (= 7.2.1.2) activesupport (= 7.2.2)
globalid (>= 0.6.0) globalid (>= 0.6.0)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
actionview (7.2.1.2) actionview (7.2.2)
activesupport (= 7.2.1.2) activesupport (= 7.2.2)
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 (7.2.1.2) activejob (7.2.2)
activesupport (= 7.2.1.2) activesupport (= 7.2.2)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (7.2.1.2) activemodel (7.2.2)
activesupport (= 7.2.1.2) activesupport (= 7.2.2)
activerecord (7.2.1.2) activerecord (7.2.2)
activemodel (= 7.2.1.2) activemodel (= 7.2.2)
activesupport (= 7.2.1.2) activesupport (= 7.2.2)
timeout (>= 0.4.0) timeout (>= 0.4.0)
activestorage (7.2.1.2) activestorage (7.2.2)
actionpack (= 7.2.1.2) actionpack (= 7.2.2)
activejob (= 7.2.1.2) activejob (= 7.2.2)
activerecord (= 7.2.1.2) activerecord (= 7.2.2)
activesupport (= 7.2.1.2) activesupport (= 7.2.2)
marcel (~> 1.0) marcel (~> 1.0)
activesupport (7.2.1.2) activesupport (7.2.2)
base64 base64
benchmark (>= 0.3)
bigdecimal bigdecimal
concurrent-ruby (~> 1.0, >= 1.3.1) concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5) connection_pool (>= 2.2.5)
@ -71,8 +72,8 @@ GEM
minitest (>= 5.1) minitest (>= 5.1)
securerandom (>= 0.3) securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5) tzinfo (~> 2.0, >= 2.0.5)
acts-as-taggable-on (11.0.0) acts-as-taggable-on (12.0.0)
activerecord (>= 7.0, < 8.0) activerecord (>= 7.1, < 8.1)
zeitwerk (>= 2.4, < 3.0) zeitwerk (>= 2.4, < 3.0)
ast (2.4.2) ast (2.4.2)
babel-source (5.8.35) babel-source (5.8.35)
@ -80,6 +81,7 @@ GEM
babel-source (>= 4.0, < 6) babel-source (>= 4.0, < 6)
execjs (~> 2.0) execjs (~> 2.0)
base64 (0.2.0) base64 (0.2.0)
benchmark (0.4.0)
bigdecimal (3.1.8) bigdecimal (3.1.8)
bindex (0.8.1) bindex (0.8.1)
bootsnap (1.18.4) bootsnap (1.18.4)
@ -90,7 +92,7 @@ GEM
connection_pool (2.4.1) connection_pool (2.4.1)
crass (1.0.6) crass (1.0.6)
csv (3.3.0) csv (3.3.0)
date (3.3.4) date (3.4.0)
debug (1.9.2) debug (1.9.2)
irb (~> 1.10) irb (~> 1.10)
reline (>= 0.3.8) reline (>= 0.3.8)
@ -120,7 +122,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.7.2) json (2.7.5)
jsonapi-deserializable (0.2.0) jsonapi-deserializable (0.2.0)
jsonapi-parser (0.1.1) jsonapi-parser (0.1.1)
jsonapi-rails (0.4.1) jsonapi-rails (0.4.1)
@ -134,7 +136,7 @@ GEM
jsonapi-renderer (~> 0.2.0) jsonapi-renderer (~> 0.2.0)
language_server-protocol (3.17.0.3) language_server-protocol (3.17.0.3)
logger (1.6.1) logger (1.6.1)
loofah (2.22.0) loofah (2.23.1)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.12.0) nokogiri (>= 1.12.0)
mail (2.8.1) mail (2.8.1)
@ -143,13 +145,13 @@ GEM
net-pop net-pop
net-smtp net-smtp
marcel (1.0.4) marcel (1.0.4)
method_source (1.0.0) method_source (1.1.0)
mini_mime (1.1.5) mini_mime (1.1.5)
minitest (5.25.1) minitest (5.25.2)
money (6.19.0) money (6.19.0)
i18n (>= 0.6.4, <= 2) i18n (>= 0.6.4, <= 2)
msgpack (1.7.2) msgpack (1.7.2)
net-imap (0.4.17) net-imap (0.5.1)
date date
net-protocol net-protocol
net-pop (0.1.2) net-pop (0.1.2)
@ -158,7 +160,7 @@ GEM
timeout timeout
net-smtp (0.5.0) net-smtp (0.5.0)
net-protocol net-protocol
nio4r (2.7.3) nio4r (2.7.4)
nokogiri (1.16.7-aarch64-linux) nokogiri (1.16.7-aarch64-linux)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.16.7-arm-linux) nokogiri (1.16.7-arm-linux)
@ -172,16 +174,16 @@ GEM
nokogiri (1.16.7-x86_64-linux) nokogiri (1.16.7-x86_64-linux)
racc (~> 1.4) racc (~> 1.4)
parallel (1.26.3) parallel (1.26.3)
parser (3.3.5.0) parser (3.3.5.1)
ast (~> 2.4.1) ast (~> 2.4.1)
racc racc
pg (1.5.9) pg (1.5.9)
pry (0.14.2) pry (0.15.0)
coderay (~> 1.1) coderay (~> 1.1)
method_source (~> 1.0) method_source (~> 1.0)
psych (5.1.2) psych (5.2.0)
stringio stringio
puma (6.4.3) puma (6.5.0)
nio4r (~> 2.0) nio4r (~> 2.0)
racc (1.8.1) racc (1.8.1)
rack (3.1.8) rack (3.1.8)
@ -191,23 +193,22 @@ GEM
rack (>= 3.0.0) rack (>= 3.0.0)
rack-test (2.1.0) rack-test (2.1.0)
rack (>= 1.3) rack (>= 1.3)
rackup (2.1.0) rackup (2.2.1)
rack (>= 3) rack (>= 3)
webrick (~> 1.8) rails (7.2.2)
rails (7.2.1.2) actioncable (= 7.2.2)
actioncable (= 7.2.1.2) actionmailbox (= 7.2.2)
actionmailbox (= 7.2.1.2) actionmailer (= 7.2.2)
actionmailer (= 7.2.1.2) actionpack (= 7.2.2)
actionpack (= 7.2.1.2) actiontext (= 7.2.2)
actiontext (= 7.2.1.2) actionview (= 7.2.2)
actionview (= 7.2.1.2) activejob (= 7.2.2)
activejob (= 7.2.1.2) activemodel (= 7.2.2)
activemodel (= 7.2.1.2) activerecord (= 7.2.2)
activerecord (= 7.2.1.2) activestorage (= 7.2.2)
activestorage (= 7.2.1.2) activesupport (= 7.2.2)
activesupport (= 7.2.1.2)
bundler (>= 1.15.0) bundler (>= 1.15.0)
railties (= 7.2.1.2) railties (= 7.2.2)
rails-dom-testing (2.2.0) rails-dom-testing (2.2.0)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
minitest minitest
@ -215,9 +216,9 @@ GEM
rails-html-sanitizer (1.6.0) rails-html-sanitizer (1.6.0)
loofah (~> 2.21) loofah (~> 2.21)
nokogiri (~> 1.14) nokogiri (~> 1.14)
railties (7.2.1.2) railties (7.2.2)
actionpack (= 7.2.1.2) actionpack (= 7.2.2)
activesupport (= 7.2.1.2) activesupport (= 7.2.2)
irb (~> 1.13) irb (~> 1.13)
rackup (>= 1.0.0) rackup (>= 1.0.0)
rake (>= 12.2) rake (>= 12.2)
@ -238,7 +239,7 @@ GEM
redis-client (0.22.2) redis-client (0.22.2)
connection_pool connection_pool
regexp_parser (2.9.2) regexp_parser (2.9.2)
reline (0.5.10) reline (0.5.11)
io-console (~> 0.5) io-console (~> 0.5)
rspec-core (3.13.2) rspec-core (3.13.2)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
@ -248,7 +249,7 @@ GEM
rspec-mocks (3.13.2) rspec-mocks (3.13.2)
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 (7.0.1) rspec-rails (7.0.2)
actionpack (>= 7.0) actionpack (>= 7.0)
activesupport (>= 7.0) activesupport (>= 7.0)
railties (>= 7.0) railties (>= 7.0)
@ -257,7 +258,7 @@ GEM
rspec-mocks (~> 3.13) rspec-mocks (~> 3.13)
rspec-support (~> 3.13) rspec-support (~> 3.13)
rspec-support (3.13.1) rspec-support (3.13.1)
rubocop (1.67.0) rubocop (1.68.0)
json (~> 2.3) json (~> 2.3)
language_server-protocol (>= 3.17.0) language_server-protocol (>= 3.17.0)
parallel (~> 1.10) parallel (~> 1.10)
@ -267,12 +268,12 @@ GEM
rubocop-ast (>= 1.32.2, < 2.0) rubocop-ast (>= 1.32.2, < 2.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0) unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.32.3) rubocop-ast (1.33.0)
parser (>= 3.3.1.0) parser (>= 3.3.1.0)
ruby-progressbar (1.13.0) ruby-progressbar (1.13.0)
rubytree (2.1.0) rubytree (2.1.0)
json (~> 2.0, > 2.3.1) json (~> 2.0, > 2.3.1)
securerandom (0.3.1) securerandom (0.3.2)
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)
@ -282,10 +283,10 @@ GEM
sprockets (>= 3.0.0) sprockets (>= 3.0.0)
stimulus-rails (1.3.4) stimulus-rails (1.3.4)
railties (>= 6.0.0) railties (>= 6.0.0)
stringio (3.1.1) stringio (3.1.2)
thor (1.3.2) thor (1.3.2)
tilt (2.4.0) tilt (2.4.0)
timeout (0.4.1) timeout (0.4.2)
turbo-rails (2.0.11) turbo-rails (2.0.11)
actionpack (>= 6.0.0) actionpack (>= 6.0.0)
railties (>= 6.0.0) railties (>= 6.0.0)
@ -298,7 +299,6 @@ GEM
activemodel (>= 6.0.0) activemodel (>= 6.0.0)
bindex (>= 0.4.0) bindex (>= 0.4.0)
railties (>= 6.0.0) railties (>= 6.0.0)
webrick (1.8.2)
websocket-driver (0.7.6) websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5) websocket-extensions (0.1.5)

View File

@ -1,24 +1,87 @@
# README # Libre Wedding Planner
This README would normally document whatever steps are necessary to get the Libre Wedding Planner is Free, Open Source Software that helps organize several aspects of a wedding.
application up and running.
Things you may want to cover: The project is not production-ready yet.
* Ruby version ## Features
* System dependencies The follwing features are either developed or under active development:
* Configuration - Guests management
- Expense management
- Seating chart
* Database creation
* Database initialization ## Next steps
* How to run the test suite Some ideas we would like to implement next:
* Services (job queues, cache servers, search engines, etc.) - Authentication (required to make an instance public)
- Website with wedding information
- Attendance confirmation forms
- Multitenancy
* Deployment instructions # Development setup
Libre Wedding Planner is made of two main pieces:
- The backend (this repo), built with Ruby (on Rails)
- The frontend (repo [here](https://gitea.bustikiller.com/bustikiller/wedding-planner-frontend/)), built with NextJS and React. You will need both to have the service fully working.
Both repositories are expected to live have a common parent directory:
```
projects <or anything else>
|-> wedding-planner
|-> wedding-planner-frontend
```
## Docker compose
Docker compose is the recommended way to run Libre Wedding Planner for development purposes. After downloading both repositories, `cd` to the root of `wedding-planner` and run:
```bash
docker compose up --build
```
Several containers will be started:
- backend: starts a Rails server that will act as an API.
- workers: starts a runner of [solid queue](https://github.com/rails/solid_queue/) that takes .care of async tasks.
- frontend: starts a NextJS application in charge of the frontend.
- nginx: A reverse proxy that the backend and frontend under the same domain, and routes all requests to the upstream services.
- db: A Postgres instance used by the backend service.
The backend service will seed the database with fake data. It's worth noting that the Postgres container does not have a volume, so the application will be seeded every time the container is created.
The backend, frontend and workers have hot-reloading enabled, so changes made to the codebase should be reflected in the application on the next request.
Once all containers have started, visit http://libre-wedding-planner.app.localhost/dashboard to load the application.
## Testing
Unit tests can be executed with
```
bundle exec rspec
```
## API documentation
Generate the OpenAPI documentation with the command:
```
rake rswag:specs:swaggerize
```
The documentation is available in Swagger UI in http://libre-wedding-planner.app.localhost/api/api-docs/index.html. If testing the API through the UI, you will need to select the second server (which includes the `/api` path), intended for development.
## Contributing
Contributions of all kinds (code, UX/UI, testing, translations, etc.) are welcome. The procedures to contribute are still being defined, but don't hesitate to reach out in case you want to participate.
# License
This project is licensed under the GNU Affero General Public License (AGPL). Check [COPYING.md](./COPYING.md) for additional information.
* ...

View File

@ -1,15 +1,43 @@
# Copyright (C) 2024 Manuel Bustillo # Copyright (C) 2024 Manuel Bustillo
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
after_action :set_csrf_cookie after_action :set_csrf_cookie
private skip_before_action :verify_authenticity_token, if: :development_swagger?
def set_csrf_cookie rescue_from ActiveRecord::RecordInvalid do |exception|
cookies["csrf-token"] = { render json: {
value: form_authenticity_token, message: 'Record invalid',
secure: Rails.env.production?, errors: exception.record.errors.full_messages
same_site: :strict, }, status: :unprocessable_entity
} end
end
rescue_from ActionController::ParameterMissing do |exception|
render json: {
message: 'Parameter missing',
errors: [exception.message]
}, status: :bad_request
end
rescue_from ActiveRecord::RecordNotFound do |exception|
render json: {
message: 'Record not found',
errors: [exception.message]
}, status: :not_found
end
private
def development_swagger?
Rails.env.test? ||
Rails.env.development? && request.headers['referer'].include?('/api-docs/index.html')
end
def set_csrf_cookie
cookies['csrf-token'] = {
value: form_authenticity_token,
secure: Rails.env.production?,
same_site: :strict
}
end
end end

View File

@ -1,76 +1,22 @@
# Copyright (C) 2024 Manuel Bustillo # Copyright (C) 2024 Manuel Bustillo
class ExpensesController < ApplicationController class ExpensesController < ApplicationController
before_action :set_expense, only: %i[ show edit update destroy ]
# GET /expenses or /expenses.json
def index
@expenses = Expense.all
end
def summary def summary
render json: Expenses::TotalQuery.new.call render json: Expenses::TotalQuery.new.call
end end
# GET /expenses/1 or /expenses/1.json def index
def show render json: Expense.all.order(pricing_type: :asc, amount: :desc).as_json(only: %i[id name amount pricing_type])
end end
# GET /expenses/new
def new
@expense = Expense.new
end
# GET /expenses/1/edit
def edit
end
# POST /expenses or /expenses.json
def create
@expense = Expense.new(expense_params)
respond_to do |format|
if @expense.save
format.html { redirect_to expense_url(@expense), notice: "Expense was successfully created." }
format.json { render :show, status: :created, location: @expense }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @expense.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /expenses/1 or /expenses/1.json
def update def update
respond_to do |format| Expense.find(params[:id]).update!(expense_params)
if @expense.update(expense_params) render json: {}, status: :ok
format.html { redirect_to expense_url(@expense), notice: "Expense was successfully updated." }
format.json { render :show, status: :ok, location: @expense }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: @expense.errors, status: :unprocessable_entity }
end
end
end
# DELETE /expenses/1 or /expenses/1.json
def destroy
@expense.destroy!
respond_to do |format|
format.html { redirect_to expenses_url, notice: "Expense was successfully destroyed." }
format.json { head :no_content }
end
end end
private private
# Use callbacks to share common setup or constraints between actions.
def set_expense
@expense = Expense.find(params[:id])
end
# Only allow a list of trusted parameters through. def expense_params
def expense_params params.require(:expense).permit(:name, :amount, :pricing_type)
params.require(:expense).permit(:name, :amount, :pricing_type) end
end
end end

View File

@ -2,7 +2,6 @@
class GroupsController < ApplicationController class GroupsController < ApplicationController
def index def index
roots = Group.where(parent_id: nil) render json: Groups::SummaryQuery.new.call.as_json
render jsonapi: roots, include: [children: [children: [:children]]]
end end
end end

View File

@ -3,94 +3,31 @@
require 'csv' require 'csv'
class GuestsController < ApplicationController class GuestsController < ApplicationController
before_action :set_guest, only: %i[show edit update destroy]
# GET /guests or /guests.json
def index def index
@guests = Guest.all render json: Guest.all.includes(:group)
.joins(:group) .joins(:group)
.order('groups.name' => :asc, first_name: :asc, last_name: :asc) .order('groups.name' => :asc, name: :asc)
.as_json(only: %i[id name status], include: { group: { only: %i[id name] } })
render jsonapi: @guests
end end
# GET /guests/1 or /guests/1.json
def show; end
# GET /guests/new
def new
@guest = Guest.new
end
# GET /guests/1/edit
def edit; end
# POST /guests or /guests.json
def create def create
@guest = Guest.new(guest_params) Guest.create!(guest_params)
render json: {}, status: :created
respond_to do |format|
if @guest.save
format.html { redirect_to guest_url(@guest), notice: 'Guest was successfully created.' }
format.json { render :show, status: :created, location: @guest }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @guest.errors, status: :unprocessable_entity }
end
end
end end
# PATCH/PUT /guests/1 or /guests/1.json
def update def update
respond_to do |format| Guest.find(params[:id]).update!(guest_params)
if @guest.update(guest_params) render json: {}, status: :ok
format.html { redirect_to guest_url(@guest), notice: 'Guest was successfully updated.' }
format.json { render :show, status: :ok, location: @guest }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: @guest.errors, status: :unprocessable_entity }
end
end
end end
# DELETE /guests/1 or /guests/1.json
def destroy def destroy
@guest.destroy! Guest.find(params[:id]).destroy!
respond_to do |format|
format.html { redirect_to guests_url, notice: 'Guest was successfully destroyed.' }
format.json { head :no_content }
end
end
def import
csv = CSV.parse(params[:file].read, headers: true)
ActiveRecord::Base.transaction do
csv.each do |row|
guest = Guest.create!(first_name: row['name'])
guest.affinity_group_list.add(row['affinity_group'])
guest.save!
end
end
redirect_to guests_url
end
def bulk_update
Guest.where(id: params[:guest_ids]).update!(params.require(:properties).permit(:status))
render json: {}, status: :ok render json: {}, status: :ok
end end
private private
# Use callbacks to share common setup or constraints between actions.
def set_guest
@guest = Guest.find(params[:id])
end
# Only allow a list of trusted parameters through.
def guest_params def guest_params
params.require(:guest).permit(:first_name, :last_name, :email, :phone) params.require(:guest).permit(:name, :group_id, :status)
end end
end end

View File

@ -2,13 +2,22 @@
class TablesArrangementsController < ApplicationController class TablesArrangementsController < ApplicationController
def index def index
@tables_arrangements = TablesArrangement.all.order(discomfort: :asc).limit(10) render json: TablesArrangement.all.order(discomfort: :asc).limit(3).as_json(only: %i[id name discomfort])
end end
def show def show
@tables_arrangement = TablesArrangement.find(params[:id]) Seat.joins(guest: :group)
@seats = @tables_arrangement.seats .where(tables_arrangement_id: params[:id])
.includes(guest: %i[affinity_groups unbreakable_bonds]) .order('guests.group_id')
.group_by(&:table_number) .pluck(
:table_number,
'guests.name',
'guests.id',
'groups.color'
)
.group_by(&:first)
.transform_values { |table| table.map { |(_, name, id, color)| { id:, name:, color: } } }
.map { |number, guests| { number:, guests: } }
.then { |result| render json: result }
end end
end end

View File

@ -1,11 +1,16 @@
namespace :vns do # Copyright (C) 2024 Manuel Bustillo
task distribute_tables: :environment do
class TableSimulatorJob < ApplicationJob
queue_as :default
def perform(*_args)
engine = VNS::Engine.new engine = VNS::Engine.new
engine.add_perturbation(Tables::Swap) engine.add_perturbation(Tables::Swap)
engine.add_perturbation(Tables::Shift)
initial_solution = Tables::Distribution.new(min_per_table: 8, max_per_table: 10) initial_solution = Tables::Distribution.new(min_per_table: 8, max_per_table: 10)
initial_solution.random_distribution(Guest.all.shuffle) initial_solution.random_distribution(Guest.potential.shuffle)
engine.initial_solution = initial_solution engine.initial_solution = initial_solution

View File

@ -1,4 +1,22 @@
# Copyright (C) 2024 Manuel Bustillo # Copyright (C) 2024 Manuel Bustillo
# == Schema Information
#
# Table name: expenses
#
# id :uuid not null, primary key
# amount :decimal(, )
# name :string
# pricing_type :enum default("fixed"), not null
# created_at :datetime not null
# updated_at :datetime not null
#
class Expense < ApplicationRecord class Expense < ApplicationRecord
enum :pricing_type,
fixed: 'fixed',
per_person: 'per_person'
validates :name, presence: true
validates :amount, presence: true, numericality: { greater_than: 0 }
validates :pricing_type, presence: true
end end

View File

@ -1,5 +1,27 @@
# Copyright (C) 2024 Manuel Bustillo # Copyright (C) 2024 Manuel Bustillo
# == Schema Information
#
# Table name: groups
#
# id :uuid not null, primary key
# color :string
# icon :string
# name :string not null
# order :integer default(1), not null
# created_at :datetime not null
# updated_at :datetime not null
# parent_id :uuid
#
# Indexes
#
# index_groups_on_name (name) UNIQUE
# index_groups_on_parent_id (parent_id)
#
# Foreign Keys
#
# fk_rails_... (parent_id => groups.id)
#
class Group < ApplicationRecord class Group < ApplicationRecord
validates :name, uniqueness: true validates :name, uniqueness: true
validates :name, :order, presence: true validates :name, :order, presence: true
@ -7,5 +29,33 @@ class Group < ApplicationRecord
has_many :children, class_name: 'Group', foreign_key: 'parent_id' has_many :children, class_name: 'Group', foreign_key: 'parent_id'
belongs_to :parent, class_name: 'Group', optional: true belongs_to :parent, class_name: 'Group', optional: true
before_create :set_color
scope :roots, -> { where(parent_id: nil) }
has_many :guests has_many :guests
def colorize_children(generation = 1)
derived_colors = generation == 1 ? color.paint.palette.analogous(size: children.count) : color.paint.palette.decreasing_saturation
children.zip(derived_colors) do |child, raw_color|
final_color = raw_color.paint
final_color.brighten(60) if final_color.dark?
child.update!(color: final_color)
child.colorize_children(generation + 1)
end
end
private
def set_color
return if color.present?
new_color = "##{SecureRandom.hex(3)}".paint
new_color = new_color.lighten(30) if new_color.dark?
self.color = new_color
end
end end

View File

@ -1,18 +1,50 @@
# Copyright (C) 2024 Manuel Bustillo # Copyright (C) 2024 Manuel Bustillo
# == Schema Information
#
# Table name: guests
#
# id :uuid not null, primary key
# name :string
# phone :string
# status :integer default("considered")
# created_at :datetime not null
# updated_at :datetime not null
# group_id :uuid not null
#
# Indexes
#
# index_guests_on_group_id (group_id)
#
# Foreign Keys
#
# fk_rails_... (group_id => groups.id)
#
class Guest < ApplicationRecord class Guest < ApplicationRecord
acts_as_taggable_on :affinity_groups, :unbreakable_bonds
belongs_to :group belongs_to :group
enum status: { enum :status, {
considered: 0, considered: 0,
invited: 10, invited: 10,
confirmed: 20, confirmed: 20,
declined: 30, declined: 30,
tentative: 40, tentative: 40
} }, validate: true
def full_name validates :name, presence: true
"#{first_name} #{last_name}"
scope :potential, -> { where.not(status: %i[declined considered]) }
after_save :recalculate_simulations, if: :saved_change_to_status?
after_destroy :recalculate_simulations
has_many :seats, dependent: :delete_all
private
def recalculate_simulations
TablesArrangement.delete_all
ActiveJob.perform_all_later(50.times.map { TableSimulatorJob.new })
end end
end end

View File

@ -1,5 +1,26 @@
# Copyright (C) 2024 Manuel Bustillo # Copyright (C) 2024 Manuel Bustillo
# == Schema Information
#
# Table name: seats
#
# id :uuid not null, primary key
# table_number :integer
# created_at :datetime not null
# updated_at :datetime not null
# guest_id :uuid not null
# tables_arrangement_id :uuid not null
#
# Indexes
#
# index_seats_on_guest_id (guest_id)
# index_seats_on_tables_arrangement_id (tables_arrangement_id)
#
# Foreign Keys
#
# fk_rails_... (guest_id => guests.id)
# fk_rails_... (tables_arrangement_id => tables_arrangements.id) ON DELETE => cascade
#
class Seat < ApplicationRecord class Seat < ApplicationRecord
belongs_to :guest belongs_to :guest
belongs_to :table_arrangement belongs_to :table_arrangement

View File

@ -1,5 +1,24 @@
# Copyright (C) 2024 Manuel Bustillo # Copyright (C) 2024 Manuel Bustillo
# == Schema Information
#
# Table name: tables_arrangements
#
# id :uuid not null, primary key
# discomfort :integer
# name :string not null
# created_at :datetime not null
# updated_at :datetime not null
#
class TablesArrangement < ApplicationRecord class TablesArrangement < ApplicationRecord
has_many :seats has_many :seats
has_many :guests, through: :seats
before_create :assign_name
private
def assign_name
self.name = "#{Faker::Adjective.positive} #{Faker::Creature::Animal.name}".capitalize
end
end end

View File

@ -0,0 +1,31 @@
# Copyright (C) 2024 Manuel Bustillo
module Groups
class SummaryQuery
def call
ActiveRecord::Base.connection.execute(query).to_a
end
private
def query
<<~SQL.squish
SELECT
groups.id,
groups.name,
groups.icon,
groups.parent_id,
groups.color,
count(*) filter (where status IS NOT NULL) as total,
count(*) filter (where status = 0) as considered,
count(*) filter (where status = 10) as invited,
count(*) filter (where status = 20) as confirmed,
count(*) filter (where status = 30) as declined,
count(*) filter (where status = 40) as tentative
FROM groups
LEFT JOIN guests on groups.id = guests.group_id
GROUP BY groups.id
SQL
end
end
end

View File

@ -3,10 +3,10 @@
class SerializableGuest < JSONAPI::Serializable::Resource class SerializableGuest < JSONAPI::Serializable::Resource
type 'guest' type 'guest'
attributes :id, :email, :group_id, :status attributes :id, :group_id, :status
attribute :name do attribute :name do
"#{@object.first_name} #{@object.last_name}" @object.name
end end
attribute :group_name do attribute :group_name do

View File

@ -6,24 +6,40 @@ class AffinityGroupsHierarchy < Array
def initialize def initialize
super super
@references = {} @references = {}
Group.roots.each do |group|
self << group.id
hydrate(group)
end
end end
def find(name) def find(id)
@references[name] @references[id]
end end
def <<(name) def <<(id)
new_node = Tree::TreeNode.new(name) new_node = Tree::TreeNode.new(id)
super(new_node).tap { @references[name] = new_node } super(new_node).tap { @references[id] = new_node }
end end
def register_child(parent_name, child_name) def register_child(parent_id, child_id)
@references[parent_name] << Tree::TreeNode.new(child_name).tap { |child_node| @references[child_name] = child_node } @references[parent_id] << Tree::TreeNode.new(child_id).tap { |child_node| @references[child_id] = child_node }
end end
def distance(name_a, name_b) def distance(id_a, id_b)
return nil if @references[name_a].nil? || @references[name_b].nil? return nil if @references[id_a].nil? || @references[id_b].nil?
@references[name_a].distance_to_common_ancestor(@references[name_b]) @references[id_a].distance_to_common_ancestor(@references[id_b])
end
private
def hydrate(group)
group.children.each do |child|
register_child(group.id, child.id)
hydrate(child)
end
end end
end end

View File

@ -3,18 +3,40 @@
module Tables module Tables
class DiscomfortCalculator class DiscomfortCalculator
private attr_reader :table private attr_reader :table
def initialize(table) def initialize(table:)
@table = table @table = table
end end
def calculate def calculate
cohesion_penalty table_size_penalty + 10 * (cohesion_penalty * 1.0 / table.size)
end end
private private
#
# Calculates the penalty associated with violating the table size constraints. The penalty is
# zero when the limits are honored, and it increases linearly as the number of guests deviates
# from the limits. Overcapacity is penalized more severely than undercapacity.
#
# @return [Number] The penalty associated with violating the table size constraints.
#
def table_size_penalty
case table.size
when 0...table.min_per_table then 5 * (table.min_per_table - table.size)
when table.min_per_table..table.max_per_table then 0
else 5 * (table.size - table.max_per_table)
end
end
#
# 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
# guests is a rational number between 1 (unrelated groups) and 0 (same group).
#
# @return [Number] Total discomfort of the table.
#
def cohesion_penalty def cohesion_penalty
table.map { |guest| guest.affinity_group_list.first }.tally.to_a.combination(2).sum do |(a, count_a), (b, count_b)| table.map(&:group_id).tally.to_a.combination(2).sum do |(a, count_a), (b, count_b)|
distance = AffinityGroupsHierarchy.instance.distance(a, b) distance = AffinityGroupsHierarchy.instance.distance(a, b)
next count_a * count_b if distance.nil? next count_a * count_b if distance.nil?

View File

@ -4,7 +4,7 @@ require_relative '../../extensions/tree_node_extension'
module Tables module Tables
class Distribution class Distribution
attr_accessor :tables attr_accessor :tables, :min_per_table, :max_per_table
def initialize(min_per_table:, max_per_table:) def initialize(min_per_table:, max_per_table:)
@min_per_table = min_per_table @min_per_table = min_per_table
@ -13,9 +13,12 @@ module Tables
end end
def random_distribution(people) def random_distribution(people)
@tables = [] min_tables = (people.count * 1.0 / @max_per_table).ceil
max_tables = (people.count * 1.0 / @min_per_table).ceil
@tables << Table.new(people.slice!(0..rand(@min_per_table..@max_per_table))) while people.any? @tables = people.in_groups(rand(min_tables..max_tables), false)
.map { |group| Table.new(group) }
.each { |table| table.min_per_table = @min_per_table }
.each { |table| table.max_per_table = @max_per_table }
end end
def discomfort def discomfort
@ -30,7 +33,7 @@ module Tables
def pretty_print def pretty_print
@tables.map.with_index do |table, i| @tables.map.with_index do |table, i|
"Table #{i + 1} (#{table.count} ppl): (#{local_discomfort(table)}) #{table.map(&:full_name).join(', ')}" "Table #{i + 1} (#{table.count} ppl): (#{local_discomfort(table)}) #{table.map(&:name).join(', ')}"
end.join("\n") end.join("\n")
end end
@ -61,7 +64,7 @@ module Tables
private private
def local_discomfort(table) def local_discomfort(table)
table.discomfort ||= DiscomfortCalculator.new(table).calculate table.discomfort ||= DiscomfortCalculator.new(table:).calculate
end end
end end
end end

View File

@ -0,0 +1,30 @@
# Copyright (C) 2024 Manuel Bustillo
module Tables
class Shift
private attr_reader :initial_solution
def initialize(initial_solution)
@initial_solution = initial_solution
end
def each
@initial_solution.tables.permutation(2) do |table_a, table_b|
table_a.dup.each do |person|
original_discomfort_a = table_a.reset
original_discomfort_b = table_b.reset
table_a.delete(person)
table_b << person
yield(@initial_solution)
ensure
table_b.delete(person)
table_a << person
table_a.discomfort = original_discomfort_a
table_b.discomfort = original_discomfort_b
end
end
end
end
end

View File

@ -9,7 +9,7 @@ module Tables
def each def each
@initial_solution.tables.combination(2) do |table_a, table_b| @initial_solution.tables.combination(2) do |table_a, table_b|
table_a.product(table_b).each do |(person_a, person_b)| table_a.to_a.product(table_b.to_a).each do |(person_a, person_b)|
original_discomfort_a = table_a.reset original_discomfort_a = table_a.reset
original_discomfort_b = table_b.reset original_discomfort_b = table_b.reset

View File

@ -1,8 +1,9 @@
# Copyright (C) 2024 Manuel Bustillo # Copyright (C) 2024 Manuel Bustillo
module Tables module Tables
class Table < Array class Table < Set
attr_accessor :discomfort attr_accessor :discomfort, :min_per_table, :max_per_table
def initialize(*args) def initialize(*args)
super super
reset reset

View File

@ -2,6 +2,13 @@
module VNS module VNS
class Engine class Engine
class << self
def sequence(elements)
elements = elements.to_a
(elements + elements.reverse).chunk(&:itself).map(&:first)
end
end
def target_function(&function) def target_function(&function)
@target_function = function @target_function = function
end end
@ -23,7 +30,7 @@ module VNS
puts "Initial score: #{@best_score.to_f}" puts "Initial score: #{@best_score.to_f}"
@perturbations.each do |perturbation| self.class.sequence(@perturbations).each do |perturbation|
puts "Running perturbation: #{perturbation.name}" puts "Running perturbation: #{perturbation.name}"
optimize(perturbation.new(@best_solution)) optimize(perturbation.new(@best_solution))
end end

View File

@ -1,19 +0,0 @@
<%# Copyright (C) 2024 Manuel Bustillo %>
<div id="<%= dom_id expense %>">
<p>
<strong>Name:</strong>
<%= expense.name %>
</p>
<p>
<strong>Amount:</strong>
<%= expense.amount %>
</p>
<p>
<strong>Pricing type:</strong>
<%= expense.pricing_type %>
</p>
</div>

View File

@ -1,34 +0,0 @@
<%# Copyright (C) 2024 Manuel Bustillo %>
<%= form_with(model: expense) do |form| %>
<% if expense.errors.any? %>
<div style="color: red">
<h2><%= pluralize(expense.errors.count, "error") %> prohibited this expense from being saved:</h2>
<ul>
<% expense.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div>
<%= form.label :name, style: "display: block" %>
<%= form.text_field :name %>
</div>
<div>
<%= form.label :amount, style: "display: block" %>
<%= form.text_field :amount %>
</div>
<div>
<%= form.label :pricing_type, style: "display: block" %>
<%= form.text_field :pricing_type %>
</div>
<div>
<%= form.submit %>
</div>
<% end %>

View File

@ -1,12 +0,0 @@
<%# Copyright (C) 2024 Manuel Bustillo %>
<h1>Editing expense</h1>
<%= render "form", expense: @expense %>
<br>
<div>
<%= link_to "Show this expense", @expense %> |
<%= link_to "Back to expenses", expenses_path %>
</div>

View File

@ -1,30 +0,0 @@
<%# Copyright (C) 2024 Manuel Bustillo %>
<p style="color: green"><%= notice %></p>
<h1>Expenses</h1>
<div id="expenses">
<table>
<tr>
<th>Name</th>
<th>Amount</th>
<th colspan="2"></th>
</tr>
<% @expenses.each do |expense| %>
<tr>
<td><%= expense.name %></td>
<td><%= expense.amount.to_currency %></td>
<td><%= link_to "Show", expense %></td>
<td><%= link_to "Edit", edit_expense_path(expense) %></td>
</tr>
<% end %>
<tr>
<td>Total</td>
<td><%= @expenses.sum(&:amount).to_currency %></td>
<td colspan="2"></td>
</tr>
</table>
</div>
<%= link_to "New expense", new_expense_path %>

View File

@ -1,11 +0,0 @@
<%# Copyright (C) 2024 Manuel Bustillo %>
<h1>New expense</h1>
<%= render "form", expense: @expense %>
<br>
<div>
<%= link_to "Back to expenses", expenses_path %>
</div>

View File

@ -1,12 +0,0 @@
<%# Copyright (C) 2024 Manuel Bustillo %>
<p style="color: green"><%= notice %></p>
<%= render @expense %>
<div>
<%= link_to "Edit this expense", edit_expense_path(@expense) %> |
<%= link_to "Back to expenses", expenses_path %>
<%= button_to "Destroy this expense", @expense, method: :delete %>
</div>

View File

@ -1,39 +0,0 @@
<%# Copyright (C) 2024 Manuel Bustillo %>
<%= form_with(model: guest) do |form| %>
<% if guest.errors.any? %>
<div style="color: red">
<h2><%= pluralize(guest.errors.count, "error") %> prohibited this guest from being saved:</h2>
<ul>
<% guest.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div>
<%= form.label :first_name, style: "display: block" %>
<%= form.text_field :first_name %>
</div>
<div>
<%= form.label :last_name, style: "display: block" %>
<%= form.text_field :last_name %>
</div>
<div>
<%= form.label :email, style: "display: block" %>
<%= form.text_field :email %>
</div>
<div>
<%= form.label :phone, style: "display: block" %>
<%= form.text_field :phone %>
</div>
<div>
<%= form.submit %>
</div>
<% end %>

View File

@ -1,24 +0,0 @@
<%# Copyright (C) 2024 Manuel Bustillo %>
<div id="<%= dom_id guest %>">
<p>
<strong>First name:</strong>
<%= guest.first_name %>
</p>
<p>
<strong>Last name:</strong>
<%= guest.last_name %>
</p>
<p>
<strong>Email:</strong>
<%= guest.email %>
</p>
<p>
<strong>Phone:</strong>
<%= guest.phone %>
</p>
</div>

View File

@ -1,12 +0,0 @@
<%# Copyright (C) 2024 Manuel Bustillo %>
<h1>Editing guest</h1>
<%= render "form", guest: @guest %>
<br>
<div>
<%= link_to "Show this guest", @guest %> |
<%= link_to "Back to guests", guests_path %>
</div>

View File

@ -1,39 +0,0 @@
<%# Copyright (C) 2024 Manuel Bustillo %>
<p style="color: green"><%= notice %></p>
<h1>Guests</h1>
<div id="guests">
<table>
<tr>
<th>Row #</th>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>Affinity groups</th>
<th>Unbreakable bonds</th>
<th colspan="2"></th>
</tr>
<% @guests.each_with_index do |guest, i| %>
<tr>
<td><%= i + 1 %></td>
<td><%= guest.full_name %></td>
<td><%= guest.email %></td>
<td><%= guest.phone %></td>
<td><%= guest.affinity_groups.pluck(:name).join(", ") %></td>
<td><%= guest.unbreakable_bonds.pluck(:name).join(", ") %></td>
<td><%= link_to "Show", guest %></td>
<td><%= link_to "Edit", edit_guest_path(guest) %></td>
</tr>
<% end %>
</table>
</div>
<%= link_to "New guest", new_guest_path %>
<%= form_with url: import_guests_path, method: :post do |form| %>
<%= form.label :file %>
<%= form.file_field :file %>
<%= form.submit "Import" %>
<% end %>

View File

@ -1,11 +0,0 @@
<%# Copyright (C) 2024 Manuel Bustillo %>
<h1>New guest</h1>
<%= render "form", guest: @guest %>
<br>
<div>
<%= link_to "Back to guests", guests_path %>
</div>

View File

@ -1,12 +0,0 @@
<%# Copyright (C) 2024 Manuel Bustillo %>
<p style="color: green"><%= notice %></p>
<%= render @guest %>
<div>
<%= link_to "Edit this guest", edit_guest_path(@guest) %> |
<%= link_to "Back to guests", guests_path %>
<%= button_to "Destroy this guest", @guest, method: :delete %>
</div>

View File

@ -1,18 +0,0 @@
<%# Copyright (C) 2024 Manuel Bustillo %>
<!DOCTYPE html>
<html>
<head>
<title>WeddingPlanner</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
</head>
<body>
<%= yield %>
</body>
</html>

View File

@ -1,11 +0,0 @@
<%# Copyright (C) 2024 Manuel Bustillo %>
<h1>Tables arrangements</h1>
<ol>
<% @tables_arrangements.each_with_index do |tables_arrangement, i| %>
<li>
<p><%= link_to "Arrangement ##{i+1}", tables_arrangement_path(tables_arrangement) %> Discomfort: <%= tables_arrangement.discomfort %></p>
</li>
<% end %>
</ol>

View File

@ -1,18 +0,0 @@
<%# Copyright (C) 2024 Manuel Bustillo %>
<h1>ID: <%= @tables_arrangement.id %></h1>
<p>Discomfort: <%= @tables_arrangement.discomfort %></p>
<h2>Seats</h2>
<% @seats.each do |table_number, seats| %>
<h3>Table <%= table_number %></h3>
<ul>
<% seats.each do |seat| %>
<li><%= seat.guest.full_name %> (<%= seat.guest.affinity_groups.pluck(:name).join(", ") %>)</li>
<% end %>
</ul>
<% end %>

6
bin/jobs Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env ruby
require_relative "../config/environment"
require "solid_queue/cli"
SolidQueue::Cli.start(ARGV)

View File

@ -30,6 +30,9 @@ module WeddingPlanner
# Common ones are `templates`, `generators`, or `middleware`, for example. # Common ones are `templates`, `generators`, or `middleware`, for example.
config.autoload_lib(ignore: %w[assets tasks]) config.autoload_lib(ignore: %w[assets tasks])
# Use a real queuing backend for Active Job (and separate queues per environment).
config.active_job.queue_adapter = :solid_queue
# Configuration for the application, engines, and railties goes here. # Configuration for the application, engines, and railties goes here.
# #
# These settings can be overridden in specific environments using the files # These settings can be overridden in specific environments using the files

View File

@ -69,8 +69,6 @@ Rails.application.configure do
# Use a different cache store in production. # Use a different cache store in production.
# config.cache_store = :mem_cache_store # config.cache_store = :mem_cache_store
# Use a real queuing backend for Active Job (and separate queues per environment).
# config.active_job.queue_adapter = :resque
# 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

View File

@ -1,41 +0,0 @@
# Copyright (C) 2024 Manuel Bustillo
require_relative '../../app/services/affinity_groups_hierarchy'
hierarchy = AffinityGroupsHierarchy.instance
hierarchy << 'guests_a'
hierarchy << 'guests_b'
hierarchy << 'common_guests'
hierarchy.register_child('guests_a', 'family_a')
hierarchy.register_child('family_a', 'close_family_a')
hierarchy.register_child('family_a', 'cousins_a')
hierarchy.register_child('family_a', 'relatives_a')
hierarchy.register_child('guests_a', 'work_a')
hierarchy.register_child('work_a', 'besties_work_a')
hierarchy.register_child('guests_a', 'friends_a')
hierarchy.register_child('friends_a', 'college_friends_a')
hierarchy.register_child('friends_a', 'high_school_friends_a')
hierarchy.register_child('friends_a', 'childhood_friends_a')
hierarchy.register_child('guests_a', 'sports_a')
hierarchy.register_child('sports_a', 'basket_team_a')
hierarchy.register_child('sports_a', 'football_team_a')
hierarchy.register_child('guests_b', 'family_b')
hierarchy.register_child('family_b', 'close_family_b')
hierarchy.register_child('family_b', 'cousins_b')
hierarchy.register_child('family_b', 'relatives_b')
hierarchy.register_child('guests_b', 'work_b')
hierarchy.register_child('work_b', 'besties_work_b')
hierarchy.register_child('guests_b', 'friends_b')
hierarchy.register_child('friends_b', 'college_friends_b')
hierarchy.register_child('friends_b', 'high_school_friends_b')
hierarchy.register_child('friends_b', 'childhood_friends_b')
hierarchy.register_child('common_guests', 'dance_club')

View File

@ -0,0 +1,8 @@
# Copyright (C) 2024 Manuel Bustillo
Chroma.define_palette :decreasing_saturation do
spin(20).desaturate(40)
spin(-20).desaturate(40)
spin(40).desaturate(40)
spin(-40).desaturate(40)
end

View File

@ -0,0 +1,16 @@
# Copyright (C) 2024 Manuel Bustillo
Rswag::Api.configure do |c|
# Specify a root folder where Swagger JSON files are located
# This is used by the Swagger middleware to serve requests for API descriptions
# NOTE: If you're using rswag-specs to generate Swagger, you'll need to ensure
# that it's configured to generate files in the same folder
c.openapi_root = Rails.root.to_s + '/swagger'
# Inject a lambda function to alter the returned Swagger prior to serialization
# The function will have access to the rack env for the current request
# For example, you could leverage this to dynamically assign the "host" property
#
#c.swagger_filter = lambda { |swagger, env| swagger['host'] = env['HTTP_HOST'] }
end

View File

@ -0,0 +1,18 @@
# Copyright (C) 2024 Manuel Bustillo
Rswag::Ui.configure do |c|
# List the Swagger endpoints that you want to be documented through the
# swagger-ui. The first parameter is the path (absolute or relative to the UI
# host) to the corresponding endpoint and the second is a title that will be
# displayed in the document selector.
# NOTE: If you're using rspec-api to expose Swagger files
# (under openapi_root) as JSON or YAML endpoints, then the list below should
# correspond to the relative paths for those endpoints.
c.swagger_endpoint '/api/api-docs/v1/swagger.yaml', 'API V1 Docs'
# Add Basic Auth in case your API is private
# c.basic_auth_enabled = true
# c.basic_auth_credentials 'username', 'password'
end

View File

@ -6,7 +6,7 @@ class Numeric
end end
end end
class Array class Set
def to_table def to_table
Tables::Table.new(self) Tables::Table.new(self)
end end

18
config/queue.yml Normal file
View File

@ -0,0 +1,18 @@
default: &default
dispatchers:
- polling_interval: 1
batch_size: 500
workers:
- queues: "*"
threads: 3
processes: <%= ENV.fetch("JOB_CONCURRENCY", 1) %>
polling_interval: 0.1
development:
<<: *default
test:
<<: *default
production:
<<: *default

10
config/recurring.yml Normal file
View File

@ -0,0 +1,10 @@
# production:
# periodic_cleanup:
# class: CleanSoftDeletedRecordsJob
# queue: background
# args: [ 1000, { batch_size: 500 } ]
# schedule: every hour
# periodic_command:
# command: "SoftDeletedRecord.due.delete_all"
# priority: 2
# schedule: at 5am every day

View File

@ -1,15 +1,16 @@
# Copyright (C) 2024 Manuel Bustillo # Copyright (C) 2024 Manuel Bustillo
Rails.application.routes.draw do Rails.application.routes.draw do
mount Rswag::Ui::Engine => '/api-docs'
mount Rswag::Api::Engine => '/api-docs'
resources :groups, only: :index resources :groups, only: :index
resources :guests do resources :guests, only: %i[index create update destroy] do
post :import, on: :collection
post :bulk_update, on: :collection post :bulk_update, on: :collection
end end
resources :expenses do resources :expenses, only: %i[index update] do
get :summary, on: :collection get :summary, on: :collection
end end
resources :tables_arrangements, only: [:index, :show] resources :tables_arrangements, only: %i[index show]
get 'up' => 'rails/health#show', as: :rails_health_check get 'up' => 'rails/health#show', as: :rails_health_check
end end

View File

@ -0,0 +1,37 @@
# Copyright (C) 2024 Manuel Bustillo
class DropTaggableTables < ActiveRecord::Migration[7.2]
def change
drop_table 'taggings', force: :cascade do |t|
t.bigint 'tag_id'
t.string 'taggable_type'
t.uuid 'taggable_id'
t.string 'tagger_type'
t.bigint 'tagger_id'
t.string 'context', limit: 128
t.datetime 'created_at', precision: nil
t.string 'tenant', limit: 128
t.index ['context'], name: 'index_taggings_on_context'
t.index %w[tag_id taggable_id taggable_type context tagger_id tagger_type], name: 'taggings_idx',
unique: true
t.index ['tag_id'], name: 'index_taggings_on_tag_id'
t.index %w[taggable_id taggable_type context], name: 'taggings_taggable_context_idx'
t.index %w[taggable_id taggable_type tagger_id context], name: 'taggings_idy'
t.index ['taggable_id'], name: 'index_taggings_on_taggable_id'
t.index %w[taggable_type taggable_id], name: 'index_taggings_on_taggable_type_and_taggable_id'
t.index ['taggable_type'], name: 'index_taggings_on_taggable_type'
t.index %w[tagger_id tagger_type], name: 'index_taggings_on_tagger_id_and_tagger_type'
t.index ['tagger_id'], name: 'index_taggings_on_tagger_id'
t.index %w[tagger_type tagger_id], name: 'index_taggings_on_tagger_type_and_tagger_id'
t.index ['tenant'], name: 'index_taggings_on_tenant'
end
drop_table "tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "taggings_count", default: 0
t.index ["name"], name: "index_tags_on_name", unique: true
end
end
end

View File

@ -0,0 +1,7 @@
# Copyright (C) 2024 Manuel Bustillo
class AddNameToTablesArrangements < ActiveRecord::Migration[7.2]
def change
add_column :tables_arrangements, :name, :string, null: false
end
end

View File

@ -0,0 +1,134 @@
# Copyright (C) 2024 Manuel Bustillo
class SolidQueueInstall < ActiveRecord::Migration[7.2]
def change
create_table 'solid_queue_blocked_executions', force: :cascade do |t|
t.bigint 'job_id', null: false
t.string 'queue_name', null: false
t.integer 'priority', default: 0, null: false
t.string 'concurrency_key', null: false
t.datetime 'expires_at', null: false
t.datetime 'created_at', null: false
t.index %w[concurrency_key priority job_id], name: 'index_solid_queue_blocked_executions_for_release'
t.index %w[expires_at concurrency_key], name: 'index_solid_queue_blocked_executions_for_maintenance'
t.index ['job_id'], name: 'index_solid_queue_blocked_executions_on_job_id', unique: true
end
create_table 'solid_queue_claimed_executions', force: :cascade do |t|
t.bigint 'job_id', null: false
t.bigint 'process_id'
t.datetime 'created_at', null: false
t.index ['job_id'], name: 'index_solid_queue_claimed_executions_on_job_id', unique: true
t.index %w[process_id job_id], name: 'index_solid_queue_claimed_executions_on_process_id_and_job_id'
end
create_table 'solid_queue_failed_executions', force: :cascade do |t|
t.bigint 'job_id', null: false
t.text 'error'
t.datetime 'created_at', null: false
t.index ['job_id'], name: 'index_solid_queue_failed_executions_on_job_id', unique: true
end
create_table 'solid_queue_jobs', force: :cascade do |t|
t.string 'queue_name', null: false
t.string 'class_name', null: false
t.text 'arguments'
t.integer 'priority', default: 0, null: false
t.string 'active_job_id'
t.datetime 'scheduled_at'
t.datetime 'finished_at'
t.string 'concurrency_key'
t.datetime 'created_at', null: false
t.datetime 'updated_at', null: false
t.index ['active_job_id'], name: 'index_solid_queue_jobs_on_active_job_id'
t.index ['class_name'], name: 'index_solid_queue_jobs_on_class_name'
t.index ['finished_at'], name: 'index_solid_queue_jobs_on_finished_at'
t.index %w[queue_name finished_at], name: 'index_solid_queue_jobs_for_filtering'
t.index %w[scheduled_at finished_at], name: 'index_solid_queue_jobs_for_alerting'
end
create_table 'solid_queue_pauses', force: :cascade do |t|
t.string 'queue_name', null: false
t.datetime 'created_at', null: false
t.index ['queue_name'], name: 'index_solid_queue_pauses_on_queue_name', unique: true
end
create_table 'solid_queue_processes', force: :cascade do |t|
t.string 'kind', null: false
t.datetime 'last_heartbeat_at', null: false
t.bigint 'supervisor_id'
t.integer 'pid', null: false
t.string 'hostname'
t.text 'metadata'
t.datetime 'created_at', null: false
t.string 'name', null: false
t.index ['last_heartbeat_at'], name: 'index_solid_queue_processes_on_last_heartbeat_at'
t.index %w[name supervisor_id], name: 'index_solid_queue_processes_on_name_and_supervisor_id', unique: true
t.index ['supervisor_id'], name: 'index_solid_queue_processes_on_supervisor_id'
end
create_table 'solid_queue_ready_executions', force: :cascade do |t|
t.bigint 'job_id', null: false
t.string 'queue_name', null: false
t.integer 'priority', default: 0, null: false
t.datetime 'created_at', null: false
t.index ['job_id'], name: 'index_solid_queue_ready_executions_on_job_id', unique: true
t.index %w[priority job_id], name: 'index_solid_queue_poll_all'
t.index %w[queue_name priority job_id], name: 'index_solid_queue_poll_by_queue'
end
create_table 'solid_queue_recurring_executions', force: :cascade do |t|
t.bigint 'job_id', null: false
t.string 'task_key', null: false
t.datetime 'run_at', null: false
t.datetime 'created_at', null: false
t.index ['job_id'], name: 'index_solid_queue_recurring_executions_on_job_id', unique: true
t.index %w[task_key run_at], name: 'index_solid_queue_recurring_executions_on_task_key_and_run_at',
unique: true
end
create_table 'solid_queue_recurring_tasks', force: :cascade do |t|
t.string 'key', null: false
t.string 'schedule', null: false
t.string 'command', limit: 2048
t.string 'class_name'
t.text 'arguments'
t.string 'queue_name'
t.integer 'priority', default: 0
t.boolean 'static', default: true, null: false
t.text 'description'
t.datetime 'created_at', null: false
t.datetime 'updated_at', null: false
t.index ['key'], name: 'index_solid_queue_recurring_tasks_on_key', unique: true
t.index ['static'], name: 'index_solid_queue_recurring_tasks_on_static'
end
create_table 'solid_queue_scheduled_executions', force: :cascade do |t|
t.bigint 'job_id', null: false
t.string 'queue_name', null: false
t.integer 'priority', default: 0, null: false
t.datetime 'scheduled_at', null: false
t.datetime 'created_at', null: false
t.index ['job_id'], name: 'index_solid_queue_scheduled_executions_on_job_id', unique: true
t.index %w[scheduled_at priority job_id], name: 'index_solid_queue_dispatch_all'
end
create_table 'solid_queue_semaphores', force: :cascade do |t|
t.string 'key', null: false
t.integer 'value', default: 1, null: false
t.datetime 'expires_at', null: false
t.datetime 'created_at', null: false
t.datetime 'updated_at', null: false
t.index ['expires_at'], name: 'index_solid_queue_semaphores_on_expires_at'
t.index %w[key value], name: 'index_solid_queue_semaphores_on_key_and_value'
t.index ['key'], name: 'index_solid_queue_semaphores_on_key', unique: true
end
add_foreign_key 'solid_queue_blocked_executions', 'solid_queue_jobs', column: 'job_id', on_delete: :cascade
add_foreign_key 'solid_queue_claimed_executions', 'solid_queue_jobs', column: 'job_id', on_delete: :cascade
add_foreign_key 'solid_queue_failed_executions', 'solid_queue_jobs', column: 'job_id', on_delete: :cascade
add_foreign_key 'solid_queue_ready_executions', 'solid_queue_jobs', column: 'job_id', on_delete: :cascade
add_foreign_key 'solid_queue_recurring_executions', 'solid_queue_jobs', column: 'job_id', on_delete: :cascade
add_foreign_key 'solid_queue_scheduled_executions', 'solid_queue_jobs', column: 'job_id', on_delete: :cascade
end
end

View File

@ -0,0 +1,7 @@
# Copyright (C) 2024 Manuel Bustillo
class RemoveEmailFromGuests < ActiveRecord::Migration[7.2]
def change
remove_column :guests, :email, :string
end
end

View File

@ -0,0 +1,7 @@
# Copyright (C) 2024 Manuel Bustillo
class AddColorToGroup < ActiveRecord::Migration[7.2]
def change
add_column :groups, :color, :string
end
end

View File

@ -0,0 +1,19 @@
# Copyright (C) 2024 Manuel Bustillo
class MergeGuestNames < ActiveRecord::Migration[8.0]
def change
add_column :guests, :name, :string
reversible do |dir|
dir.up do
execute <<~SQL
UPDATE guests
SET name = CONCAT(first_name, ' ', last_name)
SQL
end
end
remove_column :guests, :first_name, :string
remove_column :guests, :last_name, :string
end
end

4
db/queue_schema.rb Normal file
View File

@ -0,0 +1,4 @@
# Copyright (C) 2024 Manuel Bustillo
ActiveRecord::Schema[7.1].define(version: 1) do
end

169
db/schema.rb generated
View File

@ -12,9 +12,9 @@
# #
# 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[7.1].define(version: 2024_08_11_170021) do ActiveRecord::Schema[8.0].define(version: 2024_11_11_063741) 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 "plpgsql" enable_extension "pg_catalog.plpgsql"
# Custom types defined in this database. # Custom types defined in this database.
# Note that some types may not work with other database engines. Be careful if changing database. # Note that some types may not work with other database engines. Be careful if changing database.
@ -35,19 +35,18 @@ ActiveRecord::Schema[7.1].define(version: 2024_08_11_170021) do
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.uuid "parent_id" t.uuid "parent_id"
t.string "color"
t.index ["name"], name: "index_groups_on_name", unique: true t.index ["name"], name: "index_groups_on_name", unique: true
t.index ["parent_id"], name: "index_groups_on_parent_id" t.index ["parent_id"], name: "index_groups_on_parent_id"
end end
create_table "guests", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| create_table "guests", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "phone" t.string "phone"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.uuid "group_id", null: false t.uuid "group_id", null: false
t.integer "status", default: 0 t.integer "status", default: 0
t.string "name"
t.index ["group_id"], name: "index_guests_on_group_id" t.index ["group_id"], name: "index_guests_on_group_id"
end end
@ -61,46 +60,142 @@ ActiveRecord::Schema[7.1].define(version: 2024_08_11_170021) do
t.index ["tables_arrangement_id"], name: "index_seats_on_tables_arrangement_id" t.index ["tables_arrangement_id"], name: "index_seats_on_tables_arrangement_id"
end end
create_table "solid_queue_blocked_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "queue_name", null: false
t.integer "priority", default: 0, null: false
t.string "concurrency_key", null: false
t.datetime "expires_at", null: false
t.datetime "created_at", null: false
t.index ["concurrency_key", "priority", "job_id"], name: "index_solid_queue_blocked_executions_for_release"
t.index ["expires_at", "concurrency_key"], name: "index_solid_queue_blocked_executions_for_maintenance"
t.index ["job_id"], name: "index_solid_queue_blocked_executions_on_job_id", unique: true
end
create_table "solid_queue_claimed_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.bigint "process_id"
t.datetime "created_at", null: false
t.index ["job_id"], name: "index_solid_queue_claimed_executions_on_job_id", unique: true
t.index ["process_id", "job_id"], name: "index_solid_queue_claimed_executions_on_process_id_and_job_id"
end
create_table "solid_queue_failed_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.text "error"
t.datetime "created_at", null: false
t.index ["job_id"], name: "index_solid_queue_failed_executions_on_job_id", unique: true
end
create_table "solid_queue_jobs", force: :cascade do |t|
t.string "queue_name", null: false
t.string "class_name", null: false
t.text "arguments"
t.integer "priority", default: 0, null: false
t.string "active_job_id"
t.datetime "scheduled_at"
t.datetime "finished_at"
t.string "concurrency_key"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["active_job_id"], name: "index_solid_queue_jobs_on_active_job_id"
t.index ["class_name"], name: "index_solid_queue_jobs_on_class_name"
t.index ["finished_at"], name: "index_solid_queue_jobs_on_finished_at"
t.index ["queue_name", "finished_at"], name: "index_solid_queue_jobs_for_filtering"
t.index ["scheduled_at", "finished_at"], name: "index_solid_queue_jobs_for_alerting"
end
create_table "solid_queue_pauses", force: :cascade do |t|
t.string "queue_name", null: false
t.datetime "created_at", null: false
t.index ["queue_name"], name: "index_solid_queue_pauses_on_queue_name", unique: true
end
create_table "solid_queue_processes", force: :cascade do |t|
t.string "kind", null: false
t.datetime "last_heartbeat_at", null: false
t.bigint "supervisor_id"
t.integer "pid", null: false
t.string "hostname"
t.text "metadata"
t.datetime "created_at", null: false
t.string "name", null: false
t.index ["last_heartbeat_at"], name: "index_solid_queue_processes_on_last_heartbeat_at"
t.index ["name", "supervisor_id"], name: "index_solid_queue_processes_on_name_and_supervisor_id", unique: true
t.index ["supervisor_id"], name: "index_solid_queue_processes_on_supervisor_id"
end
create_table "solid_queue_ready_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "queue_name", null: false
t.integer "priority", default: 0, null: false
t.datetime "created_at", null: false
t.index ["job_id"], name: "index_solid_queue_ready_executions_on_job_id", unique: true
t.index ["priority", "job_id"], name: "index_solid_queue_poll_all"
t.index ["queue_name", "priority", "job_id"], name: "index_solid_queue_poll_by_queue"
end
create_table "solid_queue_recurring_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "task_key", null: false
t.datetime "run_at", null: false
t.datetime "created_at", null: false
t.index ["job_id"], name: "index_solid_queue_recurring_executions_on_job_id", unique: true
t.index ["task_key", "run_at"], name: "index_solid_queue_recurring_executions_on_task_key_and_run_at", unique: true
end
create_table "solid_queue_recurring_tasks", force: :cascade do |t|
t.string "key", null: false
t.string "schedule", null: false
t.string "command", limit: 2048
t.string "class_name"
t.text "arguments"
t.string "queue_name"
t.integer "priority", default: 0
t.boolean "static", default: true, null: false
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["key"], name: "index_solid_queue_recurring_tasks_on_key", unique: true
t.index ["static"], name: "index_solid_queue_recurring_tasks_on_static"
end
create_table "solid_queue_scheduled_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "queue_name", null: false
t.integer "priority", default: 0, null: false
t.datetime "scheduled_at", null: false
t.datetime "created_at", null: false
t.index ["job_id"], name: "index_solid_queue_scheduled_executions_on_job_id", unique: true
t.index ["scheduled_at", "priority", "job_id"], name: "index_solid_queue_dispatch_all"
end
create_table "solid_queue_semaphores", force: :cascade do |t|
t.string "key", null: false
t.integer "value", default: 1, null: false
t.datetime "expires_at", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["expires_at"], name: "index_solid_queue_semaphores_on_expires_at"
t.index ["key", "value"], name: "index_solid_queue_semaphores_on_key_and_value"
t.index ["key"], name: "index_solid_queue_semaphores_on_key", unique: true
end
create_table "tables_arrangements", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| create_table "tables_arrangements", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.integer "discomfort" t.integer "discomfort"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
end t.string "name", null: false
create_table "taggings", force: :cascade do |t|
t.bigint "tag_id"
t.string "taggable_type"
t.uuid "taggable_id"
t.string "tagger_type"
t.bigint "tagger_id"
t.string "context", limit: 128
t.datetime "created_at", precision: nil
t.string "tenant", limit: 128
t.index ["context"], name: "index_taggings_on_context"
t.index ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true
t.index ["tag_id"], name: "index_taggings_on_tag_id"
t.index ["taggable_id", "taggable_type", "context"], name: "taggings_taggable_context_idx"
t.index ["taggable_id", "taggable_type", "tagger_id", "context"], name: "taggings_idy"
t.index ["taggable_id"], name: "index_taggings_on_taggable_id"
t.index ["taggable_type", "taggable_id"], name: "index_taggings_on_taggable_type_and_taggable_id"
t.index ["taggable_type"], name: "index_taggings_on_taggable_type"
t.index ["tagger_id", "tagger_type"], name: "index_taggings_on_tagger_id_and_tagger_type"
t.index ["tagger_id"], name: "index_taggings_on_tagger_id"
t.index ["tagger_type", "tagger_id"], name: "index_taggings_on_tagger_type_and_tagger_id"
t.index ["tenant"], name: "index_taggings_on_tenant"
end
create_table "tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "taggings_count", default: 0
t.index ["name"], name: "index_tags_on_name", unique: true
end end
add_foreign_key "groups", "groups", column: "parent_id" add_foreign_key "groups", "groups", column: "parent_id"
add_foreign_key "guests", "groups" add_foreign_key "guests", "groups"
add_foreign_key "seats", "guests" add_foreign_key "seats", "guests"
add_foreign_key "seats", "tables_arrangements", on_delete: :cascade add_foreign_key "seats", "tables_arrangements", on_delete: :cascade
add_foreign_key "taggings", "tags" add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_claimed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_failed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_ready_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_recurring_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_scheduled_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
end end

View File

@ -5,8 +5,6 @@ NUMBER_OF_GUESTS = 50
TablesArrangement.delete_all TablesArrangement.delete_all
Expense.delete_all Expense.delete_all
Guest.delete_all Guest.delete_all
ActsAsTaggableOn::Tagging.delete_all
ActsAsTaggableOn::Tag.delete_all
Group.delete_all Group.delete_all
Expense.create!(name: 'Photographer', amount: 3000, pricing_type: 'fixed') Expense.create!(name: 'Photographer', amount: 3000, pricing_type: 'fixed')
@ -58,11 +56,15 @@ groups = Group.all
NUMBER_OF_GUESTS.times do NUMBER_OF_GUESTS.times do
Guest.create!( Guest.create!(
first_name: Faker::Name.first_name, name: Faker::Name.name,
last_name: Faker::Name.last_name,
email: Faker::Internet.email,
phone: Faker::PhoneNumber.cell_phone, phone: Faker::PhoneNumber.cell_phone,
group: groups.sample, group: groups.sample,
status: Guest.statuses.keys.sample status: Guest.statuses.keys.sample
) )
end end
ActiveJob.perform_all_later(3.times.map { TableSimulatorJob.new })
'red'.paint.palette.triad(as: :hex).zip(Group.roots).each { |(color, group)| group.update!(color: color.paint.desaturate(40)) }
Group.roots.each(&:colorize_children)

View File

@ -0,0 +1,91 @@
---
- - :permit
- MIT
- :who:
:why:
:versions: []
:when: 2024-10-25 17:45:36.831184284 Z
- - :permit
- ISC
- :who:
:why:
:versions: []
:when: 2024-10-25 17:48:14.527140943 Z
- - :permit
- Apache 2.0
- :who:
:why:
:versions: []
:when: 2024-10-25 17:48:23.863998708 Z
- - :permit
- Simplified BSD
- :who:
:why:
:versions: []
:when: 2024-10-25 17:49:01.330574375 Z
- - :permit
- New BSD
- :who:
:why:
:versions: []
:when: 2024-10-25 17:49:53.995999923 Z
- - :permit
- LGPL-3.0-or-later
- :who:
:why:
:versions: []
:when: 2024-10-25 17:51:16.274818102 Z
- - :permit
- Python-2.0
- :who:
:why:
:versions: []
:when: 2024-10-25 17:51:32.610018037 Z
- - :permit
- BlueOak-1.0.0
- :who:
:why:
:versions: []
:when: 2024-10-25 17:52:28.568966565 Z
- - :permit
- BSD
- :who:
:why:
:versions: []
:when: 2024-10-25 17:52:37.235297087 Z
- - :permit
- The Unlicense
- :who:
:why:
:versions: []
:when: 2024-10-25 17:52:49.646463302 Z
- - :permit
- CC-BY-4.0
- :who:
:why:
:versions: []
:when: 2024-10-25 17:54:29.363007852 Z
- - :permit
- "(MIT AND Zlib)"
- :who:
:why:
:versions: []
:when: 2024-10-25 17:54:49.936741134 Z
- - :permit
- BSD Zero Clause License
- :who:
:why:
:versions: []
:when: 2024-10-25 17:55:31.968339009 Z
- - :permit
- Artistic-2.0
- :who:
:why:
:versions: []
:when: 2024-10-25 17:55:52.371898047 Z
- - :permit
- ruby
- :who:
:why:
:versions: []
:when: 2024-11-03 10:58:35.358938407 Z

62
docker-compose.yml Normal file
View File

@ -0,0 +1,62 @@
services:
backend:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- 3000
depends_on:
db:
condition: service_healthy
environment:
DATABASE_URL: postgres://postgres:postgres@db:5432/postgres
RAILS_ENV: development
volumes:
- .:/rails
workers:
build:
context: .
dockerfile: Dockerfile.dev
entrypoint: bin/jobs
depends_on:
db:
condition: service_healthy
environment:
DATABASE_URL: postgres://postgres:postgres@db:5432/postgres
RAILS_ENV: development
volumes:
- .:/rails
frontend:
build:
context: ../wedding-planner-frontend
dockerfile: Dockerfile.dev
ports:
- 3000
depends_on:
- backend
volumes:
- ../wedding-planner-frontend/:/app
nginx:
image: nginx:latest
ports:
- 80:80
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- frontend
- backend
db:
image: postgres:17
ports:
- 5432
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U postgres']
interval: 10s
timeout: 5s
retries: 5

View File

@ -0,0 +1,8 @@
# This rake task was added by annotate_rb gem.
# Can set `ANNOTATERB_SKIP_ON_DB_TASKS` to be anything to skip this
if Rails.env.development? && ENV["ANNOTATERB_SKIP_ON_DB_TASKS"].nil?
require "annotate_rb"
AnnotateRb::Core.load_rake_tasks
end

View File

@ -3,12 +3,12 @@ server {
server_name libre-wedding-planner.app.localhost; server_name libre-wedding-planner.app.localhost;
location /api/ { location /api/ {
proxy_pass http://localhost:3001/; proxy_pass http://backend:3000/;
proxy_set_header Host $http_host; proxy_set_header Host $http_host;
} }
location / { location / {
proxy_pass http://localhost:3000; proxy_pass http://frontend:3000;
proxy_set_header Host $http_host; proxy_set_header Host $http_host;
} }
} }

View File

@ -1,3 +1,5 @@
# Copyright (C) 2024 Manuel Bustillo
FactoryBot.define do FactoryBot.define do
factory :expense do factory :expense do
sequence(:name) { |i| "Expense #{i}" } sequence(:name) { |i| "Expense #{i}" }

View File

@ -4,9 +4,7 @@ FactoryBot.define do
factory :guest do factory :guest do
association :group association :group
first_name { Faker::Name.first_name } name { Faker::Name.name }
last_name { Faker::Name.last_name }
email { Faker::Internet.email }
phone { Faker::PhoneNumber.cell_phone } phone { Faker::PhoneNumber.cell_phone }
end end
end end

View File

@ -3,5 +3,10 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe Expense, type: :model do RSpec.describe Expense, type: :model do
pending "add some examples to (or delete) #{__FILE__}" describe 'validations' do
it { should validate_presence_of(:name) }
it { should validate_presence_of(:amount) }
it { should validate_numericality_of(:amount).is_greater_than(0) }
it { should validate_presence_of(:pricing_type) }
end
end end

View File

@ -3,5 +3,9 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe Group, type: :model do RSpec.describe Group, type: :model do
pending "add some examples to (or delete) #{__FILE__}" describe 'callbacks' do
it 'should set color before create' do
expect(create(:group).color).to be_present
end
end
end end

View File

@ -3,5 +3,32 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe Guest, type: :model do RSpec.describe Guest, type: :model do
pending "add some examples to (or delete) #{__FILE__}" describe 'validations' do
it { should validate_presence_of(:name) }
it do
should define_enum_for(:status).with_values(
considered: 0,
invited: 10,
confirmed: 20,
declined: 30,
tentative: 40
)
end
end
it { should belong_to(:group) }
describe 'scopes' do
describe '.potential' do
it 'returns guests that are not declined or considered' do
_declined_guest = create(:guest, status: :declined)
_considered_guest = create(:guest, status: :considered)
invited_guest = create(:guest, status: :invited)
confirmed_guest = create(:guest, status: :confirmed)
tentative_guest = create(:guest, status: :tentative)
expect(Guest.potential).to match_array([invited_guest, confirmed_guest, tentative_guest])
end
end
end
end end

View File

@ -3,5 +3,9 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe TablesArrangement, type: :model do RSpec.describe TablesArrangement, type: :model do
pending "add some examples to (or delete) #{__FILE__}" describe 'callbacks' do
it 'assigns a name before creation' do
expect(described_class.create!.name).to be_present
end
end
end end

View File

@ -1,3 +1,5 @@
# Copyright (C) 2024 Manuel Bustillo
require 'rails_helper' require 'rails_helper'
module Expenses module Expenses

View File

@ -0,0 +1,98 @@
# Copyright (C) 2024 Manuel Bustillo
require 'rails_helper'
module Groups
RSpec.describe SummaryQuery do
describe '#call' do
subject { described_class.new.call }
context 'when there are no groups' do
it { is_expected.to eq([]) }
end
context 'when groups are defined' do
let!(:parent) { create(:group, name: 'Friends', icon: 'icon-1', color: '#FF0000') }
let!(:child) { create(:group, name: 'Family', icon: 'icon-2', color: '#00FF00', parent:) }
context 'when there are no guests' do
it 'returns the summary of groups' do
is_expected.to contain_exactly(
{ 'id' => parent.id,
'name' => 'Friends',
'icon' => 'icon-1',
'parent_id' => nil,
'color' => '#FF0000',
'total' => 0,
'considered' => 0,
'invited' => 0,
'confirmed' => 0,
'declined' => 0,
'tentative' => 0 },
{ 'id' => child.id,
'name' => 'Family',
'icon' => 'icon-2',
'parent_id' => parent.id,
'color' => '#00FF00',
'total' => 0,
'considered' => 0,
'invited' => 0,
'confirmed' => 0,
'declined' => 0,
'tentative' => 0 }
)
end
end
context 'when there are guests' do
before do
# Parent group
create_list(:guest, 2, group: parent, status: :considered)
create_list(:guest, 3, group: parent, status: :invited)
create_list(:guest, 4, group: parent, status: :confirmed)
create_list(:guest, 5, group: parent, status: :declined)
create_list(:guest, 6, group: parent, status: :tentative)
# Child group
create_list(:guest, 7, group: child, status: :considered)
create_list(:guest, 8, group: child, status: :invited)
create_list(:guest, 9, group: child, status: :confirmed)
create_list(:guest, 10, group: child, status: :declined)
create_list(:guest, 11, group: child, status: :tentative)
end
it 'returns the summary of groups' do
is_expected.to contain_exactly(
{
'id' => parent.id,
'name' => 'Friends',
'icon' => 'icon-1',
'parent_id' => nil,
'color' => '#FF0000',
'total' => 20,
'considered' => 2,
'invited' => 3,
'confirmed' => 4,
'declined' => 5,
'tentative' => 6
},
{
'id' => child.id,
'name' => 'Family',
'icon' => 'icon-2',
'parent_id' => parent.id,
'color' => '#00FF00',
'total' => 45,
'considered' => 7,
'invited' => 8,
'confirmed' => 9,
'declined' => 10,
'tentative' => 11
}
)
end
end
end
end
end
end

View File

@ -66,3 +66,10 @@ RSpec.configure do |config|
# config.filter_gems_from_backtrace("gem name") # config.filter_gems_from_backtrace("gem name")
config.include FactoryBot::Syntax::Methods config.include FactoryBot::Syntax::Methods
end end
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end

View File

@ -0,0 +1,49 @@
# Copyright (C) 2024 Manuel Bustillo
require 'swagger_helper'
RSpec.describe 'expenses', type: :request do
path '/expenses' do
get('list expenses') do
tags 'Expenses'
produces 'application/json'
response(200, 'successful') do
schema type: :array,
items: {
type: :object,
required: %i[id name amount pricing_type],
properties: {
id: { type: :string, format: :uuid },
name: { type: :string },
amount: { type: :number },
pricing_type: { type: :string, enum: Expense.pricing_types.keys }
}
}
xit
end
end
end
path '/expenses/{id}' do
patch('update expense') do
tags 'Expenses'
consumes 'application/json'
produces 'application/json'
parameter name: 'id', in: :path, type: :string, format: :uuid, description: 'id'
parameter name: :body, in: :body, schema: {
type: :object,
properties: {
name: { type: :string },
amount: { type: :number, minimum: 0 },
pricing_type: { type: :string, enum: Expense.pricing_types.keys }
}
}
response_empty_200
response_422
response_404
end
end
end

View File

@ -0,0 +1,33 @@
# Copyright (C) 2024 Manuel Bustillo
require 'swagger_helper'
RSpec.describe 'groups', type: :request do
path '/groups' do
get('list groups') do
tags 'Groups'
produces 'application/json'
response(200, 'successful') do
schema type: :array,
items: {
type: :object,
required: %i[id name icon parent_id color total considered invited confirmed declined tentative],
properties: {
id: { type: :string, format: :uuid, required: true },
name: { type: :string },
icon: { type: :string, example: 'pi pi-crown', description: 'The CSS classes used by the icon' },
parent_id: { type: :string, format: :uuid },
color: { type: :string, pattern: '^#(?:[0-9a-fA-F]{3}){1,2}$' },
total: { type: :integer, minimum: 0, description: 'Total number of guests in any status' },
considered: { type: :integer, minimum: 0 },
invited: { type: :integer, minimum: 0 },
confirmed: { type: :integer, minimum: 0 },
declined: { type: :integer, minimum: 0 },
tentative: { type: :integer, minimum: 0 }
}
}
xit
end
end
end
end

View File

@ -0,0 +1,91 @@
# Copyright (C) 2024 Manuel Bustillo
require 'swagger_helper'
RSpec.describe 'guests', type: :request do
path '/guests' do
get('list guests') do
tags 'Guests'
produces 'application/json'
response(200, 'successful') do
schema type: :array,
items: {
type: :object,
required: %i[id name status group],
properties: {
id: { type: :string, format: :uuid },
name: { type: :string },
status: { type: :string, enum: Guest.statuses.keys },
group: { type: :object,
required: %i[id name],
properties: {
id: { type: :string, format: :uuid },
name: { type: :string }
} }
}
}
xit
end
end
post('create guest') do
tags 'Guests'
consumes 'application/json'
produces 'application/json'
parameter name: :body, in: :body, schema: {
type: :object,
required: %i[guest],
properties: {
guest: {
type: :object,
required: %i[name group_id status],
properties: {
name: { type: :string },
group_id: { type: :string, format: :uuid },
status: { type: :string, enum: Guest.statuses.keys }
}
}
}
}
response_empty_201
response_422
end
end
path '/guests/{id}' do
patch('update guest') do
tags 'Guests'
consumes 'application/json'
produces 'application/json'
parameter name: 'id', in: :path, type: :string, format: :uuid
parameter name: :body, in: :body, schema: {
type: :object,
required: %i[guest],
properties: {
guest: {
type: :object,
properties: {
name: { type: :string },
group_id: { type: :string, format: :uuid },
status: { type: :string, enum: Guest.statuses.keys }
}
}
}
}
response_empty_200
response_422
response_404
end
delete('delete guest') do
tags 'Guests'
produces 'application/json'
parameter name: 'id', in: :path, type: :string, format: :uuid
response_empty_200
response_404
end
end
end

View File

@ -3,7 +3,73 @@
require 'rails_helper' require 'rails_helper'
module Tables module Tables
RSpec.describe DiscomfortCalculator do RSpec.describe DiscomfortCalculator do
let(:calculator) { described_class.new(table) } let(:calculator) { described_class.new(table:) }
let(:family) { create(:group, name: 'family') }
let(:friends) { create(:group, name: 'friends') }
let(:work) { create(:group, name: 'work') }
let(:school) { create(:group, name: 'school') }
describe '#calculate' do
before do
allow(calculator).to receive(:table_size_penalty).and_return(2)
allow(calculator).to receive(:cohesion_penalty).and_return(3)
end
let(:table) { Table.new(create_list(:guest, 6)) }
it 'returns the sum of the table size penalty and the average cohesion penalty' do
expect(calculator.calculate).to eq(2 + 10 * 3 / 6.0)
end
end
describe '#table_size_penalty' do
before do
table.min_per_table = 5
table.max_per_table = 7
end
context 'when the number of guests is in the lower bound' do
let(:table) { Table.new(create_list(:guest, 5)) }
it { expect(calculator.send(:table_size_penalty)).to eq(0) }
end
context 'when the number of guests is within the table size limits' do
let(:table) { Table.new(create_list(:guest, 6)) }
it { expect(calculator.send(:table_size_penalty)).to eq(0) }
end
context 'when the number of guests is in the upper bound' do
let(:table) { Table.new(create_list(:guest, 7)) }
it { expect(calculator.send(:table_size_penalty)).to eq(0) }
end
context 'when the number of guests is one unit below the lower bound' do
let(:table) { Table.new(create_list(:guest, 4)) }
it { expect(calculator.send(:table_size_penalty)).to eq(5) }
end
context 'when the number of guests is two units below the lower bound' do
let(:table) { Table.new(create_list(:guest, 3)) }
it { expect(calculator.send(:table_size_penalty)).to eq(10) }
end
context 'when the number of guests is one unit above the upper bound' do
let(:table) { Table.new(create_list(:guest, 8)) }
it { expect(calculator.send(:table_size_penalty)).to eq(5) }
end
context 'when the number of guests is two units above the upper bound' do
let(:table) { Table.new(create_list(:guest, 9)) }
it { expect(calculator.send(:table_size_penalty)).to eq(10) }
end
end
describe '#cohesion_penalty' do describe '#cohesion_penalty' do
before do before do
@ -14,16 +80,16 @@ module Tables
allow(AffinityGroupsHierarchy.instance).to receive(:distance).with(group, group).and_return(0) allow(AffinityGroupsHierarchy.instance).to receive(:distance).with(group, group).and_return(0)
end end
allow(AffinityGroupsHierarchy.instance).to receive(:distance).with('family', 'friends').and_return(nil) allow(AffinityGroupsHierarchy.instance).to receive(:distance).with(family.id, friends.id).and_return(nil)
allow(AffinityGroupsHierarchy.instance).to receive(:distance).with('friends', 'work').and_return(1) allow(AffinityGroupsHierarchy.instance).to receive(:distance).with(friends.id, work.id).and_return(1)
allow(AffinityGroupsHierarchy.instance).to receive(:distance).with('family', 'work').and_return(2) allow(AffinityGroupsHierarchy.instance).to receive(:distance).with(family.id, work.id).and_return(2)
allow(AffinityGroupsHierarchy.instance).to receive(:distance).with('family', 'school').and_return(3) allow(AffinityGroupsHierarchy.instance).to receive(:distance).with(family.id, school.id).and_return(3)
allow(AffinityGroupsHierarchy.instance).to receive(:distance).with('friends', 'school').and_return(4) allow(AffinityGroupsHierarchy.instance).to receive(:distance).with(friends.id, school.id).and_return(4)
allow(AffinityGroupsHierarchy.instance).to receive(:distance).with('work', 'school').and_return(5) allow(AffinityGroupsHierarchy.instance).to receive(:distance).with(work.id, school.id).and_return(5)
end end
context 'when the table contains just two guests' do context 'when the table contains just two guests' do
context 'when they belong to the same group' do context 'when they belong to the same group' do
let(:table) { create_list(:guest, 2, affinity_group_list: ['family']) } let(:table) { create_list(:guest, 2, group: family) }
it { expect(calculator.send(:cohesion_penalty)).to eq(0) } it { expect(calculator.send(:cohesion_penalty)).to eq(0) }
end end
@ -31,8 +97,8 @@ module Tables
context 'when they belong to completely unrelated groups' do context 'when they belong to completely unrelated groups' do
let(:table) do let(:table) do
[ [
create(:guest, affinity_group_list: ['family']), create(:guest, group: family),
create(:guest, affinity_group_list: ['friends']) create(:guest, group: friends)
] ]
end end
it { expect(calculator.send(:cohesion_penalty)).to eq(1) } it { expect(calculator.send(:cohesion_penalty)).to eq(1) }
@ -41,8 +107,8 @@ module Tables
context 'when they belong to groups at a distance of 1' do context 'when they belong to groups at a distance of 1' do
let(:table) do let(:table) do
[ [
create(:guest, affinity_group_list: ['friends']), create(:guest, group: friends),
create(:guest, affinity_group_list: ['work']) create(:guest, group: work)
] ]
end end
@ -52,8 +118,8 @@ module Tables
context 'when they belong to groups at a distance of 2' do context 'when they belong to groups at a distance of 2' do
let(:table) do let(:table) do
[ [
create(:guest, affinity_group_list: ['family']), create(:guest, group: family),
create(:guest, affinity_group_list: ['work']) create(:guest, group: work)
] ]
end end
@ -63,8 +129,8 @@ module Tables
context 'when they belong to groups at a distance of 3' do context 'when they belong to groups at a distance of 3' do
let(:table) do let(:table) do
[ [
create(:guest, affinity_group_list: ['family']), create(:guest, group: family),
create(:guest, affinity_group_list: ['school']) create(:guest, group: school)
] ]
end end
@ -75,9 +141,9 @@ module Tables
context 'when the table contains three guests' do context 'when the table contains three guests' do
let(:table) do let(:table) do
[ [
create(:guest, affinity_group_list: ['family']), create(:guest, group: family),
create(:guest, affinity_group_list: ['friends']), create(:guest, group: friends),
create(:guest, affinity_group_list: ['work']) create(:guest, group: work)
] ]
end end
@ -89,10 +155,10 @@ module Tables
context 'when the table contains four guests of different groups' do context 'when the table contains four guests of different groups' do
let(:table) do let(:table) do
[ [
create(:guest, affinity_group_list: ['family']), create(:guest, group: family),
create(:guest, affinity_group_list: ['friends']), create(:guest, group: friends),
create(:guest, affinity_group_list: ['work']), create(:guest, group: work),
create(:guest, affinity_group_list: ['school']) create(:guest, group: school)
] ]
end end
@ -105,8 +171,8 @@ module Tables
context 'when the table contains four guests of two evenly split groups' do context 'when the table contains four guests of two evenly split groups' do
let(:table) do let(:table) do
[ [
create_list(:guest, 2, affinity_group_list: ['family']), create_list(:guest, 2, group: family),
create_list(:guest, 2, affinity_group_list: ['friends']) create_list(:guest, 2, group: friends)
].flatten ].flatten
end end
@ -118,8 +184,8 @@ module Tables
context 'when the table contains six guests of two unevenly split groups' do context 'when the table contains six guests of two unevenly split groups' do
let(:table) do let(:table) do
[ [
create_list(:guest, 2, affinity_group_list: ['family']), create_list(:guest, 2, group: family),
create_list(:guest, 4, affinity_group_list: ['friends']) create_list(:guest, 4, group: friends)
].flatten ].flatten
end end
@ -131,9 +197,9 @@ module Tables
context 'when the table contains six guests of three evenly split groups' do context 'when the table contains six guests of three evenly split groups' do
let(:table) do let(:table) do
[ [
create_list(:guest, 2, affinity_group_list: ['family']), create_list(:guest, 2, group: family),
create_list(:guest, 2, affinity_group_list: ['friends']), create_list(:guest, 2, group: friends),
create_list(:guest, 2, affinity_group_list: ['work']) create_list(:guest, 2, group: work)
].flatten ].flatten
end end
@ -145,9 +211,9 @@ module Tables
context 'when the table contains six guests of three unevenly split groups' do context 'when the table contains six guests of three unevenly split groups' do
let(:table) do let(:table) do
[ [
create_list(:guest, 3, affinity_group_list: ['family']), create_list(:guest, 3, group: family),
create_list(:guest, 2, affinity_group_list: ['friends']), create_list(:guest, 2, group: friends),
create_list(:guest, 1, affinity_group_list: ['work']) create_list(:guest, 1, group: work)
].flatten ].flatten
end end

View File

@ -0,0 +1,25 @@
# Copyright (C) 2024 Manuel Bustillo
require 'rails_helper'
module Tables
RSpec.describe Distribution do
describe '#random_distribution' do
let(:subject) { described_class.new(min_per_table: 5, max_per_table: 10) }
context 'when there are fewer people than the minimum per table' do
it 'creates one table' do
subject.random_distribution([1, 2, 3, 4])
expect(subject.tables.count).to eq(1)
end
end
context 'when there are more people than the maximum per table' do
it 'creates multiple tables' do
subject.random_distribution([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
expect(subject.tables.count).to be > 1
end
end
end
end
end

View File

@ -0,0 +1,55 @@
# Copyright (C) 2024 Manuel Bustillo
require 'rails_helper'
module Tables
RSpec.describe Shift do
describe '#each' do
let(:shifts) do
acc = []
described_class.new(initial_solution).each do |solution|
acc << solution.tables.map(&:dup)
end
acc
end
context 'when there are two tables with two people each' do
let(:initial_solution) do
Distribution.new(min_per_table: 2, max_per_table: 2).tap do |distribution|
distribution.tables << Set[:a, :b].to_table
distribution.tables << Set[:c, :d].to_table
end
end
it 'yields all possible shifts between the tables' do
expect(shifts).to contain_exactly(
[Set[:b], Set[:c, :d, :a]],
[Set[:a], Set[:c, :d, :b]],
[Set[:b, :a, :d], Set[:c]],
[Set[:b, :a, :c], Set[:d]]
)
end
end
context 'when there are two tables with three people each' do
let(:initial_solution) do
Distribution.new(min_per_table: 3, max_per_table: 3).tap do |distribution|
distribution.tables << Set[:a, :b, :c].to_table
distribution.tables << Set[:d, :e, :f].to_table
end
end
it 'yields all possible shifts between the tables' do
expect(shifts).to contain_exactly(
[Set[:b, :c], Set[:d, :e, :f, :a]],
[Set[:c, :a], Set[:d, :e, :f, :b]],
[Set[:a, :b], Set[:d, :e, :f, :c]],
[Set[:a, :b, :c, :d], Set[:e, :f]],
[Set[:a, :b, :c, :e], Set[:d, :f]],
[Set[:a, :b, :c, :f], Set[:d, :e]]
)
end
end
end
end
end

View File

@ -16,17 +16,17 @@ 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).tap do |distribution|
distribution.tables << %i[a b].to_table distribution.tables << Set[:a, :b].to_table
distribution.tables << %i[c d].to_table distribution.tables << Set[:c, :d].to_table
end end
end end
it 'yields all possible swaps between the tables' do it 'yields all possible swaps between the tables' do
expect(swaps).to contain_exactly( expect(swaps).to contain_exactly(
[%i[a d], %i[c b]], [Set[:a, :d], Set[:c, :b]],
[%i[b c], %i[d a]], [Set[:b, :c], Set[:d, :a]],
[%i[a c], %i[d b]], [Set[:a, :c], Set[:d, :b]],
[%i[b d], %i[c a]] [Set[:b, :d], Set[:c, :a]]
) )
end end
end end
@ -34,22 +34,22 @@ 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).tap do |distribution|
distribution.tables << %i[a b c].to_table distribution.tables << Set[:a, :b, :c].to_table
distribution.tables << %i[d e f].to_table distribution.tables << Set[:d, :e, :f].to_table
end end
end end
it 'yields all possible swaps between the tables' do it 'yields all possible swaps between the tables' do
expect(swaps).to contain_exactly( expect(swaps).to contain_exactly(
[%i[b c d], %i[e f a]], [Set[:b, :c, :d], Set[:e, :f, :a]],
[%i[b c e], %i[f d a]], [Set[:b, :c, :e], Set[:f, :d, :a]],
[%i[b c f], %i[d e a]], [Set[:b, :c, :f], Set[:d, :e, :a]],
[%i[c a d], %i[e f b]], [Set[:c, :a, :d], Set[:e, :f, :b]],
[%i[c a e], %i[f d b]], [Set[:c, :a, :e], Set[:f, :d, :b]],
[%i[c a f], %i[d e b]], [Set[:c, :a, :f], Set[:d, :e, :b]],
[%i[a b d], %i[e f c]], [Set[:a, :b, :d], Set[:e, :f, :c]],
[%i[a b e], %i[f d c]], [Set[:a, :b, :e], Set[:f, :d, :c]],
[%i[a b f], %i[d e c]] [Set[:a, :b, :f], Set[:d, :e, :c]]
) )
end end
end end
@ -57,26 +57,26 @@ 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).tap do |distribution|
distribution.tables << %i[a b].to_table distribution.tables << Set[:a, :b].to_table
distribution.tables << %i[c d].to_table distribution.tables << Set[:c, :d].to_table
distribution.tables << %i[e f].to_table distribution.tables << Set[:e, :f].to_table
end end
end end
it 'yields all possible swaps between the tables' do it 'yields all possible swaps between the tables' do
expect(swaps).to contain_exactly( expect(swaps).to contain_exactly(
[%i[b c], %i[d a], %i[e f]], [Set[:b, :c], Set[:d, :a], Set[:e, :f]],
[%i[b d], %i[c a], %i[e f]], [Set[:b, :d], Set[:c, :a], Set[:e, :f]],
[%i[a c], %i[d b], %i[e f]], [Set[:a, :c], Set[:d, :b], Set[:e, :f]],
[%i[a d], %i[c b], %i[e f]], [Set[:a, :d], Set[:c, :b], Set[:e, :f]],
[%i[b e], %i[c d], %i[f a]], [Set[:b, :e], Set[:c, :d], Set[:f, :a]],
[%i[b f], %i[c d], %i[e a]], [Set[:b, :f], Set[:c, :d], Set[:e, :a]],
[%i[a e], %i[c d], %i[f b]], [Set[:a, :e], Set[:c, :d], Set[:f, :b]],
[%i[a f], %i[c d], %i[e b]], [Set[:a, :f], Set[:c, :d], Set[:e, :b]],
[%i[a b], %i[d e], %i[f c]], [Set[:a, :b], Set[:d, :e], Set[:f, :c]],
[%i[a b], %i[d f], %i[e c]], [Set[:a, :b], Set[:d, :f], Set[:e, :c]],
[%i[a b], %i[c e], %i[f d]], [Set[:a, :b], Set[:c, :e], Set[:f, :d]],
[%i[a b], %i[c f], %i[e d]] [Set[:a, :b], Set[:c, :f], Set[:e, :d]]
) )
end end
end end

View File

@ -0,0 +1,15 @@
# Copyright (C) 2024 Manuel Bustillo
require 'rails_helper'
module VNS
RSpec.describe Engine do
describe '.sequence' do
it { expect(described_class.sequence([])).to eq([]) }
it { expect(described_class.sequence([1])).to eq([1]) }
it { expect(described_class.sequence([1, 2])).to eq([1, 2, 1]) }
it { expect(described_class.sequence([1, 2, 3])).to eq([1, 2, 3, 2, 1]) }
it { expect(described_class.sequence([1, 2, 3, 4])).to eq([1, 2, 3, 4, 3, 2, 1]) }
end
end
end

44
spec/swagger_helper.rb Normal file
View File

@ -0,0 +1,44 @@
# Copyright (C) 2024 Manuel Bustillo
# frozen_string_literal: true
require 'rails_helper'
require_relative './swagger_response_helper'
include SwaggerResponseHelper
RSpec.configure do |config|
# Specify a root folder where Swagger JSON files are generated
# NOTE: If you're using the rswag-api to serve API descriptions, you'll need
# to ensure that it's configured to serve Swagger from the same folder
config.openapi_root = Rails.root.join('swagger').to_s
# Define one or more Swagger documents and provide global metadata for each one
# When you run the 'rswag:specs:swaggerize' rake task, the complete Swagger will
# be generated at the provided relative path under openapi_root
# By default, the operations defined in spec files are added to the first
# document below. You can override this behavior by adding a openapi_spec tag to the
# the root example_group in your specs, e.g. describe '...', openapi_spec: 'v2/swagger.json'
config.openapi_specs = {
'v1/swagger.yaml' => {
openapi: '3.0.1',
info: {
title: 'API V1',
version: 'v1'
},
paths: {},
servers: [
{
url: 'http://libre-wedding-planner.app.localhost/api',
description: 'Suitable for development'
}
]
}
}
# Specify the format of the output Swagger file when running 'rswag:specs:swaggerize'.
# The openapi_specs configuration option has the filename including format in
# the key, this may want to be changed to avoid putting yaml in json files.
# Defaults to json. Accepts ':json' and ':yaml'.
config.openapi_format = :yaml
end

View File

@ -0,0 +1,46 @@
# Copyright (C) 2024 Manuel Bustillo
module SwaggerResponseHelper
def response_422
response(422, 'Validation errors in input parameters') do
produces 'application/json'
error_schema
xit
end
end
def response_empty_200
response(200, 'Success') do
produces 'application/json'
schema type: :object
xit
end
end
def response_empty_201
response(201, 'Created') do
produces 'application/json'
schema type: :object
xit
end
end
def response_404
response(404, 'Record not found') do
produces 'application/json'
error_schema
xit
end
end
private
def error_schema
schema type: :object,
required: %i[message errors],
properties: {
message: { type: :string },
errors: { type: :array, items: { type: :string } }
}
end
end