Compare commits
4 Commits
feature/no
...
6e95fa99df
| Author | SHA1 | Date | |
|---|---|---|---|
|
6e95fa99df
|
|||
|
5283f6fce7
|
|||
|
a08a4746f7
|
|||
|
9e3652479b
|
@@ -0,0 +1,7 @@
|
|||||||
|
<% @statuses.each do |status| %>
|
||||||
|
<%= render StatusTextComponent.new(
|
||||||
|
text: status[:text],
|
||||||
|
icon_name: status[:icon_name],
|
||||||
|
icon_color: status[:icon_color]
|
||||||
|
) %>
|
||||||
|
<% end %>
|
||||||
46
app/components/settings/nostr_profile_status_component.rb
Normal file
46
app/components/settings/nostr_profile_status_component.rb
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Settings
|
||||||
|
class NostrProfileStatusComponent < ViewComponent::Base
|
||||||
|
def initialize(profile_event:, user_address:)
|
||||||
|
if profile_event.present?
|
||||||
|
profile = JSON.parse(profile_event["content"])
|
||||||
|
@statuses = []
|
||||||
|
|
||||||
|
if profile["nip05"].present? && profile["nip05"] == user_address
|
||||||
|
@statuses.push({
|
||||||
|
text: "Your profile's Nostr address is set to <strong>#{ user_address }</strong>",
|
||||||
|
icon_name: "check-circle",
|
||||||
|
icon_color: "emerald-500"
|
||||||
|
})
|
||||||
|
else
|
||||||
|
@statuses.push({
|
||||||
|
text: "Your profile's Nostr address is not set to <strong>#{ user_address }</strong> yet",
|
||||||
|
icon_name: "alert-octagon",
|
||||||
|
icon_color: "amber-500"
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
if profile["lud16"].present? && profile["lud16"] == user_address
|
||||||
|
@statuses.push({
|
||||||
|
text: "Your profile's Lightning address is set to <strong>#{ user_address }</strong>",
|
||||||
|
icon_name: "check-circle",
|
||||||
|
icon_color: "emerald-500"
|
||||||
|
})
|
||||||
|
else
|
||||||
|
@statuses.push({
|
||||||
|
text: "Your profile's Lightning address is not set to <strong>#{ user_address }</strong> yet",
|
||||||
|
icon_name: "alert-octagon",
|
||||||
|
icon_color: "amber-500"
|
||||||
|
})
|
||||||
|
end
|
||||||
|
else
|
||||||
|
@statuses.push({
|
||||||
|
text: "We could not find a profile for your public key",
|
||||||
|
icon_name: "alert-octagon",
|
||||||
|
icon_color: "amber-500"
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<%= render StatusTextComponent.new(
|
||||||
|
text: @text,
|
||||||
|
icon_name: @icon_name,
|
||||||
|
icon_color: @icon_color) %>
|
||||||
23
app/components/settings/nostr_relay_status_component.rb
Normal file
23
app/components/settings/nostr_relay_status_component.rb
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Settings
|
||||||
|
class NostrRelayStatusComponent < ViewComponent::Base
|
||||||
|
def initialize(relay_urls:)
|
||||||
|
if relay_urls.present?
|
||||||
|
if relay_urls.any? { |r| r.include?("wss://nostr.kosmos.org") }
|
||||||
|
@text = "You have a relay list, and the Kosmos relay is part of it"
|
||||||
|
@icon_name = "check-circle"
|
||||||
|
@icon_color = "emerald-500"
|
||||||
|
else
|
||||||
|
@text = "The Kosmos relay is missing from your relay list"
|
||||||
|
@icon_name = "alert-octagon"
|
||||||
|
@icon_color = "amber-500"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
@text = "We could not find a relay list for your public key"
|
||||||
|
@icon_name = "alert-octagon"
|
||||||
|
@icon_color = "amber-500"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
8
app/components/status_text_component.html.erb
Normal file
8
app/components/status_text_component.html.erb
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<p class="flex gap-x-4 items-center">
|
||||||
|
<span class="inline-block h-6 w-6 grow-0 text-<%= @icon_color %>">
|
||||||
|
<%= render "icons/#{@icon_name}" %>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<%= raw @text %>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
7
app/components/status_text_component.rb
Normal file
7
app/components/status_text_component.rb
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
class StatusTextComponent < ViewComponent::Base
|
||||||
|
def initialize(text:, icon_name:, icon_color:)
|
||||||
|
@text = text
|
||||||
|
@icon_name = icon_name
|
||||||
|
@icon_color = icon_color
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -4,8 +4,13 @@ require "bcrypt"
|
|||||||
class SettingsController < ApplicationController
|
class SettingsController < ApplicationController
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
before_action :set_main_nav_section
|
before_action :set_main_nav_section
|
||||||
before_action :set_settings_section, only: [:show, :update, :update_email, :reset_email_password]
|
before_action :set_settings_section, only: [
|
||||||
before_action :set_user, only: [:show, :update, :update_email, :reset_email_password]
|
:show, :update, :update_email, :reset_email_password
|
||||||
|
]
|
||||||
|
before_action :set_user, only: [
|
||||||
|
:show, :update, :update_email, :reset_email_password,
|
||||||
|
:fetch_nostr_user_metadata
|
||||||
|
]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
redirect_to setting_path(:profile)
|
redirect_to setting_path(:profile)
|
||||||
@@ -128,6 +133,20 @@ class SettingsController < ApplicationController
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def fetch_nostr_user_metadata
|
||||||
|
if @user.nostr_pubkey.present?
|
||||||
|
if @nip65_event = NostrManager::DiscoverUserRelays.call(pubkey: @user.nostr_pubkey)
|
||||||
|
@relay_urls = @nip65_event["tags"].select{ |t| t[0] == "r" }&.map{ |t| t[1] }
|
||||||
|
end
|
||||||
|
|
||||||
|
@profile = NostrManager::DiscoverUserProfile.call(pubkey: @user.nostr_pubkey, relays: @relay_urls)
|
||||||
|
else
|
||||||
|
@relays, @profile = [nil, nil]
|
||||||
|
end
|
||||||
|
|
||||||
|
render partial: 'nostr_user_relays'
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_main_nav_section
|
def set_main_nav_section
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ export default class extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.pubkeyHexValue) {
|
if (this.pubkeyHexValue) {
|
||||||
this.discoverUserOnNostr().then(() => {
|
// this.discoverUserOnNostr().then(() => {
|
||||||
this.renderRelayStatus()
|
// this.renderRelayStatus()
|
||||||
this.renderProfileNip05Status()
|
// this.renderProfileNip05Status()
|
||||||
this.renderProfileLud16Status()
|
// this.renderProfileLud16Status()
|
||||||
})
|
// })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.noExtensionTarget.classList.remove("hidden")
|
this.noExtensionTarget.classList.remove("hidden")
|
||||||
|
|||||||
@@ -20,6 +20,19 @@ module Settings
|
|||||||
|
|
||||||
field :nostr_zaps_relay_limit, type: :integer,
|
field :nostr_zaps_relay_limit, type: :integer,
|
||||||
default: 12
|
default: 12
|
||||||
|
|
||||||
|
field :nostr_discovery_relays, type: :array, default: %w[
|
||||||
|
wss://nostr.kosmos.org
|
||||||
|
wss://purplepag.es
|
||||||
|
wss://relay.nostr.band
|
||||||
|
wss://njump.me
|
||||||
|
wss://relay.damus.io
|
||||||
|
]
|
||||||
|
|
||||||
|
def self.nostr_relay_url_http
|
||||||
|
self.nostr_relay_url.gsub(/^ws:/, "http:")
|
||||||
|
.gsub(/^wss:/, "https:")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
36
app/services/nostr_manager/discover_user_profile.rb
Normal file
36
app/services/nostr_manager/discover_user_profile.rb
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
module NostrManager
|
||||||
|
class DiscoverUserProfile < NostrManagerService
|
||||||
|
MAX_EVENTS = 2
|
||||||
|
|
||||||
|
def initialize(pubkey:, relays: nil)
|
||||||
|
@pubkey = pubkey
|
||||||
|
@relays = relays.present? ? relays : Setting.nostr_discovery_relays
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
received_events = 0
|
||||||
|
profile_events = []
|
||||||
|
filter = Nostr::Filter.new(
|
||||||
|
authors: [@pubkey],
|
||||||
|
kinds: [0],
|
||||||
|
limit: 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
@relays.each do |url|
|
||||||
|
event = NostrManager::FetchLatestEvent.call(filter: filter, relay_url: url)
|
||||||
|
|
||||||
|
if event.present?
|
||||||
|
profile_events << event if profile_events.none? { |e| e["id"] == event["id"] }
|
||||||
|
received_events += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if received_events >= MAX_EVENTS
|
||||||
|
puts "Found #{MAX_EVENTS} events, ending the search"
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
profile_events.min_by { |e| e["created_at"] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
37
app/services/nostr_manager/discover_user_relays.rb
Normal file
37
app/services/nostr_manager/discover_user_relays.rb
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
module NostrManager
|
||||||
|
class DiscoverUserRelays < NostrManagerService
|
||||||
|
MAX_EVENTS = 2
|
||||||
|
|
||||||
|
def initialize(pubkey:)
|
||||||
|
@pubkey = pubkey
|
||||||
|
@relays = Setting.nostr_discovery_relays
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
received_events = 0
|
||||||
|
nip65_events = []
|
||||||
|
user_relays = []
|
||||||
|
filter = Nostr::Filter.new(
|
||||||
|
authors: [@pubkey],
|
||||||
|
kinds: [10002],
|
||||||
|
limit: 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
@relays.each do |url|
|
||||||
|
event = NostrManager::FetchLatestEvent.call(filter: filter, relay_url: url)
|
||||||
|
|
||||||
|
if event.present?
|
||||||
|
nip65_events << event if nip65_events.none? { |e| e["id"] == event["id"] }
|
||||||
|
received_events += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if received_events >= MAX_EVENTS
|
||||||
|
puts "Found #{MAX_EVENTS} events, ending the search"
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
nip65_events.min_by { |e| e["created_at"] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
59
app/services/nostr_manager/fetch_latest_event.rb
Normal file
59
app/services/nostr_manager/fetch_latest_event.rb
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
module NostrManager
|
||||||
|
class FetchLatestEvent < NostrManagerService
|
||||||
|
TIMEOUT = 1
|
||||||
|
|
||||||
|
def initialize(filter:, relay_url:)
|
||||||
|
@filter = filter
|
||||||
|
@relay = new_relay(relay_url)
|
||||||
|
@client = Nostr::Client.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
filter, client, relay = @filter, @client, @relay
|
||||||
|
latest_event = nil
|
||||||
|
mutex = Mutex.new
|
||||||
|
received_event = ConditionVariable.new
|
||||||
|
log_prefix = "[nostr][#{@relay.name}]"
|
||||||
|
|
||||||
|
thread = Thread.new do
|
||||||
|
client.on :connect do
|
||||||
|
client.subscribe(filter: filter)
|
||||||
|
end
|
||||||
|
|
||||||
|
client.on :error do |e|
|
||||||
|
Rails.logger.info "#{log_prefix} Error: #{e}"
|
||||||
|
Thread.current.exit
|
||||||
|
end
|
||||||
|
|
||||||
|
client.on :message do |m|
|
||||||
|
msg = JSON.parse(m) rescue nil
|
||||||
|
if msg && msg[0] == "EVENT" && msg[2]
|
||||||
|
puts "#{log_prefix} Event received: #{msg[2]["id"]}"
|
||||||
|
mutex.synchronize do
|
||||||
|
latest_event = msg[2]
|
||||||
|
received_event.signal
|
||||||
|
end
|
||||||
|
elsif msg && msg[0] == "EOSE"
|
||||||
|
Thread.current.exit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
client.connect relay
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
Timeout.timeout(TIMEOUT) do
|
||||||
|
mutex.synchronize do
|
||||||
|
received_event.wait(mutex) if latest_event.nil?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue Timeout::Error
|
||||||
|
puts "#{log_prefix} Timeout: No event received within #{TIMEOUT} seconds"
|
||||||
|
ensure
|
||||||
|
thread.exit
|
||||||
|
end
|
||||||
|
|
||||||
|
latest_event
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -3,6 +3,7 @@ require "nostr"
|
|||||||
class NostrManagerService < ApplicationService
|
class NostrManagerService < ApplicationService
|
||||||
def parse_tags(tags)
|
def parse_tags(tags)
|
||||||
out = {}
|
out = {}
|
||||||
|
# TODO support more than 1 item for each tag type
|
||||||
tags.each do |tag|
|
tags.each do |tag|
|
||||||
out[tag[0].to_sym] = tag[1, tag.length]
|
out[tag[0].to_sym] = tag[1, tag.length]
|
||||||
end
|
end
|
||||||
@@ -19,4 +20,8 @@ class NostrManagerService < ApplicationService
|
|||||||
def site_user
|
def site_user
|
||||||
Nostr::User.new(keypair: site_keypair)
|
Nostr::User.new(keypair: site_keypair)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def new_relay(url)
|
||||||
|
Nostr::Relay.new(url: url, name: URI.parse(url).host)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -31,13 +31,28 @@
|
|||||||
) %>
|
) %>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h3>Zaps</h3>
|
<h3>Zaps</h3>
|
||||||
<ul role="list">
|
<ul role="list">
|
||||||
<%= render FormElements::FieldsetResettableSettingComponent.new(
|
<%= render FormElements::FieldsetResettableSettingComponent.new(
|
||||||
key: :nostr_zaps_relay_limit,
|
key: :nostr_zaps_relay_limit,
|
||||||
title: "Relay limit",
|
title: "Relay limit",
|
||||||
description: "The maximum number of relays to publish zap receipts to"
|
description: "The maximum number of sender-defined relays to try to publish zap receipts to"
|
||||||
) %>
|
) %>
|
||||||
</ul>
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h3>Onboarding</h3>
|
||||||
|
<ul role="list">
|
||||||
|
<%= render FormElements::FieldsetComponent.new(
|
||||||
|
title: "Discovery relays",
|
||||||
|
description: "Used to discover a user's published relay list and/or profile"
|
||||||
|
) do %>
|
||||||
|
<%= f.text_area :nostr_discovery_relays,
|
||||||
|
value: Setting.nostr_discovery_relays.join("\n"),
|
||||||
|
class: "h-44 w-80" %>
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
data-settings--nostr-pubkey-site-value="<%= Setting.accounts_domain %>"
|
data-settings--nostr-pubkey-site-value="<%= Setting.accounts_domain %>"
|
||||||
data-settings--nostr-pubkey-shared-secret-value="<%= session[:shared_secret] %>"
|
data-settings--nostr-pubkey-shared-secret-value="<%= session[:shared_secret] %>"
|
||||||
data-settings--nostr-pubkey-pubkey-hex-value="<%= current_user.nostr_pubkey %>">
|
data-settings--nostr-pubkey-pubkey-hex-value="<%= current_user.nostr_pubkey %>">
|
||||||
<section>
|
<section class="mb-8 sm:mb-12">
|
||||||
<h3>Nostr</h3>
|
<h3>Nostr</h3>
|
||||||
<h4 class="mb-0">
|
<h4 class="mb-0">
|
||||||
Public Key
|
Public Key
|
||||||
@@ -26,8 +26,16 @@
|
|||||||
<% else %>
|
<% else %>
|
||||||
<p class="my-4">
|
<p class="my-4">
|
||||||
Verify your Nostr public key with us in order to enable Nostr-specific
|
Verify your Nostr public key with us in order to enable Nostr-specific
|
||||||
features for your account.
|
features for your account:
|
||||||
</p>
|
</p>
|
||||||
|
<ul class="list-disc list-inside">
|
||||||
|
<li>Log in with Nostr (no password needed)</li>
|
||||||
|
<li>Verified Nostr address</li>
|
||||||
|
<li>Receive zaps in your Lightning account</li>
|
||||||
|
<% if Setting.nostr_relay_url.present? %>
|
||||||
|
<li>Publish notes on <%= link_to "our relay", Setting.nostr_relay_url_http, class: "ks-text-link", target: "_blank" %></li>
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<div data-settings--nostr-pubkey-target="noExtension"
|
<div data-settings--nostr-pubkey-target="noExtension"
|
||||||
@@ -75,110 +83,8 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<% if current_user.nostr_pubkey.present? %>
|
<% if current_user.nostr_pubkey.present? %>
|
||||||
<section>
|
<%= turbo_frame_tag "nostr_user_metadata", src: nostr_user_metadata_settings_path do %>
|
||||||
<h3>Profile</h3>
|
<p>Loading...</p>
|
||||||
<div data-settings--nostr-pubkey-target="profileStatus" class="mb-4">
|
<% end %>
|
||||||
<p class="status-green hidden flex gap-x-4 items-center">
|
|
||||||
<span class="inline-block h-6 w-6 grow-0 text-emerald-500 %>">
|
|
||||||
<%= render "icons/check-circle" %>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
You already have a profile for your public key
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p class="status-orange hidden flex gap-x-4 items-center">
|
|
||||||
<span class="inline-block h-6 w-6 grow-0 text-amber-500 %>">
|
|
||||||
<%= render "icons/alert-octagon" %>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<strong><%= current_user.address %></strong> is not set as your Nostr address
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div data-settings--nostr-pubkey-target="profileStatusNip05" class="mb-4">
|
|
||||||
<p class="status-green hidden flex gap-x-4 items-center">
|
|
||||||
<span class="inline-block h-6 w-6 grow-0 text-emerald-500 %>">
|
|
||||||
<%= render "icons/check-circle" %>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<strong><%= current_user.address %></strong> is set as your Nostr address
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p class="status-orange hidden flex gap-x-4 items-center">
|
|
||||||
<span class="inline-block h-6 w-6 grow-0 text-amber-500 %>">
|
|
||||||
<%= render "icons/alert-octagon" %>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<strong><%= current_user.address %></strong> is not set as your Nostr address
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p class="status-red hidden flex gap-x-4 items-center">
|
|
||||||
<span class="inline-block h-6 w-6 grow-0 text-amber-500 %>">
|
|
||||||
<%= render "icons/alert-octagon" %>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
Your profile's Nostr address is not set to <strong><%= current_user.address %></strong> yet
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div data-settings--nostr-pubkey-target="profileStatusLud16">
|
|
||||||
<p class="status-green hidden flex gap-x-4 items-center">
|
|
||||||
<span class="inline-block h-6 w-6 grow-0 text-emerald-500 %>">
|
|
||||||
<%= render "icons/check-circle" %>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<strong><%= current_user.address %></strong> is set as your Lightning address
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p class="status-orange hidden flex gap-x-4 items-center">
|
|
||||||
<span class="inline-block h-6 w-6 grow-0 text-amber-500 %>">
|
|
||||||
<%= render "icons/alert-octagon" %>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<strong><%= current_user.address %></strong> is not set as your Lightning address yet
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p class="status-red hidden flex gap-x-4 items-center">
|
|
||||||
<span class="inline-block h-6 w-6 grow-0 text-amber-500 %>">
|
|
||||||
<%= render "icons/alert-octagon" %>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
Your profile's Lightning address is not set to <strong><%= current_user.address %></strong> yet
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h3>Relays</h3>
|
|
||||||
<div data-settings--nostr-pubkey-target="relayListStatus">
|
|
||||||
<p class="status-green hidden flex gap-x-4 items-center">
|
|
||||||
<span class="inline-block h-6 w-6 grow-0 text-emerald-500 %>">
|
|
||||||
<%= render "icons/check-circle" %>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
You have a relay list, and the Kosmos relay is part of it
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p class="status-orange hidden flex gap-x-4 items-center">
|
|
||||||
<span class="inline-block h-6 w-6 grow-0 text-amber-500 %>">
|
|
||||||
<%= render "icons/alert-octagon" %>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
The Kosmos relay is missing from your relay list
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p class="status-red hidden flex gap-x-4 items-center">
|
|
||||||
<span class="inline-block h-6 w-6 grow-0 text-amber-500 %>">
|
|
||||||
<%= render "icons/alert-octagon" %>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
We could not find a relay list for your public key
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<ul data-settings--nostr-pubkey-target="relayList">
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
15
app/views/settings/_nostr_user_relays.html.erb
Normal file
15
app/views/settings/_nostr_user_relays.html.erb
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<%= turbo_frame_tag "nostr_user_metadata" do %>
|
||||||
|
<section>
|
||||||
|
<h3>Profile</h3>
|
||||||
|
<%= render Settings::NostrProfileStatusComponent.new(
|
||||||
|
profile_event: @profile,
|
||||||
|
user_address: current_user.address
|
||||||
|
) %>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h3>Relays</h3>
|
||||||
|
<%= render Settings::NostrRelayStatusComponent.new(
|
||||||
|
relay_urls: @relay_urls
|
||||||
|
) %>
|
||||||
|
</section>
|
||||||
|
<% end %>
|
||||||
@@ -65,6 +65,7 @@ Rails.application.routes.draw do
|
|||||||
post 'reset_email_password'
|
post 'reset_email_password'
|
||||||
post 'set_nostr_pubkey'
|
post 'set_nostr_pubkey'
|
||||||
delete 'nostr_pubkey', to: 'settings#remove_nostr_pubkey'
|
delete 'nostr_pubkey', to: 'settings#remove_nostr_pubkey'
|
||||||
|
get 'fetch_nostr_user_metadata', as: 'nostr_user_metadata'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
1
vendor/gems/nostr
vendored
Submodule
1
vendor/gems/nostr
vendored
Submodule
Submodule vendor/gems/nostr added at 44e7454990
Reference in New Issue
Block a user