diff --git a/spec/more_speech/db/xtdb_spec.clj b/spec/more_speech/db/xtdb_spec.clj index 453cc61..9b14b7e 100644 --- a/spec/more_speech/db/xtdb_spec.clj +++ b/spec/more_speech/db/xtdb_spec.clj @@ -121,9 +121,7 @@ (gateway/add-event @db {:id 3 :pubkey 1003 :created-at 300}) (gateway/add-event @db {:id 4 :pubkey 1004 :created-at 400}) (xtdb/sync-db @db) - (should= #{1003 1004} (gateway/get-some-recent-event-authors @db 200)) - - ) + (should= #{1003 1004} (gateway/get-some-recent-event-authors @db 200))) ) (context "contacts" diff --git a/spec/more_speech/ui/swing/users_window_spec.clj b/spec/more_speech/ui/swing/users_window_spec.clj new file mode 100644 index 0000000..63c4020 --- /dev/null +++ b/spec/more_speech/ui/swing/users_window_spec.clj @@ -0,0 +1,42 @@ +(ns more-speech.ui.swing.users-window-spec + (:require + [more-speech.config :as config] + [more-speech.db.in-memory :as in-memory] + [more-speech.mem :refer :all] + [more-speech.ui.swing.users-window :as users-window] + [speclj.core :refer :all])) + +(declare db) + +(describe "users window" + (with-stubs) + (with db (in-memory/get-db)) + (before-all (config/set-db! :in-memory)) + (before (in-memory/clear-db @db)) + (before (clear-mem)) + + (context "selection management" + (it "removes ids from selection lists" + (set-mem [:user-window :some-items] + [["id1" 1] + ["id2" 2] + ["id3" 3]]) + + (set-mem [:user-window :some-ids] + [1 2 3]) + (users-window/remove-item 2 :some-items :some-ids) + (should= [["id1" 1] + ["id3" 3]] + (get-mem [:user-window :some-items])) + (should= [1 3] (get-mem [:user-window :some-ids]))) + + (it "finds item using pubkey" + (should= ["id2" 2] (users-window/find-item 2 [["id1" 1] + ["id2" 2] + ["id3" 3]])) + ) + ) + ) + + + diff --git a/src/more_speech/nostr/event_composers.clj b/src/more_speech/nostr/event_composers.clj index 669ee78..d838581 100644 --- a/src/more_speech/nostr/event_composers.clj +++ b/src/more_speech/nostr/event_composers.clj @@ -18,9 +18,8 @@ which must include kind, tags, and content. The body is put into an EVENT wrapper that is ready to send." [body] - (let [keys (get-mem :keys) - private-key (util/hex-string->bytes (:private-key keys)) - pubkey (util/hex-string->bytes (:public-key keys)) + (let [private-key (util/hex-string->bytes (get-mem [:keys :private-key])) + pubkey (get-mem :pubkey) now (quot (System/currentTimeMillis) 1000) body (assoc body :pubkey (util/bytes->hex-string pubkey) :created_at now) @@ -32,15 +31,15 @@ ["EVENT" event])) (defn compose-metadata-event [] - (let [keys (get-mem :keys) - profile {:name (:name keys) - :about (:about keys) - :picture (:picture keys)} - profile (if (some? (:nip05 keys)) - (assoc profile :nip05 (:nip05 keys)) + (let [key-map (get-mem :keys) + profile {:name (:name key-map) + :about (:about key-map) + :picture (:picture key-map)} + profile (if (some? (:nip05 key-map)) + (assoc profile :nip05 (:nip05 key-map)) profile) - profile (if (some? (:lud16 keys)) - (assoc profile :lud16 (:lud16 keys)) + profile (if (some? (:lud16 key-map)) + (assoc profile :lud16 (:lud16 key-map)) profile) content (events/to-json profile) body {:kind 0 diff --git a/src/more_speech/nostr/trust_updater.clj b/src/more_speech/nostr/trust_updater.clj index 6064982..c701a3c 100644 --- a/src/more_speech/nostr/trust_updater.clj +++ b/src/more_speech/nostr/trust_updater.clj @@ -1,8 +1,14 @@ (ns more-speech.nostr.trust-updater - (:require [more-speech.mem :refer :all] - [more-speech.nostr.event-composers :as composers] - [more-speech.db.gateway :as gateway] - [more-speech.config :refer [get-db]])) + (:require + [more-speech.config :as config] + [more-speech.config :refer [get-db]] + [more-speech.db.gateway :as gateway] + [more-speech.mem :refer :all] + [more-speech.nostr.event-composers :as composers] + [more-speech.nostr.util :as util] + [more-speech.ui.formatter-util :as f-util] + ) + (:use [seesaw.core])) (defn entrust [his-pubkey his-petname] (let [my-pubkey (get-mem :pubkey) @@ -18,4 +24,26 @@ (defn entrust-and-send [his-pubkey his-petname] (let [my-contact-list (entrust his-pubkey his-petname)] - (composers/compose-and-send-contact-list my-contact-list))) \ No newline at end of file + (composers/compose-and-send-contact-list my-contact-list))) + +(defn ask-for-petname [pubkey] + (loop [profile (gateway/get-profile (get-db) pubkey)] + (let [petname (input "Name this author" + :value (:name profile) + :title (str "Entrust " (f-util/abbreviate (util/hexify pubkey) 10)))] + (cond + (nil? petname) + nil + + (re-matches config/user-name-chars petname) + petname + + :else + (do (alert (str "Invalid pet-name: " petname)) + (recur profile)))))) + +(defn trust-this-author [event _e] + (let [his-pubkey (:pubkey event) + petname (ask-for-petname his-pubkey)] + (when (some? petname) + (entrust-and-send his-pubkey petname)))) diff --git a/src/more_speech/ui/swing/tabs.clj b/src/more_speech/ui/swing/tabs.clj index 56c01d9..1ff6a83 100644 --- a/src/more_speech/ui/swing/tabs.clj +++ b/src/more_speech/ui/swing/tabs.clj @@ -10,15 +10,13 @@ [more-speech.nostr.tab-searcher :as tab-searcher] [more-speech.nostr.trust-updater :as trust-updater] [more-speech.nostr.util :as util] - [more-speech.ui.formatter-util :as f-util] [more-speech.ui.formatters :as formatters] [more-speech.ui.swing.article-panel :as article-panel] [more-speech.ui.swing.article-tree-util :as at-util] [more-speech.ui.swing.edit-window :as edit-window] [more-speech.ui.swing.util :as swing-util] [more-speech.user-configuration :as uconfig]) - (:use (seesaw [core] [font] [tree]) - (seesaw [color] [core] [font] [tree])) + (:use (seesaw [color] [core] [font] [tree])) (:import (javax.swing.tree DefaultMutableTreeNode DefaultTreeModel TreePath))) (declare mouse-pressed tab-menu) @@ -243,15 +241,6 @@ (with-out-str (clojure.pprint/pprint (formatters/hexify-event event))))) -(defn trust-this-author [event _e] - (let [his-pubkey (:pubkey event) - profile (gateway/get-profile (get-db) his-pubkey) - petname (input "Name this author" - :value (:name profile) - :title (str "Entrust " (f-util/abbreviate (util/num32->hex-string his-pubkey) 10)))] - (when (some? petname) - (trust-updater/entrust-and-send his-pubkey petname)))) - (defn dm-author [event _e] (let [pubkey (:pubkey event) content (str "D @" (formatters/get-best-name pubkey) " ")] @@ -278,7 +267,7 @@ p (popup :items [(action :name "Get info..." :handler (partial get-info event)) (action :name "Trust this author..." - :handler (partial trust-this-author event)) + :handler (partial trust-updater/trust-this-author event)) (menu :text "Add author to tab" :items add-author-actions) (menu :text "Block author from tab" :items block-author-actions) (menu :text "Add article to tab" :items add-article-actions) diff --git a/src/more_speech/ui/swing/users_window.clj b/src/more_speech/ui/swing/users_window.clj index 7863aa4..687f20b 100644 --- a/src/more_speech/ui/swing/users_window.clj +++ b/src/more_speech/ui/swing/users_window.clj @@ -7,6 +7,8 @@ [more-speech.mem :refer :all] [more-speech.mem :refer :all] [more-speech.nostr.contact-list :as contact-list] + [more-speech.nostr.event-composers :as event-composers] + [more-speech.nostr.trust-updater :as trust-updater] [more-speech.nostr.util :as util] [more-speech.ui.formatters :as formatters]) (:use (seesaw [core]))) @@ -27,26 +29,14 @@ (text! widget value) (text! widget (first value))))) -(defn trust-selection [frame _e] - (let [selected-listbox (select frame [:#selected-users]) - selected-item (selection selected-listbox)] - (when (some? selected-item) - ))) - -(defn load-web-of-trust-authors [frame _e] - (config! (select frame [:#selected-users]) - :model (get-mem [:user-window :web-of-trust-items]))) - -(defn load-recent-users [frame _e] +(defn load-recent-users [] (let [after (- (util/get-now) (* 86400 1)) recent-users (set/difference - (set (gateway/get-some-recent-event-authors (get-db) after)) - (set (get-mem [:user-window :trusted-users]))) - recent-user-items (make-sorted-listbox-items recent-users) - selected-listbox (select frame [:#selected-users])] + (set (gateway/get-some-recent-event-authors (get-db) after)) + (set (get-mem [:user-window :trusted-users]))) + recent-user-items (make-sorted-listbox-items recent-users)] (set-mem [:user-window :recent-users] recent-users) - (set-mem [:user-window :recent-user-items] recent-user-items) - (config! selected-listbox :model recent-user-items))) + (set-mem [:user-window :recent-user-items] recent-user-items))) (defn load-trusted-users [] (let [trusted-users (contact-list/get-trustees)] @@ -62,48 +52,99 @@ (set-mem [:user-window :web-of-trust-items] (make-sorted-listbox-items web-of-trust-users)))) - (defn load-user-window-data [] - (load-trusted-users) +(defn load-user-window-data [] + (load-trusted-users) + (load-recent-users)) + +(defn select-recent-users [frame _e] + (set-mem [:user-window :selection-group] :recent-user-items) + (load-recent-users) + (let [selected-listbox (select frame [:#selected-users])] + (config! selected-listbox :model (get-mem [:user-window :recent-user-items])))) + +(defn select-web-of-trust [frame _e] + (set-mem [:user-window :selection-group] :web-of-trust-items) + (when (nil? (get-mem [:user-window :web-of-trust-items])) (load-web-of-trust-users)) + (config! (select frame [:#selected-users]) + :model (get-mem [:user-window :web-of-trust-items]))) - (defn make-users-frame [_e] - (let [users-menu (select (get-mem :frame) [:#users-menu]) - users-frame (frame :title "Users") - trusted-users-listbox (listbox :id :trusted-users-listbox - :font config/default-font - :renderer render-listbox-item) - trusted-users-panel (vertical-panel - :items [(label "Trusted") - (scrollable trusted-users-listbox :size [500 :by 800])]) - trust-button (button :text "<-" - :listen [:action (partial trust-selection users-frame)]) - selection-group (button-group) - web-of-trust-button (radio :text "Web of trust" - :group selection-group - :selected? true - :listen [:action (partial load-web-of-trust-authors users-frame)]) - recent-button (radio :text "Recent users" - :group selection-group - :listen [:action (partial load-recent-users users-frame)]) +(defn remove-item [id items-tag ids-tag] + (let [items (remove #(= id (second %)) (get-mem [:user-window items-tag])) + ids (remove #(= id %) (get-mem [:user-window ids-tag]))] + (set-mem [:user-window items-tag] items) + (set-mem [:user-window ids-tag] ids))) - search-field (text :text "" :editable? true) - selected-listbox (listbox :id :selected-users - :font config/default-font - :renderer render-listbox-item) - scrollable-selected-listbox (scrollable selected-listbox - :size [500 :by 800]) - selection-panel (vertical-panel :items [web-of-trust-button - recent-button - search-field - scrollable-selected-listbox]) +(defn find-item [id items] + (loop [items items] + (if (empty? items) + nil + (let [item (first items)] + (if (= id (second item)) + item + (recur (rest items))))))) + +(defn trust-selection [frame _e] + (let [selected-listbox (select frame [:#selected-users]) + selected-item (selection selected-listbox) + group (get-mem [:user-window :selection-group])] + (when (some? selected-item) + (let [pubkey (second selected-item) + petname (trust-updater/ask-for-petname pubkey) + trusted-listbox (select frame [:#trusted-users-listbox])] + (when (some? petname) + (let [contact-list (trust-updater/entrust pubkey petname)] + (when-not config/is-test-run? + (event-composers/compose-and-send-contact-list contact-list)) + (load-trusted-users) + (let [trusted-items (get-mem [:user-window :trusted-user-items]) + new-trusted-item (find-item pubkey trusted-items)] + (config! trusted-listbox :model trusted-items) + (remove-item pubkey :web-of-trust-items :web-of-trust-users) + (remove-item pubkey :recent-user-items :recent-users) + (config! (select frame [:#selected-users]) + :model (get-mem [:user-window group])) + (.setSelectedValue trusted-listbox + new-trusted-item true)))))))) + +(defn make-users-frame [_e] + (let [users-menu (select (get-mem :frame) [:#users-menu]) + users-frame (frame :title "Users") + trusted-users-listbox (listbox :id :trusted-users-listbox + :font config/default-font + :renderer render-listbox-item) + trusted-users-panel (vertical-panel + :items [(label "Trusted") + (scrollable trusted-users-listbox :size [500 :by 800])]) + trust-button (button :text "<-" + :listen [:action (partial trust-selection users-frame)]) + selection-group (button-group) + web-of-trust-button (radio :text "Web of trust" + :group selection-group + :selected? false + :listen [:action (partial select-web-of-trust users-frame)]) + recent-button (radio :text "Recent users" + :group selection-group + :selected? true + :listen [:action (partial select-recent-users users-frame)]) + + selected-listbox (listbox :id :selected-users + :font config/default-font + :renderer render-listbox-item) + scrollable-selected-listbox (scrollable selected-listbox + :size [500 :by 800]) + selection-panel (vertical-panel :items [web-of-trust-button + recent-button + scrollable-selected-listbox]) - users-panel (horizontal-panel :items [trusted-users-panel trust-button selection-panel])] - (load-user-window-data) - (config! trusted-users-listbox :model (get-mem [:user-window :trusted-user-items])) - (config! selected-listbox :model (get-mem [:user-window :web-of-trust-items])) - (config! users-frame :content users-panel) - (listen users-frame :window-closing (partial close-users-frame users-menu)) - (config! users-menu :enabled? false) - (pack! users-frame) - (show! users-frame))) + users-panel (horizontal-panel :items [trusted-users-panel trust-button selection-panel])] + (set-mem [:user-window :selection-group] :recent-user-items) + (load-user-window-data) + (config! trusted-users-listbox :model (get-mem [:user-window :trusted-user-items])) + (config! selected-listbox :model (get-mem [:user-window :recent-user-items])) + (config! users-frame :content users-panel) + (listen users-frame :window-closing (partial close-users-frame users-menu)) + (config! users-menu :enabled? false) + (pack! users-frame) + (show! users-frame)))