WIP Render nostr profile and relay status with Ruby
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Râu Cao 2024-10-18 15:01:08 +02:00
parent 5283f6fce7
commit 04a9061663
Signed by: raucao
GPG Key ID: 37036C356E56CC51
14 changed files with 168 additions and 126 deletions

View File

@ -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 %>

View File

@ -0,0 +1,53 @@
# frozen_string_literal: true
module Settings
class NostrProfileStatusComponent < ViewComponent::Base
def initialize(profile_event:, user_address:)
@statuses = []
if profile_event.present?
profile = JSON.parse(profile_event["content"])
@statuses.push({
text: "You have a public Nostr profile",
icon_name: "check-circle",
icon_color: "emerald-500"
})
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

View File

@ -0,0 +1,4 @@
<%= render StatusTextComponent.new(
text: @text,
icon_name: @icon_name,
icon_color: @icon_color) %>

View 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

View 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>

View 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

View File

@ -4,8 +4,13 @@ require "bcrypt"
class SettingsController < ApplicationController
before_action :authenticate_user!
before_action :set_main_nav_section
before_action :set_settings_section, only: [:show, :update, :update_email, :reset_email_password]
before_action :set_user, only: [:show, :update, :update_email, :reset_email_password]
before_action :set_settings_section, only: [
: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
redirect_to setting_path(:profile)
@ -128,6 +133,20 @@ class SettingsController < ApplicationController
}
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
def set_main_nav_section

View File

@ -23,11 +23,11 @@ export default class extends Controller {
}
if (this.pubkeyHexValue) {
this.discoverUserOnNostr().then(() => {
this.renderRelayStatus()
this.renderProfileNip05Status()
this.renderProfileLud16Status()
})
// this.discoverUserOnNostr().then(() => {
// this.renderRelayStatus()
// this.renderProfileNip05Status()
// this.renderProfileLud16Status()
// })
}
} else {
this.noExtensionTarget.classList.remove("hidden")

View File

@ -28,6 +28,11 @@ module Settings
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

View File

@ -1,10 +1,10 @@
module NostrManager
class DiscoverUserProfile < NostrManagerService
MAX_EVENTS = 3
MAX_EVENTS = 2
def initialize(pubkey:)
def initialize(pubkey:, relays: nil)
@pubkey = pubkey
@relays = Setting.nostr_discovery_relays
@relays = relays.present? ? relays : Setting.nostr_discovery_relays
end
def call
@ -30,9 +30,7 @@ module NostrManager
end
end
latest_event = profile_events.min_by { |e| e["created_at"] }
puts latest_event.inspect
profile_events.min_by { |e| e["created_at"] }
end
end
end

View File

@ -1,6 +1,6 @@
module NostrManager
class DiscoverUserRelays < NostrManagerService
MAX_EVENTS = 3
MAX_EVENTS = 2
def initialize(pubkey:)
@pubkey = pubkey
@ -31,11 +31,7 @@ module NostrManager
end
end
latest_event = nip65_events.min_by { |e| e["created_at"] }
tags = latest_event["tags"]
# puts latest_event.inspect
puts tags.select{ |t| t[0] == "r" }.inspect
nip65_events.min_by { |e| e["created_at"] }
end
end
end

View File

@ -3,7 +3,7 @@
data-settings--nostr-pubkey-site-value="<%= Setting.accounts_domain %>"
data-settings--nostr-pubkey-shared-secret-value="<%= session[:shared_secret] %>"
data-settings--nostr-pubkey-pubkey-hex-value="<%= current_user.nostr_pubkey %>">
<section>
<section class="mb-8 sm:mb-12">
<h3>Nostr</h3>
<h4 class="mb-0">
Public Key
@ -26,8 +26,16 @@
<% else %>
<p class="my-4">
Verify your Nostr public key with us in order to enable Nostr-specific
features for your account.
features for your account:
</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 %>
<div data-settings--nostr-pubkey-target="noExtension"
@ -75,110 +83,8 @@
</section>
<% if current_user.nostr_pubkey.present? %>
<section>
<h3>Profile</h3>
<div data-settings--nostr-pubkey-target="profileStatus" 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>
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>
<%= turbo_frame_tag "nostr_user_metadata", src: nostr_user_metadata_settings_path do %>
<p>Loading...</p>
<% end %>
<% end %>
</div>

View 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 %>

View File

@ -65,6 +65,7 @@ Rails.application.routes.draw do
post 'reset_email_password'
post 'set_nostr_pubkey'
delete 'nostr_pubkey', to: 'settings#remove_nostr_pubkey'
get 'fetch_nostr_user_metadata', as: 'nostr_user_metadata'
end
end