Compare commits

..

35 Commits

Author SHA1 Message Date
27ab5fc896 Add copyright notice
All checks were successful
Run unit tests / check-licenses (pull_request) Successful in 1m18s
Run unit tests / rubocop (pull_request) Successful in 1m20s
Run unit tests / copyright_notice (pull_request) Successful in 1m55s
Run unit tests / unit_tests (pull_request) Successful in 3m24s
Run unit tests / build-static-assets (pull_request) Successful in 26m0s
2025-01-25 09:14:12 +00:00
60cfbd1a40 Fix markup errors
All checks were successful
Run unit tests / check-licenses (pull_request) Successful in 58s
Run unit tests / rubocop (pull_request) Successful in 1m2s
Run unit tests / copyright_notice (pull_request) Successful in 1m48s
Run unit tests / unit_tests (pull_request) Successful in 4m2s
Run unit tests / build-static-assets (pull_request) Successful in 26m47s
2025-01-25 10:12:36 +01:00
744b13ecb8 Remove incorrect copyright notice
Some checks failed
Run unit tests / check-licenses (pull_request) Successful in 55s
Run unit tests / rubocop (pull_request) Successful in 1m1s
Run unit tests / copyright_notice (pull_request) Failing after 1m27s
Run unit tests / unit_tests (pull_request) Successful in 3m28s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-25 10:11:03 +01:00
d4b95c9c55 Redo migrations after running specs
All checks were successful
Run unit tests / check-licenses (pull_request) Successful in 1m46s
Run unit tests / rubocop (pull_request) Successful in 1m52s
Run unit tests / copyright_notice (pull_request) Successful in 2m17s
Run unit tests / unit_tests (pull_request) Successful in 4m50s
Run unit tests / build-static-assets (pull_request) Successful in 31m44s
2025-01-25 09:52:17 +01:00
c44c3b8ec8 Merge remote-tracking branch 'origin/main' into test-rollbacks
Some checks failed
Run unit tests / rubocop (pull_request) Successful in 1m19s
Run unit tests / check-licenses (pull_request) Successful in 1m24s
Run unit tests / build-static-assets (pull_request) Has been cancelled
Run unit tests / unit_tests (pull_request) Has been cancelled
Run unit tests / copyright_notice (pull_request) Has been cancelled
2025-01-25 09:40:03 +01:00
5b6082fad6 Refine names in CI steps 2025-01-24 09:10:32 +01:00
140555ed68 Do not fail job if there are new copyright assignments
All checks were successful
Run unit tests / rubocop (pull_request) Successful in 1m18s
Run unit tests / check-licenses (pull_request) Successful in 1m20s
Run unit tests / copyright_notice (pull_request) Successful in 1m32s
Run unit tests / unit_tests (pull_request) Successful in 2m42s
Run unit tests / build-static-assets (pull_request) Successful in 10m50s
2025-01-24 09:08:49 +01:00
9724e19954 Restore original version of the migration
Some checks failed
Run unit tests / build-static-assets (pull_request) Has been cancelled
Run unit tests / rubocop (pull_request) Has been cancelled
Run unit tests / check-licenses (pull_request) Has been cancelled
Run unit tests / copyright_notice (pull_request) Has been cancelled
Run unit tests / unit_tests (pull_request) Has been cancelled
2025-01-24 09:08:28 +01:00
c714a49a04 Ignore the full db directory
Some checks failed
Run unit tests / rubocop (pull_request) Successful in 1m12s
Run unit tests / check-licenses (pull_request) Successful in 1m16s
Run unit tests / copyright_notice (pull_request) Successful in 1m59s
Run unit tests / unit_tests (pull_request) Successful in 2m27s
Run unit tests / build-static-assets (pull_request) Has been cancelled
2025-01-24 09:05:24 +01:00
c30b6df0a4 Exclude db/schema.rb from copyright notice
Some checks failed
Run unit tests / rubocop (pull_request) Successful in 33s
Run unit tests / check-licenses (pull_request) Successful in 34s
Run unit tests / copyright_notice (pull_request) Failing after 40s
Run unit tests / unit_tests (pull_request) Failing after 4m36s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-24 09:02:46 +01:00
494431eea6 Add missing variable
Some checks failed
Run unit tests / check-licenses (pull_request) Successful in 56s
Run unit tests / rubocop (pull_request) Successful in 1m32s
Run unit tests / copyright_notice (pull_request) Successful in 1m43s
Run unit tests / unit_tests (pull_request) Failing after 2m50s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-24 08:58:14 +01:00
ac470a802b Redo migrations after running specs
Some checks failed
Run unit tests / rubocop (pull_request) Successful in 52s
Run unit tests / check-licenses (pull_request) Successful in 1m10s
Run unit tests / copyright_notice (pull_request) Successful in 1m37s
Run unit tests / unit_tests (pull_request) Failing after 2m29s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-24 08:55:26 +01:00
139502c69a Show number of migrations added
Some checks failed
Run unit tests / rubocop (pull_request) Successful in 48s
Run unit tests / check-licenses (pull_request) Successful in 1m17s
Run unit tests / copyright_notice (pull_request) Successful in 1m43s
Run unit tests / unit_tests (pull_request) Failing after 2m10s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-24 08:51:02 +01:00
644f35c57f Add a separate action to list changed migrations
Some checks failed
Run unit tests / rubocop (pull_request) Successful in 55s
Run unit tests / check-licenses (pull_request) Successful in 1m10s
Run unit tests / copyright_notice (pull_request) Successful in 1m17s
Run unit tests / unit_tests (pull_request) Failing after 2m0s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-24 08:45:57 +01:00
f08082fb3b Checkout the commit as is in the PR, not if merged into the base
Some checks failed
Run unit tests / copyright_notice (pull_request) Successful in 52s
Run unit tests / check-licenses (pull_request) Failing after 1m5s
Run unit tests / rubocop (pull_request) Failing after 1m5s
Run unit tests / unit_tests (pull_request) Failing after 1m40s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-24 08:39:00 +01:00
3651176bbd Fetch before diff
Some checks failed
Run unit tests / check-licenses (pull_request) Successful in 43s
Run unit tests / copyright_notice (pull_request) Successful in 1m8s
Run unit tests / rubocop (pull_request) Successful in 23s
Run unit tests / unit_tests (pull_request) Failing after 1m45s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-24 00:50:12 +01:00
a12d60e7cb Use PR base SHA
Some checks failed
Run unit tests / check-licenses (pull_request) Successful in 39s
Run unit tests / copyright_notice (pull_request) Successful in 55s
Run unit tests / unit_tests (pull_request) Failing after 1m31s
Run unit tests / rubocop (pull_request) Successful in 23s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-24 00:48:00 +01:00
44590e6889 Fetch branch before comparison
Some checks failed
Run unit tests / rubocop (pull_request) Successful in 36s
Run unit tests / check-licenses (pull_request) Successful in 38s
Run unit tests / copyright_notice (pull_request) Successful in 1m1s
Run unit tests / unit_tests (pull_request) Failing after 1m38s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-24 00:43:46 +01:00
66c5b3a526 Compare number of migrations against base ref
Some checks failed
Run unit tests / rubocop (pull_request) Successful in 1m18s
Run unit tests / check-licenses (pull_request) Successful in 1m21s
Run unit tests / copyright_notice (pull_request) Successful in 1m37s
Run unit tests / unit_tests (pull_request) Failing after 1m55s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-24 00:40:27 +01:00
966998e6c8 Display the number of migrations added
Some checks failed
Run unit tests / check-licenses (pull_request) Successful in 1m42s
Run unit tests / rubocop (pull_request) Successful in 1m45s
Run unit tests / copyright_notice (pull_request) Successful in 2m24s
Run unit tests / unit_tests (pull_request) Failing after 3m18s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-24 00:31:48 +01:00
89bc7fa142 Add copyright notice
Some checks failed
Run unit tests / check-licenses (pull_request) Successful in 1m0s
Run unit tests / rubocop (pull_request) Successful in 1m7s
Run unit tests / copyright_notice (pull_request) Successful in 2m8s
Run unit tests / unit_tests (pull_request) Failing after 3m52s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-23 23:30:49 +00:00
1306a33e8a Fix schema
Some checks failed
Run unit tests / rubocop (pull_request) Successful in 45s
Run unit tests / check-licenses (pull_request) Successful in 47s
Run unit tests / copyright_notice (pull_request) Failing after 1m19s
Run unit tests / unit_tests (pull_request) Successful in 4m1s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-24 00:29:29 +01:00
d35c0353fc Exit if reapplying last migration generates schema changes
Some checks failed
Run unit tests / rubocop (pull_request) Failing after 1m5s
Run unit tests / check-licenses (pull_request) Successful in 1m11s
Run unit tests / copyright_notice (pull_request) Successful in 1m38s
Run unit tests / unit_tests (pull_request) Failing after 2m23s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-24 00:26:02 +01:00
c8f221614a Fix previous migration to make it reversible
All checks were successful
Run unit tests / check-licenses (pull_request) Successful in 49s
Run unit tests / rubocop (pull_request) Successful in 53s
Run unit tests / copyright_notice (pull_request) Successful in 1m42s
Run unit tests / unit_tests (pull_request) Successful in 2m18s
Run unit tests / build-static-assets (pull_request) Successful in 18m5s
2025-01-24 00:19:15 +01:00
7a2feec3cb Display list of migrations
Some checks failed
Run unit tests / rubocop (pull_request) Successful in 1m3s
Run unit tests / check-licenses (pull_request) Successful in 1m7s
Run unit tests / copyright_notice (pull_request) Successful in 1m56s
Run unit tests / unit_tests (pull_request) Failing after 2m32s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-24 00:16:08 +01:00
d5173baca2 Redo last migration
Some checks failed
Run unit tests / check-licenses (pull_request) Successful in 43s
Run unit tests / rubocop (pull_request) Successful in 50s
Run unit tests / copyright_notice (pull_request) Successful in 1m44s
Run unit tests / unit_tests (pull_request) Failing after 2m18s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-24 00:13:07 +01:00
540ba0d59d Restore working version
All checks were successful
Run unit tests / check-licenses (pull_request) Successful in 1m39s
Run unit tests / rubocop (pull_request) Successful in 1m44s
Run unit tests / copyright_notice (pull_request) Successful in 2m36s
Run unit tests / unit_tests (pull_request) Successful in 4m48s
Run unit tests / build-static-assets (pull_request) Successful in 30m15s
2025-01-23 22:46:22 +01:00
bb7d7cbf49 Display last 10 migrations
Some checks failed
Run unit tests / rubocop (pull_request) Successful in 1m9s
Run unit tests / check-licenses (pull_request) Successful in 1m14s
Run unit tests / copyright_notice (pull_request) Successful in 1m40s
Run unit tests / unit_tests (pull_request) Failing after 2m41s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-23 22:43:27 +01:00
fec7efe10a Add copyright notice as part of the same workflow 2025-01-23 22:39:50 +01:00
fe456a3e52 Check licenses as part of the same workflow 2025-01-23 22:38:07 +01:00
798cf564b4 Redo last 5 migrations before running specs
Some checks failed
Check usage of free licenses / check-licenses (pull_request) Successful in 1m46s
Add copyright notice / copyright_notice (pull_request) Successful in 2m25s
Run unit tests / rubocop (pull_request) Successful in 1m8s
Run unit tests / unit_tests (pull_request) Failing after 3m45s
Run unit tests / build-static-assets (pull_request) Has been skipped
2025-01-23 22:36:23 +01:00
e612cf9936 Move docker build into the same workflow
Some checks failed
Run unit tests / reversible_migrations (pull_request) Failing after 4m36s
Run unit tests / build-static-assets (pull_request) Has been skipped
Check usage of free licenses / check-licenses (pull_request) Successful in 1m39s
Add copyright notice / copyright_notice (pull_request) Successful in 3m19s
Run unit tests / rubocop (pull_request) Successful in 1m49s
Run unit tests / unit_tests (pull_request) Successful in 5m34s
2025-01-23 22:24:35 +01:00
db55bafea1 Reuse code to wait for Postgres to be active
Some checks failed
Add copyright notice / copyright_notice (pull_request) Successful in 2m23s
Check usage of free licenses / check-licenses (pull_request) Successful in 1m7s
Run unit tests / rubocop (pull_request) Successful in 3m3s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 50m52s
Run unit tests / unit_tests (pull_request) Successful in 6m1s
Run unit tests / reversible_migrations (pull_request) Failing after 3m20s
2025-01-23 22:21:46 +01:00
f681f8d2f9 Add a new step redoing the last migration
Some checks failed
Run unit tests / rubocop (pull_request) Successful in 1m24s
Add copyright notice / copyright_notice (pull_request) Successful in 2m45s
Run unit tests / unit_tests (pull_request) Successful in 5m2s
Run unit tests / reversible_migrations (pull_request) Failing after 3m32s
Build Nginx-based docker image / build-static-assets (pull_request) Has been cancelled
Check usage of free licenses / check-licenses (pull_request) Successful in 1m19s
2025-01-23 22:12:25 +01:00
da02f37069 Extract rubocop to a separate job in CI
Some checks failed
Check usage of free licenses / check-licenses (pull_request) Successful in 54s
Add copyright notice / copyright_notice (pull_request) Successful in 1m32s
Run unit tests / rubocop (pull_request) Successful in 45s
Run unit tests / unit_tests (pull_request) Successful in 2m43s
Build Nginx-based docker image / build-static-assets (pull_request) Has been cancelled
2025-01-23 22:07:04 +01:00
53 changed files with 348 additions and 1034 deletions

