deeper refactoring of web and failjure error propagation

this includes improvements that should be backported to the leiningen
template for dyne apps
This commit is contained in:
Jaromil 2018-10-13 13:00:03 +02:00
parent d162d16116
commit de76c4887d
7 changed files with 174 additions and 167 deletions

View File

@ -19,6 +19,7 @@
(ns toaster.bulma (ns toaster.bulma
(:require [clojure.java.io :as io] (:require [clojure.java.io :as io]
[clojure.data.csv :as csv] [clojure.data.csv :as csv]
[taoensso.timbre :as log]
[yaml.core :as yaml] [yaml.core :as yaml]
[hiccup.page :as page] [hiccup.page :as page]
[hiccup.form :as hf])) [hiccup.form :as hf]))
@ -30,9 +31,6 @@
(declare render-footer) (declare render-footer)
(declare render-yaml) (declare render-yaml)
(declare render-edn) (declare render-edn)
(declare render-error)
(declare render-error-page)
(declare render-static)
;; TODO: navbars for bulma ;; TODO: navbars for bulma
@ -73,39 +71,28 @@
"text/html; charset=utf-8"} "text/html; charset=utf-8"}
:body (page/html5 :body (page/html5
(render-head) (render-head)
[:body ;; {:class "static"} [:body
;; navbar-guest ;; navbar-guest
body body
(render-footer)])}) (render-footer)])})
([account body] ([account body]
{:headers {"Content-Type" {:headers {"Content-Type"
"text/html; charset=utf-8"} "text/html; charset=utf-8"}
:body (page/html5 :body (page/html5
(render-head) (render-head)
[:body ;; (if (empty? account) [:body ;; (if (empty? account)
;; navbar-guest ;; navbar-guest
;; navbar-account) ;; navbar-account)
body body
(render-footer)])})) (render-footer)])}))
(defn render-success (defn notify
"render a successful message without ending the page" "render a notification message without ending the page"
[succ] ([msg] (notify msg ""))
[:div {:class "notification is-primary"} succ]) ([msg class]
[:div {:class (str "notification " class " has-text-centered")} msg]))
(defn render-error
"render an error message without ending the page"
[err]
[:div {:class "notification is-danger"} err])
(defn render-error-page
([] (render-error-page {} "Unknown"))
([err] (render-error-page {} err))
([session error]
(render
[:div {:class "container"}
(render-error error)])))
(defn render-error [err] (->> "is-error" (notify (log/spy :error err)) render))
(defn render-head (defn render-head
([] (render-head ([] (render-head
@ -136,45 +123,39 @@
[:div {:class "content has-text-centered"} [:div {:class "content has-text-centered"}
[:p {:class "has-text-grey"} "toaster.do transforms your Docker prototype into " [:p {:class "has-text-grey"} "toaster.do transforms your Docker prototype into "
"an installable " [:a {:href "https://devuan.org"} "Devuan GNU+Linux"] "an installable " [:a {:href "https://devuan.org"} "Devuan GNU+Linux"]
" image, choose any supported target architecture!"] " image, choose any supported target architecture."]
[:div {:class "columns is-variable is-8"} [:div {:class "columns is-variable is-8"}
[:div {:class "column is-one-quarter"} [:div {:class "column is-one-fifth"}
[:figure {:class "image"}
[:img {:src "/static/img/ec_logo.png"
:alt "European project DECODE (H2020 nr. 732546)"}]]]
[:div {:class "column is-one-fifth"}
[:a {:href "https://decodeproject.eu"} [:a {:href "https://decodeproject.eu"}
[:figure {:class "image"} [:figure {:class "image"}
[:img {:src "/static/img/decode_logo.png" [:img {:src "/static/img/decode_logo.png"
:alt "DECODE project"}]]]] :alt "DECODE project"}]]]]
[:div {:class "column is-one-quarter"} [:div {:class "column is-one-fifth"}
[:a {:href "https://www.dyne.org"} [:a {:href "https://www.dyne.org"}
[:figure {:class "image"} [:figure {:class "image"}
[:img {:src "/static/img/swbydyne.png" [:img {:src "/static/img/swbydyne.png"
:alt "Software by Dyne.org" :alt "Software by Dyne.org"
:title "Software by Dyne.org"}]]]] :title "Software by Dyne.org"}]]]]
[:div {:class "column is-one-quarter"} [:div {:class "column is-one-fifth"}
[:a {:href "https://devuan.org"} [:a {:href "https://devuan.org"}
[:figure {:class "image"} [:figure {:class "image"}
[:img {:src "/static/img/devuan_logo.png" [:img {:src "/static/img/devuan_logo.png"
:alt "powered by Devuan GNU+Linux"}]]]] :alt "powered by Devuan GNU+Linux"}]]]]
[:div {:class "column is-one-quarter"} [:div {:class "column is-one-fifth"}
[:figure {:class "image"} [:figure {:class "image"}
[:img {:src "/static/img/AGPLv3.png" ;; :style "margin-top: 2.5em" [:img {:src "/static/img/AGPLv3.png" ;; :style "margin-top: 2.5em"
:alt "Affero GPLv3 License" :alt "Affero GPLv3 License"
:title "Affero GPLv3 License"}]]]]]]) :title "Affero GPLv3 License"}]]]]]])
(defn render-static [body]
(page/html5 (render-head)
[:body {:class "fxc static"}
;; navbar-guest
[:div {:class "container"} body]
(render-footer)
]))
;; highlight functions do no conversion, take the format they highlight ;; highlight functions do no conversion, take the format they highlight
;; render functions take edn and convert to the highlight format ;; render functions take edn and convert to the highlight format
@ -232,7 +213,7 @@
[:input {:class "btn btn-success btn-lg pull-top" [:input {:class "btn btn-success btn-lg pull-top"
:type "submit" :value "submit"}]]) :type "submit" :value "submit"}]])
(def brand-img "/static/img/whale_toast.jpg") (def brand-img "/static/img/cafudda.jpg")
(defn- hero-login-box [body] (defn- hero-login-box [body]
[:section {:class "hero is-fullheight"} [:section {:class "hero is-fullheight"}
[:div {:class "hero-body"} [:div {:class "hero-body"}

View File

@ -62,47 +62,50 @@
(defroutes (defroutes
app-routes app-routes
(GET "/" request (login-page request web/login-form)) (GET "/" request
(f/attempt-all
[db (s/check-database)
conf (s/check-config request)]
(f/if-let-ok? [account (s/check-account request)]
(web/render (views/dashboard account))
;; else
(web/render web/login-form))
(f/when-failed[e]
(web/render (web/notify (f/message e) "is-error")))))
;; NEW ROUTES HERE ;; NEW ROUTES HERE
(GET "/upload" request
(->> (fn [req conf acct]
(web/render acct [:div
views/dockerfile-upload-form
(views/list-jobs acct)]))
(s/check request)))
(POST "/dockerfile" request (POST "/dockerfile" request
(->> (fn [req conf acct] (->> (fn [req conf acct]
(web/render acct (views/dockerfile-upload-post req conf acct))) (web/render acct
(s/check request))) [:span (views/dockerfile-upload-post req conf acct)
(views/dashboard acct)]))
(s/auth-wrap request)))
(GET "/list" request ;; (GET "/list" request
(->> (fn [req conf acct] ;; (->> (fn [req conf acct]
(web/render acct (views/list-jobs acct))) ;; (web/render acct (views/list-jobs acct)))
(s/check request))) ;; (s/auth-wrap request)))
(POST "/remove" request (POST "/remove" request
(->> (fn [req conf acct] (->> (fn [req conf acct]
(web/render acct (views/remove-job req conf acct))) (web/render acct (views/remove-job req conf acct)))
(s/check request))) (s/auth-wrap request)))
(POST "/start" request (POST "/start" request
(->> (fn [req conf acct] (->> (fn [req conf acct]
(web/render acct (views/start-job req conf acct))) (web/render acct (views/start-job req conf acct)))
(s/check request))) (s/auth-wrap request)))
(POST "/view" request (POST "/view" request
(->> (fn [req conf acct] (->> (fn [req conf acct]
(web/render acct (views/view-job req conf acct))) (web/render acct (views/view-job req conf acct)))
(s/check request))) (s/auth-wrap request)))
(GET "/error" request (GET "/error" request
(->> (fn [req conf acct] (->> (fn [req conf acct]
(web/render acct [:div (web/render acct [:div
(web/render-error "Generic Error Page") (web/notify "Generic Error Page" "is-error")]))
(views/list-jobs acct)])) (s/auth-wrap request)))
(s/check request)))
;; JUST-AUTH ROUTES ;; JUST-AUTH ROUTES
(GET "/login" request (login-page request web/login-form)) (GET "/login" request (login-page request web/login-form))
@ -117,15 +120,15 @@
(let [session {:session {:config config (let [session {:session {:config config
:auth logged}}] :auth logged}}]
(conj session (conj session
(web/render logged (views/list-jobs logged)))) (web/render logged (views/dashboard logged))))
;; (web/render ;; (web/render
;; logged ;; logged
;; [:div ;; [:div
;; [:h1 "Logged in: " username] ;; [:h1 "Logged in: " username]
;; views/welcome-menu]))) ;; views/welcome-menu])))
(f/when-failed [e] (f/when-failed [e]
(web/render (web/render-error (web/render (web/notify
(str "Login failed: " (f/message e))))))) (str "Login failed: " (f/message e)) "is-error")))))
(GET "/logout" request (GET "/logout" request
(conj {:session {:config config}} (conj {:session {:config config}}
@ -155,15 +158,15 @@
[:h2 (str "Account created: " [:h2 (str "Account created: "
name " <" email ">")] name " <" email ">")]
[:h3 "Account pending activation."]] [:h3 "Account pending activation."]]
(web/render-error (web/notify
(str "Failure creating account: " (str "Failure creating account: "
(f/message signup))))) (f/message signup)) "is-error")))
(web/render-error (web/notify
"Repeat password didnt match"))) "Repeat password didnt match" "is-error")))
(f/when-failed [e] (f/when-failed [e]
(web/render (web/render
(web/render-error (web/notify
(str "Sign-up failure: " (f/message e))))))) (str "Sign-up failure: " (f/message e)) "is-error")))))
(GET "/activate/:email/:activation-id" (GET "/activate/:email/:activation-id"
[email activation-id :as request] [email activation-id :as request]
@ -177,22 +180,22 @@
[act (auth/activate-account [act (auth/activate-account
@ring/auth email @ring/auth email
{:activation-link activation-uri})] {:activation-link activation-uri})]
(web/render-error (web/notify
[:div [:span
[:h1 "Failure activating account"] [:h1 {:class "title"} "Failure activating account"]
[:h2 (f/message act)] [:h2 {:class "subtitle"} (f/message act)]
[:p (str "Email: " email " activation-id: " activation-id)]]) [:p (str "Email: " email " activation-id: " activation-id)]] "is-error")
[:h1 (str "Account activated - " email)])]))) (web/notify [:h1 {:class "title"} (str "Account activated - " email)] "is-success"))])))
;; -- end of JUST-AUTH ;; -- end of JUST-AUTH
(POST "/" request (POST "/" request
;; generic endpoint for canceled operations ;; generic endpoint for canceled operations
(web/render (s/check-account request) (web/render (s/check-account request)
[:div {:class (str "alert alert-danger") :role "alert"} (web/notify
(s/param request :message)])) (s/param request :message) "is-error")))
(route/resources "/") (route/resources "/")
(route/not-found (web/render (web/render-error "Page Not Found"))) (route/not-found (web/render (web/notify "Page Not Found" "is-error")))
) ;; end of routes ) ;; end of routes

