From ee0809ab2b1969181901e5c0cdfcd26d2f0789ae Mon Sep 17 00:00:00 2001 From: Gosha Tcherednitchenko Date: Thu, 30 Jan 2025 14:56:24 +0000 Subject: [PATCH] chore: clean up the codebase Removing most of the stuff added by default by the practical.li templates (while being very grateful to their authors for enabling me to get started). Also re-architecturing the directory structure, and changing the way we start the shadow-cljs build. --- .dir-locals.el | 4 +- .dockerignore | 3 +- .gitignore | 31 ++--- CHANGELOG.md | 22 ---- Dockerfile | 33 +---- Makefile | 25 ++-- build.clj | 9 +- bun.lockb | Bin 73673 -> 22861 bytes cljs/tools/ifs/parts/core.cljs | 32 ----- compose.yaml | 2 +- deps.edn | 68 ++++------ dev/mulog_events.clj | 55 -------- dev/portal.clj | 23 ---- dev/test.http | 27 ---- dev/user.clj | 118 ------------------ package.json | 7 +- {resources/public => public}/css/flow.css | 0 {resources/public => public}/css/style.css | 0 .../images/avatars/gosha.svg | 0 .../images/avatars/tingyi.svg | 0 .../images/icons/favicon.png | Bin .../public => public}/images/nodes/exile.svg | 0 .../images/nodes/firefighter.svg | 0 .../images/nodes/manager.svg | 0 .../images/parts-logo-horizontal.svg | 0 .../images/system-illustration.svg | 0 {resources/public => public}/js/.keep | 0 .../20240821000000-create-users-table.up.sql | 1 + shadow-cljs.edn | 24 +--- src/dev/repl.clj | 26 ++++ src/{tools/ifs => main}/parts/api/account.clj | 6 +- src/{tools/ifs => main}/parts/api/auth.clj | 6 +- src/{tools/ifs => main}/parts/auth.clj | 6 +- src/{tools/ifs => main}/parts/config.clj | 2 +- src/{tools/ifs => main}/parts/db.clj | 4 +- src/{tools/ifs => main}/parts/entity/user.clj | 6 +- src/main/parts/frontend/app.cljs | 9 ++ .../parts => main/parts/handlers}/pages.clj | 24 ++-- .../parts/handlers}/waitlist.clj | 8 +- .../parts/api => main/parts}/middleware.clj | 12 +- .../ifs/parts.clj => main/parts/server.clj} | 54 +++----- .../main.clj => main/parts/views/layouts.clj} | 10 +- .../layouts => main/parts/views}/partials.clj | 4 +- .../ifs => }/parts/api/account_test.clj | 10 +- test/{tools/ifs => }/parts/api/auth_test.clj | 14 +-- test/{tools/ifs => }/parts/auth_test.clj | 10 +- .../ifs => }/parts/entity/user_test.clj | 8 +- .../handlers}/waitlist_test.clj | 10 +- .../ifs => parts}/helpers/test_factory.clj | 2 +- .../helpers/utils.clj} | 8 +- .../parts/api => parts}/middleware_test.clj | 6 +- tests.edn | 11 +- 52 files changed, 201 insertions(+), 539 deletions(-) delete mode 100644 CHANGELOG.md delete mode 100644 cljs/tools/ifs/parts/core.cljs delete mode 100644 dev/mulog_events.clj delete mode 100644 dev/portal.clj delete mode 100644 dev/test.http delete mode 100644 dev/user.clj rename {resources/public => public}/css/flow.css (100%) rename {resources/public => public}/css/style.css (100%) rename {resources/public => public}/images/avatars/gosha.svg (100%) rename {resources/public => public}/images/avatars/tingyi.svg (100%) rename {resources/public => public}/images/icons/favicon.png (100%) rename {resources/public => public}/images/nodes/exile.svg (100%) rename {resources/public => public}/images/nodes/firefighter.svg (100%) rename {resources/public => public}/images/nodes/manager.svg (100%) rename {resources/public => public}/images/parts-logo-horizontal.svg (100%) rename {resources/public => public}/images/system-illustration.svg (100%) rename {resources/public => public}/js/.keep (100%) create mode 100644 src/dev/repl.clj rename src/{tools/ifs => main}/parts/api/account.clj (92%) rename src/{tools/ifs => main}/parts/api/auth.clj (89%) rename src/{tools/ifs => main}/parts/auth.clj (95%) rename src/{tools/ifs => main}/parts/config.clj (94%) rename src/{tools/ifs => main}/parts/db.clj (97%) rename src/{tools/ifs => main}/parts/entity/user.clj (96%) create mode 100644 src/main/parts/frontend/app.cljs rename src/{tools/ifs/parts => main/parts/handlers}/pages.clj (81%) rename src/{tools/ifs/parts => main/parts/handlers}/waitlist.clj (90%) rename src/{tools/ifs/parts/api => main/parts}/middleware.clj (94%) rename src/{tools/ifs/parts.clj => main/parts/server.clj} (74%) rename src/{tools/ifs/parts/layouts/main.clj => main/parts/views/layouts.clj} (90%) rename src/{tools/ifs/parts/layouts => main/parts/views}/partials.clj (95%) rename test/{tools/ifs => }/parts/api/account_test.clj (93%) rename test/{tools/ifs => }/parts/api/auth_test.clj (92%) rename test/{tools/ifs => }/parts/auth_test.clj (91%) rename test/{tools/ifs => }/parts/entity/user_test.clj (95%) rename test/{tools/ifs/parts => parts/handlers}/waitlist_test.clj (90%) rename test/{tools/ifs => parts}/helpers/test_factory.clj (93%) rename test/{tools/ifs/helpers/test_helpers.clj => parts/helpers/utils.clj} (90%) rename test/{tools/ifs/parts/api => parts}/middleware_test.clj (97%) diff --git a/.dir-locals.el b/.dir-locals.el index 01afde7..d1da6a8 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -1,5 +1,5 @@ ((clojure-mode . ((cider-preferred-build-tool . clojure-cli) (cider-default-cljs-repl . shadow) - (cider-shadow-default-options . "app") + (cider-shadow-default-options . "frontend") (cider-offer-to-open-cljs-app-in-browser . nil) - (cider-clojure-cli-aliases . ":test/env:dev/reloaded")))) + (cider-clojure-cli-aliases . ":test/env")))) diff --git a/.dockerignore b/.dockerignore index 25421cc..866c41e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -20,7 +20,6 @@ !build.clj !Makefile !src/ -!cljs/ !test/ -!test-data/ +!public/ !resources/ diff --git a/.gitignore b/.gitignore index aa46f39..dc43b29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,10 @@ -# ------------------------ -# Clojure Project Git Ignore file patterns -# -# Ignore all except patterns starting with ! -# Add comments on separate lines, not same line as pattern -# ------------------------ - -# ------------------------ # Ignore everthing in root directory /* -# ------------------------ -# Common project files !CHANGELOG.md !README.md !LICENSE -# ------------------------ -# Include Clojure project & config !build.clj !deps.edn !pom.xml @@ -24,12 +12,15 @@ !docs/ !src/ !test/ -!config.edn - -# Don't ignore resources !resources/ -# ...but ignore shadow-cljs build artifacts -resources/public/js + +# ------------------------ +# Public directory rules +!public/ +# Handle js subdirectory specifically +!public/js/ +public/js/* +!public/js/.keep # ------------------------ # Include Clojure tools @@ -43,7 +34,6 @@ resources/public/js # ------------------------ # Frontend things -!cljs !shadow-cljs.edn !package.json !bun.lockb @@ -54,11 +44,6 @@ resources/public/js !.gitignore !.github/ -# ------------------------ -# Include ClojureScript Figwheel -!figwheel-main.edn -!*.cljs.edn - # ------------------------ # Include deployment related files !config diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index bee0b81..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,22 +0,0 @@ -# apossiblespace/parts Changelog - -All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - -* **Added** for new features -* **Changed** for changes in existing functionality -* **Deprecated** for soon-to-be removed features -* **Resolved** resolved issue -* **Security** vulnerability related change - -## [Unreleased] - -### Changed - -## 0.1.0 - 2024-08-06 - -### Added - -* [#1](https://github.com/practicalli/clojure/issues/1) Created apossiblespace/parts project with deps-new using practicalli.template/service - -[Unreleased]: https://github.com/apossiblespace/parts/compare/0.1.1...HEAD diff --git a/Dockerfile b/Dockerfile index 8d7b340..6e4f52f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,26 +1,5 @@ -# ------------------------------------------ -# Build and run Practicalli Gameboard API Service -# -# Author: Practicalli -# -# Builder image: -# Official Clojure Docker image with Java 17 (eclipse-temurin) and Clojure CLI -# https://hub.docker.com/_/clojure/ -# -# Run-time image: -# Official Java Docker image with Java 17 (eclipse-temurin) -# https://hub.docker.com/_/eclipse-temurin -# ------------------------------------------ - - -# ------------------------ -# Setup Builder container - FROM clojure:temurin-17-alpine AS builder -# Set Clojure CLI version (defaults to latest release) -# ENV CLOJURE_VERSION=1.11.1.1413 - # Create directory for project code (working directory) RUN mkdir -p /build @@ -40,14 +19,6 @@ RUN apk add --no-cache nodejs npm RUN npm install - -# ------------------------ -# Test and Package application via Makefile -# `make all` calls `deps`, `test-ci`, `dist` and `clean` tasks -# using shared library cache mounted by pipeline process - -RUN npx shadow-cljs release app - # `dist` task packages Clojure service as an uberjar # - creates: /build/practicalli-gameboard-api-service.jar # - uses command `clojure -T:build uberjar` @@ -94,7 +65,7 @@ USER clojure # Copy service archive file from Builder image WORKDIR /app -COPY --from=builder /build/target/tools-ifs-parts-standalone.jar /app/ +COPY --from=builder /build/target/parts-standalone.jar /app/ # Optional: Add System Integration testing scripts # RUN mkdir -p /app/test-scripts @@ -136,7 +107,7 @@ ENV JDK_JAVA_OPTIONS="-XshowSettings:system -XX:+UseContainerSupport -XX:MaxRAMP # Start service using dumb-init and java run-time # (overrides `jshell` entrypoint - default in eclipse-temuring image) ENTRYPOINT ["/usr/bin/dumb-init", "--"] -CMD ["java", "-jar", "/app/tools-ifs-parts-standalone.jar"] +CMD ["java", "-jar", "/app/parts-standalone.jar"] # Docker Entrypoint documentation diff --git a/Makefile b/Makefile index fbfc92c..e63e324 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,6 @@ # - `:env/dev` to include `dev` directory on class path # - `:env/test` to include `test` directory and libraries to support testing # - `:test/run` to run kaocha kaocha test runner and supporting paths and dependencies -# - `:repl/rebel` to start a Rebel terminal UI # - `:package/uberjar` to create an uberjar for the service # - docker # - mega-linter-runner @@ -28,7 +27,8 @@ HELP-DESCRIPTION-SPACING := 24 # Tool variables -MEGALINTER_RUNNER = npx mega-linter-runner --flavor java --env "'MEGALINTER_CONFIG=.github/config/megalinter.yaml'" --remove-container +FORMATTER_RUNNER = bunx @chrisoakman/standard-clojure-style +MEGALINTER_RUNNER = bunx mega-linter-runner --flavor java --env "'MEGALINTER_CONFIG=.github/config/megalinter.yaml'" --remove-container CLOJURE_TEST_RUNNER = clojure -M:test/env:test/run CLOJURE_EXEC_TEST_RUNNER = clojure -X:test/env:test/run @@ -48,15 +48,15 @@ help: ## Describe available tasks in Makefile # ------------------------------------ # # ------- Clojure Development -------- # -repl: ## Run Clojure REPL with rich terminal UI (Rebel Readline) - $(info --------- Run Rebel REPL ---------) - clojure -M:test/env:repl/reloaded +repl: ## Run Clojure REPL + $(info --------- Run REPL with Shadow ---------) + clojure -M -m shadow.cljs.devtools.cli clj-repl deps: deps.edn ## Prepare dependencies for test and dist targets $(info --------- Download test and service libraries ---------) clojure -P -X:build -dist: build-uberjar ## Build and package Clojure service +dist: build-frontend build-uberjar ## Build and package Clojure service $(info --------- Build and Package Clojure service ---------) # Remove files and directories after build tasks @@ -101,6 +101,10 @@ build-jar: ## Build a jar archive of Clojure project $(info --------- Build library jar ---------) clojure -T:build/task jar +build-frontend: ## Build shadow-cljs frontend app + $(info --------- Build frontend ---------) + clojure -M -m shadow.cljs.devtools.cli release frontend + build-uberjar: ## Build a uberjar archive of Clojure project & Clojure runtime $(info --------- Build service Uberjar ---------) clojure -T:build/task uberjar @@ -111,16 +115,17 @@ build-clean: ## Clean build assets or given directory # ------------------------------------ # # ------- Code Quality --------------- # -pre-commit-check: format-check lint test ## Run format, lint and test targets +pre-commit-check: format lint test ## Run format, lint and test targets -format-check: ## Run cljstyle to check the formatting of Clojure code +format: ## Run cljstyle to check the formatting of Clojure code $(info --------- standard-clojure-style-js Runner ---------) - standard-clj check . + $(FORMATTER_RUNNER) check . format-fix: ## Run cljstyle and fix the formatting of Clojure code $(info --------- standard-clojure-style-js Runner ---------) - standard-clj fix . + $(FORMATTER_RUNNER) fix . +# TODO: Reconsider how useful this is lint: ## Run MegaLinter with custom configuration (node.js required) $(info --------- MegaLinter Runner ---------) $(MEGALINTER_RUNNER) diff --git a/build.clj b/build.clj index e7ae07b..55ae783 100644 --- a/build.clj +++ b/build.clj @@ -30,9 +30,9 @@ (def project-config "Project configuration to support all tasks" {:class-directory "target/classes" - :main-namespace 'tools.ifs/parts + :main-namespace 'parts/server :project-basis (build-api/create-basis) - :uberjar-file "target/tools-ifs-parts-standalone.jar"}) + :uberjar-file "target/parts-standalone.jar"}) (defn config "Display build configuration" @@ -63,7 +63,7 @@ (let [config (merge project-config options) {:keys [class-directory main-namespace project-basis uberjar-file]} config] (clean "target") - (build-api/copy-dir {:src-dirs ["src" "resources"] + (build-api/copy-dir {:src-dirs ["src/main" "resources" "public"] :target-dir class-directory}) (build-api/compile-clj {:basis project-basis @@ -74,6 +74,3 @@ :class-dir class-directory :main main-namespace :uber-file uberjar-file}))) - -;; End of Build tasks -;; --------------------------------------------------------- diff --git a/bun.lockb b/bun.lockb index cffb42a931a96fbe7fefde3f326fadc39398c8c9..53f3cce56a4d132be6366ba22ee30322c9137cb1 100755 GIT binary patch delta 4404 zcmb_fdr*|u6~Eu*`GJcpLR|<7ijp85?S&T7-016RU1QanbOU$$} z6s>ri#575h=%m#oO%ts~CZ@5DCef*XSUd4eG&3r7(l*l>XVli(-}xRcw$o0h<_Vxf#&TF4nW)?>T zx<08AM#=Bk0qI);=BOrG`4u@R3s=cG8rB1XV9R*uwoTPQ2>W% zsu-@RN5H0mjUcB(Q&mh?uFYhDLdV8?Wv4<>>0b2!Y}4&}a=N6Rbgz6#(lOZLktYvq zAx0~$V6zN%B2H6xgUz^W`zu)fUE73EAs)HQTEI-3Gf7i_4raE=t(*t*-t|mE+JpVg z2jhBSEQs0m)R9m}NHQ1+#1>c?OlQ3#!IYVt-n9fQju zBy^#n;o`iCyp+xU$Ja&x9xUotwvqB#l+ZtpT(n&Bg zFpeP>>xDf-sV_rQ=Yd&4V_te4)HBhm{?2kSWR8M?B6S-op-qnT_!v z6l{H~X?S|U%vLZ6*)^Pcvc2jNC`-_EH1%a`Y7BNv8JHwzx+WisrP3U4*y~W{)5h3b ziX9e8leUBgka~fv@QER?uX#ThWvE29c_Z^_Aw~mSXDon4E7AbAKLjALTPX^kb9LE>Z*%>ed;SPj^PQ*l2j3~-0{ znZx@@VcCp= zDWla#Ysww8u~k#;(_nuBOQ9)kKH4zfL9e&z${6}1SbhcK zYuA-DdZiulf!zihPbD3QZvo=#(3J=2CRp)8#J5UUGHBN-#0TbBtt*+dcs1f%g!sU+ zNbN*?m58rXS0++FSmdLKZ;h^GQ{x)M2X-7RmlC@WpAYeM>B?j}3g)Upd~0<@qpr2{ z_AI2$p?l`jhN!4iTy$LW^6ANaz#cQ^%@3gC3-^PcZzz9Ga6U?wmN zm<>Dv6asSq+?RawPUF*Glma?{vtP^w<^dJJ0)P+Y3BbbupEeEL8_JAn99@9>=cqV3 zUd=ov9vdIMd>r%n&Ign2!;$kh|LWlbitV<|h3}ET_W+KaeVhQ_A$*9jzwOKS&z(DW z0)ScAfSbywfZNlkg!|pNoLG;Gj(?~b)6WgY0IcV4?vN)MzuS!OEJ&VozE^lalK{S~ zcpi9QV*$RL+uC7zs2AOqkGr30L;aljZL6-WU%bEAM{fIEEv;Et03UMQ?f1Godb zLmmw4ZQDIFR}TYE{XNPdI(z#5b*i~Bdy0on@6dF#@_IsPDx%Uu>C|&5bFuP7_7wLd zH_wOp(0JN4?N;Lpi~tGQp!-1ybvGO0kT zxwG>`wV)?Xxjdb4z-)H!fB);(=JZz_G8}T*p%)e;qPzC;TdUsqas4V-+=fBy5cK9H zm)tGrvr}bKC=`EsnKYDT9{aJee$pEUZ*2eU&lrm4&g0SB&yf#f-pMZ*{kNxK$wgeq zcdVp;oOa1HNv<bu)r)X8x1y=W^A!K*-^p$BTjvyCP}Q zS9Uw*YZ$NRzeHC4^qZs)gKlPWq?z92|D0ZPZCQ)YT!MwslytGo+FRtgG?JE{9u=f{ zykMIy~IY3oxj=mSk~n4 VeEGK#O6o_~!j&Dd)c4}He**D51rPuL literal 73673 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 gfh+8yufn)F)_e(js nodes) - :edges (clj->js edges) - :fitView true}) - ($ Background) - ($ Controls))))) - -(defonce root - (uix.dom/create-root (js/document.getElementById "root"))) - -(defn ^:export init [] - (uix.dom/render-root - ($ flow-diagram) - root)) diff --git a/compose.yaml b/compose.yaml index b404889..97bcf15 100644 --- a/compose.yaml +++ b/compose.yaml @@ -13,7 +13,7 @@ name: "parts" services: # --- Clojure Service --- # - parts-ifs-tools: + parts: platform: linux/amd64 # Build using Dockerfile - relative path or Git repository build: diff --git a/deps.edn b/deps.edn index 95576f8..fd3f0aa 100644 --- a/deps.edn +++ b/deps.edn @@ -1,26 +1,25 @@ -{;; --------------------------------------------------------- - :paths - ["src" "resources" "cljs"] - ;; --------------------------------------------------------- - - ;; --------------------------------------------------------- +{:paths ["src/main" "src/dev" "resources"] :deps - {;; Service - org.clojure/clojure {:mvn/version "1.12.0"} - com.brunobonacci/mulog {:mvn/version "0.9.0"} + {org.clojure/clojure {:mvn/version "1.12.0"} http-kit/http-kit {:mvn/version "2.8.0"} metosin/reitit {:mvn/version "0.7.2"} - metosin/muuntaja {:mvn/version "0.6.10"} + ;; + ;; Auth-related things buddy/buddy-auth {:mvn/version "3.0.323"} buddy/buddy-hashers {:mvn/version "2.0.167"} - com.github.seancorfield/next.jdbc {:mvn/version "1.3.955"} - org.xerial/sqlite-jdbc {:mvn/version "3.47.0.0"} + ;; + ;; Database-related things + com.github.seancorfield/next.jdbc {:mvn/version "1.3.981"} + org.xerial/sqlite-jdbc {:mvn/version "3.48.0.0"} migratus/migratus {:mvn/version "1.6.3"} - com.github.seancorfield/honeysql {:mvn/version "2.6.1203"} + com.github.seancorfield/honeysql {:mvn/version "2.6.1270"} + ring/ring-json {:mvn/version "0.5.1"} ring/ring-mock {:mvn/version "0.4.0"} - ;; Simple logging implementation using by Buddy for ex + + ;; Logging org.slf4j/slf4j-simple {:mvn/version "2.0.16"} + com.brunobonacci/mulog {:mvn/version "0.9.0"} ;; ;; A small library for explicit, intentful configuration. ;; https://github.com/juxt/aero @@ -30,37 +29,30 @@ ;; secure default configurations of Ring middleware for both websites and HTTP ;; APIs. ;; https://github.com/ring-clojure/ring-defaults - ring/ring-defaults {:mvn/version "0.5.0"} + ring/ring-defaults {:mvn/version "0.6.0"} ;; ;; Hiccup is a library for representing HTML in Clojure. It uses vectors to ;; represent elements, and maps to represent an element's attributes. ;; https://github.com/weavejester/hiccup - hiccup/hiccup {:mvn/version "2.0.0-RC3"} + hiccup/hiccup {:mvn/version "2.0.0-RC4"} ;; ;; Clojurescript ;; https://github.com/clojure/clojurescript - org.clojure/clojurescript {:mvn/version "1.11.132"}} + org.clojure/clojurescript {:mvn/version "1.11.132"} + ;; + ;; shadow-cljs + ;; https://code.thheller.com/blog/shadow-cljs/2024/10/18/fullstack-cljs-workflow-with-shadow-cljs.html + thheller/shadow-cljs {:mvn/version "2.28.20"} + cider/cider-nrepl {:mvn/version "0.51.1"} + refactor-nrepl/refactor-nrepl {:mvn/version "3.10.0"}} - ;; --------------------------------------------------------- :aliases - {;; ------------ - ;; Clojure.main execution of application - :run/app - {:main-opts ["-m" "tools.ifs.parts"]} + {:run/app + {:main-opts ["-m" "parts.server"]} - ;; Clojure.exec execution of specified function - :run/greet - {:exec-fn tools.ifs.parts/greet - :exec-args {:name "Clojure"}} - ;; ------------ - - ;; ------------ - ;; Add libraries and paths to support additional test tools :test/env {} - ;; Test runner - local and CI - ;; call with :watch? true to start file watcher and re-run tests on saved changes :test/run {:extra-paths ["test"] :extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}} @@ -69,20 +61,12 @@ :exec-fn kaocha.runner/exec-fn :exec-args {:randomize? false :fail-fast? false}} - ;; ------------ - - ;; ------------ - ;; tools.build `build.clj` built script :build/task {:replace-paths ["."] - :replace-deps {io.github.clojure/tools.build {:mvn/version "0.10.5"}} + :replace-deps {io.github.clojure/tools.build {:mvn/version "0.10.6"}} :ns-default build} - ;; ------------ - ;; ------------ ;; Updating dependencies with clojure -M:antq --upgrade :antq - {:deps {com.github.liquidz/antq {:mvn/version "2.10.1241"}} + {:deps {com.github.liquidz/antq {:mvn/version "2.11.1264"}} :main-opts ["-m" "antq.core"]}}} -;; ------------ -;; --------------------------------------------------------- diff --git a/dev/mulog_events.clj b/dev/mulog_events.clj deleted file mode 100644 index fa68482..0000000 --- a/dev/mulog_events.clj +++ /dev/null @@ -1,55 +0,0 @@ -;; --------------------------------------------------------- -;; Mulog Global Context and Custom Publisher -;; -;; - set event log global context -;; - tap publisher for use with Portal and other tap sources -;; - publish all mulog events to Portal tap source -;; --------------------------------------------------------- - -(ns mulog-events - (:require - [com.brunobonacci.mulog :as mulog] - [com.brunobonacci.mulog.buffer :as mulog-buffer])) - -;; --------------------------------------------------------- -;; Set event global context -;; - information added to every event for REPL workflow -(mulog/set-global-context! {:app-name "parts Service" - :version "0.1.0", :env "dev"}) -;; --------------------------------------------------------- - -;; --------------------------------------------------------- -;; Mulog event publishing - -(deftype TapPublisher - [buffer transform] - com.brunobonacci.mulog.publisher.PPublisher - (agent-buffer [_] buffer) - (publish-delay [_] 200) - (publish [_ buffer] - (doseq [item (transform (map second (mulog-buffer/items buffer)))] - (tap> item)) - (mulog-buffer/clear buffer))) - -#_{:clj-kondo/ignore [:unused-private-var]} -(defn ^:private tap-events - [{:keys [transform] :as _config}] - (TapPublisher. (mulog-buffer/agent-buffer 10000) (or transform identity))) - -(def tap-publisher - "Start mulog custom tap publisher to send all events to Portal - and other tap sources - `mulog-tap-publisher` to stop publisher" - (mulog/start-publisher! - {:type :custom, :fqn-function "mulog-events/tap-events"})) - -#_{:clj-kondo/ignore [:unused-public-var]} -(defn stop - "Stop mulog tap publisher to ensure multiple publishers are not started - Recommended before using `(restart)` or evaluating the `user` namespace" - [] - tap-publisher) - -;; Example mulog event message -;; (mulog/log ::dev-user-ns :message "Example event message" :ns (ns-publics *ns*)) -;; --------------------------------------------------------- diff --git a/dev/portal.clj b/dev/portal.clj deleted file mode 100644 index bf371fb..0000000 --- a/dev/portal.clj +++ /dev/null @@ -1,23 +0,0 @@ -(ns portal - (:require - ;; Data inspector - [portal.api :as inspect])) - -;; --------------------------------------------------------- -;; Start Portal and capture all evaluation results - -;; Open Portal window in browser with dark theme -;; https://cljdoc.org/d/djblue/portal/0.37.1/doc/ui-concepts/themes -;; Portal options: -;; - light theme {:portal.colors/theme :portal.colors/solarized-light} -;; - dark theme {:portal.colors/theme :portal.colors/gruvbox} - -(def instance - "Open portal window if no portal sessions have been created. - A portal session is created when opening a portal window" - (or (seq (inspect/sessions)) - (inspect/open {:portal.colors/theme :portal.colors/gruvbox}))) - -;; Add portal as tapsource (add to clojure.core/tapset) -(add-tap #'portal.api/submit) -;; --------------------------------------------------------- diff --git a/dev/test.http b/dev/test.http deleted file mode 100644 index 295bf68..0000000 --- a/dev/test.http +++ /dev/null @@ -1,27 +0,0 @@ -# Test requests for restclient.el - -# Health check -GET http://localhost:3000/api/ping - -# Working login -POST http://localhost:3000/api/auth/login -Content-Type: application/json - -{ - "email": "test2@example.com", - "password": "password2" -} - -# Failing login -POST http://localhost:3000/api/auth/login -Content-Type: application/json - -{ - "email": "bob@bobson.com", - "password": "4321tset" -} - -# Get account info -GET http://localhost:3000/api/account -Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAvYXBpIiwic3ViIjoiY2M1YTVkMTYtYjgzYS00OTZkLTk5M2EtOTM2ZjQxOGUxZDNlIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwIiwiaWF0IjoxNzI1NjMzODgzLCJleHAiOjE3MjU2Mzc0ODN9.hDjmDNvy2MNwGP6Th0Jl8THSq9bbg6APv4WndbvOBUk -Content-Type: application/json diff --git a/dev/user.clj b/dev/user.clj deleted file mode 100644 index 584d0e8..0000000 --- a/dev/user.clj +++ /dev/null @@ -1,118 +0,0 @@ -;; --------------------------------------------------------- -;; REPL workflow development tools -;; -;; Include development tool libraries vai aliases from practicalli/clojure-cli-config -;; Start Rich Terminal UI REPL prompt: -;; `clojure -M:repl/reloaded` -;; -;; Or call clojure jack-in from an editor to start a repl -;; including the `:dev/reloaded` alias -;; - alias included in the Emacs `.dir-locals.el` file -;; --------------------------------------------------------- - -(ns user - "Tools for REPL Driven Development" - (:require - [clojure.tools.namespace.repl :as namespace] - [com.brunobonacci.mulog :as mulog] ; Global context & Tap publisher - ;; REPL Workflow - [mulog-events] ; Event Logging - [portal] - [portal.api :as inspect] ; Data inspector - [tools.ifs.parts :as parts] - [tools.ifs.parts.api.account :as account] - [tools.ifs.parts.api.auth :as auth] - [tools.ifs.parts.api.middleware :as middleware] - [tools.ifs.parts.config :as config] - [tools.ifs.parts.db :as db])) - -;; --------------------------------------------------------- -;; Help - -(println "---------------------------------------------------------") -(println "Loading custom user namespace tools...") -(println "---------------------------------------------------------") - -(defn help - [] - (println "---------------------------------------------------------") - (println "Namesapece Management:") - (println "(namespace/refresh) ; refresh all changed namespaces") - (println "(namespace/refresh-all) ; refresh all namespaces") - (println) - (println "Hotload libraries: ; Clojure 1.12.x") - (println "(add-lib 'library-name)") - (println "(add-libs '{domain/library-name {:mvn/version \"v1.2.3\"}})") - (println "(sync-deps) ; load dependencies from deps.edn") - (println "- deps-* lsp snippets for adding library") - (println) - (println "Portal Inspector:") - (println "- portal started by default, listening to all evaluations") - (println "(inspect/clear) ; clear all values in portal") - (println "(remove-tap #'inspect/submit) ; stop sending to portal") - (println "(inspect/close) ; close portal") - (println) - (println "Mulog Publisher:") - (println "- mulog publisher started by default") - (println "(mulog-events/stop) ; stop publishing log events") - (println) - (println "(help) ; print help text") - (println "---------------------------------------------------------")) - -(help) - -;; End of Help -;; --------------------------------------------------------- - -;; --------------------------------------------------------- -;; Avoid reloading `dev` code -;; - code in `dev` directory should be evaluated if changed to reload into repl -(println - "Set REPL refresh directories to " - (namespace/set-refresh-dirs "src" "resources")) -;; --------------------------------------------------------- - -;; --------------------------------------------------------- -;; Mulog event logging -;; `mulog-publisher` namespace used to launch tap> events to tap-source (portal) -;; `mulog-events` namespace sets mulog global context for all events - -;; Example mulog event message -(mulog/log ::dev-user-ns - :message "Example event from user namespace" - :ns (ns-publics *ns*)) -;; --------------------------------------------------------- - -;; --------------------------------------------------------- -;; Hotload libraries into running REPL -;; `deps-*` LSP snippets to add dependency forms -(comment - ;; Require for Clojure 1.11.x and earlier - (require '[clojure.tools.deps.alpha.repl :refer [add-libs]]) - (add-libs '{domain/library-name {:mvn/version "1.0.0"}}) - - ;; Clojure 1.12.x only - #_(add-lib 'library-name) ; find and add library - #_(sync-deps) ; load dependencies in deps.edn (if not yet loaded) - #_()) ; End of rich comment -;; --------------------------------------------------------- - -;; --------------------------------------------------------- -;; Portal Data Inspector -(comment - ;; Open a portal inspector in browser window - light theme - ;; (inspect/open {:portal.colors/theme :portal.colors/solarized-light}) - - (inspect/clear) ; Clear all values in portal window (allows garbage collection) - - (remove-tap #'inspect/submit) ; Remove portal from `tap>` sources - - (inspect/close) ; Close the portal window - - (inspect/docs) ; View docs locally via Portal - - (mulog-events/stop) ; stop publishing log events - - #_()) ; End of rich comment - -;; --------------------------------------------------------- diff --git a/package.json b/package.json index 8631280..4e51306 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,8 @@ { "dependencies": { - "d3": "^7.9.0", "htmx.org": "^2.0.2", "react": "^19.0.0", "react-dom": "^19.0.0", - "reactflow": "^11.11.4", - "shadow-cljs": "^2.28.15" - }, - "scripts": { - "watch": "shadow-cljs watch app" + "reactflow": "^11.11.4" } } diff --git a/resources/public/css/flow.css b/public/css/flow.css similarity index 100% rename from resources/public/css/flow.css rename to public/css/flow.css diff --git a/resources/public/css/style.css b/public/css/style.css similarity index 100% rename from resources/public/css/style.css rename to public/css/style.css diff --git a/resources/public/images/avatars/gosha.svg b/public/images/avatars/gosha.svg similarity index 100% rename from resources/public/images/avatars/gosha.svg rename to public/images/avatars/gosha.svg diff --git a/resources/public/images/avatars/tingyi.svg b/public/images/avatars/tingyi.svg similarity index 100% rename from resources/public/images/avatars/tingyi.svg rename to public/images/avatars/tingyi.svg diff --git a/resources/public/images/icons/favicon.png b/public/images/icons/favicon.png similarity index 100% rename from resources/public/images/icons/favicon.png rename to public/images/icons/favicon.png diff --git a/resources/public/images/nodes/exile.svg b/public/images/nodes/exile.svg similarity index 100% rename from resources/public/images/nodes/exile.svg rename to public/images/nodes/exile.svg diff --git a/resources/public/images/nodes/firefighter.svg b/public/images/nodes/firefighter.svg similarity index 100% rename from resources/public/images/nodes/firefighter.svg rename to public/images/nodes/firefighter.svg diff --git a/resources/public/images/nodes/manager.svg b/public/images/nodes/manager.svg similarity index 100% rename from resources/public/images/nodes/manager.svg rename to public/images/nodes/manager.svg diff --git a/resources/public/images/parts-logo-horizontal.svg b/public/images/parts-logo-horizontal.svg similarity index 100% rename from resources/public/images/parts-logo-horizontal.svg rename to public/images/parts-logo-horizontal.svg diff --git a/resources/public/images/system-illustration.svg b/public/images/system-illustration.svg similarity index 100% rename from resources/public/images/system-illustration.svg rename to public/images/system-illustration.svg diff --git a/resources/public/js/.keep b/public/js/.keep similarity index 100% rename from resources/public/js/.keep rename to public/js/.keep diff --git a/resources/migrations/20240821000000-create-users-table.up.sql b/resources/migrations/20240821000000-create-users-table.up.sql index 82f82fa..5cda577 100644 --- a/resources/migrations/20240821000000-create-users-table.up.sql +++ b/resources/migrations/20240821000000-create-users-table.up.sql @@ -15,3 +15,4 @@ FOR EACH ROW BEGIN UPDATE users SET updated_at = CURRENT_TIMESTAMP WHERE id = OLD.id; END; +--;; diff --git a/shadow-cljs.edn b/shadow-cljs.edn index cab4678..9ac974c 100644 --- a/shadow-cljs.edn +++ b/shadow-cljs.edn @@ -1,20 +1,8 @@ -{:source-paths - ["cljs"] - - :dependencies - [[cider/cider-nrepl "0.51.1"] - [refactor-nrepl/refactor-nrepl "3.10.0"]] - - :nrepl - {:middleware [cider.nrepl/cider-middleware - refactor-nrepl.middleware/wrap-refactor] - :port 50655} - +{:deps true + :nrepl {:init-ns repl} :builds - {:app + {:frontend {:target :browser - :output-dir "resources/public/js" - :asset-path "/js" - :modules {:main {:init-fn tools.ifs.parts.core/init}} - :devtools {:http-root "resources/public" - :http-port 8020}}}} + :modules {:main {:init-fn parts.frontend.app/init}} + :devtools {:watch-dir "public"} + :optimizations :advanced}}} diff --git a/src/dev/repl.clj b/src/dev/repl.clj new file mode 100644 index 0000000..1953375 --- /dev/null +++ b/src/dev/repl.clj @@ -0,0 +1,26 @@ +(ns repl + (:require + [parts.server :as server] + [shadow.cljs.devtools.api :as shadow] + [shadow.cljs.devtools.server :as shadow-server])) + +(defonce server-ref (atom nil)) + +;; TODO: Do we also want to open Inspector automatically? +(defn start [] + (shadow-server/start!) + (shadow/watch :frontend) + + (reset! server-ref + (server/-main)) + ::started) + +(defn stop [] + (when-some [stop-server @server-ref] + (reset! server-ref nil) + (stop-server)) + ::stopped) + +(defn go [] + (stop) + (start)) diff --git a/src/tools/ifs/parts/api/account.clj b/src/main/parts/api/account.clj similarity index 92% rename from src/tools/ifs/parts/api/account.clj rename to src/main/parts/api/account.clj index 1592bd4..75b56ce 100644 --- a/src/tools/ifs/parts/api/account.clj +++ b/src/main/parts/api/account.clj @@ -1,8 +1,8 @@ -(ns tools.ifs.parts.api.account +(ns parts.api.account (:require [com.brunobonacci.mulog :as mulog] - [ring.util.response :as response] - [tools.ifs.parts.entity.user :as user])) + [parts.entity.user :as user] + [ring.util.response :as response])) (defn get-account "Retrieve own account info" diff --git a/src/tools/ifs/parts/api/auth.clj b/src/main/parts/api/auth.clj similarity index 89% rename from src/tools/ifs/parts/api/auth.clj rename to src/main/parts/api/auth.clj index 30a2e48..7aad7cd 100644 --- a/src/tools/ifs/parts/api/auth.clj +++ b/src/main/parts/api/auth.clj @@ -1,8 +1,8 @@ -(ns tools.ifs.parts.api.auth +(ns parts.api.auth (:require [com.brunobonacci.mulog :as mulog] - [ring.util.response :as response] - [tools.ifs.parts.auth :as auth])) + [parts.auth :as auth] + [ring.util.response :as response])) (defn login [request] diff --git a/src/tools/ifs/parts/auth.clj b/src/main/parts/auth.clj similarity index 95% rename from src/tools/ifs/parts/auth.clj rename to src/main/parts/auth.clj index 0f9a9f4..8e0bbb0 100644 --- a/src/tools/ifs/parts/auth.clj +++ b/src/main/parts/auth.clj @@ -1,11 +1,11 @@ -(ns tools.ifs.parts.auth +(ns parts.auth (:require [buddy.auth.backends :as backends] [buddy.hashers :as hashers] [buddy.sign.jwt :as jwt] [com.brunobonacci.mulog :as mulog] - [tools.ifs.parts.config :as conf] - [tools.ifs.parts.db :as db]) + [parts.config :as conf] + [parts.db :as db]) (:import (java.time Instant))) diff --git a/src/tools/ifs/parts/config.clj b/src/main/parts/config.clj similarity index 94% rename from src/tools/ifs/parts/config.clj rename to src/main/parts/config.clj index 7442f7d..b29e877 100644 --- a/src/tools/ifs/parts/config.clj +++ b/src/main/parts/config.clj @@ -1,4 +1,4 @@ -(ns tools.ifs.parts.config +(ns parts.config (:require [aero.core :as aero] [clojure.java.io :as io])) diff --git a/src/tools/ifs/parts/db.clj b/src/main/parts/db.clj similarity index 97% rename from src/tools/ifs/parts/db.clj rename to src/main/parts/db.clj index 39ac429..a44b757 100644 --- a/src/tools/ifs/parts/db.clj +++ b/src/main/parts/db.clj @@ -1,4 +1,4 @@ -(ns tools.ifs.parts.db +(ns parts.db (:require [clojure.string :as str] [com.brunobonacci.mulog :as mulog] @@ -6,7 +6,7 @@ [migratus.core :as migratus] [next.jdbc :as jdbc] [next.jdbc.result-set :as rs] - [tools.ifs.parts.config :as conf]) + [parts.config :as conf]) (:import (java.util UUID))) diff --git a/src/tools/ifs/parts/entity/user.clj b/src/main/parts/entity/user.clj similarity index 96% rename from src/tools/ifs/parts/entity/user.clj rename to src/main/parts/entity/user.clj index f16f940..31fa762 100644 --- a/src/tools/ifs/parts/entity/user.clj +++ b/src/main/parts/entity/user.clj @@ -1,7 +1,7 @@ -(ns tools.ifs.parts.entity.user +(ns parts.entity.user (:require - [tools.ifs.parts.auth :as auth] - [tools.ifs.parts.db :as db])) + [parts.auth :as auth] + [parts.db :as db])) (def allowed-update-fields #{:email :display_name :password}) (def sensitive-fields #{:password_hash}) diff --git a/src/main/parts/frontend/app.cljs b/src/main/parts/frontend/app.cljs new file mode 100644 index 0000000..7aba8fc --- /dev/null +++ b/src/main/parts/frontend/app.cljs @@ -0,0 +1,9 @@ +(ns parts.frontend.app + (:require + ["htmx.org" :default htmx])) + +(defn ^:export init [] + (.on htmx "htmx:load" + (fn [evt] + (let [version (.-version htmx)] + (js/console.log "HTMX loaded! Version:" version))))) diff --git a/src/tools/ifs/parts/pages.clj b/src/main/parts/handlers/pages.clj similarity index 81% rename from src/tools/ifs/parts/pages.clj rename to src/main/parts/handlers/pages.clj index fe50611..4490251 100644 --- a/src/tools/ifs/parts/pages.clj +++ b/src/main/parts/handlers/pages.clj @@ -1,27 +1,27 @@ -(ns tools.ifs.parts.pages +(ns parts.handlers.pages (:require [hiccup2.core :refer [html]] - [ring.util.response :as response] - [tools.ifs.parts.layouts.main :refer [layout]] - [tools.ifs.parts.layouts.partials :refer [footer header waitlist-signup-form]])) + [parts.views.layouts :as layouts] + [parts.views.partials :as partials] + [ring.util.response :as response])) (defn system-graph "Page rendering the graph of a system" - [system-id] + [_] (response/response (html - (layout "System" - [:section.container - [:div.content - [:div [:h2 "System"]] - [:div#root]]])))) + (layouts/main "System" + [:section.container + [:div.content + [:div [:h2 "System"]] + [:div#root]]])))) (defn home-page "Page rendered for GET /" [_] (-> (response/response (html - (layout + (layouts/main "Mapping tools for IFS practitioners and their clients" [:section.container [:div.content @@ -39,7 +39,7 @@ [:p [:strong "Parts"] " is being actively developed, and we would love to have your feedback! Please enter your email below to join the private beta test."] - (waitlist-signup-form ".signup")]]]] + (partials/waitlist-signup-form ".signup")]]]] [:section.aboutus.container [:div.content [:h3 diff --git a/src/tools/ifs/parts/waitlist.clj b/src/main/parts/handlers/waitlist.clj similarity index 90% rename from src/tools/ifs/parts/waitlist.clj rename to src/main/parts/handlers/waitlist.clj index 3321dab..4a07944 100644 --- a/src/tools/ifs/parts/waitlist.clj +++ b/src/main/parts/handlers/waitlist.clj @@ -1,11 +1,11 @@ -(ns tools.ifs.parts.waitlist +(ns parts.handlers.waitlist (:require [clojure.string :as str] [com.brunobonacci.mulog :as mulog] [hiccup2.core :refer [html]] - [ring.util.response :as response] - [tools.ifs.parts.db :as db] - [tools.ifs.parts.layouts.partials :as partials])) + [parts.db :as db] + [parts.views.partials :as partials] + [ring.util.response :as response])) (defn- valid-email? "Check if the email is valid" diff --git a/src/tools/ifs/parts/api/middleware.clj b/src/main/parts/middleware.clj similarity index 94% rename from src/tools/ifs/parts/api/middleware.clj rename to src/main/parts/middleware.clj index 3b12740..8ab6efb 100644 --- a/src/tools/ifs/parts/api/middleware.clj +++ b/src/main/parts/middleware.clj @@ -1,17 +1,18 @@ -(ns tools.ifs.parts.api.middleware +(ns parts.middleware (:require [buddy.auth :refer [authenticated?]] [buddy.auth.middleware :refer [wrap-authentication wrap-authorization]] [clojure.string :as str] [com.brunobonacci.mulog :as mulog] + [parts.auth :as auth] [reitit.ring.middleware.exception :as exception] [ring.middleware.content-type :refer [wrap-content-type]] [ring.middleware.defaults :refer [site-defaults wrap-defaults]] - [ring.middleware.resource :refer [wrap-resource]] + [ring.middleware.file :refer [wrap-file]] + [ring.middleware.file-info :refer [wrap-file-info]] [ring.middleware.session :refer [wrap-session]] [ring.middleware.session.cookie :refer [cookie-store]] - [ring.util.response :as response] - [tools.ifs.parts.auth :as auth]) + [ring.util.response :as response]) (:import (org.sqlite SQLiteException))) @@ -92,7 +93,8 @@ ;; TODO: Use secure-site-defaults for production (wrap-defaults (-> site-defaults (assoc-in [:session :store] (cookie-store)))) - (wrap-resource "public") + (wrap-file "public") + (wrap-file-info) (wrap-session) (wrap-content-type))) diff --git a/src/tools/ifs/parts.clj b/src/main/parts/server.clj similarity index 74% rename from src/tools/ifs/parts.clj rename to src/main/parts/server.clj index fa0ad8b..06f4863 100644 --- a/src/tools/ifs/parts.clj +++ b/src/main/parts/server.clj @@ -1,35 +1,32 @@ -;; --------------------------------------------------------- -;; tools.ifs.parts -;; -;; Parts is a toolkit for therapists working with the Internal Family Systems -;; model (https://en.wikipedia.org/wiki/Internal_Family_Systems_Model). It -;; provides a tool for easy, collaborative parts mapping, which can be used to -;; facilitate conversations with clients during sessions. - -;; --------------------------------------------------------- - -(ns tools.ifs.parts +(ns parts.server (:require [com.brunobonacci.mulog :as mulog] [org.httpkit.server :as server] + [parts.api.account :as account] + [parts.api.auth :as auth] + [parts.db :as db] + [parts.handlers.pages :as pages] + [parts.handlers.waitlist :as waitlist] + [parts.middleware :as middleware] [reitit.coercion.spec] [reitit.ring :as ring] [reitit.swagger :as swagger] [reitit.swagger-ui :as swagger-ui] [ring.middleware.json :refer [wrap-json-body wrap-json-response]] - [ring.middleware.params :refer [wrap-params]] - [tools.ifs.parts.api.account :as account] - [tools.ifs.parts.api.auth :as auth] - [tools.ifs.parts.api.middleware :as middleware] - [tools.ifs.parts.db :as db] - [tools.ifs.parts.pages :as pages] - [tools.ifs.parts.waitlist :as waitlist]) + [ring.middleware.params :refer [wrap-params]]) (:gen-class)) -;; --------------------------------------------------------- -;; Application +;; (def app +;; (middleware/wrap-default-middlewares +;; (ring/ring-handler +;; (ring/router +;; [["/" {:get +;; {:handler (fn [req] +;; (tap> req) ;; This will display req in the inspector +;; {:status 200}) +;; }}]])))) -(def prelaunch-app +(def app (middleware/wrap-default-middlewares (ring/ring-handler (ring/router @@ -54,7 +51,7 @@ ;; ;; It is also entirely possible that API routes will be removed, and only HTML ;; routes will remain. -(def app +(def api (middleware/wrap-default-middlewares (ring/ring-handler (ring/router @@ -99,7 +96,7 @@ "Starts the web server" [port] (mulog/log ::starting-server :port port) - (server/run-server #'prelaunch-app {:port port})) + (server/run-server #'app {:port port})) (defn -main "Entry point into the application via clojure.main -M" @@ -114,14 +111,3 @@ (fn [] (stop-fn) (println "Parts: Server stopped."))))) - -;; --------------------------------------------------------- - -;; --------------------------------------------------------- -;; Rick Comment -#_{:clj-kondo/ignore [:redefined-var]} -(comment - (def stop-server (-main)) - (stop-server) - #_()) ; End of rich comment block -;; --------------------------------------------------------- diff --git a/src/tools/ifs/parts/layouts/main.clj b/src/main/parts/views/layouts.clj similarity index 90% rename from src/tools/ifs/parts/layouts/main.clj rename to src/main/parts/views/layouts.clj index 4d33576..6955cb7 100644 --- a/src/tools/ifs/parts/layouts/main.clj +++ b/src/main/parts/views/layouts.clj @@ -1,9 +1,9 @@ -(ns tools.ifs.parts.layouts.main +(ns parts.views.layouts (:require [hiccup2.core :refer [html]] - [tools.ifs.parts.layouts.partials :refer [footer header]])) + [parts.views.partials :as partials])) -(defn layout +(defn main "Fundamental application layout" [title & content] (html @@ -24,7 +24,7 @@ :data-domain "parts.ifs.tools" :src "https://plausible.io/js/script.outbound-links.tagged-events.js"}]] [:body - (header) + (partials/header) content - (footer) + (partials/footer) [:script {:src "/js/main.js"}]])) diff --git a/src/tools/ifs/parts/layouts/partials.clj b/src/main/parts/views/partials.clj similarity index 95% rename from src/tools/ifs/parts/layouts/partials.clj rename to src/main/parts/views/partials.clj index 1517a30..9f1e437 100644 --- a/src/tools/ifs/parts/layouts/partials.clj +++ b/src/main/parts/views/partials.clj @@ -1,4 +1,4 @@ -(ns tools.ifs.parts.layouts.partials +(ns parts.views.partials (:require [ring.middleware.anti-forgery :refer [*anti-forgery-token*]])) @@ -17,7 +17,7 @@ [:div.content [:div.copyright [:p - "© 2024 " + "© 2025 " [:a {:href "https://a.possible.space"} "A Possible Space Ltd"] [:br] "Company number 11617016"]] diff --git a/test/tools/ifs/parts/api/account_test.clj b/test/parts/api/account_test.clj similarity index 93% rename from test/tools/ifs/parts/api/account_test.clj rename to test/parts/api/account_test.clj index 03f8231..7bcbd06 100644 --- a/test/tools/ifs/parts/api/account_test.clj +++ b/test/parts/api/account_test.clj @@ -1,10 +1,10 @@ -(ns tools.ifs.parts.api.account-test +(ns parts.api.account-test (:require [clojure.test :refer [deftest is testing use-fixtures]] - [tools.ifs.helpers.test-factory :as factory] - [tools.ifs.helpers.test-helpers :refer [register-test-user with-test-db]] - [tools.ifs.parts.api.account :as account] - [tools.ifs.parts.db :as db])) + [parts.api.account :as account] + [parts.db :as db] + [parts.helpers.test-factory :as factory] + [parts.helpers.utils :refer [register-test-user with-test-db]])) (use-fixtures :once with-test-db) diff --git a/test/tools/ifs/parts/api/auth_test.clj b/test/parts/api/auth_test.clj similarity index 92% rename from test/tools/ifs/parts/api/auth_test.clj rename to test/parts/api/auth_test.clj index 676d9ac..d38a663 100644 --- a/test/tools/ifs/parts/api/auth_test.clj +++ b/test/parts/api/auth_test.clj @@ -1,13 +1,13 @@ -(ns tools.ifs.parts.api.auth-test +(ns parts.api.auth-test (:require [buddy.sign.jwt :as jwt] [clojure.test :refer [deftest is testing use-fixtures]] - [tools.ifs.helpers.test-factory :as factory] - [tools.ifs.helpers.test-helpers :refer [with-test-db]] - [tools.ifs.parts.api.account :as account] - [tools.ifs.parts.api.auth :as auth] - [tools.ifs.parts.auth :as auth-utils] - [tools.ifs.parts.entity.user :as user]) + [parts.api.account :as account] + [parts.api.auth :as auth] + [parts.auth :as auth-utils] + [parts.entity.user :as user] + [parts.helpers.test-factory :as factory] + [parts.helpers.utils :refer [with-test-db]]) (:import (java.time Instant))) diff --git a/test/tools/ifs/parts/auth_test.clj b/test/parts/auth_test.clj similarity index 91% rename from test/tools/ifs/parts/auth_test.clj rename to test/parts/auth_test.clj index 8b21aba..98f078c 100644 --- a/test/tools/ifs/parts/auth_test.clj +++ b/test/parts/auth_test.clj @@ -1,11 +1,11 @@ -(ns tools.ifs.parts.auth-test +(ns parts.auth-test (:require [buddy.sign.jwt :as jwt] [clojure.test :refer [deftest is testing use-fixtures]] - [tools.ifs.helpers.test-factory :as factory] - [tools.ifs.helpers.test-helpers :refer [with-test-db]] - [tools.ifs.parts.auth :as auth] - [tools.ifs.parts.entity.user :as user]) + [parts.auth :as auth] + [parts.entity.user :as user] + [parts.helpers.test-factory :as factory] + [parts.helpers.utils :refer [with-test-db]]) (:import (java.time Instant))) diff --git a/test/tools/ifs/parts/entity/user_test.clj b/test/parts/entity/user_test.clj similarity index 95% rename from test/tools/ifs/parts/entity/user_test.clj rename to test/parts/entity/user_test.clj index db7f9ed..69ca087 100644 --- a/test/tools/ifs/parts/entity/user_test.clj +++ b/test/parts/entity/user_test.clj @@ -1,9 +1,9 @@ -(ns tools.ifs.parts.entity.user-test +(ns parts.entity.user-test (:require [clojure.test :refer [deftest is testing use-fixtures]] - [tools.ifs.helpers.test-factory :as factory] - [tools.ifs.helpers.test-helpers :refer [register-test-user with-test-db]] - [tools.ifs.parts.entity.user :as user])) + [parts.entity.user :as user] + [parts.helpers.test-factory :as factory] + [parts.helpers.utils :refer [register-test-user with-test-db]])) (use-fixtures :once with-test-db) diff --git a/test/tools/ifs/parts/waitlist_test.clj b/test/parts/handlers/waitlist_test.clj similarity index 90% rename from test/tools/ifs/parts/waitlist_test.clj rename to test/parts/handlers/waitlist_test.clj index 9168291..083be03 100644 --- a/test/tools/ifs/parts/waitlist_test.clj +++ b/test/parts/handlers/waitlist_test.clj @@ -1,11 +1,11 @@ -(ns tools.ifs.parts.waitlist-test +(ns parts.handlers.waitlist-test (:require [clojure.string :as str] [clojure.test :refer [deftest is testing use-fixtures]] - [tools.ifs.helpers.test-helpers :refer [with-test-db]] - [tools.ifs.parts.api.middleware :as middleware] - [tools.ifs.parts.db :as db] - [tools.ifs.parts.waitlist :as waitlist])) + [parts.db :as db] + [parts.handlers.waitlist :as waitlist] + [parts.helpers.utils :refer [with-test-db]] + [parts.middleware :as middleware])) (use-fixtures :once with-test-db) diff --git a/test/tools/ifs/helpers/test_factory.clj b/test/parts/helpers/test_factory.clj similarity index 93% rename from test/tools/ifs/helpers/test_factory.clj rename to test/parts/helpers/test_factory.clj index 22e5ed6..74260db 100644 --- a/test/tools/ifs/helpers/test_factory.clj +++ b/test/parts/helpers/test_factory.clj @@ -1,4 +1,4 @@ -(ns tools.ifs.helpers.test-factory) +(ns parts.helpers.test-factory) (def ^:private counter (atom 0)) diff --git a/test/tools/ifs/helpers/test_helpers.clj b/test/parts/helpers/utils.clj similarity index 90% rename from test/tools/ifs/helpers/test_helpers.clj rename to test/parts/helpers/utils.clj index 06ae5cc..0fa9f27 100644 --- a/test/tools/ifs/helpers/test_helpers.clj +++ b/test/parts/helpers/utils.clj @@ -1,11 +1,11 @@ -(ns tools.ifs.helpers.test-helpers +(ns parts.helpers.utils (:require [clojure.tools.logging :as log] [migratus.core :as migratus] [next.jdbc :as jdbc] - [tools.ifs.helpers.test-factory :as factory] - [tools.ifs.parts.config :as conf] - [tools.ifs.parts.entity.user :as user])) + [parts.config :as conf] + [parts.entity.user :as user] + [parts.helpers.test-factory :as factory])) (defn setup-test-db [] diff --git a/test/tools/ifs/parts/api/middleware_test.clj b/test/parts/middleware_test.clj similarity index 97% rename from test/tools/ifs/parts/api/middleware_test.clj rename to test/parts/middleware_test.clj index c9a5745..335b11f 100644 --- a/test/tools/ifs/parts/api/middleware_test.clj +++ b/test/parts/middleware_test.clj @@ -1,9 +1,9 @@ -(ns tools.ifs.parts.api.middleware-test +(ns parts.middleware-test (:require [clojure.test :refer [deftest is testing]] + [parts.middleware :as middleware] [reitit.ring :as ring] - [ring.mock.request :as mock] - [tools.ifs.parts.api.middleware :as middleware]) + [ring.mock.request :as mock]) (:import (org.sqlite SQLiteErrorCode SQLiteException))) diff --git a/tests.edn b/tests.edn index 0513579..8786e44 100644 --- a/tests.edn +++ b/tests.edn @@ -1,13 +1,4 @@ -;; --------------------------------------------------------- ;; Kaocha test runner configuration -;; -;; Default configuration -;; - show current config using either command: -;; -;; make test-config -;; -;; clojure -M:test/env:test/run --print-config - -;; --------------------------------------------------------- +;; clj -M:test/env:test/run --print-config #kaocha/v1 {}