From e5ff9265b4c94fbff5aa23ed1d43b6b37ff3cee0 Mon Sep 17 00:00:00 2001 From: "@s.roertgen" Date: Wed, 20 Nov 2024 15:22:40 +0100 Subject: [PATCH] Endpoint working and validating against amb schema --- .../io.pedestal/pedestal.log/config.edn | 18 +++ .../hooks/io/pedestal/log.clj_kondo | 26 ++++ deps.edn | 6 +- resources/schema.json | 121 ++++++++++++++++++ src/app/components/webserver.clj | 102 +++++++++++++-- 5 files changed, 260 insertions(+), 13 deletions(-) create mode 100644 .clj-kondo/imports/io.pedestal/pedestal.log/config.edn create mode 100644 .clj-kondo/imports/io.pedestal/pedestal.log/hooks/io/pedestal/log.clj_kondo create mode 100644 resources/schema.json diff --git a/.clj-kondo/imports/io.pedestal/pedestal.log/config.edn b/.clj-kondo/imports/io.pedestal/pedestal.log/config.edn new file mode 100644 index 0000000..bb8b71c --- /dev/null +++ b/.clj-kondo/imports/io.pedestal/pedestal.log/config.edn @@ -0,0 +1,18 @@ +; Copyright 2024 Nubank NA + +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0) +; which can be found in the file epl-v10.html at the root of this distribution. +; +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; +; You must not remove this notice, or any other, from this software. + +{:hooks + {:analyze-call + {io.pedestal.log/trace hooks.io.pedestal.log/log-expr + io.pedestal.log/debug hooks.io.pedestal.log/log-expr + io.pedestal.log/info hooks.io.pedestal.log/log-expr + io.pedestal.log/warn hooks.io.pedestal.log/log-expr + io.pedestal.log/error hooks.io.pedestal.log/log-expr}}} diff --git a/.clj-kondo/imports/io.pedestal/pedestal.log/hooks/io/pedestal/log.clj_kondo b/.clj-kondo/imports/io.pedestal/pedestal.log/hooks/io/pedestal/log.clj_kondo new file mode 100644 index 0000000..8744765 --- /dev/null +++ b/.clj-kondo/imports/io.pedestal/pedestal.log/hooks/io/pedestal/log.clj_kondo @@ -0,0 +1,26 @@ +; Copyright 2024 Nubank NA + +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0) +; which can be found in the file epl-v10.html at the root of this distribution. +; +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; +; You must not remove this notice, or any other, from this software. + +(ns hooks.io.pedestal.log + (:require [clj-kondo.hooks-api :as api])) + +(defn log-expr + "Expands (log-expr :a :A :b :B ... ) + to (hash-map :a :A :b :B ... ) per clj-kondo examples." + [{:keys [:node]}] + (let [[k v & _kvs] (rest (:children node))] + (when-not (and k v) + (throw (ex-info "No kv pair provided" {}))) + (let [new-node (api/list-node + (list* + (api/token-node 'hash-map) + (rest (:children node))))] + {:node (vary-meta new-node assoc :clj-kondo/ignore [:unused-value])}))) diff --git a/deps.edn b/deps.edn index 09aadd7..72b9e71 100644 --- a/deps.edn +++ b/deps.edn @@ -1,8 +1,10 @@ -{:deps {org.clojure/clojure {:mvn/version "1.12.0"} +{:paths ["src" "resources"] + :deps {org.clojure/clojure {:mvn/version "1.12.0"} com.stuartsierra/component {:mvn/version "1.1.0"} - io.pedestal/pedestal.service {:mvn/version "0.7.2"} + cheshire/cheshire {:mvn/version "5.13.0"} io.pedestal/pedestal.jetty {:mvn/version "0.7.1"} org.slf4j/slf4j-simple {:mvn/version "2.0.10"} + luposlip/json-schema {:mvn/version "0.4.6"} net.clojars.laoc/nostr {:local/root "/home/laoc/coding/nostr-clj"}} :aliases diff --git a/resources/schema.json b/resources/schema.json new file mode 100644 index 0000000..fb2622d --- /dev/null +++ b/resources/schema.json @@ -0,0 +1,121 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://w3id.org/kim/amb/20231019/schemas/schema.json", + "title": "OER", + "description": "This is a generic JSON schema for describing an Open Educational Resource with schema.org", + "type": "object", + "default": { + "@context": [ + "https://w3id.org/kim/amb/context.jsonld", + { + "@language": "de" + } + ], + "type": ["LearningResource"] + }, + "properties": { + "@context": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/context-schema.json" + }, + "id": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/id.json" + }, + "type": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/type.json" + }, + "name": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/name.json" + }, + "creator": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/creator.json" + }, + "contributor": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/contributor.json" + }, + "description": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/description.json" + }, + "about": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/about.json" + }, + "license": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/license.json" + }, + "image": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/image.json" + }, + "trailer": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/trailer.json" + }, + "dateCreated": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/dateCreated.json" + }, + "datePublished": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/datePublished.json" + }, + "dateModified": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/dateModified.json" + }, + "duration": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/duration.json" + }, + "inLanguage": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/inLanguage.json" + }, + "publisher": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/publisher.json" + }, + "learningResourceType": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/learningResourceType.json" + }, + "audience": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/audience.json" + }, + "isBasedOn": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/isBasedOn.json" + }, + "isPartOf": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/isPartOf.json" + }, + "hasPart": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/hasPart.json" + }, + "mainEntityOfPage": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/mainEntityOfPage.json" + }, + "keywords": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/keywords.json" + }, + "encoding": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/encoding.json" + }, + "caption": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/caption.json" + }, + "conditionsOfAccess": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/conditionsOfAccess.json" + }, + "funder": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/funder.json" + }, + "assesses": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/assesses.json" + }, + "competencyRequired": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/competencyRequired.json" + }, + "teaches": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/teaches.json" + }, + "educationalLevel": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/educationalLevel.json" + }, + "isAccessibleForFree": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/isAccessibleForFree.json" + }, + "interactivityType": { + "$ref": "https://w3id.org/kim/amb/20231019/schemas/interactivityType.json" + } + }, + "required": ["@context", "id", "name", "type"] +} diff --git a/src/app/components/webserver.clj b/src/app/components/webserver.clj index 8fffcf8..e171e72 100644 --- a/src/app/components/webserver.clj +++ b/src/app/components/webserver.clj @@ -1,28 +1,88 @@ (ns app.components.webserver (:require [io.pedestal.http :as http] [com.stuartsierra.component :as component] - [io.pedestal.http.route :as route])) + [io.pedestal.http.route :as route] + [nostr.core :as nostr] + [nostr.edufeed :as edufeed] + [cheshire.core :as json] + [json-schema.core :as json-schema] + [clojure.core.async :refer [go chan >! "resources/schema.json" + slurp + (cheshire.core/parse-string true)))] + (try + (let [validation-results + (map (fn [resource] + (try + (when (json-schema/validate schema resource) + {:valid true :resource resource}) + (catch Exception e + {:valid false :error e :resource resource}))) + resources)] + (do + ;; Log invalid resources + (doseq [{:keys [error resource]} (filter #(not (:valid %)) validation-results)] + (println "Invalid resource:" resource "Error:" error)) + ;; Return only valid resources + (->> validation-results + (filter :valid) + (map :resource)))) + (catch Exception e + (println "Unexpected error during validation" e) + [])))) -(defn resources-by-user [request] - {:status 200 :body "hello user"}) + +(defn ok [body] + {:status 200 :body body}) + +;; Async pedestal +(defn get-resources [request] + (let [result-chan (chan)] + (go + (let [npub (get-in request [:query-params :npub]) + pk (get-in request [:query-params :pk]) + filter (if pk + {:kinds [30142] :authors [pk]} + {:kinds [30142]}) + resources (nostr/fetch-events "ws://localhost:7778" filter) + transformed (map #(edufeed/convert-30142-to-nostr-amb % true true) resources) + validate (validate transformed) + resp (if validate + transformed + {:response "Some error occured during validation against AMB Scheme. Better give you nothing than wrong data"})] + (>! result-chan (json/generate-string resp)))) + result-chan)) + +(def resources-by-user + {:name ::resources-by-user + :enter (fn [context] + (go + (let [result (WebServer {})) + +;; For interactive development +(defonce server (atom nil)) + +(defn start-dev [] + (reset! server + (http/start (http/create-server + (assoc service-map + ::http/join? false))))) + +(defn stop-dev [] + (http/stop @server)) + +(defn restart [] + (stop-dev) + (start-dev)) + +(comment + (start-dev) + (restart))