View File

@ -9,11 +9,27 @@
[failjure.core :as f] [failjure.core :as f]
[taoensso.timbre :as log :refer [debug]] [taoensso.timbre :as log :refer [debug]]
[me.raynes.conch :as sh :refer [with-programs]] [me.raynes.conch :as sh :refer [with-programs]]
[toaster.webpage :as web] [toaster.bulma :as web]
[toaster.config :refer :all] [toaster.config :refer :all]
[toaster.ring :refer [jobs]] [toaster.ring :refer [jobs]]
[hiccup.form :as hf])) [hiccup.form :as hf]))
;; list of arm targets to chose from
;"beagleboneblack"
;"chromeacer"
;"chromeveyron"
;"droid4"
;"n900"
;"odroidxu4"
;"odroidxu"
;"ouya"
;"raspi1"
;"raspi2"
;"raspi3"
;"rock64"
;"sunxi"
;"turbox-twister"
(defn- ssh-host [config] (defn- ssh-host [config]
(str (q config [:jenkins :user]) "@" (q config [:jenkins :host]))) (str (q config [:jenkins :user]) "@" (q config [:jenkins :host])))
@ -59,8 +75,7 @@
{:lint r_lint {:lint r_lint
:job r_job} :job r_job}
(f/when-failed [e] (f/when-failed [e]
(web/render-error (f/fail (str "Job add '" jobname "' failure: " (f/message e))))))))
(str "Job add failure: " (f/message e))))))))
(defn trash [jobid config] (defn trash [jobid config]
(f/attempt-all [r_sync (sync_jobs config "-d" jobid)] (f/attempt-all [r_sync (sync_jobs config "-d" jobid)]

View File

@ -6,7 +6,7 @@
[failjure.core :as f] [failjure.core :as f]
[just-auth.core :as auth] [just-auth.core :as auth]
[toaster.ring :as ring] [toaster.ring :as ring]
[toaster.webpage :as web])) [toaster.bulma :as web]))
(defn param [request param] (defn param [request param]
(let [value (let [value
@ -29,7 +29,7 @@
(if (contains? session :config) (if (contains? session :config)
(:config session) (:config session)
(conf/load-config "toaster" conf/default-settings)) (conf/load-config "toaster" conf/default-settings))
(f/fail "Session not found. "))) (f/fail "Session not found.")))
(defn check-account [request] (defn check-account [request]
;; check if login is present in session ;; check if login is present in session
@ -39,22 +39,27 @@
user user
(f/when-failed [e] (f/when-failed [e]
(->> e f/message (->> e f/message
(str "Unauthorized access. ") (str "Unauthorized access: ")
f/fail)))) f/fail))))
(defn check-database [] (defn check-database []
(if-let [db @ring/db] (if-let [db @ring/db]
db db
(f/fail "No connection to database. "))) (f/fail "No connection to database.")))
(defn check [request fun] (defn auth-wrap [request fun]
(f/attempt-all (f/attempt-all
[db (check-database) [db (check-database)
config (check-config request) config (check-config request)
account (check-account request)] account (if (conf/q config [:webserver :mock-auth])
(fun request config account) {:email "mock@dyne.org"
(f/when-failed [e] :name "MockUser"
(web/render :activated true}
[:div ;; else
(web/render-error (f/message e)) (check-account request))]
web/login-form])))) (fun request config account)
(f/when-failed [e]
(web/render [:span
(web/notify (f/message e) "is-error")
web/login-form
]))))

View File

@ -1,3 +1,21 @@
;; Copyright (C) 2018 Dyne.org foundation
;; Sourcecode designed, written and maintained by
;; Denis Roio <jaromil@dyne.org>
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU Affero General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU Affero General Public License for more details.
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
(ns toaster.views (ns toaster.views
(:require (:require
[clojure.java.io :as io] [clojure.java.io :as io]
@ -19,8 +37,32 @@
[clj-storage.core :as db] [clj-storage.core :as db]
[hiccup.form :as hf])) [hiccup.form :as hf]))
(def dockerfile-upload-form (defn- box-list [account joblist]
[:div {:class "container"} [:div {:class "box column"}
[:h1 {:class "title"} (str "List all toaster jobs for " (:name account))]
[:table {:class "table is-fullwidth is-hoverable"}
[:thead nil
[:tr nil [:th nil "Date"] [:th nil "Type"] [:th nil "Status"] [:th nil "Actions"]]]
[:tbody nil
(for [j joblist]
(let [type (:type j) ;; (-> j (str/split #"-") second)
tstamp (:timestamp j) ;; (-> j (str/split #"-") last)
jobid (:jobid j)
joburl (str/replace jobid #"@" "AT")]
[:tr nil
[:td {:class "date"} (-> tstamp Long/valueOf tc/from-long humanize/datetime)]
[:td {:class "job"} [:a {:href (str "https://sdk.dyne.org:4443/view/web-sdk-builds/job/" joburl)} type]]
[:td {:class "status"} [:a {:href (str "https://sdk.dyne.org:4443/job/" joburl "/lastBuild/console")}
[:img {:src (str "https://sdk.dyne.org:4443/job/" joburl "/badge/icon")}]]]
[:td {:class "actions"}
[:div {:class "field is-grouped"}
(web/button "/view" "\uD83D\uDC41" (hf/hidden-field "jobid" jobid))
(web/button "/start" "▶" (hf/hidden-field "jobid" jobid))
(web/button "/remove" "\uD83D\uDDD1" (hf/hidden-field "jobid" jobid))]]]
))]]])
(defn- box-add []
[:div {:class "box column"}
[:h1 {:class "title"} "Upload a Dockerfile to toast"] [:h1 {:class "title"} "Upload a Dockerfile to toast"]
[:p " Choose the file in your computer and click 'Submit' to [:p " Choose the file in your computer and click 'Submit' to
proceed to validation."] proceed to validation."]
@ -37,31 +79,12 @@
"Docker file..."]] "Docker file..."]]
[:span {:class "file-name"}]]] [:span {:class "file-name"}]]]
;; [:fieldset {:class "fieldset-submit"} ;; [:fieldset {:class "fieldset-submit"}
[:div {:class "field"} [:div {:class "field"}
[:div {:class "control"} [:div {:class "control"}
[:input {:class "button is-block is-info is-large is-fullwidth" [:input {:class "button is-block is-info is-large is-fullwidth"
:type "submit" :type "submit"
:name "submit" :value "submit"}]]]]]) :name "submit" :value "submit"}]]]]])
(def dockerfile-edit-form
[:div {:class "container"}
[:h1 {:class "title"} "Edit your Dockerfile to toast"]
[:div {:class "form-group"}
[:form {:action "dockerfile" :method "post"
:class "form-shell"
:enctype "multipart/form-data"}
[:fieldset {:class "fieldset btn btn-default btn-file btn-lg"}
[:textarea {:name "editor" :id "editor"
:rows 30 :cols 72} "FROM: dyne/devuan:ascii"]
[:input {:class "btn btn-primary btn-lg"
:id "field-submit" :type "submit"
:name "submit" :value "submit"}]]]]
[:script "var editor = ace.edit(\"editor\");
editor.setTheme(\"ace/theme/monokai\");
editor.session.setMode(\"ace/mode/dockerfile\");"]])
(defn dockerfile-upload-post [request config account] (defn dockerfile-upload-post [request config account]
(let (let
[tempfile (get-in request [:params :file :tempfile]) [tempfile (get-in request [:params :file :tempfile])
@ -71,52 +94,35 @@
(> (get-in params [:file :size]) 64000) (> (get-in params [:file :size]) 64000)
;; max upload size in bytes ;; max upload size in bytes
;; TODO: put in config ;; TODO: put in config
(web/render-error params "File too big in upload (64KB limit).") (f/fail "File too big in upload (64KB limit).")
:else :else
(let [file (io/copy tempfile (io/file "/tmp" filename)) (let [file (io/copy tempfile (io/file "/tmp" filename))
path (str "/tmp/" filename)] path (str "/tmp/" filename)]
(io/delete-file tempfile) (io/delete-file tempfile)
(if (not (.exists (io/file path))) (if (not (.exists (io/file path)))
(web/render-error (f/fail
(log/spy :error (str "Uploaded file not found: " filename))
[:h1 (str "Uploaded file not found: " filename)]))
;; file is now in 'tmp' var ;; file is now in 'tmp' var
[:div {:class "container"} (f/if-let-ok? [newjob (job/add path config account)]
[:h1 {:class "title"} "Job uploaded and added"] [:div {:class "container"}
[:p "Log messages:"] [:h1 {:class "title"} "Job uploaded and added"]
(web/render-yaml (job/add path config account))]))))) [:p "Log messages:"]
(web/render-yaml newjob)]
(web/notify (f/message newjob) "is-error")))))))
(defn list-jobs [account] (defn dashboard
([account] (dashboard {} {} account))
([request config account]
(f/attempt-all (f/attempt-all
[joblist (db/query @ring/jobs {:email (:email account)})] [joblist (db/query @ring/jobs {:email (:email account)})]
[:div {:class "container has-text-centered"} [:div {:class "container has-text-centered"}
[:h1 {:class "title"} (str "List all toaster jobs for " (:name account))]
[:div {:class "box"} [:div {:class "columns"}
[:table {:class "table is-fullwidth is-hoverable"} (if (> 0 (count joblist)) (box-list account joblist))
[:thead nil (box-add) ]]
[:tr nil [:th nil "Date"] [:th nil "Type"] [:th nil "Status"] [:th nil "Actions"]]]
[:tbody nil
(for [j joblist]
(let [type (:type j) ;; (-> j (str/split #"-") second)
tstamp (:timestamp j) ;; (-> j (str/split #"-") last)
jobid (:jobid j)
joburl (str/replace jobid #"@" "AT")]
[:tr nil
[:td {:class "date"} (-> tstamp Long/valueOf tc/from-long humanize/datetime)]
[:td {:class "job"} [:a {:href (str "https://sdk.dyne.org:4443/view/web-sdk-builds/job/" joburl)} type]]
[:td {:class "status"} [:a {:href (str "https://sdk.dyne.org:4443/job/" joburl "/lastBuild/console")}
[:img {:src (str "https://sdk.dyne.org:4443/job/" joburl "/badge/icon")}]]]
[:td {:class "actions"}
[:div {:class "field is-grouped"}
(web/button "/view" "\uD83D\uDC41" (hf/hidden-field "jobid" jobid))
(web/button "/start" "▶" (hf/hidden-field "jobid" jobid))
(web/button "/remove" "\uD83D\uDDD1" (hf/hidden-field "jobid" jobid))]]]
))]]]]
(f/when-failed [e] (f/when-failed [e]
(web/render-error (web/notify
(str "Job list failure: " (f/message e)))))) (str "Job list failure: " (f/message e)) "is-error")))))
(defn remove-job [request config account] (defn remove-job [request config account]
(f/attempt-all (f/attempt-all
@ -124,32 +130,26 @@
jobfound (db/query @ring/jobs {:jobid jobid}) jobfound (db/query @ring/jobs {:jobid jobid})
r_rmjob (db/delete! @ring/jobs jobid) r_rmjob (db/delete! @ring/jobs jobid)
r_sync (job/trash jobid config)] r_sync (job/trash jobid config)]
[:span (web/notify (str "Job removed: " jobid) "is-primary")
[:div {:class "notification is-primary has-text-centered"}
(str "Job removed: " jobid)]
(list-jobs account)]
(f/when-failed [e] (f/when-failed [e]
(web/render-error (str "Failure removing job: " (f/message e)))))) (web/notify (str "Failure removing job: " (f/message e)) "is-error"))))
(defn start-job [request config account] (defn start-job [request config account]
(f/attempt-all (f/attempt-all
[jobid (s/param request :jobid) [jobid (s/param request :jobid)
jobfound (db/query @ring/jobs {:jobid jobid}) jobfound (db/query @ring/jobs {:jobid jobid})
r_sync (job/start jobid config)] r_sync (job/start jobid config)]
[:div {:class "container"} (web/notify (str "Job started: " jobid) "is-success")
[:h1 (str "Job started: " jobid)]
[:p [:a {:href (str "https://sdk.dyne.org:4443/view/web-sdk-builds/job/"
(str/replace jobid #"@" "AT"))}]]]
(f/when-failed [e] (f/when-failed [e]
(web/render-error (str "Failure starting job: " (f/message e)))))) (web/notify (str "Failure starting job: " (f/message e)) "is-error"))))
(defn view-job [request config account] (defn view-job [request config account]
(f/attempt-all (f/attempt-all
[jobid (s/param request :jobid) [jobid (s/param request :jobid)
jobfound (db/fetch @ring/jobs jobid) jobfound (db/fetch @ring/jobs jobid)
dockerfile (log/spy (-> jobfound :dockerfile))] dockerfile (-> jobfound :dockerfile)]
[:div {:class "container"} [:div {:class "container"}
[:h1 {:class "title"} (str "Viewing job: " jobid)] [:h1 {:class "title"} (str "Viewing job: " jobid)]
[:pre dockerfile]] [:pre dockerfile]]
(f/when-failed [e] (f/when-failed [e]
(web/render-error (str "Failure viewing job: " (f/message e)))))) (web/notify (str "Failure viewing job: " (f/message e)) "is-error"))))

View File

@ -38,6 +38,7 @@
(declare render-error) (declare render-error)
(declare render-error-page) (declare render-error-page)
(declare render-static) (declare render-static)
(declare render-error)
(defn q [req] (defn q [req]
"wrapper to retrieve parameters" "wrapper to retrieve parameters"

View File

@ -1,11 +1,13 @@
webserver: webserver:
anti-forgery: false anti-forgery: false
ssl-redirect: false ssl-redirect: false
mock-auth: false
jenkins: jenkins:
host: "bridge.toaster" host: "bridge.toaster"
user: "jenkins" user: "jenkins"
key: "../id_ed25519" key: "../id_ed25519"
url: "https://sdk.dyne.org:4443"
just-auth: just-auth:
email-server: "mail.dyne.org" email-server: "mail.dyne.org"