mustache templating, reorganisation and cleanup of code
This commit is contained in:
parent
527201ad89
commit
687dec948e
|
@ -26,7 +26,8 @@
|
|||
[me.raynes/conch "0.8.0"]
|
||||
;; time from joda-time
|
||||
[clj-time "0.14.4"]
|
||||
[clojure-humanize "0.2.2"]]
|
||||
[clojure-humanize "0.2.2"]
|
||||
[de.ubercode.clostache/clostache "1.4.0"]]
|
||||
:aliases {"test" "midje"}
|
||||
:source-paths ["src"]
|
||||
:resource-paths ["resources"]
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<div class="box">
|
||||
<h1 class="title">Upload a Dockerfile to toast</h1>
|
||||
<p>Choose the file in your computer and click 'Submit' to proceed to validation.</p>
|
||||
<form action="dockerfile" class="form-shell" enctype="multipart/form-data" method="post">
|
||||
<div class="file has-label is-fullwidth">
|
||||
<label class="file-label">
|
||||
<input class="file-input inputfile inputfile-2" id="file" type="file" />
|
||||
<label for="file"><span id="filename">Choose a Dockerfile...</span></label>
|
||||
<span class="file-cta"><span class="file-icon"><i class="fa fa-upload"></i></span><span class="file-label">Upload</span></span>
|
||||
</label></div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="button is-block is-info is-large is-fullwidth" name="submit" type="submit" value="submit" />
|
||||
</div></div>
|
||||
</form>
|
||||
<script>
|
||||
var file = document.getElementById("file");
|
||||
file.onchange = function(){
|
||||
if(file.files.length > 0) {
|
||||
document.getElementById('filename').innerHTML = file.files[0].name;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</div>
|
|
@ -0,0 +1,28 @@
|
|||
<footer class="footer">
|
||||
<div class="content has-text-centered">
|
||||
<p class="has-text-grey">toaster.do transforms your Docker prototype into an installable <a href="https://devuan.org">Devuan GNU+Linux</a> image, choose any supported target architecture.</p>
|
||||
<div class="columns is-variable is-8">
|
||||
<div class="column is-one-fifth">
|
||||
<figure class="image"><img alt="European project DECODE (H2020 nr. 732546)" src="/static/img/ec_logo.png" /></figure>
|
||||
</div>
|
||||
<div class="column is-one-fifth">
|
||||
<a href="https://decodeproject.eu">
|
||||
<figure class="image"><img alt="DECODE project" src="/static/img/decode_logo.png" /></figure>
|
||||
</a>
|
||||
</div>
|
||||
<div class="column is-one-fifth">
|
||||
<a href="https://www.dyne.org">
|
||||
<figure class="image"><img alt="Software by Dyne.org" src="/static/img/swbydyne.png" title="Software by Dyne.org" /></figure>
|
||||
</a>
|
||||
</div>
|
||||
<div class="column is-one-fifth">
|
||||
<a href="https://devuan.org">
|
||||
<figure class="image"><img alt="powered by Devuan GNU+Linux" src="/static/img/devuan_logo.png" /></figure>
|
||||
</a>
|
||||
</div>
|
||||
<div class="column is-one-fifth">
|
||||
<figure class="image"><img alt="Affero GPLv3 License" src="/static/img/AGPLv3.png" title="Affero GPLv3 License" /></figure>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
|
@ -0,0 +1,27 @@
|
|||
<section class="hero is-fullheight">
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<div class="column is-4 is-offset-4">
|
||||
<h3 class="title has-text-grey">toaster.do</h3>
|
||||
<h4 class="subtitle has-text-grey">from Docker to VM in a few clicks, powered by <a href="https://decodeproject.eu">DECODEproject.EU</a></h4>
|
||||
<p class="subtitle has-text-grey">please login to operate</p>
|
||||
<div class="box">
|
||||
<figure class="avatar"><img src="/static/img/cafudda.jpg" /></figure>
|
||||
<form action="/login" method="post">
|
||||
<div class="field">
|
||||
<div class="control has-icons-left">
|
||||
<input class="input is-large" name="username" placeholder="Email" type="email" /><span class="icon is-small is-left"><i class="fa fa-envelope fa-xs"></i></span></div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control has-icons-left"><input class="input is-large" name="password" placeholder="Password" type="password" /><span class="icon is-small is-left"><i class="fa fa-lock fa-xs"></i></span></div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<p class="control"><input class="button is-block is-info is-large has-icons-left is-fullwidth" type="submit" value="Login" /></p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<p class="subtitle has-text-grey">...or <a href="/signup">signup for a new account</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
|
@ -0,0 +1,32 @@
|
|||
<section class="hero is-fullheight">
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<div class="column is-4 is-offset-4">
|
||||
<h3 class="title has-text-grey">toaster.do</h3>
|
||||
<h4 class="subtitle has-text-grey">sign up for a new account</h4>
|
||||
<div class="box">
|
||||
<figure class="avatar"><img src="/static/img/cafudda.jpg" /></figure>
|
||||
<form action="/signup" method="post">
|
||||
<div class="field">
|
||||
<div class="control"><input class="input" name="name" placeholder="Name" type="text" /></div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control"><input class="input" name="email" placeholder="Email" type="email" /></div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control"><input class="input" name="password" placeholder="Password" type="password" /></div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control"><input class="input" name="repeat-password" placeholder="Repeat password" type="password" /></div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control"><input class="button is-block is-info is-large is-fullwidth" type="submit" value="Sign In" /></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible" />
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
||||
<title>toaster.do</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Ubuntu" rel="stylesheet" />
|
||||
<script src="/static/js/codemirror.js" type="text/javascript"></script>
|
||||
<script src="/static/js/codemirror-simple.js" type="text/javascript"></script>
|
||||
<script src="/static/js/codemirror-dockerfile.js" type="text/javascript"></script>
|
||||
<link href="/static/css/bulma.min.css" rel="stylesheet" type="text/css" />
|
||||
<link href="/static/css/json-html.css" rel="stylesheet" type="text/css" />
|
||||
<link href="/static/css/codemirror.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
|
||||
<link href="/static/css/toaster.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
|
@ -24,20 +24,6 @@
|
|||
[hiccup.page :as page]
|
||||
[hiccup.form :as hf]))
|
||||
|
||||
(declare render)
|
||||
(declare render-head)
|
||||
(declare navbar-guest)
|
||||
(declare navbar-account)
|
||||
(declare render-footer)
|
||||
(declare render-yaml)
|
||||
(declare render-edn)
|
||||
|
||||
|
||||
;; TODO: navbars for bulma
|
||||
(def navbar-brand [:div {:class "navbar"}])
|
||||
(def navbar-guest [:div {:class "navbar"}])
|
||||
(def navbar-account [:div {:class "navbar"}])
|
||||
|
||||
(defn button
|
||||
([url text] (button url text [:p]))
|
||||
|
||||
|
@ -65,106 +51,6 @@
|
|||
(:submit-params argmap)
|
||||
"btn-primary btn-lg btn-success col-md-3")])
|
||||
|
||||
(defn render
|
||||
([body]
|
||||
{:headers {"Content-Type"
|
||||
"text/html; charset=utf-8"}
|
||||
:body (page/html5
|
||||
(render-head)
|
||||
;; navbar-guest
|
||||
body
|
||||
(render-footer))})
|
||||
([account body]
|
||||
{:headers {"Content-Type"
|
||||
"text/html; charset=utf-8"}
|
||||
:body (page/html5
|
||||
(render-head)
|
||||
;; (if (empty? account)
|
||||
;; navbar-guest
|
||||
;; navbar-account)
|
||||
body
|
||||
(render-footer))}))
|
||||
|
||||
(defn notify
|
||||
"render a notification message without ending the page"
|
||||
([msg] (notify msg ""))
|
||||
([msg class]
|
||||
[:div {:class (str "notification " class " has-text-centered")} msg]))
|
||||
|
||||
(defn render-error [err] (->> "is-error" (notify (log/spy :error err)) render))
|
||||
|
||||
(defn render-head
|
||||
([] (render-head
|
||||
"toaster.do" ;; default title
|
||||
"From Docker to VM or ARM SDcard in a few clicks, powered by Devuan and the DECODE project" "https://toaster.dyne.org")) ;; default desc
|
||||
|
||||
([title desc url]
|
||||
[:head [:meta {:charset "utf-8"}]
|
||||
[:meta {:http-equiv "X-UA-Compatible" :content "IE=edge,chrome=1"}]
|
||||
[:meta
|
||||
{:name "viewport"
|
||||
:content "width=device-width, initial-scale=1"}]
|
||||
|
||||
[:title title]
|
||||
[:link {:href "https://fonts.googleapis.com/css?family=Ubuntu:300,400,700"
|
||||
:rel "stylesheet"}]
|
||||
|
||||
;; non-invasive js for syntax highlight of text-area
|
||||
(page/include-js "/static/js/codemirror.js")
|
||||
(page/include-js "/static/js/codemirror-simple.js")
|
||||
(page/include-js "/static/js/codemirror-dockerfile.js")
|
||||
|
||||
;; cascade style sheets
|
||||
(page/include-css "/static/css/bulma.min.css")
|
||||
(page/include-css "/static/css/json-html.css")
|
||||
(page/include-css "/static/css/codemirror.css")
|
||||
|
||||
|
||||
;; (page/include-css "/static/css/fa-regular.min.css")
|
||||
;; (page/include-css "/static/css/fontawesome.min.css")
|
||||
|
||||
(page/include-css "https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css")
|
||||
(page/include-css "/static/css/toaster.css")]))
|
||||
|
||||
(defn render-footer []
|
||||
[:footer {:class "footer"}
|
||||
[:div {:class "content has-text-centered"}
|
||||
[:p {:class "has-text-grey"} "toaster.do transforms your Docker prototype into "
|
||||
"an installable " [:a {:href "https://devuan.org"} "Devuan GNU+Linux"]
|
||||
" image, choose any supported target architecture."]
|
||||
[:div {:class "columns is-variable is-8"}
|
||||
|
||||
[: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"}
|
||||
[:figure {:class "image"}
|
||||
[:img {:src "/static/img/decode_logo.png"
|
||||
:alt "DECODE project"}]]]]
|
||||
|
||||
[:div {:class "column is-one-fifth"}
|
||||
[:a {:href "https://www.dyne.org"}
|
||||
[:figure {:class "image"}
|
||||
[:img {:src "/static/img/swbydyne.png"
|
||||
:alt "Software by Dyne.org"
|
||||
:title "Software by Dyne.org"}]]]]
|
||||
|
||||
[:div {:class "column is-one-fifth"}
|
||||
[:a {:href "https://devuan.org"}
|
||||
[:figure {:class "image"}
|
||||
[:img {:src "/static/img/devuan_logo.png"
|
||||
:alt "powered by Devuan GNU+Linux"}]]]]
|
||||
|
||||
[:div {:class "column is-one-fifth"}
|
||||
[:figure {:class "image"}
|
||||
[:img {:src "/static/img/AGPLv3.png" ;; :style "margin-top: 2.5em"
|
||||
:alt "Affero GPLv3 License"
|
||||
:title "Affero GPLv3 License"}]]]]]])
|
||||
|
||||
|
||||
;; highlight functions do no conversion, take the format they highlight
|
||||
;; render functions take edn and convert to the highlight format
|
||||
;; download functions all take an edn and convert it in target format
|
||||
|
@ -222,83 +108,3 @@
|
|||
:type "submit" :value "submit"}]])
|
||||
|
||||
(def brand-img "/static/img/cafudda.jpg")
|
||||
(defn- hero-login-box [body]
|
||||
[:section {:class "hero is-fullheight"}
|
||||
[:div {:class "hero-body"}
|
||||
[:div {:class "container has-text-centered"}
|
||||
body
|
||||
]]])
|
||||
|
||||
(def login-form
|
||||
(hero-login-box
|
||||
[:div {:class "column is-4 is-offset-4"}
|
||||
[:h3 {:class "title has-text-grey"} "toaster.do"]
|
||||
[:h4 {:class "subtitle has-text-grey"}
|
||||
"from Docker to VM in a few clicks, powered by "
|
||||
[:a {:href "https://decodeproject.eu"} "DECODEproject.EU"]]
|
||||
[:p {:class "subtitle has-text-grey"}
|
||||
"please login to operate"]
|
||||
[:div {:class "box"}
|
||||
[:figure {:class "avatar"}
|
||||
[:img {:src brand-img }]]
|
||||
[:form {:action "/login"
|
||||
:method "post"}
|
||||
[:div {:class "field"}
|
||||
;; [:label {:class "label is-large"} "Email"]
|
||||
[:div {:class "control has-icons-left"}
|
||||
[:input {:type "email" :name "username"
|
||||
:placeholder "Email"
|
||||
:class "input is-large"}]
|
||||
[:span {:class "icon is-small is-left"}
|
||||
[:i {:class "fa fa-envelope fa-xs"}]]]]
|
||||
[:div {:class "field"}
|
||||
;; [:label {:class "label is-large"} "Password"]
|
||||
[:div {:class "control has-icons-left"}
|
||||
[:input {:type "password" :name "password"
|
||||
:placeholder "Password"
|
||||
:class "input is-large"}]
|
||||
[:span {:class "icon is-small is-left"}
|
||||
[:i {:class "fa fa-lock fa-xs"}]]]]
|
||||
[:div {:class "field"}
|
||||
[:p {:class "control"}
|
||||
[:input {:type "submit" :value "Login"
|
||||
:class "button is-block is-info is-large has-icons-left is-fullwidth"}]]]]]
|
||||
[:p {:class "subtitle has-text-grey"}
|
||||
"...or " [:a {:href "/signup"} "signup for a new account"]]]))
|
||||
|
||||
(def signup-form
|
||||
(hero-login-box
|
||||
[:div {:class "column is-4 is-offset-4"}
|
||||
[:h3 {:class "title has-text-grey"} "toaster.do"]
|
||||
[:h4 {:class "subtitle has-text-grey"}
|
||||
"sign up for a new account"]
|
||||
;; [:p {:class "subtitle has-text-grey"}]
|
||||
[:div {:class "box"}
|
||||
[:figure {:class "avatar"}
|
||||
[:img {:src brand-img}]]
|
||||
[:form {:action "/signup"
|
||||
:method "post"}
|
||||
[:div {:class "field"}
|
||||
[:div {:class "control"}
|
||||
[:input {:type "text" :name "name"
|
||||
:placeholder "Name"
|
||||
:class "input"}]]]
|
||||
[:div {:class "field"}
|
||||
[:div {:class "control"}
|
||||
[:input {:type "email" :name "email"
|
||||
:placeholder "Email"
|
||||
:class "input"}]]]
|
||||
[:div {:class "field"}
|
||||
[:div {:class "control"}
|
||||
[:input {:type "password" :name "password"
|
||||
:placeholder "Password"
|
||||
:class "input"}]]]
|
||||
[:div {:class "field"}
|
||||
[:div {:class "control"}
|
||||
[:input {:type "password" :name "repeat-password"
|
||||
:placeholder "Repeat password"
|
||||
:class "input"}]]]
|
||||
[:div {:class "field"}
|
||||
[:div {:class "control"}
|
||||
[:input {:type "submit" :value "Sign In"
|
||||
:class "button is-block is-info is-large is-fullwidth"}]]]]]]))
|
||||
|
|
|
@ -37,16 +37,17 @@
|
|||
|
||||
[toaster.session :as s]
|
||||
[toaster.config :as conf]
|
||||
[toaster.bulma :as web :refer [render notify login-form]]
|
||||
[toaster.ring :as ring]
|
||||
[toaster.views :as views]
|
||||
[toaster.jobs :as job])
|
||||
[toaster.views :as views])
|
||||
(:gen-class))
|
||||
|
||||
(defonce config (conf/load-config "toaster" conf/default-settings))
|
||||
|
||||
|
||||
(defn auth-wrap [request fun]
|
||||
(defn auth-wrap
|
||||
"Comfortably wrap routes using a function pointer to be called if an
|
||||
account is correctly authenticated in the currently running session.
|
||||
(fun) is passed 3 hash-maps args: request, config and account."
|
||||
[request fun]
|
||||
(f/attempt-all
|
||||
[db (s/check-database)
|
||||
config (s/check-config request)
|
||||
|
@ -58,22 +59,9 @@
|
|||
(s/check-account request))]
|
||||
(fun request config account)
|
||||
(f/when-failed [e]
|
||||
(web/render [:body
|
||||
(web/notify (f/message e) "is-error")
|
||||
web/login-form]))))
|
||||
|
||||
(defn- login-page [request form]
|
||||
(f/attempt-all
|
||||
[acct (s/check-account request)]
|
||||
(web/render acct
|
||||
[:body
|
||||
[:h1 {:class "title"}
|
||||
(str "Already logged in with account: "
|
||||
(:email acct))]
|
||||
[:h2 {:class "subtitle"}
|
||||
[:a {:href "/logout"} "Logout"]]])
|
||||
(f/when-failed [e]
|
||||
(web/render [:body form]))))
|
||||
(s/render [:body
|
||||
(s/notify (f/message e) "is-error")
|
||||
(s/resource s/login)]))))
|
||||
|
||||
(defroutes
|
||||
app-routes
|
||||
|
@ -83,16 +71,16 @@
|
|||
[db (s/check-database)
|
||||
conf (s/check-config request)]
|
||||
(f/if-let-ok? [account (s/check-account request)]
|
||||
(web/render [:body (views/dashboard account)])
|
||||
(s/render [:body (views/dashboard account)])
|
||||
;; else
|
||||
(web/render [:body web/login-form]))
|
||||
(s/render [:body (s/resource s/login)]))
|
||||
(f/when-failed[e]
|
||||
(web/render [:body (web/notify (f/message e) "is-error")]))))
|
||||
(s/render [:body (s/notify (f/message e) "is-error")]))))
|
||||
|
||||
;; NEW ROUTES HERE
|
||||
(POST "/dockerfile" request
|
||||
(->> (fn [req conf acct]
|
||||
(web/render acct
|
||||
(s/render acct
|
||||
[:body
|
||||
(views/dockerfile-upload-post req conf acct)
|
||||
(views/dashboard acct)]))
|
||||
|
@ -100,34 +88,34 @@
|
|||
|
||||
(POST "/remove" request
|
||||
(->> (fn [req conf acct]
|
||||
(web/render acct [:body
|
||||
(s/render acct [:body
|
||||
(views/remove-job req conf acct)
|
||||
(views/dashboard acct)]))
|
||||
(auth-wrap request)))
|
||||
|
||||
(POST "/start" request
|
||||
(->> (fn [req conf acct]
|
||||
(web/render acct [:body
|
||||
(s/render acct [:body
|
||||
(views/start-job req conf acct)
|
||||
(views/dashboard acct)]))
|
||||
(auth-wrap request)))
|
||||
|
||||
(POST "/view" request
|
||||
(->> (fn [req conf acct]
|
||||
(web/render acct [:body
|
||||
(s/render acct [:body
|
||||
(views/view-job req conf acct)
|
||||
(views/dashboard acct)]))
|
||||
(auth-wrap request)))
|
||||
|
||||
(GET "/error" request
|
||||
(->> (fn [req conf acct]
|
||||
(web/render acct [:body
|
||||
(web/notify "Generic Error Page" "is-error")
|
||||
(s/render acct [:body
|
||||
(s/notify "Generic Error Page" "is-error")
|
||||
(views/dashboard acct)]))
|
||||
(auth-wrap request)))
|
||||
|
||||
;; JUST-AUTH ROUTES
|
||||
(GET "/login" request (login-page request web/login-form))
|
||||
(GET "/login" request (s/render (s/resource s/login)))
|
||||
|
||||
(POST "/login" request
|
||||
(f/attempt-all
|
||||
|
@ -139,22 +127,22 @@
|
|||
(let [session {:session {:config config
|
||||
:auth logged}}]
|
||||
(conj session
|
||||
(web/render logged [:body (views/dashboard logged)])))
|
||||
;; (web/render
|
||||
(s/render logged [:body (views/dashboard logged)])))
|
||||
;; (s/render
|
||||
;; logged
|
||||
;; [:div
|
||||
;; [:h1 "Logged in: " username]
|
||||
;; views/welcome-menu])))
|
||||
(f/when-failed [e]
|
||||
(web/render [:body (web/notify
|
||||
(s/render [:body (s/notify
|
||||
(str "Login failed: " (f/message e)) "is-error")]))))
|
||||
|
||||
(GET "/logout" request
|
||||
(conj {:session {:config config}}
|
||||
(web/render [:body
|
||||
(s/render [:body
|
||||
[:h1 {:class "title"} "Logged out."]])))
|
||||
|
||||
(GET "/signup" request (login-page request web/signup-form))
|
||||
(GET "/signup" request (s/render (s/resource s/signup)))
|
||||
(POST "/signup" request
|
||||
(f/attempt-all
|
||||
[name (s/param request :name)
|
||||
|
@ -163,7 +151,7 @@
|
|||
repeat-password (s/param request :repeat-password)
|
||||
activation {:activation-uri
|
||||
(get-in request [:headers "host"])}]
|
||||
(web/render
|
||||
(s/render
|
||||
(if (= password repeat-password)
|
||||
(f/try*
|
||||
(f/if-let-ok?
|
||||
|
@ -178,15 +166,15 @@
|
|||
name " <" email ">")]
|
||||
[:h3 "Account pending activation."]]
|
||||
[:body
|
||||
(web/notify
|
||||
(s/notify
|
||||
(str "Failure creating account: "
|
||||
(f/message signup)) "is-error")
|
||||
(login-page request web/signup-form)]))
|
||||
[:body (web/notify
|
||||
(s/resource s/signup)]))
|
||||
[:body (s/notify
|
||||
"Repeat password didnt match" "is-error")]))
|
||||
(f/when-failed [e]
|
||||
(web/render
|
||||
[:body (web/notify
|
||||
(s/render
|
||||
[:body (s/notify
|
||||
(str "Sign-up failure: " (f/message e)) "is-error")]))))
|
||||
|
||||
(GET "/activate/:email/:activation-id"
|
||||
|
@ -195,28 +183,28 @@
|
|||
(str "http://"
|
||||
(get-in request [:headers "host"])
|
||||
"/activate/" email "/" activation-id)]
|
||||
(web/render
|
||||
(s/render
|
||||
[:body
|
||||
(f/if-let-failed?
|
||||
[act (auth/activate-account
|
||||
@ring/auth email
|
||||
{:activation-link activation-uri})]
|
||||
(web/notify
|
||||
(s/notify
|
||||
[:span
|
||||
[:h1 {:class "title"} "Failure activating account"]
|
||||
[:h2 {:class "subtitle"} (f/message act)]
|
||||
[:p (str "Email: " email " activation-id: " activation-id)]] "is-error")
|
||||
(web/notify [:h1 {:class "title"} (str "Account activated - " email)] "is-success"))])))
|
||||
(s/notify [:h1 {:class "title"} (str "Account activated - " email)] "is-success"))])))
|
||||
;; -- end of JUST-AUTH
|
||||
|
||||
(POST "/" request
|
||||
;; generic endpoint for canceled operations
|
||||
(web/render (s/check-account request)
|
||||
(web/notify
|
||||
(s/render (s/check-account request)
|
||||
(s/notify
|
||||
(s/param request :message) "is-error")))
|
||||
|
||||
(route/resources "/")
|
||||
(route/not-found (web/render [:body (web/notify "Page Not Found" "is-error")]))
|
||||
(route/not-found (s/render [:body (s/notify "Page Not Found" "is-error")]))
|
||||
|
||||
) ;; end of routes
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
[failjure.core :as f]
|
||||
[taoensso.timbre :as log :refer [debug]]
|
||||
[me.raynes.conch :as sh :refer [with-programs]]
|
||||
[toaster.bulma :as web]
|
||||
[toaster.config :refer :all]
|
||||
[toaster.ring :refer [jobs]]
|
||||
[hiccup.form :as hf]))
|
||||
|
|
|
@ -5,8 +5,19 @@
|
|||
[taoensso.timbre :as log]
|
||||
[failjure.core :as f]
|
||||
[just-auth.core :as auth]
|
||||
[toaster.ring :as ring]
|
||||
[toaster.bulma :as web]))
|
||||
[hiccup.page :as page :refer [html5]]
|
||||
[clostache.parser :refer [render-resource]]
|
||||
[toaster.ring :as ring]))
|
||||
|
||||
(defn resource
|
||||
"renders a template, optionally passing it an hash-map of parameters."
|
||||
([template] (resource template {}))
|
||||
([template params] (render-resource template params)))
|
||||
|
||||
(defonce login "templates/body_loginform.html")
|
||||
(defonce signup "templates/body_signupform.html")
|
||||
(defonce head "templates/html_head.html")
|
||||
(defonce footer "templates/body_footer.html")
|
||||
|
||||
(defn param [request param]
|
||||
(let [value
|
||||
|
@ -46,3 +57,29 @@
|
|||
(if-let [db @ring/db]
|
||||
db
|
||||
(f/fail "No connection to database.")))
|
||||
|
||||
|
||||
(defn notify
|
||||
"render a notification message without ending the page"
|
||||
([msg] (notify msg ""))
|
||||
([msg class]
|
||||
;; support also is-error (not included as notify class in bulma
|
||||
(let [tclass (if (= class "is-error") "is-danger" class)]
|
||||
(cond ;; log to console using timbre
|
||||
(= tclass "is-danger") (log/error msg)
|
||||
(= tclass "is-warning") (log/warn msg)
|
||||
(= tclass "is-success") (log/info msg)
|
||||
(= tclass "is-primary") (log/debug msg))
|
||||
[:div {:class (str "notification " tclass " has-text-centered")} msg])))
|
||||
|
||||
(defn render
|
||||
"render a full webpage using headers, navbar, body and footer"
|
||||
([body] (render nil body))
|
||||
([account body]
|
||||
{:headers {"Content-Type"
|
||||
"text/html; charset=utf-8"}
|
||||
:body (page/html5
|
||||
(resource head)
|
||||
(conj body (resource footer)))}))
|
||||
|
||||
(defn render-error [err] (->> "is-danger" (notify (log/spy :error err)) render))
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
[clojure.string :as str]
|
||||
[clojure.contrib.humanize :as humanize :refer [datetime]]
|
||||
;; [clojure.data.json :as json :refer [read-str]]
|
||||
[toaster.bulma :as web :refer [button notify render-yaml]]
|
||||
[toaster.bulma :as web :refer [button render-yaml]]
|
||||
[toaster.session :as s]
|
||||
[toaster.ring :as ring]
|
||||
[toaster.jobs :as job]
|
||||
|
@ -35,8 +35,10 @@
|
|||
[clj-time.coerce :as tc]
|
||||
[clj-time.local :as tl]
|
||||
[clj-storage.core :as db]
|
||||
[hiccup.form :as hf]))
|
||||
[hiccup.form :as hf]
|
||||
[clostache.parser :refer [render-resource]]))
|
||||
|
||||
;; TODO: templated
|
||||
(defn- box-list [account joblist]
|
||||
[:div {:class "box"}
|
||||
[:h1 {:class "title"} (str "List all toaster jobs for " (:name account))]
|
||||
|
@ -61,34 +63,6 @@
|
|||
(web/button "/remove" "\uD83D\uDDD1" (hf/hidden-field "jobid" jobid))]]]
|
||||
))]]])
|
||||
|
||||
(defn- box-add []
|
||||
[:div {:class "box"}
|
||||
[: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 inputfile inputfile-2" :id "file" :type "file"}]
|
||||
[:label {:for "file"} [:span {:id "filename"} "Choose a Dockerfile..."]]
|
||||
[:span {:class "file-cta"}
|
||||
[:span {:class "file-icon"}
|
||||
[:i {:class "fa fa-upload"}]]
|
||||
[:span {:class "file-label"} "Upload"]]]]
|
||||
;; [: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"}]]]]
|
||||
[:script "var file = document.getElementById(\"file\");
|
||||
file.onchange = function(){
|
||||
if(file.files.length > 0) {
|
||||
document.getElementById('filename').innerHTML = file.files[0].name;
|
||||
} };"]])
|
||||
|
||||
(defn dockerfile-upload-post [request config account]
|
||||
(let
|
||||
[tempfile (get-in request [:params :file :tempfile])
|
||||
|
@ -112,7 +86,7 @@
|
|||
[:h1 {:class "title"} "Job uploaded and added"]
|
||||
[:p "Log messages:"]
|
||||
(web/render-yaml newjob)]
|
||||
(web/notify (f/message newjob) "is-error")))))))
|
||||
(s/notify (f/message newjob) "is-error")))))))
|
||||
|
||||
(defn dashboard
|
||||
([account] (dashboard {} {} account))
|
||||
|
@ -125,9 +99,9 @@
|
|||
;(if (> 0 (count joblist))
|
||||
(box-list account joblist)
|
||||
;)
|
||||
(box-add) ]]
|
||||
(s/resource "templates/body_addjob.html") ]]
|
||||
(f/when-failed [e]
|
||||
(web/notify
|
||||
(s/notify
|
||||
(str "Job list failure: " (f/message e)) "is-error")))))
|
||||
|
||||
(defn remove-job [request config account]
|
||||
|
@ -136,18 +110,18 @@
|
|||
jobfound (db/query @ring/jobs {:jobid jobid})
|
||||
r_rmjob (db/delete! @ring/jobs jobid)
|
||||
r_sync (job/sync_jobs config "-d" jobid)]
|
||||
(web/notify (str "Job removed: " jobid) "is-primary")
|
||||
(s/notify (str "Job removed: " jobid) "is-primary")
|
||||
(f/when-failed [e]
|
||||
(web/notify (str "Failure removing job: " (f/message e)) "is-error"))))
|
||||
(s/notify (str "Failure removing job: " (f/message e)) "is-error"))))
|
||||
|
||||
(defn start-job [request config account]
|
||||
(f/attempt-all
|
||||
[jobid (s/param request :jobid)
|
||||
jobfound (db/query @ring/jobs {:jobid jobid})
|
||||
r_sync (job/sync_jobs config "-r" jobid)]
|
||||
(web/notify (str "Job started: " jobid) "is-success")
|
||||
(s/notify (str "Job started: " jobid) "is-success")
|
||||
(f/when-failed [e]
|
||||
(web/notify (str "Failure starting job: " (f/message e)) "is-error"))))
|
||||
(s/notify (str "Failure starting job: " (f/message e)) "is-error"))))
|
||||
|
||||
(defn view-job [request config account]
|
||||
(f/attempt-all
|
||||
|
@ -160,4 +134,4 @@
|
|||
[:script "var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"),
|
||||
{ lineNumbers: true, mode: \"dockerfile\" });"]]
|
||||
(f/when-failed [e]
|
||||
(web/notify (str "Failure viewing job: " (f/message e)) "is-error"))))
|
||||
(s/notify (str "Failure viewing job: " (f/message e)) "is-error"))))
|
||||
|
|
Loading…
Reference in New Issue