diff --git a/.env.example b/.env.example
index aa77727..b7244d8 100644
--- a/.env.example
+++ b/.env.example
@@ -34,6 +34,8 @@ EJABBERD_ADMIN_URL='https://xmpp.kosmos.org/admin'
EJABBERD_API_URL='https://xmpp.kosmos.org/api'
BTCPAY_API_URL='http://localhost:23001/api/v1'
+BTCPAY_STORE_ID=''
+BTCPAY_AUTH_TOKEN=''
LNDHUB_API_URL='http://localhost:3023'
LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org'
diff --git a/.env.test b/.env.test
index 33761c3..c032b0e 100644
--- a/.env.test
+++ b/.env.test
@@ -2,13 +2,14 @@ PRIMARY_DOMAIN=kosmos.org
REDIS_URL='redis://localhost:6379/0'
+BTCPAY_API_URL='http://btcpay.example.com/api/v1'
+BTCPAY_STORE_ID='123456'
+
DISCOURSE_PUBLIC_URL='http://discourse.example.com'
DISCOURSE_CONNECT_SECRET='discourse_connect_ftw'
EJABBERD_API_URL='http://xmpp.example.com/api'
-BTCPAY_API_URL='http://btcpay.example.com/api/v1'
-
LNDHUB_API_URL='http://localhost:3026'
LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org'
LNDHUB_PUBLIC_KEY='024cd3be18617f39cf645851e3ba63f51fc13f0bb09e3bb25e6fd4de556486d946'
diff --git a/app/components/form_elements/fieldset_resettable_setting_component.rb b/app/components/form_elements/fieldset_resettable_setting_component.rb
index 18a4609..bfaa1a0 100644
--- a/app/components/form_elements/fieldset_resettable_setting_component.rb
+++ b/app/components/form_elements/fieldset_resettable_setting_component.rb
@@ -6,7 +6,7 @@ module FormElements
@tag = tag
@positioning = :vertical
@title = title
- @descripton = description
+ @description = description
@key = key.to_sym
@type = type
@resettable = is_resettable?(@key)
diff --git a/app/components/sidenav_link_component.html.erb b/app/components/sidenav_link_component.html.erb
index a49bbab..a229606 100644
--- a/app/components/sidenav_link_component.html.erb
+++ b/app/components/sidenav_link_component.html.erb
@@ -1,4 +1,8 @@
<%= link_to @path, class: @link_class, title: (@disabled ? "Coming soon" : nil) do %>
+ <% if @icon.present? %>
<%= render partial: "icons/#{@icon}", locals: { custom_class: @icon_class } %>
+ <% elsif @text_icon.present? %>
+ <%= @text_icon %>
+ <% end %>
<%= @name %>
<% end %>
diff --git a/app/components/sidenav_link_component.rb b/app/components/sidenav_link_component.rb
index 60e58ed..9436a67 100644
--- a/app/components/sidenav_link_component.rb
+++ b/app/components/sidenav_link_component.rb
@@ -1,11 +1,13 @@
# frozen_string_literal: true
class SidenavLinkComponent < ViewComponent::Base
- def initialize(name:, level: 1, path:, icon:, active: false, disabled: false)
+ def initialize(name:, level: 1, path:, icon: nil, text_icon: nil,
+ active: false, disabled: false)
@name = name
@level = level
@path = path
@icon = icon
+ @text_icon = text_icon
@active = active
@disabled = disabled
@link_class = class_names_link(path)
diff --git a/app/controllers/admin/settings/services_controller.rb b/app/controllers/admin/settings/services_controller.rb
index 54384c6..a228f5e 100644
--- a/app/controllers/admin/settings/services_controller.rb
+++ b/app/controllers/admin/settings/services_controller.rb
@@ -3,7 +3,7 @@ class Admin::Settings::ServicesController < Admin::SettingsController
@service = params[:s]
if @service.blank?
- redirect_to admin_settings_services_path(params: { s: "discourse" })
+ redirect_to admin_settings_services_path(params: { s: "btcpay" })
end
end
diff --git a/app/controllers/api/btcpay_controller.rb b/app/controllers/api/btcpay_controller.rb
new file mode 100644
index 0000000..d973af2
--- /dev/null
+++ b/app/controllers/api/btcpay_controller.rb
@@ -0,0 +1,29 @@
+class Api::BtcpayController < Api::BaseController
+ before_action :require_feature_enabled
+
+ def onchain_btc_balance
+ balance = BtcpayManager::FetchOnchainWalletBalance.call
+ render json: balance
+ rescue => error
+ Rails.logger.warn "Failed to fetch BTC wallet balance: #{error.message}"
+ render json: { error: 'Failed to fetch wallet balance' },
+ status: 500
+ end
+
+ def lightning_btc_balance
+ balance = BtcpayManager::FetchLightningWalletBalance.call
+ render json: balance
+ rescue => error
+ Rails.logger.warn "Failed to fetch BTC lightning balance: #{error.message}"
+ render json: { error: 'Failed to fetch wallet balance' },
+ status: 500
+ end
+
+ private
+
+ def require_feature_enabled
+ unless Setting.btcpay_publish_wallet_balances
+ http_status :not_found and return
+ end
+ end
+end
diff --git a/app/controllers/api/kredits_controller.rb b/app/controllers/api/kredits_controller.rb
deleted file mode 100644
index e54993d..0000000
--- a/app/controllers/api/kredits_controller.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class Api::KreditsController < Api::BaseController
-
- def onchain_btc_balance
- btcpay = BtcPay.new
- balance = btcpay.onchain_wallet_balance
- render json: balance
- rescue => error
- Rails.logger.warn "Failed to fetch kredits BTC wallet balance: #{error.message}"
- render json: { error: 'Failed to fetch wallet balance' },
- status: 500
- end
-
-end
diff --git a/app/models/setting.rb b/app/models/setting.rb
index 0a13905..9cafa2e 100644
--- a/app/models/setting.rb
+++ b/app/models/setting.rb
@@ -36,7 +36,25 @@ class Setting < RailsSettings::Base
#
field :sentry_enabled, type: :boolean, readonly: true,
- default: (ENV["SENTRY_DSN"].present?.to_s || false)
+ default: ENV["SENTRY_DSN"].present?
+
+ #
+ # BTCPay Server
+ #
+
+ field :btcpay_api_url, type: :string,
+ default: ENV["BTCPAY_API_URL"].presence
+
+ field :btcpay_enabled, type: :boolean,
+ default: ENV["BTCPAY_API_URL"].present?
+
+ field :btcpay_store_id, type: :string,
+ default: ENV["BTCPAY_STORE_ID"].presence
+
+ field :btcpay_auth_token, type: :string,
+ default: ENV["BTCPAY_AUTH_TOKEN"].presence
+
+ field :btcpay_publish_wallet_balances, type: :boolean, default: true
#
# Discourse
@@ -46,7 +64,7 @@ class Setting < RailsSettings::Base
default: ENV["DISCOURSE_PUBLIC_URL"].presence
field :discourse_enabled, type: :boolean,
- default: (ENV["DISCOURSE_PUBLIC_URL"].present?.to_s || false)
+ default: ENV["DISCOURSE_PUBLIC_URL"].present?
field :discourse_connect_secret, type: :string,
default: ENV["DISCOURSE_CONNECT_SECRET"].presence
@@ -59,14 +77,14 @@ class Setting < RailsSettings::Base
default: ENV["DRONECI_PUBLIC_URL"].presence
field :droneci_enabled, type: :boolean,
- default: (ENV["DRONECI_PUBLIC_URL"].present?.to_s || false)
+ default: ENV["DRONECI_PUBLIC_URL"].present?
#
# ejabberd
#
field :ejabberd_enabled, type: :boolean,
- default: (ENV["EJABBERD_API_URL"].present?.to_s || false)
+ default: ENV["EJABBERD_API_URL"].present?
field :ejabberd_api_url, type: :string,
default: ENV["EJABBERD_API_URL"].presence
@@ -85,7 +103,7 @@ class Setting < RailsSettings::Base
default: ENV["GITEA_PUBLIC_URL"].presence
field :gitea_enabled, type: :boolean,
- default: (ENV["GITEA_PUBLIC_URL"].present?.to_s || false)
+ default: ENV["GITEA_PUBLIC_URL"].present?
#
# Lightning Network
@@ -95,16 +113,19 @@ class Setting < RailsSettings::Base
default: ENV["LNDHUB_API_URL"].presence
field :lndhub_enabled, type: :boolean,
- default: (ENV["LNDHUB_API_URL"].present?.to_s || false)
+ default: ENV["LNDHUB_API_URL"].present?
+
+ field :lndhub_admin_token, type: :string,
+ default: ENV["LNDHUB_ADMIN_TOKEN"].presence
field :lndhub_admin_enabled, type: :boolean,
- default: (ENV["LNDHUB_ADMIN_UI"] || false)
+ default: ENV["LNDHUB_ADMIN_UI"] || false
field :lndhub_public_key, type: :string,
default: (ENV["LNDHUB_PUBLIC_KEY"] || "")
field :lndhub_keysend_enabled, type: :boolean,
- default: -> { self.lndhub_public_key.present?.to_s || false }
+ default: -> { self.lndhub_public_key.present? }
#
# Mastodon
@@ -114,7 +135,7 @@ class Setting < RailsSettings::Base
default: ENV["MASTODON_PUBLIC_URL"].presence
field :mastodon_enabled, type: :boolean,
- default: (ENV["MASTODON_PUBLIC_URL"].present?.to_s || false)
+ default: ENV["MASTODON_PUBLIC_URL"].present?
field :mastodon_address_domain, type: :string,
default: ENV["MASTODON_ADDRESS_DOMAIN"].presence || self.primary_domain
@@ -127,7 +148,7 @@ class Setting < RailsSettings::Base
default: ENV["MEDIAWIKI_PUBLIC_URL"].presence
field :mediawiki_enabled, type: :boolean,
- default: (ENV["MEDIAWIKI_PUBLIC_URL"].present?.to_s || false)
+ default: ENV["MEDIAWIKI_PUBLIC_URL"].present?
#
# Nostr
@@ -140,7 +161,7 @@ class Setting < RailsSettings::Base
#
field :remotestorage_enabled, type: :boolean,
- default: (ENV["RS_STORAGE_URL"].present?.to_s || false)
+ default: ENV["RS_STORAGE_URL"].present?
field :rs_storage_url, type: :string,
default: ENV["RS_STORAGE_URL"].presence
diff --git a/app/services/btc_pay.rb b/app/services/btc_pay.rb
deleted file mode 100644
index becd506..0000000
--- a/app/services/btc_pay.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# API Docs: https://docs.btcpayserver.org/API/Greenfield/v1/
-#
-class BtcPay
- def initialize
- @base_url = ENV["BTCPAY_API_URL"]
- @store_id = Rails.application.credentials.btcpay[:store_id]
- @auth_token = Rails.application.credentials.btcpay[:auth_token]
- end
-
- def onchain_wallet_balance
- res = get "stores/#{@store_id}/payment-methods/onchain/BTC/wallet"
-
- {
- balance: res["balance"].to_f,
- unconfirmed_balance: res["unconfirmedBalance"].to_f,
- confirmed_balance: res["confirmedBalance"].to_f
- }
- end
-
- private
-
- def get(endpoint)
- res = Faraday.get("#{@base_url}/#{endpoint}", {}, {
- "Content-Type" => "application/json",
- "Accept" => "application/json",
- "Authorization" => "token #{@auth_token}"
- })
-
- JSON.parse(res.body)
- end
-end
diff --git a/app/services/btcpay_manager/fetch_lightning_wallet_balance.rb b/app/services/btcpay_manager/fetch_lightning_wallet_balance.rb
new file mode 100644
index 0000000..533d2f1
--- /dev/null
+++ b/app/services/btcpay_manager/fetch_lightning_wallet_balance.rb
@@ -0,0 +1,11 @@
+module BtcpayManager
+ class FetchLightningWalletBalance < BtcpayManagerService
+ def call
+ res = get "stores/#{store_id}/lightning/BTC/balance"
+
+ {
+ balance: res["offchain"]["local"].to_i / 1000 # msats to sats
+ }
+ end
+ end
+end
diff --git a/app/services/btcpay_manager/fetch_onchain_wallet_balance.rb b/app/services/btcpay_manager/fetch_onchain_wallet_balance.rb
new file mode 100644
index 0000000..e28f197
--- /dev/null
+++ b/app/services/btcpay_manager/fetch_onchain_wallet_balance.rb
@@ -0,0 +1,13 @@
+module BtcpayManager
+ class FetchOnchainWalletBalance < BtcpayManagerService
+ def call
+ res = get "stores/#{store_id}/payment-methods/onchain/BTC/wallet"
+
+ {
+ balance: (res["balance"].to_f * 100000000).to_i, # BTC to sats
+ unconfirmed_balance: (res["unconfirmedBalance"].to_f * 100000000).to_i,
+ confirmed_balance: (res["confirmedBalance"].to_f * 100000000).to_i
+ }
+ end
+ end
+end
diff --git a/app/services/btcpay_manager_service.rb b/app/services/btcpay_manager_service.rb
new file mode 100644
index 0000000..d8fbf09
--- /dev/null
+++ b/app/services/btcpay_manager_service.rb
@@ -0,0 +1,24 @@
+#
+# API Docs: https://docs.btcpayserver.org/API/Greenfield/v1/
+#
+class BtcpayManagerService < ApplicationService
+ attr_reader :base_url, :store_id, :auth_token
+
+ def initialize
+ @base_url = Setting.btcpay_api_url
+ @store_id = Setting.btcpay_store_id
+ @auth_token = Setting.btcpay_auth_token
+ end
+
+ private
+
+ def get(endpoint)
+ res = Faraday.get("#{base_url}/#{endpoint}", {}, {
+ "Content-Type" => "application/json",
+ "Accept" => "application/json",
+ "Authorization" => "token #{auth_token}"
+ })
+
+ JSON.parse(res.body)
+ end
+end
diff --git a/app/services/lndhub_v2.rb b/app/services/lndhub_v2.rb
index e0a84dd..b816fcb 100644
--- a/app/services/lndhub_v2.rb
+++ b/app/services/lndhub_v2.rb
@@ -14,7 +14,7 @@ class LndhubV2 < Lndhub
end
def create_account(payload={})
- post "v2/users", payload, admin_token: Rails.application.credentials.lndhub[:admin_token]
+ post "v2/users", payload, admin_token: Setting.lndhub_admin_token
end
def create_invoice(payload)
diff --git a/app/views/admin/settings/services/_btcpay.html.erb b/app/views/admin/settings/services/_btcpay.html.erb
new file mode 100644
index 0000000..9565826
--- /dev/null
+++ b/app/views/admin/settings/services/_btcpay.html.erb
@@ -0,0 +1,37 @@
+
BTCPay Server
+
+ <%= render FormElements::FieldsetToggleComponent.new(
+ form: f,
+ attribute: :btcpay_enabled,
+ enabled: Setting.btcpay_enabled?,
+ title: "Enable BTCPay integration",
+ description: "BTCPay configuration present and features enabled"
+ ) %>
+<% if Setting.btcpay_enabled? %>
+ <%= render FormElements::FieldsetResettableSettingComponent.new(
+ key: :btcpay_api_url,
+ title: "API URL"
+ ) %>
+ <%= render FormElements::FieldsetResettableSettingComponent.new(
+ key: :btcpay_store_id,
+ title: "Store ID"
+ ) %>
+ <%= render FormElements::FieldsetResettableSettingComponent.new(
+ key: :btcpay_auth_token,
+ type: :password,
+ title: "Auth Token"
+ ) %>
+
+
+
+REST API
+
+ <%= render FormElements::FieldsetToggleComponent.new(
+ form: f,
+ attribute: :btcpay_publish_wallet_balances,
+ enabled: Setting.btcpay_publish_wallet_balances?,
+ title: "Publish wallet balances",
+ description: "Publish the store's on-chain and Lightning wallet balances"
+ ) %>
+<% end %>
+
diff --git a/app/views/admin/settings/services/_lndhub.html.erb b/app/views/admin/settings/services/_lndhub.html.erb
index a68ad37..ac679c4 100644
--- a/app/views/admin/settings/services/_lndhub.html.erb
+++ b/app/views/admin/settings/services/_lndhub.html.erb
@@ -9,29 +9,35 @@
) %>
<% if Setting.lndhub_enabled? %>
<%= render FormElements::FieldsetResettableSettingComponent.new(
- key: :lndhub_api_url,
- title: "API URL"
- ) %>
- <% end %>
- <%= render FormElements::FieldsetToggleComponent.new(
- form: f,
- attribute: :lndhub_admin_enabled,
- enabled: Setting.lndhub_admin_enabled?,
- title: "Enable LNDHub admin panel",
- description: "LNDHub database configuration present and admin panel enabled"
- ) %>
- <%= render FormElements::FieldsetToggleComponent.new(
- form: f,
- attribute: :lndhub_keysend_enabled,
- enabled: Setting.lndhub_keysend_enabled?,
- title: "Enable keysend payments",
- description: "Allow users to receive invoice-less payments to their Lightning Address"
- ) %>
- <% if Setting.lndhub_keysend_enabled? %>
+ key: :lndhub_api_url,
+ title: "API URL"
+ ) %>
<%= render FormElements::FieldsetResettableSettingComponent.new(
- key: :lndhub_public_key,
- title: "Public key",
- description: "The public key of the Lightning node used by LNDHub"
- ) %>
+ key: :lndhub_admin_token,
+ type: :password,
+ title: "Admin token",
+ description: "Auth token for creating new lndhub accounts"
+ ) %>
+ <%= render FormElements::FieldsetToggleComponent.new(
+ form: f,
+ attribute: :lndhub_admin_enabled,
+ enabled: Setting.lndhub_admin_enabled?,
+ title: "Enable LNDHub admin panel",
+ description: "LNDHub database configuration present and admin panel enabled"
+ ) %>
+ <%= render FormElements::FieldsetToggleComponent.new(
+ form: f,
+ attribute: :lndhub_keysend_enabled,
+ enabled: Setting.lndhub_keysend_enabled?,
+ title: "Enable keysend payments",
+ description: "Allow users to receive invoice-less payments to their Lightning Address"
+ ) %>
+ <% if Setting.lndhub_keysend_enabled? %>
+ <%= render FormElements::FieldsetResettableSettingComponent.new(
+ key: :lndhub_public_key,
+ title: "Public key",
+ description: "The public key of the Lightning node used by LNDHub"
+ ) %>
+ <% end %>
<% end %>
diff --git a/app/views/shared/_admin_sidenav_settings_services.html.erb b/app/views/shared/_admin_sidenav_settings_services.html.erb
index 973777f..8650277 100644
--- a/app/views/shared/_admin_sidenav_settings_services.html.erb
+++ b/app/views/shared/_admin_sidenav_settings_services.html.erb
@@ -1,63 +1,70 @@
+<%= render SidenavLinkComponent.new(
+ level: 2,
+ name: "BTCPay",
+ path: admin_settings_services_path(params: { s: "btcpay" }),
+ text_icon: Setting.btcpay_enabled? ? "◉" : "○",
+ active: current_page?(admin_settings_services_path(params: { s: "btcpay" })),
+) %>
<%= render SidenavLinkComponent.new(
level: 2,
name: "Discourse",
path: admin_settings_services_path(params: { s: "discourse" }),
- icon: Setting.discourse_enabled? ? "check" : "x",
+ text_icon: Setting.discourse_enabled? ? "◉" : "○",
active: current_page?(admin_settings_services_path(params: { s: "discourse" })),
) %>
<%= render SidenavLinkComponent.new(
level: 2,
name: "Drone CI",
path: admin_settings_services_path(params: { s: "droneci" }),
- icon: Setting.droneci_enabled? ? "check" : "x",
+ text_icon: Setting.droneci_enabled? ? "◉" : "○",
active: current_page?(admin_settings_services_path(params: { s: "droneci" })),
) %>
<%= render SidenavLinkComponent.new(
level: 2,
name: "ejabberd",
path: admin_settings_services_path(params: { s: "ejabberd" }),
- icon: Setting.ejabberd_enabled? ? "check" : "x",
+ text_icon: Setting.ejabberd_enabled? ? "◉" : "○",
active: current_page?(admin_settings_services_path(params: { s: "ejabberd" })),
) %>
<%= render SidenavLinkComponent.new(
level: 2,
name: "Gitea",
path: admin_settings_services_path(params: { s: "gitea" }),
- icon: Setting.gitea_enabled? ? "check" : "x",
+ text_icon: Setting.gitea_enabled? ? "◉" : "○",
active: current_page?(admin_settings_services_path(params: { s: "gitea" })),
) %>
<%= render SidenavLinkComponent.new(
level: 2,
name: "LNDHub",
path: admin_settings_services_path(params: { s: "lndhub" }),
- icon: Setting.lndhub_enabled? ? "check" : "x",
+ text_icon: Setting.lndhub_enabled? ? "◉" : "○",
active: current_page?(admin_settings_services_path(params: { s: "lndhub" })),
) %>
<%= render SidenavLinkComponent.new(
level: 2,
name: "Mastodon",
path: admin_settings_services_path(params: { s: "mastodon" }),
- icon: Setting.mastodon_enabled? ? "check" : "x",
+ text_icon: Setting.mastodon_enabled? ? "◉" : "○",
active: current_page?(admin_settings_services_path(params: { s: "mastodon" })),
) %>
<%= render SidenavLinkComponent.new(
level: 2,
name: "MediaWiki",
path: admin_settings_services_path(params: { s: "mediawiki" }),
- icon: Setting.mediawiki_enabled? ? "check" : "x",
+ text_icon: Setting.mediawiki_enabled? ? "◉" : "○",
active: current_page?(admin_settings_services_path(params: { s: "mediawiki" })),
) %>
<%= render SidenavLinkComponent.new(
level: 2,
name: "Nostr",
path: admin_settings_services_path(params: { s: "nostr" }),
- icon: Setting.nostr_enabled? ? "check" : "x",
+ text_icon: Setting.nostr_enabled? ? "◉" : "○",
active: current_page?(admin_settings_services_path(params: { s: "nostr" })),
) %>
<%= render SidenavLinkComponent.new(
level: 2,
name: "RemoteStorage",
path: admin_settings_services_path(params: { s: "remotestorage" }),
- icon: Setting.remotestorage_enabled? ? "check" : "x",
+ text_icon: Setting.remotestorage_enabled? ? "◉" : "○",
active: current_page?(admin_settings_services_path(params: { s: "remotestorage" })),
) %>
diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc
index 978af61..de77871 100644
--- a/config/credentials.yml.enc
+++ b/config/credentials.yml.enc
@@ -1 +1 @@
-yEs5CyuAbqphlDWgtw/YQvkPn+EN4ecen2dAjs7zvYErkRRWp99FinGlQIMe6NRkMLLLSIj2BwR/wlscn1kLpIfwGpxfSZ89srK3do6Mb5QogpxdUsnQB8qv5PTGRQFBcjM47s1Q5m0t+OKxGvOnLyKnQp+cVS2KFJMbSzQarW8wIZSz2gKArn9Ttk0kqUHMlJWNY7Yh6xIrrxlEalaTOVzPdtnF7u8Tobminu15eeWHMormMRz4dYSaDc6hUtfpdy1NzOHaeXIU9A9RY/iytxuIQNgcMAlcWbPe//rVk/unH2F8xqSOfed4h/nC08F/qq4z8va3kEXBSdW/G91aIDMu1mo0kX3YNibq8s25C/CfGpzw39ozJ9erTBH7hy6nfmxU6qZuWcTGDj3NOfKe/XIfDcpOjsqkT2IOFARrYodb67q23IuOufraK1/FD4LXu8l0S8/Oi0cqMjtPPs7tS0M1C3DrbmlEzGKETrHpmoKHqjA0rgOmK4ZZM9LeI+l8Z+fDpYcCak9fLGGxnjf+nKiYMSUtm9+1dwycG2lpBV6fbmIKHJWngO2jVGcycODkc525oUaAO4hdPMqrz1AdU3AzYmLJTxW3aZ4uL5NyEJ7TbUBC0HT7h2gEi/tUry4cfD2EsM9bCrCUNuMBrnPqd4r8AvORoqqYIw1IEsP0RgWa2+hfeG1QCjBRPFHQOcqo+W25CelivMe79qI08w0iC8S4hfOQO4QrmMgtd1BhcR+wVpVE3X9EJZi3Hl7z14hXcSic+gkswJMtVZcnJL4rmZ0iEW1mpqUuegsX5vB/4qPxiQyeB80pg8Q33shvUbixzSBkl6znmLSiIffsiDsGOsnuzfl/MUT+JBs3UswNt4tSp7nEwhUjKFHrZHrAJiGCdtIS6yDPGe3HfQv1JkQ+9A8zv88hRmzeIx2JyT/shtIqGo+4ZTJd5cma--Lij/n0+cpstyZD28--FOUhwW3y+0jdaYkKvG2xrg==
\ No newline at end of file
+tmI5vm7qZhaigr52jEBVWkRdj+EE+9OmPh3vWXC7kA/OHuuucpr7SodychuMkQDPLM0BLk88LFsqvRIR+mqnLWpRC+P9aeUFE6ohxSWzcAd7Y4sgxUD8zpCRPndrwTw0hxXXj1WZSYeWn4BoAB34aV+gYen2MajZF3a95hJGtS5yjgWxvLVkQQKqRDfykkfX6fCS0BPo5X7sT7m4xwCATD/D4219wajm5W3TIdkriHtwt28ZLspaRWA5e0UkzKf8+/Gaj2CrW7UWcvew8R93zQ5RA2/Sp3sDTVN+kLz9I9Q095lQC0ywCAEFYHeKmc2tjrzqRaAAWu06xmWLqGIg21G+A/UU9lUJOkIpxQACWoOfS2IoXR1nXhgXMopkz3aCBXDxKw554v4H2QyOceOsuRf2C685ibMqzQkKMmJ4tcbiOJL77DUc08JTjB8Dq4Ohr8sMzXbV/hATevjYoRP0XarLekqhLv90ZLuIVY16DwB0CzACeNBKeKbeLqJF51upRRWgi+gTbYpV04yUwnXdyssF8mydWocgihrTryBi8F6PsuhBGcaYdP+0yibnGxDCC4x2rupbBfMj2OIX7pYzgtIHB3Eo954Y+bCoggqbE/Qrb9VVXNMgtKgLt8EGWU2tg6wl9QicitIq87uLDAade93zTn6rmcKPywjMDo6jbVIs653ZdUhiKdHGdpnJccbgQ/iLSPB1umNnCeaEX5jM+K9zBvl7ZMCdSk1YIQ==--ekKumqLiSlVJNwMe--K/ecXmmMT1x+WnIXMbHBDw==
\ No newline at end of file
diff --git a/config/routes.rb b/config/routes.rb
index 3dc922a..e7fef10 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -54,7 +54,8 @@ Rails.application.routes.draw do
post 'webhooks/lndhub', to: 'webhooks#lndhub'
namespace :api do
- get 'kredits/onchain_btc_balance', to: 'kredits#onchain_btc_balance'
+ get 'btcpay/onchain_btc_balance', to: 'btcpay#onchain_btc_balance'
+ get 'btcpay/lightning_btc_balance', to: 'btcpay#lightning_btc_balance'
end
namespace :admin do
diff --git a/spec/features/admin/settings_spec.rb b/spec/features/admin/settings_spec.rb
index 757f991..01a43f4 100644
--- a/spec/features/admin/settings_spec.rb
+++ b/spec/features/admin/settings_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe 'Admin/global settings', type: :feature do
scenario "Opening service settings shows page for first service" do
visit admin_settings_services_path
- expect(current_url).to eq(admin_settings_services_url(params: { s: "discourse" }))
+ expect(current_url).to eq(admin_settings_services_url(params: { s: "btcpay" }))
end
scenario "View service settings" do
diff --git a/spec/requests/api/btcpay_spec.rb b/spec/requests/api/btcpay_spec.rb
new file mode 100644
index 0000000..9dc5728
--- /dev/null
+++ b/spec/requests/api/btcpay_spec.rb
@@ -0,0 +1,103 @@
+require 'rails_helper'
+require 'webmock/rspec'
+
+RSpec.describe "/api/btcpay", type: :request do
+
+ describe "GET /onchain_btc_balance" do
+ before do
+ stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/payment-methods/onchain/BTC/wallet")
+ .to_return(status: 200, headers: {}, body: {
+ balance: 0.91108606,
+ unconfirmedBalance: 0,
+ confirmedBalance: 0.91108606
+ }.to_json)
+ end
+
+ it "returns a formatted result for the onchain wallet balance" do
+ get api_btcpay_onchain_btc_balance_path
+
+ expect(response).to have_http_status(:ok)
+
+ res = JSON.parse(response.body)
+ expect(res["balance"]).to eq(91108606)
+ expect(res["unconfirmed_balance"]).to eq(0)
+ expect(res["confirmed_balance"]).to eq(91108606)
+ end
+
+ context "upstream request error" do
+ before do
+ stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/payment-methods/onchain/BTC/wallet")
+ .to_return(status: 500, headers: {}, body: "")
+ end
+
+ it "returns a formatted error" do
+ get api_btcpay_onchain_btc_balance_path
+
+ expect(response).to have_http_status(:server_error)
+
+ res = JSON.parse(response.body)
+ expect(res["error"]).not_to be_nil
+ end
+ end
+
+ context "feature disabled" do
+ before do
+ Setting.btcpay_publish_wallet_balances = false
+ end
+
+ it "returns a 404 status" do
+ get api_btcpay_onchain_btc_balance_path
+
+ expect(response).to have_http_status(:not_found)
+ end
+ end
+ end
+
+ describe "GET /lightning_btc_balance" do
+ before do
+ stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/lightning/BTC/balance")
+ .to_return(status: 200, headers: {}, body: {
+ offchain: {
+ local: 4200000000
+ },
+ }.to_json)
+ end
+
+ it "returns a formatted result for the onchain wallet balance" do
+ get api_btcpay_lightning_btc_balance_path
+
+ expect(response).to have_http_status(:ok)
+
+ res = JSON.parse(response.body)
+ expect(res["balance"]).to eq(4200000)
+ end
+
+ context "upstream request error" do
+ before do
+ stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/lightning/BTC/balance")
+ .to_return(status: 500, headers: {}, body: "")
+ end
+
+ it "returns a formatted error" do
+ get api_btcpay_lightning_btc_balance_path
+
+ expect(response).to have_http_status(:server_error)
+
+ res = JSON.parse(response.body)
+ expect(res["error"]).not_to be_nil
+ end
+ end
+
+ context "feature disabled" do
+ before do
+ Setting.btcpay_publish_wallet_balances = false
+ end
+
+ it "returns a 404 status" do
+ get api_btcpay_lightning_btc_balance_path
+
+ expect(response).to have_http_status(:not_found)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/kredits_spec.rb b/spec/requests/api/kredits_spec.rb
deleted file mode 100644
index 0e1e464..0000000
--- a/spec/requests/api/kredits_spec.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-require 'rails_helper'
-require 'webmock/rspec'
-
-RSpec.describe "/api/kredits", type: :request do
-
- describe "GET /onchain_btc_balance" do
- before do
- stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/payment-methods/onchain/BTC/wallet")
- .to_return(status: 200, headers: {}, body: {
- balance: 0.91108606,
- unconfirmedBalance: 0,
- confirmedBalance: 0.91108606
- }.to_json)
- end
-
- it "returns a formatted result for the onchain wallet balance" do
- get api_kredits_onchain_btc_balance_path
-
- expect(response).to have_http_status(:ok)
-
- res = JSON.parse(response.body)
- expect(res["balance"]).to eq(0.91108606)
- expect(res["unconfirmed_balance"]).to eq(0)
- expect(res["confirmed_balance"]).to eq(0.91108606)
- end
-
- context "upstream request error" do
- before do
- stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/payment-methods/onchain/BTC/wallet")
- .to_return(status: 500, headers: {}, body: "")
- end
-
- it "returns a formatted error" do
- get api_kredits_onchain_btc_balance_path
-
- expect(response).to have_http_status(:server_error)
-
- res = JSON.parse(response.body)
- expect(res["error"]).not_to be_nil
- end
- end
- end
-end