Merge pull request 'Extend the invitations index endpoint to return a PDF file with QRs for invitations' (#287) from invitations-pdf into main
Some checks failed
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 55s
Run unit tests / build-static-assets (push) Failing after 1m9s
Some checks failed
Run unit tests / rubocop (push) Has been skipped
Run unit tests / check-licenses (push) Has been skipped
Run unit tests / copyright_notice (push) Has been skipped
Run unit tests / unit_tests (push) Successful in 55s
Run unit tests / build-static-assets (push) Failing after 1m9s
Reviewed-on: #287
This commit is contained in:
commit
f46f25b799
@ -13,7 +13,7 @@ ENV RAILS_ENV="production" \
|
|||||||
BUNDLE_PATH="/usr/local/bundle" \
|
BUNDLE_PATH="/usr/local/bundle" \
|
||||||
BUNDLE_WITHOUT="development"
|
BUNDLE_WITHOUT="development"
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y nodejs
|
RUN apt-get update && apt-get install -y nodejs wkhtmltopdf
|
||||||
|
|
||||||
# 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
|
||||||
|
@ -7,7 +7,7 @@ FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
|
|||||||
# Rails app lives here
|
# Rails app lives here
|
||||||
WORKDIR /rails
|
WORKDIR /rails
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y nodejs
|
RUN apt-get update && apt-get install -y nodejs wkhtmltopdf
|
||||||
|
|
||||||
FROM base as build
|
FROM base as build
|
||||||
|
|
||||||
|
4
Gemfile
4
Gemfile
@ -51,3 +51,7 @@ gem 'chroma'
|
|||||||
gem 'solid_queue', '~> 1.0'
|
gem 'solid_queue', '~> 1.0'
|
||||||
|
|
||||||
gem 'devise', '~> 4.9'
|
gem 'devise', '~> 4.9'
|
||||||
|
|
||||||
|
gem 'wicked_pdf', '~> 2.8'
|
||||||
|
|
||||||
|
gem 'rqrcode', '~> 3.1'
|
||||||
|
16
Gemfile.lock
16
Gemfile.lock
@ -95,6 +95,7 @@ GEM
|
|||||||
childprocess (5.1.0)
|
childprocess (5.1.0)
|
||||||
logger (~> 1.5)
|
logger (~> 1.5)
|
||||||
chroma (0.2.0)
|
chroma (0.2.0)
|
||||||
|
chunky_png (1.4.0)
|
||||||
coderay (1.1.3)
|
coderay (1.1.3)
|
||||||
concurrent-ruby (1.3.5)
|
concurrent-ruby (1.3.5)
|
||||||
connection_pool (2.5.3)
|
connection_pool (2.5.3)
|
||||||
@ -224,6 +225,7 @@ GEM
|
|||||||
nokogiri (1.18.8-x86_64-linux-gnu)
|
nokogiri (1.18.8-x86_64-linux-gnu)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
|
ostruct (0.6.2)
|
||||||
parallel (1.27.0)
|
parallel (1.27.0)
|
||||||
parser (3.3.8.0)
|
parser (3.3.8.0)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
@ -309,6 +311,10 @@ GEM
|
|||||||
actionpack (>= 5.2)
|
actionpack (>= 5.2)
|
||||||
railties (>= 5.2)
|
railties (>= 5.2)
|
||||||
rexml (3.3.9)
|
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.4)
|
||||||
rspec-support (~> 3.13.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-expectations (3.13.5)
|
rspec-expectations (3.13.5)
|
||||||
@ -418,6 +424,9 @@ GEM
|
|||||||
base64
|
base64
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
websocket-extensions (0.1.5)
|
websocket-extensions (0.1.5)
|
||||||
|
wicked_pdf (2.8.2)
|
||||||
|
activesupport
|
||||||
|
ostruct
|
||||||
with_env (1.1.0)
|
with_env (1.1.0)
|
||||||
xml-simple (1.1.9)
|
xml-simple (1.1.9)
|
||||||
rexml
|
rexml
|
||||||
@ -456,6 +465,7 @@ DEPENDENCIES
|
|||||||
rails (~> 8.0.0, >= 8.0.0)
|
rails (~> 8.0.0, >= 8.0.0)
|
||||||
react-rails
|
react-rails
|
||||||
redis (>= 4.0.1)
|
redis (>= 4.0.1)
|
||||||
|
rqrcode (~> 3.1)
|
||||||
rspec-rails (~> 8.0.0)
|
rspec-rails (~> 8.0.0)
|
||||||
rswag
|
rswag
|
||||||
rubocop
|
rubocop
|
||||||
@ -471,6 +481,7 @@ DEPENDENCIES
|
|||||||
turbo-rails
|
turbo-rails
|
||||||
tzinfo-data
|
tzinfo-data
|
||||||
web-console
|
web-console
|
||||||
|
wicked_pdf (~> 2.8)
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
actioncable (8.0.2) sha256=7bcce2df62e91a80143592600e16583c273e98aab50ae40a9f6a2604bb3289a0
|
actioncable (8.0.2) sha256=7bcce2df62e91a80143592600e16583c273e98aab50ae40a9f6a2604bb3289a0
|
||||||
@ -499,6 +510,7 @@ CHECKSUMS
|
|||||||
builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
|
builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
|
||||||
childprocess (5.1.0) sha256=9a8d484be2fd4096a0e90a0cd3e449a05bc3aa33f8ac9e4d6dcef6ac1455b6ec
|
childprocess (5.1.0) sha256=9a8d484be2fd4096a0e90a0cd3e449a05bc3aa33f8ac9e4d6dcef6ac1455b6ec
|
||||||
chroma (0.2.0) sha256=64bdcd36a4765fbcd45adc64960cc153101300b4918f90ffdd89f4e2eb954b54
|
chroma (0.2.0) sha256=64bdcd36a4765fbcd45adc64960cc153101300b4918f90ffdd89f4e2eb954b54
|
||||||
|
chunky_png (1.4.0) sha256=89d5b31b55c0cf4da3cf89a2b4ebc3178d8abe8cbaf116a1dba95668502fdcfe
|
||||||
coderay (1.1.3) sha256=dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b
|
coderay (1.1.3) sha256=dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b
|
||||||
concurrent-ruby (1.3.5) sha256=813b3e37aca6df2a21a3b9f1d497f8cbab24a2b94cab325bffe65ee0f6cbebc6
|
concurrent-ruby (1.3.5) sha256=813b3e37aca6df2a21a3b9f1d497f8cbab24a2b94cab325bffe65ee0f6cbebc6
|
||||||
connection_pool (2.5.3) sha256=cfd74a82b9b094d1ce30c4f1a346da23ee19dc8a062a16a85f58eab1ced4305b
|
connection_pool (2.5.3) sha256=cfd74a82b9b094d1ce30c4f1a346da23ee19dc8a062a16a85f58eab1ced4305b
|
||||||
@ -561,6 +573,7 @@ CHECKSUMS
|
|||||||
nokogiri (1.18.8-x86_64-darwin) sha256=024cdfe7d9ae3466bba6c06f348fb2a8395d9426b66a3c82f1961b907945cc0c
|
nokogiri (1.18.8-x86_64-darwin) sha256=024cdfe7d9ae3466bba6c06f348fb2a8395d9426b66a3c82f1961b907945cc0c
|
||||||
nokogiri (1.18.8-x86_64-linux-gnu) sha256=4a747875db873d18a2985ee2c320a6070c4a414ad629da625fbc58d1a20e5ecc
|
nokogiri (1.18.8-x86_64-linux-gnu) sha256=4a747875db873d18a2985ee2c320a6070c4a414ad629da625fbc58d1a20e5ecc
|
||||||
orm_adapter (0.5.0) sha256=aa5d0be5d540cbb46d3a93e88061f4ece6a25f6e97d6a47122beb84fe595e9b9
|
orm_adapter (0.5.0) sha256=aa5d0be5d540cbb46d3a93e88061f4ece6a25f6e97d6a47122beb84fe595e9b9
|
||||||
|
ostruct (0.6.2) sha256=6d7302a299e400a2c248d6ce0dad18fc3a5714e8096facc25ffd0c54ee57cfc0
|
||||||
parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
|
parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
|
||||||
parser (3.3.8.0) sha256=2476364142b307fa5a1b1ece44f260728be23858a9c71078e956131a75453c45
|
parser (3.3.8.0) sha256=2476364142b307fa5a1b1ece44f260728be23858a9c71078e956131a75453c45
|
||||||
pg (1.5.9) sha256=761efbdf73b66516f0c26fcbe6515dc7500c3f0aa1a1b853feae245433c64fdc
|
pg (1.5.9) sha256=761efbdf73b66516f0c26fcbe6515dc7500c3f0aa1a1b853feae245433c64fdc
|
||||||
@ -593,6 +606,8 @@ CHECKSUMS
|
|||||||
reline (0.6.1) sha256=1afcc9d7cb1029cdbe780d72f2f09251ce46d3780050f3ec39c3ccc6b60675fb
|
reline (0.6.1) sha256=1afcc9d7cb1029cdbe780d72f2f09251ce46d3780050f3ec39c3ccc6b60675fb
|
||||||
responders (3.1.1) sha256=92f2a87e09028347368639cfb468f5fefa745cb0dc2377ef060db1cdd79a341a
|
responders (3.1.1) sha256=92f2a87e09028347368639cfb468f5fefa745cb0dc2377ef060db1cdd79a341a
|
||||||
rexml (3.3.9) sha256=d71875b85299f341edf47d44df0212e7658cbdf35aeb69cefdb63f57af3137c9
|
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-core (3.13.4) sha256=f9da156b7b775c82610a7b580624df51a55102f8c8e4a103b98f5d7a9fa23958
|
||||||
rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
|
rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
|
||||||
rspec-mocks (3.13.5) sha256=e4338a6f285ada9fe56f5893f5457783af8194f5d08884d17a87321d5195ea81
|
rspec-mocks (3.13.5) sha256=e4338a6f285ada9fe56f5893f5457783af8194f5d08884d17a87321d5195ea81
|
||||||
@ -631,6 +646,7 @@ CHECKSUMS
|
|||||||
web-console (4.2.1) sha256=e7bcf37a10ea2b4ec4281649d1cee461b32232d0a447e82c786e6841fd22fe20
|
web-console (4.2.1) sha256=e7bcf37a10ea2b4ec4281649d1cee461b32232d0a447e82c786e6841fd22fe20
|
||||||
websocket-driver (0.7.7) sha256=056d99f2cd545712cfb1291650fde7478e4f2661dc1db6a0fa3b966231a146b4
|
websocket-driver (0.7.7) sha256=056d99f2cd545712cfb1291650fde7478e4f2661dc1db6a0fa3b966231a146b4
|
||||||
websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241
|
websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241
|
||||||
|
wicked_pdf (2.8.2) sha256=648d9b0cec5a34adbc9bbf809731052a78119e2d6d323b9e4aa1383e1d683824
|
||||||
with_env (1.1.0) sha256=50b3e4f0a6cda8f90d8a6bd87a6261f6c381429abafb161c4c69ad4a0cd0b6e4
|
with_env (1.1.0) sha256=50b3e4f0a6cda8f90d8a6bd87a6261f6c381429abafb161c4c69ad4a0cd0b6e4
|
||||||
xml-simple (1.1.9) sha256=d21131e519c86f1a5bc2b6d2d57d46e6998e47f18ed249b25cad86433dbd695d
|
xml-simple (1.1.9) sha256=d21131e519c86f1a5bc2b6d2d57d46e6998e47f18ed249b25cad86433dbd695d
|
||||||
zeitwerk (2.7.3) sha256=b2e86b4a9b57d26ba68a15230dcc7fe6f040f06831ce64417b0621ad96ba3e85
|
zeitwerk (2.7.3) sha256=b2e86b4a9b57d26ba68a15230dcc7fe6f040f06831ce64417b0621ad96ba3e85
|
||||||
|
@ -6,16 +6,28 @@ class InvitationsController < ApplicationController
|
|||||||
skip_before_action :authenticate_user!, only: :show
|
skip_before_action :authenticate_user!, only: :show
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render json: Invitation.includes(:guests).as_json(
|
@invitations = Invitation.includes(:guests).all
|
||||||
only: :id,
|
respond_to do |format|
|
||||||
include: {
|
format.json do
|
||||||
guests: {
|
render json: @invitations.as_json(
|
||||||
only: %i[id name]
|
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
|
end
|
||||||
|
|
||||||
|
def sheet; end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
invitation = Invitation.includes(:guests).find(params[:id])
|
invitation = Invitation.includes(:guests).find(params[:id])
|
||||||
|
|
||||||
|
@ -22,4 +22,8 @@
|
|||||||
class Invitation < ApplicationRecord
|
class Invitation < ApplicationRecord
|
||||||
acts_as_tenant :wedding
|
acts_as_tenant :wedding
|
||||||
has_many :guests, dependent: :nullify
|
has_many :guests, dependent: :nullify
|
||||||
|
|
||||||
|
def url
|
||||||
|
"#{Rails.application.routes.url_helpers.root_url(slug: ActsAsTenant.current_tenant.slug)}/site/invitation/#{id}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
33
app/views/invitations/sheet.html.erb
Normal file
33
app/views/invitations/sheet.html.erb
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<%# 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 %>
|
12
app/views/layouts/pdf.html.erb
Normal file
12
app/views/layouts/pdf.html.erb
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<%# Copyright (C) 2024-2025 LibreWeddingPlanner contributors %>
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset='utf-8' />
|
||||||
|
</head>
|
||||||
|
<div id="content">
|
||||||
|
<%= yield %>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -79,4 +79,5 @@ Rails.application.configure do
|
|||||||
config.action_controller.raise_on_missing_callback_actions = true
|
config.action_controller.raise_on_missing_callback_actions = true
|
||||||
|
|
||||||
config.hosts << "libre-wedding-planner.app.localhost"
|
config.hosts << "libre-wedding-planner.app.localhost"
|
||||||
|
Rails.application.routes.default_url_options[:host] = "libre-wedding-planner.app.localhost"
|
||||||
end
|
end
|
||||||
|
@ -94,6 +94,7 @@ Rails.application.configure do
|
|||||||
# ]
|
# ]
|
||||||
|
|
||||||
config.hosts << "app.libreweddingplanner.org"
|
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.
|
# Skip DNS rebinding protection for the default health check endpoint.
|
||||||
config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
|
config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
|
||||||
|
32
config/initializers/wicked_pdf.rb
Normal file
32
config/initializers/wicked_pdf.rb
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# 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
|
Loading…
x
Reference in New Issue
Block a user