From c3cb7b0df82479016c252ef45a302f566bd569f6 Mon Sep 17 00:00:00 2001 From: Griffin Smith Date: Mon, 13 Dec 2021 21:28:25 -0500 Subject: feat(grfn/bbbg): Init This will eventually become a signup sheet + no-show tracker for my local board game meetup group Change-Id: Id8d1d80d95d1e2fda5041275cff2fecfd6fa43f1 --- users/grfn/bbbg/.clj-kondo/config.edn | 1 + users/grfn/bbbg/.envrc | 1 + users/grfn/bbbg/.gitignore | 9 + users/grfn/bbbg/Makefile | 2 + users/grfn/bbbg/arion-compose.nix | 15 + users/grfn/bbbg/arion-pkgs.nix | 2 + users/grfn/bbbg/default.nix | 78 ++ users/grfn/bbbg/deps.edn | 63 + users/grfn/bbbg/deps.nix | 1255 ++++++++++++++++++++ users/grfn/bbbg/env/dev/bbbg-signup/env.clj | 3 + users/grfn/bbbg/env/dev/logback.xml | 15 + users/grfn/bbbg/env/prod/bbbg-signup/env.clj | 3 + users/grfn/bbbg/env/prod/logback.xml | 31 + users/grfn/bbbg/env/test/bbbg-signup/env.clj | 3 + users/grfn/bbbg/env/test/logback.xml | 11 + users/grfn/bbbg/pom.xml | 42 + users/grfn/bbbg/resources/main.js | 49 + .../migrations/20211212165646-init-schema.down.sql | 14 + .../migrations/20211212165646-init-schema.up.sql | 31 + users/grfn/bbbg/shell.nix | 20 + users/grfn/bbbg/src/bbbg/attendee.clj | 4 + users/grfn/bbbg/src/bbbg/core.clj | 58 + users/grfn/bbbg/src/bbbg/db.clj | 357 ++++++ users/grfn/bbbg/src/bbbg/db/attendee.clj | 29 + users/grfn/bbbg/src/bbbg/db/event.clj | 50 + users/grfn/bbbg/src/bbbg/event.clj | 4 + users/grfn/bbbg/src/bbbg/event_attendee.clj | 4 + users/grfn/bbbg/src/bbbg/handlers/attendees.clj | 40 + users/grfn/bbbg/src/bbbg/handlers/core.clj | 34 + users/grfn/bbbg/src/bbbg/handlers/events.clj | 44 + users/grfn/bbbg/src/bbbg/handlers/home.clj | 17 + users/grfn/bbbg/src/bbbg/handlers/signup_form.clj | 57 + users/grfn/bbbg/src/bbbg/styles.clj | 9 + users/grfn/bbbg/src/bbbg/util/core.clj | 117 ++ users/grfn/bbbg/src/bbbg/web.clj | 77 ++ 35 files changed, 2549 insertions(+) create mode 100644 users/grfn/bbbg/.clj-kondo/config.edn create mode 100644 users/grfn/bbbg/.envrc create mode 100644 users/grfn/bbbg/.gitignore create mode 100644 users/grfn/bbbg/Makefile create mode 100644 users/grfn/bbbg/arion-compose.nix create mode 100644 users/grfn/bbbg/arion-pkgs.nix create mode 100644 users/grfn/bbbg/default.nix create mode 100644 users/grfn/bbbg/deps.edn create mode 100644 users/grfn/bbbg/deps.nix create mode 100644 users/grfn/bbbg/env/dev/bbbg-signup/env.clj create mode 100644 users/grfn/bbbg/env/dev/logback.xml create mode 100644 users/grfn/bbbg/env/prod/bbbg-signup/env.clj create mode 100644 users/grfn/bbbg/env/prod/logback.xml create mode 100644 users/grfn/bbbg/env/test/bbbg-signup/env.clj create mode 100644 users/grfn/bbbg/env/test/logback.xml create mode 100644 users/grfn/bbbg/pom.xml create mode 100644 users/grfn/bbbg/resources/main.js create mode 100644 users/grfn/bbbg/resources/migrations/20211212165646-init-schema.down.sql create mode 100644 users/grfn/bbbg/resources/migrations/20211212165646-init-schema.up.sql create mode 100644 users/grfn/bbbg/shell.nix create mode 100644 users/grfn/bbbg/src/bbbg/attendee.clj create mode 100644 users/grfn/bbbg/src/bbbg/core.clj create mode 100644 users/grfn/bbbg/src/bbbg/db.clj create mode 100644 users/grfn/bbbg/src/bbbg/db/attendee.clj create mode 100644 users/grfn/bbbg/src/bbbg/db/event.clj create mode 100644 users/grfn/bbbg/src/bbbg/event.clj create mode 100644 users/grfn/bbbg/src/bbbg/event_attendee.clj create mode 100644 users/grfn/bbbg/src/bbbg/handlers/attendees.clj create mode 100644 users/grfn/bbbg/src/bbbg/handlers/core.clj create mode 100644 users/grfn/bbbg/src/bbbg/handlers/events.clj create mode 100644 users/grfn/bbbg/src/bbbg/handlers/home.clj create mode 100644 users/grfn/bbbg/src/bbbg/handlers/signup_form.clj create mode 100644 users/grfn/bbbg/src/bbbg/styles.clj create mode 100644 users/grfn/bbbg/src/bbbg/util/core.clj create mode 100644 users/grfn/bbbg/src/bbbg/web.clj (limited to 'users/grfn') diff --git a/users/grfn/bbbg/.clj-kondo/config.edn b/users/grfn/bbbg/.clj-kondo/config.edn new file mode 100644 index 000000000000..8faddb77ecc4 --- /dev/null +++ b/users/grfn/bbbg/.clj-kondo/config.edn @@ -0,0 +1 @@ +{:lint-as {garden.def/defstyles clojure.core/def}} diff --git a/users/grfn/bbbg/.envrc b/users/grfn/bbbg/.envrc new file mode 100644 index 000000000000..051d09d292a8 --- /dev/null +++ b/users/grfn/bbbg/.envrc @@ -0,0 +1 @@ +eval "$(lorri direnv)" diff --git a/users/grfn/bbbg/.gitignore b/users/grfn/bbbg/.gitignore new file mode 100644 index 000000000000..99dbfc443636 --- /dev/null +++ b/users/grfn/bbbg/.gitignore @@ -0,0 +1,9 @@ +/target +/classes +*.jar +*.class +/.nrepl-port +/.cpcache +/.clojure +/result +/.clj-kondo/.cache diff --git a/users/grfn/bbbg/Makefile b/users/grfn/bbbg/Makefile new file mode 100644 index 000000000000..fc45477984e3 --- /dev/null +++ b/users/grfn/bbbg/Makefile @@ -0,0 +1,2 @@ +deps.nix: deps.edn + clj2nix ./deps.edn ./deps.nix '-A:uberjar' '-A:clj-test' diff --git a/users/grfn/bbbg/arion-compose.nix b/users/grfn/bbbg/arion-compose.nix new file mode 100644 index 000000000000..c8a6dd156d2c --- /dev/null +++ b/users/grfn/bbbg/arion-compose.nix @@ -0,0 +1,15 @@ +{ ... }: + +{ + services = { + postgres.service = { + image = "postgres:12"; + environment = { + POSTGRES_DB = "bbbg"; + POSTGRES_USER = "bbbg"; + POSTGRES_PASSWORD = "password"; + }; + ports = [ "5432:5432" ]; + }; + }; +} diff --git a/users/grfn/bbbg/arion-pkgs.nix b/users/grfn/bbbg/arion-pkgs.nix new file mode 100644 index 000000000000..66c016c28368 --- /dev/null +++ b/users/grfn/bbbg/arion-pkgs.nix @@ -0,0 +1,2 @@ +let depot = import ../../.. {}; +in depot.third_party.nixpkgs diff --git a/users/grfn/bbbg/default.nix b/users/grfn/bbbg/default.nix new file mode 100644 index 000000000000..90f112bf2866 --- /dev/null +++ b/users/grfn/bbbg/default.nix @@ -0,0 +1,78 @@ +{ depot, pkgs, ... }: + +with pkgs.lib; + +let + inherit (depot.third_party) gitignoreSource; + + deps = import ./deps.nix { + inherit (pkgs) fetchMavenArtifact fetchgit lib; + }; +in rec { + meta.targets = [ + "db-util" + "server" + ]; + + depsPaths = deps.makePaths {}; + + resources = builtins.filterSource (_: type: type != "symlink") ./resources; + + classpath.dev = concatStringsSep ":" ( + (map gitignoreSource [./src ./test ./env/dev]) ++ [resources] ++ depsPaths + ); + + classpath.test = concatStringsSep ":" ( + (map gitignoreSource [./src ./test ./env/test]) ++ [resources] ++ depsPaths + ); + + classpath.prod = concatStringsSep ":" ( + (map gitignoreSource [./src ./env/prod]) ++ [resources] ++ depsPaths + ); + + testClojure = pkgs.writeShellScript "test-clojure" '' + export HOME=$(pwd) + ${pkgs.clojure}/bin/clojure -Scp ${depsPaths} + ''; + + mkJar = name: opts: + with pkgs; + assert (hasSuffix ".jar" name); + stdenv.mkDerivation rec { + inherit name; + dontUnpack = true; + buildPhase = '' + export HOME=$(pwd) + cp ${./pom.xml} pom.xml + cp ${./deps.edn} deps.edn + ${clojure}/bin/clojure \ + -Scp ${classpath.prod} \ + -A:uberjar \ + ${name} \ + -C ${opts} + ''; + + doCheck = true; + + checkPhase = '' + echo "checking for existence of ${name}" + [ -f ${name} ] + ''; + + installPhase = '' + cp ${name} $out + ''; + }; + + db-util-jar = mkJar "bbbg-db-util.jar" "-m bbbg.db"; + + db-util = pkgs.writeShellScriptBin "bbbg-db-util" '' + exec ${pkgs.openjdk17_headless}/bin/java -jar ${db-util-jar} "$@" + ''; + + server-jar = mkJar "bbbg-server.jar" "-m bbbg.core"; + + server = pkgs.writeShellScriptBin "bbbg-server" '' + exec ${pkgs.openjdk17_headless}/bin/java -jar ${server-jar} "$@" + ''; +} diff --git a/users/grfn/bbbg/deps.edn b/users/grfn/bbbg/deps.edn new file mode 100644 index 000000000000..1028771457cb --- /dev/null +++ b/users/grfn/bbbg/deps.edn @@ -0,0 +1,63 @@ +{:deps + {org.clojure/clojure {:mvn/version "1.11.0-alpha3"} + + ;; DB + com.github.seancorfield/next.jdbc {:mvn/version "1.2.753"} + com.impossibl.pgjdbc-ng/pgjdbc-ng {:mvn/version "0.8.4"} + com.zaxxer/HikariCP {:mvn/version "5.0.0"} + migratus/migratus {:mvn/version "1.3.5"} + com.github.seancorfield/honeysql {:mvn/version "2.1.833"} + nilenso/honeysql-postgres {:mvn/version "0.4.112"} + + ;; HTTP + http-kit/http-kit {:mvn/version "2.5.3"} + ring/ring {:mvn/version "1.9.4"} + compojure/compojure {:mvn/version "1.6.2"} + javax.servlet/servlet-api {:mvn/version "2.5"} + + ;; Web + hiccup/hiccup {:mvn/version "1.0.5"} + garden/garden {:mvn/version "1.3.10"} + + ;; Utils + com.stuartsierra/component {:mvn/version "1.0.0"} + + ;; Logging + Observability + ch.qos.logback/logback-classic {:mvn/version "1.2.3" + :exclusions [org.slf4j/slf4j-api]} + org.slf4j/jul-to-slf4j {:mvn/version "1.7.30"} + org.slf4j/jcl-over-slf4j {:mvn/version "1.7.30"} + org.slf4j/log4j-over-slf4j {:mvn/version "1.7.30"} + cambium/cambium.core {:mvn/version "0.9.3"} + cambium/cambium.codec-cheshire {:mvn/version "0.9.3"} + cambium/cambium.logback.core {:mvn/version "0.4.3"} + cambium/cambium.logback.json {:mvn/version "0.4.3"} + clj-commons/iapetos {:mvn/version "0.1.12"} + + ;; Utilities + yogthos/config {:mvn/version "1.1.8"} + clojure.java-time/clojure.java-time {:mvn/version "0.3.3"} + cheshire/cheshire {:mvn/version "5.10.1"} + + ;; Spec + org.clojure/spec.alpha {:mvn/version "0.3.214"} + org.clojure/core.specs.alpha {:mvn/version "0.2.62"} + expound/expound {:mvn/version "0.8.10"}} + + :paths + ["src" + "test" + "resources" + "target/classes"] + :aliases + {:dev {:extra-paths ["env/dev"] + :jvm-opts ["-XX:-OmitStackTraceInFastThrow"]} + :clj-test {:extra-paths ["test" "env/test"] + :extra-deps {io.github.cognitect-labs/test-runner + {:git/url "https://github.com/cognitect-labs/test-runner" + :sha "cc75980b43011773162b485f46f939dc5fba91e4"}} + :main-opts ["-m" "cognitect.test-runner" + "-d" "test"]} + :uberjar {:extra-deps {seancorfield/depstar {:mvn/version "1.0.94"}} + :extra-paths ["env/prod"] + :main-opts ["-m" "hf.depstar.uberjar"]}}} diff --git a/users/grfn/bbbg/deps.nix b/users/grfn/bbbg/deps.nix new file mode 100644 index 000000000000..e1c17f5609b2 --- /dev/null +++ b/users/grfn/bbbg/deps.nix @@ -0,0 +1,1255 @@ +# generated by clj2nix-1.1.0-rc +{ fetchMavenArtifact, fetchgit, lib }: + +let repos = [ + "https://repo1.maven.org/maven2/" + "https://repo.clojars.org/" ]; + + in rec { + makePaths = {extraClasspaths ? []}: + if (builtins.typeOf extraClasspaths != "list") + then builtins.throw "extraClasspaths must be of type 'list'!" + else (lib.concatMap (dep: + builtins.map (path: + if builtins.isString path then + path + else if builtins.hasAttr "jar" path then + path.jar + else if builtins.hasAttr "outPath" path then + path.outPath + else + path + ) + dep.paths) + packages) ++ extraClasspaths; + makeClasspaths = {extraClasspaths ? []}: + if (builtins.typeOf extraClasspaths != "list") + then builtins.throw "extraClasspaths must be of type 'list'!" + else builtins.concatStringsSep ":" (makePaths {inherit extraClasspaths;}); + packageSources = builtins.map (dep: dep.src) packages; + packages = [ + rec { + name = "cambium.logback.json/cambium"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "cambium.logback.json"; + groupId = "cambium"; + sha512 = "a19e990652749f02a258da3ca30fee126e324a2c6969667fcdbfd7e0b313997d729efb83ccf54a500e7af7476b4bbe0e511b37540fb6f7bc9f117d2db8c4fe99"; + version = "0.4.3"; + + }; + paths = [ src ]; + } + + rec { + name = "clojure/org.clojure"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "clojure"; + groupId = "org.clojure"; + sha512 = "a242514f623a17601b360886563c4a4fe09335e4e16522ac42bbcacda073ae77651cfed446daae7fe74061bb7dff5adc454769c0edc0ded350136c3c707e75b9"; + version = "1.11.0-alpha3"; + + }; + paths = [ src ]; + } + + rec { + name = "commons-codec/commons-codec"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "commons-codec"; + groupId = "commons-codec"; + sha512 = "da30a716770795fce390e4dd340a8b728f220c6572383ffef55bd5839655d5611fcc06128b2144f6cdcb36f53072a12ec80b04afee787665e7ad0b6e888a6787"; + version = "1.15"; + + }; + paths = [ src ]; + } + + rec { + name = "HikariCP/com.zaxxer"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "HikariCP"; + groupId = "com.zaxxer"; + sha512 = "a41b6d8b1c4656e633459824f10320965976eeead01bd5cb24911040073181730e61feb797aef89d9e01c922e89cb58654f364df0a6b1bf62ab3e6f9cc367d77"; + version = "5.0.0"; + + }; + paths = [ src ]; + } + + rec { + name = "ring-devel/ring"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "ring-devel"; + groupId = "ring"; + sha512 = "79a1ec9f9d03aa4fa0426353970b13468ee65ce314b51ab7a2682212a196a9b5c985eacdee5dbc6ff2f1b536a4e06d0e85e9dd7cc9a49958735c9c4e6d427fd5"; + version = "1.9.4"; + + }; + paths = [ src ]; + } + + rec { + name = "simpleclient/io.prometheus"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "simpleclient"; + groupId = "io.prometheus"; + sha512 = "60af1cefff04e7036467eae54f5930d5677e4ab066f8ed38a391b54df17733acfefac45e19ee53cef289347bddce5fc69a2766f4e580d21a22cfd9e2348e2723"; + version = "0.12.0"; + + }; + paths = [ src ]; + } + + rec { + name = "tools.logging/org.clojure"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "tools.logging"; + groupId = "org.clojure"; + sha512 = "d846b3032f5350af7e8847e94dea223ef8a644d353e45d6ec44c2ffa1f0df96b90cfe7afc0610cd0a13b52527ff2fe71003fbd5cbc2dd60320a1be5979b62e80"; + version = "1.1.0"; + + }; + paths = [ src ]; + } + + rec { + name = "core.specs.alpha/org.clojure"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "core.specs.alpha"; + groupId = "org.clojure"; + sha512 = "f521f95b362a47bb35f7c85528c34537f905fb3dd24f2284201e445635a0df701b35d8419d53c6507cc78d3717c1f83cda35ea4c82abd8943cd2ab3de3fcad70"; + version = "0.2.62"; + + }; + paths = [ src ]; + } + + rec { + name = "netty-common/io.netty"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "netty-common"; + groupId = "io.netty"; + sha512 = "1c0baeff9f2cc687612aca4d4e4ca671eae99ac34bd91f22b1c550e5cc6ab98984bef059923248004ad92013a79503a59a89a1779ae2499116bc35f6ef7db634"; + version = "4.1.42.Final"; + + }; + paths = [ src ]; + } + + rec { + name = "jackson-databind/com.fasterxml.jackson.core"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "jackson-databind"; + groupId = "com.fasterxml.jackson.core"; + sha512 = "9f771e78af669b1e1683d6c5903bbf4790aaa88b6b420c2018437da318c3fa4220cd7fa726f3e42a1b8075def1fdbd3744937c15f3bcedfca3050199247363e8"; + version = "2.12.4"; + + }; + paths = [ src ]; + } + + rec { + name = "expound/expound"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "expound"; + groupId = "expound"; + sha512 = "ca0a57cfd215cff6be36d1f83461ec2d0559c0eae172c8a8bd6e1676d49933d3c30a71192889bd75d813581707d5eda0ec05de03326396bc0cedebf2d71811e5"; + version = "0.8.10"; + + }; + paths = [ src ]; + } + + rec { + name = "spec.alpha/org.clojure"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "spec.alpha"; + groupId = "org.clojure"; + sha512 = "0bc22505d8aadb8eda3c46af88ef2f572494b553a68333e4d9787714d5ad383c2a21c56e1c81ce47aa2e07d7d9b268236eb57edc5adf6394250f30ce2fad087d"; + version = "0.3.214"; + + }; + paths = [ src ]; + } + + rec { + name = "tools.cli/org.clojure"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "tools.cli"; + groupId = "org.clojure"; + sha512 = "1d88aa03eb6a664bf2c0ce22c45e7296d54d716e29b11904115be80ea1661623cf3e81fc222d164047058239010eb678af92ffedc7c3006475cceb59f3b21265"; + version = "1.0.206"; + + }; + paths = [ src ]; + } + + rec { + name = "compojure/compojure"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "compojure"; + groupId = "compojure"; + sha512 = "1f4ba1354bd95772963a4ef0e129dde59d16f4f9fac0f89f2505a1d5de3b4527e45073219c0478e0b3285da46793e7c145ec5a55a9dae2fca6b77dc8d67b4db6"; + version = "1.6.2"; + + }; + paths = [ src ]; + } + + rec { + name = "commons-fileupload/commons-fileupload"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "commons-fileupload"; + groupId = "commons-fileupload"; + sha512 = "a8780b7dd7ab68f9e1df38e77a5207c45ff50ec53d8b1476570d069edc8f59e52fb1d0fc534d7e513ac5a01b385ba73c320794c82369a72bd6d817a3b3b21f39"; + version = "1.4"; + + }; + paths = [ src ]; + } + + rec { + name = "jetty-http/org.eclipse.jetty"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "jetty-http"; + groupId = "org.eclipse.jetty"; + sha512 = "60422ff3ef311f1d9d7340c2accdf611d40e738a39e9128967175ede4990439f4725995988849957742d488f749dd2e0740f74dc5bd9b3364e32fbaa66689308"; + version = "9.4.42.v20210604"; + + }; + paths = [ src ]; + } + + rec { + name = "jetty-util/org.eclipse.jetty"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "jetty-util"; + groupId = "org.eclipse.jetty"; + sha512 = "d69084e2cfe0c3af1dc7ee2745d563549a4068b6e8aed5cd2b9f31167168fb64d418c4134a6dfb811b627ec0051d7ff71e0a02e4e775d18a53543d0871c44730"; + version = "9.4.42.v20210604"; + + }; + paths = [ src ]; + } + + rec { + name = "janino/org.codehaus.janino"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "janino"; + groupId = "org.codehaus.janino"; + sha512 = "e0bbae3511a2b9cc134afff4fa6c38b6cf0fc1761f233e842df78ba9e25b26f6932e8ee590c7567c0ee86b91472c6b95c49547c034cda98d862e2f00916cd98a"; + version = "3.0.12"; + + }; + paths = [ src ]; + } + + rec { + name = "jcl-over-slf4j/org.slf4j"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "jcl-over-slf4j"; + groupId = "org.slf4j"; + sha512 = "aed539305114718bd76da54f29a391362eb331108d9c033956bf68df29c62a44874c73ae39d19a25342625b6092326d39b4d8720aed6c62234a234e0855b00b5"; + version = "1.7.30"; + + }; + paths = [ src ]; + } + + (rec { + name = "io.github.cognitect-labs/test-runner"; + src = fetchgit { + name = "test-runner"; + url = "https://github.com/cognitect-labs/test-runner"; + rev = "cc75980b43011773162b485f46f939dc5fba91e4"; + sha256 = "1661ddmmqva1yiz9p09i5l32lfpi0a99h56022zgvz03nca2ksbg"; + }; + paths = map (path: src + path) [ + "/src" + ]; + }) + + rec { + name = "cambium.logback.core/cambium"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "cambium.logback.core"; + groupId = "cambium"; + sha512 = "b7b5eda0a455e36e3ba2b1cb978f0c87a3db10f7ff504437f22ca92af26ac762b1e5943b8d748e1a623036bfdad8da70e718f7a4c9e5198c31a4d27954444a19"; + version = "0.4.3"; + + }; + paths = [ src ]; + } + + rec { + name = "logback-jackson/ch.qos.logback.contrib"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "logback-jackson"; + groupId = "ch.qos.logback.contrib"; + sha512 = "d9a3d4cb6cf4eda6fc18e2d374007d27c6ddba98e989a8d8a01b49859b280450113f685df6e16c5fbe0472bc9e26308bc7e8b7e0aedab9404cf0b492d7511685"; + version = "0.1.5"; + + }; + paths = [ src ]; + } + + rec { + name = "simpleclient_tracer_otel/io.prometheus"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "simpleclient_tracer_otel"; + groupId = "io.prometheus"; + sha512 = "bce192e6162cb3ada7dd6c2d10456e78bce71c170faa09bad2896272fa1bd4a036288d707f3d47747991d8946c74fe21c565713fb15c7052305eb753c94dd939"; + version = "0.12.0"; + + }; + paths = [ src ]; + } + + rec { + name = "netty-codec/io.netty"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "netty-codec"; + groupId = "io.netty"; + sha512 = "74e04cf1a78f0066fc96b43f87562f231def49300665b679208314c2df96889835ba71f2dcd90c43fe88bf51583aaa6c868bde90cab8419e0f51702c0cadfc23"; + version = "4.1.42.Final"; + + }; + paths = [ src ]; + } + + rec { + name = "tools.macro/org.clojure"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "tools.macro"; + groupId = "org.clojure"; + sha512 = "65ce5e29379620ac458274c53cd9926e4b764fcaebb1a2b3bc8aef86bbe10c79e654b028bc4328905d2495a680fa90f5002cf5c47885f6449fad43a04a594b26"; + version = "0.1.5"; + + }; + paths = [ src ]; + } + + rec { + name = "jackson-dataformat-cbor/com.fasterxml.jackson.dataformat"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "jackson-dataformat-cbor"; + groupId = "com.fasterxml.jackson.dataformat"; + sha512 = "ea5d049eac1b94666479c5e36de14d8fa4b7f24cb92f0f310d2ec2b4de66ef9023161060e67228ef2d7420a002ef861db12a29cad0864638c21612da49686f4f"; + version = "2.12.4"; + + }; + paths = [ src ]; + } + + rec { + name = "depstar/seancorfield"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "depstar"; + groupId = "seancorfield"; + sha512 = "0f4458b39b8b1949755bc2fe64b239673a9efa3a0140998464bbbcab216ec847344c1b8920611f7c9ca07261850f3a08144ae221cc2c41813a080189e32f9c10"; + version = "1.0.94"; + + }; + paths = [ src ]; + } + + rec { + name = "logback-core/ch.qos.logback"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "logback-core"; + groupId = "ch.qos.logback"; + sha512 = "bd1a7512647fe61b90cfd18bedf2a33f3f16f334f8f8ce947cdd353c0b0b7a7cce203070f0d2183f6583e0f2b2fe6e0b12eb93bd5b2dc29076e7b466447f6dc5"; + version = "1.2.3"; + + }; + paths = [ src ]; + } + + rec { + name = "honeysql/honeysql"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "honeysql"; + groupId = "honeysql"; + sha512 = "74d1d93c968b33686848e3bf8934f3b5f002c2b69b1b55a3a3b172c952e9991324e6e95e3a0ce2fecf1de0d3a036f4dff7286df689f0733f253909464e0269f6"; + version = "1.0.461"; + + }; + paths = [ src ]; + } + + rec { + name = "netty-buffer/io.netty"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "netty-buffer"; + groupId = "io.netty"; + sha512 = "931d0933886888c6729617bd6ebae105683dad6d8ad17b8b70d02df0f406660b003533c370b83fb0aac2d0edb4b182adc7fbb1a38d7e325e6c150ba723c17605"; + version = "4.1.42.Final"; + + }; + paths = [ src ]; + } + + rec { + name = "ring-jetty-adapter/ring"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "ring-jetty-adapter"; + groupId = "ring"; + sha512 = "93075903ad73a8b73cb77ee9f53ed33594f40a5dafe8129089adb4cfa333e37468764203c00244568f02abf0c0eee9f5d9a9f96c420919027cf2746a41ec38e3"; + version = "1.9.4"; + + }; + paths = [ src ]; + } + + rec { + name = "simpleclient_tracer_common/io.prometheus"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "simpleclient_tracer_common"; + groupId = "io.prometheus"; + sha512 = "6f717af63340efd84c5467ae752be7e66f586f0e8b57adb5b7a8ef99b223203ed829aad6797f6ef1811d6d861b00a621a1288c9271ec2ba77018d6d9eb9e7987"; + version = "0.12.0"; + + }; + paths = [ src ]; + } + + rec { + name = "component/com.stuartsierra"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "component"; + groupId = "com.stuartsierra"; + sha512 = "108b02f51165ad07c2cf5232fbd954d052880c2456e6fb6db3342bda6851c76b73bf9145f03fb0df2b5782fe39f368b2868780c1e8e2dfa2ab2c68dd97f34ab7"; + version = "1.0.0"; + + }; + paths = [ src ]; + } + + rec { + name = "netty-handler/io.netty"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "netty-handler"; + groupId = "io.netty"; + sha512 = "73c446fef8fb2cc08bc35ce11f37c88a51d9f0b15bc2bb0cda9d51964ac868bcb211eb23c267ba6facf221790bf29633edda04150b37e254edd9439338b951f7"; + version = "4.1.42.Final"; + + }; + paths = [ src ]; + } + + rec { + name = "yuicompressor/com.yahoo.platform.yui"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "yuicompressor"; + groupId = "com.yahoo.platform.yui"; + sha512 = "ba2588bd50eaa3005b1919daad9f9c86a33351ceb9b7b5f0a9a498a548cc523e99f9345917a64303f8e23925feea226386d3eac01f640f788d1be4c7cf0315e0"; + version = "2.4.8"; + + }; + paths = [ src ]; + } + + rec { + name = "commons-io/commons-io"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "commons-io"; + groupId = "commons-io"; + sha512 = "6af22dffaaecd1553147e788b5cf50368582318f396e456fe9ff33f5175836713a5d700e51720465c932c2b1987daa83027358005812d6a95d5755432de3a79d"; + version = "2.10.0"; + + }; + paths = [ src ]; + } + + rec { + name = "tools.namespace/org.clojure"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "tools.namespace"; + groupId = "org.clojure"; + sha512 = "2cdb9c5d9bc4fd01dae182e9ad4b91eeaa2487003a977e7d8d5e66f562a9544b59f558710eccf421ea63cbbfa953ac8944fe9b9a76049fb82a47eb2bdcb3a4d7"; + version = "1.1.1"; + + }; + paths = [ src ]; + } + + rec { + name = "honeysql/com.github.seancorfield"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "honeysql"; + groupId = "com.github.seancorfield"; + sha512 = "0c611a1d14d18226b7796bd3e5c774a58d03af0329b83dd4ca4324f8a3ffc6e8dbab81dd4eadb4c76dbce2c88f29dd7722590ad8b865d57655e5cb0d0122c480"; + version = "2.1.833"; + + }; + paths = [ src ]; + } + + rec { + name = "jackson-core/com.fasterxml.jackson.core"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "jackson-core"; + groupId = "com.fasterxml.jackson.core"; + sha512 = "428e0ebb16dd4c74ab0adf712058fd0dc0cd788f6e6f90c60c627da6577b345fac60a30694e111f1cd4e3e8bf79a1f1b820d30ada114984b26c28e299e326eaa"; + version = "2.12.4"; + + }; + paths = [ src ]; + } + + rec { + name = "jul-to-slf4j/org.slf4j"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "jul-to-slf4j"; + groupId = "org.slf4j"; + sha512 = "82d77af8c4db84d6b35b8138dc73e6d8c5ebbc6907f77295627d8402a5c63aa3fea05bfc0f8982b3a2120615d8edc4fcb947468c1de3dd33cf943690737e652d"; + version = "1.7.30"; + + }; + paths = [ src ]; + } + + rec { + name = "migratus/migratus"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "migratus"; + groupId = "migratus"; + sha512 = "ee5ce8601930d063e0d9d90fc8e165b78fc1587bfd7e0fc9922735bc2f9fc27f8cf8bf10d49d6fd57b899ac4b250145bd653915ed770424416e026ba37d1b604"; + version = "1.3.5"; + + }; + paths = [ src ]; + } + + rec { + name = "instaparse/instaparse"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "instaparse"; + groupId = "instaparse"; + sha512 = "ec2fcf4a09319a8fa9489b08fd9c9a5fe6e63155dde74d096f947fabc4f68d3d1bf68faf21e175e80eaee785f563a1903d30c550f93fb13a16a240609e3dfa2e"; + version = "1.4.8"; + + }; + paths = [ src ]; + } + + rec { + name = "honeysql-postgres/nilenso"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "honeysql-postgres"; + groupId = "nilenso"; + sha512 = "d4accd3b8819cf715ecdb29496cf5a6a5ad3871fd579e55c7148d4e05774cb896c681b0c6f84df88aa9cd8e6ef9bfd65788ede9a49ba365ad0e32ee350091879"; + version = "0.4.112"; + + }; + paths = [ src ]; + } + + rec { + name = "clj-tuple/clj-tuple"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "clj-tuple"; + groupId = "clj-tuple"; + sha512 = "dd626944d0aba679a21b164ed0c77ea84449359361496cba810f83b9fdeab751e5889963888098ce4bf8afa112dbda0a46ed60348a9c01ad36a2e255deb7ab6d"; + version = "0.2.2"; + + }; + paths = [ src ]; + } + + rec { + name = "jackson-annotations/com.fasterxml.jackson.core"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "jackson-annotations"; + groupId = "com.fasterxml.jackson.core"; + sha512 = "6fdad6c5bb71a97331a662fe26265aacab6869f3307a710697d5c2f256fd48935764bfb0b3505a2cbb1605daf0b7350abdf84a1b1cf2bb1e91d9184565243c8e"; + version = "2.12.4"; + + }; + paths = [ src ]; + } + + rec { + name = "hiccup/hiccup"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "hiccup"; + groupId = "hiccup"; + sha512 = "034f15be46c35029f41869c912f82cb2929fbbb0524ea64bd98dcdb9cf09875b28c75e926fa5fff53942b0f9e543e85a73a2d03c3f2112eecae30fcef8b148f4"; + version = "1.0.5"; + + }; + paths = [ src ]; + } + + rec { + name = "java.classpath/org.clojure"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "java.classpath"; + groupId = "org.clojure"; + sha512 = "90cd8edeaea02bd908d8cfb0cf5b1cf901aeb38ea3f4971c4b813d33210438aae6fff8e724a8272d2ea9441d373e7d936fa5870e309c1e9721299f662dbbdb9a"; + version = "1.0.0"; + + }; + paths = [ src ]; + } + + rec { + name = "simpleclient_pushgateway/io.prometheus"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "simpleclient_pushgateway"; + groupId = "io.prometheus"; + sha512 = "31c8878929f516ba7030cc9ec4ac4cbcb09955a9fdae23c6904bc481e40e70e1b3e05619c49b646119077ef6f57c430cc7944f6bafdbca24c9efa8145474fcf7"; + version = "0.12.0"; + + }; + paths = [ src ]; + } + + rec { + name = "ns-tracker/ns-tracker"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "ns-tracker"; + groupId = "ns-tracker"; + sha512 = "cfb6c2c9f899b43d1284acdc572b34b977936c4df734b38137dfea045421b74d529509cde23695f1dc5ee06d046c2f6b61a2cd98058da1c7220c21dd0361964f"; + version = "0.4.0"; + + }; + paths = [ src ]; + } + + rec { + name = "clout/clout"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "clout"; + groupId = "clout"; + sha512 = "99d6e1a8c5726ca4e5d12b280a39e6d1182d734922600f27d588d3d65fbc830c5e03f9e0421ff25c819deee4d1f389fd3906222716ace1eb17ce70ef9c5e8f4b"; + version = "2.2.1"; + + }; + paths = [ src ]; + } + + rec { + name = "clojure.java-time/clojure.java-time"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "clojure.java-time"; + groupId = "clojure.java-time"; + sha512 = "62d8a286ec3393594e7f84eba22dbb02c1305a80a18b2574058ae963d3f3e829ff960c8b66e89069e6c071a11f869203134c6c4cdec6f8e516c9b314796c8108"; + version = "0.3.3"; + + }; + paths = [ src ]; + } + + rec { + name = "simpleclient_tracer_otel_agent/io.prometheus"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "simpleclient_tracer_otel_agent"; + groupId = "io.prometheus"; + sha512 = "97694210d9a5b48a7cb9dda2a187432c4813edb3051edfa5832a0a471e0b2d5988dab92b70c292e78f59b169345deb5c1c706361fd726f3dc2480766dedfdcec"; + version = "0.12.0"; + + }; + paths = [ src ]; + } + + rec { + name = "next.jdbc/com.github.seancorfield"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "next.jdbc"; + groupId = "com.github.seancorfield"; + sha512 = "1bcaa7092d4a082851b3d0d3daed171d8eb76f9b1f485de91d93cf32c617cf9869ab16a134e932f7813782cbc6c1585b15d2f2ae2fa24633a59bebf72a14d60e"; + version = "1.2.753"; + + }; + paths = [ src ]; + } + + rec { + name = "java.jdbc/org.clojure"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "java.jdbc"; + groupId = "org.clojure"; + sha512 = "6162b7774dca58b62a94bc5a04ba845e4c7065c9c589cc3bb802becfec0baf0989a338c1bf9a5db7c3128873702840d5f2451628f3aac977245975d65a683b7d"; + version = "0.7.11"; + + }; + paths = [ src ]; + } + + rec { + name = "netty-transport/io.netty"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "netty-transport"; + groupId = "io.netty"; + sha512 = "21c12294fc82e7032ce25b2f25769a93f75777021fd6e30cc5c450d41cb3ad5c1ea79c02291c9a8b6dd30c40a8388a00bac95983495df01fb1a539138b3b46db"; + version = "4.1.42.Final"; + + }; + paths = [ src ]; + } + + rec { + name = "crypto-random/crypto-random"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "crypto-random"; + groupId = "crypto-random"; + sha512 = "3520df744f250dbe061d1a5d7a05b7143f3a67a4c3f9ad87b8044ee68a36a702a0bcb3a203e35d380899dd01c28e01988b0a7af914b942ccbe0c35c9bdb22e11"; + version = "1.2.1"; + + }; + paths = [ src ]; + } + + rec { + name = "netty-transport-native-unix-common/io.netty"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "netty-transport-native-unix-common"; + groupId = "io.netty"; + sha512 = "62843f4fade55ea84cc831ef4f0cba75b068d15ccf2bccf7abf8813b41d75b593d5d761f35852420f8440e7b41bef631af4394df0b17666007c9ce7476a10bd9"; + version = "4.1.42.Final"; + + }; + paths = [ src ]; + } + + rec { + name = "ring-codec/ring"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "ring-codec"; + groupId = "ring"; + sha512 = "38b9775a794831b8afd8d66991a75aa5910cd50952c9035866bf9cc01353810aedafbc3f35d8f9e56981ebf9e5c37c00b968759ed087d2855348b3f46d8d0487"; + version = "1.1.3"; + + }; + paths = [ src ]; + } + + rec { + name = "spy/com.impossibl.pgjdbc-ng"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "spy"; + groupId = "com.impossibl.pgjdbc-ng"; + sha512 = "68efbf7a80acdaaefebc8e9693d1a1246cdd422472791f663422b4a5f7c6fa953a3030250e7874f97621ffd3bc844a05bdbbede67f852a0c02cca4658cc8a044"; + version = "0.8.4"; + + }; + paths = [ src ]; + } + + rec { + name = "logback-json-core/ch.qos.logback.contrib"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "logback-json-core"; + groupId = "ch.qos.logback.contrib"; + sha512 = "2a826036f21997e2979fda83ae3e33cf62f3b2b2df15a7b11d1fd8a52163b09f0f2f8d72f5fdcea0ec1289b3d27727ed5e6b0bcdf4c5d741f4bac07b7b6139e8"; + version = "0.1.5"; + + }; + paths = [ src ]; + } + + rec { + name = "crypto-equality/crypto-equality"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "crypto-equality"; + groupId = "crypto-equality"; + sha512 = "54cf3bd28f633665962bf6b41f5ccbf2634d0db210a739e10a7b12f635e13c7ef532efe1d5d8c0120bb46478bbd08000b179f4c2dd52123242dab79fea97d6a6"; + version = "1.0.0"; + + }; + paths = [ src ]; + } + + rec { + name = "cheshire/cheshire"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "cheshire"; + groupId = "cheshire"; + sha512 = "855e9c42a8d1c64f4db5cda45e31e914eb5ed99a715e8d7a5759a9c4ab6c69a82353635ca7b0837880c6cf9b41b11184ae11e09cbf2c07aa13db32c539e5dfd4"; + version = "5.10.1"; + + }; + paths = [ src ]; + } + + rec { + name = "tigris/tigris"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "tigris"; + groupId = "tigris"; + sha512 = "fdff4ef5e7175a973aaef98de4f37dee8e125fc711c495382e280aaf3e11341fe8925d52567ca60f3f1795511ade11bc23461c88959632dfae3cf50374d02bf6"; + version = "0.1.2"; + + }; + paths = [ src ]; + } + + rec { + name = "config/yogthos"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "config"; + groupId = "yogthos"; + sha512 = "af0a73e168d24864a97e4698b993ee21a86cecd5c020975257af4f5e6fb2d3741a78eb3072b235a2f601558dd5d165bfc40839c0c154ff50aee6cf38eb0bf7c8"; + version = "1.1.8"; + + }; + paths = [ src ]; + } + + rec { + name = "jetty-io/org.eclipse.jetty"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "jetty-io"; + groupId = "org.eclipse.jetty"; + sha512 = "a8c5f73089daa0c8b27f836acddf40bcbf07bbb2571a4d73653be8aac3fb339022f546326722f216bad78a68886934d24db9bec54235124592dd29dbeab69051"; + version = "9.4.42.v20210604"; + + }; + paths = [ src ]; + } + + rec { + name = "logback-json-classic/ch.qos.logback.contrib"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "logback-json-classic"; + groupId = "ch.qos.logback.contrib"; + sha512 = "d30bf70217d316914d83d46cc15783f656354084087d59cbc0620a746f10b4a42e56d33b3e50a8b3596a64ec8314730bf5ff9a3f7dc3417bdd0582665be009ec"; + version = "0.1.5"; + + }; + paths = [ src ]; + } + + rec { + name = "tools.reader/org.clojure"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "tools.reader"; + groupId = "org.clojure"; + sha512 = "3481259c7a1eac719db2921e60173686726a0c2b65879d51a64d516a37f6120db8ffbb74b8bd273404285d7b25143ab5c7ced37e7c0eaf4ab1e44586ccd3c651"; + version = "1.3.6"; + + }; + paths = [ src ]; + } + + rec { + name = "simpleclient_common/io.prometheus"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "simpleclient_common"; + groupId = "io.prometheus"; + sha512 = "dedd003638eb3651c112e2d697ac94eb4e3b3e32c94fa41bb1efe2c889a347cdc7bd13256e05423f3370592d4fd65faf8db57f0387ab75814d7fa77b14cbbadf"; + version = "0.12.0"; + + }; + paths = [ src ]; + } + + rec { + name = "commons-compiler/org.codehaus.janino"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "commons-compiler"; + groupId = "org.codehaus.janino"; + sha512 = "51fc5542e05d9a310413677855456a3e08f318210d54e24aa209826ed8f4e524a691bcabccab085d091634827fa656b110ab75ee444808e1a5a9b670cd4ff138"; + version = "3.0.12"; + + }; + paths = [ src ]; + } + + rec { + name = "servlet-api/javax.servlet"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "servlet-api"; + groupId = "javax.servlet"; + sha512 = "363ba5590436ab82067b7a2e14b481aeb2b12ca4048d7a1519a2e549b2d3c09ddf718ac64dc2be6c2fc24c51fdc9c8160261329403113369588ce27d87771db6"; + version = "2.5"; + + }; + paths = [ src ]; + } + + rec { + name = "iapetos/clj-commons"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "iapetos"; + groupId = "clj-commons"; + sha512 = "d17f36c0cf0ec78db5e893e5c033f8562b31650bda6f5ee582e68f84a07a3631d04d6f69e4e18b1ca64e732c180fa669dfb69a78849e13f601cd563a7a8aab94"; + version = "0.1.12"; + + }; + paths = [ src ]; + } + + rec { + name = "javax.servlet-api/javax.servlet"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "javax.servlet-api"; + groupId = "javax.servlet"; + sha512 = "32f7e3565c6cdf3d9a562f8fd597fe5059af0cf6b05b772a144a74bbc95927ac275eb38374538ec1c72adcce4c8e1e2c9f774a7b545db56b8085af0065e4a1e5"; + version = "3.1.0"; + + }; + paths = [ src ]; + } + + rec { + name = "netty-resolver/io.netty"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "netty-resolver"; + groupId = "io.netty"; + sha512 = "2ec515e4191b10caa78d34efffba4fbe4bf6c08badff26cd619c591eb514abba1447258181fcf61c59cd912c5d7df65bca99f092235e679ccbe04575bc41584d"; + version = "4.1.42.Final"; + + }; + paths = [ src ]; + } + + rec { + name = "netty-transport-native-epoll/io.netty"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "netty-transport-native-epoll"; + groupId = "io.netty"; + sha512 = "cdcf04b0ba953f98b09737b100394cfc2b755ae334c5897703508ce5ecc6a0c94792040bc21e2af59509a7b61f838a92b64949468c7c6f72fffe5c7574d52a25"; + version = "4.1.42.Final"; + + }; + paths = [ src ]; + } + + rec { + name = "clj-stacktrace/clj-stacktrace"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "clj-stacktrace"; + groupId = "clj-stacktrace"; + sha512 = "993f8a544203801fc074eefacee8e553e426422b3492d47b857d87ac73cde72c91e29f629382b9eae8cf9600bc2c4c29d2e7169e509c46302ab973c86e73af0c"; + version = "0.2.8"; + + }; + paths = [ src ]; + } + + rec { + name = "cambium.codec-cheshire/cambium"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "cambium.codec-cheshire"; + groupId = "cambium"; + sha512 = "33732ebdbc257b7679f705a20d4fbe41860763f67b0d338e9c8eb23839016464cf2fe7c312317ad9b1b47b3fc604fe5039e30172ee73df09faead9aa7ec6dff6"; + version = "0.9.3"; + + }; + paths = [ src ]; + } + + rec { + name = "slf4j-api/org.slf4j"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "slf4j-api"; + groupId = "org.slf4j"; + sha512 = "db7440b47e87215f9cc88c9521bce7a0f2ffa81b07e5f53c5f8afa90a0ab61168755ee6d136245461b57a01f0a857fe0d509c60baa7838c4eb6be1f885438049"; + version = "2.0.0-alpha1"; + + }; + paths = [ src ]; + } + + rec { + name = "ring-servlet/ring"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "ring-servlet"; + groupId = "ring"; + sha512 = "3d8e6ec224e13d54810a945c0b6c0d2d863736a48d8c4bfc8fadb96b6b0fa9baa638644d0d92d8a53650b188e6e75d391731b08b26eb0f551e90a7504e7f4267"; + version = "1.9.4"; + + }; + paths = [ src ]; + } + + rec { + name = "logback-classic/ch.qos.logback"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "logback-classic"; + groupId = "ch.qos.logback"; + sha512 = "9ad5df9055e74c1db67e10422774e740903477c821591702d2709a4c1f73e3fc3fa6b1a871b6985901817bc2bdeba916849035dc2bbf518f308637b0586e36f1"; + version = "1.2.3"; + + }; + paths = [ src ]; + } + + rec { + name = "dependency/com.stuartsierra"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "dependency"; + groupId = "com.stuartsierra"; + sha512 = "d32fbc4813bd16f2ed8c82e2915e1fb564e88422159bd3580a85c8cd969d1bbbe315bdc13d29c2f0eaceeeafcf649ee712c8df4532464d560aaeae4ae5953866"; + version = "1.0.0"; + + }; + paths = [ src ]; + } + + rec { + name = "camel-snake-kebab/camel-snake-kebab"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "camel-snake-kebab"; + groupId = "camel-snake-kebab"; + sha512 = "589d34b500560b7113760a16bfb6f0ccd8f162a1ce8c9bc829495432159ba9c95aebf6bc43aa126237a0525806a205a05f9910122074902b659e7fd151d176b1"; + version = "0.4.2"; + + }; + paths = [ src ]; + } + + rec { + name = "ring/ring"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "ring"; + groupId = "ring"; + sha512 = "93c48fb670736b91fb41d8076e1e9c4f53c67693d15e75290da319e7d7881b829a24180029b3a0fa051473c6c77ac3c97b519254ebf2b2c9538b185e79b69162"; + version = "1.9.4"; + + }; + paths = [ src ]; + } + + rec { + name = "netty-transport-native-kqueue/io.netty"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "netty-transport-native-kqueue"; + groupId = "io.netty"; + sha512 = "054ec02b78cbfe5cee6e96e3d8aeff35b2283f5f08e88456c9946c36c86f2a5b35074d333ad87a3f002a15e5816e3d51fbceb4134a91930dae83fee1ce80e5f4"; + version = "4.1.42.Final"; + + }; + paths = [ src ]; + } + + rec { + name = "java.data/org.clojure"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "java.data"; + groupId = "org.clojure"; + sha512 = "7fea02e1620e44602b806174d3500051a1ce45d8464fe4600dc19dce06e24bafa071cdbb0e4ae858e8dc01eda77f3e01269c1b1e21b42709b432f38828b39f2d"; + version = "1.0.92"; + + }; + paths = [ src ]; + } + + rec { + name = "jetty-server/org.eclipse.jetty"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "jetty-server"; + groupId = "org.eclipse.jetty"; + sha512 = "b347f8a6e5b84e0f460037027e238a61edec710ade768c95e7be13dcea498abe43d5e622ee69ac7494138d1a8fcf92e07b7deab569c554831c57baad71c53b9b"; + version = "9.4.42.v20210604"; + + }; + paths = [ src ]; + } + + rec { + name = "log4j-over-slf4j/org.slf4j"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "log4j-over-slf4j"; + groupId = "org.slf4j"; + sha512 = "c70a080409a2741dd1977318ce78b61f86fc8e02a2120e934e91cc3b8b0f9bb67e0bac3d3753a0e7a195ff1866bead77e3fc51e1ede89bb537a6869ec58a5724"; + version = "1.7.30"; + + }; + paths = [ src ]; + } + + rec { + name = "ring-core/ring"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "ring-core"; + groupId = "ring"; + sha512 = "38d7214a3fc1b80ab55999036638dd1971272e01bec4cb8e0ee0a4aa83f51b8c41ba8a5850b0660227f067d2f9c6d75c0c0737725ea02762bbf8d192dc72febe"; + version = "1.9.4"; + + }; + paths = [ src ]; + } + + rec { + name = "cambium.core/cambium"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "cambium.core"; + groupId = "cambium"; + sha512 = "c355fcd2855f9639155ea8ecf310e42bbe3cac4e9f1b305590284f25ffda25bd2fb76908b39bb947293d7af0fd3beba8b76b55d79c115c1222a5c0944c2ba47a"; + version = "0.9.3"; + + }; + paths = [ src ]; + } + + rec { + name = "medley/medley"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "medley"; + groupId = "medley"; + sha512 = "749ef43b5ea2cae7dc96db871cdd15c7b3c9cfbd96828c20ab08e67d39a5e938357d15994d8d413bc68678285d6c666f2a7296fbf305706d03b3007254e3c55c"; + version = "1.3.0"; + + }; + paths = [ src ]; + } + + rec { + name = "garden/garden"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "garden"; + groupId = "garden"; + sha512 = "2cc29f071b68bf451835f76de351ac2efb930b5df9ca7237fdca439d3c4d797d7fa207a147886efe1738ab1c50b76c1e366bf9ffcd6f286b0b211260aedd0b25"; + version = "1.3.10"; + + }; + paths = [ src ]; + } + + rec { + name = "jackson-dataformat-smile/com.fasterxml.jackson.dataformat"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "jackson-dataformat-smile"; + groupId = "com.fasterxml.jackson.dataformat"; + sha512 = "69676964a2b09516b8ffd0d847b6f9a9b843424185453731b548c25e7e9ce30e808c56d66923f9183e2b5c1ba007421b146a6806e768b8e6b07470d60227f1dd"; + version = "2.12.4"; + + }; + paths = [ src ]; + } + + rec { + name = "jaxb-api/javax.xml.bind"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "jaxb-api"; + groupId = "javax.xml.bind"; + sha512 = "0c5bfc2c9f655bf5e6d596e0c196dcb9344d6dc78bf774207c8f8b6be59f69addf2b3121e81491983eff648dfbd55002b9878132de190825dad3ef3a1265b367"; + version = "2.3.0"; + + }; + paths = [ src ]; + } + + rec { + name = "pgjdbc-ng/com.impossibl.pgjdbc-ng"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "pgjdbc-ng"; + groupId = "com.impossibl.pgjdbc-ng"; + sha512 = "d19ddde1c700972531df24f4ea9326772f74210e5489ee340d81c6f2c6963788d0f4c86aeb869450ef599c741f91154079168e12c26c32f3e926abedc6b9c2a2"; + version = "0.8.4"; + + }; + paths = [ src ]; + } + + rec { + name = "http-kit/http-kit"; + src = fetchMavenArtifact { + inherit repos; + artifactId = "http-kit"; + groupId = "http-kit"; + sha512 = "4186a2429984745e18730aa8fd545f1fc1812083819ebf77aecfc04e0d31585358a5e25a308c7f21d81359418bbc72390c281f5ed91ae116cf1af79860ba22c3"; + version = "2.5.3"; + + }; + paths = [ src ]; + } + + ]; + } + \ No newline at end of file diff --git a/users/grfn/bbbg/env/dev/bbbg-signup/env.clj b/users/grfn/bbbg/env/dev/bbbg-signup/env.clj new file mode 100644 index 000000000000..c30e328ffa24 --- /dev/null +++ b/users/grfn/bbbg/env/dev/bbbg-signup/env.clj @@ -0,0 +1,3 @@ +(ns bbbg.env) + +(def environment :env/dev) diff --git a/users/grfn/bbbg/env/dev/logback.xml b/users/grfn/bbbg/env/dev/logback.xml new file mode 100644 index 000000000000..7aa21978bbe7 --- /dev/null +++ b/users/grfn/bbbg/env/dev/logback.xml @@ -0,0 +1,15 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg { %mdc }%n + + + + + + + + + + diff --git a/users/grfn/bbbg/env/prod/bbbg-signup/env.clj b/users/grfn/bbbg/env/prod/bbbg-signup/env.clj new file mode 100644 index 000000000000..46e8cd67e318 --- /dev/null +++ b/users/grfn/bbbg/env/prod/bbbg-signup/env.clj @@ -0,0 +1,3 @@ +(ns bbbg.env) + +(def environment :env/prod) diff --git a/users/grfn/bbbg/env/prod/logback.xml b/users/grfn/bbbg/env/prod/logback.xml new file mode 100644 index 000000000000..b81118ed6b32 --- /dev/null +++ b/users/grfn/bbbg/env/prod/logback.xml @@ -0,0 +1,31 @@ + + + + + + + + + + INFO + + + + + false + + + yyyy-MM-dd'T'HH:mm:ss.SSS'Z' + UTC + true + + + + + + + + + + + diff --git a/users/grfn/bbbg/env/test/bbbg-signup/env.clj b/users/grfn/bbbg/env/test/bbbg-signup/env.clj new file mode 100644 index 000000000000..352147a6d0fd --- /dev/null +++ b/users/grfn/bbbg/env/test/bbbg-signup/env.clj @@ -0,0 +1,3 @@ +(ns bbbg.env) + +(def environment :env/test) diff --git a/users/grfn/bbbg/env/test/logback.xml b/users/grfn/bbbg/env/test/logback.xml new file mode 100644 index 000000000000..8554f3d0ed0b --- /dev/null +++ b/users/grfn/bbbg/env/test/logback.xml @@ -0,0 +1,11 @@ + + + + + %msg%n + + + + + + diff --git a/users/grfn/bbbg/pom.xml b/users/grfn/bbbg/pom.xml new file mode 100644 index 000000000000..012c0985f12f --- /dev/null +++ b/users/grfn/bbbg/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + fyi.gws + bbbg + 0.1.0-SNAPSHOT + fyi.gws/bbbg + webhook listener for per-branch deploys + https://bbbg.gws.fyi + + + Griffin Smith + + + + + org.clojure + clojure + 1.11.0-alpha3 + + + + src + + + + clojars + https://repo.clojars.org/ + + + sonatype + https://oss.sonatype.org/content/repositories/snapshots/ + + + + + clojars + Clojars repository + https://clojars.org/repo + + + diff --git a/users/grfn/bbbg/resources/main.js b/users/grfn/bbbg/resources/main.js new file mode 100644 index 000000000000..d4752f114167 --- /dev/null +++ b/users/grfn/bbbg/resources/main.js @@ -0,0 +1,49 @@ +window.onload = () => { + console.log("loaded"); + const input = document.getElementById("name-autocomplete"); + if (input != null) { + const eventID = document.getElementById("event-id").value; + + const autocomplete = new autoComplete({ + selector: "#name-autocomplete", + placeHolder: "Enter your name", + data: { + src: async (query) => { + const resp = await fetch( + `/attendees.json?q=${query}&event_id=${eventID}&attended=false` + ); + console.log("got resp"); + const { results } = await resp.json(); + return results; + }, + keys: ["bbbg.attendee/meetup-name"], + }, + resultItem: { + highlight: { + render: true, + }, + }, + }); + + input.addEventListener("selection", function (event) { + const attendee = event.detail.selection.value; + event.target.value = attendee["bbbg.attendee/meetup-name"]; + + const attendeeID = attendee["bbbg.attendee/id"]; + document.getElementById("attendee-id").value = attendeeID; + document.getElementById("signup-form").removeAttribute("disabled"); + document + .getElementById("signup-form") + .querySelector('input[type="submit"]') + .removeAttribute("disabled"); + }); + } + + document.querySelectorAll("form").forEach((form) => { + form.onsubmit = (e) => { + if (e.target.attributes.disabled) { + e.preventDefault(); + } + }; + }); +}; diff --git a/users/grfn/bbbg/resources/migrations/20211212165646-init-schema.down.sql b/users/grfn/bbbg/resources/migrations/20211212165646-init-schema.down.sql new file mode 100644 index 000000000000..69b818a4f4ab --- /dev/null +++ b/users/grfn/bbbg/resources/migrations/20211212165646-init-schema.down.sql @@ -0,0 +1,14 @@ +drop table "public"."user"; + +-- ;; + +drop table "public"."event_attendee"; + + +-- ;; + +drop table "public"."event"; + +-- ;; + +drop table "public"."attendee"; diff --git a/users/grfn/bbbg/resources/migrations/20211212165646-init-schema.up.sql b/users/grfn/bbbg/resources/migrations/20211212165646-init-schema.up.sql new file mode 100644 index 000000000000..8c3276e1e61d --- /dev/null +++ b/users/grfn/bbbg/resources/migrations/20211212165646-init-schema.up.sql @@ -0,0 +1,31 @@ +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; +-- ;; +CREATE TABLE "attendee" ( + "id" UUID PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(), + "meetup_name" TEXT NOT NULL, + "discord_name" TEXT, + "meetup_user_id" TEXT, + "organizer_notes" TEXT NOT NULL DEFAULT '', + "created_at" TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now() +); +-- ;; +CREATE TABLE "event" ( + "id" UUID PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(), + "date" DATE NOT NULL, + "created_at" TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now() +); +-- ;; +CREATE TABLE "event_attendee" ( + "event_id" UUID NOT NULL REFERENCES "event" ("id"), + "attendee_id" UUID NOT NULL REFERENCES "attendee" ("id"), + "rsvpd_attending" BOOL, + "attended" BOOL, + "created_at" TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now(), + PRIMARY KEY ("event_id", "attendee_id") +); +-- ;; +CREATE TABLE "user" ( + "id" UUID PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(), + "discord_user_id" TEXT NOT NULL, + "created_at" TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now() +); diff --git a/users/grfn/bbbg/shell.nix b/users/grfn/bbbg/shell.nix new file mode 100644 index 000000000000..195562519ed4 --- /dev/null +++ b/users/grfn/bbbg/shell.nix @@ -0,0 +1,20 @@ +let + depot = import ../../.. {}; +in +with depot.third_party.nixpkgs; + +mkShell { + buildInputs = [ + arion + depot.third_party.clj2nix + clojure + openjdk11_headless + postgresql_12 + nix-prefetch-git + ]; + + PGHOST = "localhost"; + PGUSER = "bbbg"; + PGDATABASE = "bbbg"; + PGPASSWORD = "password"; +} diff --git a/users/grfn/bbbg/src/bbbg/attendee.clj b/users/grfn/bbbg/src/bbbg/attendee.clj new file mode 100644 index 000000000000..fabedb0a910d --- /dev/null +++ b/users/grfn/bbbg/src/bbbg/attendee.clj @@ -0,0 +1,4 @@ +(ns bbbg.attendee + (:require [clojure.spec.alpha :as s])) + +(s/def ::id uuid?) diff --git a/users/grfn/bbbg/src/bbbg/core.clj b/users/grfn/bbbg/src/bbbg/core.clj new file mode 100644 index 000000000000..70c7da50d502 --- /dev/null +++ b/users/grfn/bbbg/src/bbbg/core.clj @@ -0,0 +1,58 @@ +(ns bbbg.core + (:gen-class) + (:require + [bbbg.db :as db] + [bbbg.web :as web] + [clojure.spec.alpha :as s] + [clojure.spec.test.alpha :as stest] + [com.stuartsierra.component :as component] + [expound.alpha :as exp])) + +(s/def ::config + (s/merge + ::db/config + ::web/config)) + +(defn make-system [config] + (component/system-map + :db (db/make-database config) + :web (web/make-server config))) + +(defn env->config [] + (s/assert + ::config + (merge + (db/env->config) + (web/env->config)))) + +(defn dev-config [] + (s/assert + ::config + (merge + (db/dev-config) + (web/dev-config)))) + +(defonce system nil) + +(defn init-dev [] + (s/check-asserts true) + (set! s/*explain-out* exp/printer) + (stest/instrument)) + +(defn run-dev [] + (init-dev) + (alter-var-root + #'system + (fn [sys] + (when sys + (component/start sys)) + (component/start (make-system (dev-config)))))) + +(defn -main [& _args] + (alter-var-root + #'system + (constantly (component/start (make-system (env->config)))))) + +(comment + (run-dev) + ) diff --git a/users/grfn/bbbg/src/bbbg/db.clj b/users/grfn/bbbg/src/bbbg/db.clj new file mode 100644 index 000000000000..03c86d6fb965 --- /dev/null +++ b/users/grfn/bbbg/src/bbbg/db.clj @@ -0,0 +1,357 @@ +(ns bbbg.db + (:gen-class) + (:refer-clojure :exclude [get list]) + (:require [camel-snake-kebab.core :as csk :refer [->kebab-case ->snake_case]] + [bbbg.util.core :as u] + [clojure.set :as set] + [clojure.spec.alpha :as s] + [clojure.string :as str] + [com.stuartsierra.component :as component] + [config.core :refer [env]] + [honeysql.format :as hformat] + [migratus.core :as migratus] + [next.jdbc :as jdbc] + [next.jdbc.connection :as jdbc.conn] + next.jdbc.date-time + [next.jdbc.optional :as jdbc.opt] + [next.jdbc.result-set :as rs] + [next.jdbc.sql :as sql]) + (:import [com.impossibl.postgres.jdbc PGSQLSimpleException] + com.zaxxer.hikari.HikariDataSource + [java.sql Connection ResultSet Types] + javax.sql.DataSource)) + +(s/def ::host string?) +(s/def ::database string?) +(s/def ::user string?) +(s/def ::password string?) + +(s/def ::config + (s/keys :opt [::host + ::database + ::user + ::password])) + +(s/fdef make-database + :args + (s/cat :config (s/keys :opt [::config]))) + +(s/fdef env->config :ret ::config) + +(s/def ::db any?) + +;;; + +(def default-config + (s/assert + ::config + {::host "localhost" + ::database "bbbg" + ::user "bbbg" + ::password "password"})) + +(defn dev-config [] default-config) + +(defn env->config [] + (->> + {::host (:pghost env) + ::database (:pgdatabase env) + ::user (:pguser env) + ::password (:pgpassword env)} + u/remove-nils + (s/assert ::config))) + +(defn ->db-spec [config] + (-> default-config + (merge config) + (set/rename-keys + {::host :host + ::database :dbname + ::user :username + ::password :password}) + (assoc :dbtype "pgsql"))) + +(defn connection + "Make a one-off connection from the given `::config` map, or the environment + if not provided" + ([] (connection (env->config))) + ([config] + (-> config + ->db-spec + (set/rename-keys {:username :user}) + jdbc/get-datasource + jdbc/get-connection))) + +(defrecord Database [config] + component/Lifecycle + (start [this] + (assoc this :pool (jdbc.conn/->pool HikariDataSource (->db-spec config)))) + (stop [this] + (some-> this :pool .close) + (dissoc this :pool)) + + clojure.lang.IFn + (invoke [this] (:pool this))) + +(defn make-database [config] + (map->Database {:config config})) + +;;; +;;; Migrations +;;; + +(defn migratus-config + [db] + {:store :database + :migration-dir "migrations/" + :migration-table-name "__migrations__" + :db + (let [db (if (ifn? db) (db) db)] + (cond + (.isInstance Connection db) + {:connection db} + (.isInstance DataSource db) + {:datasource db} + :else (throw + (ex-info "migratus-config called with value of unrecognized type" + {:value db}))))}) + +(defn generate-migration + ([db name] (generate-migration db name :sql)) + ([db name type] (migratus/create (migratus-config db) name type))) + +(defn migrate! + [db] (migratus/migrate (migratus-config db))) + +(defn rollback! + [db] (migratus/rollback (migratus-config db))) + +;;; +;;; Database interaction +;;; + +(defn ->key-ns [tn] + (let [tn (name tn) + tn (if (str/starts-with? tn "public.") + (second (str/split tn #"\." 2)) + tn)] + (str "bbbg." (->kebab-case tn)))) + +(defn ->table-name [kns] + (let [kns (name kns)] + (->snake_case + (if (str/starts-with? kns "public.") + kns + (str "public." (last (str/split kns #"\."))))))) + +(defn ->column + ([col] (->column nil col)) + ([table col] + (let [col-table (some-> col namespace ->table-name) + snake-col (-> col name ->snake_case (str/replace #"\?$" ""))] + (if (or (not (namespace col)) + (not table) + (= (->table-name table) col-table)) + snake-col + ;; different table, assume fk + (str + (str/replace-first col-table "public." "") + "_" + snake-col))))) + +(defn ->value [v] + (if (keyword? v) + (-> v name csk/->snake_case_string) + v)) + +(defn process-key-map [table key-map] + (into {} + (map (fn [[k v]] [(->column table k) + (->value v)])) + key-map)) + +(defn fkize [col] + (if (str/ends-with? col "-id") + (let [table (str/join "-" (butlast (str/split (name col) #"-")))] + (keyword (->key-ns table) "id")) + col)) + +(def ^:private enum-members-cache (atom {})) +(defn- enum-members + "Returns a set of enum members as strings for the enum with the given name" + [db name] + (if-let [e (find @enum-members-cache name)] + (val e) + (let [r (try + (-> (jdbc/execute-one! + (db) + [(format "select enum_range(null::%s) as members" name)]) + :members + .getArray + set) + (catch PGSQLSimpleException _ + nil))] + (swap! enum-members-cache assoc name r) + r))) + +(def ^{:private true + :dynamic true} + *meta-db* + "Database connection to use to query metadata" + nil) + +(extend-protocol rs/ReadableColumn + String + (read-column-by-label [x _] x) + (read-column-by-index [x rsmeta idx] + (if-not *meta-db* + x + (let [typ (.getColumnTypeName rsmeta idx)] + ;; TODO: Is there a better way to figure out if a type is an enum? + (if (enum-members *meta-db* typ) + (keyword (csk/->kebab-case-string typ) + (csk/->kebab-case-string x)) + x))))) + +(comment + (->key-ns :public.user) + (->key-ns :public.api-token) + (->key-ns :api-token) + (->table-name :api-token) + (->table-name :public.user) + (->table-name :bbbg.user) + ) + +(defn as-fq-maps [^ResultSet rs _opts] + (let [qualify #(when (seq %) (str "bbbg." (->kebab-case %))) + rsmeta (.getMetaData rs) + cols (mapv + (fn [^Integer i] + (let [ty (.getColumnType rsmeta i) + lab (.getColumnLabel rsmeta i) + n (str (->kebab-case lab) + (when (= ty Types/BOOLEAN) "?"))] + (fkize + (if-let [q (some-> rsmeta (.getTableName i) qualify not-empty)] + (keyword q n) + (keyword n))))) + (range 1 (inc (.getColumnCount rsmeta))))] + (jdbc.opt/->MapResultSetOptionalBuilder rs rsmeta cols))) + +(def jdbc-opts + {:builder-fn as-fq-maps + :column-fn ->snake_case + :table-fn ->snake_case}) + +(defmethod hformat/fn-handler "count-distinct" [_ field] + (str "count(distinct " (hformat/to-sql field) ")")) + +(defn fetch + "Fetch a single row from the db matching the given `sql-map` or query" + [db sql-map & [opts]] + (s/assert + (s/nilable (s/keys)) + (binding [*meta-db* db] + (jdbc/execute-one! + (db) + (if (map? sql-map) + (hformat/format sql-map) + sql-map) + (merge jdbc-opts opts))))) + +(defn get + "Retrieve a single record from the given table by ID" + [db table id & [opts]] + (when id + (fetch + db + {:select [:*] + :from [table] + :where [:= :id id]} + opts))) + +(defn list + "Returns a list of rows from the db matching the given sql-map, table or + query" + [db sql-map-or-table & [opts]] + (s/assert + (s/coll-of (s/keys)) + (binding [*meta-db* db] + (jdbc/execute! + (db) + (cond + (map? sql-map-or-table) + (hformat/format sql-map-or-table) + (keyword? sql-map-or-table) + (hformat/format {:select [:*] :from [sql-map-or-table]}) + :else + sql-map-or-table) + (merge jdbc-opts opts))))) + +(defn exists? + "Returns true if the given sql query-map would return any results" + [db sql-map] + (binding [*meta-db* db] + (pos? + (:count + (fetch db {:select [[:%count.* :count]], :from [[sql-map :sq]]}))))) + +(defn execute! + "Given a database and a honeysql query map, perform an operation on the + database and discard the results" + [db sql-map & [opts]] + (jdbc/execute! + (db) + (hformat/format sql-map) + (merge jdbc-opts opts))) + +(defn insert! + "Given a database, a table name, and a data hash map, inserts the + data as a single row in the database and attempts to return a map of generated + keys." + [db table key-map & [opts]] + (binding [*meta-db* db] + (sql/insert! + (db) + table + (process-key-map table key-map) + (merge jdbc-opts opts)))) + +(defn update! + "Given a database, a table name, a hash map of columns and values + to set, and a honeysql predicate, perform an update on the table. + Will " + [db table key-map where-params & [opts]] + (binding [*meta-db* db] + (execute! db + {:update table + :set (u/map-keys keyword (process-key-map table key-map)) + :where where-params + :returning [:id]} + opts))) + +(defn delete! + "Delete all rows from the given table matching the given where clause" + [db table where-clause] + (binding [*meta-db* db] + (sql/delete! (db) table (hformat/format-predicate where-clause)))) + +(defmacro with-transaction [[sym db opts] & body] + `(jdbc/with-transaction + [tx# (~db) ~opts] + (let [~sym (constantly tx#)] + ~@body))) + +(defn -main [& args] + (let [db (component/start (make-database {::config (env->config)}))] + (case (first args) + "migrate" (migrate! db) + "rollback" (rollback! db)))) + +(comment + (def db (:db bbbg.core/system)) + (generate-migration db "init-schema") + (migrate! db) + + + ) diff --git a/users/grfn/bbbg/src/bbbg/db/attendee.clj b/users/grfn/bbbg/src/bbbg/db/attendee.clj new file mode 100644 index 000000000000..7584b1cceb8e --- /dev/null +++ b/users/grfn/bbbg/src/bbbg/db/attendee.clj @@ -0,0 +1,29 @@ +(ns bbbg.db.attendee + (:require + [bbbg.db :as db] + honeysql-postgres.helpers + [honeysql.helpers :refer [merge-join merge-where]])) + +(defn search + ([query] + (cond-> + {:select [:attendee.*] + :from [:attendee]} + query + (assoc + :where [:or + [:ilike :meetup_name (str "%" query "%")] + [:ilike :discord_name (str "%" query "%")]]))) + ([db query] + (db/list db (search query)))) + +(defn for-event + ([query event-id] + (-> query + (merge-join :event_attendee [:= :attendee.id :event_attendee.attendee_id]) + (merge-where [:= :event_attendee.event_id event-id])))) + +(comment + (def db (:db bbbg.core/system)) + (search db "gri") + ) diff --git a/users/grfn/bbbg/src/bbbg/db/event.clj b/users/grfn/bbbg/src/bbbg/db/event.clj new file mode 100644 index 000000000000..a2aa30fd0dad --- /dev/null +++ b/users/grfn/bbbg/src/bbbg/db/event.clj @@ -0,0 +1,50 @@ +(ns bbbg.db.event + (:require + [bbbg.attendee :as attendee] + [bbbg.db :as db] + [bbbg.event :as event] + [honeysql.helpers :refer [merge-group-by merge-join merge-select]] + [java-time :refer [local-date]])) + +(defn create! [db event] + (db/insert! db :event (select-keys event [::event/date]))) + +(defn attended! + [db params] + (db/execute! + db + {:insert-into :event-attendee + :values [{:event_id (::event/id params) + :attendee_id (::attendee/id params) + :attended true}] + :upsert {:on-conflict [:event-id :attendee-id] + :do-update-set! {:attended true}}})) + +(defn on-day + ([day] {:select [:event.*] + :from [:event] + :where [:= :date (str day)]}) + ([db day] + (db/list db (on-day day)))) + +(defn today + ([] (on-day (local-date))) + ([db] (db/list db (today)))) + +(defn with-attendee-counts + [query] + (-> query + (merge-join :event_attendee [:= :event.id :event_attendee.event-id]) + (merge-select :%count.event_attendee.attendee_id) + (merge-group-by :event.id :event_attendee.event-id))) + +(comment + (def db (:db bbbg.core/system)) + (db/list db (-> (today) (with-attendee-counts))) + + (honeysql.format/format + (honeysql-postgres.helpers/upsert {:insert-into :foo + :values {:bar 1}} + (-> (honeysql-postgres.helpers/on-conflict :did) + (honeysql-postgres.helpers/do-update-set! [:did true])))) + ) diff --git a/users/grfn/bbbg/src/bbbg/event.clj b/users/grfn/bbbg/src/bbbg/event.clj new file mode 100644 index 000000000000..aa0578f3546b --- /dev/null +++ b/users/grfn/bbbg/src/bbbg/event.clj @@ -0,0 +1,4 @@ +(ns bbbg.event + (:require [clojure.spec.alpha :as s])) + +(s/def ::id uuid?) diff --git a/users/grfn/bbbg/src/bbbg/event_attendee.clj b/users/grfn/bbbg/src/bbbg/event_attendee.clj new file mode 100644 index 000000000000..af37bf01c023 --- /dev/null +++ b/users/grfn/bbbg/src/bbbg/event_attendee.clj @@ -0,0 +1,4 @@ +(ns bbbg.event-attendee + (:require [clojure.spec.alpha :as s])) + +(s/def ::attended? boolean?) diff --git a/users/grfn/bbbg/src/bbbg/handlers/attendees.clj b/users/grfn/bbbg/src/bbbg/handlers/attendees.clj new file mode 100644 index 000000000000..00a8a5908046 --- /dev/null +++ b/users/grfn/bbbg/src/bbbg/handlers/attendees.clj @@ -0,0 +1,40 @@ +(ns bbbg.handlers.attendees + (:require + [bbbg.attendee :as attendee] + [bbbg.db :as db] + [bbbg.db.attendee :as db.attendee] + [bbbg.db.event :as db.event] + [bbbg.event :as event] + [cheshire.core :as json] + [compojure.core :refer [GET POST routes]] + [honeysql.helpers :refer [merge-where]] + [ring.util.response :refer [content-type redirect response]])) + +(defn attendees-routes [{:keys [db]}] + (routes + (GET "/attendees.json" [q event_id attended] + (let [results + (db/list + db + (cond-> + (if q + (db.attendee/search q) + {:select [:attendee.*] :from [:attendee]}) + event_id (db.attendee/for-event event_id) + (some? attended) (merge-where [:= :attended (case attended + "true" true + "false" false)])))] + (-> {:results results} + json/generate-string + response + (content-type "application/json")))) + + (POST "/event_attendees" [event_id attendee_id] + (if (and (db/exists? db {:select [:id] :from [:event] :where [:= :id event_id]}) + (db/exists? db {:select [:id] :from [:attendee] :where [:= :id attendee_id]})) + (do + (db.event/attended! db {::event/id event_id + ::attendee/id attendee_id}) + (-> (redirect (str "/signup-forms/" event_id)) + (assoc :flash "Thank you for signing in! Enjoy the event."))) + (response "Something went wrong"))))) diff --git a/users/grfn/bbbg/src/bbbg/handlers/core.clj b/users/grfn/bbbg/src/bbbg/handlers/core.clj new file mode 100644 index 000000000000..34ab74553fdd --- /dev/null +++ b/users/grfn/bbbg/src/bbbg/handlers/core.clj @@ -0,0 +1,34 @@ +(ns bbbg.handlers.core + (:require + [hiccup.core :refer [html]] + [ring.util.response :refer [content-type response]])) + +(defn render-page [opts & body] + (let [[{:keys [title]} body] + (if (map? opts) + [opts body] + [{} (into [opts] body)])] + (html + [:html {:lang "en"} + [:head + [:meta {:charset "UTF-8"}] + [:title (if title + (str title " - BBBG") + "BBBG")] + [:link {:rel "stylesheet" + :type "text/css" + :href "/main.css"}]] + [:body + (into [:div.content] body) + [:script {:src "https://cdnjs.cloudflare.com/ajax/libs/tarekraafat-autocomplete.js/10.2.6/autoComplete.js"}] + [:script {:src "/main.js"}]]]))) + +(defn page-response [& render-page-args] + (-> (apply render-page render-page-args) + response + (content-type "text/html"))) + +(comment + (render-page + [:h1 "hi"]) + ) diff --git a/users/grfn/bbbg/src/bbbg/handlers/events.clj b/users/grfn/bbbg/src/bbbg/handlers/events.clj new file mode 100644 index 000000000000..f42b7bea2c7e --- /dev/null +++ b/users/grfn/bbbg/src/bbbg/handlers/events.clj @@ -0,0 +1,44 @@ +(ns bbbg.handlers.events + (:require + [bbbg.db :as db] + [bbbg.db.event :as db.event] + [bbbg.event :as event] + [bbbg.handlers.core :refer [page-response]] + [compojure.core :refer [context GET POST]] + [ring.util.response :refer [redirect]])) + +(defn events-index [events] + [:ul.events-list + (for [event events] + [:li (::event/date event)])]) + +(defn event-form + ([] (event-form {})) + ([event] + [:form {:method "POST" :action "/events"} + [:div.form-group + [:label "Date" + [:input {:type "date" + :id "date" + :name "date" + :value (str (::event/date event))}]]] + [:div.form-group + [:input {:type "submit" + :value "Create Event"}]]])) + +(defn events-routes [{:keys [db]}] + (context "/events" [] + (GET "/" [] + (let [events (db/list db :event)] + (events-index events))) + + (GET "/new" [date] + (page-response + {:title "New Event"} + (event-form {::event/date date}))) + + (POST "/" [date] + (let [event (db.event/create! db {::event/date date})] + (-> (str "/signup-forms/" (::event/id event)) + redirect + (assoc-in [:flash :message] "Event Created")))))) diff --git a/users/grfn/bbbg/src/bbbg/handlers/home.clj b/users/grfn/bbbg/src/bbbg/handlers/home.clj new file mode 100644 index 000000000000..d5ba72878ab1 --- /dev/null +++ b/users/grfn/bbbg/src/bbbg/handlers/home.clj @@ -0,0 +1,17 @@ +(ns bbbg.handlers.home + (:require + [bbbg.handlers.core :refer [page-response]] + [compojure.core :refer [GET routes]])) + +(defn- home-page [] + [:nav.home-nav + [:ul + [:li [:a {:href "/signup-forms"} + "Event Signup Form"]] + [:li [:a {:href "/login"} + "Sign In"]]]]) + +(defn home-routes [_env] + (routes + (GET "/" [] + (page-response (home-page))))) diff --git a/users/grfn/bbbg/src/bbbg/handlers/signup_form.clj b/users/grfn/bbbg/src/bbbg/handlers/signup_form.clj new file mode 100644 index 000000000000..8c4958f1035a --- /dev/null +++ b/users/grfn/bbbg/src/bbbg/handlers/signup_form.clj @@ -0,0 +1,57 @@ +(ns bbbg.handlers.signup-form + (:require + [bbbg.db :as db] + [bbbg.db.event :as db.event] + [bbbg.event :as event] + [bbbg.handlers.core :refer [page-response]] + [compojure.core :refer [GET context]] + [java-time :refer [local-date]] + [ring.util.response :refer [redirect]])) + +(defn no-events-page [] + [:div.no-events + [:p + "There are no events for today"] + [:p + [:a {:href (str "/events/new?date=" (str (local-date)))} "Create Event"] + [:a {:href "/events"} "All Events"]]]) + +(defn signup-page [event] + [:div.signup-page + [:form#signup-form + {:method "POST" + :action "/event_attendees" + :disabled "disabled"} + [:input#event-id {:type "hidden" :name "event_id" :value (::event/id event)}] + [:input#attendee-id {:type "hidden" :name "attendee_id"}] + [:label "Name" + [:input#name-autocomplete + {:type "search" + :name "name" + :spellcheck "false" + :autocorrect "off" + :autocomplete "off" + :autocapitalize "off" + :maxlength "2048"}]] + [:input {:type "submit" + :value "Sign In" + :disabled "disabled"}]]]) + +(defn event-not-found [] + [:div.event-not-found + [:p "Event not found"] + [:p [:a {:href (str "/events/new")} "Create a new event"]]]) + +;;; + +(defn signup-form-routes [{:keys [db]}] + (context "/signup-forms" [] + (GET "/" [] + (if-let [event (db/fetch db (db.event/today))] + (redirect (str "/signup-forms/" (::event/id event))) + (page-response (no-events-page)))) + + (GET "/:event-id" [event-id] + (if-let [event (db/get db :event event-id)] + (page-response (signup-page event)) + (event-not-found))))) diff --git a/users/grfn/bbbg/src/bbbg/styles.clj b/users/grfn/bbbg/src/bbbg/styles.clj new file mode 100644 index 000000000000..07ed87ba1a40 --- /dev/null +++ b/users/grfn/bbbg/src/bbbg/styles.clj @@ -0,0 +1,9 @@ +(ns bbbg.styles + (:require [garden.def :refer [defstyles]] + [garden.compiler :refer [compile-css]])) + +(defstyles styles + ) + +(def stylesheet + (compile-css styles)) diff --git a/users/grfn/bbbg/src/bbbg/util/core.clj b/users/grfn/bbbg/src/bbbg/util/core.clj new file mode 100644 index 000000000000..7f2a8516bf86 --- /dev/null +++ b/users/grfn/bbbg/src/bbbg/util/core.clj @@ -0,0 +1,117 @@ +(ns bbbg.util.core + (:import java.util.UUID)) + +(defn remove-nils + "Remove all keys with nil values from m" + [m] + (let [!m (transient m)] + (doseq [[k v] m] + (when (nil? v) + (dissoc! !m k))) + (persistent! !m))) + + +(defn alongside + "Apply a pair of functions to the first and second element of a two element + vector, respectively. The two argument form partially applies, such that: + + ((alongside f g) xy) ≡ (alongside f g xy) + + This is equivalent to (***) in haskell's Control.Arrow" + ([f g] (partial alongside f g)) + ([f g [x y]] [(f x) (g y)])) + +(defn map-kv + "Map a pair of functions over the keys and values of a map, respectively. + Preserves metadata on the incoming map. + The two argument form returns a transducer that yields map-entries. + + (partial map-kv identity identity) ≡ identity" + ([kf vf] + (map (fn [[k v]] + ;; important to return a map-entry here so that callers down the road + ;; can use `key` or `val` + (first {(kf k) (vf v)})))) + ([kf vf m] + (into (empty m) (map-kv kf vf) m))) + +(defn filter-kv + "Returns a map containing the elements of m for which (f k v) returns logical + true. The one-argument form returns a transducer that yields map entries" + ([f] (filter (partial apply f))) + ([f m] + (into (empty m) (filter-kv f) m))) + +(defn map-keys + "Map f over the keys of m. Preserves metadata on the incoming map. The + one-argument form returns a transducer that yields map-entries." + ([f] (map-kv f identity)) + ([f m] (map-kv f identity m))) + +(defn map-vals + "Map f over the values of m. Preserves metadata on the incoming map. The + one-argument form returns a transducer that yields map-entries." + ([f] (map-kv identity f)) + ([f m] (map-kv identity f m))) + +(defn map-keys-recursive [f x] + (cond + (map? x) (map-kv f (partial map-keys-recursive f) x) + (sequential? x) (map (partial map-keys-recursive f) x) + :else x)) + +(defn denamespace [x] + (if (keyword? x) + (keyword (name x)) + (map-keys-recursive denamespace x))) + +(defn reverse-merge + "Like `clojure.core/merge`, except duplicate keys from maps earlier in the + argument list take precedence + + => (merge {:x 1} {:x 2}) + {:x 2} + + => (sut/reverse-merge {:x 1} {:x 2}) + {:x 1}" + [& ms] + (apply merge (reverse ms))) + +(defn invert-map + "Invert the keys and vals of m. Behavior with duplicate vals is undefined. + + => (sut/invert-map {:x 1 :y 2}) + {1 :x 2 :y}" + [m] + (into {} (map (comp vec reverse)) m)) + +(defn ->uuid + "Converts x to uuid, returning nil if x is nil or empty" + [x] + (cond + (not x) nil + (uuid? x) x + (and (string? x) (seq x)) + (UUID/fromString x))) + +(defn key-by + "Create a map from a seq obtaining keys via f + + => (sut/key-by :x [{:x 1} {:x 2 :y 3}]) + {1 {:x 1}, 2 {:x 2 :y 3}}" + [f l] + (into {} (map (juxt f identity)) l)) + +(defn distinct-by + "Like clojure.core/distinct, but can take a function f by which + distinctiveness is calculated" + [distinction-fn coll] + (let [step (fn step [xs seen] + (lazy-seq + ((fn [[f :as xs] seen] + (when-let [s (seq xs)] + (if (contains? seen (distinction-fn f)) + (recur (rest s) seen) + (cons f (step (rest s) (conj seen (distinction-fn f))))))) + xs seen)))] + (step coll #{}))) diff --git a/users/grfn/bbbg/src/bbbg/web.clj b/users/grfn/bbbg/src/bbbg/web.clj new file mode 100644 index 000000000000..4e0566bcc3c6 --- /dev/null +++ b/users/grfn/bbbg/src/bbbg/web.clj @@ -0,0 +1,77 @@ +(ns bbbg.web + (:require + [bbbg.handlers.attendees :as attendees] + [bbbg.handlers.events :as events] + [bbbg.handlers.home :as home] + [bbbg.handlers.signup-form :as signup-form] + [bbbg.styles :refer [stylesheet]] + [clojure.spec.alpha :as s] + [com.stuartsierra.component :as component] + [compojure.core :refer [GET routes]] + [config.core :refer [env]] + [org.httpkit.server :as http-kit] + [ring.middleware.flash :refer [wrap-flash]] + [ring.middleware.keyword-params :refer [wrap-keyword-params]] + [ring.middleware.params :refer [wrap-params]] + [ring.util.response :refer [content-type response resource-response]])) + +(s/def ::port pos-int?) + +(s/def ::config + (s/keys :req [::port])) + +(s/fdef make-server + :args (s/cat :config ::config)) + +(defn env->config [] + (s/assert + ::config + {::port (:port env 8888)})) + +(defn dev-config [] + (s/assert ::config {::port 8888})) + +;;; + +(defn app-routes [env] + (routes + (GET "/main.css" [] + (-> (response stylesheet) + (content-type "text/css"))) + (GET "/main.js" [] + (-> (resource-response "main.js") + (content-type "text/javascript"))) + + (attendees/attendees-routes env) + (signup-form/signup-form-routes env) + (events/events-routes env) + (home/home-routes env))) + +(defn middleware [app] + (-> app + wrap-keyword-params + wrap-params + wrap-flash)) + +(defn handler [this] + (middleware + (app-routes this))) + +(defrecord WebServer [port db] + component/Lifecycle + (start [this] + (assoc this + ::shutdown-fn + (http-kit/run-server + (fn [r] ((handler this) r)) + {:port port}))) + (stop [this] + (if-let [shutdown-fn (::shutdown-fn this)] + (do (shutdown-fn :timeout 100) + (dissoc this ::shutdown-fn)) + this))) + +(defn make-server [{::keys [port]}] + (component/using + (map->WebServer {:port port}) + [:db])) -- cgit 1.4.1