View File

@ -23,7 +23,7 @@ jobs:
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.head_ref }} # Checkout the actual branch, not the result if merged into the base
- uses: ruby/setup-ruby@v1
- uses: ruby/setup-ruby@v1.207.0
- run: bundle install
- &postgres_wait
name: Wait until Postgres is ready to accept connections
@ -65,29 +65,26 @@ jobs:
if: failure()
run: docker ps --filter network=$JOB_CONTAINER_NAME-$GITHUB_JOB-network --filter name=$JOB_CONTAINER_NAME-* --format "{{.ID}}" | xargs docker rm -f
rubocop:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: ruby/setup-ruby@v1
- uses: ruby/setup-ruby@v1.207.0
- run: bundle install
- run: bundle exec rubocop --force-exclusion --parallel
check-licenses:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: ruby/setup-ruby@v1
- uses: ruby/setup-ruby@v1.207.0
- name: Install project dependencies
run: bundle install --jobs `getconf _NPROCESSORS_ONLN`
- name: Run license finder
run: license_finder
copyright_notice:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@ -124,6 +121,9 @@ jobs:
timeout-minutes: 30
needs:
- unit_tests
- rubocop
- check-licenses
- copyright_notice
steps:
- uses: actions/checkout@v4
with:

1
.gitignore vendored
View File

@ -36,4 +36,3 @@
# Ignore swagger generated documentation
swagger/v1/swagger.yaml
wedding-planner.code-workspace

View File

@ -1 +1 @@
ruby-3.4.3
ruby-3.4.1

View File

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

View File

@ -1,13 +1,13 @@
# syntax = docker/dockerfile:1
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.4.3
ARG RUBY_VERSION=3.4.1
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 wkhtmltopdf
RUN apt-get update && apt-get install -y nodejs
FROM base as build

View File

@ -2,7 +2,7 @@
source 'https://rubygems.org'
ruby '3.4.3'
ruby '3.4.1'
gem 'bootsnap', require: false
gem 'csv'
gem 'importmap-rails'
@ -33,7 +33,7 @@ group :development, :test do
gem 'factory_bot_rails'
gem 'license_finder'
gem 'pry'
gem 'rspec-rails', '~> 8.0.0'
gem 'rspec-rails', '~> 7.1.0'
gem 'shoulda-matchers', '~> 6.0'
end
@ -51,7 +51,3 @@ gem 'chroma'
gem 'solid_queue', '~> 1.0'
gem 'devise', '~> 4.9'
gem 'wicked_pdf', '~> 2.8'
gem 'rqrcode', '~> 3.1'

View File

