edufeed-web/src/ied/events.cljs
2024-11-21 16:27:08 +01:00

816 lines
29 KiB
Clojure

(ns ied.events
(:require
[re-frame.core :as re-frame]
[ied.config :as config]
[ied.db :as db]
[day8.re-frame.tracing :refer-macros [fn-traced]]
[ied.nostr :as nostr]
[day8.re-frame.http-fx]
[promesa.core :as p]
[wscljs.client :as ws]
[wscljs.format :as fmt]
[clojure.string :as str]
[clojure.set :as set]
[superstructor.re-frame.fetch-fx]
[ajax.core :as ajax]
["js-confetti" :as jsConfetti]
[js-confetti :as jsConfetti]))
(re-frame/reg-event-db
::initialize-db
(fn-traced [_ _]
db/default-db))
(re-frame/reg-event-fx
::navigate
(fn-traced [_ [_ handler]]
{:dispatch [::set-visit-timestamp]
:navigate handler}))
(re-frame/reg-event-fx
::set-active-panel
(fn-traced [{:keys [db]} [_ active-panel]]
{:db (assoc db :active-panel active-panel)}))
(re-frame/reg-event-fx
::set-route
(fn-traced [{:keys [db]} [_ route]]
{:db (assoc db :route route)}))
(def confetti-instance
(new jsConfetti))
(re-frame/reg-fx
::add-confetti
(fn [cofx _]
(let [visited-at (-> cofx :db :visited-at)
now (quot (.now js/Date) 1000)
diff (- now visited-at)]
(when (-> cofx :db :confetti)
(when (>= diff 5)
(.addConfetti confetti-instance (clj->js {:emojis ["😺" "🐈‍⬛" "🦄"]}))))
{})))
(re-frame/reg-fx
::relay-list
(fn [event]
(when (= 30002 (:kind event))
(.log js/console "got a relay list!"))))
;; Database Event?
(re-frame/reg-event-fx
::save-event
;; TODO if EOSE retrieved end connection identified by uri
(fn-traced [{:keys [db]} [_ [uri raw-event]]]
(let [event (nth raw-event 2 raw-event)]
(when (and
(= (first raw-event) "EVENT"))
{:fx [[::add-confetti]
[::relay-list event]]
:db (update db :events conj event)}))))
(defn handlers
[ws-uri]
{:on-message (fn [e] (re-frame/dispatch [::save-event [ws-uri (-> (.-data e)
js/JSON.parse
(js->clj :keywordize-keys true))]]))
:on-open #(re-frame/dispatch [::load-events ws-uri])
:on-close #(prn "Closing a connection")
:on-error (fn [e] (.log js/console "Error with uri: " ws-uri (clj->js e))
(re-frame/dispatch [::update-ws-connection-status ws-uri "error"]))})
(re-frame/reg-event-db
::update-ws-connection-status
(fn [db [_ ws-uri status]]
(let [target-ws (first (filter #(= ws-uri (:uri %)) (:sockets db)))]
(assoc db
:sockets
(assoc (:sockets db)
(.indexOf (:sockets db) target-ws)
(merge target-ws {:status status}))))))
(re-frame/reg-event-fx
::load-events
(fn-traced [cofx [_ ws-uri]]
{::load-events-fx [ws-uri (-> cofx :db :sockets)]}))
(re-frame/reg-fx
::load-events-fx
(fn [[ws-uri sockets]]
(println "loading events")
(let [target-ws (first (filter #(= ws-uri (:uri %)) sockets))]
(ws/send (:socket target-ws) ["REQ" "424242" {:kinds [30004 30142]
:limit 100}] fmt/json)
; (ws/close (:socket (first @sockets))) ;; should be handled otherwise (?)
)))
(defn create-socket
[uri]
(println "creating socket with uri" uri)
(ws/create uri (handlers uri)))
(re-frame/reg-event-fx
::create-websocket
;; ws {:id uuid
;; :uri
;; :name
;; :status connected | disconnected | error}
(fn-traced [{:keys [db]} [_ ws]]
(if (some #(= (:uri ws) (:uri %)) (:sockets db))
(doall
(println "uri already there" (:uri ws))
{:db (assoc db
:sockets
(assoc (:sockets db)
(.indexOf (:sockets db) ws)
(merge ws {:socket (create-socket (:uri ws))
:status "connected"})))})
(doall
(println "uri not yet known")
{:db (update db :sockets conj (merge ws {:socket (create-socket (:uri ws))
:status "connected"}))}))))
(re-frame/reg-event-fx
::connect-to-websocket
(fn-traced [{:keys [db]} [_ ws-uri]]
{::connect-to-websocket-fx [ws-uri (:sockets db)]}))
(re-frame/reg-fx
::connect-to-websocket-fx
(fn [[ws-uri sockets]]
(let [target-ws (first (filter #(= ws-uri (:uri %)) sockets))]
(re-frame/dispatch [::create-websocket target-ws]))))
;; TODO use id to close socket
;; add connection status to socket
;; render connect / disconnect button based on status
(re-frame/reg-event-fx
::close-connection-to-websocket
(fn-traced [{:keys [db]} [_ ws-uri]]
{::close-connection-to-websocket-fx [ws-uri (:sockets db)]}))
(re-frame/reg-fx
::close-connection-to-websocket-fx
(fn [[ws-uri sockets]]
(ws/close (:socket (first (filter #(= ws-uri (:uri %)) sockets))))
(re-frame/dispatch [::update-ws-connection-status ws-uri "disconnected"])))
(re-frame/reg-event-fx
::connect-to-default-relays
(fn-traced [cofx [_ default-relays]]
{::connect-to-default-relays-fx default-relays}))
(re-frame/reg-fx
::connect-to-default-relays-fx
(fn [default-relays]
(doall
(for [r default-relays]
(re-frame/dispatch [::create-websocket r])))))
;; TODO
(re-frame/reg-event-fx
::publish-signed-event
(fn-traced [cofx [_ signedEvent]]
(let [sockets (filter
(fn [s]
(some #(= "outbox" %)
(:type s)))
(-> cofx :db :sockets))
_ (.log js/console "available sockets " (clj->js sockets))]
{::send-to-relays-fx [sockets signedEvent]})))
(re-frame/reg-fx
::send-to-relays-fx
(fn [[sockets signedEvent]]
(let [connected-sockets (filter #(= "connected" (:status %)) sockets)]
(doseq [socket connected-sockets]
(ws/send (:socket socket) ["EVENT" signedEvent] fmt/json)))))
(re-frame/reg-event-db
::update-websockets
(fn [db [_ sockets]]
(assoc db :sockets sockets)))
(re-frame/reg-event-fx
::remove-websocket
(fn-traced [{:keys [db]} [_ socket]]
{::remove-websocket-fx [(:id socket) (:sockets db)]}))
(re-frame/reg-fx
::remove-websocket-fx
(fn [[id sockets]]
(let [filtered (filter #(not= id (:id %)) sockets)] ;; TODO maybe this can also be done using the URI
(re-frame/dispatch [::update-websockets filtered]))))
(re-frame/reg-event-db
::toggle-show-add-event
(fn [db _]
(assoc db :show-add-event (not (:show-add-event db)))))
;; TODO just pass an event here that is then passed on to signing
(re-frame/reg-event-fx
::publish-resource
[(re-frame/inject-cofx :now)]
(fn-traced [cofx _]
;; TODO hier muss ich den ansatz ändern, es ist vmtl sinnvoller durch alle keys in md-form-resource zu iterieren und abhängig davon die tags zu bauen
;; -> vllt kann ich einfach eine Funktion bauen, die md-form resource amb-konform verwandet und dann die funktion zur publikation von amb daten recyclen
(let [form-data (-> cofx :db :md-form-resource)
about (map (fn [e] ["about"
(:id e)
(second (first (filter (fn [l]
(= :de (first l)))
(:prefLabel e))))
"de"])
(:about form-data)) ;; TODO this should be abstracted in a nostr-make-event-kind-function or sth
tags [["d" (:uri form-data)]
["id" (:uri form-data)]
["author" "" (:author form-data)]
["name" (:name form-data)]]
event {:kind 30142
:created_at (:now cofx)
:content ""
:tags (into tags about)}
_ (.log js/console "Event to publish " (clj->js event))]
{:navigate [:home]
::sign-and-publish-event [event (-> cofx :db :sk)]
:db (assoc (:db cofx) :md-form-resource nil)})))
(defn sign-event [unsignedEvent sk]
(if (nostr/valid-unsigned-nostr-event? unsignedEvent)
(p/let [_ (js/console.log (clj->js unsignedEvent))
signedEvent (if (nil? sk)
(.nostr.signEvent js/window (clj->js unsignedEvent))
(nostr/finalize-event unsignedEvent sk))
_ (js/console.log "Signed event: " (clj->js signedEvent))]
signedEvent)
(.error js/console "Event is not a valid nostr event: " (clj->js unsignedEvent))))
;; TODO maybe we need some validation before publishing
(re-frame/reg-fx
::sign-and-publish-event
(fn [[unsignedEvent sk]]
(p/let [signedEvent (sign-event unsignedEvent sk)]
(re-frame/dispatch [::publish-signed-event signedEvent]))))
;; TODO make login a multimethod and call it with either extension or anononymslouy keyword?
(re-frame/reg-event-fx
::login-with-extension
(fn-traced [cofx [_ _]]
{::login-with-extension-fx _}))
(re-frame/reg-fx
::login-with-extension-fx
(fn [db _]
(p/let [pk (.nostr.getPublicKey js/window)]
(re-frame/dispatch [::save-pk pk])
(re-frame/dispatch [::relay-list-for-pk pk]))))
(re-frame/reg-event-fx
::save-pk
(fn-traced [{:keys [db]} [_ pk]]
{:db (assoc db :pk pk)
:dispatch [::get-lists-for-npub (nostr/get-npub-from-pk pk)]}))
(re-frame/reg-event-db
::logout
(fn-traced [db _]
(assoc db :pk nil :sk nil)))
(re-frame/reg-cofx
:now
(fn [cofx _data] ;; _data unused
(assoc cofx :now (quot (.now js/Date) 1000))))
(re-frame/reg-cofx
:sk
(fn [cofx _]
(assoc cofx :sk (:sk cofx))))
(re-frame/reg-cofx
:pk
(fn [cofx _]
(assoc cofx :pk (:pk cofx))))
(defn convert-amb-to-nostr-event
[parsed-json created_at]
(let [tags (into [["d" (:id parsed-json)]
["r" (:id parsed-json)]
["id" (:id parsed-json)]
["name" (:name parsed-json)]
["description" (:description parsed-json "")]
(into ["keywords"] (:keywords parsed-json))
["image" (:image parsed-json "")]]
cat [(map (fn [e] ["about" (:id e) (-> e :prefLabel :de) "de"]) (:about parsed-json)) ;; TODO fix the language parsing and make it generic
(map (fn [e] ["creator"
(if-let [id (get e :id)]
id
"")
(:name e)])
(:creator parsed-json))
(map (fn [e] ["inLanguage" e]) (:inLanguage parsed-json))])
event {:kind 30142
:created_at created_at
:content ""
:tags tags}]
event))
(re-frame/reg-event-fx
::convert-amb-string-and-publish-as-nostr-event
[(re-frame/inject-cofx :now)]
(fn-traced [cofx [_ json-string]]
(let [parsed-json (js->clj (js/JSON.parse json-string) :keywordize-keys true)
event (convert-amb-to-nostr-event parsed-json (:now cofx))]
{::sign-and-publish-event [event (-> cofx :db :sk)]})))
(re-frame/reg-event-fx
::convert-amb-json-and-publish-as-nostr-event
[(re-frame/inject-cofx :now)]
(fn-traced [cofx [_ json]]
(let [event (convert-amb-to-nostr-event json (:now cofx))]
{::sign-and-publish-event [event (-> cofx :db :sk)]})))
(re-frame/reg-event-fx
::toggle-selected-events
(fn [{:keys [db]} [_ event]]
(let [selected-event-ids (set (map (fn [e] (:id e)) (:selected-events db)))]
(if (and (seq (:selected-events db))
(contains? selected-event-ids (:id event)))
{:db (assoc db :selected-events (filter #(not= (:id event) (:id %)) (:selected-events db)))}
{:db (update db :selected-events conj event)}))))
(re-frame/reg-event-db
::toggle-selected-list-ids
(fn [db [_ id]]
(println "Toggle list ids: " id)
(let [in-selected-list-ids (contains? (:selected-list-ids db) id)]
(if in-selected-list-ids
(update db :selected-list-ids disj id)
(update db :selected-list-ids conj id)))))
(re-frame/reg-event-fx
::add-metadata-event-to-list
[(re-frame/inject-cofx :now)]
(fn [cofx [_ [list resources-to-add]]]
(let [existing-tags (:tags list)
existing-tags-set (set existing-tags)
tags-to-add (filter #(not (contains? existing-tags-set %))
(map (fn [e] (cond
(= 1 (:kind e)) ["e" (:id e)]
(= 30142 (:kind e)) (nostr/build-tag-for-adressable-event e)))
resources-to-add))
new-tags (vec (concat existing-tags tags-to-add))
event {:kind 30004
:created_at (:now cofx)
:content ""
:tags new-tags}]
{::sign-and-publish-event [event (-> cofx :db :sk)]})))
(re-frame/reg-event-fx
::add-metadata-events-to-lists
(fn [cofx [_ [events lists]]]
(let [dispatch-events (mapv (fn [l] [::add-metadata-event-to-list [l events]]) lists)
_ (.log js/console (clj->js dispatch-events))]
{:fx [[:dispatch-n dispatch-events]]})))
(defn sanitize-subscription-id [s]
(str/join "" (take 64 s)))
(defn make-sub-id [prefix id]
(-> (str prefix id)
(sanitize-subscription-id)))
(re-frame/reg-event-fx
::get-lists-for-npub
(fn [{:keys [db]} [_ npub]]
(let [query-for-lists ["REQ"
(make-sub-id "lists-" npub) ;; TODO maybe make this more explicit later
{:authors [(nostr/get-pk-from-npub npub)]
:kinds (concat (:follow-sets db) (:list-kinds db))}]
sockets (:sockets db)]
{::request-from-relay [sockets query-for-lists]
:dispatch [::get-deleted-lists-for-npub [sockets npub]]})))
(re-frame/reg-event-fx
::relay-list-for-pk
(fn [{:keys [db]} [_ pk]]
(.log js/console "get relay list for pk" pk)
(let [query-for-relay-list ["REQ"
(make-sub-id "relay-lists-" pk) ;; TODO maybe make this more explicit later
{:authors [pk]
:kinds [30002]}]
sockets (:sockets db)]
{::request-from-relay [sockets query-for-relay-list]})))
(re-frame/reg-event-fx
::get-follow-set-for-npub
(fn [{:keys [db]} [_ npub]]
(let [query-for-lists ["REQ"
(make-sub-id "follow-set-" npub) ;; TODO maybe make this more explicit later
{:authors [(nostr/get-pk-from-npub npub)]
:kinds (:follow-sets db)}]
sockets (:sockets db)]
{::request-from-relay [sockets query-for-lists]})))
(re-frame/reg-event-fx
::get-deleted-lists-for-npub
(fn [cofx [_ [sockets npub]]]
(let [query-for-deleted-lists ["REQ"
(make-sub-id "deleted-lists-" npub) ;; TODO maybe make this more explicit later
{:authors [(nostr/get-pk-from-npub npub)]
:kinds [5]}]]
{::request-from-relay [sockets query-for-deleted-lists]})))
(re-frame/reg-event-fx
::events-from-pks-actor-follows
(fn [{:keys [db]} [_ pks]]
(.log js/console "requesting events from pks actor follows..")
(let [query-for-events ["REQ"
(make-sub-id "events-from-pks-actor-follows" (:pk db))
{:authors pks
:kinds [1]
:limit 10}]] ;; TODO remember timestamps and use them in query
{::request-from-relay [(:sockets db) query-for-events]})))
(re-frame/reg-fx
::request-from-relay
(fn [[sockets query]]
(doall
(for [s (filter (fn [s] (= "connected" (:status s))) sockets)]
(ws/send (:socket s) query fmt/json)))))
(re-frame/reg-event-fx
::query-for-event-ids
(fn [db [_ [sockets event-ids]]]
(let [query ["REQ"
"RAND42"
{:ids event-ids}]]
{::request-from-relay [sockets query]})))
(defn cleanup-list-name [s]
(-> s
(str/replace #"\s" "-")
(str/replace #"[^a-zA-Z0-9]" "-")))
(re-frame/reg-event-fx
::create-new-list
[(re-frame/inject-cofx :now)]
(fn [cofx [_ name]]
(let [tags [["d" (cleanup-list-name name)]
["title" name]]
create-list-event {:kind 30004
:created_at (:now cofx)
:content ""
:tags tags}]
{::sign-and-publish-event [create-list-event (-> cofx :db :sk)]})))
;;;;;;;;;;;;;;;;;;;;;;;;
;; Opencard stuff
;;;;;;;;;;;;;;;;;;;;;;;;
(re-frame/reg-event-fx
::create-new-opencard-index
[(re-frame/inject-cofx :now)]
(fn [cofx [_ name]]
(let [tags [["d" (cleanup-list-name name)]
["title" name]]
create-opencard-index-event {:kind 30043
:created_at (:now cofx)
:content ""
:tags tags}]
{::sign-and-publish-event [create-opencard-index-event (-> cofx :db :sk)]})))
;; create, sign, publish list event
;; add signed list event to opencard-index
(re-frame/reg-event-fx
::add-opencard-list-to-index
(fn [cofx [_ [name opencard-index-old]]]
(let [opencard-list {:kind 30044
:created_at (:now cofx)
:content ""
:tags [["d" (cleanup-list-name name)]
["title" name]]}
opencard-index (update opencard-index-old :created_at (:now cofx))]
{::add-opencard-list-to-index-fx [opencard-list opencard-index (-> cofx :db :sk)]})))
(re-frame/reg-fx
::add-opencard-list-to-index-fx
(fn [opencard-list opencard-index sk]
(p/let [opencard-list-signed (sign-event opencard-list sk)
opencard-index (update opencard-index :tags (fn [tags]
(conj tags ["a" (nostr/build-tag-for-adressable-event opencard-list-signed)])))
opencard-index-signed (sign-event opencard-index sk)]
(re-frame/dispatch [::publish-signed-event opencard-list-signed])
(re-frame/dispatch [::publish-signed-event opencard-index-signed]))))
(re-frame/reg-event-fx
::remove-opencard-list-from-index
[(re-frame/inject-cofx :now)]
(fn [cofx [_ opencard-list-to-delete opencard-index]]
(let [opencard-index-new {:kind 30043
:created_at (:now cofx)
:content ""
:tags (filter #(not= (:id opencard-list-to-delete) (:id %)) (:tags opencard-index))}]
{::sign-and-publish-event [opencard-index-new (-> cofx :db :sk)]
::delete-list [opencard-list-to-delete]})))
;; TODO add 30045 opencard note to opencard-list
(re-frame/reg-event-fx
::add-opencard-note-to-list
[(re-frame/inject-cofx :now)]
(fn [cofx [_ [name content] opencard-list]]
(let [tags [["d" (cleanup-list-name name)]
["title" name]] ;; TODO depending on the note content we might need to add more tags like references to other events and so on
opencard-note-event {:kind 30045
:created_at (:now cofx)
:content content
:tags tags}]
{::sign-and-publish-event [opencard-note-event (-> cofx :db :sk)]})))
;; TODO delete-opencard-index
;; should we just remove the index or anything associated? maybe ask the user first
(re-frame/reg-event-fx
::delete-list
[(re-frame/inject-cofx :now)]
(fn [cofx [_ l]]
(let [{:keys [list-kinds opencard-kinds]} (:db cofx)
all-list-kinds (concat list-kinds opencard-kinds)
deletion-event {:kind 5
:created_at (:now cofx)
:content ""
:tags [(cond
(= 1 (:kind l))
["e" (:id l)]
(some #{(:kind l)} all-list-kinds)
["a" (str (:kind l) ":" (:pubkey l) ":" (second (first (filter
#(= "d" (first %))
(:tags l)))))])]}]
{::sign-and-publish-event [deletion-event (-> cofx :db :sk)]})))
(re-frame/reg-event-db
::toggle-show-lists-modal
(fn [db _]
(assoc db :show-lists-modal (not (:show-lists-modal db)))))
(re-frame/reg-event-db
::toggle-show-create-list-modal
(fn [db _]
(assoc db :show-create-list-modal (not (:show-create-list-modal db)))))
(re-frame/reg-event-db
::toggle-show-event-data-modal
(fn [db [_ event]]
(assoc db
:show-event-data-modal (not (:show-event-data-modal db))
:selected-event event)))
(re-frame/reg-event-fx
::delete-event-from-list
[(re-frame/inject-cofx :now)]
(fn [cofx [_ [event list]]]
(let [filtered-tags (filterv (fn [t] (not= (:id event) (nostr/extract-id-from-tag (second t)))) (:tags list))
_ (println (:tags list))
_ (.log js/console "Filtered Tags: " (clj->js filtered-tags))
event {:kind 30004
:created_at (:now cofx)
:content ""
:tags filtered-tags}]
{::sign-and-publish-event [event (-> cofx :db :sk)]})))
(re-frame/reg-event-db
::create-sk
(fn [db [_]]
(let [sk (nostr/generate-sk)
pk (nostr/get-pk-from-sk sk)]
(assoc db :sk sk :pk pk))))
(re-frame/reg-fx
::get-amb-json-from-uri
(fn [uri]
(p/let [raw-html (js/fetch uri {:headers {"Access-Control-Allow-Origin" "*"}})]
(println raw-html))))
(re-frame/reg-event-fx
::publish-amb-uri-as-nostr-event
(fn [db [_ uri]]
{:http-xhrio {:method :get
:uri uri
:timeout 8000
:response-format (ajax/json-response-format {:keywords? true})
:on-success [::convert-amb-json-and-publish-as-nostr-event]
:on-failure (.log js/console "publishing amb uri as nostr did not work")}}))
(re-frame/reg-event-fx
::set-visit-timestamp
[(re-frame/inject-cofx :now)]
(fn [cofx [_]]
{:db (assoc (:db cofx) :visited-at (:now cofx))}))
;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Get metadata from uri ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn valid-uri? [s]
(try
(js/URL. s)
true
(catch :default e false)))
(re-frame/reg-event-fx
::try-get-metadata-from-uri
(fn [cofx [_ uri]]
(when (valid-uri? uri)
(println "valid uri" (valid-uri? uri))
{:dispatch [::get-metadata-from-json uri]})))
(re-frame/reg-fx
::try-get-metadata-from-uri-fx
(fn [uri]
(try
(println "trying to get metadata from json")
(re-frame/dispatch [::get-metadata-from-json uri])
(catch :default e
(println "... did not work..looking for script tag")
(try
(re-frame/dispatch [::get-metadata-from-script-tag uri])
(catch :default e
(js/console.error "all attempts to fetch something sensible failed.")))))))
(re-frame/reg-event-db
::prefill-metadata-form
(fn [db [_ uri data]]
(if (and
(:id data)
(:about data))
(assoc db :resource-to-add data)
(doall (js/console.error "Not the right kind of data")
(re-frame/dispatch [::get-metadata-from-script-tag uri])))))
(re-frame/reg-event-fx
::failure
(fn [cofx _]
(println "failure in xhrio request")))
(re-frame/reg-event-db
::parse-text-for-script-tag
(fn [db [_ uri data]]
(let [parser (js/DOMParser.)
doc (.parseFromString parser data "text/html")
script-tag (.querySelector doc "script[type='application/ld+json']")]
(if script-tag
(let [ld-json (js/JSON.parse (.-textContent script-tag))]
(assoc db :resource-to-add (js->clj ld-json)))
(println "did not get script tag")))))
(re-frame/reg-event-fx
::get-metadata-from-script-tag
(fn [cofx [_ uri]]
(println "now trying to get script tag..")
{:http-xhrio {:method :get
:uri uri
:timeout 3000
:response-format (ajax/text-response-format)
:on-success [::parse-text-for-script-tag uri]
:on-failure [::failure]}}))
(re-frame/reg-event-fx
::get-metadata-from-json
(fn [cofx [_ uri]]
{:http-xhrio {:method :get
:uri (if (str/ends-with? uri "json") ;; TODO elaborate this a bit more
uri
(str/replace uri #".html" ".json"))
:timeout 3000
:response-format (ajax/json-response-format {:keywords? true})
:on-success [::prefill-metadata-form uri]
:on-failure [::get-metadata-from-script-tag uri]}}))
(re-frame/reg-event-db
::save-concept-scheme
(fn [db [_ cs]]
(assoc-in db [:concept-schemes (:id cs)] cs)))
(comment
(keyword "https://ww.googl-e.com/"))
(defn jsonize-uri
[uri]
(cond
(str/ends-with? uri ".json")
uri
(str/ends-with? uri ".html")
(str/replace uri #"\.\w{4}" ".json")
:else
(str uri ".json")))
(comment
(jsonize-uri "https:/goo"))
(re-frame/reg-event-fx
::skos-concept-scheme-from-uri
(fn [cofx [_ uri]]
{:http-xhrio {:method :get
:uri (jsonize-uri uri)
:timeout 5000
:response-format (ajax/json-response-format {:keywords? true})
:on-success [::save-concept-scheme]
:on-failure [::failure]}}))
(re-frame/reg-event-db
::toggle-concept
(fn [db [_ [concept field]]]
(update-in db [:md-form-resource field] (fn [coll]
(if (some #(= (:id concept) (:id %)) coll)
(filter (fn [e] (not= (:id e) (:id concept))) coll)
(conj coll (select-keys concept [:id :notation :prefLabel] )))))))
(re-frame/reg-event-db
::handle-md-form-input
(fn [db [_ [field-name field-value]]]
(assoc-in db [:md-form-resource field-name] field-value)))
(re-frame/reg-event-db
::handle-md-form-array-input
(fn [db [_ [field-name field-id field-value]]]
(assoc-in db [:md-form-resource field-name field-id] field-value)))
(re-frame/reg-event-db
::handle-md-form-rm-input
(fn [db [_ [field-name field-id]]]
(update-in
db
[:md-form-resource field-name]
dissoc
field-id)))
(re-frame/reg-event-db
::handle-md-form-add-input
(fn [db [_ [field-name]]]
(assoc-in db [:md-form-resource field-name (random-uuid)] nil)))
(re-frame/reg-event-fx
::handle-search
(fn [cofx [_ search-term]]
(let [uri (str config/typesense-uri
"search?q="
search-term
"&query_by="
"name,about,description,creator")]
{:http-xhrio {:method :get
:uri uri
:headers {"x-typesense-api-key" "xyz"}
:timeout 5000
:response-format (ajax/json-response-format {:keywords? true})
:on-success [::save-search-results]
:on-failure [::failure]}})))
(defn sanitize-filter-term [term]
(str/replace term #"[ ()]" " "))
(re-frame/reg-event-fx
::handle-filter-search
(fn [cofx [_ [filter-attribute filter-term]]]
(let [uri (str config/typesense-uri
"search?q=*"
"&query_by="
"name"
"&filter_by="
filter-attribute
":="
(sanitize-filter-term filter-term ))] ;; parantetheses seem to cause error when filtering
{:http-xhrio {:method :get
:uri uri
:headers {"x-typesense-api-key" "xyz"}
:timeout 5000
:response-format (ajax/json-response-format {:keywords? true})
:on-success [::save-search-results]
:on-failure [::failure]}})))
(re-frame/reg-event-db
::save-search-results
(fn [db [_ results]]
(let [raw-result-events (map #(-> % :document :event_raw) (:hits results))]
(-> db
(assoc :search-results (:hits results))
(update :events into raw-result-events)))))
(re-frame/reg-event-fx
::load-profile
(fn [cofx [_ pubkey]]
(let [sockets (filter #(= "connected" (:status %)) (-> cofx :db :sockets))
profile-request ["REQ"
(make-sub-id "profile" pubkey)
{:kinds [0]
:authors [pubkey]
:limit 10}]]
{::request-from-relay [sockets profile-request]})))
(re-frame/reg-event-db
::set-md-scheme
(fn [db [_ md-scheme]]
(assoc db :selected-md-scheme md-scheme)))