diff --git a/README.md b/README.md index 41e8f94..5fbd212 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,33 @@ At present, only the duck-typing functions work. To play with them, use Full documentation is [here](https://simon-brooke.github.io/dog-and-duck/). +## Building + +### clj-activitypub + +**NOTE THAT** `dog-and-duck` depends on Jahfer's `clj-activitypub`, which is also currently not yet released and under rapid development and consequently currently *very* unstable. For this reason it's probably best to clone [my fork](https://github.com/simon-brooke/clj-activitypub) rather than [the original](https://github.com/jahfer/clj-activitypub), because that way you are less likely to encounter version incompatibilities. + +`clj-activitypub` is configured to build with [tools.bui;d](https://clojure.org/guides/tools_build). To prepare `clj-activitypub` before building `dog-and-duck`, do + +```bash +$ git clone git@github.com:simon-brooke/clj-activitypub.git +$ cd clj-activitypub/ +$ clj -T:build jar +$ clj -T:build install +``` + +I shall keep `dog-and-duck` and my fork of `clj-activitypub` in sync at least until Jahfer makes a production release of his project to [Clojars](). + +### Leiningen + +`dog-and-duck` itself is still set up to build with [Leiningen](https://leiningen.org/). Yes, I know that's not what the cool kids are using any more but hey, I'm an old man, leave me be. To get `dog-and-duck` up to a point where you can start to play, + +```bash +$ git clone git@github.com:simon-brooke/dog-and-duck.git +$ cd dog-and-duck +$ lein repl +``` + ## Testing Prior to testing, you should clone [activitystreams-test-documents](https://github.com/w3c-social/activitystreams-test-documents) into the `resources` directory. You can then test with diff --git a/doc/intro.md b/doc/intro.md index 34b706f..b30ba70 100644 --- a/doc/intro.md +++ b/doc/intro.md @@ -78,6 +78,10 @@ Duck-typing for ActivityStreams objects. As of version 0.1.0, this is substantially the only part that is yet at all useful, and it is still a long way from finished or robust. +### Bouncer + +Enhanced tools for moderators (I have as yet absolutely no idea what this looks like). + ### Scratch What the dog does when bored. Essentially, a place where I can learn how to make this stuff work, but perhaps eventually an ActivityPub server in its own right. @@ -90,6 +94,37 @@ At present, only the duck-typing functions work. To play with them, use (require '[dog-and-duck.quack.quack :as q]) ``` +## Documentation + +Full documentation is [here](https://simon-brooke.github.io/dog-and-duck/). + +## Building + +### clj-activitypub + +**NOTE THAT** `dog-and-duck` depends on Jahfer's `clj-activitypub`, which is also currently not yet released and under rapid development and consequently currently *very* unstable. For this reason it's probably best to clone [my fork](https://github.com/simon-brooke/clj-activitypub) rather than [the original](https://github.com/jahfer/clj-activitypub), because that way you are less likely to encounter version incompatibilities. + +`clj-activitypub` is configured to build with [tools.bui;d](https://clojure.org/guides/tools_build). To prepare `clj-activitypub` before building `dog-and-duck`, do + +```bash +$ git clone git@github.com:simon-brooke/clj-activitypub.git +$ cd clj-activitypub/ +$ clj -T:build jar +$ clj -T:build install +``` + +I shall keep `dog-and-duck` and my fork of `clj-activitypub` in sync at least until Jahfer makes a production release of his project to [Clojars](). + +### Leiningen + +`dog-and-duck` itself is still set up to build with [Leiningen](https://leiningen.org/). Yes, I know that's not what the cool kids are using any more but hey, I'm an old man, leave me be. To get `dog-and-duck` up to a point where you can start to play, + +```bash +$ git clone git@github.com:simon-brooke/dog-and-duck.git +$ cd dog-and-duck +$ lein repl +``` + ## Testing Prior to testing, you should clone [activitystreams-test-documents](https://github.com/w3c-social/activitystreams-test-documents) into the `resources` directory. You can then test with diff --git a/project.clj b/project.clj index 523d98e..c6bec5e 100644 --- a/project.clj +++ b/project.clj @@ -7,7 +7,7 @@ :output-path "docs/codox" :source-uri "https://github.com/simon-brooke/dog-and-duck/blob/master/{filepath}#L{line}"} :description "A playground for hacking ActivityPub stuff." - :dependencies [[clj-activitypub/activitypub "0.49"] + :dependencies [[clj-activitypub/activitypub "0.52"] [com.taoensso/timbre "6.0.4"] [mvxcvi/clj-pgp "1.1.0"] [org.bouncycastle/bcpkix-jdk18on "1.72"] diff --git a/src/dog_and_duck/quack/picky/collections.clj b/src/dog_and_duck/quack/picky/collections.clj index 3159e42..6697197 100644 --- a/src/dog_and_duck/quack/picky/collections.clj +++ b/src/dog_and_duck/quack/picky/collections.clj @@ -29,8 +29,8 @@ (object-faults x type) (list (object-reference-or-faults x type :critical :expected-collection) (cond-make-fault-object (integer? (:totalItems x)) :should :no-total-items) - (object-reference-or-faults (:first x) nil :must :no-first-page) - (object-reference-or-faults (:last x) nil :should :no-last-page)))) + (object-reference-or-faults (:first x) (str type "Page") :must :no-first-page) + (object-reference-or-faults (:last x) (str type "Page") :should :no-last-page)))) (defn simple-collection-faults "Return a list of faults found in `x` considered as a non-paged collection @@ -38,11 +38,12 @@ [x type] (concat-non-empty (object-faults x type) - (cons - (list (object-reference-or-faults x type :critical :expected-collection) - (cond-make-fault-object (integer? (:totalItems x)) :should :no-total-items) + (concat + (list (cond-make-fault-object (integer? (:totalItems x)) :should :no-total-items) (cond-make-fault-object (coll? (:items x)) :must :no-items-collection)) - (map #(object-reference-or-faults % nil :must :not-object-reference) (:items x))))) + (reduce + concat + (map #(object-reference-or-faults % nil :must :not-object-reference) (:items x)))))) (defn collection-page-faults "Return a list of faults found in `x` considered as a collection page diff --git a/src/dog_and_duck/quack/picky/utils.clj b/src/dog_and_duck/quack/picky/utils.clj index 1e4d8d0..2094bb7 100644 --- a/src/dog_and_duck/quack/picky/utils.clj +++ b/src/dog_and_duck/quack/picky/utils.clj @@ -185,12 +185,15 @@ (and (coll? tv) (string? acceptable)) ((set tv) acceptable) (and (coll? tv) (set? acceptable)) (not-empty (intersection (set tv) acceptable)) - :else - (throw (ex-info "Type value or `acceptable` argument not as expected." - {:arguments {:x x - :acceptable acceptable - :severity severity - :token token}}))) + (not + (or (string? acceptable) + (set? acceptable))) (throw + (ex-info + "`acceptable` argument not as expected." + {:arguments {:x x + :acceptable acceptable + :severity severity + :token token}}))) (make-fault-object severity token))))) (defn any-or-faults @@ -204,7 +207,7 @@ are always required." [options severity-if-none token] (let [faults (filter empty? options)] - (when (empty? faults) + (when (empty? faults) ;; i.e. there was at least one option that returned no faults... (cons (make-fault-object severity-if-none token) faults)))) diff --git a/test/dog_and_duck/quack/picky/collections_test.clj b/test/dog_and_duck/quack/picky/collections_test.clj new file mode 100644 index 0000000..ee4a491 --- /dev/null +++ b/test/dog_and_duck/quack/picky/collections_test.clj @@ -0,0 +1,56 @@ +(ns dog-and-duck.quack.picky.collections-test + (:require [clojure.test :refer [deftest is testing]] + [dog-and-duck.quack.picky.collections :refer + [collection-page-faults paged-collection-faults + simple-collection-faults]] + [dog-and-duck.quack.picky.constants :refer + [activitystreams-context-uri]] + [dog-and-duck.scratch.parser :refer [clean]])) + +;;; Copyright (C) Simon Brooke, 2022 + +;;; This program is free software; you can redistribute it and/or +;;; modify it under the terms of the GNU General Public License +;;; as published by the Free Software Foundation; either version 2 +;;; of the License, or (at your option) any later version. + +;;; This program is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. + +;;; You should have received a copy of the GNU General Public License +;;; along with this program; if not, write to the Free Software +;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +(deftest collection-identification-test + (let [paged (-> "resources/test_documents/outbox.json" slurp clean first) + page (-> "resources/test_documents/outbox_page.json" + slurp clean first) + simple (-> "resources/activitystreams-test-documents/vocabulary-ex5-jsonld.json" + slurp clean first) + not-a-collection {(keyword "@context") activitystreams-context-uri + :id "https://somewhere.out.there/object/14323:1671654380083" + :type "Test"}] + (testing "Outbox sample" + (let [actual (paged-collection-faults paged "OrderedCollection") + expected nil] (is (= actual expected) + "There should be no faults from a perfect object"))) + (testing "Outbox page sample" + (let [actual (collection-page-faults page "OrderedCollectionPage") + expected nil] (is (= actual expected) + "There should be no faults from a perfect object"))) + (testing "Simple sample" + (let [actual (set + (remove + nil? + (map :fault + (simple-collection-faults simple "Collection")))) + expected #{:no-id-transient :no-context :not-object-reference}] + (is (= actual expected) + "There should be no faults from vocabulary-ex5-jsonld, either, but there are."))) + (testing "Non-collection" + (let [actual (empty? (simple-collection-faults not-a-collection "Collection")) + expected false] + (is (= actual expected) + "There should be faults from anything which isn't a collection"))))) \ No newline at end of file diff --git a/test/dog_and_duck/quack/picky_test.clj b/test/dog_and_duck/quack/picky_test.clj index 79b0424..a40368c 100644 --- a/test/dog_and_duck/quack/picky_test.clj +++ b/test/dog_and_duck/quack/picky_test.clj @@ -5,7 +5,8 @@ [dog-and-duck.quack.picky.utils :refer [filter-severity object-faults]] [dog-and-duck.quack.picky :refer - [persistent-object-faults]])) + [collection-faults persistent-object-faults]] + [dog-and-duck.scratch.parser :refer [clean]])) ;;; Copyright (C) Simon Brooke, 2022 @@ -107,4 +108,31 @@ expected :id-not-uri actual (-> o persistent-object-faults first :fault)] (is (= actual expected) - "The fault from a persistent object with an id which is not a valid URI should be :id-not-uri"))))) \ No newline at end of file + "The fault from a persistent object with an id which is not a valid URI should be :id-not-uri"))))) + +(deftest collection-faults-test + (let [outbox (-> "resources/test_documents/outbox.json" slurp clean first) + outbox-page (-> "resources/test_documents/outbox_page.json" + slurp clean first) + simple (-> "resources/activitystreams-test-documents/vocabulary-ex5-jsonld.json" + slurp clean first) + not-a-collection {(keyword "@context") activitystreams-context-uri + :id "https://somewhere.out.there/object/14323:1671654380083" + :type "Test"}] + (testing "Collection type identification" + (let [actual (collection-faults outbox) + expected nil] + (is (= actual expected) + "There should be no faults in an outbox delivered by mastodon.")) + (let [actual (collection-faults outbox-page) + expected nil] + (is (= actual expected) + "There should be no faults in an outbox page delivered by mastodon.")) + (let [actual (set (remove nil? (map :fault (collection-faults simple)))) + expected #{:no-id-transient :no-context :not-object-reference}] + (is (= actual expected) + "There should be no faults from vocabulary-ex5-jsonld, either, but there are.")) + (let [actual (empty? (collection-faults not-a-collection)) + expected false] + (is (= actual expected) + "There should be faults from anything which isn't a collection"))))) \ No newline at end of file