class Contributions::DonationsController < ApplicationController include BtcpayHelper before_action :authenticate_user! before_action :set_donation_methods, only: [:index, :create] before_action :require_donation_method_enabled, only: [:create] before_action :validate_donation_params, only: [:create] before_action :set_donation, only: [:confirm_btcpay] # GET /contributions/donations def index @current_section = :contributions @donations_completed = current_user.donations.completed.order('paid_at desc') @donations_processing = current_user.donations.processing.order('created_at desc') if Setting.lndhub_enabled? begin lndhub_authenticate lndhub_fetch_balance rescue @balance = 0 end end end # POST /contributions/donations def create if params[:currency] == "sats" fiat_amount = nil fiat_currency = nil amount_sats = params[:amount] else fiat_amount = params[:amount].to_i fiat_currency = params[:currency] amount_sats = nil end @donation = current_user.donations.create!( donation_method: params[:donation_method], payment_method: nil, paid_at: nil, amount_sats: amount_sats, fiat_amount: (fiat_amount.nil? ? nil : fiat_amount * 100), # store in cents fiat_currency: fiat_currency, public_name: params[:public_name] ) case params[:donation_method] when "btcpay" res = BtcpayManager::CreateInvoice.call( amount: fiat_amount || (amount_sats.to_f / 100000000), currency: fiat_currency || "BTC", redirect_url: confirm_btcpay_contributions_donation_url(@donation) ) @donation.update! btcpay_invoice_id: res["id"] redirect_to btcpay_checkout_url(res["id"]), allow_other_host: true else redirect_to contributions_donations_url, flash: { error: "Donation method currently not available" } end end def confirm_btcpay redirect_to contributions_donations_url and return if @donation.completed? invoice = BtcpayManager::FetchInvoice.call(invoice_id: @donation.btcpay_invoice_id) if @donation.amount_sats.present? # TODO make default fiat currency configurable and/or determine from user's # i18n browser settings @donation.fiat_currency = "EUR" exchange_rate = BtcpayManager::FetchExchangeRate.call(fiat_currency: @donation.fiat_currency) @donation.fiat_amount = (((@donation.amount_sats.to_f / 100000000) * exchange_rate) * 100).to_i else amt_str = invoice["paymentMethods"].first["amount"] @donation.amount_sats = amt_str.tr(".","").sub(/0*$/, "").to_i end case invoice["status"] when "Settled" @donation.complete! flash_message = { success: "Thank you!" } when "Processing" unless @donation.processing? @donation.start_processing! flash_message = { success: "Thank you! We will send you an email when the payment is confirmed." } BtcpayCheckDonationJob.set(wait: 20.seconds).perform_later(@donation) end when "Expired" flash_message = { warning: "The payment request for this donation has expired" } else flash_message = { warning: "Could not determine status of payment" } end redirect_to contributions_donations_url, flash: flash_message end private def set_donation @donation = current_user.donations.find_by(id: params[:id]) http_status :not_found unless @donation.present? end def set_donation_methods @donation_methods = [] @donation_methods.push :btcpay if Setting.btcpay_enabled? @donation_methods.push :lndhub if Setting.lndhub_enabled? @donation_methods.push :opencollective if Setting.opencollective_enabled? end def require_donation_method_enabled http_status :forbidden unless @donation_methods.include?( params[:donation_method].to_sym ) end def validate_donation_params if !%w[EUR USD sats].include?(params[:currency]) || (params[:amount].to_i <= 0) http_status :unprocessable_entity end end end