Skip to content

Commit

Permalink
zip
Browse files Browse the repository at this point in the history
  • Loading branch information
michelson committed Aug 7, 2024
1 parent 145cc44 commit b52e8c0
Show file tree
Hide file tree
Showing 31 changed files with 653 additions and 127 deletions.
6 changes: 3 additions & 3 deletions app/assets/stylesheets/application.tailwind.css
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@

.select,
select {
@apply block w-full rounded-md border-0 px-3 pl-3 pr-10 text-default ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-brand-600 sm:text-sm sm:leading-6;
@apply block w-full rounded-md border-0 px-3 pl-3 pr-10 text-default ring-1 ring-inset ring-subtle focus:ring-2 focus:ring-brand-600 sm:text-sm sm:leading-6;
}

label {
Expand Down Expand Up @@ -261,11 +261,11 @@
oijoijoij
} */
.my-react-select-container .my-react-select__control {
@apply bg-white dark:bg-neutral-700 border-2 border-neutral-300 dark:border-neutral-700 hover:border-neutral-400 dark:hover:border-neutral-500;
@apply bg-default border-2 border-subtle hover:border-muted;
}

.my-react-select-container .my-react-select__control--is-focused {
@apply border-neutral-500 hover:border-neutral-500 dark:border-neutral-400 dark:hover:border-neutral-400 shadow-none;
@apply border-subtle hover:border-subtle shadow-none;
}

