Initial commit
This commit is contained in:
commit
86c675f22d
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/target
|
||||||
|
/lib
|
||||||
|
/classes
|
||||||
|
/checkouts
|
||||||
|
pom.xml
|
||||||
|
dev-config.edn
|
||||||
|
test-config.edn
|
||||||
|
*.jar
|
||||||
|
*.class
|
||||||
|
/.lein-*
|
||||||
|
profiles.clj
|
||||||
|
/.env
|
||||||
|
.nrepl-port
|
||||||
|
|
||||||
|
/node_modules
|
||||||
|
/log
|
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 /geocsv/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:
|
||||||
|
/geocsv/app.jar: ./target/uberjar/geocsv.jar
|
||||||
|
|
7
Dockerfile
Normal file
7
Dockerfile
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
FROM openjdk:8-alpine
|
||||||
|
|
||||||
|
COPY target/uberjar/geocsv.jar /geocsv/app.jar
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["java", "-jar", "/geocsv/app.jar"]
|
1
Procfile
Normal file
1
Procfile
Normal file
|
@ -0,0 +1 @@
|
||||||
|
web: java -cp target/uberjar/geocsv.jar clojure.main -m geocsv.core
|
21
README.md
Normal file
21
README.md
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# geocsv
|
||||||
|
|
||||||
|
generated using Luminus version "3.57"
|
||||||
|
|
||||||
|
FIXME
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
You will need [Leiningen][1] 2.0 or above installed.
|
||||||
|
|
||||||
|
[1]: https://github.com/technomancy/leiningen
|
||||||
|
|
||||||
|
## Running
|
||||||
|
|
||||||
|
To start a web server for the application, run:
|
||||||
|
|
||||||
|
lein run
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Copyright © 2020 FIXME
|
11
env/dev/clj/geocsv/dev_middleware.clj
vendored
Normal file
11
env/dev/clj/geocsv/dev_middleware.clj
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
(ns geocsv.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 ['geocsv]})))
|
15
env/dev/clj/geocsv/env.clj
vendored
Normal file
15
env/dev/clj/geocsv/env.clj
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
(ns geocsv.env
|
||||||
|
(:require
|
||||||
|
[selmer.parser :as parser]
|
||||||
|
[clojure.tools.logging :as log]
|
||||||
|
[geocsv.dev-middleware :refer [wrap-dev]]))
|
||||||
|
|
||||||
|
(def defaults
|
||||||
|
{:init
|
||||||
|
(fn []
|
||||||
|
(parser/cache-off!)
|
||||||
|
(log/info "\n-=[geocsv started successfully using the development profile]=-"))
|
||||||
|
:stop
|
||||||
|
(fn []
|
||||||
|
(log/info "\n-=[geocsv has shut down successfully]=-"))
|
||||||
|
:middleware wrap-dev})
|
12
env/dev/clj/geocsv/figwheel.clj
vendored
Normal file
12
env/dev/clj/geocsv/figwheel.clj
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
(ns geocsv.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))
|
||||||
|
|
33
env/dev/clj/user.clj
vendored
Normal file
33
env/dev/clj/user.clj
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
(ns user
|
||||||
|
"Userspace functions you can run by default in your local REPL."
|
||||||
|
(:require
|
||||||
|
[geocsv.config :refer [env]]
|
||||||
|
[clojure.pprint]
|
||||||
|
[clojure.spec.alpha :as s]
|
||||||
|
[expound.alpha :as expound]
|
||||||
|
[mount.core :as mount]
|
||||||
|
[geocsv.figwheel :refer [start-fw stop-fw cljs]]
|
||||||
|
[geocsv.core :refer [start-app]]))
|
||||||
|
|
||||||
|
(alter-var-root #'s/*explain-out* (constantly expound/printer))
|
||||||
|
|
||||||
|
(add-tap (bound-fn* clojure.pprint/pprint))
|
||||||
|
|
||||||
|
(defn start
|
||||||
|
"Starts application.
|
||||||
|
You'll usually want to run this on startup."
|
||||||
|
[]
|
||||||
|
(mount/start-without #'geocsv.core/repl-server))
|
||||||
|
|
||||||
|
(defn stop
|
||||||
|
"Stops application."
|
||||||
|
[]
|
||||||
|
(mount/stop-except #'geocsv.core/repl-server))
|
||||||
|
|
||||||
|
(defn restart
|
||||||
|
"Restarts application."
|
||||||
|
[]
|
||||||
|
(stop)
|
||||||
|
(start))
|
||||||
|
|
||||||
|
|
19
env/dev/cljs/geocsv/app.cljs
vendored
Normal file
19
env/dev/cljs/geocsv/app.cljs
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
(ns^:figwheel-no-load geocsv.app
|
||||||
|
(:require
|
||||||
|
[geocsv.core :as core]
|
||||||
|
[cljs.spec.alpha :as s]
|
||||||
|
[expound.alpha :as expound]
|
||||||
|
[devtools.core :as devtools]))
|
||||||
|
|
||||||
|
(extend-protocol IPrintWithWriter
|
||||||
|
js/Symbol
|
||||||
|
(-pr-writer [sym writer _]
|
||||||
|
(-write writer (str "\"" (.toString sym) "\""))))
|
||||||
|
|
||||||
|
(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 @@
|
||||||
|
{}
|
34
env/dev/resources/logback.xml
vendored
Normal file
34
env/dev/resources/logback.xml
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration scan="true" scanPeriod="10 seconds">
|
||||||
|
<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/geocsv.log</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>log/geocsv.%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="org.eclipse.jetty" level="warn" />
|
||||||
|
<root level="DEBUG">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
<appender-ref ref="FILE" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
11
env/prod/clj/geocsv/env.clj
vendored
Normal file
11
env/prod/clj/geocsv/env.clj
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
(ns geocsv.env
|
||||||
|
(:require [clojure.tools.logging :as log]))
|
||||||
|
|
||||||
|
(def defaults
|
||||||
|
{:init
|
||||||
|
(fn []
|
||||||
|
(log/info "\n-=[geocsv started successfully]=-"))
|
||||||
|
:stop
|
||||||
|
(fn []
|
||||||
|
(log/info "\n-=[geocsv has shut down successfully]=-"))
|
||||||
|
:middleware identity})
|
7
env/prod/cljs/geocsv/app.cljs
vendored
Normal file
7
env/prod/cljs/geocsv/app.cljs
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
(ns geocsv.app
|
||||||
|
(:require [geocsv.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/geocsv.log</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>log/geocsv.%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="org.eclipse.jetty" 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 @@
|
||||||
|
{}
|
34
env/test/resources/logback.xml
vendored
Normal file
34
env/test/resources/logback.xml
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration scan="true" scanPeriod="10 seconds">
|
||||||
|
<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/geocsv.log</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>log/geocsv.%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="org.eclipse.jetty" level="warn" />
|
||||||
|
<root level="DEBUG">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
<appender-ref ref="FILE" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
134
project.clj
Normal file
134
project.clj
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
(defproject geocsv "0.1.0-SNAPSHOT"
|
||||||
|
|
||||||
|
:description "FIXME: write description"
|
||||||
|
:url "http://example.com/FIXME"
|
||||||
|
|
||||||
|
:dependencies [[ch.qos.logback/logback-classic "1.2.3"]
|
||||||
|
[cheshire "5.9.0"]
|
||||||
|
[cljs-ajax "0.8.0"]
|
||||||
|
[cljsjs/leaflet "1.2.0-0"]
|
||||||
|
[clojure.java-time "0.3.2"]
|
||||||
|
[com.cognitect/transit-clj "0.8.319"]
|
||||||
|
[cprop "0.1.15"]
|
||||||
|
[day8.re-frame/http-fx "0.1.6"]
|
||||||
|
[expound "0.8.3"]
|
||||||
|
[funcool/struct "1.4.0"]
|
||||||
|
[luminus-jetty "0.1.7"]
|
||||||
|
[luminus-transit "0.1.2"]
|
||||||
|
[luminus/ring-ttl-session "0.3.3"]
|
||||||
|
[markdown-clj "1.10.1"]
|
||||||
|
[metosin/muuntaja "0.6.6"]
|
||||||
|
[metosin/reitit "0.3.10"]
|
||||||
|
[metosin/ring-http-response "0.9.1"]
|
||||||
|
[mount "0.1.16"]
|
||||||
|
[nrepl "0.6.0"]
|
||||||
|
[org.clojure/clojure "1.10.1"]
|
||||||
|
[org.clojure/clojurescript "1.10.597" :scope "provided"]
|
||||||
|
[org.clojure/tools.cli "0.4.2"]
|
||||||
|
[org.clojure/tools.logging "0.5.0"]
|
||||||
|
[org.webjars.npm/bulma "0.8.0"]
|
||||||
|
[org.webjars.npm/material-icons "0.3.1"]
|
||||||
|
[org.webjars/webjars-locator "0.38"]
|
||||||
|
[re-frame "0.10.9"]
|
||||||
|
[reagent "0.9.0-rc3"]
|
||||||
|
[recalcitrant "0.1.2"]
|
||||||
|
[ring-webjars "0.2.0"]
|
||||||
|
[ring/ring-core "1.8.0"]
|
||||||
|
[ring/ring-defaults "0.3.2"]
|
||||||
|
[selmer "1.12.18"]]
|
||||||
|
|
||||||
|
: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 geocsv.core
|
||||||
|
|
||||||
|
:plugins [[lein-cljsbuild "1.1.7"]]
|
||||||
|
: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.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}
|
||||||
|
:externs ["react/externs/react.js"]}}}}
|
||||||
|
|
||||||
|
:aot :all
|
||||||
|
:uberjar-name "geocsv.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.11"]
|
||||||
|
[cider/piggieback "0.4.2"]
|
||||||
|
[doo "0.1.11"]
|
||||||
|
[figwheel-sidecar "0.5.19"]
|
||||||
|
[pjstadig/humane-test-output "0.10.0"]
|
||||||
|
[prone "2019-07-08"]
|
||||||
|
[re-frisk "0.5.4.1"]
|
||||||
|
[ring/ring-devel "1.8.0"]
|
||||||
|
[ring/ring-mock "0.4.0"]]
|
||||||
|
:plugins [[com.jakemccrary/lein-test-refresh "0.24.1"]
|
||||||
|
[jonase/eastwood "0.3.5"]
|
||||||
|
[lein-doo "0.1.11"]
|
||||||
|
[lein-figwheel "0.5.19"]]
|
||||||
|
:cljsbuild{:builds
|
||||||
|
{:app
|
||||||
|
{:source-paths ["src/cljs" "src/cljc" "env/dev/cljs"]
|
||||||
|
:figwheel {:on-jsload "geocsv.core/mount-components"}
|
||||||
|
:compiler
|
||||||
|
{:output-dir "target/cljsbuild/public/js/out"
|
||||||
|
:closure-defines {"re_frame.trace.trace_enabled_QMARK_" true}
|
||||||
|
:optimizations :none
|
||||||
|
:preloads [re-frisk.preload]
|
||||||
|
:output-to "target/cljsbuild/public/js/app.js"
|
||||||
|
:asset-path "/js/out"
|
||||||
|
:source-map true
|
||||||
|
:main "geocsv.app"
|
||||||
|
: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 "geocsv.doo-runner"
|
||||||
|
:optimizations :whitespace
|
||||||
|
:pretty-print true}}}}
|
||||||
|
|
||||||
|
}
|
||||||
|
:profiles/dev {}
|
||||||
|
:profiles/test {}})
|
88
resources/docs/docs.md
Normal file
88
resources/docs/docs.md
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
<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 `geocsv.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.
|
||||||
|
|
||||||
|
```
|
||||||
|
(defn home-routes []
|
||||||
|
[""
|
||||||
|
{:middleware [middleware/wrap-csrf
|
||||||
|
middleware/wrap-formats]}
|
||||||
|
["/" {:get home-page}]
|
||||||
|
["/docs" {:get (fn [_]
|
||||||
|
(-> (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 `geocsv.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/geocsv/core.cljs` file.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### Organizing the routes
|
||||||
|
|
||||||
|
The routes are aggregated and wrapped with middleware in the `geocsv.handler` namespace:
|
||||||
|
|
||||||
|
```
|
||||||
|
(mount/defstate app
|
||||||
|
:start
|
||||||
|
(middleware/wrap-base
|
||||||
|
(ring/ring-handler
|
||||||
|
(ring/router
|
||||||
|
[(home-routes)])
|
||||||
|
(ring/routes
|
||||||
|
(ring/create-resource-handler
|
||||||
|
{:path "/"})
|
||||||
|
(wrap-content-type
|
||||||
|
(wrap-webjars (constantly nil)))
|
||||||
|
(ring/create-default-handler
|
||||||
|
{:not-found
|
||||||
|
(constantly (error-page {:status 404, :title "404 - Page not found"}))
|
||||||
|
:method-not-allowed
|
||||||
|
(constantly (error-page {:status 405, :title "405 - Not allowed"}))
|
||||||
|
:not-acceptable
|
||||||
|
(constantly (error-page {:status 406, :title "406 - Not acceptable"}))})))))
|
||||||
|
```
|
||||||
|
|
||||||
|
The `app` definition groups all the routes in the application into a single handler.
|
||||||
|
A default route group is added to handle the `404`, `405`, and `406` errors.
|
||||||
|
|
||||||
|
<a class="btn btn-primary" href="https://metosin.github.io/reitit/basics">learn more about routing »</a>
|
||||||
|
|
||||||
|
#### Managing your middleware
|
||||||
|
|
||||||
|
Request middleware functions are located under the `geocsv.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 `geocsv.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>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### 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.
|
49
resources/html/error.html
Normal file
49
resources/html/error.html
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<!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/bulma/css/bulma.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 is-fluid">
|
||||||
|
<div class="has-text-centered">
|
||||||
|
<h1><span class="is-size-4 has-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>
|
||||||
|
</body>
|
||||||
|
</html>
|
41
resources/html/home.html
Normal file
41
resources/html/home.html
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Welcome to geocsv</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="app">
|
||||||
|
<section class="section">
|
||||||
|
<div class="container is-fluid">
|
||||||
|
<div class="content">
|
||||||
|
<h4 class="title">Welcome to geocsv</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>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- scripts and styles -->
|
||||||
|
{% style "/assets/bulma/css/bulma.min.css" %}
|
||||||
|
{% style "/assets/material-icons/css/material-icons.min.css" %}
|
||||||
|
{% style "/css/screen.css" %}
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
var csrfToken = "{{csrf-token}}";
|
||||||
|
</script>
|
||||||
|
{% script "/js/app.js" %}
|
||||||
|
</body>
|
||||||
|
</html>
|
35
resources/public/css/screen.css
Normal file
35
resources/public/css/screen.css
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Material Icons';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url(/assets/material-icons/iconfont/MaterialIcons-Regular.eot); /* For IE6-8 */
|
||||||
|
src: local('Material Icons'),
|
||||||
|
local('MaterialIcons-Regular'),
|
||||||
|
url(/assets/material-icons/iconfont/MaterialIcons-Regular.woff2) format('woff2'),
|
||||||
|
url(/assets/material-icons/iconfont/MaterialIcons-Regular.woff) format('woff'),
|
||||||
|
url(/assets/material-icons/iconfont/MaterialIcons-Regular.ttf) format('truetype');
|
||||||
|
}
|
||||||
|
.material-icons {
|
||||||
|
font-family: 'Material Icons';
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 24px; /* Preferred icon size */
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 1;
|
||||||
|
text-transform: none;
|
||||||
|
letter-spacing: normal;
|
||||||
|
word-wrap: normal;
|
||||||
|
white-space: nowrap;
|
||||||
|
direction: ltr;
|
||||||
|
/* Support for all WebKit browsers. */
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
/* Support for Safari and Chrome. */
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
/* Support for Firefox. */
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
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
src/clj/geocsv/config.clj
Normal file
13
src/clj/geocsv/config.clj
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
(ns geocsv.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)]))
|
58
src/clj/geocsv/core.clj
Normal file
58
src/clj/geocsv/core.clj
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
(ns geocsv.core
|
||||||
|
(:require
|
||||||
|
[geocsv.handler :as handler]
|
||||||
|
[geocsv.nrepl :as nrepl]
|
||||||
|
[luminus.http-server :as http]
|
||||||
|
[geocsv.config :refer [env]]
|
||||||
|
[clojure.tools.cli :refer [parse-opts]]
|
||||||
|
[clojure.tools.logging :as log]
|
||||||
|
[mount.core :as mount])
|
||||||
|
(:gen-class))
|
||||||
|
|
||||||
|
;; log uncaught exceptions in threads
|
||||||
|
(Thread/setDefaultUncaughtExceptionHandler
|
||||||
|
(reify Thread$UncaughtExceptionHandler
|
||||||
|
(uncaughtException [_ thread ex]
|
||||||
|
(log/error {:what :uncaught-exception
|
||||||
|
:exception ex
|
||||||
|
:where (str "Uncaught exception on" (.getName thread))}))))
|
||||||
|
|
||||||
|
(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]
|
||||||
|
(start-app args))
|
35
src/clj/geocsv/handler.clj
Normal file
35
src/clj/geocsv/handler.clj
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
(ns geocsv.handler
|
||||||
|
(:require
|
||||||
|
[geocsv.middleware :as middleware]
|
||||||
|
[geocsv.layout :refer [error-page]]
|
||||||
|
[geocsv.routes.home :refer [home-routes]]
|
||||||
|
[reitit.ring :as ring]
|
||||||
|
[ring.middleware.content-type :refer [wrap-content-type]]
|
||||||
|
[ring.middleware.webjars :refer [wrap-webjars]]
|
||||||
|
[geocsv.env :refer [defaults]]
|
||||||
|
[mount.core :as mount]))
|
||||||
|
|
||||||
|
(mount/defstate init-app
|
||||||
|
:start ((or (:init defaults) (fn [])))
|
||||||
|
:stop ((or (:stop defaults) (fn []))))
|
||||||
|
|
||||||
|
(mount/defstate app-routes
|
||||||
|
:start
|
||||||
|
(ring/ring-handler
|
||||||
|
(ring/router
|
||||||
|
[(home-routes)])
|
||||||
|
(ring/routes
|
||||||
|
(ring/create-resource-handler
|
||||||
|
{:path "/"})
|
||||||
|
(wrap-content-type
|
||||||
|
(wrap-webjars (constantly nil)))
|
||||||
|
(ring/create-default-handler
|
||||||
|
{:not-found
|
||||||
|
(constantly (error-page {:status 404, :title "404 - Page not found"}))
|
||||||
|
:method-not-allowed
|
||||||
|
(constantly (error-page {:status 405, :title "405 - Not allowed"}))
|
||||||
|
:not-acceptable
|
||||||
|
(constantly (error-page {:status 406, :title "406 - Not acceptable"}))}))))
|
||||||
|
|
||||||
|
(defn app []
|
||||||
|
(middleware/wrap-base #'app-routes))
|
39
src/clj/geocsv/layout.clj
Normal file
39
src/clj/geocsv/layout.clj
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
(ns geocsv.layout
|
||||||
|
(:require
|
||||||
|
[clojure.java.io]
|
||||||
|
[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*]]
|
||||||
|
[ring.util.response]))
|
||||||
|
|
||||||
|
(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"
|
||||||
|
[request 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)})
|
49
src/clj/geocsv/middleware.clj
Normal file
49
src/clj/geocsv/middleware.clj
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
(ns geocsv.middleware
|
||||||
|
(:require
|
||||||
|
[geocsv.env :refer [defaults]]
|
||||||
|
[cheshire.generate :as cheshire]
|
||||||
|
[cognitect.transit :as transit]
|
||||||
|
[clojure.tools.logging :as log]
|
||||||
|
[geocsv.layout :refer [error-page]]
|
||||||
|
[ring.middleware.anti-forgery :refer [wrap-anti-forgery]]
|
||||||
|
[geocsv.middleware.formats :as formats]
|
||||||
|
[muuntaja.middleware :refer [wrap-format wrap-params]]
|
||||||
|
[geocsv.config :refer [env]]
|
||||||
|
[ring-ttl-session.core :refer [ttl-memory-store]]
|
||||||
|
[ring.middleware.defaults :refer [site-defaults wrap-defaults]])
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
(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 wrap-base [handler]
|
||||||
|
(-> ((:middleware defaults) handler)
|
||||||
|
(wrap-defaults
|
||||||
|
(-> site-defaults
|
||||||
|
(assoc-in [:security :anti-forgery] false)
|
||||||
|
(assoc-in [:session :store] (ttl-memory-store (* 60 30)))))
|
||||||
|
wrap-internal-error))
|
15
src/clj/geocsv/middleware/formats.clj
Normal file
15
src/clj/geocsv/middleware/formats.clj
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
(ns geocsv.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)))))
|
27
src/clj/geocsv/nrepl.clj
Normal file
27
src/clj/geocsv/nrepl.clj
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
(ns geocsv.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"))
|
20
src/clj/geocsv/routes/home.clj
Normal file
20
src/clj/geocsv/routes/home.clj
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
(ns geocsv.routes.home
|
||||||
|
(:require
|
||||||
|
[geocsv.layout :as layout]
|
||||||
|
[clojure.java.io :as io]
|
||||||
|
[geocsv.middleware :as middleware]
|
||||||
|
[ring.util.response]
|
||||||
|
[ring.util.http-response :as response]))
|
||||||
|
|
||||||
|
(defn home-page [request]
|
||||||
|
(layout/render request "home.html"))
|
||||||
|
|
||||||
|
(defn home-routes []
|
||||||
|
[""
|
||||||
|
{:middleware [middleware/wrap-csrf
|
||||||
|
middleware/wrap-formats]}
|
||||||
|
["/" {:get home-page}]
|
||||||
|
["/docs" {:get (fn [_]
|
||||||
|
(-> (response/ok (-> "docs/docs.md" io/resource slurp))
|
||||||
|
(response/header "Content-Type" "text/plain; charset=utf-8")))}]])
|
||||||
|
|
2
src/cljc/geocsv/validation.cljc
Normal file
2
src/cljc/geocsv/validation.cljc
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
(ns geocsv.validation
|
||||||
|
(:require [struct.core :as st]))
|
30
src/cljs/geocsv/ajax.cljs
Normal file
30
src/cljs/geocsv/ajax.cljs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
(ns geocsv.ajax
|
||||||
|
(:require
|
||||||
|
[ajax.core :as ajax]
|
||||||
|
[luminus-transit.time :as time]
|
||||||
|
[cognitect.transit :as transit]
|
||||||
|
[re-frame.core :as rf]))
|
||||||
|
|
||||||
|
(defn local-uri? [{:keys [uri]}]
|
||||||
|
(not (re-find #"^\w+?://" uri)))
|
||||||
|
|
||||||
|
(defn default-headers [request]
|
||||||
|
(if (local-uri? request)
|
||||||
|
(-> request
|
||||||
|
(update :headers #(merge {"x-csrf-token" js/csrfToken} %)))
|
||||||
|
request))
|
||||||
|
|
||||||
|
;; injects transit serialization config into request options
|
||||||
|
(defn as-transit [opts]
|
||||||
|
(merge {:raw false
|
||||||
|
:format :transit
|
||||||
|
:response-format :transit
|
||||||
|
:reader (transit/reader :json time/time-deserialization-handlers)
|
||||||
|
:writer (transit/writer :json time/time-serialization-handlers)}
|
||||||
|
opts))
|
||||||
|
|
||||||
|
(defn load-interceptors! []
|
||||||
|
(swap! ajax/default-interceptors
|
||||||
|
conj
|
||||||
|
(ajax/to-interceptor {:name "default headers"
|
||||||
|
:request default-headers})))
|
91
src/cljs/geocsv/core.cljs
Normal file
91
src/cljs/geocsv/core.cljs
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
(ns geocsv.core
|
||||||
|
(:require
|
||||||
|
[day8.re-frame.http-fx]
|
||||||
|
[reagent.core :as r]
|
||||||
|
[re-frame.core :as rf]
|
||||||
|
[geocsv.views.map :as mv]
|
||||||
|
[goog.events :as events]
|
||||||
|
[goog.history.EventType :as HistoryEventType]
|
||||||
|
[markdown.core :refer [md->html]]
|
||||||
|
[geocsv.ajax :as ajax]
|
||||||
|
[geocsv.events]
|
||||||
|
[reitit.core :as reitit]
|
||||||
|
[reitit.frontend.easy :as rfe]
|
||||||
|
[clojure.string :as string])
|
||||||
|
(:import goog.History))
|
||||||
|
|
||||||
|
(defn nav-link [uri title page]
|
||||||
|
[:a.navbar-item
|
||||||
|
{:href uri
|
||||||
|
:class (when (= page @(rf/subscribe [:page])) :is-active)}
|
||||||
|
title])
|
||||||
|
|
||||||
|
(defn navbar []
|
||||||
|
(r/with-let [expanded? (r/atom false)]
|
||||||
|
[:nav.navbar.is-info>div.container
|
||||||
|
[:div.navbar-brand
|
||||||
|
[:a.navbar-item {:href "/" :style {:font-weight :bold}} "geocsv"]
|
||||||
|
[:span.navbar-burger.burger
|
||||||
|
{:data-target :nav-menu
|
||||||
|
:on-click #(swap! expanded? not)
|
||||||
|
:class (when @expanded? :is-active)}
|
||||||
|
[:span][:span][:span]]]
|
||||||
|
[:div#nav-menu.navbar-menu
|
||||||
|
{:class (when @expanded? :is-active)}
|
||||||
|
[:div.navbar-start
|
||||||
|
[nav-link "#/" "Home" :home]
|
||||||
|
[nav-link "#/about" "About" :about]]]]))
|
||||||
|
|
||||||
|
(defn about-page []
|
||||||
|
[:section.section>div.container>div.content
|
||||||
|
[:img {:src "/img/warning_clojure.png"}]])
|
||||||
|
|
||||||
|
(defn home-page []
|
||||||
|
[:section.section>div.container>div.content
|
||||||
|
(when-let [docs @(rf/subscribe [:docs])]
|
||||||
|
[:div {:dangerouslySetInnerHTML {:__html (md->html docs)}}])])
|
||||||
|
|
||||||
|
(defn map-page []
|
||||||
|
"Return the content for the main map page. Map showing current location."
|
||||||
|
(mv/panel))
|
||||||
|
|
||||||
|
(def pages
|
||||||
|
{:home #'home-page
|
||||||
|
:about #'about-page})
|
||||||
|
|
||||||
|
(defn page []
|
||||||
|
(if-let [page @(rf/subscribe [:page])]
|
||||||
|
[:div
|
||||||
|
[navbar]
|
||||||
|
[page]]))
|
||||||
|
|
||||||
|
(defn navigate! [match _]
|
||||||
|
(rf/dispatch [:navigate match]))
|
||||||
|
|
||||||
|
(def router
|
||||||
|
(reitit/router
|
||||||
|
[["/" {:name :home
|
||||||
|
:view #'home-page
|
||||||
|
:controllers [{:start (fn [_] (rf/dispatch [:page/init-home]))}]}]
|
||||||
|
["/map" {:name :home
|
||||||
|
:view #'map-page
|
||||||
|
:controllers [{:start (fn [_] (rf/dispatch [:page/init-map]))}]}]
|
||||||
|
["/about" {:name :about
|
||||||
|
:view #'about-page}]]))
|
||||||
|
|
||||||
|
(defn start-router! []
|
||||||
|
(rfe/start!
|
||||||
|
router
|
||||||
|
navigate!
|
||||||
|
{}))
|
||||||
|
|
||||||
|
;; -------------------------
|
||||||
|
;; Initialize app
|
||||||
|
(defn mount-components []
|
||||||
|
(rf/clear-subscription-cache!)
|
||||||
|
(r/render [#'page] (.getElementById js/document "app")))
|
||||||
|
|
||||||
|
(defn init! []
|
||||||
|
(start-router!)
|
||||||
|
(ajax/load-interceptors!)
|
||||||
|
(mount-components))
|
125
src/cljs/geocsv/events.cljs
Normal file
125
src/cljs/geocsv/events.cljs
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
(ns geocsv.events
|
||||||
|
(:require
|
||||||
|
[re-frame.core :as rf]
|
||||||
|
[ajax.core :as ajax]
|
||||||
|
[reitit.frontend.easy :as rfe]
|
||||||
|
[reitit.frontend.controllers :as rfc]))
|
||||||
|
|
||||||
|
;;dispatchers
|
||||||
|
|
||||||
|
(rf/reg-event-db
|
||||||
|
:navigate
|
||||||
|
(fn [db [_ match]]
|
||||||
|
(let [old-match (:common/route db)
|
||||||
|
new-match (assoc match :controllers
|
||||||
|
(rfc/apply-controllers (:controllers old-match) match))]
|
||||||
|
(assoc db :route new-match))))
|
||||||
|
|
||||||
|
(rf/reg-fx
|
||||||
|
:navigate-fx!
|
||||||
|
(fn [[k & [params query]]]
|
||||||
|
(rfe/push-state k params query)))
|
||||||
|
|
||||||
|
(rf/reg-event-fx
|
||||||
|
:navigate!
|
||||||
|
(fn [_ [_ url-key params query]]
|
||||||
|
{:navigate-fx! [url-key params query]}))
|
||||||
|
|
||||||
|
(rf/reg-event-db
|
||||||
|
:set-docs
|
||||||
|
(fn [db [_ docs]]
|
||||||
|
(assoc db :docs docs)))
|
||||||
|
|
||||||
|
(rf/reg-event-fx
|
||||||
|
:fetch-docs
|
||||||
|
(fn [_ _]
|
||||||
|
{:http-xhrio {:method :get
|
||||||
|
:uri "/docs"
|
||||||
|
:response-format (ajax/raw-response-format)
|
||||||
|
:on-success [:set-docs]}}))
|
||||||
|
|
||||||
|
(rf/reg-event-db
|
||||||
|
:common/set-error
|
||||||
|
(fn [db [_ error]]
|
||||||
|
(assoc db :common/error error)))
|
||||||
|
|
||||||
|
(reg-event-db
|
||||||
|
:set-view
|
||||||
|
(fn [db [_ view]]
|
||||||
|
(assoc db :view view)))
|
||||||
|
|
||||||
|
(rf/reg-event-fx
|
||||||
|
:page/init-home
|
||||||
|
(fn [_ _]
|
||||||
|
{:dispatch [:fetch-docs]}))
|
||||||
|
|
||||||
|
(rf/reg-event-fx
|
||||||
|
:page/init-maps
|
||||||
|
(fn [_ _]
|
||||||
|
{:dispatch [:fetch-data]}))
|
||||||
|
|
||||||
|
|
||||||
|
(re-frame/reg-event-fx
|
||||||
|
:fetch-data
|
||||||
|
(fn [{db :db} _]
|
||||||
|
(let [uri (assoc source-host
|
||||||
|
:path "/data/data.json")]
|
||||||
|
(js/console.log
|
||||||
|
(str
|
||||||
|
"Fetching data: " uri))
|
||||||
|
;; we return a map of (side) effects
|
||||||
|
{:http-xhrio {:method :get
|
||||||
|
:uri uri
|
||||||
|
:format (json-request-format)
|
||||||
|
:response-format (json-response-format {:keywords? true})
|
||||||
|
:on-success [:process-data]
|
||||||
|
:on-failure [:bad-data]}
|
||||||
|
:db db})))
|
||||||
|
|
||||||
|
(re-frame/reg-event-fx
|
||||||
|
:process-data
|
||||||
|
;; TODO: why is this an `-fx`? Does it need to be?
|
||||||
|
(fn
|
||||||
|
[{db :db} [_ response]]
|
||||||
|
(let [data (js->clj response)]
|
||||||
|
(js/console.log (str ":process-data: " response))
|
||||||
|
{:db (refresh-map-pins (assoc db :data data))})))
|
||||||
|
|
||||||
|
(re-frame/reg-event-fx
|
||||||
|
:bad-data
|
||||||
|
;; TODO: why is this an `-fx`? Does it need to be?
|
||||||
|
(fn
|
||||||
|
[{db :db} [_ response]]
|
||||||
|
;; TODO: signal something has failed? It doesn't matter very much, unless it keeps failing.
|
||||||
|
(js/console.log (str "Failed to fetch data data" response))
|
||||||
|
db))
|
||||||
|
|
||||||
|
|
||||||
|
;;subscriptions
|
||||||
|
|
||||||
|
(rf/reg-sub
|
||||||
|
:route
|
||||||
|
(fn [db _]
|
||||||
|
(-> db :route)))
|
||||||
|
|
||||||
|
(rf/reg-sub
|
||||||
|
:page-id
|
||||||
|
:<- [:route]
|
||||||
|
(fn [route _]
|
||||||
|
(-> route :data :name)))
|
||||||
|
|
||||||
|
(rf/reg-sub
|
||||||
|
:page
|
||||||
|
:<- [:route]
|
||||||
|
(fn [route _]
|
||||||
|
(-> route :data :view)))
|
||||||
|
|
||||||
|
(rf/reg-sub
|
||||||
|
:docs
|
||||||
|
(fn [db _]
|
||||||
|
(:docs db)))
|
||||||
|
|
||||||
|
(rf/reg-sub
|
||||||
|
:common/error
|
||||||
|
(fn [db _]
|
||||||
|
(:common/error db)))
|
134
src/cljs/geocsv/gis.cljs
Normal file
134
src/cljs/geocsv/gis.cljs
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
(ns ^{:doc "geocsv app map stuff."
|
||||||
|
:author "Simon Brooke"}
|
||||||
|
geocsv.gis
|
||||||
|
(:require [cljs.reader :refer [read-string]]
|
||||||
|
[clojure.string :refer [capitalize lower-case]]
|
||||||
|
[cemerick.url :refer (url url-encode)]
|
||||||
|
[day8.re-frame.http-fx]
|
||||||
|
[re-frame.core :refer [dispatch reg-event-db reg-event-fx subscribe]]
|
||||||
|
[ajax.core :refer [GET]]
|
||||||
|
[ajax.json :refer [json-request-format json-response-format]]
|
||||||
|
[youyesyet.locality :refer [locality]]
|
||||||
|
))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;;
|
||||||
|
;;;; geocsv.gis: stuff to do with maps.
|
||||||
|
;;;;
|
||||||
|
;;;; This program is free software; you can redistribute it and/or
|
||||||
|
;;;; modify it under the terms of the GNU General Public License
|
||||||
|
;;;; as published by the Free Software Foundation; either version 2
|
||||||
|
;;;; of the License, or (at your option) any later version.
|
||||||
|
;;;;
|
||||||
|
;;;; This program is distributed in the hope that it will be useful,
|
||||||
|
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
;;;; GNU General Public License for more details.
|
||||||
|
;;;;
|
||||||
|
;;;; You should have received a copy of the GNU General Public License
|
||||||
|
;;;; along with this program; if not, write to the Free Software
|
||||||
|
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
;;;; USA.
|
||||||
|
;;;;
|
||||||
|
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||||
|
;;;;
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
;; map stuff.
|
||||||
|
|
||||||
|
(defn get-current-location []
|
||||||
|
"Return the current location from the device, setting it in the database and
|
||||||
|
returning the locality."
|
||||||
|
(try
|
||||||
|
(if (.-geolocation js/navigator)
|
||||||
|
(.getCurrentPosition
|
||||||
|
(.-geolocation js/navigator)
|
||||||
|
(fn [position]
|
||||||
|
(let [view @(subscribe [:view])
|
||||||
|
lat (.-latitude (.-coords position))
|
||||||
|
lng (.-longitude (.-coords position))]
|
||||||
|
(js/console.log (str "Current location is: " lat ", " lng))
|
||||||
|
(if
|
||||||
|
(and view (float? lat) (float? lng))
|
||||||
|
(do
|
||||||
|
(dispatch [:set-latitude lat])
|
||||||
|
(dispatch [:set-longitude lng])
|
||||||
|
(.panTo view (.latLng js/L lat lng))
|
||||||
|
(locality lat lng))
|
||||||
|
(do
|
||||||
|
(js/console.log
|
||||||
|
(if view
|
||||||
|
(str "Geolocation failed lat: '" lat "'; lng '" lng "'")
|
||||||
|
"No value for subscription to [:view]"))
|
||||||
|
0)))))
|
||||||
|
(do
|
||||||
|
(js/console.log "Geolocation not available")
|
||||||
|
0))
|
||||||
|
(catch js/Object any
|
||||||
|
(js/console.log "Exception while trying to access location: " + any)
|
||||||
|
0)))
|
||||||
|
|
||||||
|
(defn map-pin-click-handler
|
||||||
|
[id]
|
||||||
|
(js/console.log (str "Click handler for record #" id)))
|
||||||
|
|
||||||
|
(defn pin-image
|
||||||
|
"Return the name of a suitable pin image for this `record`."
|
||||||
|
[record]
|
||||||
|
(if
|
||||||
|
(:category record)
|
||||||
|
(str
|
||||||
|
(s/capitalize
|
||||||
|
(s/replace (s/lower-case (str (:category record))) #"[^a-z0-9]" "-")) "-pin")
|
||||||
|
"unknown-pin"))
|
||||||
|
|
||||||
|
(defn add-map-pin
|
||||||
|
"Add an appropriate map-pin for this `record` in this map `view`."
|
||||||
|
[record index view]
|
||||||
|
(let [lat (:latitude record)
|
||||||
|
lng (:longitude record)
|
||||||
|
pin (.icon js/L
|
||||||
|
(clj->js
|
||||||
|
{:iconAnchor [16 41]
|
||||||
|
:iconSize [32 42]
|
||||||
|
:iconUrl (str "img/map-pins/" (pin-image record) ".png")
|
||||||
|
:riseOnHover true
|
||||||
|
:shadowAnchor [16 23]
|
||||||
|
:shadowSize [57 24]
|
||||||
|
:shadowUrl "img/map-pins/shadow_pin.png"}))
|
||||||
|
marker (.marker js/L
|
||||||
|
(.latLng js/L lat lng)
|
||||||
|
(clj->js {:icon pin
|
||||||
|
:title (:name record)}))]
|
||||||
|
(.on
|
||||||
|
(.addTo marker view)
|
||||||
|
"click"
|
||||||
|
(fn [_] (map-pin-click-handler index)))
|
||||||
|
marker))
|
||||||
|
|
||||||
|
(defn map-remove-pins
|
||||||
|
"Remove all pins from this map `view`. Side-effecty; liable to be
|
||||||
|
problematic."
|
||||||
|
[view]
|
||||||
|
(if view
|
||||||
|
(.eachLayer view
|
||||||
|
#(if
|
||||||
|
(instance? js/L.Marker %)
|
||||||
|
(.removeLayer view %)))
|
||||||
|
view))
|
||||||
|
|
||||||
|
|
||||||
|
(defn refresh-map-pins
|
||||||
|
"Refresh the map pins on the current map. Side-effecty; liable to be
|
||||||
|
problematic."
|
||||||
|
[db]
|
||||||
|
(let [view (map-remove-pins @(re-frame/subscribe [:view]))
|
||||||
|
data (:data db)]
|
||||||
|
(if
|
||||||
|
view
|
||||||
|
(do
|
||||||
|
(js/console.log (str "Adding " (count data) " pins"))
|
||||||
|
(doall (map #(add-map-pin %1 %2 view) data (range))))
|
||||||
|
(js/console.log "View is not yet ready"))
|
||||||
|
db))
|
||||||
|
|
102
src/cljs/geocsv/views/map.cljs
Normal file
102
src/cljs/geocsv/views/map.cljs
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
(ns ^{:doc "a map onto which to project CSV data."
|
||||||
|
:author "Simon Brooke"}
|
||||||
|
geocsv.views.map
|
||||||
|
(:require [cljsjs.leaflet]
|
||||||
|
[re-frame.core :refer [reg-sub subscribe dispatch dispatch-sync]]
|
||||||
|
[reagent.core :as reagent]
|
||||||
|
[recalcitrant.core :refer [error-boundary]]
|
||||||
|
[geocsv.gis :refer [refresh-map-pins get-current-location]]))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;;
|
||||||
|
;;;; geocsv.map: a map onto which to project CSV data.
|
||||||
|
;;;;
|
||||||
|
;;;; This program is free software; you can redistribute it and/or
|
||||||
|
;;;; modify it under the terms of the GNU General Public License
|
||||||
|
;;;; as published by the Free Software Foundation; either version 2
|
||||||
|
;;;; of the License, or (at your option) any later version.
|
||||||
|
;;;;
|
||||||
|
;;;; This program is distributed in the hope that it will be useful,
|
||||||
|
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
;;;; GNU General Public License for more details.
|
||||||
|
;;;;
|
||||||
|
;;;; You should have received a copy of the GNU General Public License
|
||||||
|
;;;; along with this program; if not, write to the Free Software
|
||||||
|
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
;;;; USA.
|
||||||
|
;;;;
|
||||||
|
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||||
|
;;;;
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
;;; Cribbed heavily from
|
||||||
|
;;; https://github.com/reagent-project/reagent-cookbook/tree/master/recipes/leaflet
|
||||||
|
;;; but using OSM data because we can't afford commercial, so also cribbed from
|
||||||
|
;;; https://switch2osm.org/using-tiles/getting-started-with-leaflet/
|
||||||
|
;;; Note that this is raw reagent stylee; it should be refactoed into re-frame stylee
|
||||||
|
;;; when I understand it better.
|
||||||
|
|
||||||
|
;; which provider to use
|
||||||
|
(def ^:dynamic *map-provider* :osm)
|
||||||
|
|
||||||
|
(def osm-url "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png")
|
||||||
|
(def osm-attrib "Map data © <a href='http://openstreetmap.org'>OpenStreetMap</a> contributors")
|
||||||
|
|
||||||
|
;; My gods mapbox is user-hostile!
|
||||||
|
(defn map-did-mount-mapbox
|
||||||
|
"Did-mount function loading map tile data from MapBox (proprietary)."
|
||||||
|
[]
|
||||||
|
(get-current-location)
|
||||||
|
(let [view (.setView
|
||||||
|
(.map js/L "map" (clj->js {:zoomControl "false"})))]
|
||||||
|
;; NEED TO REPLACE FIXME with your mapID!
|
||||||
|
(.addTo (.tileLayer js/L "http://{s}.tiles.mapbox.com/v3/FIXME/{z}/{x}/{y}.png"
|
||||||
|
(clj->js {:attribution "Map data © [...]"
|
||||||
|
:maxZoom 18})))
|
||||||
|
view))
|
||||||
|
|
||||||
|
(defn map-did-mount-osm
|
||||||
|
"Did-mount function loading map tile data from Open Street Map."
|
||||||
|
[]
|
||||||
|
(get-current-location) ;; - [Violation] Only request geolocation information in response to a user gesture.
|
||||||
|
(let [view (.setView
|
||||||
|
(.map js/L
|
||||||
|
"map"
|
||||||
|
(clj->js {:zoomControl false}))
|
||||||
|
#js [@(subscribe [:latitude]) @(subscribe [:longitude])]
|
||||||
|
@(subscribe [:zoom]))]
|
||||||
|
(.addTo (.tileLayer js/L osm-url
|
||||||
|
(clj->js {:attribution osm-attrib
|
||||||
|
:maxZoom 18}))
|
||||||
|
view)
|
||||||
|
(dispatch-sync [:set-view view])
|
||||||
|
(.on view "moveend"
|
||||||
|
(fn [_] (let [c (.getCenter view)]
|
||||||
|
(js/console.log (str "Moving centre to " c))
|
||||||
|
(dispatch-sync [:set-latitude (.-lat c)])
|
||||||
|
(dispatch-sync [:set-longitude (.-lng c)])
|
||||||
|
(dispatch [:fetch-locality]))))
|
||||||
|
(refresh-map-pins)
|
||||||
|
view))
|
||||||
|
|
||||||
|
(defn map-did-mount
|
||||||
|
"Select the actual map provider to use."
|
||||||
|
[]
|
||||||
|
(dispatch-sync [:set-view (case *map-provider*
|
||||||
|
:mapbox (map-did-mount-mapbox)
|
||||||
|
:osm (map-did-mount-osm)
|
||||||
|
;; potentially others
|
||||||
|
)]))
|
||||||
|
|
||||||
|
(defn map-render
|
||||||
|
"Render the actual div containing the map."
|
||||||
|
[]
|
||||||
|
[:div#map {:style {:height "500px"}}])
|
||||||
|
|
||||||
|
(defn panel
|
||||||
|
"A reagent class for the map object."
|
||||||
|
[]
|
||||||
|
;; (get-current-location)
|
||||||
|
(reagent/create-class {:reagent-render map-render
|
||||||
|
:component-did-mount map-did-mount}))
|
27
test/clj/geocsv/test/handler.clj
Normal file
27
test/clj/geocsv/test/handler.clj
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
(ns geocsv.test.handler
|
||||||
|
(:require
|
||||||
|
[clojure.test :refer :all]
|
||||||
|
[ring.mock.request :refer :all]
|
||||||
|
[geocsv.handler :refer :all]
|
||||||
|
[geocsv.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 #'geocsv.config/env
|
||||||
|
#'geocsv.handler/app-routes)
|
||||||
|
(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))))))
|
9
test/cljs/geocsv/core_test.cljs
Normal file
9
test/cljs/geocsv/core_test.cljs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
(ns geocsv.core-test
|
||||||
|
(:require [cljs.test :refer-macros [is are deftest testing use-fixtures]]
|
||||||
|
[pjstadig.humane-test-output]
|
||||||
|
[reagent.core :as reagent :refer [atom]]
|
||||||
|
[geocsv.core :as rc]))
|
||||||
|
|
||||||
|
(deftest test-home
|
||||||
|
(is (= true true)))
|
||||||
|
|
6
test/cljs/geocsv/doo_runner.cljs
Normal file
6
test/cljs/geocsv/doo_runner.cljs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
(ns geocsv.doo-runner
|
||||||
|
(:require [doo.runner :refer-macros [doo-tests]]
|
||||||
|
[geocsv.core-test]))
|
||||||
|
|
||||||
|
(doo-tests 'geocsv.core-test)
|
||||||
|
|
Loading…
Reference in a new issue