Compare commits

..

10 Commits

Author SHA1 Message Date
612cb9a789 Refine arrangement detail endpoint
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 1m21s
Run unit tests / unit_tests (pull_request) Successful in 2m17s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 25m8s
2024-11-02 11:23:00 +01:00
d4c1e5aab0 Rewrite table arrangements endpoints 2024-11-02 10:40:43 +01:00
83fbac76f6 Merge pull request 'Remove acts_as_taggable_on gem' (#82) from remove-acts-as-taggable into main
All checks were successful
Run unit tests / unit_tests (push) Successful in 2m14s
Build Nginx-based docker image / build-static-assets (push) Successful in 25m23s
Reviewed-on: #82
2024-11-02 08:54:23 +00:00
bf970af2c5 Remove tags table as well
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 2m40s
Run unit tests / unit_tests (pull_request) Successful in 4m16s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 47m21s
2024-11-01 19:55:39 +00:00
eb85028eea Add copyright notice 2024-11-01 19:55:39 +00:00
5fef6f1011 Remove references to acts_as_taggable_on gem 2024-11-01 19:55:39 +00:00
ea129602b5 Uninstall acts as taggable on gem 2024-11-01 19:55:39 +00:00
7bb9d83c6e Merge pull request 'Remove HTML views and non-JSON endpoints' (#81) from remove-html-views into main
All checks were successful
Run unit tests / unit_tests (push) Successful in 4m1s
Build Nginx-based docker image / build-static-assets (push) Successful in 49m11s
Reviewed-on: #81
2024-11-01 19:54:15 +00:00
db644c85be Remove HTML views
All checks were successful
Add copyright notice / copyright_notice (pull_request) Successful in 1m31s
Run unit tests / unit_tests (pull_request) Successful in 2m49s
Build Nginx-based docker image / build-static-assets (pull_request) Successful in 31m42s
2024-11-01 19:08:01 +01:00
1f93fe42c5 Clean up unused methods and non-API endpoints from controllers 2024-11-01 19:07:12 +01:00
25 changed files with 48 additions and 505 deletions

View File

@ -1,7 +1,6 @@
source 'https://rubygems.org'
ruby '3.3.5'
gem 'acts-as-taggable-on'
gem 'bootsnap', require: false
gem 'csv'
gem 'importmap-rails'

View File

@ -72,9 +72,6 @@ GEM
minitest (>= 5.1)
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
acts-as-taggable-on (11.0.0)
activerecord (>= 7.0, < 8.0)
zeitwerk (>= 2.4, < 3.0)
ast (2.4.2)
babel-source (5.8.35)
babel-transpiler (0.7.0)
@ -315,7 +312,6 @@ PLATFORMS
x86_64-linux
DEPENDENCIES
acts-as-taggable-on
bootsnap
csv
debug

View File

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

View File

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

View File

@ -2,35 +2,15 @@
class TablesArrangementsController < ApplicationController
def index
@tables_arrangements = TablesArrangement.all.order(discomfort: :asc).limit(10)
respond_to do |format|
format.html
format.json { render json: @tables_arrangements }
end
render json: TablesArrangement.all.order(discomfort: :asc).limit(10).as_json(only: %i[id discomfort])
end
def show
@tables_arrangement = TablesArrangement.find(params[:id])
@seats = @tables_arrangement.seats.group_by(&:table_number)
respond_to do |format|
format.html
format.json do
render json: {
tables: @seats.map do |table_number, seats|
{
table_number: table_number,
guests: seats.map do |seat|
{
guest: seat.guest,
group: seat.guest.group,
}
end
}
end
}
end
end
Seat.joins(:guest).where(tables_arrangement_id: params[:id])
.pluck(:table_number, Arel.sql("guests.first_name || ' ' || guests.last_name "), 'guests.id')
.group_by(&:first)
.transform_values { |table| table.map { |(_, name, id)| { id:, name: } } }
.map { |number, guests| { number:, guests: } }
.then { |result| render json: result }
end
end

View File

@ -1,7 +1,6 @@
# Copyright (C) 2024 Manuel Bustillo
class Guest < ApplicationRecord
acts_as_taggable_on :affinity_groups, :unbreakable_bonds
belongs_to :group
enum status: {

View File

@ -2,4 +2,5 @@
class TablesArrangement < ApplicationRecord
has_many :seats
has_many :guests, through: :seats
end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

34
db/schema.rb generated
View File

@ -12,7 +12,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.1].define(version: 2024_08_11_170021) do
ActiveRecord::Schema[7.2].define(version: 2024_11_01_181052) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -67,40 +67,8 @@ ActiveRecord::Schema[7.1].define(version: 2024_08_11_170021) do
t.datetime "updated_at", null: false
end
create_table "taggings", force: :cascade do |t|
t.bigint "tag_id"
t.string "taggable_type"
t.uuid "taggable_id"
t.string "tagger_type"
t.bigint "tagger_id"
t.string "context", limit: 128
t.datetime "created_at", precision: nil
t.string "tenant", limit: 128
t.index ["context"], name: "index_taggings_on_context"
t.index ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true
t.index ["tag_id"], name: "index_taggings_on_tag_id"
t.index ["taggable_id", "taggable_type", "context"], name: "taggings_taggable_context_idx"
t.index ["taggable_id", "taggable_type", "tagger_id", "context"], name: "taggings_idy"
t.index ["taggable_id"], name: "index_taggings_on_taggable_id"
t.index ["taggable_type", "taggable_id"], name: "index_taggings_on_taggable_type_and_taggable_id"
t.index ["taggable_type"], name: "index_taggings_on_taggable_type"
t.index ["tagger_id", "tagger_type"], name: "index_taggings_on_tagger_id_and_tagger_type"
t.index ["tagger_id"], name: "index_taggings_on_tagger_id"
t.index ["tagger_type", "tagger_id"], name: "index_taggings_on_tagger_type_and_tagger_id"
t.index ["tenant"], name: "index_taggings_on_tenant"
end
create_table "tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "taggings_count", default: 0
t.index ["name"], name: "index_tags_on_name", unique: true
end
add_foreign_key "groups", "groups", column: "parent_id"
add_foreign_key "guests", "groups"
add_foreign_key "seats", "guests"
add_foreign_key "seats", "tables_arrangements", on_delete: :cascade
add_foreign_key "taggings", "tags"
end

View File

@ -5,8 +5,6 @@ NUMBER_OF_GUESTS = 50
TablesArrangement.delete_all
Expense.delete_all
Guest.delete_all
ActsAsTaggableOn::Tagging.delete_all
ActsAsTaggableOn::Tag.delete_all
Group.delete_all
Expense.create!(name: 'Photographer', amount: 3000, pricing_type: 'fixed')