Compare commits
10 Commits
v0.6.0
...
feature/co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
462dd24da3
|
||
|
|
8eb5f093a4
|
||
| de45d070aa | |||
| c0b1112e49 | |||
|
|
2f90393eb6
|
||
|
|
8b87072485
|
||
|
|
82019f47be
|
||
|
|
259e72167b
|
||
|
|
7000908891
|
||
|
|
df0c13b400
|
3
app/components/header_tab_link_component.html.erb
Normal file
3
app/components/header_tab_link_component.html.erb
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<%= link_to @path, class: @link_class do %>
|
||||||
|
<%= @name %>
|
||||||
|
<% end %>
|
||||||
20
app/components/header_tab_link_component.rb
Normal file
20
app/components/header_tab_link_component.rb
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class HeaderTabLinkComponent < ViewComponent::Base
|
||||||
|
def initialize(name:, path:, active: false, disabled: false)
|
||||||
|
@name = name
|
||||||
|
@path = path
|
||||||
|
@active = active
|
||||||
|
@disabled = disabled
|
||||||
|
@link_class = class_names_link(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def class_names_link(path)
|
||||||
|
common = "block md:inline-block px-5 py-2 rounded-md font-medium text-base md:text-xl"
|
||||||
|
if @active
|
||||||
|
"#{common} bg-gray-900/50 text-white"
|
||||||
|
else
|
||||||
|
"#{common} text-gray-300 hover:bg-gray-900/30 hover:text-white active:bg-gray-900/30 active:text-white"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
12
app/components/header_with_tabs_component.html.erb
Normal file
12
app/components/header_with_tabs_component.html.erb
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<header class="py-10">
|
||||||
|
<div class="max-w-6xl md:flex md:gap-x-10 mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<% if @title.present? %>
|
||||||
|
<h1 class="text-3xl font-bold text-white">
|
||||||
|
<%= @title %>
|
||||||
|
</h1>
|
||||||
|
<% end %>
|
||||||
|
<nav class="md:grow flex gap-x-4 <%= @title.present? ? "justify-end" : "justify-start" %>" aria-label="Tabs">
|
||||||
|
<%= render partial: @tabnav_partial %>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
8
app/components/header_with_tabs_component.rb
Normal file
8
app/components/header_with_tabs_component.rb
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class HeaderWithTabsComponent < ViewComponent::Base
|
||||||
|
def initialize(title: nil, tabnav_partial:)
|
||||||
|
@title = title
|
||||||
|
@tabnav_partial = tabnav_partial
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
class DashboardController < ApplicationController
|
class DashboardController < ApplicationController
|
||||||
before_action :authenticate_user!
|
before_action :require_user_signed_in
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@current_section = :services
|
@current_section = :services
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ class Services::LightningController < ApplicationController
|
|||||||
session[:ln_auth_token] = auth_token
|
session[:ln_auth_token] = auth_token
|
||||||
@ln_auth_token = auth_token
|
@ln_auth_token = auth_token
|
||||||
end
|
end
|
||||||
rescue
|
rescue => e
|
||||||
# TODO add exception tracking
|
Sentry.capture_exception(e) if Setting.sentry_enabled?
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_current_section
|
def set_current_section
|
||||||
@@ -49,9 +49,9 @@ class Services::LightningController < ApplicationController
|
|||||||
lndhub = Lndhub.new
|
lndhub = Lndhub.new
|
||||||
data = lndhub.balance @ln_auth_token
|
data = lndhub.balance @ln_auth_token
|
||||||
@balance = data["BTC"]["AvailableBalance"] rescue nil
|
@balance = data["BTC"]["AvailableBalance"] rescue nil
|
||||||
rescue
|
rescue AuthError
|
||||||
authenticate_with_lndhub(force_reauth: true)
|
authenticate_with_lndhub(force_reauth: true)
|
||||||
return nil if @fetch_balance_retried
|
raise if @fetch_balance_retried
|
||||||
@fetch_balance_retried = true
|
@fetch_balance_retried = true
|
||||||
fetch_balance
|
fetch_balance
|
||||||
end
|
end
|
||||||
@@ -61,9 +61,9 @@ class Services::LightningController < ApplicationController
|
|||||||
txs = lndhub.gettxs @ln_auth_token
|
txs = lndhub.gettxs @ln_auth_token
|
||||||
invoices = lndhub.getuserinvoices(@ln_auth_token).select{|i| i["ispaid"]}
|
invoices = lndhub.getuserinvoices(@ln_auth_token).select{|i| i["ispaid"]}
|
||||||
process_transactions(txs + invoices)
|
process_transactions(txs + invoices)
|
||||||
rescue
|
rescue AuthError
|
||||||
authenticate_with_lndhub(force_reauth: true)
|
authenticate_with_lndhub(force_reauth: true)
|
||||||
return [] if @fetch_transactions_retried
|
raise if @fetch_transactions_retried
|
||||||
@fetch_transactions_retried = true
|
@fetch_transactions_retried = true
|
||||||
fetch_transactions
|
fetch_transactions
|
||||||
end
|
end
|
||||||
@@ -86,6 +86,10 @@ class Services::LightningController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Handle an edge case where lndhub.go includes a failed payment in the
|
||||||
|
# list, which wasn't actually booked
|
||||||
|
txs.reject!{ |tx| tx["type"] == "paid_invoice" && tx["payment_preimage"].blank? }
|
||||||
|
|
||||||
txs.sort{ |a,b| b["datetime"] <=> a["datetime"] }
|
txs.sort{ |a,b| b["datetime"] <=> a["datetime"] }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
1
app/errors/auth_error.rb
Normal file
1
app/errors/auth_error.rb
Normal file
@@ -0,0 +1 @@
|
|||||||
|
class AuthError < StandardError; end
|
||||||
@@ -12,12 +12,7 @@ class Lndhub
|
|||||||
end
|
end
|
||||||
|
|
||||||
res = Faraday.post "#{@base_url}/#{endpoint}", payload.to_json, headers
|
res = Faraday.post "#{@base_url}/#{endpoint}", payload.to_json, headers
|
||||||
|
log_error(res) if res.status != 200
|
||||||
if res.status != 200
|
|
||||||
Rails.logger.error "[lndhub] API request failed:"
|
|
||||||
Rails.logger.error res.body
|
|
||||||
#TODO add some kind of exception tracking/notifications
|
|
||||||
end
|
|
||||||
|
|
||||||
JSON.parse(res.body)
|
JSON.parse(res.body)
|
||||||
end
|
end
|
||||||
@@ -31,7 +26,7 @@ class Lndhub
|
|||||||
data = JSON.parse(res.body)
|
data = JSON.parse(res.body)
|
||||||
|
|
||||||
if data.is_a?(Hash) && data["error"] && data["message"] == "bad auth"
|
if data.is_a?(Hash) && data["error"] && data["message"] == "bad auth"
|
||||||
raise "BAD_AUTH"
|
raise AuthError
|
||||||
else
|
else
|
||||||
data
|
data
|
||||||
end
|
end
|
||||||
@@ -68,4 +63,13 @@ class Lndhub
|
|||||||
|
|
||||||
invoice["payment_request"]
|
invoice["payment_request"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def log_error(res)
|
||||||
|
Rails.logger.error "[lndhub] API request failed:"
|
||||||
|
Rails.logger.error res.body
|
||||||
|
|
||||||
|
if Setting.sentry_enabled?
|
||||||
|
Sentry.capture_message("Lndhub API request failed: #{res.body}")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
class LndhubV2
|
class LndhubV2 < Lndhub
|
||||||
attr_accessor :auth_token
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
@base_url = ENV["LNDHUB_API_URL"]
|
|
||||||
end
|
|
||||||
|
|
||||||
def post(endpoint, payload, options={})
|
def post(endpoint, payload, options={})
|
||||||
headers = { "Content-Type" => "application/json" }
|
headers = { "Content-Type" => "application/json" }
|
||||||
@@ -12,64 +7,12 @@ class LndhubV2
|
|||||||
elsif options[:admin_token]
|
elsif options[:admin_token]
|
||||||
headers.merge!({ "Authorization" => "Bearer #{options[:admin_token]}" })
|
headers.merge!({ "Authorization" => "Bearer #{options[:admin_token]}" })
|
||||||
end
|
end
|
||||||
|
|
||||||
res = Faraday.post "#{@base_url}/#{endpoint}", payload.to_json, headers
|
res = Faraday.post "#{@base_url}/#{endpoint}", payload.to_json, headers
|
||||||
|
log_error(res) if res.status != 200
|
||||||
if res.status != 200
|
|
||||||
Rails.logger.error "[lndhub] API request failed:"
|
|
||||||
Rails.logger.error res.body
|
|
||||||
#TODO add some kind of exception tracking/notifications
|
|
||||||
end
|
|
||||||
|
|
||||||
JSON.parse(res.body)
|
JSON.parse(res.body)
|
||||||
end
|
end
|
||||||
|
|
||||||
def get(endpoint, auth_token)
|
|
||||||
res = Faraday.get("#{@base_url}/#{endpoint}", {}, {
|
|
||||||
"Content-Type" => "application/json",
|
|
||||||
"Accept" => "application/json",
|
|
||||||
"Authorization" => "Bearer #{auth_token}"
|
|
||||||
})
|
|
||||||
|
|
||||||
JSON.parse(res.body)
|
|
||||||
end
|
|
||||||
|
|
||||||
def create(payload)
|
|
||||||
post "create", payload
|
|
||||||
end
|
|
||||||
|
|
||||||
def authenticate(user)
|
|
||||||
credentials = post "auth?type=auth", { login: user.ln_account, password: user.ln_password }
|
|
||||||
self.auth_token = credentials["access_token"]
|
|
||||||
self.auth_token
|
|
||||||
end
|
|
||||||
|
|
||||||
def balance(user_token=nil)
|
|
||||||
get "balance", user_token || auth_token
|
|
||||||
end
|
|
||||||
|
|
||||||
def gettxs(user_token)
|
|
||||||
get "gettxs", user_token || auth_token
|
|
||||||
end
|
|
||||||
|
|
||||||
def getuserinvoices(user_token)
|
|
||||||
get "getuserinvoices", user_token || auth_token
|
|
||||||
end
|
|
||||||
|
|
||||||
def addinvoice(payload)
|
|
||||||
invoice = post "addinvoice", {
|
|
||||||
amt: payload[:amount],
|
|
||||||
memo: payload[:memo],
|
|
||||||
description_hash: payload[:description_hash]
|
|
||||||
}
|
|
||||||
|
|
||||||
invoice["payment_request"]
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# V2
|
|
||||||
#
|
|
||||||
|
|
||||||
def create_account(payload={})
|
def create_account(payload={})
|
||||||
post "v2/users", payload, admin_token: Rails.application.credentials.lndhub[:admin_token]
|
post "v2/users", payload, admin_token: Rails.application.credentials.lndhub[:admin_token]
|
||||||
end
|
end
|
||||||
@@ -78,4 +21,5 @@ class LndhubV2
|
|||||||
# Payload: { amount: 1000, description: "", description_hash: "" }
|
# Payload: { amount: 1000, description: "", description_hash: "" }
|
||||||
post "v2/invoices", payload
|
post "v2/invoices", payload
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
<%= render HeaderComponent.new(title: "Contributions") %>
|
<%# <%= render HeaderComponent.new(title: "Contributions") %>
|
||||||
|
<%= render HeaderWithTabsComponent.new(
|
||||||
|
# title: "Contributions",
|
||||||
|
tabnav_partial: "shared/tabnav_contributions"
|
||||||
|
) %>
|
||||||
|
|
||||||
<%= render MainWithTabnavComponent.new(tabnav_partial: "shared/tabnav_contributions") do %>
|
<%= render MainSimpleComponent.new do %>
|
||||||
<section>
|
<section>
|
||||||
<% if @donations.any? %>
|
<% if @donations.any? %>
|
||||||
<p class="mb-12">
|
<p class="mb-12">
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
<%= render HeaderComponent.new(title: "Contributions") %>
|
<%= render HeaderWithTabsComponent.new(
|
||||||
|
# title: "Contributions",
|
||||||
|
tabnav_partial: "shared/tabnav_contributions"
|
||||||
|
) %>
|
||||||
|
|
||||||
<%= render MainWithTabnavComponent.new(tabnav_partial: "shared/tabnav_contributions") do %>
|
<%= render MainSimpleComponent.new do %>
|
||||||
<section>
|
<section>
|
||||||
<p class="mb-8">
|
<p class="mb-8">
|
||||||
Project contributions are how we develop and run all Kosmos software and
|
Project contributions are how we develop and run all Kosmos software and
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
||||||
bg-[length:95%] bg-center bg-no-repeat
|
bg-[length:95%] bg-center bg-no-repeat
|
||||||
bg-[url(/img/logos/icon_discourse.svg)]">
|
bg-[url(/img/logos/icon_discourse.svg)]">
|
||||||
<%= link_to "https://community.kosmos.org",
|
<%= link_to "#{Setting.discourse_public_url}/session/sso?return_path=/",
|
||||||
class: "block h-full px-6 py-6 rounded-md" do %>
|
class: "block h-full px-6 py-6 rounded-md" do %>
|
||||||
<h3 class="mb-3.5">Discourse</h3>
|
<h3 class="mb-3.5">Discourse</h3>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<%
|
<%
|
||||||
# TODO remove when https://github.com/hotwired/turbo/issues/203 is fixed
|
# TODO remove when https://github.com/hotwired/turbo/issues/203 is fixed
|
||||||
enable_turbo = !session[:user_return_to].match?('/discourse/connect')
|
enable_turbo = !session[:user_return_to] || !session[:user_return_to].match?('/discourse/connect')
|
||||||
%>
|
%>
|
||||||
|
|
||||||
<%= render HeaderCompactComponent.new(title: "Log in") %>
|
<%= render HeaderCompactComponent.new(title: "Log in") %>
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
<div class="border-b border-gray-200">
|
<%= render HeaderTabLinkComponent.new(
|
||||||
<nav class="-mb-px flex" aria-label="Tabs">
|
name: "Donations", path: contributions_donations_path,
|
||||||
<%= render TabnavLinkComponent.new(
|
active: current_page?(contributions_donations_path)
|
||||||
name: "Donations", path: contributions_donations_path,
|
) %>
|
||||||
active: current_page?(contributions_donations_path)
|
<%= render HeaderTabLinkComponent.new(
|
||||||
) %>
|
name: "Projects", path: contributions_projects_path,
|
||||||
<%= render TabnavLinkComponent.new(
|
active: current_page?(contributions_projects_path)
|
||||||
name: "Projects", path: contributions_projects_path,
|
) %>
|
||||||
active: current_page?(contributions_projects_path)
|
|
||||||
) %>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user