@ -1,29 +1,29 @@
GEM
remote: https://rubygems.org/
specs:
actioncable (8.0.2)
actionpack (= 8.0.2)
activesupport (= 8.0.2)
actioncable (8.0.1)
actionpack (= 8.0.1)
activesupport (= 8.0.1)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6)
actionmailbox (8.0.2)
actionpack (= 8.0.2)
activejob (= 8.0.2)
activerecord (= 8.0.2)
activestorage (= 8.0.2)
activesupport (= 8.0.2)
actionmailbox (8.0.1)
actionpack (= 8.0.1)
activejob (= 8.0.1)
activerecord (= 8.0.1)
activestorage (= 8.0.1)
activesupport (= 8.0.1)
mail (>= 2.8.0)
actionmailer (8.0.2)
actionpack (= 8.0.2)
actionview (= 8.0.2)
activejob (= 8.0.2)
activesupport (= 8.0.2)
actionmailer (8.0.1)
actionpack (= 8.0.1)
actionview (= 8.0.1)
activejob (= 8.0.1)
activesupport (= 8.0.1)
mail (>= 2.8.0)
rails-dom-testing (~> 2.2)
actionpack (8.0.2)
actionview (= 8.0.2)
activesupport (= 8.0.2)
actionpack (8.0.1)
actionview (= 8.0.1)
activesupport (= 8.0.1)
nokogiri (>= 1.8.5)
rack (>= 2.2.4)
rack-session (>= 1.0.1)
@ -31,35 +31,35 @@ GEM
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
useragent (~> 0.16)
actiontext (8.0.2)
actionpack (= 8.0.2)
activerecord (= 8.0.2)
activestorage (= 8.0.2)
activesupport (= 8.0.2)
actiontext (8.0.1)
actionpack (= 8.0.1)
activerecord (= 8.0.1)
activestorage (= 8.0.1)
activesupport (= 8.0.1)
globalid (>= 0.6.0)
nokogiri (>= 1.8.5)
actionview (8.0.2)
activesupport (= 8.0.2)
actionview (8.0.1)
activesupport (= 8.0.1)
builder (~> 3.1)
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
activejob (8.0.2)
activesupport (= 8.0.2)
activejob (8.0.1)
activesupport (= 8.0.1)
globalid (>= 0.3.6)
activemodel (8.0.2)
activesupport (= 8.0.2)
activerecord (8.0.2)
activemodel (= 8.0.2)
activesupport (= 8.0.2)
activemodel (8.0.1)
activesupport (= 8.0.1)
activerecord (8.0.1)
activemodel (= 8.0.1)
activesupport (= 8.0.1)
timeout (>= 0.4.0)
activestorage (8.0.2)
actionpack (= 8.0.2)
activejob (= 8.0.2)
activerecord (= 8.0.2)
activesupport (= 8.0.2)
activestorage (8.0.1)
actionpack (= 8.0.1)
activejob (= 8.0.1)
activerecord (= 8.0.1)
activesupport (= 8.0.1)
marcel (~> 1.0)
activesupport (8.0.2)
activesupport (8.0.1)
base64
benchmark (>= 0.3)
bigdecimal
@ -76,33 +76,30 @@ GEM
rails (>= 6.0)
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
annotaterb (4.17.0)
activerecord (>= 6.0.0)
activesupport (>= 6.0.0)
ast (2.4.3)
annotaterb (4.13.0)
ast (2.4.2)
babel-source (5.8.35)
babel-transpiler (0.7.0)
babel-source (>= 4.0, < 6)
execjs (~> 2.0)
base64 (0.3.0)
base64 (0.2.0)
bcrypt (3.1.20)
benchmark (0.4.1)
bigdecimal (3.2.2)
benchmark (0.4.0)
bigdecimal (3.1.9)
bindex (0.8.1)
bootsnap (1.18.6)
bootsnap (1.18.4)
msgpack (~> 1.2)
builder (3.3.0)
childprocess (5.1.0)
logger (~> 1.5)
chroma (0.2.0)
chunky_png (1.4.0)
coderay (1.1.3)
concurrent-ruby (1.3.5)
connection_pool (2.5.3)
concurrent-ruby (1.3.4)
connection_pool (2.4.1)
crass (1.0.6)
csv (3.3.5)
csv (3.3.2)
date (3.4.1)
debug (1.11.0)
debug (1.10.0)
irb (~> 1.10)
reline (>= 0.3.8)
devise (4.9.4)
@ -111,44 +108,42 @@ GEM
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
diff-lcs (1.6.2)
drb (2.2.3)
erb (5.0.1)
diff-lcs (1.5.1)
drb (2.2.1)
erubi (1.13.1)
et-orbi (1.2.11)
tzinfo
execjs (2.9.1)
factory_bot (6.5.4)
activesupport (>= 6.1.0)
factory_bot_rails (6.5.0)
factory_bot (~> 6.5)
railties (>= 6.1.0)
faker (3.5.2)
factory_bot (6.4.6)
activesupport (>= 5.0.0)
factory_bot_rails (6.4.3)
factory_bot (~> 6.4)
railties (>= 5.0.0)
faker (3.5.1)
i18n (>= 1.8.11, < 2)
fugit (1.11.1)
et-orbi (~> 1, >= 1.2.11)
raabro (~> 1.4)
globalid (1.2.1)
activesupport (>= 6.1)
httparty (0.23.1)
httparty (0.22.0)
csv
mini_mime (>= 1.0.0)
multi_xml (>= 0.5.2)
i18n (1.14.7)
i18n (1.14.6)
concurrent-ruby (~> 1.0)
importmap-rails (2.1.0)
actionpack (>= 6.0.0)
activesupport (>= 6.0.0)
railties (>= 6.0.0)
io-console (0.8.0)
irb (1.15.2)
pp (>= 0.6.0)
irb (1.14.3)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
jbuilder (2.13.0)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
json (2.12.2)
json (2.9.1)
json-schema (5.0.1)
addressable (~> 2.8)
jsonapi-deserializable (0.2.0)
@ -162,7 +157,7 @@ GEM
jsonapi-renderer (0.2.2)
jsonapi-serializable (0.3.1)
jsonapi-renderer (~> 0.2.0)
language_server-protocol (3.17.0.5)
language_server-protocol (3.17.0.3)
launchy (3.0.1)
addressable (~> 2.8)
childprocess (~> 5.0)
@ -181,9 +176,8 @@ GEM
tomlrb (>= 1.3, < 2.1)
with_env (= 1.1.0)
xml-simple (~> 1.1.9)
lint_roller (1.1.0)
logger (1.7.0)
loofah (2.24.1)
logger (1.6.5)
loofah (2.23.1)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
mail (2.8.1)
@ -194,105 +188,97 @@ GEM
marcel (1.0.4)
method_source (1.1.0)
mini_mime (1.1.5)
mini_portile2 (2.8.9)
minitest (5.25.5)
mini_portile2 (2.8.8)
minitest (5.25.4)
money (6.19.0)
i18n (>= 0.6.4, <= 2)
msgpack (1.7.5)
msgpack (1.7.2)
multi_xml (0.7.1)
bigdecimal (~> 3.1)
net-imap (0.5.6)
net-imap (0.5.2)
date
net-protocol
net-pop (0.1.2)
net-protocol
net-protocol (0.2.2)
timeout
net-smtp (0.5.1)
net-smtp (0.5.0)
net-protocol
nio4r (2.7.4)
nokogiri (1.18.8)
nokogiri (1.18.1)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nokogiri (1.18.8-aarch64-linux-gnu)
nokogiri (1.18.1-aarch64-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.8-arm-linux-gnu)
nokogiri (1.18.1-arm-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.8-arm64-darwin)
nokogiri (1.18.1-arm64-darwin)
racc (~> 1.4)
nokogiri (1.18.8-x86_64-darwin)
nokogiri (1.18.1-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.18.8-x86_64-linux-gnu)
nokogiri (1.18.1-x86_64-linux-gnu)
racc (~> 1.4)
orm_adapter (0.5.0)
ostruct (0.6.2)
parallel (1.27.0)
parser (3.3.8.0)
parallel (1.26.3)
parser (3.3.7.0)
ast (~> 2.4.1)
racc
pg (1.5.9)
pluck_to_hash (1.0.2)
activerecord (>= 4.0.2)
activesupport (>= 4.0.2)
pp (0.6.2)
prettyprint
prettyprint (0.2.0)
prism (1.4.0)
pry (0.15.2)
coderay (~> 1.1)
method_source (~> 1.0)
psych (5.2.6)
psych (5.2.2)
date
stringio
public_suffix (6.0.1)
puma (6.6.0)
puma (6.5.0)
nio4r (~> 2.0)
raabro (1.4.0)
racc (1.8.1)
rack (3.1.16)
rack-cors (3.0.0)
logger
rack (>= 3.0.14)
rack-session (2.1.1)
base64 (>= 0.1.0)
rack (3.1.8)
rack-cors (2.0.2)
rack (>= 2.0.0)
rack-session (2.0.0)
rack (>= 3.0.0)
rack-test (2.2.0)
rack-test (2.1.0)
rack (>= 1.3)
rackup (2.2.1)
rack (>= 3)
rails (8.0.2)
actioncable (= 8.0.2)
actionmailbox (= 8.0.2)
actionmailer (= 8.0.2)
actionpack (= 8.0.2)
actiontext (= 8.0.2)
actionview (= 8.0.2)
activejob (= 8.0.2)
activemodel (= 8.0.2)
activerecord (= 8.0.2)
activestorage (= 8.0.2)
activesupport (= 8.0.2)
rails (8.0.1)
actioncable (= 8.0.1)
actionmailbox (= 8.0.1)
actionmailer (= 8.0.1)
actionpack (= 8.0.1)
actiontext (= 8.0.1)
actionview (= 8.0.1)
activejob (= 8.0.1)
activemodel (= 8.0.1)
activerecord (= 8.0.1)
activestorage (= 8.0.1)
activesupport (= 8.0.1)
bundler (>= 1.15.0)
railties (= 8.0.2)
rails-dom-testing (2.3.0)
railties (= 8.0.1)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
nokogiri (>= 1.6)
rails-html-sanitizer (1.6.2)
loofah (~> 2.21)
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
railties (8.0.2)
actionpack (= 8.0.2)
activesupport (= 8.0.2)
railties (8.0.1)
actionpack (= 8.0.1)
activesupport (= 8.0.1)
irb (~> 1.13)
rackup (>= 1.0.0)
rake (>= 12.2)
thor (~> 1.0, >= 1.2.2)
zeitwerk (~> 2.6)
rainbow (3.1.1)
rake (13.3.0)
rdoc (6.14.2)
erb
rake (13.2.1)
rdoc (6.10.0)
psych (>= 4.0.0)
react-rails (3.2.1)
babel-transpiler (>= 0.7.0)
@ -300,38 +286,34 @@ GEM
execjs
railties (>= 3.2)
tilt
redis (5.4.1)
redis (5.3.0)
redis-client (>= 0.22.0)
redis-client (0.23.2)
redis-client (0.22.2)
connection_pool
regexp_parser (2.10.0)
reline (0.6.1)
reline (0.6.0)
io-console (~> 0.5)
responders (3.1.1)
actionpack (>= 5.2)
railties (>= 5.2)
rexml (3.3.9)
rqrcode (3.1.0)
chunky_png (~> 1.0)
rqrcode_core (~> 2.0)
rqrcode_core (2.0.0)
rspec-core (3.13.4)
rspec-core (3.13.2)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.5)
rspec-expectations (3.13.3)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.5)
rspec-mocks (3.13.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-rails (8.0.1)
actionpack (>= 7.2)
activesupport (>= 7.2)
railties (>= 7.2)
rspec-rails (7.1.0)
actionpack (>= 7.0)
activesupport (>= 7.0)
railties (>= 7.0)
rspec-core (~> 3.13)
rspec-expectations (~> 3.13)
rspec-mocks (~> 3.13)
rspec-support (~> 3.13)
rspec-support (3.13.4)
rspec-support (3.13.1)
rswag (2.16.0)
rswag-api (= 2.16.0)
rswag-specs (= 2.16.0)
@ -347,44 +329,38 @@ GEM
rswag-ui (2.16.0)
actionpack (>= 5.2, < 8.1)
railties (>= 5.2, < 8.1)
rubocop (1.78.0)
rubocop (1.71.0)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.45.1, < 2.0)
rubocop-ast (>= 1.36.2, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.45.1)
parser (>= 3.3.7.2)
prism (~> 1.4)
rubocop-factory_bot (2.27.1)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-rails (2.32.0)
rubocop-ast (1.37.0)
parser (>= 3.3.1.0)
rubocop-factory_bot (2.26.1)
rubocop (~> 1.61)
rubocop-rails (2.29.0)
activesupport (>= 4.2.0)
lint_roller (~> 1.1)
rack (>= 1.1)
rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.44.0, < 2.0)
rubocop-rspec (3.6.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-rspec_rails (2.31.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-rspec (~> 3.5)
rubocop (>= 1.52.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rspec (3.4.0)
rubocop (~> 1.61)
rubocop-rspec_rails (2.30.0)
rubocop (~> 1.61)
rubocop-rspec (~> 3, >= 3.0.1)
ruby-progressbar (1.13.0)
rubytree (2.1.1)
json (~> 2.0, > 2.9)
rubyzip (2.3.2)
securerandom (0.4.1)
shoulda-matchers (6.5.0)
shoulda-matchers (6.4.0)
activesupport (>= 5.2.0)
solid_queue (1.2.0)
solid_queue (1.1.2)
activejob (>= 7.1)
activerecord (>= 7.1)
concurrent-ruby (>= 1.3.1)
@ -400,18 +376,18 @@ GEM
sprockets (>= 3.0.0)
stimulus-rails (1.3.4)
railties (>= 6.0.0)
stringio (3.1.7)
stringio (3.1.2)
thor (1.3.2)
tilt (2.4.0)
timeout (0.4.3)
tomlrb (2.0.3)
turbo-rails (2.0.16)
actionpack (>= 7.1.0)
railties (>= 7.1.0)
turbo-rails (2.0.11)
actionpack (>= 6.0.0)
railties (>= 6.0.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.6.0)
uri (1.0.3)
uri (1.0.2)
useragent (0.16.11)
warden (1.2.9)
rack (>= 2.0.9)
@ -420,17 +396,13 @@ GEM
activemodel (>= 6.0.0)
bindex (>= 0.4.0)
railties (>= 6.0.0)
websocket-driver (0.7.7)
base64
websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
wicked_pdf (2.8.2)
activesupport
ostruct
with_env (1.1.0)
xml-simple (1.1.9)
rexml
zeitwerk (2.7.3)
zeitwerk (2.7.1)
PLATFORMS
aarch64-linux
@ -465,8 +437,7 @@ DEPENDENCIES
rails (~> 8.0.0, >= 8.0.0)
react-rails
redis (>= 4.0.1)
rqrcode (~> 3.1)
rspec-rails (~> 8.0.0)
rspec-rails (~> 7.1.0)
rswag
rubocop
rubocop-factory_bot
@ -481,62 +452,59 @@ DEPENDENCIES
turbo-rails
tzinfo-data
web-console
wicked_pdf (~> 2.8)
CHECKSUMS
actioncable (8.0.2) sha256=7bcce2df62e91a80143592600e16583c273e98aab50ae40a9f6a2604bb3289a0
actionmailbox (8.0.2) sha256=3d8fb3453913e6257da4d02004bbfa2b997dfd10672f8d990e95013983e2cedb
actionmailer (8.0.2) sha256=b0c968b38576ec56a3dc2795931818e0aaae6a18cc9801f53f175c12d4b277d0
actionpack (8.0.2) sha256=93e703064f3815295ccf820f57acbca719aec836749597da9262781c9b2f4b78
actiontext (8.0.2) sha256=a40db32032ee2fbb479d5d69318c4284344c1cda73836fd73ffcdb917d203abf
actionview (8.0.2) sha256=e038e1405cdfc18f04f17243da4fb8eeda3a4992f63a6d70a7281d255cf7cebb
activejob (8.0.2) sha256=b0228b45e36b1ef3a081c684e81494147e094a6baf729018756ccf125b1853ca
activemodel (8.0.2) sha256=0ae1fb7fa1fae0699ba041a9e97702df42ea3b13f2d39f2d0fde51fca5f0656c
activerecord (8.0.2) sha256=793470b92c44e4198d0262ac60086b7822f0ea585079ad67e32a6e4c86f2d90a
activestorage (8.0.2) sha256=f83d221e0f06ae38f2200e55490bd155c76d0add330f6e300e8646048d672977
activesupport (8.0.2) sha256=8565cddba31b900cdc17682fd66ecd020441e3eef320a9930285394e8c07a45e
actioncable (8.0.1) sha256=808bff2a4e3aba36f66f0cd65d7a1579ad52fb65e99304442c46051a79689d9b
actionmailbox (8.0.1) sha256=bbc7db779be857fb6eb5b53f313d3881cd8cda38a150c3aa25f89f2f9977b08c
actionmailer (8.0.1) sha256=7b074e9590e4ec5cebd2fc91d1f9ba4c61bbd4bbd4376f731527da187cd39952
actionpack (8.0.1) sha256=c764e4bfc0ad9d3505c09ef9b6fbf9eca4292793550c6b7e2ea93167181bfcba
actiontext (8.0.1) sha256=f232d303e854db2098f34d7331fe493a72dc2e53dfce80fbd517c7b93d4b05b2
actionview (8.0.1) sha256=3005e3de5ca49ea789bf1ad46002d63fe5aa543c61c341239d3c533757e64f8a
activejob (8.0.1) sha256=95acd9a32d498d3a458efbb317f6191fb678758cde0ebb6c68f0b25e0fe3477f
activemodel (8.0.1) sha256=f46292fd6dcc128e18d588854298a933fd9eb22544c412b414ec02821062dc78
activerecord (8.0.1) sha256=34a7f0610660bb704f0363025d4b8d35ffe8ddc8f5b8147e0809171f724b5306
activestorage (8.0.1) sha256=91a8f156638568fac971ff25962a617d9c58fdc0e44eb6bd0edff36aff7df205
activesupport (8.0.1) sha256=fd5bc74641c24ac3541055c2879789198ff42adee3e39c2933289ba008912e37
acts_as_tenant (1.0.1) sha256=6944e4d64533337938a8817a6b4ff9b11189c9dcc0b1333bb89f3821a4c14c53
addressable (2.8.7) sha256=462986537cf3735ab5f3c0f557f14155d778f4b43ea4f485a9deb9c8f7c58232
annotaterb (4.17.0) sha256=f0338f8aaadd5c47fa3deaccb560a54abcdde29aca6f69f4b94726ea9256b4bd
ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
annotaterb (4.13.0) sha256=6f472912002fefa735665b4132de47d0134ebf1efb76a7ef05f579cc4a6b2ff1
ast (2.4.2) sha256=1e280232e6a33754cde542bc5ef85520b74db2aac73ec14acef453784447cc12
babel-source (5.8.35) sha256=79ef222a9dcb867ac2efa3b0da35b4bcb15a4bfa67b6b2dcbf1e9a29104498d9
babel-transpiler (0.7.0) sha256=4c06f4ad9e8e1cabe94f99e11df2f140bb72aca9ba067dbb49dc14d9b98d1570
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
base64 (0.2.0) sha256=0f25e9b21a02a0cc0cea8ef92b2041035d39350946e8789c562b2d1a3da01507
bcrypt (3.1.20) sha256=8410f8c7b3ed54a3c00cd2456bf13917d695117f033218e2483b2e40b0784099
benchmark (0.4.1) sha256=d4ef40037bba27f03b28013e219b950b82bace296549ec15a78016552f8d2cce
bigdecimal (3.2.2) sha256=39085f76b495eb39a79ce07af716f3a6829bc35eb44f2195e2753749f2fa5adc
benchmark (0.4.0) sha256=0f12f8c495545e3710c3e4f0480f63f06b4c842cc94cec7f33a956f5180e874a
bigdecimal (3.1.9) sha256=2ffc742031521ad69c2dfc815a98e426a230a3d22aeac1995826a75dabfad8cc
bindex (0.8.1) sha256=7b1ecc9dc539ed8bccfc8cb4d2732046227b09d6f37582ff12e50a5047ceb17e
bootsnap (1.18.6) sha256=0ae2393c1e911e38be0f24e9173e7be570c3650128251bf06240046f84a07d00
bootsnap (1.18.4) sha256=ac4c42af397f7ee15521820198daeff545e4c360d2772c601fbdc2c07d92af55
builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
childprocess (5.1.0) sha256=9a8d484be2fd4096a0e90a0cd3e449a05bc3aa33f8ac9e4d6dcef6ac1455b6ec
chroma (0.2.0) sha256=64bdcd36a4765fbcd45adc64960cc153101300b4918f90ffdd89f4e2eb954b54
chunky_png (1.4.0) sha256=89d5b31b55c0cf4da3cf89a2b4ebc3178d8abe8cbaf116a1dba95668502fdcfe
coderay (1.1.3) sha256=dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b
concurrent-ruby (1.3.5) sha256=813b3e37aca6df2a21a3b9f1d497f8cbab24a2b94cab325bffe65ee0f6cbebc6
connection_pool (2.5.3) sha256=cfd74a82b9b094d1ce30c4f1a346da23ee19dc8a062a16a85f58eab1ced4305b
concurrent-ruby (1.3.4) sha256=d4aa926339b0a86b5b5054a0a8c580163e6f5dcbdfd0f4bb916b1a2570731c32
connection_pool (2.4.1) sha256=0f40cf997091f1f04ff66da67eabd61a9fe0d4928b9a3645228532512fab62f4
crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d
csv (3.3.5) sha256=6e5134ac3383ef728b7f02725d9872934f523cb40b961479f69cf3afa6c8e73f
csv (3.3.2) sha256=6ff0c135e65e485d1864dde6c1703b60d34cc9e19bed8452834a0b28a519bd4e
date (3.4.1) sha256=bf268e14ef7158009bfeaec40b5fa3c7271906e88b196d958a89d4b408abe64f
debug (1.11.0) sha256=1425db64cfa0130c952684e3dc974985be201dd62899bf4bbe3f8b5d6cf1aef2
debug (1.10.0) sha256=11e28ca74875979e612444104f3972bd5ffb9e79179907d7ad46dba44bd2e7a4
devise (4.9.4) sha256=920042fe5e704c548aa4eb65ebdd65980b83ffae67feb32c697206bfd975a7f8
diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
erb (5.0.1) sha256=760439803b36cc93eca8a266aab614614e588024a89bc30a62e78d98ff452c23
diff-lcs (1.5.1) sha256=273223dfb40685548436d32b4733aa67351769c7dea621da7d9dd4813e63ddfe
drb (2.2.1) sha256=e9d472bf785f558b96b25358bae115646da0dbfd45107ad858b0bc0d935cb340
erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9
et-orbi (1.2.11) sha256=d26e868cc21db88280a9ec1a50aa3da5d267eb9b2037ba7b831d6c2731f5df64
execjs (2.9.1) sha256=e8fd066f6df60c8e8fbebc32c6fb356b5212c77374e8416a9019ca4bb154dcfb
factory_bot (6.5.4) sha256=4707fb7d80a7c14d71feb069460587bfc342e4ff1ef28097e0ad69d5ddfce613
factory_bot_rails (6.5.0) sha256=4a7b61635424a57cc60412a18b72b9dcfb02fabfce2c930447a01dce8b37c0a2
faker (3.5.2) sha256=f9a80291b2e3f259801d1dd552f0732fe04dce5d1f74e798365bc0413789c473
factory_bot (6.4.6) sha256=1a9486ce98d318d740d8f5804b885a8265a28f326ecf2bcd4ce9fb27a71a6e04
factory_bot_rails (6.4.3) sha256=ea73ceac1c0ff3dc11fff390bf2ea8a2604066525ed8ecd3b3bc2c267226dcc8
faker (3.5.1) sha256=1ad1fbea279d882f486059c23fe3ddb816ccd1d7052c05a45014b4450d859bfc
fugit (1.11.1) sha256=e89485e7be22226d8e9c6da411664d0660284b4b1c08cacb540f505907869868
globalid (1.2.1) sha256=70bf76711871f843dbba72beb8613229a49429d1866828476f9c9d6ccc327ce9
httparty (0.23.1) sha256=3ac1dd62f2010f6ece551716f5ceec2b2012011d89f1751917ab7f724e966b55
i18n (1.14.7) sha256=ceba573f8138ff2c0915427f1fc5bdf4aa3ab8ae88c8ce255eb3ecf0a11a5d0f
httparty (0.22.0) sha256=78652a5c9471cf0093d3b2083c2295c9c8f12b44c65112f1846af2b71430fa6c
i18n (1.14.6) sha256=dc229a74f5d181f09942dd60ab5d6e667f7392c4ee826f35096db36d1fe3614c
importmap-rails (2.1.0) sha256=9f10c67d60651a547579f448100d033df311c5d5db578301374aeb774faae741
io-console (0.8.0) sha256=cd6a9facbc69871d69b2cb8b926fc6ea7ef06f06e505e81a64f14a470fddefa2
irb (1.15.2) sha256=222f32952e278da34b58ffe45e8634bf4afc2dc7aa9da23fed67e581aa50fdba
irb (1.14.3) sha256=c457f1f2f1438ae9ce5c5be3981ae2138dec7fb894c7d73777eeeb0a6c0d0752
jbuilder (2.13.0) sha256=7200a38a1c0081aa81b7a9757e7a299db75bc58cf1fd45ca7919a91627d227d6
json (2.12.2) sha256=ba94a48ad265605c8fa9a50a5892f3ba6a02661aa010f638211f3cb36f44abf4
json (2.9.1) sha256=d2bdef4644052fad91c1785d48263756fe32fcac08b96a20bb15840e96550d11
json-schema (5.0.1) sha256=bef71a82c600a42594911553522e143f7634affc198ed507ef3ded2f920a74a9
jsonapi-deserializable (0.2.0) sha256=5f0ca2d3f8404cce1584a314e8a3753be32a56054c942adfe997b87e92bce147
jsonapi-parser (0.1.1) sha256=9ee0dc031e88fc7548d56fab66f9716d1e1c06f972b529b8c4617bc42a097020
@ -544,115 +512,107 @@ CHECKSUMS
jsonapi-rb (0.5.0) sha256=7922a164278f506c43d56277f6bd0800a0b603cc985f7f63fe7241b2628bd105
jsonapi-renderer (0.2.2) sha256=b5c44b033d61b4abdb6500fa4ab84807ca0b36ea0e59e47a2c3ca7095a6e447b
jsonapi-serializable (0.3.1) sha256=221e657677659d798e268a33ec97a83ec5ea0e4233f931358db84e88056552e9
language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
language_server-protocol (3.17.0.3) sha256=3d5c58c02f44a20d972957a9febe386d7e7468ab3900ce6bd2b563dd910c6b3f
launchy (3.0.1) sha256=b7fa60bda0197cf57614e271a250a8ca1f6a34ab889a3c73f67ec5d57c8a7f2c
letter_opener (1.10.0) sha256=2ff33f2e3b5c3c26d1959be54b395c086ca6d44826e8bf41a14ff96fdf1bdbb2
letter_opener_web (3.0.0) sha256=3f391efe0e8b9b24becfab5537dfb17a5cf5eb532038f947daab58cb4b749860
license_finder (7.2.1) sha256=179ead19b64b170638b72fd16024233813673ac9d20d5ba75ae0b4444887ef14
lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
loofah (2.24.1) sha256=655a30842b70ec476410b347ab1cd2a5b92da46a19044357bbd9f401b009a337
logger (1.6.5) sha256=c3cfe56d01656490ddd103d38b8993d73d86296adebc5f58cefc9ec03741e56b
loofah (2.23.1) sha256=d0a07422cb3b69272e124afa914ef6d517e30d5496b7f1c1fc5b95481f13f75e
mail (2.8.1) sha256=ec3b9fadcf2b3755c78785cb17bc9a0ca9ee9857108a64b6f5cfc9c0b5bfc9ad
marcel (1.0.4) sha256=0d5649feb64b8f19f3d3468b96c680bae9746335d02194270287868a661516a4
method_source (1.1.0) sha256=181301c9c45b731b4769bc81e8860e72f9161ad7d66dd99103c9ab84f560f5c5
mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef
mini_portile2 (2.8.9) sha256=0cd7c7f824e010c072e33f68bc02d85a00aeb6fce05bb4819c03dfd3c140c289
minitest (5.25.5) sha256=391b6c6cb43a4802bfb7c93af1ebe2ac66a210293f4a3fb7db36f2fc7dc2c756
mini_portile2 (2.8.8) sha256=8e47136cdac04ce81750bb6c09733b37895bf06962554e4b4056d78168d70a75
minitest (5.25.4) sha256=9cf2cae25ac4dfc90c988ebc3b917f53c054978b673273da1bd20bcb0778f947
money (6.19.0) sha256=ec936fa1e42f2783719241ed9fd52725d0efa628f928feea1eb5c37d5de7daf3
msgpack (1.7.5) sha256=ffb04979f51e6406823c03abe50e1da2c825c55a37dee138518cdd09d9d3aea8
msgpack (1.7.2) sha256=59ab62fd8a4d0dfbde45009f87eb6f158ab2628a7c48886b0256f175166baaa8
multi_xml (0.7.1) sha256=4fce100c68af588ff91b8ba90a0bb3f0466f06c909f21a32f4962059140ba61b
net-imap (0.5.6) sha256=1ede8048ee688a14206060bf37a716d18cb6ea00855f6c9b15daee97ee51fbe5
net-imap (0.5.2) sha256=e955b55e539712518bdb4eb747c6514f9c8d56ec4eb8eb573a82a6885a9effea
net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3
net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736
net-smtp (0.5.0) sha256=5fc0415e6ea1cc0b3dfea7270438ec22b278ca8d524986a3ae4e5ae8d087b42a
nio4r (2.7.4) sha256=d95dee68e0bb251b8ff90ac3423a511e3b784124e5db7ff5f4813a220ae73ca9
nokogiri (1.18.8) sha256=8c7464875d9ca7f71080c24c0db7bcaa3940e8be3c6fc4bcebccf8b9a0016365
nokogiri (1.18.8-aarch64-linux-gnu) sha256=36badd2eb281fca6214a5188e24a34399b15d89730639a068d12931e2adc210e
nokogiri (1.18.8-arm-linux-gnu) sha256=17de01ca3adf9f8e187883ed73c672344d3dbb3c260f88ffa1008e8dc255a28e
nokogiri (1.18.8-arm64-darwin) sha256=483b5b9fb33653f6f05cbe00d09ea315f268f0e707cfc809aa39b62993008212
nokogiri (1.18.8-x86_64-darwin) sha256=024cdfe7d9ae3466bba6c06f348fb2a8395d9426b66a3c82f1961b907945cc0c
nokogiri (1.18.8-x86_64-linux-gnu) sha256=4a747875db873d18a2985ee2c320a6070c4a414ad629da625fbc58d1a20e5ecc
nokogiri (1.18.1) sha256=df18be7e96c34736b6abfdeda80c6e845134fb9afe2fe5d4fbc1cf1f89c68475
nokogiri (1.18.1-aarch64-linux-gnu) sha256=35837013800e34342fcbaca305f8c49231f6bd4f779bfa23fe7b4686ae82d5b8
nokogiri (1.18.1-arm-linux-gnu) sha256=3b873fd6b0cd1ad7c77e87af701075bdfd14c9a6b2f2965c5e00ed29a5627a37
nokogiri (1.18.1-arm64-darwin) sha256=d75193f284c899d225943a8944479faedd995a7573ddd5c8308ffbdf2ec55204
nokogiri (1.18.1-x86_64-darwin) sha256=d94e3aa6483577495fc8969d6b4b5c075840ce6b1ab09636a6d4177ad171051d
nokogiri (1.18.1-x86_64-linux-gnu) sha256=e516cf16ccde67ed4cc595a2621ca5ddd42562ecb24928914b0045a20a41620e
orm_adapter (0.5.0) sha256=aa5d0be5d540cbb46d3a93e88061f4ece6a25f6e97d6a47122beb84fe595e9b9
ostruct (0.6.2) sha256=6d7302a299e400a2c248d6ce0dad18fc3a5714e8096facc25ffd0c54ee57cfc0
parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
parser (3.3.8.0) sha256=2476364142b307fa5a1b1ece44f260728be23858a9c71078e956131a75453c45
parallel (1.26.3) sha256=d86babb7a2b814be9f4b81587bf0b6ce2da7d45969fab24d8ae4bf2bb4d4c7ef
parser (3.3.7.0) sha256=7449011771e3e7881297859b849de26a6f4fccd515bece9520a87e7d2116119b
pg (1.5.9) sha256=761efbdf73b66516f0c26fcbe6515dc7500c3f0aa1a1b853feae245433c64fdc
pluck_to_hash (1.0.2) sha256=1599906239716f98262a41493dd7d4cb72e8d83ad3d76d666deacfc5de50a47e
pp (0.6.2) sha256=947ec3120c6f92195f8ee8aa25a7b2c5297bb106d83b41baa02983686577b6ff
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
prism (1.4.0) sha256=dc0e3e00e93160213dc2a65519d9002a4a1e7b962db57d444cf1a71565bb703e
pry (0.15.2) sha256=12d54b8640d3fa29c9211dd4ffb08f3fd8bf7a4fd9b5a73ce5b59c8709385b6b
psych (5.2.6) sha256=814328aa5dcb6d604d32126a20bc1cbcf05521a5b49dbb1a8b30a07e580f316e
psych (5.2.2) sha256=a4a9477c85d3e858086c38cf64e7096abe40d1b1eed248b01020dec0ff9906ab
public_suffix (6.0.1) sha256=61d44e1cab5cbbbe5b31068481cf16976dd0dc1b6b07bd95617ef8c5e3e00c6f
puma (6.6.0) sha256=f25c06873eb3d5de5f0a4ebc783acc81a4ccfe580c760cfe323497798018ad87
puma (6.5.0) sha256=94d1b75cab7f356d52e4f1b17b9040a090889b341dbeee6ee3703f441dc189f2
raabro (1.4.0) sha256=d4fa9ff5172391edb92b242eed8be802d1934b1464061ae5e70d80962c5da882
racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
rack (3.1.16) sha256=efb5606c351efc56b85b10c3493055d0d35209d23f44792ec4e1183eb0234635
rack-cors (3.0.0) sha256=7b95be61db39606906b61b83bd7203fa802b0ceaaad8fcb2fef39e097bf53f68
rack-session (2.1.1) sha256=0b6dc07dea7e4b583f58a48e8b806d4c9f1c6c9214ebc202ec94562cbea2e4e9
rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463
rack (3.1.8) sha256=d3fbcbca43dc2b43c9c6d7dfbac01667ae58643c42cea10013d0da970218a1b1
rack-cors (2.0.2) sha256=415d4e1599891760c5dc9ef0349c7fecdf94f7c6a03e75b2e7c2b54b82adda1b
rack-session (2.0.0) sha256=db04b2063e180369192a9046b4559af311990af38c6a93d4c600cee4eb6d4e81
rack-test (2.1.0) sha256=0c61fc61904049d691922ea4bb99e28004ed3f43aa5cfd495024cc345f125dfb
rackup (2.2.1) sha256=f737191fd5c5b348b7f0a4412a3b86383f88c43e13b8217b63d4c8d90b9e798d
rails (8.0.2) sha256=fdfaa5a83ec0388e02864e88d515959caedc88053b5f701c4deb1652d8f164c6
rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d
rails (8.0.1) sha256=c86f4cd7834a67c1e5d04a77d35c88a5f56a20e2022ec416fa52c1af2cdc9491
rails-dom-testing (2.2.0) sha256=e515712e48df1f687a1d7c380fd7b07b8558faa26464474da64183a7426fa93b
rails-html-sanitizer (1.6.2) sha256=35fce2ca8242da8775c83b6ba9c1bcaad6751d9eb73c1abaa8403475ab89a560
railties (8.0.2) sha256=0d7c3f40c49ba74980f1bac1d4bb153a9331c5ee8a9631d89c7bf79db82e5cf9
railties (8.0.1) sha256=8f653c6b1b0721b553045bd0deda1f22074b9ddc2209526e6f7285fcf607ac51
rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
rake (13.3.0) sha256=96f5092d786ff412c62fde76f793cc0541bd84d2eb579caa529aa8a059934493
rdoc (6.14.2) sha256=9fdd44df130f856ae70cc9a264dfd659b9b40de369b16581f4ab746e42439226
rake (13.2.1) sha256=46cb38dae65d7d74b6020a4ac9d48afed8eb8149c040eccf0523bec91907059d
rdoc (6.10.0) sha256=db665021883ac9df3ba29cdf71aece960749888db1bf9615b4a584cfa3fa3eda
react-rails (3.2.1) sha256=2235db0b240517596b1cb3e26177ab5bc64d3a56579b0415ee242b1691f81f64
redis (5.4.1) sha256=b5e675b57ad22b15c9bcc765d5ac26f60b675408af916d31527af9bd5a81faae
redis-client (0.23.2) sha256=e33bab6682c8155cfef95e6dd296936bb9c2981a89fb578ace27a076fa2836fa
redis (5.3.0) sha256=6bf810c5ae889187f0c45f77db503310980310afa57cf1640d57f419ccda72b1
redis-client (0.22.2) sha256=31fee4b7cf04109b227327fabeaaf1fc5b652cf48a186a03bc607e40767bacc0
regexp_parser (2.10.0) sha256=cb6f0ddde88772cd64bff1dbbf68df66d376043fe2e66a9ef77fcb1b0c548c61
reline (0.6.1) sha256=1afcc9d7cb1029cdbe780d72f2f09251ce46d3780050f3ec39c3ccc6b60675fb
reline (0.6.0) sha256=57620375dcbe56ec09bac7192bfb7460c716bbf0054dc94345ecaa5438e539d2
responders (3.1.1) sha256=92f2a87e09028347368639cfb468f5fefa745cb0dc2377ef060db1cdd79a341a
rexml (3.3.9) sha256=d71875b85299f341edf47d44df0212e7658cbdf35aeb69cefdb63f57af3137c9
rqrcode (3.1.0) sha256=e2d5996375f6e9a013823c289ed575dbea678b8e0388574302c1fac563f098af
rqrcode_core (2.0.0) sha256=1e40b823ab57a96482a417fff5dd5c33645a00cea6ef5d9e342fecc5ef91d9ab
rspec-core (3.13.4) sha256=f9da156b7b775c82610a7b580624df51a55102f8c8e4a103b98f5d7a9fa23958
rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
rspec-mocks (3.13.5) sha256=e4338a6f285ada9fe56f5893f5457783af8194f5d08884d17a87321d5195ea81
rspec-rails (8.0.1) sha256=0c3700b10ab6d7c648c4cd554023d8c2b5b07e7f01205f7608f0c511cf686505
rspec-support (3.13.4) sha256=184b1814f6a968102b57df631892c7f1990a91c9a3b9e80ef892a0fc2a71a3f7
rspec-core (3.13.2) sha256=94fbda6e4738e478f1c7532b7cc241272fcdc8b9eac03a97338b1122e4573300
rspec-expectations (3.13.3) sha256=0e6b5af59b900147698ea0ff80456c4f2e69cac4394fbd392fbd1ca561f66c58
rspec-mocks (3.13.2) sha256=2327335def0e1665325a9b617e3af9ae20272741d80ac550336309a7c59abdef
rspec-rails (7.1.0) sha256=94585b69c4086ca79afae5cc8d2c5e314f6ad32a88c927f9c065b99596e3ee47
rspec-support (3.13.1) sha256=48877d4f15b772b7538f3693c22225f2eda490ba65a0515c4e7cf6f2f17de70f
rswag (2.16.0) sha256=f07ce41548b9bb51464c38bc7b95af22fee84b90f2d1197a515a623906353086
rswag-api (2.16.0) sha256=b653f7bd92e98be18b01ab4525d88950d7b0960e293a99f856b9efcee3ae6074
rswag-specs (2.16.0) sha256=8ba26085c408b0bd2ed21dc8015c80f417c7d34c63720ab7133c2549b5bd2a91
rswag-ui (2.16.0) sha256=a1f49e927dceda92e6e6e7c1000f1e217ee66c565f69e28131dc98b33cd3a04f
rubocop (1.78.0) sha256=8b74a6f912eb4fd3e6878851f7f7f45dcad8c7185c34250d4f952b0ee80d6bc0
rubocop-ast (1.45.1) sha256=94042e49adc17f187ba037b33f941ba7398fede77cdf4bffafba95190a473a3e
rubocop-factory_bot (2.27.1) sha256=9d744b5916778c1848e5fe6777cc69855bd96548853554ec239ba9961b8573fe
rubocop-rails (2.32.0) sha256=9fcc623c8722fe71e835e99c4a18b740b5b0d3fb69915d7f0777f00794b30490
rubocop-rspec (3.6.0) sha256=c0e4205871776727e54dee9cc91af5fd74578001551ba40e1fe1a1ab4b404479
rubocop-rspec_rails (2.31.0) sha256=775375e18a26a1184a812ef3054b79d218e85601b9ae897f38f8be24dddf1f45
rubocop (1.71.0) sha256=e19679efd447346ac476122313d3788ae23c38214790bcf660e984c747608bf0
rubocop-ast (1.37.0) sha256=9513ac88aaf113d04b52912533ffe46475de1362d4aa41141b51b2455827c080
rubocop-factory_bot (2.26.1) sha256=8de13cd4edcee5ca800f255188167ecef8dbfc3d1fae9f15734e9d2e755392aa
rubocop-rails (2.29.0) sha256=35bffd140c80671453aafac0e2d5ab5b3dd65736a3fc8f3936ccca226b89c234
rubocop-rspec (3.4.0) sha256=8721c13b6a8c9530a7ac481cea9423022f946fcf72428bda8289f8b57e4d4885
rubocop-rspec_rails (2.30.0) sha256=888112e83f9d7ef7ad2397e9d69a0b9614a4bae24f072c399804a180f80c4c46
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
rubytree (2.1.1) sha256=4925016356a81730e982f1f8c3b5f8da461f18906c77d238bad4c4ba896abd41
rubyzip (2.3.2) sha256=3f57e3935dc2255c414484fbf8d673b4909d8a6a57007ed754dde39342d2373f
securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
shoulda-matchers (6.5.0) sha256=ef6b572b2bed1ac4aba6ab2c5ff345a24b6d055a93a3d1c3bfc86d9d499e3f44
solid_queue (1.2.0) sha256=482ac5305cbe91ebf845627caec493fda8545bf22b18205df01afb80999e28de
shoulda-matchers (6.4.0) sha256=9055bb7f4bb342125fb860809798855c630e05ef5e75837b3168b8e6ee1608b0
solid_queue (1.1.2) sha256=178c9396d1cf0dac595c7508da90ddb397d25848ca007b5c5ed48e6ac6fc360c
sprockets (4.2.1) sha256=951b13dd2f2fcae840a7184722689a803e0ff9d2702d902bd844b196da773f97
sprockets-rails (3.5.2) sha256=a9e88e6ce9f8c912d349aa5401509165ec42326baf9e942a85de4b76dbc4119e
stimulus-rails (1.3.4) sha256=765676ffa1f33af64ce026d26b48e8ffb2e0b94e0f50e9119e11d6107d67cb06
stringio (3.1.7) sha256=5b78b7cb242a315fb4fca61a8255d62ec438f58da2b90be66048546ade4507fa
stringio (3.1.2) sha256=204f1828f85cdb39d57cac4abc6dc44b04505a223f131587f2e20ae3729ba131
thor (1.3.2) sha256=eef0293b9e24158ccad7ab383ae83534b7ad4ed99c09f96f1a6b036550abbeda
tilt (2.4.0) sha256=df74f29a451daed26591a85e8e0cebb198892cb75b6573394303acda273fba4d
timeout (0.4.3) sha256=9509f079b2b55fe4236d79633bd75e34c1c1e7e3fb4b56cb5fda61f80a0fe30e
tomlrb (2.0.3) sha256=c2736acf24919f793334023a4ff396c0647d93fce702a73c9d348deaa815d4f7
turbo-rails (2.0.16) sha256=d24e1b60f0c575b3549ecda967e5391027143f8220d837ed792c8d48ea0ea38d
turbo-rails (2.0.11) sha256=fc47674736372780abd2a4dc0d84bef242f5ca156a457cd7fa6308291e397fcf
tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
unicode-display_width (2.6.0) sha256=12279874bba6d5e4d2728cef814b19197dbb10d7a7837a869bab65da943b7f5a
uri (1.0.3) sha256=e9f2244608eea2f7bc357d954c65c910ce0399ca5e18a7a29207ac22d8767011
uri (1.0.2) sha256=b303504ceb7e5905771fa7fa14b649652fa949df18b5880d69cfb12494791e27
useragent (0.16.11) sha256=700e6413ad4bb954bb63547fa098dddf7b0ebe75b40cc6f93b8d54255b173844
warden (1.2.9) sha256=46684f885d35a69dbb883deabf85a222c8e427a957804719e143005df7a1efd0
web-console (4.2.1) sha256=e7bcf37a10ea2b4ec4281649d1cee461b32232d0a447e82c786e6841fd22fe20
websocket-driver (0.7.7) sha256=056d99f2cd545712cfb1291650fde7478e4f2661dc1db6a0fa3b966231a146b4
websocket-driver (0.7.6) sha256=f69400be7bc197879726ad8e6f5869a61823147372fd8928836a53c2c741d0db
websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241
wicked_pdf (2.8.2) sha256=648d9b0cec5a34adbc9bbf809731052a78119e2d6d323b9e4aa1383e1d683824
with_env (1.1.0) sha256=50b3e4f0a6cda8f90d8a6bd87a6261f6c381429abafb161c4c69ad4a0cd0b6e4
xml-simple (1.1.9) sha256=d21131e519c86f1a5bc2b6d2d57d46e6998e47f18ed249b25cad86433dbd695d
zeitwerk (2.7.3) sha256=b2e86b4a9b57d26ba68a15230dcc7fe6f040f06831ce64417b0621ad96ba3e85
zeitwerk (2.7.1) sha256=0945986050e4907140895378e74df1fe882a2271ed087cc6c6d6b00d415a2756
RUBY VERSION
ruby 3.4.3p32
ruby 3.4.1p0
BUNDLED WITH
2.6.1

View File

@ -57,12 +57,6 @@ The backend service will seed the database with fake data. It's worth noting tha
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.
Please, include this in your `/etc/hosts` file:
```
127.0.0.1 libre-wedding-planner.app.localhost
```
Once all containers have started, visit http://libre-wedding-planner.app.localhost/default/dashboard to load the application.
## Multitenancy

View File

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

View File

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

View File

@ -4,15 +4,7 @@
class TablesArrangementsController < ApplicationController
def index
current_digest = Tables::Distribution.digest(current_tenant)
render json: TablesArrangement
.order(valid: :desc)
.order(discomfort: :asc)
.select(:id, :name, :discomfort)
.select("digest = '#{current_digest}'::uuid as valid")
.limit(20)
.as_json(only: %i[id name discomfort valid])
render json: TablesArrangement.order(discomfort: :asc).limit(3).as_json(only: %i[id name discomfort])
end
def show
@ -24,12 +16,6 @@ class TablesArrangementsController < ApplicationController
.then { |result| render json: { id: params[:id], tables: result } }
end
def create
TableSimulatorJob.perform_later(current_tenant.id)
render json: {}, status: :created
end
private
def format(number:, guests:)

View File

@ -1,25 +0,0 @@
# Copyright (C) 2024-2025 LibreWeddingPlanner contributors
# frozen_string_literal: true
class WebsitesController < ApplicationController
skip_before_action :authenticate_user!, only: :show
def show
render json: current_tenant.website.as_json(only: %i[content]) || {}, status: :ok
end
def update
ActiveRecord::Base.transaction do
website = current_tenant.website || current_tenant.create_website
website.update!(website_params)
render json: website.as_json(only: %i[content]), status: :ok
end
end
private
def website_params
params.expect(website: [:content])
end
end

View File

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

View File

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

View File

@ -20,7 +20,7 @@
#
# Foreign Keys
#
# fk_rails_... (wedding_id => weddings.id) ON DELETE => cascade
# fk_rails_... (wedding_id => weddings.id)
#
class Expense < ApplicationRecord
acts_as_tenant :wedding

View File

@ -25,7 +25,7 @@
# Foreign Keys
#
# fk_rails_... (parent_id => groups.id)
# fk_rails_... (wedding_id => weddings.id) ON DELETE => cascade
# fk_rails_... (wedding_id => weddings.id)
#
class Group < ApplicationRecord
acts_as_tenant :wedding

View File

@ -6,32 +6,28 @@
#
# 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
# invitation_id :uuid
# wedding_id :uuid not null
# 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
# wedding_id :uuid not null
#
# Indexes
#
# index_guests_on_group_id (group_id)
# index_guests_on_invitation_id (invitation_id)
# index_guests_on_wedding_id (wedding_id)
# index_guests_on_group_id (group_id)
# index_guests_on_wedding_id (wedding_id)
#
# Foreign Keys
#
# fk_rails_... (group_id => groups.id)
# fk_rails_... (invitation_id => invitations.id)
# fk_rails_... (wedding_id => weddings.id) ON DELETE => cascade
# fk_rails_... (wedding_id => weddings.id)
#
class Guest < ApplicationRecord
acts_as_tenant :wedding
belongs_to :group, optional: true
belongs_to :invitation, optional: true
enum :status, {
considered: 0,
@ -45,5 +41,16 @@ class Guest < ApplicationRecord
scope :potential, -> { where.not(status: %i[declined considered]) }
after_destroy :recalculate_simulations
after_save :recalculate_simulations, if: :saved_change_to_status?
has_many :seats, dependent: :delete_all
private
def recalculate_simulations
TablesArrangement.delete_all
ActiveJob.perform_all_later(50.times.map { TableSimulatorJob.new(wedding_id) })
end
end

View File

@ -1,29 +0,0 @@
# Copyright (C) 2024-2025 LibreWeddingPlanner contributors
# frozen_string_literal: true
# == Schema Information
#
# Table name: invitations
#
# id :uuid not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
# wedding_id :uuid not null
#
# Indexes
#
# index_invitations_on_wedding_id (wedding_id)
#
# Foreign Keys
#
# fk_rails_... (wedding_id => weddings.id) ON DELETE => cascade
#
class Invitation < ApplicationRecord
acts_as_tenant :wedding
has_many :guests, dependent: :nullify
def url
"#{Rails.application.routes.url_helpers.root_url(slug: ActsAsTenant.current_tenant.slug)}/site/invitation/#{id}"
end
end

View File

@ -24,7 +24,7 @@
#
# fk_rails_... (guest_id => guests.id)
# fk_rails_... (tables_arrangement_id => tables_arrangements.id) ON DELETE => cascade
# fk_rails_... (wedding_id => weddings.id) ON DELETE => cascade
# fk_rails_... (wedding_id => weddings.id)
#
class Seat < ApplicationRecord
acts_as_tenant :wedding

View File

@ -7,7 +7,6 @@
# Table name: tables_arrangements
#
# id :uuid not null, primary key
# digest :uuid not null
# discomfort :integer
# name :string not null
# created_at :datetime not null
@ -20,7 +19,7 @@
#
# Foreign Keys
#
# fk_rails_... (wedding_id => weddings.id) ON DELETE => cascade
# fk_rails_... (wedding_id => weddings.id)
#
class TablesArrangement < ApplicationRecord
acts_as_tenant :wedding

View File

@ -32,7 +32,7 @@
#
# Foreign Keys
#
# fk_rails_... (wedding_id => weddings.id) ON DELETE => cascade
# fk_rails_... (wedding_id => weddings.id)
#
class User < ApplicationRecord
acts_as_tenant :wedding

View File

@ -1,25 +0,0 @@
# Copyright (C) 2024-2025 LibreWeddingPlanner contributors
# frozen_string_literal: true
# == Schema Information
#
# Table name: websites
#
# id :bigint not null, primary key
# content :text
# created_at :datetime not null
# updated_at :datetime not null
# wedding_id :uuid not null
#
# Indexes
#
# index_websites_on_wedding_id (wedding_id)
#
# Foreign Keys
#
# fk_rails_... (wedding_id => weddings.id)
#
class Website < ApplicationRecord
belongs_to :wedding
end

View File

@ -19,10 +19,4 @@ class Wedding < ApplicationRecord
SLUG_REGEX = /[a-z\d-]+/
validates :slug, presence: true, uniqueness: true, format: { with: /\A#{SLUG_REGEX}\z/ }
has_many :guests, dependent: :delete_all
has_many :groups, dependent: :delete_all
has_many :invitations, dependent: :delete_all
has_many :users, dependent: :delete_all
has_one :website, dependent: :destroy
end

View File

@ -5,12 +5,16 @@
class SerializableGuest < JSONAPI::Serializable::Resource
type 'guest'
attributes :id, :status
attributes :id, :group_id, :status
attribute :name do
@object.name
end
attribute :group_name do
@object.group.name
end
attribute :status do
@object.status.capitalize
end

View File

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

View File

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

View File

@ -6,26 +6,19 @@ require_relative '../../extensions/tree_node_extension'
module Tables
class Distribution
class << self
def digest(wedding)
Digest::UUID.uuid_v5(wedding.id, wedding.guests.potential.order(:id).pluck(:id).join)
end
end
attr_accessor :tables, :min_per_table, :max_per_table
attr_accessor :tables, :min_per_table, :max_per_table, :hierarchy
def initialize(min_per_table:, max_per_table:, hierarchy: AffinityGroupsHierarchy.new)
def initialize(min_per_table:, max_per_table:)
@min_per_table = min_per_table
@max_per_table = max_per_table
@hierarchy = hierarchy
@hierarchy = AffinityGroupsHierarchy.new
@tables = []
end
def random_distribution(people, random: Random.new)
def random_distribution(people)
min_tables = (people.count * 1.0 / @max_per_table).ceil
max_tables = (people.count * 1.0 / @min_per_table).ceil
table_size = random.rand(min_tables..max_tables)
@tables = people.in_groups(table_size, false)
@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 }
@ -42,8 +35,7 @@ module Tables
end
def deep_dup
self.class.new(min_per_table: @min_per_table, max_per_table: @max_per_table,
hierarchy: @hierarchy).tap do |new_distribution|
self.class.new(min_per_table: @min_per_table, max_per_table: @max_per_table).tap do |new_distribution|
new_distribution.tables = @tables.map(&:dup)
end
end
@ -62,10 +54,7 @@ module Tables
Seat.insert_all!(records_to_store)
arrangement.update!(
discomfort:,
digest: self.class.digest(tables.first.first.wedding)
)
arrangement.update!(discomfort:)
end
end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,8 +2,4 @@
ActsAsTenant.configure do |config|
config.require_tenant = !Rails.env.test?
end
Rails.application.console do
ActsAsTenant.current_tenant = Wedding.first
end
end

View File

@ -10,7 +10,7 @@ Rswag::Ui.configure do |c|
# (under openapi_root) as JSON or YAML endpoints, then the list below should
# correspond to the relative paths for those endpoints.
c.openapi_endpoint '/api/api-docs/v1/swagger.yaml', 'API V1 Docs'
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

View File

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

View File

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

View File

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

View File

@ -1,5 +0,0 @@
class AddGuestsDigestColumnToTablesArrangements < ActiveRecord::Migration[8.0]
def change
add_column :tables_arrangements, :digest, :uuid, null: false, default: 'gen_random_uuid()'
end
end

View File

@ -1,10 +0,0 @@
class CreateInvitations < ActiveRecord::Migration[8.0]
def change
create_table :invitations, id: :uuid do |t|
t.references :wedding, null: false, foreign_key: { on_delete: :cascade }, type: :uuid
t.timestamps
end
add_reference :guests, :invitation, foreign_key: true, type: :uuid
end
end

View File

@ -1,8 +0,0 @@
class FixCascadingWeddingDeletion < ActiveRecord::Migration[8.0]
def change
[:expenses, :groups, :guests, :seats, :tables_arrangements, :users].each do |table|
remove_foreign_key table, :weddings, column: :wedding_id
add_foreign_key table, :weddings, on_delete: :cascade
end
end
end

View File

@ -1,10 +0,0 @@
class CreateWebsites < ActiveRecord::Migration[8.0]
def change
create_table :websites do |t|
t.text :content
t.references :wedding, null: false, foreign_key: true, type: :uuid
t.timestamps
end
end
end

35
db/schema.rb generated
View File

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.0].define(version: 2025_06_08_181054) do
ActiveRecord::Schema[8.0].define(version: 2024_12_16_231415) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_catalog.plpgsql"
@ -63,19 +63,10 @@ ActiveRecord::Schema[8.0].define(version: 2025_06_08_181054) do
t.integer "status", default: 0
t.string "name"
t.uuid "wedding_id", null: false
t.uuid "invitation_id"
t.index ["group_id"], name: "index_guests_on_group_id"
t.index ["invitation_id"], name: "index_guests_on_invitation_id"
t.index ["wedding_id"], name: "index_guests_on_wedding_id"
end
create_table "invitations", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.uuid "wedding_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["wedding_id"], name: "index_invitations_on_wedding_id"
end
create_table "seats", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.uuid "guest_id", null: false
t.uuid "tables_arrangement_id", null: false
@ -215,7 +206,6 @@ ActiveRecord::Schema[8.0].define(version: 2025_06_08_181054) do
t.datetime "updated_at", null: false
t.string "name", null: false
t.uuid "wedding_id", null: false
t.uuid "digest", default: -> { "gen_random_uuid()" }, null: false
t.index ["wedding_id"], name: "index_tables_arrangements_on_wedding_id"
end
@ -241,14 +231,6 @@ ActiveRecord::Schema[8.0].define(version: 2025_06_08_181054) do
t.index ["wedding_id"], name: "index_users_on_wedding_id"
end
create_table "websites", force: :cascade do |t|
t.text "content"
t.uuid "wedding_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["wedding_id"], name: "index_websites_on_wedding_id"
end
create_table "weddings", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "slug", null: false
t.datetime "created_at", null: false
@ -256,25 +238,22 @@ ActiveRecord::Schema[8.0].define(version: 2025_06_08_181054) do
t.index ["slug"], name: "index_weddings_on_slug", unique: true
end
add_foreign_key "expenses", "weddings", on_delete: :cascade
add_foreign_key "expenses", "weddings"
add_foreign_key "group_affinities", "groups", column: "group_a_id"
add_foreign_key "group_affinities", "groups", column: "group_b_id"
add_foreign_key "groups", "groups", column: "parent_id"
add_foreign_key "groups", "weddings", on_delete: :cascade
add_foreign_key "groups", "weddings"
add_foreign_key "guests", "groups"
add_foreign_key "guests", "invitations"
add_foreign_key "guests", "weddings", on_delete: :cascade
add_foreign_key "invitations", "weddings", on_delete: :cascade
add_foreign_key "guests", "weddings"
add_foreign_key "seats", "guests"
add_foreign_key "seats", "tables_arrangements", on_delete: :cascade
add_foreign_key "seats", "weddings", on_delete: :cascade
add_foreign_key "seats", "weddings"
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
add_foreign_key "tables_arrangements", "weddings", on_delete: :cascade
add_foreign_key "users", "weddings", on_delete: :cascade
add_foreign_key "websites", "weddings"
add_foreign_key "tables_arrangements", "weddings"
add_foreign_key "users", "weddings"
end

View File

@ -1,33 +1,33 @@
# frozen_string_literal: true
# Copyright (C) 2024-2025 LibreWeddingPlanner contributors
NUMBER_OF_GUESTS = 200
NUMBER_OF_GUESTS = 50
ActsAsTenant.without_tenant do
GroupAffinity.delete_all
TablesArrangement.delete_all
Expense.delete_all
Guest.delete_all
Group.delete_all
Wedding.delete_all
end
wedding = Wedding.create!(slug: :default)
ActsAsTenant.with_tenant(wedding) do
[
{ name: 'Photographer', amount: 3000, pricing_type: 'fixed' },
{ name: 'Country house', amount: 6000, pricing_type: 'fixed' },
{ name: 'Catering', amount: 200, pricing_type: 'per_person' },
{ name: 'Flowers', amount: 500, pricing_type: 'fixed' },
{ name: 'Band', amount: 1000, pricing_type: 'fixed' },
{ name: 'Wedding planner', amount: 2000, pricing_type: 'fixed' },
{ name: 'Dress', amount: 1000, pricing_type: 'fixed' },
{ name: 'Suit', amount: 500, pricing_type: 'fixed' },
{ name: 'Rings', amount: 1000, pricing_type: 'fixed' },
{ name: 'Makeup', amount: 200, pricing_type: 'fixed' },
{ name: 'Hair', amount: 200, pricing_type: 'fixed' },
{ name: 'Transportation', amount: 3000, pricing_type: 'fixed' },
{ name: 'Invitations', amount: 200, pricing_type: 'fixed' },
{ name: 'Cake', amount: 500, pricing_type: 'fixed' }
].then { Expense.insert_all!(it) }
Expense.create!(name: 'Photographer', amount: 3000, pricing_type: 'fixed')
Expense.create!(name: 'Country house', amount: 6000, pricing_type: 'fixed')
Expense.create!(name: 'Catering', amount: 200, pricing_type: 'per_person')
Expense.create!(name: 'Flowers', amount: 500, pricing_type: 'fixed')
Expense.create!(name: 'Band', amount: 1000, pricing_type: 'fixed')
Expense.create!(name: 'Wedding planner', amount: 2000, pricing_type: 'fixed')
Expense.create!(name: 'Dress', amount: 1000, pricing_type: 'fixed')
Expense.create!(name: 'Suit', amount: 500, pricing_type: 'fixed')
Expense.create!(name: 'Rings', amount: 1000, pricing_type: 'fixed')
Expense.create!(name: 'Makeup', amount: 200, pricing_type: 'fixed')
Expense.create!(name: 'Hair', amount: 200, pricing_type: 'fixed')
Expense.create!(name: 'Transportation', amount: 3000, pricing_type: 'fixed')
Expense.create!(name: 'Invitations', amount: 200, pricing_type: 'fixed')
Expense.create!(name: 'Cake', amount: 500, pricing_type: 'fixed')
Group.create!(name: "Jim's guests", icon: 'pi pi-heart').tap do |parent|
parent.children.create!(name: "Jim's family", icon: 'pi pi-users').tap do |family|
@ -61,34 +61,18 @@ ActsAsTenant.with_tenant(wedding) do
groups = Group.all
NUMBER_OF_GUESTS.times.map do |i|
{
NUMBER_OF_GUESTS.times do
Guest.create!(
name: Faker::Name.name,
phone: Faker::PhoneNumber.cell_phone,
group_id: groups.sample.id,
status: Guest.statuses.keys.sample,
}
end.then { Guest.insert_all!(it) }
Group.includes(:guests).each do |group|
guests = group.guests.potential.to_a
while guests.any?
invitation = Invitation.create!
guests.shift(rand(1..3)).each do |guest|
guest.update!(invitation:)
end
guests.shift(1) if rand < 0.3 # Leave a percentage of guests without an invitation
end
group: groups.sample,
status: Guest.statuses.keys.sample
)
end
# TODO: Clean up invitations with no guests
ActiveJob.perform_all_later(3.times.map { TableSimulatorJob.new(wedding.id) })
"red".dup.paint.palette.triad(as: :hex).zip(Group.roots).each { |(color, group)| group.update!(color: color.paint.desaturate(40)) }
'red'.paint.palette.triad(as: :hex).zip(Group.roots).each { |(color, group)| group.update!(color: color.paint.desaturate(40)) }
Group.roots.each(&:colorize_children)
@ -96,6 +80,6 @@ ActsAsTenant.with_tenant(wedding) do
email: 'development@example.com',
confirmed_at: Time.zone.now,
password: 'supersecretpassword',
password_confirmation: 'supersecretpassword'
password_confirmation: 'supersecretpassword',
)
end

View File

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

View File

@ -1,9 +0,0 @@
# Copyright (C) 2024-2025 LibreWeddingPlanner contributors
# frozen_string_literal: true
FactoryBot.define do
factory :invitation do
wedding
end
end

View File

@ -1,10 +0,0 @@
# Copyright (C) 2024-2025 LibreWeddingPlanner contributors
# frozen_string_literal: true
FactoryBot.define do
factory :website do
content { 'MyText' }
wedding { nil }
end
end

View File

@ -1,9 +0,0 @@
# Copyright (C) 2024-2025 LibreWeddingPlanner contributors
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Invitation do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -1,9 +0,0 @@
# Copyright (C) 2024-2025 LibreWeddingPlanner contributors
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Website do
it { is_expected.to belong_to(:wedding) }
end

View File

@ -18,27 +18,13 @@ RSpec.describe 'tables_arrangements' do
properties: {
id: { type: :string, format: :uuid },
name: { type: :string },
discomfort: { type: :integer },
valid: { type: :boolean }
discomfort: { type: :integer }
}
}
xit
end
regular_api_responses
end
post('create tables arrangement') do
tags 'Tables Arrangements'
produces 'application/json'
parameter Swagger::Schema::SLUG
response(201, 'successful') do
schema type: :object,
required: [],
properties: {}
xit
end
regular_api_responses
end
end
path '/{slug}/tables_arrangements/{id}' do

View File

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