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:
parent
d162d16116
commit
de76c4887d
|
@ -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,7 +71,7 @@
|
||||||
"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)])})
|
||||||
|
@ -88,24 +86,13 @@
|
||||||
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"}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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])
|
||||||
|
{:email "mock@dyne.org"
|
||||||
|
:name "MockUser"
|
||||||
|
:activated true}
|
||||||
|
;; else
|
||||||
|
(check-account request))]
|
||||||
(fun request config account)
|
(fun request config account)
|
||||||
(f/when-failed [e]
|
(f/when-failed [e]
|
||||||
(web/render
|
(web/render [:span
|
||||||
[:div
|
(web/notify (f/message e) "is-error")
|
||||||
(web/render-error (f/message e))
|
web/login-form
|
||||||
web/login-form]))))
|
]))))
|
||||||
|
|
|
@ -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,80 +37,9 @@
|
||||||
[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"} "Upload a Dockerfile to toast"]
|
|
||||||
[:p " Choose the file in your computer and click 'Submit' to
|
|
||||||
proceed to validation."]
|
|
||||||
[:form {:action "dockerfile" :method "post"
|
|
||||||
:class "form-shell"
|
|
||||||
:enctype "multipart/form-data"}
|
|
||||||
[:div {:class "file has-label is-fullwidth"}
|
|
||||||
[:label {:class "file-label"}
|
|
||||||
[:input {:class "file-input" :name "file" :type "file"}]
|
|
||||||
[:span {:class "file-cta"}
|
|
||||||
[:span {:class "file-icon"}
|
|
||||||
[:i {:class "fa fa-upload"}]]
|
|
||||||
[:span {:class "file-label"}
|
|
||||||
"Docker file..."]]
|
|
||||||
[:span {:class "file-name"}]]]
|
|
||||||
;; [:fieldset {:class "fieldset-submit"}
|
|
||||||
|
|
||||||
[:div {:class "field"}
|
|
||||||
[:div {:class "control"}
|
|
||||||
[:input {:class "button is-block is-info is-large is-fullwidth"
|
|
||||||
:type "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]
|
|
||||||
(let
|
|
||||||
[tempfile (get-in request [:params :file :tempfile])
|
|
||||||
filename (get-in request [:params :file :filename])
|
|
||||||
params (:params request)]
|
|
||||||
(cond
|
|
||||||
(> (get-in params [:file :size]) 64000)
|
|
||||||
;; max upload size in bytes
|
|
||||||
;; TODO: put in config
|
|
||||||
(web/render-error params "File too big in upload (64KB limit).")
|
|
||||||
:else
|
|
||||||
(let [file (io/copy tempfile (io/file "/tmp" filename))
|
|
||||||
path (str "/tmp/" filename)]
|
|
||||||
(io/delete-file tempfile)
|
|
||||||
(if (not (.exists (io/file path)))
|
|
||||||
(web/render-error
|
|
||||||
(log/spy :error
|
|
||||||
[:h1 (str "Uploaded file not found: " filename)]))
|
|
||||||
;; file is now in 'tmp' var
|
|
||||||
[:div {:class "container"}
|
|
||||||
[:h1 {:class "title"} "Job uploaded and added"]
|
|
||||||
[:p "Log messages:"]
|
|
||||||
(web/render-yaml (job/add path config account))])))))
|
|
||||||
|
|
||||||
(defn list-jobs [account]
|
|
||||||
(f/attempt-all
|
|
||||||
[joblist (db/query @ring/jobs {:email (:email account)})]
|
|
||||||
[:div {:class "container has-text-centered"}
|
|
||||||
[:h1 {:class "title"} (str "List all toaster jobs for " (:name account))]
|
[:h1 {:class "title"} (str "List all toaster jobs for " (:name account))]
|
||||||
|
|
||||||
[:div {:class "box"}
|
|
||||||
[:table {:class "table is-fullwidth is-hoverable"}
|
[:table {:class "table is-fullwidth is-hoverable"}
|
||||||
[:thead nil
|
[:thead nil
|
||||||
[:tr nil [:th nil "Date"] [:th nil "Type"] [:th nil "Status"] [:th nil "Actions"]]]
|
[:tr nil [:th nil "Date"] [:th nil "Type"] [:th nil "Status"] [:th nil "Actions"]]]
|
||||||
|
@ -112,11 +59,70 @@
|
||||||
(web/button "/view" "\uD83D\uDC41" (hf/hidden-field "jobid" jobid))
|
(web/button "/view" "\uD83D\uDC41" (hf/hidden-field "jobid" jobid))
|
||||||
(web/button "/start" "▶" (hf/hidden-field "jobid" jobid))
|
(web/button "/start" "▶" (hf/hidden-field "jobid" jobid))
|
||||||
(web/button "/remove" "\uD83D\uDDD1" (hf/hidden-field "jobid" jobid))]]]
|
(web/button "/remove" "\uD83D\uDDD1" (hf/hidden-field "jobid" jobid))]]]
|
||||||
))]]]]
|
))]]])
|
||||||
(f/when-failed [e]
|
|
||||||
(web/render-error
|
|
||||||
(str "Job list failure: " (f/message e))))))
|
|
||||||
|
|
||||||
|
(defn- box-add []
|
||||||
|
[:div {:class "box column"}
|
||||||
|
[:h1 {:class "title"} "Upload a Dockerfile to toast"]
|
||||||
|
[:p " Choose the file in your computer and click 'Submit' to
|
||||||
|
proceed to validation."]
|
||||||
|
[:form {:action "dockerfile" :method "post"
|
||||||
|
:class "form-shell"
|
||||||
|
:enctype "multipart/form-data"}
|
||||||
|
[:div {:class "file has-label is-fullwidth"}
|
||||||
|
[:label {:class "file-label"}
|
||||||
|
[:input {:class "file-input" :name "file" :type "file"}]
|
||||||
|
[:span {:class "file-cta"}
|
||||||
|
[:span {:class "file-icon"}
|
||||||
|
[:i {:class "fa fa-upload"}]]
|
||||||
|
[:span {:class "file-label"}
|
||||||
|
"Docker file..."]]
|
||||||
|
[:span {:class "file-name"}]]]
|
||||||
|
;; [:fieldset {:class "fieldset-submit"}
|
||||||
|
[:div {:class "field"}
|
||||||
|
[:div {:class "control"}
|
||||||
|
[:input {:class "button is-block is-info is-large is-fullwidth"
|
||||||
|
:type "submit"
|
||||||
|
:name "submit" :value "submit"}]]]]])
|
||||||
|
|
||||||
|
(defn dockerfile-upload-post [request config account]
|
||||||
|
(let
|
||||||
|
[tempfile (get-in request [:params :file :tempfile])
|
||||||
|
filename (get-in request [:params :file :filename])
|
||||||
|
params (:params request)]
|
||||||
|
(cond
|
||||||
|
(> (get-in params [:file :size]) 64000)
|
||||||
|
;; max upload size in bytes
|
||||||
|
;; TODO: put in config
|
||||||
|
(f/fail "File too big in upload (64KB limit).")
|
||||||
|
:else
|
||||||
|
(let [file (io/copy tempfile (io/file "/tmp" filename))
|
||||||
|
path (str "/tmp/" filename)]
|
||||||
|
(io/delete-file tempfile)
|
||||||
|
(if (not (.exists (io/file path)))
|
||||||
|
(f/fail
|
||||||
|
(str "Uploaded file not found: " filename))
|
||||||
|
;; file is now in 'tmp' var
|
||||||
|
(f/if-let-ok? [newjob (job/add path config account)]
|
||||||
|
[:div {:class "container"}
|
||||||
|
[:h1 {:class "title"} "Job uploaded and added"]
|
||||||
|
[:p "Log messages:"]
|
||||||
|
(web/render-yaml newjob)]
|
||||||
|
(web/notify (f/message newjob) "is-error")))))))
|
||||||
|
|
||||||
|
(defn dashboard
|
||||||
|
([account] (dashboard {} {} account))
|
||||||
|
([request config account]
|
||||||
|
(f/attempt-all
|
||||||
|
[joblist (db/query @ring/jobs {:email (:email account)})]
|
||||||
|
[:div {:class "container has-text-centered"}
|
||||||
|
|
||||||
|
[:div {:class "columns"}
|
||||||
|
(if (> 0 (count joblist)) (box-list account joblist))
|
||||||
|
(box-add) ]]
|
||||||
|
(f/when-failed [e]
|
||||||
|
(web/notify
|
||||||
|
(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"))))
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue