Skip to content

Commit 4e11ede

Browse files
author
Bastien Guerry
committed
src/subscribe-dsfr.clj: Handle subdirectory deployments
1 parent f92f0ff commit 4e11ede

File tree

1 file changed

+66
-24
lines changed

1 file changed

+66
-24
lines changed

src/subscribe-dsfr.clj

Lines changed: 66 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
;; MAILGUN_LIST_ID (example: "my@list.com")
1111
;; MAILGUN_API_ENDPOINT (example "https://api.eu.mailgun.net/v3")
1212
;; MAILGUN_API_KEY (example "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxx-xxxxxxxx"
13+
;; APP_BASE_PATH (optional, example: "/app" - for subdirectory deployments)
1314
;;
1415
;; Running the web application as http://localhost:8080
1516
;;
@@ -40,6 +41,27 @@
4041
:appenders {:println {:min-level :debug
4142
:fn #(println %)}}})
4243

44+
;; Base path configuration for subdirectory deployments
45+
(def base-path
46+
(let [path (or (System/getenv "APP_BASE_PATH") "")]
47+
(if (str/blank? path)
48+
""
49+
(if (str/ends-with? path "/")
50+
(str/replace path #"/$" "") ;; Remove trailing slash
51+
path))))
52+
53+
(log/info "APP_BASE_PATH:" (if (str/blank? base-path) "[not set]" base-path))
54+
55+
;; Helper function to construct paths with the base path
56+
(defn make-path [& segments]
57+
(let [segments (remove str/blank? segments)]
58+
(str base-path
59+
(if (and (not (str/blank? base-path))
60+
(not (str/starts-with? (first segments) "/")))
61+
"/"
62+
"")
63+
(str/join "/" segments))))
64+
4365
;; Default language setting
4466
(def default-language :en)
4567

@@ -327,38 +349,38 @@
327349
<meta charset=\"UTF-8\">
328350
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
329351
<title>%s</title>
330-
352+
331353
<!-- DSFR resources -->
332354
<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/@gouvfr/dsfr@1.11.0/dist/dsfr/dsfr.min.css\">
333355
<link rel=\"apple-touch-icon\" href=\"https://cdn.jsdelivr.net/npm/@gouvfr/dsfr@1.11.0/dist/favicon/apple-touch-icon.png\">
334356
<link rel=\"icon\" href=\"https://cdn.jsdelivr.net/npm/@gouvfr/dsfr@1.11.0/dist/favicon/favicon.svg\" type=\"image/svg+xml\">
335357
<link rel=\"shortcut icon\" href=\"https://cdn.jsdelivr.net/npm/@gouvfr/dsfr@1.11.0/dist/favicon/favicon.ico\" type=\"image/x-icon\">
336-
358+
337359
<!-- HTMX for form interactions -->
338360
<script src=\"https://unpkg.com/htmx.org@1.9.6\"></script>
339-
361+
340362
<style>
341363
.success {
342364
border-left: 5px solid var(--success-425-625);
343365
padding: 1rem;
344366
margin-bottom: 1rem;
345367
background-color: var(--success-950-100);
346368
}
347-
369+
348370
.error {
349371
border-left: 5px solid var(--error-425-625);
350372
padding: 1rem;
351373
margin-bottom: 1rem;
352374
background-color: var(--error-950-100);
353375
}
354-
376+
355377
.warning {
356378
border-left: 5px solid var(--warning-425-625);
357379
padding: 1rem;
358380
margin-bottom: 1rem;
359381
background-color: var(--warning-950-100);
360382
}
361-
383+
362384
.debug {
363385
margin-top: 1rem;
364386
padding: 1rem;
@@ -369,20 +391,20 @@
369391
display: none;
370392
font-size: 0.85rem;
371393
}
372-
394+
373395
.htmx-indicator {
374396
opacity: 0;
375397
transition: opacity 200ms ease-in;
376398
}
377-
399+
378400
.htmx-request .htmx-indicator {
379401
opacity: 1;
380402
}
381-
403+
382404
.htmx-request.htmx-indicator {
383405
opacity: 1;
384406
}
385-
407+
386408
/* Honeypot field - hidden from users but visible to bots */
387409
.visually-hidden {
388410
position: absolute;
@@ -391,7 +413,7 @@
391413
width: 1px;
392414
overflow: hidden;
393415
}
394-
416+
395417
.fr-subscribe-form {
396418
padding: 2rem 0;
397419
}
@@ -434,8 +456,8 @@
434456
<div class=\"fr-card__content\">
435457
<h2>%s</h2>
436458
<p>%s</p>
437-
438-
<form hx-post=\"/subscribe\" hx-target=\"#result\" hx-swap=\"outerHTML\" hx-indicator=\"#loading\" class=\"fr-form\">
459+
460+
<form hx-post=\"%s/subscribe\" hx-target=\"#result\" hx-swap=\"outerHTML\" hx-indicator=\"#loading\" class=\"fr-form\">
439461
<div class=\"fr-input-group\">
440462
<label class=\"fr-label\" for=\"email\">E-mail</label>
441463
<input class=\"fr-input\" type=\"email\" id=\"email\" name=\"email\" placeholder=\"%s\" required>
@@ -462,7 +484,7 @@
462484
</div>
463485
</div>
464486
</article>
465-
487+
466488
<div id=\"result\"></div>
467489
</div>
468490
</div>
@@ -514,7 +536,7 @@
514536
</div>
515537
</div>
516538
</footer>
517-
539+
518540
<!-- DSFR JavaScript -->
519541
<script src=\"https://cdn.jsdelivr.net/npm/@gouvfr/dsfr@1.11.0/dist/dsfr/dsfr.module.min.js\" type=\"module\"></script>
520542
<script src=\"https://cdn.jsdelivr.net/npm/@gouvfr/dsfr@1.11.0/dist/dsfr/dsfr.nomodule.min.js\" nomodule></script>
@@ -525,6 +547,7 @@
525547
(:title (:page strings))
526548
(:heading (:page strings))
527549
(:subheading (:page strings))
550+
base-path ;; Add base path to form action
528551
(:email-placeholder (:form strings))
529552
csrf-token
530553
(:website-label (:form strings))
@@ -544,13 +567,13 @@
544567
</div>
545568
" (case type
546569
"success" "success"
547-
"error" "error"
570+
"error" "error"
548571
"warning" "warning"
549572
"info")
550-
heading
551-
(if (seq args)
552-
(apply format message (map escape-html args))
553-
message))))
573+
heading
574+
(if (seq args)
575+
(apply format message (map escape-html args))
576+
message))))
554577

555578
(defn debug-result-template [strings type heading-key message & debug-info]
556579
(format "
@@ -691,7 +714,9 @@
691714
csrf-token (generate-csrf-token)]
692715
{:status 200
693716
:headers {"Content-Type" "text/html"
694-
"Set-Cookie" (format "csrf_token=%s; Path=/; HttpOnly; SameSite=Strict" csrf-token)}
717+
"Set-Cookie" (format "csrf_token=%s; Path=%s; HttpOnly; SameSite=Strict"
718+
csrf-token
719+
(if (str/blank? base-path) "/" base-path))}
695720
:body (build-index-html strings lang csrf-token)}))
696721

697722
(defn parse-form-data [request]
@@ -893,7 +918,8 @@
893918
(let [lang (determine-language req)
894919
debug-info {:env {:mailgun-list-id mailgun-list-id
895920
:mailgun-api-endpoint mailgun-api-endpoint
896-
:mailgun-api-key "****"}
921+
:mailgun-api-key "****"
922+
:base-path base-path}
897923
:i18n {:current-language (name lang)
898924
:available-languages (keys ui-strings)
899925
:browser-language (get-in req [:headers "accept-language"])}
@@ -907,13 +933,27 @@
907933
:headers {"Content-Type" "application/json"}
908934
:body (json/generate-string debug-info {:pretty true})}))
909935

936+
;; Function to normalize URI for path matching
937+
(defn normalize-uri [uri]
938+
(let [uri-without-base (if (and (not (str/blank? base-path))
939+
(str/starts-with? uri base-path))
940+
(let [path (subs uri (count base-path))]
941+
(if (str/blank? path) "/" path))
942+
uri)]
943+
(log/debug "Normalized URI from" uri "to" uri-without-base)
944+
uri-without-base))
945+
910946
;; Main app with routes
911947
(defn app [req]
912948
(let [uri (:uri req)
949+
normalized-uri (normalize-uri uri)
913950
query-params (parse-query-params uri)
914951
req-with-params (assoc req :query-params query-params)]
915952
(try
916-
(case [(:request-method req) uri]
953+
(log/debug "Processing request:" (:request-method req) uri)
954+
(log/debug "Normalized path:" normalized-uri)
955+
956+
(case [(:request-method req) normalized-uri]
917957
[:get "/"] (handle-index req-with-params)
918958
[:post "/subscribe"] (handle-subscribe req-with-params)
919959
[:get "/debug"] (handle-debug req-with-params)
@@ -940,13 +980,14 @@
940980
(defn start-server [& [port]]
941981
(let [port (or port 8080)]
942982
(log/info (str "Starting server on http://localhost:" port))
983+
(log/info (str "Base path: " (if (str/blank? base-path) "[root]" base-path)))
943984
(server/run-server app {:port port})))
944985

945986
;; Main entry point
946987
(when (= *file* (System/getProperty "babashka.file"))
947988
(let [args *command-line-args*
948989
;; Check if first argument is a valid port number
949-
port (if (and (seq args)
990+
port (if (and (seq args)
950991
(try (Integer/parseInt (first args)) true
951992
(catch NumberFormatException _ false)))
952993
(Integer/parseInt (first args))
@@ -962,6 +1003,7 @@
9621003
mailgun-api-key)
9631004
(log/error "Missing environment variable")
9641005
(do (log/info (str "Starting server on http://localhost:" port))
1006+
(log/info (str "Base path: " (if (str/blank? base-path) "[root]" base-path)))
9651007
(server/run-server app {:port port})
9661008
;; Keep the server running
9671009
@(promise)))))

0 commit comments

Comments
 (0)