Initial commit
This commit is contained in:
commit
17fe28a1ac
55 changed files with 3786 additions and 0 deletions
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/target
|
||||||
|
/lib
|
||||||
|
/classes
|
||||||
|
/checkouts
|
||||||
|
pom.xml
|
||||||
|
dev-config.edn
|
||||||
|
test-config.edn
|
||||||
|
*.jar
|
||||||
|
*.class
|
||||||
|
/.lein-*
|
||||||
|
profiles.clj
|
||||||
|
/.env
|
||||||
|
.nrepl-port
|
||||||
|
/log
|
||||||
|
.idea
|
8
.rebel_readline_history
Normal file
8
.rebel_readline_history
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
1547000855890:(append-svg)
|
||||||
|
1547001941101:(clean-builds)
|
||||||
|
1547001987967:(reset-autobuild)
|
||||||
|
1547002493261:cljs:quit
|
||||||
|
1547049842827:(reset-autobuild)
|
||||||
|
1547053573677:(reload-config)
|
||||||
|
1547053584758:(fig-status)
|
||||||
|
1547053746469:(reload-config)
|
28
Capstanfile
Normal file
28
Capstanfile
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
#
|
||||||
|
# Name of the base image. Capstan will download this automatically from
|
||||||
|
# Cloudius S3 repository.
|
||||||
|
#
|
||||||
|
#base: cloudius/osv
|
||||||
|
base: cloudius/osv-openjdk8
|
||||||
|
|
||||||
|
#
|
||||||
|
# The command line passed to OSv to start up the application.
|
||||||
|
#
|
||||||
|
cmdline: /java.so -jar /cat/app.jar
|
||||||
|
|
||||||
|
#
|
||||||
|
# The command to use to build the application.
|
||||||
|
# You can use any build tool/command (make/rake/lein/boot) - this runs locally on your machine
|
||||||
|
#
|
||||||
|
# For Leiningen, you can use:
|
||||||
|
#build: lein uberjar
|
||||||
|
# For Boot, you can use:
|
||||||
|
#build: boot build
|
||||||
|
|
||||||
|
#
|
||||||
|
# List of files that are included in the generated image.
|
||||||
|
#
|
||||||
|
files:
|
||||||
|
/cat/app.jar: ./target/uberjar/cat.jar
|
||||||
|
|
7
Dockerfile
Normal file
7
Dockerfile
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
FROM openjdk:8-alpine
|
||||||
|
|
||||||
|
COPY target/uberjar/cat.jar /cat/app.jar
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["java", "-jar", "/cat/app.jar"]
|
1
Procfile
Normal file
1
Procfile
Normal file
|
@ -0,0 +1 @@
|
||||||
|
web: java -cp target/uberjar/cat.jar clojure.main -m cat.core
|
29
README.md
Normal file
29
README.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# cat
|
||||||
|
|
||||||
|
generated using Luminus version "3.10.29"
|
||||||
|
init with options: postgres, cljs, auth, oauth, site, kibit
|
||||||
|
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
You will need [Leiningen][1] 2.0 or above installed.
|
||||||
|
|
||||||
|
[1]: https://github.com/technomancy/leiningen
|
||||||
|
|
||||||
|
## Running
|
||||||
|
|
||||||
|
Copy `dev-config.edn_example` to `dev-config.edn` and fill in the needed fields
|
||||||
|
|
||||||
|
`test-config.edn` is used for test execution.
|
||||||
|
|
||||||
|
To start a web server for the application, run:
|
||||||
|
|
||||||
|
lein run
|
||||||
|
|
||||||
|
To start the ui live rendering, run:
|
||||||
|
|
||||||
|
lein figwheel
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Copyright © 2019 FIXME
|
220
cat.iml
Normal file
220
cat.iml
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module cursive.leiningen.project.LeiningenProjectsManager.displayName="cat:0.1.0-SNAPSHOT" cursive.leiningen.project.LeiningenProjectsManager.isLeinModule="true" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<output url="file://$MODULE_DIR$/target/default/classes" />
|
||||||
|
<output-test url="file://$MODULE_DIR$/target/default/classes" />
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/cljs" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/env/dev/clj" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/target/cljsbuild" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/clj" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/dev-resources" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/cljc" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/env/dev/resources" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/env/dev/cljs" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/test/clj" isTestSource="true" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target/cljsbuild/public/js" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target/default" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="vega" level="application" />
|
||||||
|
<orderEntry type="library" name="Leiningen: args4j:2.0.26" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: binaryage/devtools:0.9.10" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: binaryage/env-config:0.2.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: buddy/buddy-auth:2.1.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: buddy/buddy-core:1.4.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: buddy/buddy-hashers:1.3.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: buddy/buddy-sign:2.2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: buddy:2.0.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: ch.qos.logback/logback-classic:1.1.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: ch.qos.logback/logback-core:1.1.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: cheshire:5.8.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: cider/cider-nrepl:0.18.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: cider/piggieback:0.3.10" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: clj-http:2.0.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: clj-oauth:1.5.5" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: clj-stacktrace:0.2.8" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: clj-time:0.14.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: clj-tuple:0.2.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: cljfmt:0.5.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: cljsjs/ajv:4.7.7-0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: cljsjs/d3:3.5.16-0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: cljsjs/vega:2.6.0-0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: clojure-complete:0.2.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: clojure.java-time:0.3.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: clojurewerkz/scrypt:1.2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: clout:2.2.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: co.deps/ring-etag-middleware:0.2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.andrewmcveigh/cljs-time:0.5.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.carouselapps/to-jdbc-uri:0.5.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.cognitect/transit-clj:0.8.313" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.cognitect/transit-cljs:0.8.256" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.cognitect/transit-java:0.8.337" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.cognitect/transit-js:0.8.846" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.fasterxml.jackson.core/jackson-annotations:2.9.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.fasterxml.jackson.core/jackson-core:2.9.6" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.fasterxml.jackson.core/jackson-databind:2.9.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.fasterxml.jackson.dataformat/jackson-dataformat-cbor:2.9.6" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.fasterxml.jackson.dataformat/jackson-dataformat-smile:2.9.6" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.fasterxml.jackson.datatype/jackson-datatype-jsr310:2.9.7" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.google.code.findbugs/jsr305:3.0.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.google.code.gson/gson:2.7" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.google.errorprone/error_prone_annotations:2.0.18" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.google.guava/guava:25.1-jre" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.google.j2objc/j2objc-annotations:1.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.google.javascript/closure-compiler-externs:v20180805" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.google.javascript/closure-compiler-unshaded:v20180805" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.google.jsinterop/jsinterop-annotations:1.0.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.google.protobuf/protobuf-java:3.0.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.googlecode.json-simple/json-simple:1.1.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.lambdaworks/scrypt:1.4.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.layerware/hugsql-adapter-clojure-java-jdbc:0.4.9" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.layerware/hugsql-adapter:0.4.9" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.layerware/hugsql-core:0.4.9" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.layerware/hugsql:0.4.9" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.stuartsierra/component:0.3.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.stuartsierra/dependency:0.2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: com.zaxxer/HikariCP:3.2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: commons-codec:1.8" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: commons-fileupload:1.3.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: commons-io:2.6" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: commons-logging:1.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: compojure:1.6.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: conman:0.8.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: cprop:0.1.13" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: criterium:0.4.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: crypto-equality:1.0.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: crypto-random:1.2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: doo:0.1.11" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: expiring-map:0.1.8" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: expound:0.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: figwheel-sidecar:0.5.18" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: figwheel:0.5.18" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: fipp:0.6.12" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: funcool/cuerdas:2.0.5" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: funcool/promesa:1.9.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: funcool/struct:1.3.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: hawk:0.2.11" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: hiccup:1.0.5" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: hikari-cp:2.6.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: http-kit:2.3.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: instaparse:1.4.8" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: io.undertow/undertow-core:1.4.14.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: io.undertow/undertow-servlet:1.4.14.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: io.undertow/undertow-websockets-jsr:1.4.14.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: javax.servlet/javax.servlet-api:3.1.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: javax.xml.bind/jaxb-api:2.3.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: joda-time:2.9.9" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: jonase/eastwood:0.2.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: json-html:0.4.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: karma-reporter:3.1.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: luminus-immutant:0.2.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: luminus-migrations:0.6.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: luminus-transit:0.1.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: luminus/ring-ttl-session:0.3.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: markdown-clj:1.0.5" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: medley:1.0.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: meta-merge:1.0.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: metosin/jsonista:0.2.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: metosin/muuntaja:0.6.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: metosin/ring-http-response:0.9.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: metosin/vega-tools:0.2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: migratus:1.2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: mount:0.1.15" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: net.cgrand/parsley:0.9.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: net.cgrand/regex:1.1.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: net.cgrand/sjacket:0.1.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: net.incongru.watchservice/barbary-watchservice:1.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: net.java.dev.jna/jna:3.2.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: net.jodah/expiringmap:0.5.8" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: nrepl/bencode:1.0.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: nrepl:0.5.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: ns-tracker:0.3.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.apache.commons/commons-compress:1.9" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.apache.commons/commons-lang3:3.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.apache.httpcomponents/httpclient:4.5" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.apache.httpcomponents/httpcore:4.4.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.apache.httpcomponents/httpmime:4.5" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.bouncycastle/bcpkix-jdk15on:1.54" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.bouncycastle/bcprov-jdk15on:1.54" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.checkerframework/checker-qual:2.0.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojars.brenton/google-diff-match-patch:0.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/clojure:1.10.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/clojurescript:1.10.439" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/core.async:0.4.474" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/core.cache:0.6.5" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/core.memoize:0.5.9" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/core.rrb-vector:0.0.11" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/core.specs.alpha:0.2.44" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/data.json:0.2.6" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/data.priority-map:0.0.7" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/google-closure-library-third-party:0.0-20170809-b9c14c6b" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/google-closure-library:0.0-20170809-b9c14c6b" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/java.classpath:0.2.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/java.jdbc:0.7.7" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/spec.alpha:0.2.176" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/tools.analyzer.jvm:0.7.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/tools.analyzer:0.6.9" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/tools.cli:0.4.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/tools.logging:0.4.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/tools.macro:0.1.5" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/tools.namespace:0.2.11" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/tools.nrepl:0.2.12" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.clojure/tools.reader:1.3.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.codehaus.mojo/animal-sniffer-annotations:1.14" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.immutant/core:2.1.9" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.immutant/web:2.1.9" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.javassist/javassist:3.18.1-GA" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.jboss.logging/jboss-logging:3.2.1.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.jboss.spec.javax.annotation/jboss-annotations-api_1.2_spec:1.0.0.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.jboss.spec.javax.servlet/jboss-servlet-api_3.1_spec:1.0.0.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.jboss.spec.javax.websocket/jboss-websocket-api_1.1_spec:1.1.0.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.jboss.xnio/xnio-api:3.3.6.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.jboss.xnio/xnio-nio:3.3.6.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.mozilla/rhino:1.7R5" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.msgpack/msgpack:0.6.12" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.ow2.asm/asm-all:4.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.ow2.asm/asm:5.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.postgresql/postgresql:42.2.5" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.projectodd.wunderboss/wunderboss-clojure:0.13.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.projectodd.wunderboss/wunderboss-core:0.13.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.projectodd.wunderboss/wunderboss-web-undertow:0.13.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.projectodd.wunderboss/wunderboss-web:0.13.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.slf4j/slf4j-api:1.7.7" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.tobereplaced/lettercase:1.0.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.webjars.bower/tether:1.4.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.webjars/bootstrap:4.2.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.webjars/font-awesome:5.6.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.webjars/jquery:3.0.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.webjars/popper.js:1.14.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.webjars/webjars-locator-core:0.35" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: org.webjars/webjars-locator:0.34" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: pjstadig/humane-test-output:0.9.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: potemkin:0.4.5" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: prone:1.6.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: realize:1.1.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: rewrite-clj:0.4.12" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: rewrite-cljs:0.4.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: riddley:0.1.12" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: ring-cors:0.1.12" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: ring-webjars:0.2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: ring/ring-anti-forgery:1.3.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: ring/ring-codec:1.1.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: ring/ring-core:1.7.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: ring/ring-defaults:0.3.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: ring/ring-devel:1.7.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: ring/ring-headers:0.3.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: ring/ring-mock:0.3.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: ring/ring-ssl:0.3.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: selmer:1.12.5" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: simple-lein-profile-merge:0.1.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: slingshot:0.12.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: strictly-specking-standalone:0.1.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: suspendable:0.1.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: tigris:0.1.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Leiningen: virgil:0.1.6" level="project" />
|
||||||
|
</component>
|
||||||
|
</module>
|
15
dev-config.edn_example
Normal file
15
dev-config.edn_example
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
;; WARNING
|
||||||
|
;; The dev-config.edn file is used for local environment variables, such as database credentials.
|
||||||
|
;; This file is listed in .gitignore and will be excluded from version control by Git.
|
||||||
|
|
||||||
|
{:dev true
|
||||||
|
:port 3000
|
||||||
|
;; when :nrepl-port is set the application starts the nREPL server on load
|
||||||
|
:nrepl-port 7000
|
||||||
|
|
||||||
|
;;Twitter used as an example, replace these URIs with the OAuth provider of your choice
|
||||||
|
:request-token-uri "https://api.twitter.com/oauth/request_token"
|
||||||
|
:access-token-uri "https://api.twitter.com/oauth/access_token"
|
||||||
|
:authorize-uri "https://api.twitter.com/oauth/authenticate"
|
||||||
|
; set your dev database connection URL here
|
||||||
|
:database-url "postgresql://localhost:5432/a_db_name?user=a_username&password=a_password"}
|
10
env/dev/clj/cat/dev_middleware.clj
vendored
Normal file
10
env/dev/clj/cat/dev_middleware.clj
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
(ns cat.dev-middleware
|
||||||
|
(:require [ring.middleware.reload :refer [wrap-reload]]
|
||||||
|
[selmer.middleware :refer [wrap-error-page]]
|
||||||
|
[prone.middleware :refer [wrap-exceptions]]))
|
||||||
|
|
||||||
|
(defn wrap-dev [handler]
|
||||||
|
(-> handler
|
||||||
|
wrap-reload
|
||||||
|
wrap-error-page
|
||||||
|
(wrap-exceptions {:app-namespaces ['cat]})))
|
14
env/dev/clj/cat/env.clj
vendored
Normal file
14
env/dev/clj/cat/env.clj
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
(ns cat.env
|
||||||
|
(:require [selmer.parser :as parser]
|
||||||
|
[clojure.tools.logging :as log]
|
||||||
|
[cat.dev-middleware :refer [wrap-dev]]))
|
||||||
|
|
||||||
|
(def defaults
|
||||||
|
{:init
|
||||||
|
(fn []
|
||||||
|
(parser/cache-off!)
|
||||||
|
(log/info "\n-=[cat started successfully using the development profile]=-"))
|
||||||
|
:stop
|
||||||
|
(fn []
|
||||||
|
(log/info "\n-=[cat has shut down successfully]=-"))
|
||||||
|
:middleware wrap-dev})
|
12
env/dev/clj/cat/figwheel.clj
vendored
Normal file
12
env/dev/clj/cat/figwheel.clj
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
(ns cat.figwheel
|
||||||
|
(:require [figwheel-sidecar.repl-api :as ra]))
|
||||||
|
|
||||||
|
(defn start-fw []
|
||||||
|
(ra/start-figwheel!))
|
||||||
|
|
||||||
|
(defn stop-fw []
|
||||||
|
(ra/stop-figwheel!))
|
||||||
|
|
||||||
|
(defn cljs []
|
||||||
|
(ra/cljs-repl))
|
||||||
|
|
42
env/dev/clj/user.clj
vendored
Normal file
42
env/dev/clj/user.clj
vendored
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
(ns user
|
||||||
|
(:require [cat.config :refer [env]]
|
||||||
|
[clojure.spec.alpha :as s]
|
||||||
|
[expound.alpha :as expound]
|
||||||
|
[mount.core :as mount]
|
||||||
|
[cat.figwheel :refer [start-fw stop-fw cljs]]
|
||||||
|
[cat.core :refer [start-app]]
|
||||||
|
[cat.db.core]
|
||||||
|
[conman.core :as conman]
|
||||||
|
[luminus-migrations.core :as migrations]))
|
||||||
|
|
||||||
|
(alter-var-root #'s/*explain-out* (constantly expound/printer))
|
||||||
|
|
||||||
|
(defn start []
|
||||||
|
(mount/start-without #'cat.core/repl-server))
|
||||||
|
|
||||||
|
(defn stop []
|
||||||
|
(mount/stop-except #'cat.core/repl-server))
|
||||||
|
|
||||||
|
(defn restart []
|
||||||
|
(stop)
|
||||||
|
(start))
|
||||||
|
|
||||||
|
(defn restart-db []
|
||||||
|
(mount/stop #'cat.db.core/*db*)
|
||||||
|
(mount/start #'cat.db.core/*db*)
|
||||||
|
(binding [*ns* 'cat.db.core]
|
||||||
|
(conman/bind-connection cat.db.core/*db* "sql/queries.sql")))
|
||||||
|
|
||||||
|
(defn reset-db []
|
||||||
|
(migrations/migrate ["reset"] (select-keys env [:database-url])))
|
||||||
|
|
||||||
|
(defn migrate []
|
||||||
|
(migrations/migrate ["migrate"] (select-keys env [:database-url])))
|
||||||
|
|
||||||
|
(defn rollback []
|
||||||
|
(migrations/migrate ["rollback"] (select-keys env [:database-url])))
|
||||||
|
|
||||||
|
(defn create-migration [name]
|
||||||
|
(migrations/create name (select-keys env [:database-url])))
|
||||||
|
|
||||||
|
|
13
env/dev/cljs/cat/app.cljs
vendored
Normal file
13
env/dev/cljs/cat/app.cljs
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
(ns ^:figwheel-no-load cat.app
|
||||||
|
(:require [cat.core :as core]
|
||||||
|
[cljs.spec.alpha :as s]
|
||||||
|
[expound.alpha :as expound]
|
||||||
|
[devtools.core :as devtools]))
|
||||||
|
|
||||||
|
(set! s/*explain-out* expound/printer)
|
||||||
|
|
||||||
|
(enable-console-print!)
|
||||||
|
|
||||||
|
(devtools/install!)
|
||||||
|
|
||||||
|
(core/init!)
|
1
env/dev/resources/config.edn
vendored
Normal file
1
env/dev/resources/config.edn
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
36
env/dev/resources/logback.xml
vendored
Normal file
36
env/dev/resources/logback.xml
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<!-- encoders are assigned the type
|
||||||
|
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
|
||||||
|
<encoder>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
<pattern>%date{ISO8601} [%thread] %-5level %logger{36} - %msg %n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>log/cat.log</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>log/cat.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||||
|
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||||
|
<maxFileSize>100MB</maxFileSize>
|
||||||
|
</timeBasedFileNamingAndTriggeringPolicy>
|
||||||
|
<!-- keep 30 days of history -->
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
<pattern>%date{ISO8601} [%thread] %-5level %logger{36} - %msg %n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
<logger name="org.apache.http" level="warn" />
|
||||||
|
<logger name="org.xnio.nio" level="warn" />
|
||||||
|
<logger name="com.zaxxer.hikari" level="warn" />
|
||||||
|
<logger name="io.undertow.session" level="warn" />
|
||||||
|
<logger name="io.undertow.request" level="warn" />
|
||||||
|
<root level="DEBUG">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
<appender-ref ref="FILE" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
11
env/prod/clj/cat/env.clj
vendored
Normal file
11
env/prod/clj/cat/env.clj
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
(ns cat.env
|
||||||
|
(:require [clojure.tools.logging :as log]))
|
||||||
|
|
||||||
|
(def defaults
|
||||||
|
{:init
|
||||||
|
(fn []
|
||||||
|
(log/info "\n-=[cat started successfully]=-"))
|
||||||
|
:stop
|
||||||
|
(fn []
|
||||||
|
(log/info "\n-=[cat has shut down successfully]=-"))
|
||||||
|
:middleware identity})
|
7
env/prod/cljs/cat/app.cljs
vendored
Normal file
7
env/prod/cljs/cat/app.cljs
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
(ns cat.app
|
||||||
|
(:require [cat.core :as core]))
|
||||||
|
|
||||||
|
;;ignore println statements in prod
|
||||||
|
(set! *print-fn* (fn [& _]))
|
||||||
|
|
||||||
|
(core/init!)
|
2
env/prod/resources/config.edn
vendored
Normal file
2
env/prod/resources/config.edn
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
{:prod true
|
||||||
|
:port 3000}
|
25
env/prod/resources/logback.xml
vendored
Normal file
25
env/prod/resources/logback.xml
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
|
||||||
|
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>log/cat.log</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>log/cat.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||||
|
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||||
|
<maxFileSize>100MB</maxFileSize>
|
||||||
|
</timeBasedFileNamingAndTriggeringPolicy>
|
||||||
|
<!-- keep 30 days of history -->
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
<pattern>%date{ISO8601} [%thread] %-5level %logger{36} - %msg %n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
<logger name="org.apache.http" level="warn" />
|
||||||
|
<logger name="org.xnio.nio" level="warn" />
|
||||||
|
<logger name="com.zaxxer.hikari" level="warn" />
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="FILE" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
1
env/test/resources/config.edn
vendored
Normal file
1
env/test/resources/config.edn
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
36
env/test/resources/logback.xml
vendored
Normal file
36
env/test/resources/logback.xml
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<!-- encoders are assigned the type
|
||||||
|
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
|
||||||
|
<encoder>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
<pattern>%date{ISO8601} [%thread] %-5level %logger{36} - %msg %n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>log/cat.log</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>log/cat.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||||
|
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||||
|
<maxFileSize>100MB</maxFileSize>
|
||||||
|
</timeBasedFileNamingAndTriggeringPolicy>
|
||||||
|
<!-- keep 30 days of history -->
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
<pattern>%date{ISO8601} [%thread] %-5level %logger{36} - %msg %n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
<logger name="org.apache.http" level="warn" />
|
||||||
|
<logger name="org.xnio.nio" level="warn" />
|
||||||
|
<logger name="com.zaxxer.hikari" level="warn" />
|
||||||
|
<logger name="io.undertow.session" level="warn" />
|
||||||
|
<logger name="io.undertow.request" level="warn" />
|
||||||
|
<root level="DEBUG">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
<appender-ref ref="FILE" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
142
project.clj
Normal file
142
project.clj
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
(defproject cat "0.1.0-SNAPSHOT"
|
||||||
|
|
||||||
|
:description "A cuddle graph for zeus people"
|
||||||
|
;:url "http://example.com/FIXME"
|
||||||
|
|
||||||
|
:dependencies [[buddy "2.0.0"]
|
||||||
|
[cheshire "5.8.1"]
|
||||||
|
[clj-oauth "1.5.5"]
|
||||||
|
[clojure.java-time "0.3.2"]
|
||||||
|
[com.cognitect/transit-clj "0.8.313"]
|
||||||
|
[compojure "1.6.1"]
|
||||||
|
[conman "0.8.3"]
|
||||||
|
[cprop "0.1.13"]
|
||||||
|
[funcool/struct "1.3.0"]
|
||||||
|
[luminus-immutant "0.2.4"]
|
||||||
|
[luminus-migrations "0.6.3"]
|
||||||
|
[luminus-transit "0.1.1"]
|
||||||
|
[luminus/ring-ttl-session "0.3.2"]
|
||||||
|
[markdown-clj "1.0.5"]
|
||||||
|
[metosin/muuntaja "0.6.3"]
|
||||||
|
[metosin/ring-http-response "0.9.1"]
|
||||||
|
[mount "0.1.15"]
|
||||||
|
[nrepl "0.5.3"]
|
||||||
|
[org.clojure/clojure "1.10.0"]
|
||||||
|
[org.clojure/clojurescript "1.10.439" :scope "provided"]
|
||||||
|
[org.clojure/tools.cli "0.4.1"]
|
||||||
|
[org.clojure/tools.logging "0.4.1"]
|
||||||
|
[org.postgresql/postgresql "42.2.5"]
|
||||||
|
[org.webjars.bower/tether "1.4.4"]
|
||||||
|
[org.webjars/bootstrap "4.2.1"]
|
||||||
|
[org.webjars/font-awesome "5.6.1"]
|
||||||
|
[org.webjars/webjars-locator "0.34"]
|
||||||
|
[ring-webjars "0.2.0"]
|
||||||
|
[ring/ring-core "1.7.1"]
|
||||||
|
[ring/ring-defaults "0.3.2"]
|
||||||
|
[selmer "1.12.5"]
|
||||||
|
[metosin/vega-tools "0.2.0"]
|
||||||
|
[funcool/promesa "1.9.0"]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
:min-lein-version "2.0.0"
|
||||||
|
|
||||||
|
:source-paths ["src/clj" "src/cljs" "src/cljc"]
|
||||||
|
:test-paths ["test/clj"]
|
||||||
|
:resource-paths ["resources" "target/cljsbuild"]
|
||||||
|
:target-path "target/%s/"
|
||||||
|
:main ^:skip-aot cat.core
|
||||||
|
|
||||||
|
:plugins [[lein-cljsbuild "1.1.7"]
|
||||||
|
[lein-immutant "2.1.0"]
|
||||||
|
[lein-kibit "0.1.2"]]
|
||||||
|
:clean-targets ^{:protect false}
|
||||||
|
[:target-path [:cljsbuild :builds :app :compiler :output-dir] [:cljsbuild :builds :app :compiler :output-to]]
|
||||||
|
:figwheel
|
||||||
|
{:http-server-root "public"
|
||||||
|
:server-logfile "log/figwheel-logfile.log"
|
||||||
|
:nrepl-port 7002
|
||||||
|
:css-dirs ["resources/public/css"]
|
||||||
|
:nrepl-middleware
|
||||||
|
[cider/wrap-cljs-repl cider.piggieback/wrap-cljs-repl]}
|
||||||
|
|
||||||
|
|
||||||
|
:profiles
|
||||||
|
{:uberjar {:omit-source true
|
||||||
|
:prep-tasks ["compile" ["cljsbuild" "once" "min"]]
|
||||||
|
:cljsbuild
|
||||||
|
{:builds
|
||||||
|
{:min
|
||||||
|
{:source-paths ["src/cljc" "src/cljs" "env/prod/cljs"]
|
||||||
|
:compiler
|
||||||
|
{:output-dir "target/cljsbuild/public/js"
|
||||||
|
:output-to "target/cljsbuild/public/js/app.js"
|
||||||
|
:source-map "target/cljsbuild/public/js/app.js.map"
|
||||||
|
:optimizations :advanced
|
||||||
|
:pretty-print false
|
||||||
|
:infer-externs true
|
||||||
|
:closure-warnings
|
||||||
|
{:externs-validation :off :non-standard-jsdoc :off}}}}}
|
||||||
|
|
||||||
|
|
||||||
|
:aot :all
|
||||||
|
:uberjar-name "cat.jar"
|
||||||
|
:source-paths ["env/prod/clj"]
|
||||||
|
:resource-paths ["env/prod/resources"]}
|
||||||
|
|
||||||
|
:dev [:project/dev :profiles/dev]
|
||||||
|
:test [:project/dev :project/test :profiles/test]
|
||||||
|
|
||||||
|
:project/dev {:jvm-opts ["-Dconf=dev-config.edn"]
|
||||||
|
:dependencies [[binaryage/devtools "0.9.10"]
|
||||||
|
[cider/piggieback "0.3.10"]
|
||||||
|
[doo "0.1.11"]
|
||||||
|
[expound "0.7.2"]
|
||||||
|
[figwheel-sidecar "0.5.18"]
|
||||||
|
[pjstadig/humane-test-output "0.9.0"]
|
||||||
|
[prone "1.6.1"]
|
||||||
|
[ring/ring-devel "1.7.1"]
|
||||||
|
[ring/ring-mock "0.3.2"]]
|
||||||
|
:plugins [[com.jakemccrary/lein-test-refresh "0.23.0"]
|
||||||
|
[lein-doo "0.1.11"]
|
||||||
|
[lein-figwheel "0.5.18"]]
|
||||||
|
:cljsbuild
|
||||||
|
{:builds
|
||||||
|
{:app
|
||||||
|
{:source-paths ["src/cljs" "src/cljc" "env/dev/cljs"]
|
||||||
|
:figwheel {:on-jsload "cat.core/mount-components"}
|
||||||
|
:compiler
|
||||||
|
{:main "cat.app"
|
||||||
|
:asset-path "/js/out"
|
||||||
|
:output-to "target/cljsbuild/public/js/app.js"
|
||||||
|
:output-dir "target/cljsbuild/public/js/out"
|
||||||
|
:source-map true
|
||||||
|
:optimizations :none
|
||||||
|
:pretty-print true}}}}
|
||||||
|
:doo {:build "test"}
|
||||||
|
:source-paths ["env/dev/clj"]
|
||||||
|
:resource-paths ["env/dev/resources"]
|
||||||
|
:repl-options {:init-ns user}
|
||||||
|
:injections [(require 'pjstadig.humane-test-output)
|
||||||
|
(pjstadig.humane-test-output/activate!)]}
|
||||||
|
:project/test {:jvm-opts ["-Dconf=test-config.edn"]
|
||||||
|
:resource-paths ["env/test/resources"]
|
||||||
|
:cljsbuild
|
||||||
|
{:builds
|
||||||
|
{:test
|
||||||
|
{:source-paths ["src/cljc" "src/cljs" "test/cljs"]
|
||||||
|
:compiler
|
||||||
|
{:output-to "target/test.js"
|
||||||
|
:main "cat.doo-runner"
|
||||||
|
:optimizations :whitespace
|
||||||
|
:pretty-print true}}}}}
|
||||||
|
|
||||||
|
|
||||||
|
:profiles/dev {}
|
||||||
|
:profiles/test {}}
|
||||||
|
:repl-options {
|
||||||
|
;; If nREPL takes too long to load it may timeout,
|
||||||
|
;; increase this to wait longer before timing out.
|
||||||
|
;; Defaults to 30000 (30 seconds)
|
||||||
|
:timeout 120000})
|
||||||
|
|
97
resources/docs/docs.md
Normal file
97
resources/docs/docs.md
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
<h2 class="alert alert-success">Congratulations, your <a class="alert-link" href="http://luminusweb.net">Luminus</a> site is ready!</h2>
|
||||||
|
|
||||||
|
This page will help guide you through the first steps of building your site.
|
||||||
|
|
||||||
|
#### Why are you seeing this page?
|
||||||
|
|
||||||
|
The `home-routes` handler in the `cat.routes.home` namespace
|
||||||
|
defines the route that invokes the `home-page` function whenever an HTTP
|
||||||
|
request is made to the `/` URI using the `GET` method.
|
||||||
|
|
||||||
|
```
|
||||||
|
(defroutes home-routes
|
||||||
|
(GET "/" []
|
||||||
|
(home-page))
|
||||||
|
(GET "/docs" []
|
||||||
|
(-> (response/ok (-> "docs/docs.md" io/resource slurp))
|
||||||
|
(response/header "Content-Type" "text/plain; charset=utf-8"))))
|
||||||
|
```
|
||||||
|
|
||||||
|
The `home-page` function will in turn call the `cat.layout/render` function
|
||||||
|
to render the HTML content:
|
||||||
|
|
||||||
|
```
|
||||||
|
(defn home-page []
|
||||||
|
(layout/render "home.html"))
|
||||||
|
```
|
||||||
|
|
||||||
|
The page contains a link to the compiled ClojureScript found in the `target/cljsbuild/public` folder:
|
||||||
|
|
||||||
|
```
|
||||||
|
{% script "/js/app.js" %}
|
||||||
|
```
|
||||||
|
|
||||||
|
The rest of this page is rendered by ClojureScript found in the `src/cljs/cat/core.cljs` file.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### Organizing the routes
|
||||||
|
|
||||||
|
The routes are aggregated and wrapped with middleware in the `cat.handler` namespace:
|
||||||
|
|
||||||
|
```
|
||||||
|
(defstate app
|
||||||
|
:start
|
||||||
|
(middleware/wrap-base
|
||||||
|
(routes
|
||||||
|
(-> #'home-routes
|
||||||
|
(wrap-routes middleware/wrap-csrf)
|
||||||
|
(wrap-routes middleware/wrap-formats))
|
||||||
|
(route/not-found
|
||||||
|
(:body
|
||||||
|
(error-page {:status 404
|
||||||
|
:title "page not found"}))))))
|
||||||
|
```
|
||||||
|
|
||||||
|
The `app` definition groups all the routes in the application into a single handler.
|
||||||
|
A default route group is added to handle the `404` case.
|
||||||
|
|
||||||
|
<a class="btn btn-primary" href="http://www.luminusweb.net/docs/routes.md">learn more about routing »</a>
|
||||||
|
|
||||||
|
The `home-routes` are wrapped with two middleware functions. The first enables CSRF protection.
|
||||||
|
The second takes care of serializing and deserializing various encoding formats, such as JSON.
|
||||||
|
|
||||||
|
#### Managing your middleware
|
||||||
|
|
||||||
|
Request middleware functions are located under the `cat.middleware` namespace.
|
||||||
|
|
||||||
|
This namespace is reserved for any custom middleware for the application. Some default middleware is
|
||||||
|
already defined here. The middleware is assembled in the `wrap-base` function.
|
||||||
|
|
||||||
|
Middleware used for development is placed in the `cat.dev-middleware` namespace found in
|
||||||
|
the `env/dev/clj/` source path.
|
||||||
|
|
||||||
|
<a class="btn btn-primary" href="http://www.luminusweb.net/docs/middleware.md">learn more about middleware »</a>
|
||||||
|
|
||||||
|
<div class="bs-callout bs-callout-danger">
|
||||||
|
|
||||||
|
#### Database configuration is required
|
||||||
|
|
||||||
|
If you haven't already, then please follow the steps below to configure your database connection and run the necessary migrations.
|
||||||
|
|
||||||
|
* Create the database for your application.
|
||||||
|
* Update the connection URL in the `dev-config.edn` and `test-config.edn` files with your database name and login credentials.
|
||||||
|
* Run `lein run migrate` in the root of the project to create the tables.
|
||||||
|
* Let `mount` know to start the database connection by `require`-ing `cat.db.core` in some other namespace.
|
||||||
|
* Restart the application.
|
||||||
|
|
||||||
|
<a class="btn btn-primary" href="http://www.luminusweb.net/docs/database.md">learn more about database access »</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### Need some help?
|
||||||
|
|
||||||
|
Visit the [official documentation](http://www.luminusweb.net/docs) for examples
|
||||||
|
on how to accomplish common tasks with Luminus. The `#luminus` channel on the [Clojurians Slack](http://clojurians.net/) and [Google Group](https://groups.google.com/forum/#!forum/luminusweb) are both great places to seek help and discuss projects with other users.
|
55
resources/html/error.html
Normal file
55
resources/html/error.html
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Something bad happened</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
{% style "/assets/bootstrap/css/bootstrap.min.css" %}
|
||||||
|
<style type="text/css">
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
min-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
html body {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
html .container-fluid {
|
||||||
|
display: table;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
html .row-fluid {
|
||||||
|
display: table-cell;
|
||||||
|
height: 100%;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="centering text-center">
|
||||||
|
<div class="text-center">
|
||||||
|
<h1><span class="text-danger">Error: {{status}}</span></h1>
|
||||||
|
<hr>
|
||||||
|
{% if title %}
|
||||||
|
<h2 class="without-margin">{{title}}</h2>
|
||||||
|
{% endif %}
|
||||||
|
{% if message %}
|
||||||
|
<h4 class="text-danger">{{message}}</h4>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
123
resources/html/home.html
Normal file
123
resources/html/home.html
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Welcome to cat</title>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/vega@4.4.0"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="navbar"></div>
|
||||||
|
<div id="raw">
|
||||||
|
<div id="view"></div>
|
||||||
|
<div id="chart"></div>
|
||||||
|
<div class="grid-container">
|
||||||
|
<div class="grid-item">
|
||||||
|
<h3>Add person</h3>
|
||||||
|
<form action="/users" method="post">
|
||||||
|
{% csrf-field %}
|
||||||
|
<label for="name">Name</label><br>
|
||||||
|
<input type="text" name="name" id="name"><br>
|
||||||
|
<label for="gender">Gender</label><br>
|
||||||
|
<input type="text" name="gender" id="gender">
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="grid-item">
|
||||||
|
<h3>Add relation (please enter correct id's of the person)</h3>
|
||||||
|
<form action="/relations" method="post">
|
||||||
|
{% csrf-field %}
|
||||||
|
<div class="input-container">
|
||||||
|
<div class="input-item">
|
||||||
|
<label for="from">Person from</label><br>
|
||||||
|
<select name="from_id" id="from">
|
||||||
|
{% for user in users %}
|
||||||
|
<option value="{{user.id}}">{{user.name}}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="input-item">
|
||||||
|
<label for="to">Person to</label><br>
|
||||||
|
<select name="to_id" id="to">
|
||||||
|
{% for user in users %}
|
||||||
|
<option value="{{user.id}}">{{user.name}}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="grid-item">
|
||||||
|
<h3>Users</h3>
|
||||||
|
<div class="item-container">
|
||||||
|
<div class="item"><b>Name</b></div>
|
||||||
|
<div class="item"><b>Gender</b></div>
|
||||||
|
{% for user in users %}
|
||||||
|
<div class="item">
|
||||||
|
{{user.name}}
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
{{user.gender}}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid-item">
|
||||||
|
<h3>Relations</h3>
|
||||||
|
<div class="item-container">
|
||||||
|
<div class="item"><b>Person 1</b></div>
|
||||||
|
<div class="item"><b>Person 2</b></div>
|
||||||
|
{% for relation in relations %}
|
||||||
|
<div class="item">
|
||||||
|
{{relation.name}}
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
{{relation.name_2}}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="app">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="card-deck">
|
||||||
|
<div class="card-block">
|
||||||
|
<h4>Welcome to cat</h4>
|
||||||
|
<p>If you're seeing this message, that means you haven't yet compiled your ClojureScript!</p>
|
||||||
|
<p>Please run <code>lein figwheel</code> to start the ClojureScript compiler and reload the page.</p>
|
||||||
|
<h4>For better ClojureScript development experience in Chrome follow these steps:</h4>
|
||||||
|
<ul>
|
||||||
|
<li>Open DevTools
|
||||||
|
<li>Go to Settings ("three dots" icon in the upper right corner of DevTools > Menu > Settings F1 >
|
||||||
|
General > Console)
|
||||||
|
<li>Check-in "Enable custom formatters"
|
||||||
|
<li>Close DevTools
|
||||||
|
<li>Open DevTools
|
||||||
|
</ul>
|
||||||
|
<p>See <a href="http://www.luminusweb.net/docs/clojurescript.md">ClojureScript</a> documentation for
|
||||||
|
further details.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- scripts and styles -->
|
||||||
|
{% style "/assets/bootstrap/css/bootstrap.min.css" %}
|
||||||
|
{% style "/assets/font-awesome/css/all.css" %}
|
||||||
|
{% style "/css/screen.css" %}
|
||||||
|
|
||||||
|
{% script "/assets/jquery/jquery.min.js" %}
|
||||||
|
{% script "/assets/font-awesome/js/all.js" %}
|
||||||
|
{% script "/assets/tether/dist/js/tether.min.js" %}
|
||||||
|
{% script "/assets/bootstrap/js/bootstrap.min.js" %}
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
var csrfToken = "{{csrf-token}}";
|
||||||
|
</script>
|
||||||
|
{% script "/js/app.js" %}
|
||||||
|
|
||||||
|
{% script "/js/graphing.js" %}
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1 @@
|
||||||
|
DROP TABLE users;
|
|
@ -0,0 +1,9 @@
|
||||||
|
CREATE TABLE users
|
||||||
|
(id VARCHAR(20) PRIMARY KEY,
|
||||||
|
first_name VARCHAR(30),
|
||||||
|
last_name VARCHAR(30),
|
||||||
|
email VARCHAR(30),
|
||||||
|
admin BOOLEAN,
|
||||||
|
last_login TIMESTAMP,
|
||||||
|
is_active BOOLEAN,
|
||||||
|
pass VARCHAR(300));
|
|
@ -0,0 +1 @@
|
||||||
|
DROP TABLE users;
|
|
@ -0,0 +1,4 @@
|
||||||
|
CREATE TABLE users
|
||||||
|
(id SERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
gender VARCHAR(255));
|
|
@ -0,0 +1 @@
|
||||||
|
DROP TABLE relations;
|
|
@ -0,0 +1,6 @@
|
||||||
|
CREATE TABLE relations
|
||||||
|
(id SERIAL PRIMARY KEY,
|
||||||
|
from_id INTEGER NOT NULL,
|
||||||
|
to_id INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (from_id) REFERENCES users (id),
|
||||||
|
FOREIGN KEY (to_id) REFERENCES users (id));
|
46
resources/public/css/screen.css
Normal file
46
resources/public/css/screen.css
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
nav {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-item{
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-container{
|
||||||
|
/*https://medium.com/@js_tut/new-things-css-grid-brings-to-the-table-e465cb5d2841*/
|
||||||
|
display: grid;
|
||||||
|
/*grid-template-rows: 100px 100px;*/
|
||||||
|
grid-template-columns: 100px 100px;
|
||||||
|
grid-gap: 10px;
|
||||||
|
justify-items: unset;
|
||||||
|
padding: 0 0 20px 10px;
|
||||||
|
}
|
||||||
|
.item {
|
||||||
|
justify-content: start;
|
||||||
|
border: 1px solid #b1b1b1;
|
||||||
|
align-items: start;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container{
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
.input-item {
|
||||||
|
|
||||||
|
}
|
BIN
resources/public/favicon.ico
Normal file
BIN
resources/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
resources/public/img/warning_clojure.png
Normal file
BIN
resources/public/img/warning_clojure.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
13
resources/public/js/graphing.js
Normal file
13
resources/public/js/graphing.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
var view;
|
||||||
|
|
||||||
|
vega.loader()
|
||||||
|
.load('/js/spec.json')
|
||||||
|
.then(function(data) { render(JSON.parse(data)); });
|
||||||
|
|
||||||
|
function render(spec) {
|
||||||
|
view = new vega.View(vega.parse(spec))
|
||||||
|
.renderer('canvas') // set renderer (canvas or svg)
|
||||||
|
.initialize('#view') // initialize view within parent DOM container
|
||||||
|
.hover() // enable hover encode set processing
|
||||||
|
.run();
|
||||||
|
}
|
325
resources/public/js/spec.json
Normal file
325
resources/public/js/spec.json
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://vega.github.io/schema/vega/v4.json",
|
||||||
|
"width": 400,
|
||||||
|
"height": 300,
|
||||||
|
"padding": {
|
||||||
|
"top": 25,
|
||||||
|
"left": 0,
|
||||||
|
"right": 0,
|
||||||
|
"bottom": 0
|
||||||
|
},
|
||||||
|
"autosize": "none",
|
||||||
|
"signals": [
|
||||||
|
{
|
||||||
|
"name": "hover",
|
||||||
|
"value": null,
|
||||||
|
"on": [
|
||||||
|
{
|
||||||
|
"events": "symbol:mouseover",
|
||||||
|
"update": "datum"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"events": "symbol:mouseout",
|
||||||
|
"update": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "title",
|
||||||
|
"value": "",
|
||||||
|
"update": "hover ? hover.name : '' "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cx",
|
||||||
|
"update": "width / 2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cy",
|
||||||
|
"update": "height / 2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nodeRadius",
|
||||||
|
"value": 8,
|
||||||
|
"bind": {
|
||||||
|
"input": "range",
|
||||||
|
"min": 1,
|
||||||
|
"max": 50,
|
||||||
|
"step": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nodeCharge",
|
||||||
|
"value": -30,
|
||||||
|
"bind": {
|
||||||
|
"input": "range",
|
||||||
|
"min": -100,
|
||||||
|
"max": 10,
|
||||||
|
"step": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linkDistance",
|
||||||
|
"value": 70,
|
||||||
|
"bind": {
|
||||||
|
"input": "range",
|
||||||
|
"min": 5,
|
||||||
|
"max": 100,
|
||||||
|
"step": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "static",
|
||||||
|
"value": true,
|
||||||
|
"bind": {
|
||||||
|
"input": "checkbox"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "State variable for active node fix status.",
|
||||||
|
"name": "fix",
|
||||||
|
"value": false,
|
||||||
|
"on": [
|
||||||
|
{
|
||||||
|
"events": "symbol:mouseout[!event.buttons], window:mouseup",
|
||||||
|
"update": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"events": "symbol:mouseover",
|
||||||
|
"update": "fix || true"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"events": "[symbol:mousedown, window:mouseup] > window:mousemove!",
|
||||||
|
"update": "xy()",
|
||||||
|
"force": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Graph node most recently interacted with.",
|
||||||
|
"name": "node",
|
||||||
|
"value": null,
|
||||||
|
"on": [
|
||||||
|
{
|
||||||
|
"events": "symbol:mouseover",
|
||||||
|
"update": "fix === true ? item() : node"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Flag to restart Force simulation upon data changes.",
|
||||||
|
"name": "restart",
|
||||||
|
"value": false,
|
||||||
|
"on": [
|
||||||
|
{
|
||||||
|
"events": {
|
||||||
|
"signal": "fix"
|
||||||
|
},
|
||||||
|
"update": "fix && fix.length"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"name": "node-data",
|
||||||
|
"url": "/relations_zeroed",
|
||||||
|
"format": {
|
||||||
|
"type": "json",
|
||||||
|
"property": "nodes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "link-data",
|
||||||
|
"url": "/relations_zeroed",
|
||||||
|
"format": {
|
||||||
|
"type": "json",
|
||||||
|
"property": "links"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scales": [
|
||||||
|
{
|
||||||
|
"name": "color",
|
||||||
|
"type": "ordinal",
|
||||||
|
"domain": {
|
||||||
|
"data": "node-data",
|
||||||
|
"field": "group"
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"scheme": "category20c"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"name": "nodes-group",
|
||||||
|
"type": "group",
|
||||||
|
"zindex": 1,
|
||||||
|
"from": {
|
||||||
|
"data": "node-data"
|
||||||
|
},
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"name": "nodes",
|
||||||
|
"type": "symbol",
|
||||||
|
"encode": {
|
||||||
|
"enter": {
|
||||||
|
"fill": {
|
||||||
|
"scale": "color",
|
||||||
|
"field": {"parent": "group"}
|
||||||
|
},
|
||||||
|
"stroke": {
|
||||||
|
"value": "white"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"update": {
|
||||||
|
"size": {
|
||||||
|
"signal": "2 * nodeRadius * nodeRadius"
|
||||||
|
},
|
||||||
|
"cursor": {
|
||||||
|
"value": "pointer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"interactive": false,
|
||||||
|
"encode": {
|
||||||
|
"enter": {
|
||||||
|
"fill": {
|
||||||
|
"value": "black"
|
||||||
|
},
|
||||||
|
"fontSize": {
|
||||||
|
"value": 12
|
||||||
|
},
|
||||||
|
"align": {
|
||||||
|
"value": "center"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"field": {"parent": "name"}
|
||||||
|
},
|
||||||
|
"y": {
|
||||||
|
"value": -10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"on": [
|
||||||
|
{
|
||||||
|
"trigger": "fix",
|
||||||
|
"modify": "node",
|
||||||
|
"values": "fix === true ? {fx: node.x, fy: node.y} : {fx: fix[0], fy: fix[1]}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"trigger": "!fix",
|
||||||
|
"modify": "node",
|
||||||
|
"values": "{fx: null, fy: null}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transform": [
|
||||||
|
{
|
||||||
|
"type": "force",
|
||||||
|
"iterations": 300,
|
||||||
|
"restart": {
|
||||||
|
"signal": "restart"
|
||||||
|
},
|
||||||
|
"static": {
|
||||||
|
"signal": "static"
|
||||||
|
},
|
||||||
|
"signal": "force",
|
||||||
|
"forces": [
|
||||||
|
{
|
||||||
|
"force": "center",
|
||||||
|
"x": {
|
||||||
|
"signal": "cx"
|
||||||
|
},
|
||||||
|
"y": {
|
||||||
|
"signal": "cy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"force": "collide",
|
||||||
|
"radius": {
|
||||||
|
"signal": "nodeRadius"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"force": "nbody",
|
||||||
|
"strength": {
|
||||||
|
"signal": "nodeCharge"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"force": "link",
|
||||||
|
"links": "link-data",
|
||||||
|
"distance": {
|
||||||
|
"signal": "linkDistance"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "path",
|
||||||
|
"from": {
|
||||||
|
"data": "link-data"
|
||||||
|
},
|
||||||
|
"interactive": false,
|
||||||
|
"encode": {
|
||||||
|
"update": {
|
||||||
|
"stroke": {
|
||||||
|
"value": "#ccc"
|
||||||
|
},
|
||||||
|
"strokeWidth": {
|
||||||
|
"value": 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transform": [
|
||||||
|
{
|
||||||
|
"type": "linkpath",
|
||||||
|
"require": {
|
||||||
|
"signal": "force"
|
||||||
|
},
|
||||||
|
"shape": "line",
|
||||||
|
"sourceX": "datum.source.x",
|
||||||
|
"sourceY": "datum.source.y",
|
||||||
|
"targetX": "datum.target.x",
|
||||||
|
"targetY": "datum.target.y"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"interactive": false,
|
||||||
|
"encode": {
|
||||||
|
"enter": {
|
||||||
|
"x": {
|
||||||
|
"signal": "width",
|
||||||
|
"offset": -5
|
||||||
|
},
|
||||||
|
"y": {
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
"fill": {
|
||||||
|
"value": "black"
|
||||||
|
},
|
||||||
|
"fontSize": {
|
||||||
|
"value": 20
|
||||||
|
},
|
||||||
|
"align": {
|
||||||
|
"value": "right"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"update": {
|
||||||
|
"text": {
|
||||||
|
"signal": "title"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
1661
resources/public/js/vega_tuto_data.json
Normal file
1661
resources/public/js/vega_tuto_data.json
Normal file
File diff suppressed because it is too large
Load diff
34
resources/sql/queries.sql
Normal file
34
resources/sql/queries.sql
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
-- :name create-user! :! :n
|
||||||
|
-- :doc creates a new user record
|
||||||
|
INSERT INTO users
|
||||||
|
(name, gender)
|
||||||
|
VALUES (:name, :gender)
|
||||||
|
|
||||||
|
-- :name update-user! :! :n
|
||||||
|
-- :doc updates an existing user record
|
||||||
|
--UPDATE users
|
||||||
|
--SET first_name = :first_name, last_name = :last_name, email = :email
|
||||||
|
--WHERE id = :id
|
||||||
|
|
||||||
|
-- :name get-users :? :*
|
||||||
|
-- :doc retrieves a user record given the id
|
||||||
|
SELECT * FROM users
|
||||||
|
--WHERE id = :id
|
||||||
|
|
||||||
|
-- :name delete-user! :! :n
|
||||||
|
-- :doc deletes a user record given the id
|
||||||
|
--DELETE FROM users
|
||||||
|
--WHERE id = :id
|
||||||
|
|
||||||
|
|
||||||
|
-- :name create-relation! :! :n
|
||||||
|
-- :doc creates a new relation record
|
||||||
|
INSERT INTO relations
|
||||||
|
(from_id, to_id)
|
||||||
|
VALUES (:from_id, :to_id)
|
||||||
|
|
||||||
|
-- :name get-relations :? :*
|
||||||
|
-- :doc retrieves all relations
|
||||||
|
SELECT * FROM relations
|
||||||
|
JOIN users u_from on relations.from_id = u_from.id
|
||||||
|
JOIN users u_to on relations.to_id = u_to.id
|
12
src/clj/cat/config.clj
Normal file
12
src/clj/cat/config.clj
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
(ns cat.config
|
||||||
|
(:require [cprop.core :refer [load-config]]
|
||||||
|
[cprop.source :as source]
|
||||||
|
[mount.core :refer [args defstate]]))
|
||||||
|
|
||||||
|
(defstate env
|
||||||
|
:start
|
||||||
|
(load-config
|
||||||
|
:merge
|
||||||
|
[(args)
|
||||||
|
(source/from-system-props)
|
||||||
|
(source/from-env)]))
|
66
src/clj/cat/core.clj
Normal file
66
src/clj/cat/core.clj
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
(ns cat.core
|
||||||
|
(:require [cat.handler :as handler]
|
||||||
|
[cat.nrepl :as nrepl]
|
||||||
|
[luminus.http-server :as http]
|
||||||
|
[luminus-migrations.core :as migrations]
|
||||||
|
[cat.config :refer [env]]
|
||||||
|
[clojure.tools.cli :refer [parse-opts]]
|
||||||
|
[clojure.tools.logging :as log]
|
||||||
|
[mount.core :as mount])
|
||||||
|
(:gen-class))
|
||||||
|
|
||||||
|
(def cli-options
|
||||||
|
[["-p" "--port PORT" "Port number"
|
||||||
|
:parse-fn #(Integer/parseInt %)]])
|
||||||
|
|
||||||
|
(mount/defstate ^{:on-reload :noop} http-server
|
||||||
|
:start
|
||||||
|
(http/start
|
||||||
|
(-> env
|
||||||
|
(assoc :handler #'handler/app)
|
||||||
|
(update :io-threads #(or % (* 2 (.availableProcessors (Runtime/getRuntime)))))
|
||||||
|
(update :port #(or (-> env :options :port) %))))
|
||||||
|
:stop
|
||||||
|
(http/stop http-server))
|
||||||
|
|
||||||
|
(mount/defstate ^{:on-reload :noop} repl-server
|
||||||
|
:start
|
||||||
|
(when (env :nrepl-port)
|
||||||
|
(nrepl/start {:bind (env :nrepl-bind)
|
||||||
|
:port (env :nrepl-port)}))
|
||||||
|
:stop
|
||||||
|
(when repl-server
|
||||||
|
(nrepl/stop repl-server)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn stop-app []
|
||||||
|
(doseq [component (:stopped (mount/stop))]
|
||||||
|
(log/info component "stopped"))
|
||||||
|
(shutdown-agents))
|
||||||
|
|
||||||
|
(defn start-app [args]
|
||||||
|
(doseq [component (-> args
|
||||||
|
(parse-opts cli-options)
|
||||||
|
mount/start-with-args
|
||||||
|
:started)]
|
||||||
|
(log/info component "started"))
|
||||||
|
(.addShutdownHook (Runtime/getRuntime) (Thread. stop-app)))
|
||||||
|
|
||||||
|
(defn -main [& args]
|
||||||
|
(mount/start #'cat.config/env)
|
||||||
|
(cond
|
||||||
|
(nil? (:database-url env))
|
||||||
|
(do
|
||||||
|
(log/error "Database configuration not found, :database-url environment variable must be set before running")
|
||||||
|
(System/exit 1))
|
||||||
|
(some #{"init"} args)
|
||||||
|
(do
|
||||||
|
(migrations/init (select-keys env [:database-url :init-script]))
|
||||||
|
(System/exit 0))
|
||||||
|
(migrations/migration? args)
|
||||||
|
(do
|
||||||
|
(migrations/migrate args (select-keys env [:database-url]))
|
||||||
|
(System/exit 0))
|
||||||
|
:else
|
||||||
|
(start-app args)))
|
||||||
|
|
85
src/clj/cat/db/core.clj
Normal file
85
src/clj/cat/db/core.clj
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
(ns cat.db.core
|
||||||
|
(:require
|
||||||
|
[cheshire.core :refer [generate-string parse-string]]
|
||||||
|
[clojure.java.jdbc :as jdbc]
|
||||||
|
[clojure.tools.logging :as log]
|
||||||
|
[conman.core :as conman]
|
||||||
|
[java-time :as jt]
|
||||||
|
[cat.config :refer [env]]
|
||||||
|
[mount.core :refer [defstate]])
|
||||||
|
(:import org.postgresql.util.PGobject
|
||||||
|
java.sql.Array
|
||||||
|
clojure.lang.IPersistentMap
|
||||||
|
clojure.lang.IPersistentVector
|
||||||
|
[java.sql
|
||||||
|
BatchUpdateException
|
||||||
|
PreparedStatement]))
|
||||||
|
(defstate ^:dynamic *db*
|
||||||
|
:start (if-let [jdbc-url (env :database-url)]
|
||||||
|
(conman/connect! {:jdbc-url jdbc-url})
|
||||||
|
(do
|
||||||
|
(log/warn "database connection URL was not found, please set :database-url in your config, e.g: dev-config.edn")
|
||||||
|
*db*))
|
||||||
|
:stop (conman/disconnect! *db*))
|
||||||
|
|
||||||
|
(conman/bind-connection *db* "sql/queries.sql")
|
||||||
|
|
||||||
|
|
||||||
|
(extend-protocol jdbc/IResultSetReadColumn
|
||||||
|
java.sql.Timestamp
|
||||||
|
(result-set-read-column [v _2 _3]
|
||||||
|
(.toLocalDateTime v))
|
||||||
|
java.sql.Date
|
||||||
|
(result-set-read-column [v _2 _3]
|
||||||
|
(.toLocalDate v))
|
||||||
|
java.sql.Time
|
||||||
|
(result-set-read-column [v _2 _3]
|
||||||
|
(.toLocalTime v))
|
||||||
|
Array
|
||||||
|
(result-set-read-column [v _ _] (vec (.getArray v)))
|
||||||
|
PGobject
|
||||||
|
(result-set-read-column [pgobj _metadata _index]
|
||||||
|
(let [type (.getType pgobj)
|
||||||
|
value (.getValue pgobj)]
|
||||||
|
(case type
|
||||||
|
"json" (parse-string value true)
|
||||||
|
"jsonb" (parse-string value true)
|
||||||
|
"citext" (str value)
|
||||||
|
value))))
|
||||||
|
|
||||||
|
(defn to-pg-json [value]
|
||||||
|
(doto (PGobject.)
|
||||||
|
(.setType "jsonb")
|
||||||
|
(.setValue (generate-string value))))
|
||||||
|
|
||||||
|
(extend-type clojure.lang.IPersistentVector
|
||||||
|
jdbc/ISQLParameter
|
||||||
|
(set-parameter [v ^java.sql.PreparedStatement stmt ^long idx]
|
||||||
|
(let [conn (.getConnection stmt)
|
||||||
|
meta (.getParameterMetaData stmt)
|
||||||
|
type-name (.getParameterTypeName meta idx)]
|
||||||
|
(if-let [elem-type (when (= (first type-name) \_) (apply str (rest type-name)))]
|
||||||
|
(.setObject stmt idx (.createArrayOf conn elem-type (to-array v)))
|
||||||
|
(.setObject stmt idx (to-pg-json v))))))
|
||||||
|
|
||||||
|
(extend-protocol jdbc/ISQLValue
|
||||||
|
java.util.Date
|
||||||
|
(sql-value [v]
|
||||||
|
(java.sql.Timestamp. (.getTime v)))
|
||||||
|
java.time.LocalTime
|
||||||
|
(sql-value [v]
|
||||||
|
(jt/sql-time v))
|
||||||
|
java.time.LocalDate
|
||||||
|
(sql-value [v]
|
||||||
|
(jt/sql-date v))
|
||||||
|
java.time.LocalDateTime
|
||||||
|
(sql-value [v]
|
||||||
|
(jt/sql-timestamp v))
|
||||||
|
java.time.ZonedDateTime
|
||||||
|
(sql-value [v]
|
||||||
|
(jt/sql-timestamp v))
|
||||||
|
IPersistentMap
|
||||||
|
(sql-value [value] (to-pg-json value))
|
||||||
|
IPersistentVector
|
||||||
|
(sql-value [value] (to-pg-json value)))
|
||||||
|
|
28
src/clj/cat/handler.clj
Normal file
28
src/clj/cat/handler.clj
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
(ns cat.handler
|
||||||
|
(:require [cat.middleware :as middleware]
|
||||||
|
[cat.layout :refer [error-page]]
|
||||||
|
[cat.routes.home :refer [home-routes]]
|
||||||
|
[cat.routes.oauth :refer [oauth-routes]]
|
||||||
|
[compojure.core :refer [routes wrap-routes]]
|
||||||
|
[ring.util.http-response :as response]
|
||||||
|
[compojure.route :as route]
|
||||||
|
[cat.env :refer [defaults]]
|
||||||
|
[mount.core :as mount]))
|
||||||
|
|
||||||
|
(mount/defstate init-app
|
||||||
|
:start ((or (:init defaults) identity))
|
||||||
|
:stop ((or (:stop defaults) identity)))
|
||||||
|
|
||||||
|
(mount/defstate app
|
||||||
|
:start
|
||||||
|
(middleware/wrap-base
|
||||||
|
(routes
|
||||||
|
(-> #'home-routes
|
||||||
|
(wrap-routes middleware/wrap-csrf)
|
||||||
|
(wrap-routes middleware/wrap-formats))
|
||||||
|
#'oauth-routes
|
||||||
|
(route/not-found
|
||||||
|
(:body
|
||||||
|
(error-page {:status 404
|
||||||
|
:title "page not found"}))))))
|
||||||
|
|
37
src/clj/cat/layout.clj
Normal file
37
src/clj/cat/layout.clj
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
(ns cat.layout
|
||||||
|
(:require [selmer.parser :as parser]
|
||||||
|
[selmer.filters :as filters]
|
||||||
|
[markdown.core :refer [md-to-html-string]]
|
||||||
|
[ring.util.http-response :refer [content-type ok]]
|
||||||
|
[ring.util.anti-forgery :refer [anti-forgery-field]]
|
||||||
|
[ring.middleware.anti-forgery :refer [*anti-forgery-token*]]))
|
||||||
|
|
||||||
|
|
||||||
|
(parser/set-resource-path! (clojure.java.io/resource "html"))
|
||||||
|
(parser/add-tag! :csrf-field (fn [_ _] (anti-forgery-field)))
|
||||||
|
(filters/add-filter! :markdown (fn [content] [:safe (md-to-html-string content)]))
|
||||||
|
|
||||||
|
(defn render
|
||||||
|
"renders the HTML template located relative to resources/html"
|
||||||
|
[template & [params]]
|
||||||
|
(content-type
|
||||||
|
(ok
|
||||||
|
(parser/render-file
|
||||||
|
template
|
||||||
|
(assoc params
|
||||||
|
:page template
|
||||||
|
:csrf-token *anti-forgery-token*)))
|
||||||
|
"text/html; charset=utf-8"))
|
||||||
|
|
||||||
|
(defn error-page
|
||||||
|
"error-details should be a map containing the following keys:
|
||||||
|
:status - error status
|
||||||
|
:title - error title (optional)
|
||||||
|
:message - detailed error message (optional)
|
||||||
|
|
||||||
|
returns a response map with the error page as the body
|
||||||
|
and the status specified by the status key"
|
||||||
|
[error-details]
|
||||||
|
{:status (:status error-details)
|
||||||
|
:headers {"Content-Type" "text/html; charset=utf-8"}
|
||||||
|
:body (parser/render-file "error.html" error-details)})
|
73
src/clj/cat/middleware.clj
Normal file
73
src/clj/cat/middleware.clj
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
(ns cat.middleware
|
||||||
|
(:require [cat.env :refer [defaults]]
|
||||||
|
[cheshire.generate :as cheshire]
|
||||||
|
[cognitect.transit :as transit]
|
||||||
|
[clojure.tools.logging :as log]
|
||||||
|
[cat.layout :refer [error-page]]
|
||||||
|
[ring.middleware.anti-forgery :refer [wrap-anti-forgery]]
|
||||||
|
[ring.middleware.webjars :refer [wrap-webjars]]
|
||||||
|
[cat.middleware.formats :as formats]
|
||||||
|
[muuntaja.middleware :refer [wrap-format wrap-params]]
|
||||||
|
[cat.config :refer [env]]
|
||||||
|
[ring.middleware.flash :refer [wrap-flash]]
|
||||||
|
[immutant.web.middleware :refer [wrap-session]]
|
||||||
|
[ring.middleware.defaults :refer [site-defaults wrap-defaults]]
|
||||||
|
[buddy.auth.middleware :refer [wrap-authentication wrap-authorization]]
|
||||||
|
[buddy.auth.accessrules :refer [restrict]]
|
||||||
|
[buddy.auth :refer [authenticated?]]
|
||||||
|
[buddy.auth.backends.session :refer [session-backend]])
|
||||||
|
(:import))
|
||||||
|
|
||||||
|
|
||||||
|
(defn wrap-internal-error [handler]
|
||||||
|
(fn [req]
|
||||||
|
(try
|
||||||
|
(handler req)
|
||||||
|
(catch Throwable t
|
||||||
|
(log/error t (.getMessage t))
|
||||||
|
(error-page {:status 500
|
||||||
|
:title "Something very bad has happened!"
|
||||||
|
:message "We've dispatched a team of highly trained gnomes to take care of the problem."})))))
|
||||||
|
|
||||||
|
(defn wrap-csrf [handler]
|
||||||
|
(wrap-anti-forgery
|
||||||
|
handler
|
||||||
|
{:error-response
|
||||||
|
(error-page
|
||||||
|
{:status 403
|
||||||
|
:title "Invalid anti-forgery token"})}))
|
||||||
|
|
||||||
|
|
||||||
|
(defn wrap-formats [handler]
|
||||||
|
(let [wrapped (-> handler wrap-params (wrap-format formats/instance))]
|
||||||
|
(fn [request]
|
||||||
|
;; disable wrap-formats for websockets
|
||||||
|
;; since they're not compatible with this middleware
|
||||||
|
((if (:websocket? request) handler wrapped) request))))
|
||||||
|
|
||||||
|
(defn on-error [request response]
|
||||||
|
(error-page
|
||||||
|
{:status 403
|
||||||
|
:title (str "Access to " (:uri request) " is not authorized")}))
|
||||||
|
|
||||||
|
(defn wrap-restricted [handler]
|
||||||
|
(restrict handler {:handler authenticated?
|
||||||
|
:on-error on-error}))
|
||||||
|
|
||||||
|
(defn wrap-auth [handler]
|
||||||
|
(let [backend (session-backend)]
|
||||||
|
(-> handler
|
||||||
|
(wrap-authentication backend)
|
||||||
|
(wrap-authorization backend))))
|
||||||
|
|
||||||
|
(defn wrap-base [handler]
|
||||||
|
(-> ((:middleware defaults) handler)
|
||||||
|
wrap-auth
|
||||||
|
wrap-webjars
|
||||||
|
wrap-flash
|
||||||
|
(wrap-session {:cookie-attrs {:http-only true}})
|
||||||
|
(wrap-defaults
|
||||||
|
(-> site-defaults
|
||||||
|
(assoc-in [:security :anti-forgery] false)
|
||||||
|
(dissoc :session)))
|
||||||
|
wrap-internal-error))
|
14
src/clj/cat/middleware/formats.clj
Normal file
14
src/clj/cat/middleware/formats.clj
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
(ns cat.middleware.formats
|
||||||
|
(:require [cognitect.transit :as transit]
|
||||||
|
[luminus-transit.time :as time]
|
||||||
|
[muuntaja.core :as m]))
|
||||||
|
|
||||||
|
(def instance
|
||||||
|
(m/create
|
||||||
|
(-> m/default-options
|
||||||
|
(update-in
|
||||||
|
[:formats "application/transit+json" :decoder-opts]
|
||||||
|
(partial merge time/time-deserialization-handlers))
|
||||||
|
(update-in
|
||||||
|
[:formats "application/transit+json" :encoder-opts]
|
||||||
|
(partial merge time/time-serialization-handlers)))))
|
26
src/clj/cat/nrepl.clj
Normal file
26
src/clj/cat/nrepl.clj
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
(ns cat.nrepl
|
||||||
|
(:require [nrepl.server :as nrepl]
|
||||||
|
[clojure.tools.logging :as log]))
|
||||||
|
|
||||||
|
(defn start
|
||||||
|
"Start a network repl for debugging on specified port followed by
|
||||||
|
an optional parameters map. The :bind, :transport-fn, :handler,
|
||||||
|
:ack-port and :greeting-fn will be forwarded to
|
||||||
|
clojure.tools.nrepl.server/start-server as they are."
|
||||||
|
[{:keys [port bind transport-fn handler ack-port greeting-fn]}]
|
||||||
|
(try
|
||||||
|
(log/info "starting nREPL server on port" port)
|
||||||
|
(nrepl/start-server :port port
|
||||||
|
:bind bind
|
||||||
|
:transport-fn transport-fn
|
||||||
|
:handler handler
|
||||||
|
:ack-port ack-port
|
||||||
|
:greeting-fn greeting-fn)
|
||||||
|
|
||||||
|
(catch Throwable t
|
||||||
|
(log/error t "failed to start nREPL")
|
||||||
|
(throw t))))
|
||||||
|
|
||||||
|
(defn stop [server]
|
||||||
|
(nrepl/stop-server server)
|
||||||
|
(log/info "nREPL server stopped"))
|
35
src/clj/cat/oauth.clj
Normal file
35
src/clj/cat/oauth.clj
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
(ns cat.oauth
|
||||||
|
(:require [cat.config :refer [env]]
|
||||||
|
[oauth.client :as oauth]
|
||||||
|
[mount.core :refer [defstate]]
|
||||||
|
[clojure.tools.logging :as log]))
|
||||||
|
|
||||||
|
(defstate consumer
|
||||||
|
:start (oauth/make-consumer
|
||||||
|
(env :oauth-consumer-key)
|
||||||
|
(env :oauth-consumer-secret)
|
||||||
|
(env :request-token-uri)
|
||||||
|
(env :access-token-uri)
|
||||||
|
(env :authorize-uri)
|
||||||
|
:hmac-sha1))
|
||||||
|
|
||||||
|
(defn oauth-callback-uri
|
||||||
|
"Generates the oauth request callback URI"
|
||||||
|
[{:keys [headers]}]
|
||||||
|
(str (headers "x-forwarded-proto") "://" (headers "host") "/oauth/oauth-callback"))
|
||||||
|
|
||||||
|
(defn fetch-request-token
|
||||||
|
"Fetches a request token."
|
||||||
|
[request]
|
||||||
|
(let [callback-uri (oauth-callback-uri request)]
|
||||||
|
(log/info "Fetching request token using callback-uri" callback-uri)
|
||||||
|
(oauth/request-token consumer (oauth-callback-uri request))))
|
||||||
|
|
||||||
|
(defn fetch-access-token
|
||||||
|
[request_token]
|
||||||
|
(oauth/access-token consumer request_token (:oauth_verifier request_token)))
|
||||||
|
|
||||||
|
(defn auth-redirect-uri
|
||||||
|
"Gets the URI the user should be redirected to when authenticating."
|
||||||
|
[request-token]
|
||||||
|
(str (oauth/user-approval-uri consumer request-token)))
|
88
src/clj/cat/routes/home.clj
Normal file
88
src/clj/cat/routes/home.clj
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
(ns cat.routes.home
|
||||||
|
(:require [cat.layout :as layout]
|
||||||
|
[cat.db.core :refer [*db*] :as db]
|
||||||
|
[compojure.core :refer [defroutes GET POST]]
|
||||||
|
[ring.util.http-response :as response]
|
||||||
|
[clojure.java.io :as io]
|
||||||
|
[struct.core :as st]
|
||||||
|
[clojure.edn :as edn]
|
||||||
|
[clojure.tools.logging :as log]
|
||||||
|
[clojure.data.json :as json]))
|
||||||
|
|
||||||
|
(def user-schema
|
||||||
|
[[:name st/required st/string]
|
||||||
|
[:gender st/string]])
|
||||||
|
|
||||||
|
(def relation-schema
|
||||||
|
[[:from_id st/required st/integer-str]
|
||||||
|
[:to_id st/required st/integer-str]])
|
||||||
|
|
||||||
|
(defn home-page [params]
|
||||||
|
(layout/render "home.html" params))
|
||||||
|
|
||||||
|
(defn get-relations []
|
||||||
|
(map
|
||||||
|
(fn [relation] (select-keys relation [:name :name_2]))
|
||||||
|
(db/get-relations)))
|
||||||
|
|
||||||
|
(defn get-users []
|
||||||
|
(db/get-users))
|
||||||
|
|
||||||
|
(defroutes home-routes
|
||||||
|
(GET "/" []
|
||||||
|
(let [users (get-users)
|
||||||
|
relations (get-relations)]
|
||||||
|
(home-page {:relations relations :users users})))
|
||||||
|
;(GET "/docs" []
|
||||||
|
; (-> (response/ok (-> "docs/docs.md" io/resource slurp))
|
||||||
|
; (response/header "Content-Type" "text/plain; charset=utf-8")))
|
||||||
|
(GET "/relations" []
|
||||||
|
(let []
|
||||||
|
(response/ok {})))
|
||||||
|
(GET "/relations_zeroed" []
|
||||||
|
(let [users (db/get-users)
|
||||||
|
relations (db/get-relations)
|
||||||
|
used-node-ids (set (flatten (map (fn [ln] [(:from_id ln) (:to_id ln)]) relations)))
|
||||||
|
filtered-users (filter (fn [{id :id}] (contains? used-node-ids id)) users)
|
||||||
|
id-index-map (:map (reduce (fn [{map :map idx :index} usr]
|
||||||
|
{:map (assoc map (:id usr) idx)
|
||||||
|
:index (inc idx)})
|
||||||
|
{:map {} :index 0}
|
||||||
|
filtered-users))
|
||||||
|
rels-indexed (map (fn [{src :from_id target :to_id}]
|
||||||
|
{:source (get id-index-map src)
|
||||||
|
:target (get id-index-map target)
|
||||||
|
:value (+ 20 (rand-int 30))})
|
||||||
|
relations)
|
||||||
|
nodes-indexed (->> filtered-users
|
||||||
|
(map (fn [usr]
|
||||||
|
(-> usr
|
||||||
|
(dissoc :gender :id)
|
||||||
|
(assoc :index (get id-index-map (:id usr)))
|
||||||
|
(assoc :group (rand-int 2))))))]
|
||||||
|
(response/ok {:nodes nodes-indexed
|
||||||
|
:links rels-indexed})))
|
||||||
|
(POST "/relations" req
|
||||||
|
(let [data (:params req) [err result] (st/validate data relation-schema)]
|
||||||
|
(log/info "Post to " (:uri req))
|
||||||
|
(if (nil? err)
|
||||||
|
(do
|
||||||
|
(db/create-relation! result)
|
||||||
|
(response/no-content))
|
||||||
|
(do
|
||||||
|
(response/bad-request "Incorrect input")))))
|
||||||
|
(POST "/users" req
|
||||||
|
(let [data (:params req)]
|
||||||
|
(log/info "Post to " (:uri req))
|
||||||
|
(println data)
|
||||||
|
(if (st/valid? data user-schema)
|
||||||
|
(do
|
||||||
|
(db/create-user! data)
|
||||||
|
(response/no-content))
|
||||||
|
(do
|
||||||
|
(response/bad-request "Incorrect input"))))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
34
src/clj/cat/routes/oauth.clj
Normal file
34
src/clj/cat/routes/oauth.clj
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
(ns cat.routes.oauth
|
||||||
|
(:require [ring.util.http-response :refer [ok found]]
|
||||||
|
[compojure.core :refer [defroutes GET]]
|
||||||
|
[clojure.java.io :as io]
|
||||||
|
[cat.oauth :as oauth]
|
||||||
|
[clojure.tools.logging :as log]))
|
||||||
|
|
||||||
|
(defn oauth-init
|
||||||
|
"Initiates the Twitter OAuth"
|
||||||
|
[request]
|
||||||
|
(-> (oauth/fetch-request-token request)
|
||||||
|
:oauth_token
|
||||||
|
oauth/auth-redirect-uri
|
||||||
|
found))
|
||||||
|
|
||||||
|
(defn oauth-callback
|
||||||
|
"Handles the callback from Twitter."
|
||||||
|
[{:keys [session params]}]
|
||||||
|
; oauth request was denied by user
|
||||||
|
(if (:denied params)
|
||||||
|
(-> (found "/")
|
||||||
|
(assoc :flash {:denied true}))
|
||||||
|
; fetch the request token and do anything else you wanna do if not denied.
|
||||||
|
(let [{:keys [user_id screen_name]} (oauth/fetch-access-token params)]
|
||||||
|
(log/info "successfully authenticated as" user_id screen_name)
|
||||||
|
(-> (found "/")
|
||||||
|
(assoc :session
|
||||||
|
(assoc session :user-id user_id :screen-name screen_name))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defroutes oauth-routes
|
||||||
|
(GET "/oauth/oauth-init" req (oauth-init req))
|
||||||
|
(GET "/oauth/oauth-callback" [& req_token :as req] (oauth-callback req)))
|
||||||
|
|
2
src/cljc/cat/validation.cljc
Normal file
2
src/cljc/cat/validation.cljc
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
(ns cat.validation
|
||||||
|
(:require [struct.core :as st]))
|
159
src/cljs/cat/core.cljs
Normal file
159
src/cljs/cat/core.cljs
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
(ns cat.core
|
||||||
|
(:require [vega-tools.core :refer [validate-and-parse]]
|
||||||
|
[promesa.core :as p]))
|
||||||
|
|
||||||
|
|
||||||
|
;(defn ^:export main []
|
||||||
|
; (println "This is the main function.")
|
||||||
|
; (let [spec {:width 200 :height 200
|
||||||
|
; :marks [{:type "symbol"
|
||||||
|
; :properties {:enter {:size {:value 1000}
|
||||||
|
; :x {:value 100}
|
||||||
|
; :y {:value 100}
|
||||||
|
; :shape {:value "circle"}
|
||||||
|
; :stroke {:value "red"}}}}]}]
|
||||||
|
; (-> (validate-and-parse spec)
|
||||||
|
; (p/catch #(js/alert (str "Unable to parse spec:\n\n" %)))
|
||||||
|
; (p/then #(-> (% {:el (js/document.getElementById "#chart")})
|
||||||
|
; (.update))))))
|
||||||
|
|
||||||
|
|
||||||
|
;(defn on-js-reload []
|
||||||
|
; (println "This is the on-js-reload function.")
|
||||||
|
; (main))
|
||||||
|
|
||||||
|
(defn mount-components []
|
||||||
|
(let [spec {:width 700 :height 500
|
||||||
|
:signals [{:name "cx"}]
|
||||||
|
:marks [{:name "nodes"
|
||||||
|
:type "symbol"
|
||||||
|
:properties {:enter {:size {:value 1000}
|
||||||
|
:x {:value 100}
|
||||||
|
:y {:value 100}
|
||||||
|
:shape {:value "circle"}
|
||||||
|
:stroke {:value "red"}}}}]}
|
||||||
|
nodespec {;:$schema "https://vega.github.io/schema/vega/v4.json",
|
||||||
|
:width 700,
|
||||||
|
:height 500,
|
||||||
|
:padding 0,
|
||||||
|
:autosize "none",
|
||||||
|
:signals [{:name "cx", :update "width / 2"}
|
||||||
|
{:name "cy", :update "height / 2"}
|
||||||
|
{:name "nodeRadius", :value 8,
|
||||||
|
:bind {:input "range",
|
||||||
|
:min 1,
|
||||||
|
:max 50,
|
||||||
|
:step 1}}
|
||||||
|
{:name "nodeCharge", :value -30,
|
||||||
|
:bind {:input "range",
|
||||||
|
:min -100,
|
||||||
|
:max 10,
|
||||||
|
:step 1}}
|
||||||
|
{:name "linkDistance", :value 30,
|
||||||
|
:bind {:input "range",
|
||||||
|
:min 5,
|
||||||
|
:max 100,
|
||||||
|
:step 1}}
|
||||||
|
{:name "static", :value true,
|
||||||
|
:bind {:input "checkbox"}}
|
||||||
|
;{:description
|
||||||
|
; "State variable for active node fix status.",
|
||||||
|
; :name "fix", :value false,
|
||||||
|
; :on [{:events "symbol:mouseout[!event.buttons], window:mouseup",
|
||||||
|
; :update "false"}
|
||||||
|
; {:events "symbol:mouseover",
|
||||||
|
; :update "fix || true"}
|
||||||
|
; {:events "[symbol:mousedown, window:mouseup] > window:mousemove!",
|
||||||
|
; :update "xy()",
|
||||||
|
; :force true}]}
|
||||||
|
;{:description "Graph node most recently interacted with.",
|
||||||
|
; :name "node", :value nil,
|
||||||
|
; :on [{:events "symbol:mouseover",
|
||||||
|
; :update "fix === true ? item() : node"}]}
|
||||||
|
{:description "Flag to restart Force simulation upon data changes.",
|
||||||
|
:name "restart",
|
||||||
|
:value false,
|
||||||
|
:on [{:events {:signal "fix"},
|
||||||
|
:update "fix && fix.length"}]}],
|
||||||
|
:data [{:name "node-data"
|
||||||
|
:url "/relations"
|
||||||
|
:format {:type "json", :property "nodes"}
|
||||||
|
}
|
||||||
|
{:name "link-data"
|
||||||
|
:url "/relations"
|
||||||
|
:format {:type "json", :property "links"}
|
||||||
|
:transform [{:type "lookup"
|
||||||
|
:fields ["name" "name_2"]
|
||||||
|
:as ["source" "target"]}]
|
||||||
|
}],
|
||||||
|
;:scales
|
||||||
|
; [{:name "color",
|
||||||
|
; :type "ordinal",
|
||||||
|
; :domain {:data "node-data", :field "name"},
|
||||||
|
; :range {:scheme "category20c"}}],
|
||||||
|
|
||||||
|
:marks
|
||||||
|
[{:name "nodes",
|
||||||
|
:type "symbol",
|
||||||
|
:zindex 1,
|
||||||
|
:from {:data "node-data"},
|
||||||
|
:on
|
||||||
|
[{:trigger "fix",
|
||||||
|
:modify "node",
|
||||||
|
:values
|
||||||
|
"fix === true ? {fx: node.x, fy: node.y} : {fx: fix[0], fy: fix[1]}"}
|
||||||
|
{:trigger "!fix",
|
||||||
|
:modify "node",
|
||||||
|
:values "{fx: null, fy: null}"}],
|
||||||
|
;:encode
|
||||||
|
; {:enter
|
||||||
|
; {:fill {:scale "color", :field "group"},
|
||||||
|
; :stroke {:value "white"}},
|
||||||
|
; :update
|
||||||
|
; {:size
|
||||||
|
; {:signal "2 * nodeRadius * nodeRadius"},
|
||||||
|
; :cursor {:value "pointer"}}},
|
||||||
|
:transform
|
||||||
|
[{:type "force",
|
||||||
|
:iterations 300,
|
||||||
|
:restart {:signal "restart"},
|
||||||
|
:static {:signal "static"},
|
||||||
|
:signal "force",
|
||||||
|
:forces [{:force "center",
|
||||||
|
:x {:signal "cx"},
|
||||||
|
:y {:signal "cy"}}
|
||||||
|
{:force "collide",
|
||||||
|
:radius {:signal "nodeRadius"}}
|
||||||
|
{:force "nbody",
|
||||||
|
:strength {:signal "nodeCharge"}}
|
||||||
|
{:force "link",
|
||||||
|
:links "link-data",
|
||||||
|
:distance {:signal "linkDistance"}}]}]}
|
||||||
|
{:type "path",
|
||||||
|
:interactive false,
|
||||||
|
:from {:data "link-data"},
|
||||||
|
:encode {:update
|
||||||
|
{:stroke {:value "#ccc"},
|
||||||
|
:strokeWidth {:value 0.5}}},
|
||||||
|
:transform
|
||||||
|
[{:type "linkpath",
|
||||||
|
:require {:signal "force"},
|
||||||
|
:shape "line",
|
||||||
|
:sourceX "datum.source.x", :sourceY "datum.source.y",
|
||||||
|
:targetX "datum.target.x", :targetY "datum.target.y"}]}]}]
|
||||||
|
|
||||||
|
;(-> (validate-and-parse nodespec)
|
||||||
|
; (p/catch #(js/alert (str "Unable to parse spec:\n\n" %)))
|
||||||
|
; (p/then #(-> (% {:el (js/document.getElementById "chart")})
|
||||||
|
; (.update))))
|
||||||
|
|
||||||
|
(let [content (js/document.getElementById "app")]
|
||||||
|
(while (.hasChildNodes content)
|
||||||
|
(.removeChild content (.-lastChild content)))
|
||||||
|
(.appendChild content (js/document.createTextNode "Welcome to cat")))))
|
||||||
|
|
||||||
|
(defn init! []
|
||||||
|
(mount-components))
|
||||||
|
;(main))
|
||||||
|
|
||||||
|
|
36
test/clj/cat/test/db/core.clj
Normal file
36
test/clj/cat/test/db/core.clj
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
(ns cat.test.db.core
|
||||||
|
(:require [cat.db.core :refer [*db*] :as db]
|
||||||
|
[luminus-migrations.core :as migrations]
|
||||||
|
[clojure.test :refer :all]
|
||||||
|
[clojure.java.jdbc :as jdbc]
|
||||||
|
[cat.config :refer [env]]
|
||||||
|
[mount.core :as mount]))
|
||||||
|
|
||||||
|
(use-fixtures
|
||||||
|
:once
|
||||||
|
(fn [f]
|
||||||
|
(mount/start
|
||||||
|
#'cat.config/env
|
||||||
|
#'cat.db.core/*db*)
|
||||||
|
(migrations/migrate ["migrate"] (select-keys env [:database-url]))
|
||||||
|
(f)))
|
||||||
|
|
||||||
|
(deftest test-users
|
||||||
|
(jdbc/with-db-transaction [t-conn *db*]
|
||||||
|
(jdbc/db-set-rollback-only! t-conn)
|
||||||
|
(is (= 1 (db/create-user!
|
||||||
|
t-conn
|
||||||
|
{:id "1"
|
||||||
|
:first_name "Sam"
|
||||||
|
:last_name "Smith"
|
||||||
|
:email "sam.smith@example.com"
|
||||||
|
:pass "pass"})))
|
||||||
|
(is (= {:id "1"
|
||||||
|
:first_name "Sam"
|
||||||
|
:last_name "Smith"
|
||||||
|
:email "sam.smith@example.com"
|
||||||
|
:pass "pass"
|
||||||
|
:admin nil
|
||||||
|
:last_login nil
|
||||||
|
:is_active nil}
|
||||||
|
(db/get-user t-conn {:id "1"})))))
|
26
test/clj/cat/test/handler.clj
Normal file
26
test/clj/cat/test/handler.clj
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
(ns cat.test.handler
|
||||||
|
(:require [clojure.test :refer :all]
|
||||||
|
[ring.mock.request :refer :all]
|
||||||
|
[cat.handler :refer :all]
|
||||||
|
[cat.middleware.formats :as formats]
|
||||||
|
[muuntaja.core :as m]
|
||||||
|
[mount.core :as mount]))
|
||||||
|
|
||||||
|
(defn parse-json [body]
|
||||||
|
(m/decode formats/instance "application/json" body))
|
||||||
|
|
||||||
|
(use-fixtures
|
||||||
|
:once
|
||||||
|
(fn [f]
|
||||||
|
(mount/start #'cat.config/env
|
||||||
|
#'cat.handler/app)
|
||||||
|
(f)))
|
||||||
|
|
||||||
|
(deftest test-app
|
||||||
|
(testing "main route"
|
||||||
|
(let [response (app (request :get "/"))]
|
||||||
|
(is (= 200 (:status response)))))
|
||||||
|
|
||||||
|
(testing "not-found route"
|
||||||
|
(let [response (app (request :get "/invalid"))]
|
||||||
|
(is (= 404 (:status response))))))
|
8
test/cljs/cat/core_test.cljs
Normal file
8
test/cljs/cat/core_test.cljs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
(ns cat.core-test
|
||||||
|
(:require [cljs.test :refer-macros [is are deftest testing use-fixtures]]
|
||||||
|
[pjstadig.humane-test-output]
|
||||||
|
[cat.core :as rc]))
|
||||||
|
|
||||||
|
(deftest test-home
|
||||||
|
(is (= true true)))
|
||||||
|
|
6
test/cljs/cat/doo_runner.cljs
Normal file
6
test/cljs/cat/doo_runner.cljs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
(ns cat.doo-runner
|
||||||
|
(:require [doo.runner :refer-macros [doo-tests]]
|
||||||
|
[cat.core-test]))
|
||||||
|
|
||||||
|
(doo-tests 'cat.core-test)
|
||||||
|
|
Loading…
Reference in a new issue