diff --git a/Gemfile b/Gemfile index cc2ec6e..ead69aa 100644 --- a/Gemfile +++ b/Gemfile @@ -20,6 +20,7 @@ gem 'jsonapi-rails' gem 'rack-cors' gem 'react-rails' gem 'rubytree' +gem 'acts_as_tenant' group :development, :test do gem 'annotaterb' diff --git a/Gemfile.lock b/Gemfile.lock index bfe49bd..7e795fc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -72,6 +72,8 @@ GEM securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) uri (>= 0.13.1) + acts_as_tenant (1.0.1) + rails (>= 6.0) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) annotaterb (4.13.0) @@ -387,6 +389,7 @@ PLATFORMS x86_64-linux DEPENDENCIES + acts_as_tenant annotaterb bootsnap chroma diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0d2a0c7..13400e3 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,6 +1,7 @@ # Copyright (C) 2024 Manuel Bustillo class ApplicationController < ActionController::Base + before_action :set_tenant before_action :authenticate_user! after_action :set_csrf_cookie @@ -29,6 +30,10 @@ class ApplicationController < ActionController::Base private + def set_tenant + ActsAsTenant.current_tenant = Wedding.find_by(slug: params[:slug]) + end + def development_swagger? Rails.env.test? || Rails.env.development? && request.headers['referer']&.include?('/api-docs/index.html') diff --git a/app/jobs/table_simulator_job.rb b/app/jobs/table_simulator_job.rb index ef91719..ced9b2d 100644 --- a/app/jobs/table_simulator_job.rb +++ b/app/jobs/table_simulator_job.rb @@ -3,21 +3,23 @@ class TableSimulatorJob < ApplicationJob queue_as :default - def perform(*_args) - engine = VNS::Engine.new + def perform(wedding_id) + ActsAsTenant.with_tenant(Wedding.find(wedding_id)) do + engine = VNS::Engine.new - engine.add_perturbation(Tables::Swap) - engine.add_perturbation(Tables::Shift) + engine.add_perturbation(Tables::Swap) + engine.add_perturbation(Tables::Shift) - initial_solution = Tables::Distribution.new(min_per_table: 8, max_per_table: 10) - initial_solution.random_distribution(Guest.potential.shuffle) + initial_solution = Tables::Distribution.new(min_per_table: 8, max_per_table: 10) + initial_solution.random_distribution(Guest.potential.shuffle) - engine.initial_solution = initial_solution + engine.initial_solution = initial_solution - engine.target_function(&:discomfort) + engine.target_function(&:discomfort) - best_solution = engine.run + best_solution = engine.run - best_solution.save! + best_solution.save! + end end end diff --git a/app/models/expense.rb b/app/models/expense.rb index 6da98af..5601c30 100644 --- a/app/models/expense.rb +++ b/app/models/expense.rb @@ -10,8 +10,18 @@ # pricing_type :enum default("fixed"), not null # created_at :datetime not null # updated_at :datetime not null +# wedding_id :uuid not null +# +# Indexes +# +# index_expenses_on_wedding_id (wedding_id) +# +# Foreign Keys +# +# fk_rails_... (wedding_id => weddings.id) # class Expense < ApplicationRecord + acts_as_tenant :wedding enum :pricing_type, fixed: 'fixed', per_person: 'per_person' diff --git a/app/models/group.rb b/app/models/group.rb index fe11e0b..5056b28 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -12,17 +12,22 @@ # created_at :datetime not null # updated_at :datetime not null # parent_id :uuid +# wedding_id :uuid not null # # Indexes # -# index_groups_on_name (name) UNIQUE -# index_groups_on_parent_id (parent_id) +# index_groups_on_name (name) UNIQUE +# index_groups_on_parent_id (parent_id) +# index_groups_on_wedding_id (wedding_id) # # Foreign Keys # # fk_rails_... (parent_id => groups.id) +# fk_rails_... (wedding_id => weddings.id) # class Group < ApplicationRecord + acts_as_tenant :wedding + validates :name, uniqueness: true validates :name, :order, presence: true diff --git a/app/models/guest.rb b/app/models/guest.rb index 40c41be..929cc6e 100644 --- a/app/models/guest.rb +++ b/app/models/guest.rb @@ -11,16 +11,20 @@ # created_at :datetime not null # updated_at :datetime not null # group_id :uuid not null +# wedding_id :uuid not null # # Indexes # -# index_guests_on_group_id (group_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_... (wedding_id => weddings.id) # class Guest < ApplicationRecord + acts_as_tenant :wedding belongs_to :group enum :status, { @@ -45,6 +49,6 @@ class Guest < ApplicationRecord def recalculate_simulations TablesArrangement.delete_all - ActiveJob.perform_all_later(50.times.map { TableSimulatorJob.new }) + ActiveJob.perform_all_later(50.times.map { TableSimulatorJob.new(wedding_id) }) end end diff --git a/app/models/seat.rb b/app/models/seat.rb index 1f3769c..3f13629 100644 --- a/app/models/seat.rb +++ b/app/models/seat.rb @@ -10,18 +10,22 @@ # updated_at :datetime not null # guest_id :uuid not null # tables_arrangement_id :uuid not null +# wedding_id :uuid not null # # Indexes # # index_seats_on_guest_id (guest_id) # index_seats_on_tables_arrangement_id (tables_arrangement_id) +# index_seats_on_wedding_id (wedding_id) # # Foreign Keys # # fk_rails_... (guest_id => guests.id) # fk_rails_... (tables_arrangement_id => tables_arrangements.id) ON DELETE => cascade +# fk_rails_... (wedding_id => weddings.id) # class Seat < ApplicationRecord + acts_as_tenant :wedding belongs_to :guest belongs_to :table_arrangement end diff --git a/app/models/tables_arrangement.rb b/app/models/tables_arrangement.rb index 6e2f621..3080e49 100644 --- a/app/models/tables_arrangement.rb +++ b/app/models/tables_arrangement.rb @@ -9,8 +9,18 @@ # name :string not null # created_at :datetime not null # updated_at :datetime not null +# wedding_id :uuid not null +# +# Indexes +# +# index_tables_arrangements_on_wedding_id (wedding_id) +# +# Foreign Keys +# +# fk_rails_... (wedding_id => weddings.id) # class TablesArrangement < ApplicationRecord + acts_as_tenant :wedding has_many :seats has_many :guests, through: :seats diff --git a/app/models/user.rb b/app/models/user.rb index d338416..43c3a9e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -18,6 +18,7 @@ # unlock_token :string # created_at :datetime not null # updated_at :datetime not null +# wedding_id :uuid not null # # Indexes # @@ -25,8 +26,15 @@ # index_users_on_email (email) UNIQUE # index_users_on_reset_password_token (reset_password_token) UNIQUE # index_users_on_unlock_token (unlock_token) UNIQUE +# index_users_on_wedding_id (wedding_id) +# +# Foreign Keys +# +# fk_rails_... (wedding_id => weddings.id) # class User < ApplicationRecord + acts_as_tenant :wedding + devise :database_authenticatable, :registerable, :recoverable, :validatable, :confirmable, :lockable end diff --git a/app/models/wedding.rb b/app/models/wedding.rb new file mode 100644 index 0000000..fa6c6e4 --- /dev/null +++ b/app/models/wedding.rb @@ -0,0 +1,20 @@ +# Copyright (C) 2024 Manuel Bustillo + +# == Schema Information +# +# Table name: weddings +# +# id :uuid not null, primary key +# date :date not null +# slug :string not null +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_weddings_on_slug (slug) UNIQUE +# +class Wedding < ApplicationRecord + validates :date, presence: true + validates :slug, presence: true, uniqueness: true +end diff --git a/config/routes.rb b/config/routes.rb index 35fd068..b407e01 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,26 +2,30 @@ Rails.application.routes.draw do mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development? - devise_for :users, skip: [:registration, :session, :confirmation] - devise_scope :user do - post 'users', to: 'users/registrations#create' + scope ":slug", constraints: {slug: /[a-z]+/} do + devise_for :users, skip: [:registration, :session, :confirmation] + devise_scope :user do + post 'users', to: 'users/registrations#create' - post '/users/sign_in', to: 'users/sessions#create' - delete '/users/sign_out', to: 'users/sessions#destroy' + post '/users/sign_in', to: 'users/sessions#create' + delete '/users/sign_out', to: 'users/sessions#destroy' - get '/users/confirmation', to: 'users/confirmations#show', as: :confirmation + get '/users/confirmation', to: 'users/confirmations#show', as: :confirmation + end + + resources :groups, only: :index + resources :guests, only: %i[index create update destroy] do + post :bulk_update, on: :collection + end + resources :expenses, only: %i[index update] do + get :summary, on: :collection + end + resources :tables_arrangements, only: %i[index show] end + mount Rswag::Ui::Engine => '/api-docs' mount Rswag::Api::Engine => '/api-docs' - resources :groups, only: :index - resources :guests, only: %i[index create update destroy] do - post :bulk_update, on: :collection - end - resources :expenses, only: %i[index update] do - get :summary, on: :collection - end - resources :tables_arrangements, only: %i[index show] get 'up' => 'rails/health#show', as: :rails_health_check diff --git a/db/migrate/20241130182228_create_weddings.rb b/db/migrate/20241130182228_create_weddings.rb new file mode 100644 index 0000000..2151f72 --- /dev/null +++ b/db/migrate/20241130182228_create_weddings.rb @@ -0,0 +1,12 @@ +# Copyright (C) 2024 Manuel Bustillo + +class CreateWeddings < ActiveRecord::Migration[8.0] + def change + create_table :weddings, id: :uuid do |t| + t.string :slug, null: false, index: { unique: true } + t.date :date, null: false + + t.timestamps + end + end +end diff --git a/db/migrate/20241130185731_add_wedding_id_to_models.rb b/db/migrate/20241130185731_add_wedding_id_to_models.rb new file mode 100644 index 0000000..63e5c32 --- /dev/null +++ b/db/migrate/20241130185731_add_wedding_id_to_models.rb @@ -0,0 +1,9 @@ +# Copyright (C) 2024 Manuel Bustillo + +class AddWeddingIdToModels < ActiveRecord::Migration[8.0] + def change + [:expenses, :guests, :seats, :tables_arrangements, :groups, :users].each do |table| + add_reference table, :wedding, type: :uuid, null: false, foreign_key: true + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 6e9d747..7ff33f3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -12,7 +12,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2024_11_30_095753) do +ActiveRecord::Schema[8.0].define(version: 2024_11_30_185731) do # These are extensions that must be enabled in order to support this database enable_extension "pg_catalog.plpgsql" @@ -26,6 +26,8 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_30_095753) do t.enum "pricing_type", default: "fixed", null: false, enum_type: "pricing_types" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.uuid "wedding_id", null: false + t.index ["wedding_id"], name: "index_expenses_on_wedding_id" end create_table "groups", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| @@ -36,8 +38,10 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_30_095753) do t.datetime "updated_at", null: false t.uuid "parent_id" t.string "color" + t.uuid "wedding_id", null: false t.index ["name"], name: "index_groups_on_name", unique: true t.index ["parent_id"], name: "index_groups_on_parent_id" + t.index ["wedding_id"], name: "index_groups_on_wedding_id" end create_table "guests", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| @@ -47,7 +51,9 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_30_095753) do t.uuid "group_id", null: false t.integer "status", default: 0 t.string "name" + t.uuid "wedding_id", null: false t.index ["group_id"], name: "index_guests_on_group_id" + t.index ["wedding_id"], name: "index_guests_on_wedding_id" end create_table "seats", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| @@ -56,8 +62,10 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_30_095753) do t.integer "table_number" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.uuid "wedding_id", null: false t.index ["guest_id"], name: "index_seats_on_guest_id" t.index ["tables_arrangement_id"], name: "index_seats_on_tables_arrangement_id" + t.index ["wedding_id"], name: "index_seats_on_wedding_id" end create_table "solid_queue_blocked_executions", force: :cascade do |t| @@ -186,6 +194,8 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_30_095753) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "name", null: false + t.uuid "wedding_id", null: false + t.index ["wedding_id"], name: "index_tables_arrangements_on_wedding_id" end create_table "users", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| @@ -202,20 +212,36 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_30_095753) do t.datetime "locked_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.uuid "wedding_id", null: false t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true t.index ["unlock_token"], name: "index_users_on_unlock_token", unique: true + t.index ["wedding_id"], name: "index_users_on_wedding_id" end + create_table "weddings", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.string "slug", null: false + t.date "date", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["slug"], name: "index_weddings_on_slug", unique: true + end + + add_foreign_key "expenses", "weddings" add_foreign_key "groups", "groups", column: "parent_id" + add_foreign_key "groups", "weddings" add_foreign_key "guests", "groups" + add_foreign_key "guests", "weddings" add_foreign_key "seats", "guests" add_foreign_key "seats", "tables_arrangements", 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" + add_foreign_key "users", "weddings" end diff --git a/db/seeds.rb b/db/seeds.rb index 9590f3a..e493f6b 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -7,71 +7,76 @@ Expense.delete_all Guest.delete_all Group.delete_all -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') +Wedding.delete_all +wedding = Wedding.create!(slug: :default, date: 1.year.from_now) -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| - family.children.create!(name: "Jim's close family", icon: 'pi pi-home') - family.children.create!(name: "Jim's cousins", icon: 'pi pi-home') - family.children.create!(name: "Jim's relatives", icon: 'pi pi-home') +ActsAsTenant.with_tenant(wedding) do + 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| + family.children.create!(name: "Jim's close family", icon: 'pi pi-home') + family.children.create!(name: "Jim's cousins", icon: 'pi pi-home') + family.children.create!(name: "Jim's relatives", icon: 'pi pi-home') + end + parent.children.create!(name: "Jim's friends", icon: 'pi pi-bullseye') + parent.children.create!(name: "Jim's work", icon: 'pi pi-desktop').tap do |work| + work.children.create!(name: "Jim's besties at work", icon: 'pi pi-briefcase') + end end - parent.children.create!(name: "Jim's friends", icon: 'pi pi-bullseye') - parent.children.create!(name: "Jim's work", icon: 'pi pi-desktop').tap do |work| - work.children.create!(name: "Jim's besties at work", icon: 'pi pi-briefcase') + + Group.create!(name: "Pam's guests", icon: 'pi pi-heart-fill').tap do |parent| + parent.children.create!(name: "Pam's family", icon: 'pi pi-users').tap do |family| + family.children.create!(name: "Pam's close family", icon: 'pi pi-home') + family.children.create!(name: "Pam's cousins", icon: 'pi pi-home') + family.children.create!(name: "Pam's relatives", icon: 'pi pi-home') + end + parent.children.create!(name: "Pam's friends", icon: 'pi pi-bullseye') + parent.children.create!(name: "Pam's work", icon: 'pi pi-desktop').tap do |work| + work.children.create!(name: "Pam's besties at work", icon: 'pi pi-briefcase') + end end -end -Group.create!(name: "Pam's guests", icon: 'pi pi-heart-fill').tap do |parent| - parent.children.create!(name: "Pam's family", icon: 'pi pi-users').tap do |family| - family.children.create!(name: "Pam's close family", icon: 'pi pi-home') - family.children.create!(name: "Pam's cousins", icon: 'pi pi-home') - family.children.create!(name: "Pam's relatives", icon: 'pi pi-home') + Group.create!(name: 'Common guests', icon: 'pi pi-users').tap do |parent| + parent.children.create!(name: 'College friends', icon: 'pi pi-calculator') + parent.children.create!(name: 'High school friends', icon: 'pi pi-crown') + parent.children.create!(name: 'Childhood friends', icon: 'pi pi-envelope') end - parent.children.create!(name: "Pam's friends", icon: 'pi pi-bullseye') - parent.children.create!(name: "Pam's work", icon: 'pi pi-desktop').tap do |work| - work.children.create!(name: "Pam's besties at work", icon: 'pi pi-briefcase') + + groups = Group.all + + NUMBER_OF_GUESTS.times do + Guest.create!( + name: Faker::Name.name, + phone: Faker::PhoneNumber.cell_phone, + group: groups.sample, + status: Guest.statuses.keys.sample + ) end -end -Group.create!(name: 'Common guests', icon: 'pi pi-users').tap do |parent| - parent.children.create!(name: 'College friends', icon: 'pi pi-calculator') - parent.children.create!(name: 'High school friends', icon: 'pi pi-crown') - parent.children.create!(name: 'Childhood friends', icon: 'pi pi-envelope') -end + ActiveJob.perform_all_later(3.times.map { TableSimulatorJob.new(wedding.id) }) -groups = Group.all + 'red'.paint.palette.triad(as: :hex).zip(Group.roots).each { |(color, group)| group.update!(color: color.paint.desaturate(40)) } -NUMBER_OF_GUESTS.times do - Guest.create!( - name: Faker::Name.name, - phone: Faker::PhoneNumber.cell_phone, - group: groups.sample, - status: Guest.statuses.keys.sample + Group.roots.each(&:colorize_children) + + User.create!( + email: 'development@example.com', + confirmed_at: Time.zone.now, + password: 'supersecretpassword', + password_confirmation: 'supersecretpassword', ) end - -ActiveJob.perform_all_later(3.times.map { TableSimulatorJob.new }) - -'red'.paint.palette.triad(as: :hex).zip(Group.roots).each { |(color, group)| group.update!(color: color.paint.desaturate(40)) } - -Group.roots.each(&:colorize_children) - -User.create!( - email: 'development@example.com', - confirmed_at: Time.zone.now, - password: 'supersecretpassword', - password_confirmation: 'supersecretpassword', -) \ No newline at end of file diff --git a/spec/factories/expense.rb b/spec/factories/expense.rb index 9670768..726d94d 100644 --- a/spec/factories/expense.rb +++ b/spec/factories/expense.rb @@ -2,6 +2,7 @@ FactoryBot.define do factory :expense do + wedding sequence(:name) { |i| "Expense #{i}" } pricing_type { "fixed" } amount { 100 } diff --git a/spec/factories/groups.rb b/spec/factories/groups.rb index 4ebce4e..ccd1156 100644 --- a/spec/factories/groups.rb +++ b/spec/factories/groups.rb @@ -2,6 +2,7 @@ FactoryBot.define do factory :group do + wedding sequence(:name) { |i| "Group #{i}" } order { 1 } end diff --git a/spec/factories/guest.rb b/spec/factories/guest.rb index 4c9b58a..28f3b80 100644 --- a/spec/factories/guest.rb +++ b/spec/factories/guest.rb @@ -2,7 +2,8 @@ FactoryBot.define do factory :guest do - association :group + group + wedding name { Faker::Name.name } phone { Faker::PhoneNumber.cell_phone } diff --git a/spec/factories/table_arrangement.rb b/spec/factories/table_arrangement.rb new file mode 100644 index 0000000..693e68a --- /dev/null +++ b/spec/factories/table_arrangement.rb @@ -0,0 +1,8 @@ +# Copyright (C) 2024 Manuel Bustillo + +FactoryBot.define do + factory :tables_arrangement do + wedding + end +end + \ No newline at end of file diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 7839fbe..2aa8a37 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -2,6 +2,6 @@ FactoryBot.define do factory :user do - + wedding end end diff --git a/spec/factories/weddings.rb b/spec/factories/weddings.rb new file mode 100644 index 0000000..3680045 --- /dev/null +++ b/spec/factories/weddings.rb @@ -0,0 +1,8 @@ +# Copyright (C) 2024 Manuel Bustillo + +FactoryBot.define do + factory :wedding do + sequence(:slug) { |i| "wedding-#{i}" } + date { 1.year.from_now } + end +end diff --git a/spec/models/tables_arrangement_spec.rb b/spec/models/tables_arrangement_spec.rb index c15971a..4db0859 100644 --- a/spec/models/tables_arrangement_spec.rb +++ b/spec/models/tables_arrangement_spec.rb @@ -5,7 +5,7 @@ require 'rails_helper' RSpec.describe TablesArrangement, type: :model do describe 'callbacks' do it 'assigns a name before creation' do - expect(described_class.create!.name).to be_present + expect(create(:tables_arrangement).name).to be_present end end end diff --git a/spec/models/wedding_spec.rb b/spec/models/wedding_spec.rb new file mode 100644 index 0000000..702769f --- /dev/null +++ b/spec/models/wedding_spec.rb @@ -0,0 +1,7 @@ +# Copyright (C) 2024 Manuel Bustillo + +require 'rails_helper' + +RSpec.describe Wedding, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/expenses_spec.rb b/spec/requests/expenses_spec.rb index 5e99097..74cf861 100644 --- a/spec/requests/expenses_spec.rb +++ b/spec/requests/expenses_spec.rb @@ -3,10 +3,12 @@ require 'swagger_helper' RSpec.describe 'expenses', type: :request do - path '/expenses' do + path '/{slug}/expenses' do get('list expenses') do tags 'Expenses' produces 'application/json' + parameter Swagger::Schema::SLUG + response(200, 'successful') do schema type: :array, items: { @@ -26,12 +28,13 @@ RSpec.describe 'expenses', type: :request do end end - path '/expenses/{id}' do + path '/{slug}/expenses/{id}' do patch('update expense') do tags 'Expenses' consumes 'application/json' produces 'application/json' + parameter Swagger::Schema::SLUG parameter name: 'id', in: :path, type: :string, format: :uuid, description: 'id' parameter name: :body, in: :body, schema: { type: :object, diff --git a/spec/requests/groups_spec.rb b/spec/requests/groups_spec.rb index fd014b5..6d5f057 100644 --- a/spec/requests/groups_spec.rb +++ b/spec/requests/groups_spec.rb @@ -3,10 +3,11 @@ require 'swagger_helper' RSpec.describe 'groups', type: :request do - path '/groups' do + path '/{slug}/groups' do get('list groups') do tags 'Groups' produces 'application/json' + parameter Swagger::Schema::SLUG response(200, 'successful') do schema type: :array, items: { diff --git a/spec/requests/guests_spec.rb b/spec/requests/guests_spec.rb index b73fbcb..9b542fd 100644 --- a/spec/requests/guests_spec.rb +++ b/spec/requests/guests_spec.rb @@ -3,10 +3,11 @@ require 'swagger_helper' RSpec.describe 'guests', type: :request do - path '/guests' do + path '/{slug}/guests' do get('list guests') do tags 'Guests' produces 'application/json' + parameter Swagger::Schema::SLUG response(200, 'successful') do schema type: :array, items: { @@ -33,6 +34,7 @@ RSpec.describe 'guests', type: :request do tags 'Guests' consumes 'application/json' produces 'application/json' + parameter Swagger::Schema::SLUG parameter name: :body, in: :body, schema: { type: :object, required: %i[guest], @@ -55,11 +57,12 @@ RSpec.describe 'guests', type: :request do end end - path '/guests/{id}' do + path '/{slug}/guests/{id}' do patch('update guest') do tags 'Guests' consumes 'application/json' produces 'application/json' + parameter Swagger::Schema::SLUG parameter name: 'id', in: :path, type: :string, format: :uuid parameter name: :body, in: :body, schema: { type: :object, @@ -85,6 +88,7 @@ RSpec.describe 'guests', type: :request do delete('delete guest') do tags 'Guests' produces 'application/json' + parameter Swagger::Schema::SLUG parameter name: 'id', in: :path, type: :string, format: :uuid response_empty_200 diff --git a/spec/requests/schemas.rb b/spec/requests/schemas.rb index 7a49ca0..ce35ad7 100644 --- a/spec/requests/schemas.rb +++ b/spec/requests/schemas.rb @@ -9,5 +9,13 @@ module Swagger updated_at: SwaggerResponseHelper::TIMESTAMP } + + SLUG = { + name: 'slug', + in: :path, + type: :string, + example: :default, + description: 'Wedding slug' + } end end \ No newline at end of file diff --git a/spec/requests/users/confirmations_spec.rb b/spec/requests/users/confirmations_spec.rb index e99794e..12bdfbc 100644 --- a/spec/requests/users/confirmations_spec.rb +++ b/spec/requests/users/confirmations_spec.rb @@ -4,11 +4,12 @@ require 'swagger_helper' RSpec.describe 'users/confirmations', type: :request do - path '/users/confirmation' do + path '/{slug}/users/confirmation' do get('confirm user email') do tags 'Users' produces 'application/json' + parameter Swagger::Schema::SLUG parameter name: :confirmation_token, in: :query, type: :string, required: true response(200, 'confirmed') do diff --git a/spec/requests/users/registrations_spec.rb b/spec/requests/users/registrations_spec.rb index f92222c..aa7562f 100644 --- a/spec/requests/users/registrations_spec.rb +++ b/spec/requests/users/registrations_spec.rb @@ -4,12 +4,13 @@ require 'swagger_helper' RSpec.describe 'users/registrations', type: :request do - path '/users' do + path '/{slug}/users' do post('create registration') do tags 'Users Registrations' consumes 'application/json' produces 'application/json' - + + parameter Swagger::Schema::SLUG parameter name: :body, in: :body, schema: { type: :object, required: [:user], diff --git a/spec/requests/users/sessions_spec.rb b/spec/requests/users/sessions_spec.rb index ff7c8a3..a803965 100644 --- a/spec/requests/users/sessions_spec.rb +++ b/spec/requests/users/sessions_spec.rb @@ -4,13 +4,14 @@ require 'swagger_helper' RSpec.describe 'users/sessions', type: :request do - path '/users/sign_in' do + path '/{slug}/users/sign_in' do post('create session') do tags 'Users Sessions' consumes 'application/json' produces 'application/json' + parameter Swagger::Schema::SLUG parameter name: :body, in: :body, schema: { type: :object, required: %i[user], @@ -35,8 +36,8 @@ RSpec.describe 'users/sessions', type: :request do end end - path '/users/sign_out' do - + path '/{slug}/users/sign_out' do + parameter Swagger::Schema::SLUG delete('delete session') do tags 'Users Sessions' consumes 'application/json'