Compare commits
21 Commits
copyright-
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
fcb1e77a3a | ||
|
f550b8d92c | ||
7c968f555f | |||
1f0c6c2aac | |||
390899524b | |||
|
59e7653064 | ||
d6fd72a45c | |||
889485eaab | |||
105a0ad30c | |||
d03ef173e6 | |||
b86d537cdc | |||
c1774a1c6c | |||
23d09df543 | |||
44dbb7e005 | |||
8a9d0bfdb8 | |||
c6c5a87d8b | |||
acf3b7b82a | |||
0ade367fb5 | |||
a154e92b6c | |||
492c8e362a | |||
c5c7ea6d54 |
@ -14,9 +14,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.202.0
|
- uses: ruby/setup-ruby@v1.207.0
|
||||||
with:
|
|
||||||
ruby-version: '3.3.6'
|
|
||||||
- name: Install project dependencies
|
- name: Install project dependencies
|
||||||
run: bundle install --jobs `getconf _NPROCESSORS_ONLN`
|
run: bundle install --jobs `getconf _NPROCESSORS_ONLN`
|
||||||
- name: Run license finder
|
- name: Run license finder
|
||||||
|
@ -22,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.202.0
|
- uses: ruby/setup-ruby@v1.207.0
|
||||||
- run: bundle install
|
- run: bundle install
|
||||||
- run: bundle exec rubocop --force-exclusion --parallel
|
- run: bundle exec rubocop --force-exclusion --parallel
|
||||||
- name: Wait until Postgres is ready to accept connections
|
- name: Wait until Postgres is ready to accept connections
|
||||||
|
@ -1 +1 @@
|
|||||||
ruby-3.3.6
|
ruby-3.4.1
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
# 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.6
|
ARG RUBY_VERSION=3.4.1
|
||||||
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
|
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim AS base
|
||||||
|
|
||||||
# Rails app lives here
|
# Rails app lives here
|
||||||
WORKDIR /rails
|
WORKDIR /rails
|
||||||
@ -16,11 +16,11 @@ ENV RAILS_ENV="production" \
|
|||||||
RUN apt-get update && apt-get install -y nodejs
|
RUN apt-get update && apt-get install -y nodejs
|
||||||
|
|
||||||
# Throw-away build stage to reduce size of final image
|
# Throw-away build stage to reduce size of final image
|
||||||
FROM base as build
|
FROM base AS build
|
||||||
|
|
||||||
# Install packages needed to build gems
|
# Install packages needed to build gems
|
||||||
RUN apt-get update -qq && \
|
RUN apt-get update -qq && \
|
||||||
apt-get install --no-install-recommends -y build-essential git libpq-dev libvips pkg-config
|
apt-get install --no-install-recommends -y build-essential git libpq-dev libvips pkg-config libyaml-dev
|
||||||
|
|
||||||
# Install application gems
|
# Install application gems
|
||||||
COPY Gemfile Gemfile.lock ./
|
COPY Gemfile Gemfile.lock ./
|
||||||
|
@ -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.6
|
ARG RUBY_VERSION=3.4.1
|
||||||
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
|
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
|
||||||
|
|
||||||
# Rails app lives here
|
# Rails app lives here
|
||||||
@ -13,7 +13,7 @@ FROM base as build
|
|||||||
|
|
||||||
# Install packages needed to build gems
|
# Install packages needed to build gems
|
||||||
RUN apt-get update -qq && \
|
RUN apt-get update -qq && \
|
||||||
apt-get install --no-install-recommends -y build-essential git libpq-dev libvips pkg-config
|
apt-get install --no-install-recommends -y build-essential git libpq-dev libvips pkg-config libyaml-dev
|
||||||
|
|
||||||
# Install application gems
|
# Install application gems
|
||||||
COPY Gemfile Gemfile.lock ./
|
COPY Gemfile Gemfile.lock ./
|
||||||
|
2
Gemfile
2
Gemfile
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
ruby '3.3.6'
|
ruby '3.4.1'
|
||||||
gem 'bootsnap', require: false
|
gem 'bootsnap', require: false
|
||||||
gem 'csv'
|
gem 'csv'
|
||||||
gem 'importmap-rails'
|
gem 'importmap-rails'
|
||||||
|
45
Gemfile.lock
45
Gemfile.lock
@ -188,6 +188,7 @@ GEM
|
|||||||
marcel (1.0.4)
|
marcel (1.0.4)
|
||||||
method_source (1.1.0)
|
method_source (1.1.0)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
|
mini_portile2 (2.8.8)
|
||||||
minitest (5.25.4)
|
minitest (5.25.4)
|
||||||
money (6.19.0)
|
money (6.19.0)
|
||||||
i18n (>= 0.6.4, <= 2)
|
i18n (>= 0.6.4, <= 2)
|
||||||
@ -204,21 +205,22 @@ GEM
|
|||||||
net-smtp (0.5.0)
|
net-smtp (0.5.0)
|
||||||
net-protocol
|
net-protocol
|
||||||
nio4r (2.7.4)
|
nio4r (2.7.4)
|
||||||
nokogiri (1.17.2-aarch64-linux)
|
nokogiri (1.18.1)
|
||||||
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.17.2-arm-linux)
|
nokogiri (1.18.1-aarch64-linux-gnu)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.17.2-arm64-darwin)
|
nokogiri (1.18.1-arm-linux-gnu)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.17.2-x86-linux)
|
nokogiri (1.18.1-arm64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.17.2-x86_64-darwin)
|
nokogiri (1.18.1-x86_64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.17.2-x86_64-linux)
|
nokogiri (1.18.1-x86_64-linux-gnu)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
parallel (1.26.3)
|
parallel (1.26.3)
|
||||||
parser (3.3.6.0)
|
parser (3.3.7.0)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
racc
|
racc
|
||||||
pg (1.5.9)
|
pg (1.5.9)
|
||||||
@ -327,7 +329,7 @@ GEM
|
|||||||
rswag-ui (2.16.0)
|
rswag-ui (2.16.0)
|
||||||
actionpack (>= 5.2, < 8.1)
|
actionpack (>= 5.2, < 8.1)
|
||||||
railties (>= 5.2, < 8.1)
|
railties (>= 5.2, < 8.1)
|
||||||
rubocop (1.70.0)
|
rubocop (1.71.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)
|
||||||
@ -341,12 +343,12 @@ GEM
|
|||||||
parser (>= 3.3.1.0)
|
parser (>= 3.3.1.0)
|
||||||
rubocop-factory_bot (2.26.1)
|
rubocop-factory_bot (2.26.1)
|
||||||
rubocop (~> 1.61)
|
rubocop (~> 1.61)
|
||||||
rubocop-rails (2.28.0)
|
rubocop-rails (2.29.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
rack (>= 1.1)
|
rack (>= 1.1)
|
||||||
rubocop (>= 1.52.0, < 2.0)
|
rubocop (>= 1.52.0, < 2.0)
|
||||||
rubocop-ast (>= 1.31.1, < 2.0)
|
rubocop-ast (>= 1.31.1, < 2.0)
|
||||||
rubocop-rspec (3.3.0)
|
rubocop-rspec (3.4.0)
|
||||||
rubocop (~> 1.61)
|
rubocop (~> 1.61)
|
||||||
rubocop-rspec_rails (2.30.0)
|
rubocop-rspec_rails (2.30.0)
|
||||||
rubocop (~> 1.61)
|
rubocop (~> 1.61)
|
||||||
@ -521,6 +523,7 @@ CHECKSUMS
|
|||||||
marcel (1.0.4) sha256=0d5649feb64b8f19f3d3468b96c680bae9746335d02194270287868a661516a4
|
marcel (1.0.4) sha256=0d5649feb64b8f19f3d3468b96c680bae9746335d02194270287868a661516a4
|
||||||
method_source (1.1.0) sha256=181301c9c45b731b4769bc81e8860e72f9161ad7d66dd99103c9ab84f560f5c5
|
method_source (1.1.0) sha256=181301c9c45b731b4769bc81e8860e72f9161ad7d66dd99103c9ab84f560f5c5
|
||||||
mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef
|
mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef
|
||||||
|
mini_portile2 (2.8.8) sha256=8e47136cdac04ce81750bb6c09733b37895bf06962554e4b4056d78168d70a75
|
||||||
minitest (5.25.4) sha256=9cf2cae25ac4dfc90c988ebc3b917f53c054978b673273da1bd20bcb0778f947
|
minitest (5.25.4) sha256=9cf2cae25ac4dfc90c988ebc3b917f53c054978b673273da1bd20bcb0778f947
|
||||||
money (6.19.0) sha256=ec936fa1e42f2783719241ed9fd52725d0efa628f928feea1eb5c37d5de7daf3
|
money (6.19.0) sha256=ec936fa1e42f2783719241ed9fd52725d0efa628f928feea1eb5c37d5de7daf3
|
||||||
msgpack (1.7.2) sha256=59ab62fd8a4d0dfbde45009f87eb6f158ab2628a7c48886b0256f175166baaa8
|
msgpack (1.7.2) sha256=59ab62fd8a4d0dfbde45009f87eb6f158ab2628a7c48886b0256f175166baaa8
|
||||||
@ -530,15 +533,15 @@ CHECKSUMS
|
|||||||
net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
|
net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
|
||||||
net-smtp (0.5.0) sha256=5fc0415e6ea1cc0b3dfea7270438ec22b278ca8d524986a3ae4e5ae8d087b42a
|
net-smtp (0.5.0) sha256=5fc0415e6ea1cc0b3dfea7270438ec22b278ca8d524986a3ae4e5ae8d087b42a
|
||||||
nio4r (2.7.4) sha256=d95dee68e0bb251b8ff90ac3423a511e3b784124e5db7ff5f4813a220ae73ca9
|
nio4r (2.7.4) sha256=d95dee68e0bb251b8ff90ac3423a511e3b784124e5db7ff5f4813a220ae73ca9
|
||||||
nokogiri (1.17.2-aarch64-linux) sha256=585c8cac6380848b7973bacfd0584628d116810e5f209db25e22d0c32313e681
|
nokogiri (1.18.1) sha256=df18be7e96c34736b6abfdeda80c6e845134fb9afe2fe5d4fbc1cf1f89c68475
|
||||||
nokogiri (1.17.2-arm-linux) sha256=3d033ad9b09d5b8a203f0f2156053e93a9327a9c7887c0ceb9fa78c71d27280d
|
nokogiri (1.18.1-aarch64-linux-gnu) sha256=35837013800e34342fcbaca305f8c49231f6bd4f779bfa23fe7b4686ae82d5b8
|
||||||
nokogiri (1.17.2-arm64-darwin) sha256=0c5eb06ba1c112d33c2bb29973b07e2f21c4ddb66c67c9386fd97ff1c5d84686
|
nokogiri (1.18.1-arm-linux-gnu) sha256=3b873fd6b0cd1ad7c77e87af701075bdfd14c9a6b2f2965c5e00ed29a5627a37
|
||||||
nokogiri (1.17.2-x86-linux) sha256=8c4dd75e35810bdeb7c74943f383ca665baf6aed8fc2b78c1d305094a72794aa
|
nokogiri (1.18.1-arm64-darwin) sha256=d75193f284c899d225943a8944479faedd995a7573ddd5c8308ffbdf2ec55204
|
||||||
nokogiri (1.17.2-x86_64-darwin) sha256=dc5977eb3416e1d501b22b0ed4737bf7604121491405865b887975eacfb3e896
|
nokogiri (1.18.1-x86_64-darwin) sha256=d94e3aa6483577495fc8969d6b4b5c075840ce6b1ab09636a6d4177ad171051d
|
||||||
nokogiri (1.17.2-x86_64-linux) sha256=e8614ae8d776bd9adb535ca814375e7ae05d7cfa6aa01909e561484f6d70be0b
|
nokogiri (1.18.1-x86_64-linux-gnu) sha256=e516cf16ccde67ed4cc595a2621ca5ddd42562ecb24928914b0045a20a41620e
|
||||||
orm_adapter (0.5.0) sha256=aa5d0be5d540cbb46d3a93e88061f4ece6a25f6e97d6a47122beb84fe595e9b9
|
orm_adapter (0.5.0) sha256=aa5d0be5d540cbb46d3a93e88061f4ece6a25f6e97d6a47122beb84fe595e9b9
|
||||||
parallel (1.26.3) sha256=d86babb7a2b814be9f4b81587bf0b6ce2da7d45969fab24d8ae4bf2bb4d4c7ef
|
parallel (1.26.3) sha256=d86babb7a2b814be9f4b81587bf0b6ce2da7d45969fab24d8ae4bf2bb4d4c7ef
|
||||||
parser (3.3.6.0) sha256=25d4e67cc4f0f7cab9a2ae1f38e2005b6904d2ea13c34734511d0faad038bc3b
|
parser (3.3.7.0) sha256=7449011771e3e7881297859b849de26a6f4fccd515bece9520a87e7d2116119b
|
||||||
pg (1.5.9) sha256=761efbdf73b66516f0c26fcbe6515dc7500c3f0aa1a1b853feae245433c64fdc
|
pg (1.5.9) sha256=761efbdf73b66516f0c26fcbe6515dc7500c3f0aa1a1b853feae245433c64fdc
|
||||||
pluck_to_hash (1.0.2) sha256=1599906239716f98262a41493dd7d4cb72e8d83ad3d76d666deacfc5de50a47e
|
pluck_to_hash (1.0.2) sha256=1599906239716f98262a41493dd7d4cb72e8d83ad3d76d666deacfc5de50a47e
|
||||||
pry (0.15.2) sha256=12d54b8640d3fa29c9211dd4ffb08f3fd8bf7a4fd9b5a73ce5b59c8709385b6b
|
pry (0.15.2) sha256=12d54b8640d3fa29c9211dd4ffb08f3fd8bf7a4fd9b5a73ce5b59c8709385b6b
|
||||||
@ -575,11 +578,11 @@ CHECKSUMS
|
|||||||
rswag-api (2.16.0) sha256=b653f7bd92e98be18b01ab4525d88950d7b0960e293a99f856b9efcee3ae6074
|
rswag-api (2.16.0) sha256=b653f7bd92e98be18b01ab4525d88950d7b0960e293a99f856b9efcee3ae6074
|
||||||
rswag-specs (2.16.0) sha256=8ba26085c408b0bd2ed21dc8015c80f417c7d34c63720ab7133c2549b5bd2a91
|
rswag-specs (2.16.0) sha256=8ba26085c408b0bd2ed21dc8015c80f417c7d34c63720ab7133c2549b5bd2a91
|
||||||
rswag-ui (2.16.0) sha256=a1f49e927dceda92e6e6e7c1000f1e217ee66c565f69e28131dc98b33cd3a04f
|
rswag-ui (2.16.0) sha256=a1f49e927dceda92e6e6e7c1000f1e217ee66c565f69e28131dc98b33cd3a04f
|
||||||
rubocop (1.70.0) sha256=96751f8440b36a0ac6e9a8ab596900803118d83d6b83f2037bf8b3d7a5bc440e
|
rubocop (1.71.0) sha256=e19679efd447346ac476122313d3788ae23c38214790bcf660e984c747608bf0
|
||||||
rubocop-ast (1.37.0) sha256=9513ac88aaf113d04b52912533ffe46475de1362d4aa41141b51b2455827c080
|
rubocop-ast (1.37.0) sha256=9513ac88aaf113d04b52912533ffe46475de1362d4aa41141b51b2455827c080
|
||||||
rubocop-factory_bot (2.26.1) sha256=8de13cd4edcee5ca800f255188167ecef8dbfc3d1fae9f15734e9d2e755392aa
|
rubocop-factory_bot (2.26.1) sha256=8de13cd4edcee5ca800f255188167ecef8dbfc3d1fae9f15734e9d2e755392aa
|
||||||
rubocop-rails (2.28.0) sha256=4967bed9ea13e6dcab566fea4265a6dd0381db739b305e48930aba1282da2715
|
rubocop-rails (2.29.0) sha256=35bffd140c80671453aafac0e2d5ab5b3dd65736a3fc8f3936ccca226b89c234
|
||||||
rubocop-rspec (3.3.0) sha256=79e1b281a689044d1516fefbc52e2e6c06cd367c25ebeaf06a7a198e9071cd7d
|
rubocop-rspec (3.4.0) sha256=8721c13b6a8c9530a7ac481cea9423022f946fcf72428bda8289f8b57e4d4885
|
||||||
rubocop-rspec_rails (2.30.0) sha256=888112e83f9d7ef7ad2397e9d69a0b9614a4bae24f072c399804a180f80c4c46
|
rubocop-rspec_rails (2.30.0) sha256=888112e83f9d7ef7ad2397e9d69a0b9614a4bae24f072c399804a180f80c4c46
|
||||||
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
|
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
|
||||||
rubytree (2.1.1) sha256=4925016356a81730e982f1f8c3b5f8da461f18906c77d238bad4c4ba896abd41
|
rubytree (2.1.1) sha256=4925016356a81730e982f1f8c3b5f8da461f18906c77d238bad4c4ba896abd41
|
||||||
@ -609,7 +612,7 @@ CHECKSUMS
|
|||||||
zeitwerk (2.7.1) sha256=0945986050e4907140895378e74df1fe882a2271ed087cc6c6d6b00d415a2756
|
zeitwerk (2.7.1) sha256=0945986050e4907140895378e74df1fe882a2271ed087cc6c6d6b00d415a2756
|
||||||
|
|
||||||
RUBY VERSION
|
RUBY VERSION
|
||||||
ruby 3.3.6p108
|
ruby 3.4.1p0
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.6.1
|
2.6.1
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class AffinitiesController < ApplicationController
|
class AffinitiesController < ApplicationController
|
||||||
before_action :set_group
|
before_action :set_group, except: :reset
|
||||||
|
|
||||||
def index
|
def index
|
||||||
overridden = @group.affinities.each_with_object({}) do |affinity, acc|
|
overridden = @group.affinities.each_with_object({}) do |affinity, acc|
|
||||||
@ -26,7 +26,7 @@ class AffinitiesController < ApplicationController
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
GroupAffinity.upsert_all(affinities)
|
GroupAffinity.upsert_all(affinities, unique_by: :uindex_group_pair)
|
||||||
|
|
||||||
render json: {}, status: :ok
|
render json: {}, status: :ok
|
||||||
rescue ActiveRecord::InvalidForeignKey
|
rescue ActiveRecord::InvalidForeignKey
|
||||||
@ -36,11 +36,29 @@ class AffinitiesController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def default
|
def default
|
||||||
|
hierarchy = AffinityGroupsHierarchy.new
|
||||||
|
|
||||||
for_each_group do |group_id|
|
for_each_group do |group_id|
|
||||||
Tables::DiscomfortCalculator.cohesion_discomfort(id_a: @group.id, id_b: group_id).to_f
|
hierarchy.default_discomfort(@group.id, group_id).to_f
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reset
|
||||||
|
hierarchy = AffinityGroupsHierarchy.new
|
||||||
|
|
||||||
|
affinities = Group.pluck(:id).combination(2).map do |(group_a_id, group_b_id)|
|
||||||
|
{
|
||||||
|
group_a_id:,
|
||||||
|
group_b_id:,
|
||||||
|
discomfort: hierarchy.default_discomfort(group_a_id, group_b_id).to_f
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
GroupAffinity.upsert_all(affinities, unique_by: :uindex_group_pair)
|
||||||
|
|
||||||
|
render json: {}, status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def for_each_group
|
def for_each_group
|
||||||
|
@ -31,6 +31,6 @@ class ExpensesController < ApplicationController
|
|||||||
private
|
private
|
||||||
|
|
||||||
def expense_params
|
def expense_params
|
||||||
params.require(:expense).permit(:name, :amount, :pricing_type)
|
params.expect(expense: %i[name amount pricing_type])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -32,6 +32,6 @@ class GuestsController < ApplicationController
|
|||||||
private
|
private
|
||||||
|
|
||||||
def guest_params
|
def guest_params
|
||||||
params.require(:guest).permit(:name, :group_id, :status)
|
params.expect(guest: %i[name group_id status])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class AffinityGroupsHierarchy < Array
|
class AffinityGroupsHierarchy < Array
|
||||||
include Singleton
|
DEFAULT_DISCOMFORT = 1
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
super
|
super
|
||||||
@ -16,6 +16,9 @@ class AffinityGroupsHierarchy < Array
|
|||||||
|
|
||||||
hydrate(group)
|
hydrate(group)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
load_discomforts
|
||||||
|
freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
def find(id)
|
def find(id)
|
||||||
@ -37,8 +40,35 @@ class AffinityGroupsHierarchy < Array
|
|||||||
@references[id_a].distance_to_common_ancestor(@references[id_b])
|
@references[id_a].distance_to_common_ancestor(@references[id_b])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def discomfort(id_a, id_b)
|
||||||
|
return 0 if id_a == id_b
|
||||||
|
|
||||||
|
@discomforts[uuid_to_int(id_a) + uuid_to_int(id_b)] || DEFAULT_DISCOMFORT
|
||||||
|
end
|
||||||
|
|
||||||
|
def default_discomfort(id_a, id_b)
|
||||||
|
return 0 if id_a == id_b
|
||||||
|
|
||||||
|
dist = distance(id_a, id_b)
|
||||||
|
|
||||||
|
return DEFAULT_DISCOMFORT if dist.nil?
|
||||||
|
|
||||||
|
Rational(dist, dist + 1)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def load_discomforts
|
||||||
|
@load_discomforts ||= GroupAffinity.pluck(:group_a_id, :group_b_id,
|
||||||
|
:discomfort).each_with_object({}) do |(id_a, id_b, discomfort), acc|
|
||||||
|
acc[uuid_to_int(id_a) + uuid_to_int(id_b)] = discomfort
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def uuid_to_int(uuid)
|
||||||
|
uuid.gsub('-', '').hex
|
||||||
|
end
|
||||||
|
|
||||||
def hydrate(group)
|
def hydrate(group)
|
||||||
group.children.each do |child|
|
group.children.each do |child|
|
||||||
register_child(group.id, child.id)
|
register_child(group.id, child.id)
|
||||||
|
@ -6,19 +6,10 @@
|
|||||||
|
|
||||||
module Tables
|
module Tables
|
||||||
class DiscomfortCalculator
|
class DiscomfortCalculator
|
||||||
class << self
|
private attr_reader :table, :hierarchy
|
||||||
def cohesion_discomfort(id_a:, id_b:)
|
def initialize(table:, hierarchy: AffinityGroupsHierarchy.new)
|
||||||
distance = AffinityGroupsHierarchy.instance.distance(id_a, id_b)
|
|
||||||
|
|
||||||
return 1 if distance.nil?
|
|
||||||
|
|
||||||
Rational(distance, distance + 1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private attr_reader :table
|
|
||||||
def initialize(table:)
|
|
||||||
@table = table
|
@table = table
|
||||||
|
@hierarchy = hierarchy
|
||||||
end
|
end
|
||||||
|
|
||||||
def calculate
|
def calculate
|
||||||
@ -59,7 +50,7 @@ module Tables
|
|||||||
#
|
#
|
||||||
def cohesion_discomfort
|
def cohesion_discomfort
|
||||||
table.map(&:group_id).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)|
|
||||||
count_a * count_b * self.class.cohesion_discomfort(id_a: a, id_b: b)
|
count_a * count_b * hierarchy.discomfort(a, b)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -13,6 +13,7 @@ module Tables
|
|||||||
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
|
||||||
@max_per_table = max_per_table
|
@max_per_table = max_per_table
|
||||||
|
@hierarchy = AffinityGroupsHierarchy.new
|
||||||
@tables = []
|
@tables = []
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -35,12 +36,6 @@ module Tables
|
|||||||
"#{@tables.count} tables, discomfort: #{discomfort}"
|
"#{@tables.count} tables, discomfort: #{discomfort}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def pretty_print
|
|
||||||
@tables.map.with_index do |table, i|
|
|
||||||
"Table #{i + 1} (#{table.count} ppl): (#{local_discomfort(table)}) #{table.map(&:name).join(', ')}"
|
|
||||||
end.join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def deep_dup
|
def deep_dup
|
||||||
self.class.new(min_per_table: @min_per_table, max_per_table: @max_per_table).tap do |new_distribution|
|
self.class.new(min_per_table: @min_per_table, max_per_table: @max_per_table).tap do |new_distribution|
|
||||||
new_distribution.tables = @tables.map(&:dup)
|
new_distribution.tables = @tables.map(&:dup)
|
||||||
@ -68,7 +63,7 @@ module Tables
|
|||||||
private
|
private
|
||||||
|
|
||||||
def local_discomfort(table)
|
def local_discomfort(table)
|
||||||
table.discomfort ||= DiscomfortCalculator.new(table:).calculate
|
table.discomfort ||= DiscomfortCalculator.new(table:, hierarchy:).calculate
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -26,6 +26,7 @@ Rails.application.routes.draw do
|
|||||||
end
|
end
|
||||||
|
|
||||||
resources :groups, only: %i[index create update destroy] do
|
resources :groups, only: %i[index create update destroy] do
|
||||||
|
post 'affinities/reset', to: 'affinities#reset', on: :collection
|
||||||
resources :affinities, only: %i[index] do
|
resources :affinities, only: %i[index] do
|
||||||
put :bulk_update, on: :collection
|
put :bulk_update, on: :collection
|
||||||
get :default, on: :collection
|
get :default, on: :collection
|
||||||
|
@ -7,6 +7,17 @@
|
|||||||
require 'swagger_helper'
|
require 'swagger_helper'
|
||||||
|
|
||||||
RSpec.describe 'affinities' do
|
RSpec.describe 'affinities' do
|
||||||
|
path '/{slug}/groups/affinities/reset' do
|
||||||
|
parameter Swagger::Schema::SLUG
|
||||||
|
|
||||||
|
post('reset affinities') do
|
||||||
|
tags 'Affinities'
|
||||||
|
description 'Reset all affinities to default values based on the distance between groups in the hierarchy.'
|
||||||
|
|
||||||
|
response_empty200
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
path '/{slug}/groups/{group_id}/affinities' do
|
path '/{slug}/groups/{group_id}/affinities' do
|
||||||
parameter Swagger::Schema::SLUG
|
parameter Swagger::Schema::SLUG
|
||||||
parameter name: 'group_id', in: :path, type: :string, format: :uuid, description: 'group_id'
|
parameter name: 'group_id', in: :path, type: :string, format: :uuid, description: 'group_id'
|
||||||
|
@ -75,159 +75,5 @@ module Tables
|
|||||||
it { expect(calculator.send(:table_size_penalty)).to eq(10) }
|
it { expect(calculator.send(:table_size_penalty)).to eq(10) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#cohesion_discomfort' do
|
|
||||||
before do
|
|
||||||
# Overridden in each test except trivial cases
|
|
||||||
allow(AffinityGroupsHierarchy.instance).to receive(:distance).and_call_original
|
|
||||||
|
|
||||||
%w[family friends work school].each do |group|
|
|
||||||
allow(AffinityGroupsHierarchy.instance).to receive(:distance).with(group, group).and_return(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
allow(AffinityGroupsHierarchy.instance).to receive(:distance).with(family.id, friends.id).and_return(nil)
|
|
||||||
allow(AffinityGroupsHierarchy.instance).to receive(:distance).with(friends.id, work.id).and_return(1)
|
|
||||||
allow(AffinityGroupsHierarchy.instance).to receive(:distance).with(family.id, work.id).and_return(2)
|
|
||||||
allow(AffinityGroupsHierarchy.instance).to receive(:distance).with(family.id, school.id).and_return(3)
|
|
||||||
allow(AffinityGroupsHierarchy.instance).to receive(:distance).with(friends.id, school.id).and_return(4)
|
|
||||||
allow(AffinityGroupsHierarchy.instance).to receive(:distance).with(work.id, school.id).and_return(5)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the table contains just two guests' do
|
|
||||||
context 'when they belong to the same group' do
|
|
||||||
let(:table) { create_list(:guest, 2, group: family) }
|
|
||||||
|
|
||||||
it { expect(calculator.send(:cohesion_discomfort)).to eq(0) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when they belong to completely unrelated groups' do
|
|
||||||
let(:table) do
|
|
||||||
[
|
|
||||||
create(:guest, group: family),
|
|
||||||
create(:guest, group: friends)
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
it { expect(calculator.send(:cohesion_discomfort)).to eq(1) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when they belong to groups at a distance of 1' do
|
|
||||||
let(:table) do
|
|
||||||
[
|
|
||||||
create(:guest, group: friends),
|
|
||||||
create(:guest, group: work)
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
it { expect(calculator.send(:cohesion_discomfort)).to eq(0.5) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when they belong to groups at a distance of 2' do
|
|
||||||
let(:table) do
|
|
||||||
[
|
|
||||||
create(:guest, group: family),
|
|
||||||
create(:guest, group: work)
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
it { expect(calculator.send(:cohesion_discomfort)).to eq(Rational(2, 3)) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when they belong to groups at a distance of 3' do
|
|
||||||
let(:table) do
|
|
||||||
[
|
|
||||||
create(:guest, group: family),
|
|
||||||
create(:guest, group: school)
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
it { expect(calculator.send(:cohesion_discomfort)).to eq(Rational(3, 4)) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the table contains three guests' do
|
|
||||||
let(:table) do
|
|
||||||
[
|
|
||||||
create(:guest, group: family),
|
|
||||||
create(:guest, group: friends),
|
|
||||||
create(:guest, group: work)
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns the sum of the penalties for each pair of guests' do
|
|
||||||
expect(calculator.send(:cohesion_discomfort)).to eq(1 + Rational(1, 2) + Rational(2, 3))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the table contains four guests of different groups' do
|
|
||||||
let(:table) do
|
|
||||||
[
|
|
||||||
create(:guest, group: family),
|
|
||||||
create(:guest, group: friends),
|
|
||||||
create(:guest, group: work),
|
|
||||||
create(:guest, group: school)
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns the sum of the penalties for each pair of guests' do
|
|
||||||
expect(calculator.send(:cohesion_discomfort))
|
|
||||||
.to eq(1 + Rational(1, 2) + Rational(2, 3) + Rational(3, 4) + Rational(4, 5) + Rational(5, 6))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the table contains four guests of two evenly split groups' do
|
|
||||||
let(:table) do
|
|
||||||
[
|
|
||||||
create_list(:guest, 2, group: family),
|
|
||||||
create_list(:guest, 2, group: friends)
|
|
||||||
].flatten
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns the sum of the penalties for each pair of guests' do
|
|
||||||
expect(calculator.send(:cohesion_discomfort)).to eq(4)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the table contains six guests of two unevenly split groups' do
|
|
||||||
let(:table) do
|
|
||||||
[
|
|
||||||
create_list(:guest, 2, group: family),
|
|
||||||
create_list(:guest, 4, group: friends)
|
|
||||||
].flatten
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns the sum of the penalties for each pair of guests' do
|
|
||||||
expect(calculator.send(:cohesion_discomfort)).to eq(8)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the table contains six guests of three evenly split groups' do
|
|
||||||
let(:table) do
|
|
||||||
[
|
|
||||||
create_list(:guest, 2, group: family),
|
|
||||||
create_list(:guest, 2, group: friends),
|
|
||||||
create_list(:guest, 2, group: work)
|
|
||||||
].flatten
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns the sum of the penalties for each pair of guests' do
|
|
||||||
expect(calculator.send(:cohesion_discomfort)).to eq((4 * 1) + (4 * Rational(1, 2)) + (4 * Rational(2, 3)))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the table contains six guests of three unevenly split groups' do
|
|
||||||
let(:table) do
|
|
||||||
[
|
|
||||||
create_list(:guest, 3, group: family),
|
|
||||||
create_list(:guest, 2, group: friends),
|
|
||||||
create_list(:guest, 1, group: work)
|
|
||||||
].flatten
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns the sum of the penalties for each pair of guests' do
|
|
||||||
expect(calculator.send(:cohesion_discomfort)).to eq((6 * 1) + (2 * Rational(1, 2)) + (3 * Rational(2, 3)))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user