diff --git a/.env b/.env index 090969c..23bfcab 100644 --- a/.env +++ b/.env @@ -6,12 +6,6 @@ DATABASE_PASSWORD=kI1BtN@rCbh2i6wg7EiEO*FwcdugST7s HOSTNAME=hhu.de -DBAS_AUTHN_SECRET=89#s3cr3t_15 -DBAS_DB_HOST=db -DBAS_DB_PORT=5432 -DBAS_DB_USER=postgres -DBAS_DB_NAME=discussion -DBAS_DB_PW=DXxCNtfnt!MOo!f8LY1!P%sw3KGzt@s! AUTHN_SECRET=89#s3cr3t_15 DB_PORT=5432 DB_USER=postgres diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e455518..fff9dda 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,9 +5,9 @@ stages: - deploy cache: + key: "$CI_JOB_NAME" paths: - - ~/.m2 - - /root/.m2 + - aggregator/.m2 untracked: true variables: diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..12537da --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +# 0.3 +Major Changes with 0.3 +* The user is not a simple String anymore. The user is now a map containing the public Screenname (`:name`), the `:id` and the `dgep-native` flag which is set when the user is native to the aggregator stated in `identifier.aggregator-id`. +* Shorthands for adding statements and whole arguments just by text all accept a author-id and assume the author is local to the current DGEP instance. +* Shorthands for adding arguments and statements now accept additional fields trhough the `additional` map. You can add any custom field there. Attributes added here will be first-class on the resulting statements. This means that adding `additional: {"foo" "bar"}` will add a field `:foo` with the value `bar` to the resulting statement. +* Added support for first-class reference search. + * A `reference` field is expected to contain a `:text`, `:host` and `:path` + * References can be searched by host- and text-content in the corresponding routes (See `/index.html#!/statements` for an overview) +* Other custom fields can be searched via `/statements/custom` +* A bug with the DBAS-Connector has been fixed and now again produces correct links. diff --git a/aggregator/.gitignore b/aggregator/.gitignore index c53038e..230ec18 100644 --- a/aggregator/.gitignore +++ b/aggregator/.gitignore @@ -9,3 +9,4 @@ pom.xml.asc /.nrepl-port .hgignore .hg/ +.m2/ diff --git a/aggregator/db/set1/arguments.edn b/aggregator/db/set1/arguments.edn index 0d9e0ee..7ffdc6a 100644 --- a/aggregator/db/set1/arguments.edn +++ b/aggregator/db/set1/arguments.edn @@ -1,26 +1,26 @@ -[{:content {:author "deka" :content-string "der Kampf unentschieden ausfällt" :created nil} :identifier {:aggregate-id "aggregator:8888" :entity-id "1" :version 1} :delete-flag false :predecessors []} - {:content {:author "dekan" :content-string "der Kampf nicht unentschieden ausfallen kann. Zu irgend einem Zeitpunkt wird nur noch genau ein Tier leben. Dieses hat gewonnen" :created nil} :identifier {:aggregate-id "aggregator:8888" :entity-id "2" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "diepfe" :content-string "die Pferde fliehen und die meisten überleben werden"} :identifier {:aggregate-id "aggregator:8888" :entity-id "3" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "woot" :content-string "sie ihre Energien aneinander aufrauchen werden und dann umfallen"} :identifier {:aggregate-id "aggregator:8888" :entity-id "4" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "diepfe" :content-string "die Pferde fliehen und die meisten somit überleben werden"} :identifier {:aggregate-id "aggregator:8888" :entity-id "5" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Wendy" :content-string "wenn die Pferde fliehen, gibt es keinen Kampf. Nach Vorraussetzung der Frage findet aber ein Kampf statt"} :identifier {:aggregate-id "aggregator:8888" :entity-id "6" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Pazi" :content-string "man alles dran setzen sollte, den ewigen Konflikt zu beenden"} :identifier {:aggregate-id "aggregator:8888" :entity-id "10" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "elkawe" :content-string "der Kampf ein wundervolles Entertainment ist"} :identifier {:aggregate-id "aggregator:8888" :entity-id "11" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Adolf" :content-string "beide Abnormitäten aus dem Genpool entfernt werden sollten"} :identifier {:aggregate-id "aggregator:8888" :entity-id "12" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Hans" :content-string "diese Abnormitäten sich durchaus behaupten können"} :identifier {:aggregate-id "aggregator:8888" :entity-id "14" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Peta" :content-string "Tiere nur aussterben sollten, wenn sie sich nicht behaupten können"} :identifier {:aggregate-id "aggregator:8888" :entity-id "16" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Piece" :content-string "Frieden das beste für unsere Welt ist"} :identifier {:aggregate-id "aggregator:8888" :entity-id "17" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "!Leroy" :content-string "es besser ist, wenn sich diese aggressiven Tiere sich gegenseitig beschäftigen"} :identifier {:aggregate-id "aggregator:8888" :entity-id "18" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "LongJohn" :content-string "sie sich im Frieden verbünden könnten. Anschließend könnten wir die gejagten sein. Eine neue Ära der Unterdrückung unter Herrschaft von tyrannischen Hühnern und grausamen Pferdchen erwartet uns"} :identifier {:aggregate-id "aggregator:8888" :entity-id "20" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Johnny" :content-string "Und wen grillen wir, wenn sich die Viecher nicht gegenseitig abmurksen"} :identifier {:aggregate-id "aggregator:8888" :entity-id "21" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "elkawe" :content-string "Frieden zwischen Riesenhühnern und Mini-Pferden sehr langweilig ist"} :identifier {:aggregate-id "aggregator:8888" :entity-id "22" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Piece" :content-string "Frieden unser größtes Ziel sein sollte :)"} :identifier {:aggregate-id "aggregator:8888" :entity-id "23" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Reuter" :content-string "einem egal sein sollte wer von beiden Verliert"} :identifier {:aggregate-id "aggregator:8888" :entity-id "35" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Johnny" :content-string "wenn alle leben, kann man alle Essen! Lecker Lasagne"} :identifier {:aggregate-id "aggregator:8888" :entity-id "36" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Johnny" :content-string "Lasagne schmeckt immer gut! Mjam Mjam Mjam"} :identifier {:aggregate-id "aggregator:8888" :entity-id "40" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Menschenfreund" :content-string "Es ist besser Nutztiere zu halten als die Ausrottung einer potenziell köstlichen Nahrungsquelle zu riskieren. Lasagne"} :identifier {:aggregate-id "aggregator:8888" :entity-id "41" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Melvin" :content-string "wir dann möglicherweise zu wenig Daten generieren"} :identifier {:aggregate-id "aggregator:8888" :entity-id "42" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Haniball" :content-string "Fleisch ist Fleisch"} :identifier { :aggregate-id "aggregator:8888" :entity-id "43" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Susi" :content-string "die 100 Pferde deutlich aufwendiger zuzubereiten sind"} :identifier { :aggregate-id "aggregator:8888" :entity-id "44" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Johnny" :content-string "Das Riesen Huhn brät ewig auf dem Grill"} :identifier {:aggregate-id "aggregator:8888" :entity-id "45" :version 1} :delete-flag false :predecessors []} - {:content {:created nil :author "Haniball" :content-string "das Huhn natürlich (mit geringem Aufwand) vorher zerlegt werden muss"} :identifier {:aggregate-id "aggregator:8888" :entity-id "46" :version 1} :delete-flag false :predecessors []}] +[{:content {:author {:name "deka" :dgep-native false :id 123} :text "der Kampf unentschieden ausfällt" :created nil} :identifier {:aggregate-id "aggregator:8888" :entity-id "1" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "dekan" :dgep-native false :id 123} :text "der Kampf nicht unentschieden ausfallen kann. Zu irgend einem Zeitpunkt wird nur noch genau ein Tier leben. Dieses hat gewonnen" :created nil} :identifier {:aggregate-id "aggregator:8888" :entity-id "2" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "diepfe" :dgep-native false :id 123} :text "die Pferde fliehen und die meisten überleben werden"} :identifier {:aggregate-id "aggregator:8888" :entity-id "3" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "woot" :dgep-native false :id 123} :text "sie ihre Energien aneinander aufrauchen werden und dann umfallen"} :identifier {:aggregate-id "aggregator:8888" :entity-id "4" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "diepfe" :dgep-native false :id 123} :text "die Pferde fliehen und die meisten somit überleben werden"} :identifier {:aggregate-id "aggregator:8888" :entity-id "5" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Wendy" :dgep-native false :id 123} :text "wenn die Pferde fliehen, gibt es keinen Kampf. Nach Vorraussetzung der Frage findet aber ein Kampf statt"} :identifier {:aggregate-id "aggregator:8888" :entity-id "6" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Pazi" :dgep-native false :id 123} :text "man alles dran setzen sollte, den ewigen Konflikt zu beenden"} :identifier {:aggregate-id "aggregator:8888" :entity-id "10" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "elkawe" :dgep-native false :id 123} :text "der Kampf ein wundervolles Entertainment ist"} :identifier {:aggregate-id "aggregator:8888" :entity-id "11" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Adolf" :dgep-native false :id 123} :text "beide Abnormitäten aus dem Genpool entfernt werden sollten"} :identifier {:aggregate-id "aggregator:8888" :entity-id "12" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Hans" :dgep-native false :id 123} :text "diese Abnormitäten sich durchaus behaupten können"} :identifier {:aggregate-id "aggregator:8888" :entity-id "14" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Peta" :dgep-native false :id 123} :text "Tiere nur aussterben sollten, wenn sie sich nicht behaupten können"} :identifier {:aggregate-id "aggregator:8888" :entity-id "16" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Piece" :dgep-native false :id 123} :text "Frieden das beste für unsere Welt ist"} :identifier {:aggregate-id "aggregator:8888" :entity-id "17" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "!Leroy" :dgep-native false :id 123} :text "es besser ist, wenn sich diese aggressiven Tiere sich gegenseitig beschäftigen"} :identifier {:aggregate-id "aggregator:8888" :entity-id "18" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "LongJohn" :dgep-native false :id 123} :text "sie sich im Frieden verbünden könnten. Anschließend könnten wir die gejagten sein. Eine neue Ära der Unterdrückung unter Herrschaft von tyrannischen Hühnern und grausamen Pferdchen erwartet uns"} :identifier {:aggregate-id "aggregator:8888" :entity-id "20" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Johnny" :dgep-native false :id 123} :text "Und wen grillen wir, wenn sich die Viecher nicht gegenseitig abmurksen"} :identifier {:aggregate-id "aggregator:8888" :entity-id "21" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "elkawe" :dgep-native false :id 123} :text "Frieden zwischen Riesenhühnern und Mini-Pferden sehr langweilig ist"} :identifier {:aggregate-id "aggregator:8888" :entity-id "22" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Piece" :dgep-native false :id 123} :text "Frieden unser größtes Ziel sein sollte :)"} :identifier {:aggregate-id "aggregator:8888" :entity-id "23" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Reuter" :dgep-native false :id 123} :text "einem egal sein sollte wer von beiden Verliert"} :identifier {:aggregate-id "aggregator:8888" :entity-id "35" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Johnny" :dgep-native false :id 123} :text "wenn alle leben, kann man alle Essen! Lecker Lasagne"} :identifier {:aggregate-id "aggregator:8888" :entity-id "36" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Johnny" :dgep-native false :id 123} :text "Lasagne schmeckt immer gut! Mjam Mjam Mjam"} :identifier {:aggregate-id "aggregator:8888" :entity-id "40" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Menschenfreund" :dgep-native false :id 123} :text "Es ist besser Nutztiere zu halten als die Ausrottung einer potenziell köstlichen Nahrungsquelle zu riskieren. Lasagne"} :identifier {:aggregate-id "aggregator:8888" :entity-id "41" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Melvin" :dgep-native false :id 123} :text "wir dann möglicherweise zu wenig Daten generieren"} :identifier {:aggregate-id "aggregator:8888" :entity-id "42" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Haniball" :dgep-native false :id 123} :text "Fleisch ist Fleisch"} :identifier { :aggregate-id "aggregator:8888" :entity-id "43" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Susi" :dgep-native false :id 123} :text "die 100 Pferde deutlich aufwendiger zuzubereiten sind"} :identifier { :aggregate-id "aggregator:8888" :entity-id "44" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Johnny" :dgep-native false :id 123} :text "Das Riesen Huhn brät ewig auf dem Grill"} :identifier {:aggregate-id "aggregator:8888" :entity-id "45" :version 1} :delete-flag false :predecessors []} + {:content {:created nil :author {:name "Haniball" :dgep-native false :id 123} :text "das Huhn natürlich (mit geringem Aufwand) vorher zerlegt werden muss"} :identifier {:aggregate-id "aggregator:8888" :entity-id "46" :version 1} :delete-flag false :predecessors []}] diff --git a/aggregator/db/set1/links.edn b/aggregator/db/set1/links.edn index 5cc9956..48791ef 100644 --- a/aggregator/db/set1/links.edn +++ b/aggregator/db/set1/links.edn @@ -1,24 +1,24 @@ -[{:author "woot" :type :support :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l2"} :source {:aggregate-id "aggregator:8888" :entity-id "4" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "1" :version 1} :delete-flag false} - {:author "dekan" :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l3"} :source {:aggregate-id "aggregator:8888" :entity-id "2" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "1" :version 1} :delete-flag false} - {:author "diepfe" :type :support :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l4"} :source {:aggregate-id "aggregator:8888" :entity-id "3" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "1" :version 1} :delete-flag false} - {:author "diepfe" :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l5"} :source {:aggregate-id "aggregator:8888" :entity-id "3" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "4" :version 1} :delete-flag false} - {:author "diepfe" :type :support :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l6"} :source {:aggregate-id "aggregator:8888" :entity-id "5" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "1" :version 1} :delete-flag false} - {:author "Wendy" :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l7"} :source {:aggregate-id "aggregator:8888" :entity-id "6" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "5" :version 1} :delete-flag false} - {:author "Johnny" :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l9"} :source {:aggregate-id "aggregator:8888" :entity-id "36" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "35" :version 1} :delete-flag false} - {:author "Melvin" :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l10"} :source {:aggregate-id "aggregator:8888" :entity-id "42" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "35" :version 1} :delete-flag false} - {:author "Johnny" :type :support :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l11"} :source {:aggregate-id "aggregator:8888" :entity-id "40" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "35" :version 1} :delete-flag false} - {:author "Haniball" :type :support :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l12"} :source {:aggregate-id "aggregator:8888" :entity-id "43" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "35" :version 1} :delete-flag false} - {:author "Menschenfreund" :type :undercut :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l13"} :source {:aggregate-id "aggregator:8888" :entity-id "41" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "l11" :version 1} :delete-flag false} - {:author "Susi" :type :undercut :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l14"} :source {:aggregate-id "aggregator:8888" :entity-id "44" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "l12" :version 1} :delete-flag false} - {:author "Johnny" :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l15"} :source {:aggregate-id "aggregator:8888" :entity-id "45" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "44" :version 1} :delete-flag false} - {:author "Haniball" :type :undercut :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l16"} :source {:aggregate-id "aggregator:8888" :entity-id "46" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "l15" :version 1} :delete-flag false} - {:author "elkawe" :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l18"} :source {:aggregate-id "aggregator:8888" :entity-id "11" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "10" :version 1} :delete-flag false} - {:author "Adolf" :type :support :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l19"} :source {:aggregate-id "aggregator:8888" :entity-id "12" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "10" :version 1} :delete-flag false} - {:author "Hans" :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l20"} :source {:aggregate-id "aggregator:8888" :entity-id "14" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "12" :version 1} :delete-flag false} - {:author "Peta" :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l21"} :source {:aggregate-id "aggregator:8888" :entity-id "16" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "12" :version 1} :delete-flag false} - {:author "Piece" :type :support :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l22"} :source {:aggregate-id "aggregator:8888" :entity-id "17" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "10" :version 1} :delete-flag false} - {:author "!Leroy" :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l23"} :source {:aggregate-id "aggregator:8888" :entity-id "18" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "17" :version 1} :delete-flag false} - {:author "Johnny" :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l24"} :source {:aggregate-id "aggregator:8888" :entity-id "21" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "17" :version 1} :delete-flag false} - {:author "LongJohn" :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l25"} :source {:aggregate-id "aggregator:8888" :entity-id "20" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "17" :version 1} :delete-flag false} - {:author "elkawe" :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l26"} :source {:aggregate-id "aggregator:8888" :entity-id "22" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "17" :version 1} :delete-flag false} - {:author "Piece" :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l27"} :source {:aggregate-id "aggregator:8888" :entity-id "23" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "22" :version 1} :delete-flag false}] +[{:author {:name "woot" :dgep-native false :id 666} :type :support :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l2"} :source {:aggregate-id "aggregator:8888" :entity-id "4" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "1" :version 1} :delete-flag false} + {:author {:name "dekan" :dgep-native false :id 666} :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l3"} :source {:aggregate-id "aggregator:8888" :entity-id "2" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "1" :version 1} :delete-flag false} + {:author {:name "diepfe" :dgep-native false :id 666} :type :support :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l4"} :source {:aggregate-id "aggregator:8888" :entity-id "3" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "1" :version 1} :delete-flag false} + {:author {:name "diepfe" :dgep-native false :id 666} :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l5"} :source {:aggregate-id "aggregator:8888" :entity-id "3" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "4" :version 1} :delete-flag false} + {:author {:name "diepfe" :dgep-native false :id 666} :type :support :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l6"} :source {:aggregate-id "aggregator:8888" :entity-id "5" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "1" :version 1} :delete-flag false} + {:author {:name "Wendy" :dgep-native false :id 666} :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l7"} :source {:aggregate-id "aggregator:8888" :entity-id "6" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "5" :version 1} :delete-flag false} + {:author {:name "Johnny" :dgep-native false :id 666} :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l9"} :source {:aggregate-id "aggregator:8888" :entity-id "36" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "35" :version 1} :delete-flag false} + {:author {:name "Melvin" :dgep-native false :id 666} :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l10"} :source {:aggregate-id "aggregator:8888" :entity-id "42" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "35" :version 1} :delete-flag false} + {:author {:name "Johnny" :dgep-native false :id 666} :type :support :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l11"} :source {:aggregate-id "aggregator:8888" :entity-id "40" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "35" :version 1} :delete-flag false} + {:author {:name "Haniball" :dgep-native false :id 666} :type :support :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l12"} :source {:aggregate-id "aggregator:8888" :entity-id "43" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "35" :version 1} :delete-flag false} + {:author {:name "Menschenfreund" :dgep-native false :id 666} :type :undercut :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l13"} :source {:aggregate-id "aggregator:8888" :entity-id "41" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "l11" :version 1} :delete-flag false} + {:author {:name "Susi" :dgep-native false :id 666} :type :undercut :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l14"} :source {:aggregate-id "aggregator:8888" :entity-id "44" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "l12" :version 1} :delete-flag false} + {:author {:name "Johnny" :dgep-native false :id 666} :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l15"} :source {:aggregate-id "aggregator:8888" :entity-id "45" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "44" :version 1} :delete-flag false} + {:author {:name "Haniball" :dgep-native false :id 666} :type :undercut :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l16"} :source {:aggregate-id "aggregator:8888" :entity-id "46" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "l15" :version 1} :delete-flag false} + {:author {:name "elkawe" :dgep-native false :id 666} :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l18"} :source {:aggregate-id "aggregator:8888" :entity-id "11" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "10" :version 1} :delete-flag false} + {:author {:name "Adolf" :dgep-native false :id 666} :type :support :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l19"} :source {:aggregate-id "aggregator:8888" :entity-id "12" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "10" :version 1} :delete-flag false} + {:author {:name "Hans" :dgep-native false :id 666} :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l20"} :source {:aggregate-id "aggregator:8888" :entity-id "14" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "12" :version 1} :delete-flag false} + {:author {:name "Peta" :dgep-native false :id 666} :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l21"} :source {:aggregate-id "aggregator:8888" :entity-id "16" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "12" :version 1} :delete-flag false} + {:author {:name "Piece" :dgep-native false :id 666} :type :support :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l22"} :source {:aggregate-id "aggregator:8888" :entity-id "17" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "10" :version 1} :delete-flag false} + {:author {:name "!Leroy" :dgep-native false :id 666} :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l23"} :source {:aggregate-id "aggregator:8888" :entity-id "18" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "17" :version 1} :delete-flag false} + {:author {:name "Johnny" :dgep-native false :id 666} :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l24"} :source {:aggregate-id "aggregator:8888" :entity-id "21" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "17" :version 1} :delete-flag false} + {:author {:name "LongJohn" :dgep-native false :id 666} :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l25"} :source {:aggregate-id "aggregator:8888" :entity-id "20" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "17" :version 1} :delete-flag false} + {:author {:name "elkawe" :dgep-native false :id 666} :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l26"} :source {:aggregate-id "aggregator:8888" :entity-id "22" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "17" :version 1} :delete-flag false} + {:author {:name "Piece" :dgep-native false :id 666} :type :attack :identifier {:version 1 :aggregate-id "aggregator:8888" :entity-id "l27"} :source {:aggregate-id "aggregator:8888" :entity-id "23" :version 1} :created nil :destination {:aggregate-id "aggregator:8888" :entity-id "22" :version 1} :delete-flag false}] diff --git a/aggregator/db/set2/arguments.edn b/aggregator/db/set2/arguments.edn index 475e531..61248c3 100644 --- a/aggregator/db/set2/arguments.edn +++ b/aggregator/db/set2/arguments.edn @@ -1,37 +1,37 @@ -[{:content {:author "erazor" :content-string "die hundert Pferde gewinnen" :created nil} :identifier {:entity-id "1" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Feuerlöscher" :content-string "Als direkter Nachfahre der Dinosaurier sind Hühner schlicht der überlegene Gegner" :created nil} :identifier {:entity-id "2" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Freud" :content-string "Pferde sind leider zu doof" :created nil} :identifier {:entity-id "3" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Feuerlöscher" :content-string "Pferde im Vergleich zu Hühner ein ausgeprägtes Sozial- und Kommunikationsverhalten zeigen" :created nil} :identifier {:entity-id "4" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Feuerlöscher" :content-string "Hühner nicht intelligenter sind" :identifier {:entity-id "5" :aggregate-id "aggregator_set2:8888" :created nil} :version 1} :delete-flag false :predecessors []} - {:content {:author "Bombur" :content-string "Pferde sind Fluchttiere. Ein riesiges Huhn kann sie jagen. Kann sie zerstören. Kann sie vernichten" :created nil} :identifier {:entity-id "6" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Johnny" :content-string "Lasagne schmeckt immer gut" :created nil} :identifier {:entity-id "7" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Haniball" :content-string "Das Huhn Lasagne sicher auch mag" :created nil} :identifier {:entity-id "8" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Lucifer" :content-string "Pferde keine Hörner haben" :created nil} :identifier {:entity-id "9" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Balthasar" :content-string "Hühner auch keine Hörner haben" :created nil} :identifier {:entity-id "10" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Lucy" :content-string "Pferde sind zu gutmütig" :created nil} :identifier {:entity-id "11" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Fallout" :content-string "Sich der Krieg nie ändert" :created nil} :identifier {:entity-id "12" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "LP" :content-string "die große Anzahl an Pferden, die geringe Größe eine einzelnen Pferde, in Summe mehr als aufwiegt" :created nil} :identifier {:entity-id "20" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Feuerlöscher" :content-string "sie dem Huhn keinen Schaden beibringen können. Das Huhn durch Flügelschläge, den enormen Schnabel, oder die Krallen an den Füßen gleich mehrere Pferde gleichzeitig töten kann. Ein Gemetzel" :created nil} :identifier {:entity-id "21" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Carlos" :content-string "eine zu große Anzahl gegen ein einzelnes Ziel eher hinderlich ist" :created nil} :identifier {:entity-id "22" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "lolzor" :content-string "die Pferde das Huhn langsam zu tode trampeln" :created nil} :identifier {:entity-id "23" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Indiana Jones" :content-string "Die Mini-Pferde können Hühner einfach nur kitzeln. Mehr nicht" :created nil} :identifier {:entity-id "24" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Bombur" :content-string "vermutlich auch genug Pferde von dem übergroßen Huhn tod getrampelt werden" :created nil} :identifier {:entity-id "25" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "McGockles" :content-string "das Huhn gewinnen würde" :created nil} :identifier {:entity-id "50" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Meter" :content-string "die Pferde nicht mal so groß sind wie die Beine des Huhns. -> Die Pferde können dem Huhn (fast) nichts tun" :created nil} :identifier {:entity-id "51" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Herbi" :content-string "es fliegen kann. So wird es für die Pferde schwer, das Huhn zu attackieren" :created nil} :identifier {:entity-id "52" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Feuerlöscher" :content-string "Hühner nicht fliegen können" :created nil} :identifier {:entity-id "53" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Gore" :content-string "der Schnabel größer wäre als ein Menschlicher Kopf!? Zack. Kopf weg" :created nil} :identifier {:entity-id "54" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Imperator" :content-string "Die Federn eines pferdegroßen Huhns so dick sind, dass die Mini Pferde keinen Schaden anrichten können" :created nil} :identifier {:entity-id "55" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "PewPew" :content-string "es Laseraugen hat" :created nil} :identifier {:entity-id "56" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Greenwall" :content-string "Laseraugen keinen erkennbaren Vorteil im Kampf gegen hundert Pferde bringen" :created nil} :identifier {:entity-id "57" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "PewPew" :content-string "Laseraugen durchaus mehrere huhngroße Pferde pro Sekunde rösten können" :created nil} :identifier {:entity-id "58" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Dr. Schlauschlau" :content-string "Laser traditionell zu den Doomsday-Waffen zu zählen sind" :created nil} :identifier {:entity-id "59" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Hans" :content-string "die Kategorisierung einer Waffe alleine keinen Aufschluss über den Kampfwert gibt" :created nil} :identifier {:entity-id "60" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Fiat Multipla" :content-string "ein Huhn auf Pferde im Rücken nicht reagieren kann, wenn es gleichzeitig von vorne angegriffen wird" :created nil} :identifier {:entity-id "61" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Meter" :content-string "die Größe der Pferde nicht ausreicht, um dem Huhn zu schaden. Folglich kann das Huhn aus allen Richtungen agegriffen werden ohne in Bedrängnis zu geraten" :created nil} :identifier {:entity-id "62" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "C. Meter" :content-string "ein huhngroßes Huhn ca. 40 cm groß ist und daher ein huhngroßes Pferd ebenfalls 40cm groß ist. Schon deutlich kleinere Tiere können Menschen/Tiere Schaden zufügen" :created nil} :identifier {:entity-id "63" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Doomsday" :content-string "Auf dem Rücken des Huhns sind sie verloren! Das Huhn kann sie so nur noch einfacher zu ihrem Nest von Kalbsgroßen Kpken bringen und den blutrünstigen Nachwuchs heranzüchten" :created nil} :identifier {:entity-id "64" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Pilot" :content-string "Hühner können zumindest kurz fliegen. Somit können Feinde vom Rücken abgeschüttelt werden. Das alleine kann tödlich enden" :created nil} :identifier {:entity-id "65" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Meter" :content-string "die Fallhöhe nicht so groß ist, dass alle Pferde sterben, wenn sie runterfallen. Sie beträgt maximal 1 Meter" :created nil} :identifier {:entity-id "66" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Pilot" :content-string "selbst wenn die Fallhöhe nicht tödlich ist, können die Pferde dem Huhn dann nicht mehr gefährlich werden" :created nil} :identifier {:entity-id "67" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} - {:content {:author "Pensimax" :content-string "Die Fallhöhe ist mitunter nicht hoch genug um die Pferde zu töten, aber sie bringen sie definitiv in einen taktischen Nachteil. Die Chance auf tödliche Verletzungen ist dennoch da" :created nil} :identifier {:entity-id "68" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []}] +[{:content {:author {:name "erazor" :dgep-native false :id 123} :text "die hundert Pferde gewinnen" :created nil} :identifier {:entity-id "1" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Feuerlöscher" :dgep-native false :id 123} :text "Als direkter Nachfahre der Dinosaurier sind Hühner schlicht der überlegene Gegner" :created nil} :identifier {:entity-id "2" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Freud" :dgep-native false :id 123} :text "Pferde sind leider zu doof" :created nil} :identifier {:entity-id "3" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Feuerlöscher" :dgep-native false :id 123} :text "Pferde im Vergleich zu Hühner ein ausgeprägtes Sozial- und Kommunikationsverhalten zeigen" :created nil} :identifier {:entity-id "4" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Feuerlöscher" :dgep-native false :id 123} :text "Hühner nicht intelligenter sind" :identifier {:entity-id "5" :aggregate-id "aggregator_set2:8888" :created nil} :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Bombur" :dgep-native false :id 123} :text "Pferde sind Fluchttiere. Ein riesiges Huhn kann sie jagen. Kann sie zerstören. Kann sie vernichten" :created nil} :identifier {:entity-id "6" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Johnny" :dgep-native false :id 123} :text "Lasagne schmeckt immer gut" :created nil} :identifier {:entity-id "7" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Haniball" :dgep-native false :id 123} :text "Das Huhn Lasagne sicher auch mag" :created nil} :identifier {:entity-id "8" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Lucifer" :dgep-native false :id 123} :text "Pferde keine Hörner haben" :created nil} :identifier {:entity-id "9" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Balthasar" :dgep-native false :id 123} :text "Hühner auch keine Hörner haben" :created nil} :identifier {:entity-id "10" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Lucy" :dgep-native false :id 123} :text "Pferde sind zu gutmütig" :created nil} :identifier {:entity-id "11" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Fallout" :dgep-native false :id 123} :text "Sich der Krieg nie ändert" :created nil} :identifier {:entity-id "12" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "LP" :dgep-native false :id 123} :text "die große Anzahl an Pferden, die geringe Größe eine einzelnen Pferde, in Summe mehr als aufwiegt" :created nil} :identifier {:entity-id "20" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Feuerlöscher" :dgep-native false :id 123} :text "sie dem Huhn keinen Schaden beibringen können. Das Huhn durch Flügelschläge, den enormen Schnabel, oder die Krallen an den Füßen gleich mehrere Pferde gleichzeitig töten kann. Ein Gemetzel" :created nil} :identifier {:entity-id "21" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Carlos" :dgep-native false :id 123} :text "eine zu große Anzahl gegen ein einzelnes Ziel eher hinderlich ist" :created nil} :identifier {:entity-id "22" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "lolzor" :dgep-native false :id 123} :text "die Pferde das Huhn langsam zu tode trampeln" :created nil} :identifier {:entity-id "23" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Indiana Jones" :dgep-native false :id 123} :text "Die Mini-Pferde können Hühner einfach nur kitzeln. Mehr nicht" :created nil} :identifier {:entity-id "24" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Bombur" :dgep-native false :id 123} :text "vermutlich auch genug Pferde von dem übergroßen Huhn tod getrampelt werden" :created nil} :identifier {:entity-id "25" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "McGockles" :dgep-native false :id 123} :text "das Huhn gewinnen würde" :created nil} :identifier {:entity-id "50" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Meter" :dgep-native false :id 123} :text "die Pferde nicht mal so groß sind wie die Beine des Huhns. -> Die Pferde können dem Huhn (fast) nichts tun" :created nil} :identifier {:entity-id "51" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Herbi" :dgep-native false :id 123} :text "es fliegen kann. So wird es für die Pferde schwer, das Huhn zu attackieren" :created nil} :identifier {:entity-id "52" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Feuerlöscher" :dgep-native false :id 123} :text "Hühner nicht fliegen können" :created nil} :identifier {:entity-id "53" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Gore" :dgep-native false :id 123} :text "der Schnabel größer wäre als ein Menschlicher Kopf!? Zack. Kopf weg" :created nil} :identifier {:entity-id "54" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Imperator" :dgep-native false :id 123} :text "Die Federn eines pferdegroßen Huhns so dick sind, dass die Mini Pferde keinen Schaden anrichten können" :created nil} :identifier {:entity-id "55" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "PewPew" :dgep-native false :id 123} :text "es Laseraugen hat" :created nil} :identifier {:entity-id "56" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Greenwall" :dgep-native false :id 123} :text "Laseraugen keinen erkennbaren Vorteil im Kampf gegen hundert Pferde bringen" :created nil} :identifier {:entity-id "57" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "PewPew" :dgep-native false :id 123} :text "Laseraugen durchaus mehrere huhngroße Pferde pro Sekunde rösten können" :created nil} :identifier {:entity-id "58" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Dr. Schlauschlau" :dgep-native false :id 123} :text "Laser traditionell zu den Doomsday-Waffen zu zählen sind" :created nil} :identifier {:entity-id "59" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Hans" :dgep-native false :id 123} :text "die Kategorisierung einer Waffe alleine keinen Aufschluss über den Kampfwert gibt" :created nil} :identifier {:entity-id "60" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Fiat Multipla" :dgep-native false :id 123} :text "ein Huhn auf Pferde im Rücken nicht reagieren kann, wenn es gleichzeitig von vorne angegriffen wird" :created nil} :identifier {:entity-id "61" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Meter" :dgep-native false :id 123} :text "die Größe der Pferde nicht ausreicht, um dem Huhn zu schaden. Folglich kann das Huhn aus allen Richtungen agegriffen werden ohne in Bedrängnis zu geraten" :created nil} :identifier {:entity-id "62" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "C. Meter" :dgep-native false :id 123} :text "ein huhngroßes Huhn ca. 40 cm groß ist und daher ein huhngroßes Pferd ebenfalls 40cm groß ist. Schon deutlich kleinere Tiere können Menschen/Tiere Schaden zufügen" :created nil} :identifier {:entity-id "63" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Doomsday" :dgep-native false :id 123} :text "Auf dem Rücken des Huhns sind sie verloren! Das Huhn kann sie so nur noch einfacher zu ihrem Nest von Kalbsgroßen Kpken bringen und den blutrünstigen Nachwuchs heranzüchten" :created nil} :identifier {:entity-id "64" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Pilot" :dgep-native false :id 123} :text "Hühner können zumindest kurz fliegen. Somit können Feinde vom Rücken abgeschüttelt werden. Das alleine kann tödlich enden" :created nil} :identifier {:entity-id "65" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Meter" :dgep-native false :id 123} :text "die Fallhöhe nicht so groß ist, dass alle Pferde sterben, wenn sie runterfallen. Sie beträgt maximal 1 Meter" :created nil} :identifier {:entity-id "66" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Pilot" :dgep-native false :id 123} :text "selbst wenn die Fallhöhe nicht tödlich ist, können die Pferde dem Huhn dann nicht mehr gefährlich werden" :created nil} :identifier {:entity-id "67" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []} + {:content {:author {:name "Pensimax" :dgep-native false :id 123} :text "Die Fallhöhe ist mitunter nicht hoch genug um die Pferde zu töten, aber sie bringen sie definitiv in einen taktischen Nachteil. Die Chance auf tödliche Verletzungen ist dennoch da" :created nil} :identifier {:entity-id "68" :aggregate-id "aggregator_set2:8888" :version 1} :delete-flag false :predecessors []}] diff --git a/aggregator/db/set2/links.edn b/aggregator/db/set2/links.edn index daa9d16..9c9fd39 100644 --- a/aggregator/db/set2/links.edn +++ b/aggregator/db/set2/links.edn @@ -1,36 +1,36 @@ -[{:author "Meter" :type :support :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l2" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "51" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "50" :version 1} :created nil } - {:author "Herbi" :type :support :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l3" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "52" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "50" :version 1} :created nil } - {:author "Feuerlöscher" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l4" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "53" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "52" :version 1} :created nil } - {:author "Gore" :type :support :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l5" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "54" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "50" :version 1} :created nil } - {:author "Imperator" :type :support :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l6" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "55" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "50" :version 1} :created nil } - {:author "PewPew" :type :support :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l7" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "56" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "50" :version 1} :created nil } - {:author "Greenwall" :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l8" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "57" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l7" :version 1} :created nil} - {:author "PewPew" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l9" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "58" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "57" :version 1} :created nil } - {:author "Dr. Schlauschlau" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l10" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "59" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "57" :version 1} :created nil } - {:author "Hans" :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l11" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "60" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l10" :version 1} :created nil} - {:author "Fiat Multipla" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l12" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "61" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "50" :version 1} :created nil } - {:author "Meter" :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l13" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "62" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l12" :version 1} :created nil} - {:author "C. Meter" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l14" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "63" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "62" :version 1} :created nil } - {:author "Doomsday" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l15" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "64" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "61" :version 1} :created nil } - {:author "Pilot" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l16" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "65" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "61" :version 1} :created nil } - {:author "Meter" :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l17" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "66" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l16" :version 1} :created nil} - {:author "Pilot" :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l18" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "67" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l17" :version 1} :created nil} - {:author "Pensimax" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l19" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "68" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "66" :version 1} :created nil } - {:author "Feuerlöscher" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l21" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "2" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "1" :version 1} :created nil } - {:author "Bombur" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l22" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "6" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "1" :version 1} :created nil } - {:author "Freud" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l23" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "3" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "1" :version 1} :created nil } - {:author "Feuerlöscher" :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l24" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "5" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l23" :version 1} :created nil} - {:author "Feuerlöscher" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l25" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "4" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "3" :version 1} :created nil } - {:author "Lucifer" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l26" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "8" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "1" :version 1} :created nil } - {:author "Balthasar" :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l27" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "10" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l26" :version 1} :created nil} - {:author "Johnny" :type :support :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l28" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "7" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "1" :version 1} :created nil } - {:author "Haniball" :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l29" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "8" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l28" :version 1} :created nil } - {:author "Lucy" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l30" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "11" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "1" :version 1} :created nil } - {:author "Fallout" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l31" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "12" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "11" :version 1} :created nil } - {:author "LP" :type :support :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l32" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "20" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "1" :version 1} :created nil } - {:author "Feuerlöscher" :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l33" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "21" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l32" :version 1} :created nil} - {:author "Carlos" :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l34" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "22" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l32" :version 1} :created nil} - {:author "lolzor" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l35" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "23" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "22" :version 1} :created nil } - {:author "Bombur" :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l36" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "25" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l35" :version 1} :created nil} - {:author "Indiana Jones" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l37" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "24" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "23" :version 1} :created nil } - {:author "Imperator" :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l38" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "55" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "23" :version 1} :created nil }] +[{:author {:name "Meter" :dgep-native false :id 666} :type :support :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l2" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "51" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "50" :version 1} :created nil } + {:author {:name "Herbi" :dgep-native false :id 666} :type :support :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l3" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "52" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "50" :version 1} :created nil } + {:author {:name "Feuerlöscher" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l4" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "53" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "52" :version 1} :created nil } + {:author {:name "Gore" :dgep-native false :id 666} :type :support :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l5" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "54" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "50" :version 1} :created nil } + {:author {:name "Imperator" :dgep-native false :id 666} :type :support :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l6" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "55" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "50" :version 1} :created nil } + {:author {:name "PewPew" :dgep-native false :id 666} :type :support :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l7" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "56" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "50" :version 1} :created nil } + {:author {:name "Greenwall" :dgep-native false :id 666} :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l8" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "57" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l7" :version 1} :created nil} + {:author {:name "PewPew" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l9" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "58" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "57" :version 1} :created nil } + {:author {:name "Dr. Schlauschlau" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l10" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "59" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "57" :version 1} :created nil } + {:author {:name "Hans" :dgep-native false :id 666} :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l11" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "60" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l10" :version 1} :created nil} + {:author {:name "Fiat Multipla" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l12" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "61" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "50" :version 1} :created nil } + {:author {:name "Meter" :dgep-native false :id 666} :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l13" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "62" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l12" :version 1} :created nil} + {:author {:name "C. Meter" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l14" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "63" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "62" :version 1} :created nil } + {:author {:name "Doomsday" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l15" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "64" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "61" :version 1} :created nil } + {:author {:name "Pilot" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l16" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "65" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "61" :version 1} :created nil } + {:author {:name "Meter" :dgep-native false :id 666} :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l17" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "66" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l16" :version 1} :created nil} + {:author {:name "Pilot" :dgep-native false :id 666} :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l18" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "67" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l17" :version 1} :created nil} + {:author {:name "Pensimax" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l19" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "68" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "66" :version 1} :created nil } + {:author {:name "Feuerlöscher" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l21" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "2" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "1" :version 1} :created nil } + {:author {:name "Bombur" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l22" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "6" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "1" :version 1} :created nil } + {:author {:name "Freud" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l23" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "3" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "1" :version 1} :created nil } + {:author {:name "Feuerlöscher" :dgep-native false :id 666} :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l24" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "5" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l23" :version 1} :created nil} + {:author {:name "Feuerlöscher" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l25" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "4" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "3" :version 1} :created nil } + {:author {:name "Lucifer" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l26" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "8" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "1" :version 1} :created nil } + {:author {:name "Balthasar" :dgep-native false :id 666} :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l27" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "10" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l26" :version 1} :created nil} + {:author {:name "Johnny" :dgep-native false :id 666} :type :support :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l28" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "7" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "1" :version 1} :created nil } + {:author {:name "Haniball" :dgep-native false :id 666} :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l29" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "8" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l28" :version 1} :created nil } + {:author {:name "Lucy" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l30" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "11" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "1" :version 1} :created nil } + {:author {:name "Fallout" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l31" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "12" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "11" :version 1} :created nil } + {:author {:name "LP" :dgep-native false :id 666} :type :support :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l32" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "20" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "1" :version 1} :created nil } + {:author {:name "Feuerlöscher" :dgep-native false :id 666} :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l33" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "21" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l32" :version 1} :created nil} + {:author {:name "Carlos" :dgep-native false :id 666} :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l34" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "22" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l32" :version 1} :created nil} + {:author {:name "lolzor" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l35" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "23" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "22" :version 1} :created nil } + {:author {:name "Bombur" :dgep-native false :id 666} :type :undercut :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l36" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "25" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "l35" :version 1} :created nil} + {:author {:name "Indiana Jones" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l37" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "24" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "23" :version 1} :created nil } + {:author {:name "Imperator" :dgep-native false :id 666} :type :attack :identifier {:aggregate-id "aggregator_set2:8888" :entity-id "l38" :version 1} :source {:aggregate-id "aggregator_set2:8888" :entity-id "55" :version 1 } :destination {:aggregate-id "aggregator_set2:8888" :entity-id "23" :version 1} :created nil }] diff --git a/aggregator/project.clj b/aggregator/project.clj index 6b8683d..951d688 100644 --- a/aggregator/project.clj +++ b/aggregator/project.clj @@ -1,4 +1,4 @@ -(defproject aggregator "0.2" +(defproject aggregator "0.3" :description "The aggregator module for the EDEN framework. The aggregator coordinates the internal and external dataflows of an EDEN instance." :url "http://example.com/FIXME" :license {:name "Eclipse Public License" @@ -17,10 +17,11 @@ [ring/ring-json "0.4.0"] [ring/ring-mock "0.3.2"] [ring/ring-jetty-adapter "1.6.3"] + [ring-cors "0.1.12"] [clj-http "3.7.0"] [codox-theme-rdash "0.1.2"] - [metosin/compojure-api "2.0.0-alpha19"] - [metosin/spec-tools "0.6.1"] + [metosin/compojure-api "2.0.0-alpha28"] + [metosin/spec-tools "0.8.2"] [cheshire "5.8.0"]] :profiles {:dev {:dependencies [[org.clojure/test.check "0.9.0"] @@ -46,5 +47,7 @@ :main ^:skip-aot aggregator.core :target-path "target/%s" + :local-repo ".m2/repo" + :codox {:metadata {:doc/format :markdown} :themes [:rdash]}) diff --git a/aggregator/src/aggregator/api/routes.clj b/aggregator/src/aggregator/api/routes.clj index 104e8fe..ef2889b 100644 --- a/aggregator/src/aggregator/api/routes.clj +++ b/aggregator/src/aggregator/api/routes.clj @@ -1,21 +1,67 @@ (ns aggregator.api.routes "Define and expose the routes for the REST API in this file." (:require [compojure.route] - [compojure.api.sweet :refer [GET api context resource undocumented]] + [compojure.api.sweet :refer [GET POST api context resource undocumented]] + [compojure.api.exception :as ex] [aggregator.query.query :as query] + [aggregator.utils.common :as utils] + [aggregator.query.update :as update] [spec-tools.spec :as spec] [clojure.spec.alpha :as s] [aggregator.specs :as eden-specs] - [ring.util.http-response :refer [ok not-found]])) + [ring.util.http-response :refer [ok not-found created]] + [ring.middleware.cors :as ring-cors])) (s/def ::welcome-message spec/string?) (s/def ::statements (s/coll-of ::eden-specs/statement)) (s/def ::statements-map (s/keys :req-un [::statements])) + +(s/def ::premise ::eden-specs/text) +(s/def ::conclusion ::eden-specs/text) + (s/def ::links (s/coll-of ::eden-specs/link)) (s/def ::links-map (s/keys :req-un [::links])) (s/def ::statement-map (s/keys :req-un [::eden-specs/statement])) (s/def ::link-map (s/keys :req-un [::eden-specs/link])) +(s/def ::premise-name ::eden-specs/identifier) +(s/def ::conclusion-name ::eden-specs/identifier) +(s/def ::link-name ::eden-specs/identifier) +(s/def ::new-argument (s/keys :req-un [::premise-name ::conclusion-name] + :opt-un [::link-name])) + +(s/def ::author-id ::eden-specs/id) +(s/def ::link-type #{"support" "attack" "undercut"}) +(s/def ::additional map?) +(s/def ::additional-premise map?) +(s/def ::additional-conclusion map?) +(s/def ::minimal-argument (s/keys :req-un [::premise ::conclusion ::link-type ::author-id] + :opt-un [::additional-premise ::additional-conclusion])) + +(s/def ::quick-statement-body (s/keys :req-un [::eden-specs/text ::author-id] + :opt-un [::additional])) +(s/def ::quicklink-request (s/keys :req-un [::eden-specs/type ::eden-specs/source + ::eden-specs/destination ::author-id])) + +(def argument-routes + (context "/argument" [] + :tags ["argument"] + :coercion :spec + + (POST "/" [] + :summary "Add a new argument to the EDEN database." + :body [request-body ::minimal-argument] + :return ::new-argument + (created + "/argument" + (let [premise (:premise request-body) + conclusion (:conclusion request-body) + link-type (:link-type request-body) + author-id (:author-id request-body) + additional-p (:additional-premise request-body) + additional-c (:additional-conclusion request-body)] + (update/add-argument premise conclusion link-type author-id additional-p additional-c)))))) + (def statements-routes (context "/statements" [] :tags ["statements"] @@ -40,12 +86,31 @@ (ok {:statements (query/starter-set)})) (GET "/by-id" [] - :summary "Returns all statements matching aggregator and entity-id" - :query-params [aggregate-id :- ::eden-specs/aggregate-id, - entity-id :- ::eden-specs/entity-id] + :summary "Returns all statements matching aggregator and entity-id" + :query-params [aggregate-id :- ::eden-specs/aggregate-id, + entity-id :- ::eden-specs/entity-id] + :return ::statements-map + (ok {:statements (query/tiered-retrieval aggregate-id entity-id + {:opts [:no-remote]})})) + + (GET "/by-reference-host" [] + :summary "Returns all statements matching aggregator and entity-id" + :query-params [host :- spec/string?] + :return ::statements-map + (ok {:statements (query/custom-statement :reference.host host)})) + + (GET "/by-reference-text" [] + :summary "Returns all statements matching aggregator and entity-id" + :query-params [text :- spec/string?] + :return ::statements-map + (ok {:statements (query/custom-statement :reference.text text)})) + + (GET "/custom" [] + :summary "Returns all statements matching the search term in a custom field" + :query-params [custom-field :- spec/string? + search-term :- spec/string?] :return ::statements-map - (ok {:statements (query/tiered-retrieval aggregate-id entity-id - {:opts [:no-remote]})})))) + (ok {:statements (query/custom-statement custom-field search-term)})))) (def links-routes (context "/links" [] @@ -64,7 +129,7 @@ entity-id :- ::eden-specs/entity-id] :return ::links-map (ok {:links (query/local-undercuts aggregate-id entity-id)})) - + (GET "/to" [] :summary "Return all links pointing to a specific statement" :query-params [aggregate-id :- ::eden-specs/aggregate-id @@ -79,14 +144,39 @@ :coercion :spec (GET "/" [] - :summary "Return a specific statement by identifiers" - :query-params [aggregate-id :- ::eden-specs/aggregate-id - entity-id :- ::eden-specs/entity-id - version :- ::eden-specs/version] - :return ::statement-map - (if-let [statement (query/exact-statement aggregate-id entity-id version)] - (ok {:statement statement}) - (not-found nil))))) + :summary "Return a specific statement by identifiers" + :query-params [aggregate-id :- ::eden-specs/aggregate-id + entity-id :- ::eden-specs/entity-id + version :- ::eden-specs/version] + :return ::statement-map + (if-let [statement (query/exact-statement aggregate-id entity-id version)] + (ok {:statement statement}) + (not-found nil))) + + (POST "/" [] + :summary "Add a statement to the EDEN database" + :body [statement ::eden-specs/statement] + :return ::statement-map + (created + "/statement" + {:statement (update/update-statement (utils/json->edn statement))})) + + (POST "/from-text" [] + :summary "Add a statement only providing text and author-id" + :body [request-body ::quick-statement-body] + :return ::statement-map + (created + "/statement" + (let [text (:text request-body) + author-id (:author-id request-body) + additional (:additional request-body)] + {:statement (update/statement-from-text text author-id additional)}))))) + +(defn wrap-link-type [handler] + (fn [request] + (if-let [type (-> request :body-params :type)] + (handler (assoc-in request [:body-params :type] (keyword type))) + (handler request)))) (def link-routes (context "/link" [] @@ -101,33 +191,59 @@ :return ::link-map (if-let [link (query/retrieve-link aggregate-id entity-id version)] (ok {:link link}) - (not-found nil))))) + (not-found nil))) + + (POST "/" [] + :summary "Add a link to the EDEN database" + :middleware [wrap-link-type] + :body [link ::eden-specs/link] + :return ::link-map + (created + "/link" + {:link (update/update-link (utils/json->edn link))})) + + (POST "/shorthand" [] + :summary "Add a link via source, destination and author. Autogenerate rest." + :middleware [wrap-link-type] + :body [quicklink-request ::quicklink-request] + :return ::link-map + (created + "/link" + (let [source (:source quicklink-request) + destination (:destination quicklink-request) + author-id (:author-id quicklink-request) + link-type (:type quicklink-request)] + {:link (update/quicklink link-type source destination author-id)}))))) (def app - (api {:coercion :spec - :swagger - {:ui "/swagger" - :spec "/swagger.json" - :data {:info {:title "EDEN Aggregator API" - :description "An API to request statements and links from the EDEN instance."} - :tags [{:name "statements" :description "Retrieve Statements"} - {:name "links" :description "Retrieve Links"} - {:name "statement" :description "Retrieve single specific statement"} - {:name "link" :description "Retrieve single specific link"}]}}} - - statement-routes - statements-routes - link-routes - links-routes - - (GET "/" [] - :summary "Test whether the api is online" - :query-params [] - :return ::welcome-message - (ok "Hello!")) - - (undocumented - (compojure.route/not-found (not-found {:not "found"}))))) + (let [compojure-api-handler + (api {:coercion :spec + :exceptions + {:handlers + {::ex/request-parsing (ex/with-logging ex/request-parsing-handler :info) + ::ex/request-validation (ex/with-logging ex/request-validation-handler :error) + ::ex/response-validation (ex/with-logging ex/response-validation-handler :error)}} + :swagger + {:ui "/" + :spec "/swagger.json" + :data {:info {:title "EDEN Aggregator API" + :description "An API to request statements and links from the EDEN instance."} + :tags [{:name "statements" :description "Retrieve Statements"} + {:name "links" :description "Retrieve Links"} + {:name "statement" :description "Retrieve or add a single specific statement"} + {:name "link" :description "Retrieve or add a single specific link"} + {:name "argument" :description "Add whole arguments"}]}}} + statement-routes + statements-routes + link-routes + links-routes + argument-routes + (undocumented + (compojure.route/not-found (not-found {:not "found"}))))] + (ring-cors/wrap-cors + compojure-api-handler + :access-control-allow-origin #".*" + :access-control-allow-methods [:get :put :post :delete]))) (comment (use 'ring.adapter.jetty) diff --git a/aggregator/src/aggregator/broker/connector.clj b/aggregator/src/aggregator/broker/connector.clj index 321d514..e747836 100644 --- a/aggregator/src/aggregator/broker/connector.clj +++ b/aggregator/src/aggregator/broker/connector.clj @@ -5,15 +5,24 @@ [langohr.channel :as lch] [langohr.queue :as lq] [aggregator.broker.config :as bconf] + [aggregator.config :as config] [aggregator.utils.common :as lib])) -(def ^:private conn (atom nil)) +(defn broker-data + "Helper shortcut to get the broker-data from the state." + [name] + (get-in @config/app-state [:broker-info name])) (defn connected? - "Check if connection to broker is established." - [] (if (and @conn (not (rmq/closed? @conn))) true false)) - -(defmacro with-connection + "Check if connection to broker is established. When no broker-name is given, the local broker is checked. If connection is established return connection, otherwise nil." + ([broker-name] + (:conn (broker-data broker-name))) + ([] + (connected? (System/getenv "BROKER_HOST")))) + +#_(defmacro with-connection + "Executes the body if the local connection is established. + Returns the error message otherwise." [error-msg & body] `(if (connected?) (do ~@body) @@ -26,42 +35,70 @@ (defn- create-connection! "Read variables from environment and establish connection to the message broker." - [] (reset! conn (rmq/connect {:host (System/getenv "BROKER_HOST") - :username (System/getenv "BROKER_USER") - :password (System/getenv "BROKER_PASS")}))) - -(defn init-connection! - "Initializes connection to broker and creates an exchange." + [hostname] (rmq/connect {:host hostname + :username (System/getenv "BROKER_USER") + :password (System/getenv "BROKER_PASS")})) + +(defn get-connection! + "Opens a connection to a remote broker. If the connection is already opened, returns the opened connection. + Connections are stored within the app-state inside the config-module." + ([broker-name] + (let [conn (:conn (broker-data broker-name))] + (or conn + (let [new-conn (create-connection! broker-name)] + (swap! config/app-state assoc-in [:broker-info broker-name :conn] new-conn) + new-conn)))) + ([] + (get-connection! (System/getenv "BROKER_HOST")))) + +(defn init-local-connection! + "Initializes connection to local broker and creates an exchange." [] - (create-connection!) + (get-connection! (System/getenv "BROKER_HOST")) (log/debug "Connection to Message Broker established.") (lib/return-ok "Connection established.")) +(declare close-all-channels!) (defn close-connection! - "Close connection to message broker." + "Closes a connection for a given broker and returns :ok. If the connection is already closed, return nil." + [broker-name] + (when-let [conn (:conn (broker-data broker-name))] + (close-all-channels! broker-name) + (rmq/close conn) + (swap! config/app-state assoc-in [:broker-info broker-name :conn] nil) + :ok)) + +(defn close-local-connection! + "Close connection to the local message broker." [] - (with-connection "Connection could not be closed." - (rmq/close @conn) - (reset! conn nil) - (lib/return-ok "Connection closed."))) + (close-connection! (System/getenv "BROKER_HOST")) + (lib/return-ok "Connection closed.")) ;; ----------------------------------------------------------------------------- ;; For the communication with the broker -(defn open-channel - "Opens a channel for an existing connection to the broker." - [] - (with-connection "Could not create channel." - (lch/open @conn))) +(defn open-channel! + "Opens a channel returns it. + Keep in mind that you need to close this connection when finished." + ([broker-name] + (when-let [connection (get-connection! broker-name)] + (lch/open connection))) + ([] (open-channel! (System/getenv "BROKER_HOST")))) -(defn close-channel +(defn close-channel! "Given a channel, close it!" [ch] - (with-connection "Could not close channel." - (when-not (lch/closed? ch) - (lch/close ch) - (lib/return-ok "Channel closed.")))) + (when-not (lch/closed? ch) + (lch/close ch) + (lib/return-ok "Channel closed."))) + +(defn close-all-channels! + "Closes all known channels for a certain broker." + [broker-name] + (let [channels (:subscriptions (broker-data broker-name))] + (run! (fn [[_ chan]] (lch/close chan)) channels) + (swap! config/app-state assoc-in [:broker-info broker-name :subscriptions] {}))) (defn create-queue "Creates a queue for a given aggregator. Uses aggregator as the queue name and @@ -71,49 +108,47 @@ Example: (create-queue \"statements\")" ([queue-name exchange] - (with-connection "Could not create queue." + (let [ch (open-channel!)] (try - (let [ch (open-channel) - queue-name queue-name - expires-in-ms (* 30 60 1000)] - (lq/declare ch queue-name {:arguments {"x-expires" expires-in-ms}}) - (lq/bind ch queue-name exchange {:routing-key queue-name}) - (close-channel ch) - (log/debug "Created queue:" queue-name) - (lib/return-ok "Queue created." {:queue-name queue-name :expires-in-ms expires-in-ms})) + (lq/declare ch queue-name {:durable true + :auto-delete false}) + (lq/bind ch queue-name exchange {:routing-key queue-name}) + (log/debug "Created queue:" queue-name) + (lib/return-ok "Queue created." {:queue-name queue-name}) (catch java.io.IOException _e (log/error "Could not create queue" queue-name) - (lib/return-error "Could not create queue, caught IOException."))))) + (lib/return-error "Could not create queue, caught IOException.")) + (finally (close-channel! ch))))) ([queue-name] (create-queue queue-name bconf/exchange))) (defn queue-exists? "Check if queue exists. Returns a Boolean when connection is established." [queue] - (with-connection (format "Can't query existence of queue '%s'." queue) + (let [_ (get-connection!) + ch (open-channel!)] (try - (let [ch (open-channel)] - (lq/status ch queue) - (close-channel ch) - true) - (catch java.io.IOException _e false)))) + (lq/status ch queue) + true + (catch java.io.IOException _e false) + (finally (close-channel! ch))))) (defn delete-queue "Given a queue-name, delete it!" [queue] - (with-connection "Could not delete queue." + (let [_ (get-connection!) + ch (open-channel!)] (when queue-exists? - (let [ch (open-channel)] - (lq/delete ch queue) - (close-channel ch) - (lib/return-ok "Queue deleted."))))) + (lq/delete ch queue) + (close-channel! ch) + (lib/return-ok "Queue deleted.")))) ;; ----------------------------------------------------------------------------- ;; Entrypoint (defn entrypoint [] - (init-connection!) + (init-local-connection!) (create-queue "statements") (create-queue "links")) ;;(entrypoint) diff --git a/aggregator/src/aggregator/broker/publish.clj b/aggregator/src/aggregator/broker/publish.clj index 1026c5c..9742852 100644 --- a/aggregator/src/aggregator/broker/publish.clj +++ b/aggregator/src/aggregator/broker/publish.clj @@ -11,12 +11,12 @@ (defn- publish "Create queue for entity and publish it on this queue." [payload routing-key entity-type] - (let [ch (connector/open-channel)] + (let [ch (connector/open-channel!)] (try (lb/publish ch bconf/exchange routing-key (json/write-str payload) {:content-type "application/json" :type (name entity-type)}) (catch Throwable t (.printStackTrace t)) - (finally (connector/close-channel ch))))) + (finally (connector/close-channel! ch))))) (defn publish-statement "Put a statement to the correct queue. Statement must conform spec to be diff --git a/aggregator/src/aggregator/broker/subscriber.clj b/aggregator/src/aggregator/broker/subscriber.clj index b6c7785..4b5a706 100644 --- a/aggregator/src/aggregator/broker/subscriber.clj +++ b/aggregator/src/aggregator/broker/subscriber.clj @@ -6,6 +6,8 @@ [aggregator.utils.common :as lib] [aggregator.query.update :as qupd] [aggregator.specs :as gspecs] + [aggregator.broker.connector :as conn] + [aggregator.config :as config] [clojure.spec.alpha :as s]) (:import [com.rabbitmq.client AuthenticationFailureException])) @@ -37,21 +39,33 @@ (log/debug "Received a valid link. Passing it to query-module...") (qupd/update-link nlink)))) +(defn save-sub-to-state! + "Adds a subscription and the corresponding channel to the app-state." + [broker sub-name channel] + (swap! config/app-state + assoc-in [:broker-info broker :subscriptions sub-name] channel)) + (defn subscribe "Subscribe to queue and call a function f with meta-information and payload. Example: (subscribe (fn [meta payload] [meta payload]) \"statements\" {:host \"broker\" :user \"groot\" :password \"iamgroot\"}) (subscribe \"statements\" {:host \"broker\"})" - ([f queue {:keys [host user password]}] + ([f queue {:keys [host]}] (try - (let [conn (rmq/connect - {:host host - :username (or user (System/getenv "BROKER_USER")) - :password (or password (System/getenv "BROKER_PASS"))}) - ch (lch/open conn)] - (lcons/subscribe ch queue (partial message-handler f) {:auto-ack true}) - (log/debug (format "Connected to queue %s. Channel id: %s" queue (.getChannelNumber ch))) + (let [current-subs (:subscriptions (conn/broker-data host)) + connection (conn/get-connection! host) + channel (if-not (contains? current-subs queue) + (do + (log/debug (format + "The queue %s has no open channel for it." + queue)) + (lch/open connection)) + (get current-subs queue))] + (lcons/subscribe channel queue (partial message-handler f) {:auto-ack true}) + (save-sub-to-state! host queue channel) + (log/debug (format "Connected to queue %s. Channel id: %s" + queue (.getChannelNumber channel))) (lib/return-ok "Connection to message queue established.")) (catch AuthenticationFailureException e (log/debug (:auth-ex exceptions)) @@ -64,7 +78,6 @@ (lib/return-error (:queue-ex exceptions))))) ([queue broker] (subscribe to-query queue broker))) - ;; ----------------------------------------------------------------------------- ;; Specs diff --git a/aggregator/src/aggregator/core.clj b/aggregator/src/aggregator/core.clj index 62a95c2..9720354 100644 --- a/aggregator/src/aggregator/core.clj +++ b/aggregator/src/aggregator/core.clj @@ -34,8 +34,7 @@ [& args] (load-config) (search/entrypoint) - (when-not (broker/connected?) - (broker/init-connection!)) + (broker/entrypoint) (load-test-data) (bootstrap-dgep-data) (pg-listener/start-listeners) diff --git a/aggregator/src/aggregator/graphql/dbas_connector.clj b/aggregator/src/aggregator/graphql/dbas_connector.clj index 5ee04fb..570c572 100644 --- a/aggregator/src/aggregator/graphql/dbas_connector.clj +++ b/aggregator/src/aggregator/graphql/dbas_connector.clj @@ -2,7 +2,8 @@ (:require [clj-http.client :as client] [clojure.data.json :as json] [clojure.walk :refer [keywordize-keys]] - [aggregator.config :as config])) + [aggregator.config :as config] + [taoensso.timbre :as log])) (defn- query-db [query] @@ -27,13 +28,16 @@ (defn get-statements "Return all statements from the D-BAS instance. The result is already in the EDEN-conform format." [] - (let [result (query-db "query { statements { uid, textversions { content, authorUid} }}")] + (let [result (query-db "query { statements { uid, textversions { content, author {publicNickname, uid}} }}")] (map (fn [statement] - (let [default-statement {:content - {:content-string (get-in statement [:textversions :content]) + (let [author-name (get-in statement [:textversions :author :publicNickname]) + author-id (get-in statement [:textversions :author :uid]) + default-statement {:content + {:text (get-in statement [:textversions :content]) :created nil ;; dbas won't play - :author (str "author#: " - (get-in statement [:textversions :authorUid]))} + :author {:dgep-native true + :name author-name + :id (Integer/parseInt author-id)}} :identifier {:aggregate-id config/aggregate-name :entity-id (:uid statement) @@ -67,36 +71,46 @@ "Use the strange structure of D-BAS-arguments to create links. Needs a connection to the local dbas instance. Returned links in EDEN format." [argument] - (let [group-uid (:premisesgroupUid argument) + (let [group-uid (:premisegroupUid argument) premises (query-db (format "query {premises(premisegroupUid: %d) {statementUid}}" group-uid)) - link-type-val (link-type argument)] + link-type-val (link-type argument) + author (:author argument) + destination-id (or (:conclusionUid argument) (:argumentUid argument))] (map (fn [premise] - (let [prepared-link - {:author (str "author#: " - (:authorUid argument)) - :created nil ;; nil until we solve the graphql problem - :type link-type-val - :source {:aggregate-id config/aggregate-name - :entity-id (:statementUid premise) - :version 1} - :destination {:aggregate-id config/aggregate-name} - :identifier {:aggregate-id config/aggregate-name - :entity-id (:uid argument) - :version 1}}] - (if (not= link-type-val :undercut) - (assoc prepared-link :destination {:aggregate-id config/aggregate-name - :version 1 - :entity-id (:conclusionUid argument)}) - (assoc-in prepared-link [:destination :entity-id] (:argumentUid argument))))) + {:author {:dgep-native true + :name (:publicNickname author) + :id (Integer/parseInt (:uid author))} + :created nil ;; nil until we solve the graphql problem + :type link-type-val + :source {:aggregate-id config/aggregate-name + :entity-id (str (:statementUid premise)) + :version 1} + :destination {:aggregate-id config/aggregate-name + :version 1 + :entity-id (str destination-id)} + :identifier {:aggregate-id config/aggregate-name + :entity-id (str (:uid argument)) + :version 1} + :delete-flag (:isDisabled argument)}) (:premises premises)))) - (defn get-links "Return a map of all links that can be requested from the connected D-BAS instance." [] - (let [result (query-db "query {arguments {uid conclusionUid, isSupportive, authorUid, argumentUid, premisegroupUid}}") + (let [result (query-db "query {arguments {uid conclusionUid, isSupportive, author {publicNickname uid}, argumentUid, premisegroupUid, isDisabled}}") return-val (mapcat links-from-argument (:arguments result))] return-val)) +(defn get-author + "Queries D-BAS for an author and returns an author-map." + [author-id] + (let [id (if (int? author-id) + author-id + (Integer/parseInt author-id)) + result (query-db (format "query {user(uid: %d){publicNickname}}" id))] + (log/debug result) + {:dgep-native true + :id id + :name (get-in result [:user :publicNickname])})) diff --git a/aggregator/src/aggregator/query/db.clj b/aggregator/src/aggregator/query/db.clj index 1a96462..64f518d 100644 --- a/aggregator/src/aggregator/query/db.clj +++ b/aggregator/src/aggregator/query/db.clj @@ -42,7 +42,7 @@ (defn statements-by-author "Return all statements with a certain author." [author] - (unpack-elastic (elastic/search :statements {:content.author author}))) + (unpack-elastic (elastic/search :statements {:content.author.name author}))) (defn links-by-uri "Return all link-versions defined by the uri" @@ -93,15 +93,16 @@ "Returns all undercuts that point to target aggregator and entity-id." [target-aggregator target-entity-id] (keywordize-types (unpack-elastic (elastic/search :links {:type "undercut" - :destination.aggregate-id target-aggregator - :destination.entity-id target-entity-id})))) + :destination.aggregate-id target-aggregator + :destination.entity-id target-entity-id})))) (defn links-by-target "Return all links with the corresponding target." [target-aggregator target-entity target-version] - (keywordize-types (unpack-elastic (elastic/search :links {:destination.aggregate-id target-aggregator - :destination.entity-id target-entity - :destination.version target-version})))) + (keywordize-types (unpack-elastic + (elastic/search :links {:destination.aggregate-id target-aggregator + :destination.entity-id target-entity + :destination.version target-version})))) (defn random-statements "Return *num* random statements from the db." @@ -112,6 +113,12 @@ {:identifier.aggregate-id config/aggregate-name}))))) (defn statements-contain - "Return all statements from the elasticsearch-db where content.content-string containts `query`" + "Return all statements from the elasticsearch-db where content.text containts `query`" [query] (unpack-elastic (elastic/search :statements-fuzzy query))) + + +(defn custom-statement-search + "Search for statements by looking for content in a custom field." + [field search-term] + (unpack-elastic (elastic/search :statements {(keyword field) search-term}))) diff --git a/aggregator/src/aggregator/query/query.clj b/aggregator/src/aggregator/query/query.clj index 1b270f0..9b4e641 100644 --- a/aggregator/src/aggregator/query/query.clj +++ b/aggregator/src/aggregator/query/query.clj @@ -7,7 +7,8 @@ [aggregator.config :as config] [clj-http.client :as client] [clojure.string :as str] - [taoensso.timbre :as log])) + [taoensso.timbre :as log] + [aggregator.query.update :as update])) (defn get-data "Get data from a remote aggregator." @@ -24,9 +25,8 @@ "Uses the broker module to subscribe to a queue for updates. Sanitizes the host if a port is appended. Example: example.com:8888 is treated as example.com." [queue host] - (let [queue-name (get-in queue [:data :queue-name]) - cleaned-host (first (str/split host #":"))] - (sub/subscribe queue-name {:host cleaned-host}))) + (let [cleaned-host (first (str/split host #":"))] + (sub/subscribe queue {:host cleaned-host}))) (defn exact-statement "Return the exact statement from cache or db" @@ -94,10 +94,13 @@ [aggregate-id entity-id version] (if-let [possible-links (links-by-target aggregate-id entity-id version)] possible-links - (let [request-url (str config/protocol aggregate-id "/link/to/") + (let [request-url (str config/protocol aggregate-id "/links/to/") results (get-data request-url {:aggregate-id aggregate-id :entity-id entity-id :version version})] + (log/debug (format "Pulled %s downstream links for %s/%s/%s" + (count results) + aggregate-id entity-id version)) (doseq [link results] (up/update-link link)) results))) @@ -138,7 +141,7 @@ (defn starter-set "Retrieve a set of starting arguments, which can be used by remote aggregators to bootstrap the connection. This particular implementation just takes a random set of arguments from the cache or database." [] - (db/random-statements 10)) + (db/random-statements 100)) (defn remote-starter-set "Retrieve remote starter sets and put them into the cache and db." @@ -161,6 +164,7 @@ (all-remote-statements aggregator)))) ([aggregator] (let [results (:statements (get-data (str config/protocol aggregator "/statements")))] + (subscribe-to-queue "statements" aggregator) (doseq [statement results] (up/update-statement statement))))) @@ -177,10 +181,16 @@ (all-remote-links aggregator)))) ([aggregator] (let [results (get-data (str config/protocol aggregator "/links"))] + (subscribe-to-queue "links" aggregator) (doseq [link results] (up/update-link link))))) (defn statements-contain - "Retrieve all statements where the content.content-string contains the `query`" + "Retrieve all statements where the content.text contains the `query`" [query] (db/statements-contain query)) + +(defn custom-statement + "Retrieve a statement with a custom field containg a specific search-term." + [field search-term] + (db/custom-statement-search field search-term)) diff --git a/aggregator/src/aggregator/query/retriever.clj b/aggregator/src/aggregator/query/retriever.clj index 8a998af..3206f4d 100644 --- a/aggregator/src/aggregator/query/retriever.clj +++ b/aggregator/src/aggregator/query/retriever.clj @@ -5,52 +5,71 @@ [taoensso.timbre :as log])) (defn whitelisted? - "Return whether the source of a link is whitelisted." + "Return whether the aggregator of an entity is whitelisted." [link] - (some #{(get-in link [:source :aggregate-id])} config/whitelist)) + (some #{(get-in link [:identifier :aggregate-id])} config/whitelist)) -(defn next-entity - "Accepts a list and retrieves the statement the head-link is sourced by if its provider is whitelisted. Then retrieves all links connected to it and queues them. Returns the updated list." - [queue] - (if (whitelisted? (first queue)) - (let [link (first queue) - aggregate (get-in link [:source :aggregate-id]) - entity-id (get-in link [:source :entity-id]) - version (get-in link [:source :link]) - undercuts (query/retrieve-undercuts aggregate entity-id) - additional-links (query/links-to aggregate entity-id version)] - (concat (rest queue) undercuts additional-links)) - (rest queue))) +(defn- statement? + "Is the argument a statement?" + [entity] + (when (contains? entity :content) + true)) -(defn loop-next - "Loop the next function with the queue until its empty." - [queue] - (loop [q queue] - (let [next-step (next-entity q)] - (when (seq next-step) - (recur next-step))))) +(defn- str-id + "Return the string-representation of an entities ID." + [entity] + (let [aggregate-id (get-in entity [:identifier :aggregate-id]) + entity-id (get-in entity [:identifier :aggregate-id]) + version (get-in entity [:identifier :version])] + (format "%s/%s/%s" aggregate-id entity-id version))) -(defn- lookup-related - "Lookup all related links and statements 'downstream' from the starting statement." - [statement] - (log/debug (format "[retriever] Starting to pull related data for %s" statement)) - (let [aggregate-id (get-in statement [:identifier :aggregate-id]) - entity-id (get-in statement [:identifier :entity-id]) - version (get-in statement [:identifier :version]) - startlinks (query/links-to aggregate-id entity-id version)] - (loop-next startlinks))) +(defn- add-visited + "Add an element to the visited set. Returns the new set." + [visited entity] + (conj visited (str-id entity))) + +(defn lookup-related-breadth-first + [entity] + (loop [[head & rest] [entity] + visited #{}] + ;; Sleep half a second to not hog many resources + (Thread/sleep 500) + (log/debug (format "Continuing background retrieval with head %s" head)) + (let [aggregate-id (get-in head [:identifier :aggregate-id]) + entity-id (get-in head [:identifier :entity-id]) + version (get-in head [:identifier :version])] + (if (and (whitelisted? head) + (not (contains? visited (str-id head)))) ;; Loop prevention + (if (statement? head) + ;; Head is a statement - Continue with rest + all links to head + (let [links-to (query/links-to aggregate-id entity-id version) + continue-queue (concat rest links-to)] + (some-> (seq continue-queue) (recur (add-visited visited head)))) + ;; Head is a link - Get all undercuts to it and the links source if possible + (let [undercuts-to (query/retrieve-undercuts aggregate-id entity-id) + source-aggregator (get-in head [:source :aggregate-id]) + source-entity-id (get-in head [:source :entity-id]) + source-version (get-in head [:source :version]) + ; Put the statement in a vector for easier concat + source-statement [(query/retrieve-exact-statement source-aggregator + source-entity-id + source-version)] + continue-queue (concat rest undercuts-to source-statement)] + (some-> (seq continue-queue) (recur (add-visited visited head))))) + ;; Aggregator not whitelisted - Recur with rest when there are elements left + (some-> (seq rest) (recur (add-visited visited head))))))) (defn automatic-retriever "Starts an automatic retriever that looks up statements and links related to things contained in the cache." [] (future - (loop [starter (rand-nth (keys (cache/get-cached-statements)))] - (lookup-related starter) + (loop [starter (rand-nth (vals (cache/get-cached-statements)))] + (lookup-related-breadth-first starter) (log/debug "[retriever] sleeping") (Thread/sleep 60000) (log/debug "[retriever] Automatic search waking up.") (query/remote-starter-set) - (recur (rand-nth (keys (cache/get-cached-statements))))))) + (recur (rand-nth (vals (cache/get-cached-statements))))))) (defn bootstrap "Call this method when the aggregator starts. Pulls the whitelisted aggregators diff --git a/aggregator/src/aggregator/query/update.clj b/aggregator/src/aggregator/query/update.clj index 12b72bf..006fe9b 100644 --- a/aggregator/src/aggregator/query/update.clj +++ b/aggregator/src/aggregator/query/update.clj @@ -3,6 +3,10 @@ [aggregator.query.cache :as cache] [aggregator.broker.publish :as pub] [aggregator.config :as config] + [aggregator.graphql.dbas-connector :as dbas] + [aggregator.specs :as specs] + [aggregator.utils.common :as utils] + [clojure.spec.alpha :as s] [taoensso.timbre :as log])) (defn update-statement @@ -18,9 +22,12 @@ (when (= (:aggregate-id identifier) config/aggregate-name) (pub/publish-statement statement)) (db/insert-statement statement)) - (cache/cache-miss (str (:aggregate-id identifier) "/" (:entity-id identifier) "/" - (:version identifier)) - statement))) + (let [cache-uri (str (:aggregate-id identifier) "/" (:entity-id identifier) "/" + (:version identifier)) + cached-entity (cache/retrieve cache-uri)] + (when (= :missing cached-entity) + (cache/cache-miss cache-uri statement)))) + statement) (defn update-link "Update a database-entry for a link. Typically inserts a link if not in DB yet." @@ -38,4 +45,99 @@ (cache/cache-miss-link (str (:aggregate-id identifier) "/" (:entity-id identifier) "/" (:version identifier)) link) - (db/insert-link link)))) + (db/insert-link link)) + link)) + +(defn update-statement-content + "Updates the text of a statement and bumps the version." + [statement updated-text] + (let [updated-statement (-> statement + (assoc-in [:content :text] (str updated-text)) + (update-in [:identifier :version] inc))] + (when (s/valid? ::specs/statement updated-statement) + (db/insert-statement updated-statement) + updated-statement))) + +(defn fork-statement + "Forks a statement with a new identifier, text and author." + [statement identifier text author] + (let [updated-statement (-> statement + (assoc-in [:content :text] (str text)) + (assoc-in [:content :author] (utils/json->edn author)) + (assoc :identifier identifier) + (assoc-in [:identifier :version] 1) + (assoc :predecessors [(:identifier statement)]))] + (when (s/valid? ::specs/statement updated-statement) + (db/insert-statement updated-statement) + (pub/publish-statement updated-statement) + updated-statement))) + +(defn- statement-from-minimal + "Generate a statement from the minimal needed information." + ([text author] + (statement-from-minimal text author {})) + ([text author additional] + (let [statement {:content {:text text + :author author + :created (utils/time-now-str)} + :identifier {:aggregate-id config/aggregate-name + :entity-id (str (java.util.UUID/randomUUID)) + :version 1} + :delete-flag false + :predecessors []} + forbidden-fields #{:content :identifier :delete-flag :predecessors} + filtered-additional (apply dissoc additional forbidden-fields)] + (conj statement filtered-additional)))) + +(defn- link-premise-conclusion + "Given a premise and a conclusion, link them both with an argument link." + [premise conclusion link-type author] + (let [premise-id (:identifier premise) + conclusion-id (:identifier conclusion)] + {:type (:keyword link-type) + :author author + :source premise-id + :destination conclusion-id + :delete-flag false + :identifier {:aggregate-id config/aggregate-name + :entity-id (str "link_" (java.util.UUID/randomUUID)) + :version 1} + :created (utils/time-now-str)})) + +(defn add-argument + "Adds an argument to the database. Asuming the author exists and belongs to the local DGEP." + ([premise conclusion link-type author-id] + (add-argument premise conclusion link-type author-id {} {})) + ([premise conclusion link-type author-id additional-premise additional-conclusion] + (let [author (dbas/get-author author-id) + complete-premise (statement-from-minimal premise author additional-premise) + complete-conclusion (statement-from-minimal conclusion author additional-conclusion) + link (link-premise-conclusion complete-premise complete-conclusion link-type author)] + (update-statement complete-premise) + (update-statement complete-conclusion) + (update-link link) + {:premise-id (:identifier complete-premise) + :conclusion-id (:identifier complete-conclusion) + :link-id (:identifier link)}))) + +(defn statement-from-text + "Adds an argument only from text and author-id. Assumes author belongs to local DGEP." + ([text author-id] + (statement-from-text text author-id {})) + ([text author-id additional] + (let [author (dbas/get-author author-id)] + (update-statement (statement-from-minimal text author additional))))) + +(defn quicklink + "Add a link from source, destination, type and author. Assumes author belongs to local DGEP" + [type source destination author-id] + (let [author (dbas/get-author author-id)] + {:type type + :source source + :destination destination + :identifier {:aggregate-id config/aggregate-name + :entity-id (str "link-" (java.util.UUID/randomUUID)) + :version 1} + :delete-flag false + :created (utils/time-now-str) + :author author})) diff --git a/aggregator/src/aggregator/search/core.clj b/aggregator/src/aggregator/search/core.clj index b678b53..e6a0086 100644 --- a/aggregator/src/aggregator/search/core.clj +++ b/aggregator/src/aggregator/search/core.clj @@ -171,7 +171,7 @@ (search-request {:query {:match - {:content.content-string + {:content.text {:query (append-star-if-not-empty querystring) :fuzziness "AUTO"}}}} :statements)) @@ -220,8 +220,8 @@ :filter ["lowercase" "synonym_filter"]}}}}} {:statement {:properties {:identifier.aggregate-id {:type :keyword} :identifier.entity-id {:type :keyword} - :content.content-string {:type "text" - :analyzer "synonym_analyzer"}}}}) + :content.text {:type "text" + :analyzer "synonym_analyzer"}}}}) (create-index "links" {} {:link {:properties {:identifier.aggregate-id {:type :keyword} :identifier.entity-id {:type :keyword}}}})) diff --git a/aggregator/src/aggregator/specs.clj b/aggregator/src/aggregator/specs.clj index d04e608..f395ca6 100644 --- a/aggregator/src/aggregator/specs.clj +++ b/aggregator/src/aggregator/specs.clj @@ -2,12 +2,17 @@ (:require [clojure.spec.alpha :as s])) (s/def ::no-slash (s/and string? #(not (re-find #"/" %)) #(pos? (count %)))) +(s/def ::non-empty-string (s/and string? #((complement clojure.string/blank?) %))) -(s/def ::author string?) -(s/def ::content-string string?) +(s/def ::dgep-native boolean?) +(s/def ::name ::non-empty-string) +(s/def ::id pos-int?) +(s/def ::author (s/keys :req-un [::dgep-native ::name ::id])) + +(s/def ::text ::non-empty-string) (s/def ::created (s/or :nil nil? :timestamp string?)) ;; timestamp (s/def ::content - (s/keys :req-un [::content-string ::created ::author])) + (s/keys :req-un [::text ::created ::author])) (s/def ::aggregate-id ::no-slash) (s/def ::entity-id ::no-slash) diff --git a/aggregator/src/aggregator/utils/common.clj b/aggregator/src/aggregator/utils/common.clj index 40e599c..bd83648 100644 --- a/aggregator/src/aggregator/utils/common.clj +++ b/aggregator/src/aggregator/utils/common.clj @@ -58,6 +58,11 @@ ([message data] (return-map :ok message data))) +(defn time-now-str + "Returns the current time as an Linux Epoch Time String." + [] + (str (.getEpochSecond (java.time.Instant/now)))) + ;; ----------------------------------------------------------------------------- ;; Specs diff --git a/aggregator/src/aggregator/utils/pg_listener.clj b/aggregator/src/aggregator/utils/pg_listener.clj index 8b20acb..98c611e 100644 --- a/aggregator/src/aggregator/utils/pg_listener.clj +++ b/aggregator/src/aggregator/utils/pg_listener.clj @@ -3,7 +3,7 @@ [aggregator.config :as config] [aggregator.query.update :as update] [taoensso.timbre :as log] - [aggregator.graphql.dbas-connector :refer [links-from-argument get-statement-origin]])) + [aggregator.graphql.dbas-connector :as dbas-conn :refer [links-from-argument get-statement-origin]])) (defn- handle-statements "Handle changes in statements" @@ -14,11 +14,12 @@ "Handle changes in the textversions. They belong to the statements." [textversion] (log/debug (format "Received new textversion from D-BAS: %s" (:data textversion))) - (let [statement {:content {:author (get-in textversion [:data :author_uid]) - :content-string (get-in textversion [:data :content]) + (let [author-id (get-in textversion [:data :author_uid]) + statement {:content {:author (dbas-conn/get-author author-id) + :text (get-in textversion [:data :content]) :created nil} :identifier {:aggregate-id config/aggregate-name - :entity-id (get-in textversion [:data :uid]) + :entity-id (str (get-in textversion [:data :uid])) :version 1} :delete-flag false :predecessors []} @@ -26,13 +27,14 @@ (if origin (update/update-statement (assoc-in (assoc statement - :identifier {:aggregate-id (:aggregate_id origin) - :entity-id (:entity_id origin) + :identifier {:aggregate-id (str (:aggregate_id origin)) + :entity-id (str (:entity_id origin)) :version (:version origin)}) - [:content :author] (:author origin))) + [:content :author] {:dgep-native false + :name (str (:author origin)) + :id 1234567})) (update/update-statement statement)))) - (defn- handle-arguments "Handle changes in arguments and update links correspondingly." [argument] diff --git a/aggregator/test/aggregator/api/routes_test.clj b/aggregator/test/aggregator/api/routes_test.clj index d1b53eb..67efe5a 100644 --- a/aggregator/test/aggregator/api/routes_test.clj +++ b/aggregator/test/aggregator/api/routes_test.clj @@ -6,9 +6,9 @@ [cheshire.core :as cheshire])) (defn fixtures [f] - (connector/init-connection!) + (connector/init-local-connection!) (f) - (connector/close-connection!)) + (connector/close-local-connection!)) (use-fixtures :once fixtures) (defn- parse-body [body] @@ -16,9 +16,9 @@ (deftest handler-test - (testing "Test root route for status 200" + (testing "Test root route for status 302" (let [response (routes/app (mock/request :get "/"))] - (is (= (:status response) 200))))) + (is (= (:status response) 302))))) (deftest statement-nonexistent-route (testing "Test nonexistent-route for status 500" diff --git a/aggregator/test/aggregator/broker/connector_test.clj b/aggregator/test/aggregator/broker/connector_test.clj index b8f2dda..48dd9a8 100644 --- a/aggregator/test/aggregator/broker/connector_test.clj +++ b/aggregator/test/aggregator/broker/connector_test.clj @@ -5,9 +5,9 @@ ;; Test preparation (defn fixtures [f] - (connector/init-connection!) + (connector/init-local-connection!) (f) - (connector/close-connection!)) + (connector/close-local-connection!)) (use-fixtures :once fixtures) @@ -15,13 +15,14 @@ ;; Tests (deftest open-channel-test - (is (not (nil? (connector/open-channel))))) + (is (not (nil? (connector/open-channel!))))) (deftest close-channel-test - (is (= :ok (:status (-> (connector/open-channel) connector/close-channel))))) + (is (= :ok (:status (-> (connector/open-channel!) connector/close-channel!))))) (deftest create-queue-test - (is (= :ok (:status (connector/create-queue "i.am.groot"))))) + (is (= :ok (:status (connector/create-queue "i.am.groot")))) + (connector/delete-queue "i.am.groot")) (deftest delete-queue-test (let [queue (str (lib/uuid))] @@ -36,8 +37,8 @@ (is (not (connector/queue-exists? queue))))) (deftest connected? - (connector/init-connection!) + (connector/init-local-connection!) (is (connector/connected?)) - (connector/close-connection!) + (connector/close-local-connection!) (is (not (connector/connected?))) - (connector/init-connection!)) + (connector/init-local-connection!)) diff --git a/aggregator/test/aggregator/broker/publish_test.clj b/aggregator/test/aggregator/broker/publish_test.clj index e1307be..f4d5855 100644 --- a/aggregator/test/aggregator/broker/publish_test.clj +++ b/aggregator/test/aggregator/broker/publish_test.clj @@ -7,11 +7,12 @@ (defonce queue (first (last (s/exercise string?)))) -(def statement {:content {:author "kangaroo" - :content-string "Schnapspralinen" +(def statement {:content {:author {:dgep-native false + :name "Kängaroo" + :id 15} + :text "Schnapspralinen" :created nil} - :identifier { - :aggregate-id "huepfer.verlag" + :identifier {:aggregate-id "huepfer.verlag" :entity-id "1" :version 1} :predecessors {} @@ -22,9 +23,9 @@ ;; Test preparation (defn fixtures [f] - (connector/init-connection!) + (connector/init-local-connection!) (f) - (connector/close-connection!)) + (connector/close-local-connection!)) (use-fixtures :once fixtures) diff --git a/aggregator/test/aggregator/broker/subscriber_test.clj b/aggregator/test/aggregator/broker/subscriber_test.clj index 751fcea..4175221 100644 --- a/aggregator/test/aggregator/broker/subscriber_test.clj +++ b/aggregator/test/aggregator/broker/subscriber_test.clj @@ -10,12 +10,16 @@ (def queue (str (lib/uuid))) (def queue-two (str (lib/uuid))) ;; like Mewto, hihi -(def statement {:author "kangaroo" - :content "Schnapspralinen" - :aggregate-id "huepfer.verlag" - :entity-id "1" - :version 1 - :created nil}) +(def statement {:content {:text "Schnapspralinen2" + :created nil + :author {:dgep-native false + :name "kangaroo" + :id 42}} + :identifier {:aggregate-id "huepfer.verlag" + :entity-id "1" + :version 1} + :delete-flag true + :predecessors []}) (def link (first (last (s/exercise ::gspecs/link)))) @@ -26,7 +30,7 @@ ;; Test preparation (defn fixtures [f] - (connector/init-connection!) + (connector/init-local-connection!) (connector/create-queue queue) (connector/create-queue queue-two) (pub/publish-statement statement) @@ -34,7 +38,7 @@ (f) (connector/delete-queue queue) (connector/delete-queue queue-two) - (connector/close-connection!)) + (connector/close-local-connection!)) (use-fixtures :once fixtures) @@ -52,15 +56,6 @@ (is (= :error (:status (sub/subscribe handler queue (assoc broker :host "deathstar#4")))))) - (testing "Wrong user gives status :error" - (deftest subscribe-wrong-user - (is (= :error (:status - (sub/subscribe handler queue - (assoc broker :user "yoda"))))))) - (testing "Wrong password also returns an :error" - (is (= :error (:status - (sub/subscribe handler queue - (assoc broker :user "The wrong password you have.")))))) (testing "Can't subscribe to a non-existent queue" (is (= :error (:status (sub/subscribe handler diff --git a/aggregator/test/aggregator/query/db_test.clj b/aggregator/test/aggregator/query/db_test.clj index c968128..e10864d 100644 --- a/aggregator/test/aggregator/query/db_test.clj +++ b/aggregator/test/aggregator/query/db_test.clj @@ -7,73 +7,98 @@ (defn fixtures [f] (search/entrypoint) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "34" :version 1} - :content {:author "Jorge" - :content-string "money does not solve problems of our society" + :content {:author {:name "Jorge" + :dgep-native true + :id 1234} + :text "money does not solve problems of our society" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P12" :version 1} - :content {:author "George" - :content-string "we should shut down University Park" + :content {:author {:name "George" + :dgep-native true + :id 1234} + :text "we should shut down University Park" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P13" :version 1} - :content {:author "George" - :content-string "shutting down University Park will save $100.000 a year" + :content {:author {:name "George" + :dgep-native true + :id 1234} + :text "shutting down University Park will save $100.000 a year" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P22" :version 1} - :content {:author "AlterVerwalter" - :content-string "the city is planing a new park in the upcoming month" + :content {:author {:name "AlterVerwalter" + :dgep-native true + :id 1234} + :text "the city is planing a new park in the upcoming month" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "7" :version 1} - :content {:author "Bolek" - :content-string "we should not abandon our town's core task" + :content {:author {:name "Bolek" + :dgep-native true + :id 1234} + :text "we should not abandon our town's core task" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P23" :version 1} - :content {:author "XxxBaerchiDarkDestoyerxxX" - :content-string "there is a smaller park in O-Town" + :content {:author {:name "XxxBaerchiDarkDestoyerxxX" + :dgep-native true + :id 1234} + :text "there is a smaller park in O-Town" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P232" :version 1} - :content {:author "XxxBestoyerxxX" - :content-string "there is a smaller park in O-Town" + :content {:author {:name "XxxBestroyerxxX" + :dgep-native true + :id 1234} + :text "there is a smaller park in O-Town" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P231" :version 1} - :content {:author "XxxBoyerxxX" - :content-string "there is a smaller park in O-Town" + :content {:author {:name "XxxBoyerxxX" + :dgep-native true + :id 1234} + :text "there is a smaller park in O-Town" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P230" :version 1} - :content {:author "XxxBayerxxX" - :content-string "there is a smaller park in O-Town" + :content {:author {:name "XxxBayerxxX" + :dgep-native true + :id 1234} + :text "there is a smaller park in O-Town" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P29" :version 1} - :content {:author "XxxBaeryerxxX" - :content-string "there is a smaller park in O-Town" + :content {:author {:name "XxxBaeryerxxX" + :dgep-native true + :id 1234} + :text "there is a smaller park in O-Town" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id config/aggregate-name :entity-id "P29v2" :version 1} - :content {:author "XxxBaeryerxxX" - :content-string "there is a smaller park in O-Town" + :content {:author {:name "XxxBaeryerxxX" + :dgep-native true + :id 1234} + :text "there is a smaller park in O-Town" :created nil} :predecessors {} :delete-flag false}) - - (db/insert-link {:author "Wegi" :created nil :type :undercut + + (db/insert-link {:author {:name "Wegi" + :dgep-native true + :id 1234} + :created nil :type :undercut :source {:aggregate-id "schneider.gg" :entity-id "W01" :version 1337} :destination {:aggregate-id "schneider.gg" @@ -89,9 +114,9 @@ (is (= (get-in (first (db/statements-by-uri "hhu.de/34")) [:identifier :version]) 1)) (is (= (get-in (first (db/statements-by-uri "hhu.de/P12")) [:identifier :aggregate-id]) "hhu.de")) (is (= (get-in (first (db/statements-by-uri "hhu.de/P13")) [:identifier :entity-id]) "P13")) - (is (= (get-in (first (db/statements-by-uri "hhu.de/P22")) [:content :content-string]) + (is (= (get-in (first (db/statements-by-uri "hhu.de/P22")) [:content :text]) "the city is planing a new park in the upcoming month")) - (is (= (get-in (first (db/statements-by-uri "hhu.de/7")) [:content :author]) "Bolek"))) + (is (= (get-in (first (db/statements-by-uri "hhu.de/7")) [:content :author :name]) "Bolek"))) (deftest statement-by-author-test (is (= (count (db/statements-by-author "XxxBaerchiDarkDestoyerxxX")) 1)) @@ -99,19 +124,22 @@ (deftest insert-statement-test (db/insert-statement {:content - {:author "Wegi" :content-string "Test me baby one more time" :created nil} + {:author {:name "Wegi" + :dgep-native true + :id 1234} + :text "Test me baby one more time" :created nil} :identifier {:aggregate-id "schneider.gg" :entity-id "W01" :version 1337} :delete-flag false :predecessors {}}) (Thread/sleep 2000) - (is (= (get-in (db/exact-statement "schneider.gg" "W01" 1337) [:content :content-string]) + (is (= (get-in (db/exact-statement "schneider.gg" "W01" 1337) [:content :text]) "Test me baby one more time"))) (deftest insert-link-test - (is (= (:author (db/exact-link "schneider.gg" "W01" 1337 "schneider.gg" "W_link_35" 1)) + (is (= (:name (:author (db/exact-link "schneider.gg" "W01" 1337 "schneider.gg" "W_link_35" 1))) "Wegi")) - (is (= "Wegi" (:author (first (db/links-by-uri "schneider.gg/link0r1337")))))) + (is (= "Wegi" (:name (:author (first (db/links-by-uri "schneider.gg/link0r1337"))))))) (deftest random-statements (let [results (db/random-statements 1)] @@ -121,7 +149,7 @@ (deftest test-entity-by-uri (let [results (db/entities-by-uri "hhu.de/34" :statements)] (is (= 1 (count results))) - (is (= "Jorge" (get-in (first results) [:content :author]))))) + (is (= "Jorge" (get-in (first results) [:content :author :name]))))) (deftest test-undercuts (let [results (db/get-undercuts "schneider.gg" "W_link_35")] diff --git a/aggregator/test/aggregator/query/query_test.clj b/aggregator/test/aggregator/query/query_test.clj index 3323104..35ba4ba 100644 --- a/aggregator/test/aggregator/query/query_test.clj +++ b/aggregator/test/aggregator/query/query_test.clj @@ -8,79 +8,106 @@ (defn fixtures [f] (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "34" :version 1} - :content {:author "Jorge" - :content-string "money does not solve problems of our society" + :content {:author {:name "Jorge" + :dgep-native true + :id 1234} + :text "money does not solve problems of our society" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P12" :version 1} - :content {:author "George" - :content-string "we should shut down University Park" + :content {:author {:name "George" + :dgep-native true + :id 1234} + :text "we should shut down University Park" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P13" :version 1} - :content {:author "George" - :content-string "shutting down University Park will save $100.000 a year" + :content {:author {:name "George" + :dgep-native true + :id 1234} + :text "shutting down University Park will save $100.000 a year" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P22" :version 1} - :content {:author "AlterVerwalter" - :content-string "the city is planing a new park in the upcoming month" + :content {:author {:name "AlterVerwalter" + :dgep-native true + :id 1234} + :text "the city is planing a new park in the upcoming month" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "7" :version 1} - :content {:author "Bolek" - :content-string "we should not abandon our town's core task" + :content {:author {:name "Bolek" + :dgep-native true + :id 1234} + :text "we should not abandon our town's core task" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P23" :version 1} - :content {:author "XxxBaerchiDarkDestoyerxxX" - :content-string "there is a smaller park in O-Town" + :content {:author {:name "XxxBaerchiDarkDestoyerxxX" + :dgep-native true + :id 1234} + :text "there is a smaller park in O-Town" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P232" :version 1} - :content {:author "XxxBestoyerxxX" - :content-string "there is a smaller park in O-Town" + :content {:author {:name "XxxBestoyerxxX" + :dgep-native true + :id 1234} + :text "there is a smaller park in O-Town" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P231" :version 1} - :content {:author "XxxBoyerxxX" - :content-string "there is a smaller park in O-Town" + :content {:author {:name "XxxBoyerxxX" + :dgep-native true + :id 1234} + :text "there is a smaller park in O-Town" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P230" :version 1} - :content {:author "XxxBayerxxX" - :content-string "there is a smaller park in O-Town" + :content {:author {:name "XxxBayerxxX" + :dgep-native true + :id 1234} + :text "there is a smaller park in O-Town" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P29" :version 1} - :content {:author "XxxBaeryerxxX" - :content-string "there is a smaller park in O-Town" + :content {:author {:name "XxxBaeryerxxX" + :dgep-native true + :id 1234} + :text "there is a smaller park in O-Town" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id "hhu.de" :entity-id "P420" :version 1} - :content {:author "saywhaaat" - :content-string "califragilistic extrahotentific" + :content {:author {:name "saywhaaat" + :dgep-native true + :id 1234} + :text "califragilistic extrahotentific" :created nil} :predecessors {} :delete-flag false}) (db/insert-statement {:identifier {:aggregate-id config/aggregate-name :entity-id "P29v2" :version 1} - :content {:author "XxxBaeryerxxX" - :content-string "there is a smaller park in O-Town" + :content {:author {:name "XxxBaeryerxxX" + :dgep-native true + :id 1234} + :text "there is a smaller park in O-Town" :created nil} :predecessors {} :delete-flag false}) - (db/insert-link {:author "Wegi" :created nil :type :undercut + (db/insert-link {:author {:name "Wegi" + :dgep-native true + :id 1234} + :created nil :type :undercut :source {:aggregate-id "schneider.gg" :entity-id "W01" :version 1337} :destination {:aggregate-id "schneider.gg" @@ -103,8 +130,10 @@ (deftest test-cached-statements (let [statement {:identifier {:aggregate-id "cache-aggregator" :entity-id "cache-id" :version 1} - :content {:author "XxxBaeryerxxX" - :content-string "there is a smaller park in O-Town" + :content {:author {:name "XxxBaeryerxxX" + :dgep-native true + :id 1234} + :text "there is a smaller park in O-Town" :created nil} :predecessors {} :delete-flag false} diff --git a/aggregator/test/aggregator/query/update_test.clj b/aggregator/test/aggregator/query/update_test.clj index 51f0dc3..916dd92 100644 --- a/aggregator/test/aggregator/query/update_test.clj +++ b/aggregator/test/aggregator/query/update_test.clj @@ -1,29 +1,113 @@ (ns aggregator.query.update-test (:require [aggregator.query.update :as update] + [aggregator.query.query :as query] [aggregator.config :as config] [clojure.test :refer [deftest is]])) +(def some-statement + {:identifier {:aggregate-id "name-test" :entity-id "34" :version 1} + :content {:author {:name "Jorge" + :id 666 + :dgep-native false} + :text "money does not solve problems of our society" + :created nil} + :predecessors {} + :delete-flag false}) + +(def some-link + {:author {:name "Wegi" + :dgep-native true + :id 1234} + :created nil + :type :undercut + :source {:aggregate-id "schneider.gg" + :entity-id "W01" :version 1337} + :destination {:aggregate-id "test-link" + :entity-id "W_link_35" :version 1} + :identifier {:aggregate-id "number2" :entity-id "link0r1337" :version 1} + :delete-flag false}) + (deftest test-known-aggregators-update (reset! config/app-state {:known-aggregators #{}}) - (update/update-statement - {:identifier {:aggregate-id "name-test" :entity-id "34" :version 1} - :content {:author "Jorge" - :content-string "money does not solve problems of our society" - :created nil} - :predecessors {} - :delete-flag false}) + (update/update-statement some-statement) (is (contains? (:known-aggregators @config/app-state) "name-test"))) (deftest test-known-aggregators-from-links (reset! config/app-state {:known-aggregators #{}}) - (update/update-link - {:author "Wegi" :created nil :type :undercut - :source {:aggregate-id "schneider.gg" - :entity-id "W01" :version 1337} - :destination {:aggregate-id "test-link" - :entity-id "W_link_35" :version 1} - :identifier {:aggregate-id "number2" :entity-id "link0r1337" :version 1} - :delete-flag false}) + (update/update-link some-link) (is (contains? (:known-aggregators @config/app-state) "schneider.gg")) (is (contains? (:known-aggregators @config/app-state) "test-link")) (is (contains? (:known-aggregators @config/app-state) "number2"))) + +(deftest test-updated-content + (let [updated-statement (update/update-statement-content some-statement "lolz") + updated-statement-2 (update/update-statement-content some-statement :fooo) + not-a-statement (update/update-statement-content some-link "fail")] + (is (= 2 (get-in updated-statement [:identifier :version]))) + (is (= "lolz" (get-in updated-statement [:content :text]))) + (is (= ":fooo" (get-in updated-statement-2 [:content :text]))) + (is (nil? not-a-statement)))) + +(deftest test-fork-statement + (let [updated-statement (update/fork-statement some-statement {:aggregate-id "new-agg.de" + :entity-id "42" + :version 15} + "New content" + {:name "Der Wetschi" + :dgep-native true + :id 1}) + predecessor (first (:predecessors updated-statement))] + (is (= 1 (get-in updated-statement [:identifier :version]))) + (is (= "New content" (get-in updated-statement [:content :text]))) + (is (= "new-agg.de" (get-in updated-statement [:identifier :aggregate-id]))) + (is (= "42" (get-in updated-statement [:identifier :entity-id]))) + (is (= "Der Wetschi" (get-in updated-statement [:content :author :name]))) + (is (= "name-test" (:aggregate-id predecessor))) + (is (= "34" (:entity-id predecessor))))) + + +(deftest test-add-argument + (let [{:keys [premise-id conclusion-id link-id]} (update/add-argument + "Der Kalli testet" + "Conclusion wird supportet" + :support + 1)] + (is (= "anonymous" + (get-in (query/exact-statement (:aggregate-id premise-id) + (:entity-id premise-id) + (:version premise-id)) + [:content :author :name]))) + (is (= "Conclusion wird supportet" + (get-in (query/exact-statement (:aggregate-id conclusion-id) + (:entity-id conclusion-id) + (:version conclusion-id)) + [:content :text]))) + (is (not (nil? + (count (query/retrieve-link (:aggregate-id link-id) + (:entity-id link-id) + (:version link-id)))))))) + +(deftest test-statement-from-text + (let [text "This statement-stuff is craaaaazy" + new-statement (update/statement-from-text text 1) + statement-with-adds (update/statement-from-text text 1 {:aggregator-id :rekt + :content "doubly" + :reference "My Humps"})] + (is (= text (get-in new-statement [:content :text]))) + (is (= "anonymous" (get-in new-statement [:content :author :name]))) + (is (= config/aggregate-name (get-in new-statement [:identifier :aggregate-id]))) + (is (= 1 (get-in new-statement [:identifier :version]))) + (is (= text (get-in statement-with-adds [:content :text]))) + (is (= "anonymous" (get-in statement-with-adds [:content :author :name]))) + (is (= config/aggregate-name (get-in statement-with-adds [:identifier :aggregate-id]))) + (is (= "My Humps" (:reference statement-with-adds))))) + +(deftest test-quicklink-add + (let [source (:source some-link) + destination (assoc (:source some-link) :entity-id "link_special_1") + new-link (update/quicklink :support source destination 1)] + (is (= "schneider.gg" (get-in new-link [:source :aggregate-id]))) + (is (= "link_special_1" (get-in new-link [:destination :entity-id]))) + (is (= config/aggregate-name (get-in new-link [:identifier :aggregate-id]))) + (is (= 1 (get-in new-link [:identifier :version]))) + (is (= "anonymous" (get-in new-link [:author :name]))))) diff --git a/aggregator/test/aggregator/search/core_test.clj b/aggregator/test/aggregator/search/core_test.clj index 70a04af..4a3730f 100644 --- a/aggregator/test/aggregator/search/core_test.clj +++ b/aggregator/test/aggregator/search/core_test.clj @@ -4,8 +4,10 @@ [clojure.spec.alpha :as s] [aggregator.specs :as gspecs])) -(def kangaroo {:content {:content-string "Schnapspralinen" - :author "kangaroo" +(def kangaroo {:content {:text "Schnapspralinen" + :author {:name "kangaroo" + :dgep-native true + :id 1234} :created nil} :identifier {:aggregate-id "huepfer.verlag" :entity-id "1" @@ -13,8 +15,10 @@ :predecessors {} :delete-flag false}) -(def penguin {:content {:content-string "Teewurst" - :author "penguin" +(def penguin {:content {:text "Teewurst" + :author {:name "penguin" + :dgep-native true + :id 1234} :created nil} :identifier {:aggregate-id "penguin.books:8080" :entity-id "1" @@ -22,8 +26,10 @@ :predecessors {} :delete-flag false}) -(def penguin2 {:content {:content-string "Teewurst 2: Die Rache der Teewurst" - :author "penguin" +(def penguin2 {:content {:text "Teewurst 2: Die Rache der Teewurst" + :author {:name "penguin" + :dgep-native true + :id 1234} :created nil} :identifier {:aggregate-id "penguin.books:8080" :entity-id "2" diff --git a/dbas b/dbas index a76cb46..f6c0abc 160000 --- a/dbas +++ b/dbas @@ -1 +1 @@ -Subproject commit a76cb46963436be183f1b799d587b9900082affa +Subproject commit f6c0abc9942731fd2092a2cd0fee502f22690b12 diff --git a/docker-compose.yml b/docker-compose.yml index 2888dbb..02ea5c2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,11 @@ -version: "3.1" +version: "3.2" services: broker: image: rabbitmq:3.6-management-alpine ports: - "15672:15672" # web-access to management console - # - "5671-5672:5671-5672" # for debugging, exposes RabbitMQs port to connect from localhost + - "5671-5672:5671-5672" # for debugging, exposes RabbitMQs port to connect from localhost environment: - "RABBITMQ_DEFAULT_USER=${BROKER_USER}" - "RABBITMQ_DEFAULT_PASS=${BROKER_PASS}" @@ -37,7 +37,7 @@ services: - "DBAS_HOST=dbas" - "ELASTICSEARCH_HOST=search" - "DB_HOST=dbas-db" - - "AGGREGATOR_NAME=aggregator:8888" + - AGGREGATOR_NAME search: build: elasticsearch/ @@ -62,18 +62,24 @@ services: ports: - "4284:4284" links: - - dbas-db:db - env_file: - - dbas/development.env -# environment: -# - "DBAS_DB_USER=${DBAS_DB_USER}" -# - "DBAS_DB_PW=${DBAS_DB_PW}" -# - "DBAS_DB_HOST=${DBAS_DB_HOST}" -# - "DBAS_DB_PORT=${DBAS_DB_PORT}" -# - "DBAS_AUTHN_SECRET=${DBAS_AUTHN_SECRET}" + - dbas-db:db + environment: + - "DB_USER=${DB_USER}" + - "DB_PW=${DB_PW}" + - "DB_PORT=${DB_PORT}" + - "DB_NAME=${DB_NAME}" + - "DB_HOST=${DB_HOST}" + - "AUTHN_SECRET=${AUTHN_SECRET}" + - HHU_LDAP_SERVER + - HHU_LDAP_BASE + - HHU_LDAP_ACCOUNT_SCOPE + - HHU_LDAP_ACCOUNT_FILTER + - HHU_LDAP_ACCOUNT_FIRSTNAME + - HHU_LDAP_ACCOUNT_LAST + - HHU_LDAP_ACCOUNT_TITLE + - HHU_LDAP_ACCOUNT_EMAIL volumes: - ./dbas:/dbas - - ./dbas_development.env:/dbas/development.env dbas-db: build: dbas/docker/db/