.my-react-select-container .my-react-select__menu {
Expand Down
107 changes: 107 additions & 0 deletions app/controllers/playlist_purchases_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
class PlaylistPurchasesController < ApplicationController
before_action :authenticate_user!

def new
@playlist = Playlist.friendly.find(params[:playlist_id])
@payment = Payment.new
@payment.assign_attributes(initial_price: @playlist.price)
@purchase = current_user.purchases.new
end

def create
@playlist = Playlist.friendly.find(params[:playlist_id])
@payment = Payment.new
@payment.assign_attributes(build_params)

customer = current_user

price = @playlist.price
price_param = build_params[:price].to_f
if @playlist.name_your_price? && price_param && price_param > @playlist.price.to_f
price = price_param
end

@purchase = current_user.purchases.new(purchasable: @playlist, price: price)

@purchase.virtual_purchased = [
VirtualPurchasedItem.new({resource: @playlist, quantity: 1})
]

handle_stripe_session
end

def handle_stripe_session
account = @playlist.user.oauth_credentials.find_by(provider: "stripe_connect")
Stripe.stripe_account = account.uid unless account.blank?

ActiveRecord::Base.transaction do
@purchase.store_items
@purchase.save

line_items = [{
"quantity" => 1,
"price_data" => {
"unit_amount" => (@purchase.price * 100).to_i,
"currency" => "USD",
"product_data" => {
"name" => @playlist.title,
"description" => "#{@playlist.title} from #{@playlist.user.username}"
}
}
}]

fee_amount = ENV.fetch('PLATFORM_EVENTS_FEE', 3).to_i

payment_intent_data = {}

if account
payment_intent_data = {
application_fee_amount: fee_amount
}
end

@session = Stripe::Checkout::Session.create(
payment_method_types: ["card"],
line_items: line_items,
payment_intent_data: payment_intent_data,
customer_email: current_user.email,
mode: "payment",
success_url: success_playlist_playlist_purchase_url(@playlist, @purchase),
cancel_url: failure_playlist_playlist_purchase_url(@playlist, @purchase)
)

@purchase.update(
checkout_type: "stripe",
checkout_id: @session["id"]
)

@payment_url = @session["url"]
end
end

def success
@playlist = Playlist.friendly.find(params[:playlist_id])
@purchase = current_user.purchases.find(params[:id])

if params[:enc].present?
decoded_purchase = Purchase.find_signed(CGI.unescape(params[:enc]))
@purchase.complete_purchase! if decoded_purchase.id == @purchase.id
end

render "show"
end

def failure
@playlist = Playlist.friendly.find(params[:playlist_id])
@purchase = current_user.purchases.find(params[:id])
render "show"
end

private

def build_params
params.require(:payment).permit(
:include_message, :optional_message, :price
)
end
end
1 change: 1 addition & 0 deletions app/controllers/playlists_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def playlist_params
:record_label, :buy_link, :buy_link_title,
:enable_label,
:copyright,
:name_your_price,
:attribution, :noncommercial, :non_derivative_works, :copies,
track_playlists_attributes: [
:id,
Expand Down
35 changes: 34 additions & 1 deletion app/controllers/purchases_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,39 @@ def tickets

def music
kind = (params[:tab] == "tracks") ? "Track" : "Playlist"
@collection = current_user.purchases.where(state: "paid", purchasable_type: kind).page
type = params[:type] || "paid"
@collection = current_user.purchases.where(state: type, purchasable_type: kind).page
end

def download
@purchase = Purchase.find(params[:id])

if @purchase.purchasable.zip.attached?
render turbo_stream: turbo_stream.replace(
"purchase_#{@purchase.id}_download",
partial: 'purchases/download_ready',
locals: { purchase: @purchase }
)
else
ZipperJob.perform_later(purchase_id: @purchase.id)
render turbo_stream: turbo_stream.replace(
"purchase_#{@purchase.id}_download",
partial: 'purchases/download_processing',
locals: { purchase: @purchase }
)
end
end

def check_zip_status
@purchase = Purchase.find(params[:id])
if @purchase.purchasable.zip.attached?
render turbo_stream: turbo_stream.replace(
"purchase_#{@purchase.id}_download",
partial: 'purchases/download_ready',
locals: { purchase: @purchase }
)
else
head :no_content
end
end
end
2 changes: 1 addition & 1 deletion app/controllers/track_purchases_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def handle_stripe_session

puts line_items

fee_amount = 3
fee_amount = ENV.fetch('PLATFORM_EVENTS_FEE', 3).to_i

payment_intent_data = {}

Expand Down
2 changes: 2 additions & 0 deletions app/helpers/playlist_purchases_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module PlaylistPurchasesHelper
end
17 changes: 12 additions & 5 deletions app/helpers/tailwind_form_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ def radio_button(method, value, options = {})
end

def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
# Conditionally build the label if options[:label] is not false
info = ""
unless options[:label] == false
info = @template.label_tag(
Expand All @@ -160,14 +159,22 @@ def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
) + field_details(method, object, options)
end

# Merge in default class unless a specific class has been provided in options
options.merge!(class: "self-center mt-1-- mr-2 form-checkbox h-4 w-4 text-indigo-600 transition duration-150 ease-in-out") unless options.key?(:class)

# Create the checkbox and, conditionally, its label
hint = ""
if options[:hint].present?
hint_text = options[:hint].is_a?(Proc) ? @template.capture(&options[:hint]) : options[:hint]
hint = @template.content_tag(:p, hint_text.html_safe, class: "mt-1 text-sm text-gray-500")
end

@template.tag.div(class: "flex items-center space-x-2") do
@template.check_box(
checkbox = @template.check_box(
@object_name, method, objectify_options(options), checked_value, unchecked_value
) + (info.present? ? @template.tag.div(class: "flex-col items-center") { info } : "".html_safe)
)
label_and_hint = @template.tag.div(class: "flex-col items-center") do
(info + hint).html_safe
end
checkbox + label_and_hint
end
end

Expand Down
88 changes: 63 additions & 25 deletions app/jobs/zipper_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@
class ZipperJob < ApplicationJob
queue_as :default

def perform(track_id: nil, playlist_id: nil)
if track_id
def perform(track_id: nil, playlist_id: nil, purchase_id: nil)
if purchase_id
purchase = Purchase.find(purchase_id)
resource = purchase.purchasable
if resource.is_a?(Track)
track_zip(resource)
elsif resource.is_a?(Playlist)
playlist_zip(resource)
end
elsif track_id
track = Track.find_by(id: track_id)
return unless track
track_zip(track)
Expand Down Expand Up @@ -52,32 +60,62 @@ def track_zip(record)
Rails.logger.error "Error zipping track #{record.id}: #{e.message}"
end

def playlist_zip(playlist)
zipfile_path = Rails.root.join("tmp", "#{playlist.slug}-#{playlist.id}.zip")

Zip::File.open(zipfile_path, Zip::File::CREATE) do |zipfile|
playlist.tracks.each do |track|
next unless track.audio.attached?

audio_path = Rails.root.join("tmp", track.slug)
track.audio.download do |chunk|
File.open(audio_path, "ab") { |file| file.write(chunk) }
def playlist_zip(playlist)
zip_file = Tempfile.new(["#{playlist.slug}-#{playlist.id}", '.zip'])

begin
Zip::File.open(zip_file.path, Zip::File::CREATE) do |zipfile|
playlist.tracks.each do |track|
next unless track.audio.attached?

begin
track.audio.open do |file|
# Use the original filename from the blob
filename = track.audio.filename.to_s
# Add the file directly to the zip without creating a separate temp file
zipfile.get_output_stream(filename) do |os|
IO.copy_stream(file, os)
end
end
rescue StandardError => e
Rails.logger.error("Error processing track #{track.id}: #{e.message}")
end
end

zipfile.add(track.audio.filename.to_s, audio_path)
File.delete(audio_path) # Clean up the downloaded audio file
end

# Attach the zipped file to the playlist
playlist.zip.attach(
io: File.open(zip_file.path),
filename: "#{playlist.slug}.zip",
content_type: 'application/zip'
)

# # Broadcast the update (commented out as requested)
# Turbo::StreamsChannel.broadcast_replace_to(
# "playlist_#{playlist.id}",
# target: "playlist_#{playlist.id}_download",
# partial: 'playlists/download_ready',
# locals: { playlist: playlist }
# )

true # Return true if successful
rescue StandardError => e
Rails.logger.error("Failed to create zip for playlist #{playlist.id}: #{e.message}")

# # Broadcast error message (commented out as requested)
# Turbo::StreamsChannel.broadcast_replace_to(
# "playlist_#{playlist.id}",
# target: "playlist_#{playlist.id}_download",
# partial: 'playlists/download_error',
# locals: { playlist: playlist, error: e.message }
# )

false # Return false if failed
ensure
zip_file.close
zip_file.unlink
end

# Here you can attach the zipped file to the playlist or whatever you want
# e.g.
playlist.zip.attach(
io: File.open(zipfile_path),
filename: "#{playlist.slug}.zip"
)
# or store it somewhere else or let the user download it directly.

# Clean up the generated zip file if you're not attaching it
File.delete(zipfile_path)
end

end
4 changes: 4 additions & 0 deletions app/models/playlist.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ def check_label
store_accessor :metadata, :price, :decimal
store_accessor :metadata, :name_your_price, :boolean

def name_your_price?
name_your_price.present?
end

def cover_url(size = nil)
url = case size
when :medium
Expand Down
25 changes: 20 additions & 5 deletions app/models/purchased_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,27 @@ class PurchasedItem < ApplicationRecord

def qr
url = Rails.application.routes.url_helpers.event_event_ticket_url(purchase.purchasable, signed_id)
encoded_url = ERB::Util.url_encode(url)
size = 120
data_param = "chl=#{encoded_url}"
google_charts_url = "https://chart.googleapis.com/chart?cht=qr&chs=#{size}x#{size}&#{data_param}"
qrcode = RQRCode::QRCode.new(url)

# Generate PNG data
png = qrcode.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
)

# Convert to base64 for embedding in HTML
base64_image = Base64.strict_encode64(png.to_s)
"data:image/png;base64,#{base64_image}"
end

def toggle_check_in!
if checked_in?
update({checked_in: false, checked_in_at: nil})
Expand Down
4 changes: 4 additions & 0 deletions app/models/track.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ def peaks=(peaks)
end
end

def presicion_for_currency
0
end

def cover_url(size = nil)
url = case size
when :medium
Expand Down
Loading

0 comments on commit b52e8c0

Please sign in to comment.