From 04a9061663a76d3deb1445da034139f003c5c973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Fri, 18 Oct 2024 15:01:08 +0200 Subject: [PATCH] WIP Render nostr profile and relay status with Ruby --- .../nostr_profile_status_component.html.erb | 7 + .../nostr_profile_status_component.rb | 53 ++++++++ .../nostr_relay_status_component.html.erb | 4 + .../settings/nostr_relay_status_component.rb | 23 ++++ app/components/status_text_component.html.erb | 8 ++ app/components/status_text_component.rb | 7 + app/controllers/settings_controller.rb | 23 +++- .../settings/nostr_pubkey_controller.js | 10 +- .../concerns/settings/nostr_settings.rb | 5 + .../nostr_manager/discover_user_profile.rb | 10 +- .../nostr_manager/discover_user_relays.rb | 8 +- app/views/settings/_nostr.html.erb | 120 ++---------------- .../settings/_nostr_user_relays.html.erb | 15 +++ config/routes.rb | 1 + 14 files changed, 168 insertions(+), 126 deletions(-) create mode 100644 app/components/settings/nostr_profile_status_component.html.erb create mode 100644 app/components/settings/nostr_profile_status_component.rb create mode 100644 app/components/settings/nostr_relay_status_component.html.erb create mode 100644 app/components/settings/nostr_relay_status_component.rb create mode 100644 app/components/status_text_component.html.erb create mode 100644 app/components/status_text_component.rb create mode 100644 app/views/settings/_nostr_user_relays.html.erb diff --git a/app/components/settings/nostr_profile_status_component.html.erb b/app/components/settings/nostr_profile_status_component.html.erb new file mode 100644 index 0000000..24d38f5 --- /dev/null +++ b/app/components/settings/nostr_profile_status_component.html.erb @@ -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 %> diff --git a/app/components/settings/nostr_profile_status_component.rb b/app/components/settings/nostr_profile_status_component.rb new file mode 100644 index 0000000..3f685a0 --- /dev/null +++ b/app/components/settings/nostr_profile_status_component.rb @@ -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 #{ user_address }", + icon_name: "check-circle", + icon_color: "emerald-500" + }) + else + @statuses.push({ + text: "Your profile's Nostr address is not set to #{ user_address } 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 #{ user_address }", + icon_name: "check-circle", + icon_color: "emerald-500" + }) + else + @statuses.push({ + text: "Your profile's Lightning address is not set to #{ user_address } 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 diff --git a/app/components/settings/nostr_relay_status_component.html.erb b/app/components/settings/nostr_relay_status_component.html.erb new file mode 100644 index 0000000..0a4cd0d --- /dev/null +++ b/app/components/settings/nostr_relay_status_component.html.erb @@ -0,0 +1,4 @@ +<%= render StatusTextComponent.new( + text: @text, + icon_name: @icon_name, + icon_color: @icon_color) %> diff --git a/app/components/settings/nostr_relay_status_component.rb b/app/components/settings/nostr_relay_status_component.rb new file mode 100644 index 0000000..fbdc7f8 --- /dev/null +++ b/app/components/settings/nostr_relay_status_component.rb @@ -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 diff --git a/app/components/status_text_component.html.erb b/app/components/status_text_component.html.erb new file mode 100644 index 0000000..6134458 --- /dev/null +++ b/app/components/status_text_component.html.erb @@ -0,0 +1,8 @@ +

+ + <%= render "icons/#{@icon_name}" %> + + + <%= raw @text %> + +

diff --git a/app/components/status_text_component.rb b/app/components/status_text_component.rb new file mode 100644 index 0000000..d5f94bc --- /dev/null +++ b/app/components/status_text_component.rb @@ -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 diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb index a21c542..a140f2e 100644 --- a/app/controllers/settings_controller.rb +++ b/app/controllers/settings_controller.rb @@ -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 diff --git a/app/javascript/controllers/settings/nostr_pubkey_controller.js b/app/javascript/controllers/settings/nostr_pubkey_controller.js index 038d7cd..9bf07da 100644 --- a/app/javascript/controllers/settings/nostr_pubkey_controller.js +++ b/app/javascript/controllers/settings/nostr_pubkey_controller.js @@ -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") diff --git a/app/models/concerns/settings/nostr_settings.rb b/app/models/concerns/settings/nostr_settings.rb index d5dc7e6..4b55742 100644 --- a/app/models/concerns/settings/nostr_settings.rb +++ b/app/models/concerns/settings/nostr_settings.rb @@ -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 diff --git a/app/services/nostr_manager/discover_user_profile.rb b/app/services/nostr_manager/discover_user_profile.rb index 789cbcf..e98e198 100644 --- a/app/services/nostr_manager/discover_user_profile.rb +++ b/app/services/nostr_manager/discover_user_profile.rb @@ -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 diff --git a/app/services/nostr_manager/discover_user_relays.rb b/app/services/nostr_manager/discover_user_relays.rb index a2216be..6065ae1 100644 --- a/app/services/nostr_manager/discover_user_relays.rb +++ b/app/services/nostr_manager/discover_user_relays.rb @@ -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 diff --git a/app/views/settings/_nostr.html.erb b/app/views/settings/_nostr.html.erb index 7579a69..c01f3a3 100644 --- a/app/views/settings/_nostr.html.erb +++ b/app/views/settings/_nostr.html.erb @@ -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 %>"> -
+

Nostr

Public Key @@ -26,8 +26,16 @@ <% else %>

Verify your Nostr public key with us in order to enable Nostr-specific - features for your account. + features for your account:

+
    +
  • Log in with Nostr (no password needed)
  • +
  • Verified Nostr address
  • +
  • Receive zaps in your Lightning account
  • + <% if Setting.nostr_relay_url.present? %> +
  • Publish notes on <%= link_to "our relay", Setting.nostr_relay_url_http, class: "ks-text-link", target: "_blank" %>
  • + <% end %> +
<% end %>
<% if current_user.nostr_pubkey.present? %> -
-

Profile

-
- - -
-
- - - -
-
- - - -
-
- -
-

Relays

-
- - - -
-
    -
-
+ <%= turbo_frame_tag "nostr_user_metadata", src: nostr_user_metadata_settings_path do %> +

Loading...

+ <% end %> <% end %>
diff --git a/app/views/settings/_nostr_user_relays.html.erb b/app/views/settings/_nostr_user_relays.html.erb new file mode 100644 index 0000000..e2e69ef --- /dev/null +++ b/app/views/settings/_nostr_user_relays.html.erb @@ -0,0 +1,15 @@ +<%= turbo_frame_tag "nostr_user_metadata" do %> +
+

Profile

+ <%= render Settings::NostrProfileStatusComponent.new( + profile_event: @profile, + user_address: current_user.address + ) %> +
+
+

Relays

+ <%= render Settings::NostrRelayStatusComponent.new( + relay_urls: @relay_urls + ) %> +
+<% end %> diff --git a/config/routes.rb b/config/routes.rb index 07e1ffe..64eeb6c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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