Adding tests.
This commit is contained in:
17
src/db.scm
17
src/db.scm
@@ -5,7 +5,7 @@
|
||||
;;functions
|
||||
with-db with-db/transaction
|
||||
|
||||
create-user
|
||||
create-user delete-user
|
||||
update-user-service-config get-user-service-config
|
||||
update-user-selected-apps get-user-selected-apps
|
||||
update-user-app-config get-user-app-config
|
||||
@@ -126,13 +126,6 @@
|
||||
(user-iv (blob->hexstring/uppercase (generate-iv))))
|
||||
(receive (enc-user-key tag)
|
||||
(encrypt user-key *root-key-key* *root-key-iv* (string->blob (number->string auth-user-id)))
|
||||
;; (write user-key)
|
||||
;; (newline)
|
||||
;; (write user-iv)
|
||||
;; (newline)
|
||||
;; (write (blob->hexstring/uppercase (string->blob enc-user-key)))
|
||||
;; (newline)
|
||||
;; (write (blob->hexstring/uppercase (string->blob tag)))
|
||||
(let ((user-id
|
||||
(value-at
|
||||
(query conn
|
||||
@@ -145,7 +138,11 @@ returning users.user_id;"
|
||||
(query conn "insert into user_service_configs(user_id) values ($1);" user-id)
|
||||
(query conn "insert into user_selected_apps(user_id) values ($1);" user-id)
|
||||
(query conn "insert into user_app_configs(user_id) values ($1);" user-id)
|
||||
(query conn "insert into user_terraform_state(user_id) values ($1);" user-id)))))
|
||||
(query conn "insert into user_terraform_state(user_id) values ($1);" user-id)
|
||||
user-id))))
|
||||
|
||||
(define (delete-user conn user-id)
|
||||
(query conn "delete from users where user_id=$1;" user-id))
|
||||
|
||||
(define *user-service-configs-column-map*
|
||||
'((cloudflare-api-token . ("cloudflare_api_token_enc" #t))
|
||||
@@ -443,7 +440,7 @@ returning users.user_id;"
|
||||
""
|
||||
(user-decrypt-from-db (alist-ref 'state_backup_enc res) user-key user-iv user-id)))))))
|
||||
|
||||
(with-db/transaction (lambda (db) (get-user-deployments db 7)))
|
||||
;; (with-db/transaction (lambda (db) (get-user-deployments db 7)))
|
||||
;; (with-db/transaction (lambda (db) (get-most-recent-deployment-progress db 7)))
|
||||
;; (with-db/transaction (lambda (db) (get-deployment-progress db 14)))
|
||||
;; (with-db/transaction (lambda (db) (update-deployment-progress db 14 '((generate-configs . complete) (custom-image . in-progress) (machine-create . queued)))))
|
||||
|
||||
3096
src/mocks.scm
Normal file
3096
src/mocks.scm
Normal file
File diff suppressed because one or more lines are too long
653
src/nassella.scm
653
src/nassella.scm
@@ -1,4 +1,5 @@
|
||||
(load "db.scm")
|
||||
(load "mocks.scm")
|
||||
|
||||
(import (chicken string)
|
||||
(chicken port)
|
||||
@@ -14,7 +15,7 @@
|
||||
|
||||
html-widgets
|
||||
sxml-transforms
|
||||
(prefix schematra schematra:)
|
||||
schematra
|
||||
schematra-body-parser
|
||||
schematra-session
|
||||
uri-common
|
||||
@@ -24,7 +25,11 @@
|
||||
nassella-db
|
||||
sql-null)
|
||||
|
||||
(schematra:use-middleware! (body-parser-middleware))
|
||||
(define app (schematra/make-app))
|
||||
|
||||
(with-schematra-app app
|
||||
(lambda ()
|
||||
(use-middleware! (body-parser-middleware))))
|
||||
|
||||
(define *global-css-reset*
|
||||
"/*
|
||||
@@ -261,31 +266,45 @@ h1, h2, h3, h4, h5, h6 {
|
||||
val))
|
||||
(resolved-style-path-value *style-tokens* path-or-symbol)))
|
||||
|
||||
|
||||
(define test-mode (make-parameter #f))
|
||||
(define last-request-body-sxml (make-parameter '()))
|
||||
(define last-request-body-widget-sxml (make-parameter '()))
|
||||
|
||||
(define (widget-sxml->html sxml-head sxml-body)
|
||||
(let ((sxml-head-out (widget->sxml-and-css sxml-head)))
|
||||
(receive (sxml-body-out css-list)
|
||||
(widget->sxml-and-css sxml-body)
|
||||
(when test-mode
|
||||
(last-request-body-widget-sxml sxml-body)
|
||||
(last-request-body-sxml (widget->sxml sxml-body)))
|
||||
(print "<!DOCTYPE html>")
|
||||
(SXML->HTML
|
||||
`(html (head (style ,(apply string-append (cons *global-css-reset* css-list)))
|
||||
,@sxml-head-out)
|
||||
,sxml-body-out)))))
|
||||
|
||||
(schematra:use-middleware! (session-middleware "your-secret-key-here"))
|
||||
(with-schematra-app app
|
||||
(lambda ()
|
||||
(use-middleware! (session-middleware "your-secret-key-here")))) ;; TODO generate better one
|
||||
|
||||
(define-syntax get
|
||||
(define test-user-id (make-parameter 7))
|
||||
(define (session-user-id)
|
||||
(or (session-get "user-id") (test-user-id)))
|
||||
|
||||
(define-syntax get/widgets
|
||||
(syntax-rules ()
|
||||
((_ (path) body ...)
|
||||
(schematra:get (path)
|
||||
(with-output-to-string
|
||||
(lambda ()
|
||||
(widget-sxml->html
|
||||
'((meta (@ (name "viewport") (content "width=device-width"))))
|
||||
(begin
|
||||
;; TODO remove once sessions are integrated
|
||||
(session-set! "user-id" 7)
|
||||
(session-set! "username" "me")
|
||||
body ...))))))))
|
||||
(get path
|
||||
(with-output-to-string
|
||||
(lambda ()
|
||||
(widget-sxml->html
|
||||
'((meta (@ (name "viewport") (content "width=device-width"))))
|
||||
(begin
|
||||
;; TODO remove once sessions are integrated
|
||||
(session-set! "user-id" (test-user-id))
|
||||
(session-set! "username" "me")
|
||||
body ...))))))))
|
||||
|
||||
(define-widget (Container ((max-width ($ 'width.main.max)) (style '())) contents)
|
||||
`(div (@ (data-name "Container")
|
||||
@@ -479,164 +498,6 @@ h1, h2, h3, h4, h5, h6 {
|
||||
"Back")
|
||||
(Button ,submit-button)))
|
||||
|
||||
(get
|
||||
("/config/wizard/services")
|
||||
(let ((config (with-db/transaction (lambda (db) (get-user-service-config db (session-get "user-id"))))))
|
||||
`(App
|
||||
(Configuration-Wizard
|
||||
(@ (step "Services"))
|
||||
(form
|
||||
(@ (action "/config/wizard/services-submit")
|
||||
(method POST))
|
||||
(VStack
|
||||
(Fieldset
|
||||
(@ (title "Cloudflare"))
|
||||
(Field (@ (name "cloudflare-api-token") (label ("API Token")) (value ,(alist-ref 'cloudflare-api-token config))))
|
||||
(Field (@ (name "cloudflare-zone-id") (label ("Zone ID")) (value ,(alist-ref 'cloudflare-zone-id config))))
|
||||
(Field (@ (name "cloudflare-account-id") (label ("Account ID")) (value ,(alist-ref 'cloudflare-account-id config)))))
|
||||
(Fieldset
|
||||
(@ (title "DigitalOcean"))
|
||||
(Field (@ (name "digitalocean-api-token") (label ("API Token")) (value ,(alist-ref 'digitalocean-api-token config)))))
|
||||
(Fieldset
|
||||
(@ (title "Backblaze"))
|
||||
(Field (@ (name "backblaze-application-key") (label ("Application Key")) (value ,(alist-ref 'backblaze-application-key config))))
|
||||
(Field (@ (name "backblaze-key-id") (label ("Key ID")) (value ,(alist-ref 'backblaze-key-id config))))
|
||||
(Field (@ (name "backblaze-bucket-url") (label ("Bucket URL")) (value ,(alist-ref 'backblaze-bucket-url config)))))
|
||||
(Form-Nav)))))))
|
||||
|
||||
(schematra:post ("/config/wizard/services-submit")
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
(update-user-service-config
|
||||
db
|
||||
(session-get "user-id")
|
||||
`((cloudflare-api-token . ,(alist-ref 'cloudflare-api-token (schematra:current-params)))
|
||||
(cloudflare-account-id . ,(alist-ref 'cloudflare-account-id (schematra:current-params)))
|
||||
(cloudflare-zone-id . ,(alist-ref 'cloudflare-zone-id (schematra:current-params)))
|
||||
(digitalocean-api-token . ,(alist-ref 'digitalocean-api-token (schematra:current-params)))
|
||||
(backblaze-application-key . ,(alist-ref 'backblaze-application-key (schematra:current-params)))
|
||||
(backblaze-key-id . ,(alist-ref 'backblaze-key-id (schematra:current-params)))
|
||||
(backblaze-bucket-url . ,(alist-ref 'backblaze-bucket-url (schematra:current-params)))))))
|
||||
(schematra:redirect "/config/wizard/services-success"))
|
||||
|
||||
(get
|
||||
("/config/wizard/services-success")
|
||||
`(App
|
||||
(Configuration-Wizard
|
||||
(@ (step "Services"))
|
||||
(form
|
||||
(@ (action "/config/wizard/apps"))
|
||||
(VStack
|
||||
(Fieldset
|
||||
(@ (title "Cloudflare"))
|
||||
(h3 "Connected")
|
||||
(p "Your Cloudflare account was successfully connected!"))
|
||||
(Fieldset
|
||||
(@ (title "DigitalOcean"))
|
||||
(h3 "Connected")
|
||||
(p "Your DigitalOcean account was successfully connected!"))
|
||||
(Fieldset
|
||||
(@ (title "Backblaze"))
|
||||
(h3 "Connected")
|
||||
(p "Your Backblaze account was successfully connected!"))
|
||||
(Form-Nav (@ (back-to "/config/wizard/services"))))))))
|
||||
|
||||
(get
|
||||
("/config/wizard/apps")
|
||||
(let ((results
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
`((selected-apps . ,(map
|
||||
car
|
||||
(filter cdr
|
||||
(get-user-selected-apps db (session-get "user-id")))))
|
||||
(app-config . ,(get-user-app-config db (session-get "user-id"))))))))
|
||||
`(App
|
||||
(Configuration-Wizard
|
||||
(@ (step "Apps"))
|
||||
(form
|
||||
(@ (action "/config/wizard/apps-submit") (method POST))
|
||||
(VStack
|
||||
(Fieldset
|
||||
(@ (title "Root Domain"))
|
||||
(Field (@ (element select) (name "root-domain"))
|
||||
(option (@ (value ,(alist-ref 'root-domain (alist-ref 'app-config results)))) "nassella.cc"))) ;; TODO fetch from cloudflare API?
|
||||
(Fieldset
|
||||
(@ (title "Selected Apps"))
|
||||
(Field (@ (name "wg-easy") (type "checkbox") (label ("WG Easy")) (checked ,(member 'wg-easy (alist-ref 'selected-apps results)))))
|
||||
(Field (@ (name "nextcloud") (type "checkbox") (label ("NextCloud")) (checked ,(member 'nextcloud (alist-ref 'selected-apps results)))))
|
||||
(Field (@ (name "log-viewer") (type "checkbox") (label ("Log Viewer")) (checked #t) (disabled "disabled"))))
|
||||
(Form-Nav (@ (back-to "/config/wizard/services-success")))))))))
|
||||
|
||||
(schematra:post ("/config/wizard/apps-submit")
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
(update-user-selected-apps
|
||||
db
|
||||
(session-get "user-id")
|
||||
`((wg-easy . ,(or (and (alist-ref 'wg-easy (schematra:current-params)) "0.0") (sql-null)))
|
||||
(nextcloud . ,(or (and (alist-ref 'nextcloud (schematra:current-params)) "0.0") (sql-null)))))
|
||||
(update-root-domain db (session-get "user-id") (alist-ref 'root-domain (schematra:current-params)))))
|
||||
(schematra:redirect "/config/wizard/apps2"))
|
||||
|
||||
(get
|
||||
("/config/wizard/apps2")
|
||||
(let* ((results
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
`((selected-apps . ,(map
|
||||
car
|
||||
(filter cdr
|
||||
(get-user-selected-apps db (session-get "user-id")))))
|
||||
(app-config . ,(get-user-app-config db (session-get "user-id")))))))
|
||||
(selected-apps (alist-ref 'selected-apps results))
|
||||
(app-config (alist-ref 'app-config results)))
|
||||
`(App
|
||||
(Configuration-Wizard
|
||||
(@ (step "Apps"))
|
||||
(form
|
||||
(@ (action "/config/wizard/apps2-submit") (method POST))
|
||||
(VStack
|
||||
,@(if (member 'wg-easy selected-apps)
|
||||
`((Fieldset
|
||||
(@ (title "WG-Easy"))
|
||||
(Field (@ (name "wg-easy-subdomain") (label ("Subdomain")) (value ,(alist-ref 'subdomain (alist-ref 'wg-easy app-config eq? '()) eq? "wg-easy"))))))
|
||||
'())
|
||||
,@(if (member 'nextcloud selected-apps)
|
||||
`((Fieldset
|
||||
(@ (title "NextCloud"))
|
||||
(Field (@ (name "nextcloud-subdomain") (label ("Subdomain"))
|
||||
(value ,(alist-ref 'subdomain (alist-ref 'nextcloud app-config eq? '()) eq? "nextcloud"))))
|
||||
(Field (@ (name "nextcloud-admin-user") (label ("Admin Username"))
|
||||
(value ,(alist-ref 'admin-user (alist-ref 'nextcloud app-config eq? '()) eq? "admin"))))
|
||||
(Field (@ (name "nextcloud-admin-password") (label ("Admin Password")) (type "password")
|
||||
(value ,(alist-ref 'admin-password (alist-ref 'nextcloud app-config eq? '()) eq? ""))))))
|
||||
'())
|
||||
(Fieldset
|
||||
(@ (title "Log Viewer"))
|
||||
(Field (@ (name "log-viewer-subdomain") (label ("Subdomain"))
|
||||
(value ,(alist-ref 'subdomain (alist-ref 'log-viewer app-config eq? '()) eq? "logs"))))
|
||||
(Field (@ (name "log-viewer-user") (label ("Username"))
|
||||
(value ,(alist-ref 'user (alist-ref 'log-viewer app-config eq? '()) eq? ""))))
|
||||
(Field (@ (name "log-viewer-password") (label ("Password")) (type "password")
|
||||
(value ,(alist-ref 'password (alist-ref 'log-viewer app-config eq? '()) eq? "")))))
|
||||
(Form-Nav (@ (back-to "/config/wizard/apps")))))))))
|
||||
|
||||
(schematra:post ("/config/wizard/apps2-submit")
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
(update-user-app-config
|
||||
db
|
||||
(session-get "user-id")
|
||||
`((wg-easy . ((subdomain . ,(alist-ref 'wg-easy-subdomain (schematra:current-params)))))
|
||||
(nextcloud . ((subdomain . ,(alist-ref 'nextcloud-subdomain (schematra:current-params)))
|
||||
(admin-user . ,(alist-ref 'nextcloud-admin-user (schematra:current-params)))
|
||||
(admin-password . ,(alist-ref 'nextcloud-admin-password (schematra:current-params)))))
|
||||
(log-viewer . ((subdomain . ,(alist-ref 'log-viewer-subdomain (schematra:current-params)))
|
||||
(user . ,(alist-ref 'log-viewer-user (schematra:current-params)))
|
||||
(password . ,(alist-ref 'log-viewer-password (schematra:current-params)))))))))
|
||||
(schematra:redirect "/config/wizard/machine"))
|
||||
|
||||
;; Parsing JSON arrays as lists instead of vectors
|
||||
(define array-as-list-parser
|
||||
(cons 'array (lambda (x) x)))
|
||||
@@ -647,14 +508,16 @@ h1, h2, h3, h4, h5, h6 {
|
||||
(filter
|
||||
(lambda (r)
|
||||
(alist-ref 'available r))
|
||||
(alist-ref
|
||||
'regions
|
||||
(let* ((uri (uri-reference "https://api.digitalocean.com/v2/regions"))
|
||||
(req (make-request method: 'GET
|
||||
uri: uri
|
||||
headers: (headers `((content-type application/json)
|
||||
(Authorization ,(conc "Bearer " api-token)))))))
|
||||
(with-input-from-request req #f read-json)))))
|
||||
(if (test-mode)
|
||||
*digital-ocean-regions-response*
|
||||
(alist-ref
|
||||
'regions
|
||||
(let* ((uri (uri-reference "https://api.digitalocean.com/v2/regions"))
|
||||
(req (make-request method: 'GET
|
||||
uri: uri
|
||||
headers: (headers `((content-type application/json)
|
||||
(Authorization ,(conc "Bearer " api-token)))))))
|
||||
(with-input-from-request req #f read-json))))))
|
||||
|
||||
(define (get-digital-ocean-sizes api-token)
|
||||
(filter
|
||||
@@ -662,114 +525,14 @@ h1, h2, h3, h4, h5, h6 {
|
||||
(alist-ref 'available r))
|
||||
(alist-ref
|
||||
'sizes
|
||||
(let* ((uri (uri-reference "https://api.digitalocean.com/v2/sizes?per_page=200"))
|
||||
(req (make-request method: 'GET
|
||||
uri: uri
|
||||
headers: (headers `((content-type application/json)
|
||||
(Authorization ,(conc "Bearer " api-token)))))))
|
||||
(with-input-from-request req #f read-json)))))
|
||||
|
||||
(get
|
||||
("/config/wizard/machine")
|
||||
(let ((config (with-db/transaction
|
||||
(lambda (db)
|
||||
(get-user-service-config db (session-get "user-id"))))))
|
||||
`(App
|
||||
(Configuration-Wizard
|
||||
(@ (step "Machine"))
|
||||
(form
|
||||
(@ (action "/config/wizard/machine-submit")
|
||||
(method POST))
|
||||
(VStack
|
||||
(Fieldset
|
||||
(@ (title "Region"))
|
||||
(Field (@ (element select) (name "region"))
|
||||
(option (@ (value "")) "")
|
||||
,@(map (lambda (r)
|
||||
`(option (@ (value ,(alist-ref 'slug r))) ,(alist-ref 'name r)))
|
||||
(get-digital-ocean-regions (alist-ref 'digitalocean-api-token config)))))
|
||||
(Form-Nav (@ (back-to ,(conc "/config/wizard/apps2"))))))))))
|
||||
|
||||
(schematra:post ("/config/wizard/machine-submit")
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
(update-user-service-config
|
||||
db
|
||||
(session-get "user-id")
|
||||
`((digitalocean-region . ,(alist-ref 'region (schematra:current-params)))))))
|
||||
(schematra:redirect "/config/wizard/machine2"))
|
||||
|
||||
(get
|
||||
("/config/wizard/machine2")
|
||||
(let* ((config (with-db/transaction
|
||||
(lambda (db)
|
||||
(get-user-service-config db (session-get "user-id")))))
|
||||
(region (alist-ref 'digitalocean-region config))
|
||||
(all-sizes (get-digital-ocean-sizes (alist-ref 'digitalocean-api-token config)))
|
||||
(sizes (filter (lambda (s) (member region (alist-ref 'regions s))) all-sizes)))
|
||||
`(App
|
||||
(Configuration-Wizard
|
||||
(@ (step "Machine"))
|
||||
(form
|
||||
(@ (action "/config/wizard/machine2-submit")
|
||||
(method POST))
|
||||
(VStack
|
||||
(Fieldset
|
||||
(@ (title "Size"))
|
||||
(Field (@ (element select) (name "size") (input-style ((max-width "100%"))))
|
||||
,@(map (lambda (s) `(option (@ (value ,(alist-ref 'slug s))
|
||||
,@(if (equal? (alist-ref 'slug s) "s-2vcpu-2gb") `((selected "selected")) '()))
|
||||
"$" ,(alist-ref 'price_monthly s)
|
||||
" (CPU: ",(alist-ref 'vcpus s)
|
||||
" Mem: " ,(/ (alist-ref 'memory s) 1024)
|
||||
" Disk: " ,(alist-ref 'disk s)
|
||||
") " ,(alist-ref 'description s)))
|
||||
sizes)))
|
||||
(Form-Nav (@ (back-to ,(conc "/config/wizard/machine"))))))))))
|
||||
|
||||
(schematra:post ("/config/wizard/machine2-submit")
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
(update-user-service-config
|
||||
db
|
||||
(session-get "user-id")
|
||||
`((digitalocean-size . ,(alist-ref 'size (schematra:current-params)))))))
|
||||
(schematra:redirect "/config/wizard/review"))
|
||||
|
||||
(get
|
||||
("/config/wizard/review")
|
||||
(let* ((results
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
`((selected-apps . ,(map
|
||||
car
|
||||
(filter cdr
|
||||
(get-user-selected-apps db (session-get "user-id")))))
|
||||
(app-config . ,(get-user-app-config db (session-get "user-id")))
|
||||
(service-config . ,(get-user-service-config db (session-get "user-id")))))))
|
||||
(selected-apps (cons 'log-viewer (alist-ref 'selected-apps results)))
|
||||
(app-config (alist-ref 'app-config results))
|
||||
(config (alist-ref 'config app-config))
|
||||
(root-domain (alist-ref 'root-domain app-config))
|
||||
(service-config (alist-ref 'service-config results)))
|
||||
`(App
|
||||
(Configuration-Wizard
|
||||
(@ (step "Review"))
|
||||
(h2 "Root Domain")
|
||||
,root-domain
|
||||
(h2 "Apps")
|
||||
(ul ,@(map (lambda (app) `(li ,app " @ "
|
||||
,(alist-ref 'subdomain (alist-ref app config))
|
||||
"."
|
||||
,root-domain))
|
||||
selected-apps))
|
||||
(h2 "Machine")
|
||||
(ul (li "Region: " ,(alist-ref 'digitalocean-region service-config))
|
||||
(li "Size: " ,(alist-ref 'digitalocean-size service-config)))
|
||||
(form
|
||||
(@ (action "/config/wizard/review-submit") (method POST))
|
||||
(VStack
|
||||
(Form-Nav (@ (back-to ,(conc "/config/wizard/machine2")) (submit-button "Launch")))))))))
|
||||
(if (test-mode)
|
||||
*digital-ocean-sizes-response*
|
||||
(let* ((uri (uri-reference "https://api.digitalocean.com/v2/sizes?per_page=200"))
|
||||
(req (make-request method: 'GET
|
||||
uri: uri
|
||||
headers: (headers `((content-type application/json)
|
||||
(Authorization ,(conc "Bearer " api-token)))))))
|
||||
(with-input-from-request req #f read-json))))))
|
||||
|
||||
(define (deployment-directory user-id)
|
||||
(string-append "deploy-" (number->string user-id)))
|
||||
@@ -803,24 +566,298 @@ h1, h2, h3, h4, h5, h6 {
|
||||
(display value)
|
||||
(print "\""))
|
||||
|
||||
(schematra:post ("/config/wizard/review-submit")
|
||||
(define (progress-status->text status)
|
||||
(case status
|
||||
((queued) "queued")
|
||||
((in-progress) "in progress")
|
||||
((complete) "complete")
|
||||
((failed) "failed")))
|
||||
|
||||
(with-schematra-app app
|
||||
(lambda ()
|
||||
|
||||
(get/widgets
|
||||
("/config/wizard/services")
|
||||
(let ((config (with-db/transaction (lambda (db) (get-user-service-config db (session-user-id))))))
|
||||
`(App
|
||||
(Configuration-Wizard
|
||||
(@ (step "Services"))
|
||||
(form
|
||||
(@ (action "/config/wizard/services-submit")
|
||||
(method POST))
|
||||
(VStack
|
||||
(Fieldset
|
||||
(@ (title "Cloudflare"))
|
||||
(Field (@ (name "cloudflare-api-token") (label ("API Token")) (value ,(alist-ref 'cloudflare-api-token config))))
|
||||
(Field (@ (name "cloudflare-zone-id") (label ("Zone ID")) (value ,(alist-ref 'cloudflare-zone-id config))))
|
||||
(Field (@ (name "cloudflare-account-id") (label ("Account ID")) (value ,(alist-ref 'cloudflare-account-id config)))))
|
||||
(Fieldset
|
||||
(@ (title "DigitalOcean"))
|
||||
(Field (@ (name "digitalocean-api-token") (label ("API Token")) (value ,(alist-ref 'digitalocean-api-token config)))))
|
||||
(Fieldset
|
||||
(@ (title "Backblaze"))
|
||||
(Field (@ (name "backblaze-application-key") (label ("Application Key")) (value ,(alist-ref 'backblaze-application-key config))))
|
||||
(Field (@ (name "backblaze-key-id") (label ("Key ID")) (value ,(alist-ref 'backblaze-key-id config))))
|
||||
(Field (@ (name "backblaze-bucket-url") (label ("Bucket URL")) (value ,(alist-ref 'backblaze-bucket-url config)))))
|
||||
(Form-Nav)))))))
|
||||
|
||||
(post "/config/wizard/services-submit"
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
(update-user-service-config
|
||||
db
|
||||
(session-user-id)
|
||||
`((cloudflare-api-token . ,(alist-ref 'cloudflare-api-token (current-params)))
|
||||
(cloudflare-account-id . ,(alist-ref 'cloudflare-account-id (current-params)))
|
||||
(cloudflare-zone-id . ,(alist-ref 'cloudflare-zone-id (current-params)))
|
||||
(digitalocean-api-token . ,(alist-ref 'digitalocean-api-token (current-params)))
|
||||
(backblaze-application-key . ,(alist-ref 'backblaze-application-key (current-params)))
|
||||
(backblaze-key-id . ,(alist-ref 'backblaze-key-id (current-params)))
|
||||
(backblaze-bucket-url . ,(alist-ref 'backblaze-bucket-url (current-params)))))))
|
||||
(redirect "/config/wizard/services-success"))
|
||||
|
||||
(get/widgets
|
||||
("/config/wizard/services-success")
|
||||
`(App
|
||||
(Configuration-Wizard
|
||||
(@ (step "Services"))
|
||||
(form
|
||||
(@ (action "/config/wizard/apps"))
|
||||
(VStack
|
||||
(Fieldset
|
||||
(@ (title "Cloudflare"))
|
||||
(h3 "Connected")
|
||||
(p "Your Cloudflare account was successfully connected!"))
|
||||
(Fieldset
|
||||
(@ (title "DigitalOcean"))
|
||||
(h3 "Connected")
|
||||
(p "Your DigitalOcean account was successfully connected!"))
|
||||
(Fieldset
|
||||
(@ (title "Backblaze"))
|
||||
(h3 "Connected")
|
||||
(p "Your Backblaze account was successfully connected!"))
|
||||
(Form-Nav (@ (back-to "/config/wizard/services"))))))))
|
||||
|
||||
(get/widgets
|
||||
("/config/wizard/apps")
|
||||
(let ((results
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
`((selected-apps . ,(map
|
||||
car
|
||||
(filter cdr
|
||||
(get-user-selected-apps db (session-user-id)))))
|
||||
(app-config . ,(get-user-app-config db (session-user-id))))))))
|
||||
`(App
|
||||
(Configuration-Wizard
|
||||
(@ (step "Apps"))
|
||||
(form
|
||||
(@ (action "/config/wizard/apps-submit") (method POST))
|
||||
(VStack
|
||||
(Fieldset
|
||||
(@ (title "Root Domain"))
|
||||
(Field (@ (element select) (name "root-domain"))
|
||||
(option (@ (value ,(alist-ref 'root-domain (alist-ref 'app-config results)))) "nassella.cc"))) ;; TODO fetch from cloudflare API?
|
||||
(Fieldset
|
||||
(@ (title "Selected Apps"))
|
||||
(Field (@ (name "wg-easy") (type "checkbox") (label ("WG Easy")) (checked ,(member 'wg-easy (alist-ref 'selected-apps results)))))
|
||||
(Field (@ (name "nextcloud") (type "checkbox") (label ("NextCloud")) (checked ,(member 'nextcloud (alist-ref 'selected-apps results)))))
|
||||
(Field (@ (name "log-viewer") (type "checkbox") (label ("Log Viewer")) (checked #t) (disabled "disabled"))))
|
||||
(Form-Nav (@ (back-to "/config/wizard/services-success")))))))))
|
||||
|
||||
(post "/config/wizard/apps-submit"
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
(update-user-selected-apps
|
||||
db
|
||||
(session-user-id)
|
||||
`((wg-easy . ,(or (and (alist-ref 'wg-easy (current-params)) "0.0") (sql-null)))
|
||||
(nextcloud . ,(or (and (alist-ref 'nextcloud (current-params)) "0.0") (sql-null)))))
|
||||
(update-root-domain db
|
||||
(session-user-id)
|
||||
(alist-ref 'root-domain (current-params)))))
|
||||
(redirect "/config/wizard/apps2"))
|
||||
|
||||
;; TODO should this even allow changing existing username/passwords like for db?
|
||||
;; wouldn't that break the db connection and you would lose data?
|
||||
(get/widgets
|
||||
("/config/wizard/apps2")
|
||||
(let* ((results
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
`((selected-apps . ,(map
|
||||
car
|
||||
(filter cdr
|
||||
(get-user-selected-apps db (session-get "user-id")))))
|
||||
(app-config . ,(get-user-app-config db (session-get "user-id")))
|
||||
(service-config . ,(get-user-service-config db (session-get "user-id")))
|
||||
(terraform-state . ,(get-user-terraform-state db (session-get "user-id")))))))
|
||||
(get-user-selected-apps db (session-user-id)))))
|
||||
(app-config . ,(get-user-app-config db (session-user-id)))))))
|
||||
(selected-apps (alist-ref 'selected-apps results))
|
||||
(app-config (alist-ref 'config (alist-ref 'app-config results))))
|
||||
`(App
|
||||
(Configuration-Wizard
|
||||
(@ (step "Apps"))
|
||||
(form
|
||||
(@ (action "/config/wizard/apps2-submit") (method POST))
|
||||
(VStack
|
||||
,@(if (member 'wg-easy selected-apps)
|
||||
`((Fieldset
|
||||
(@ (title "WG-Easy"))
|
||||
(Field (@ (name "wg-easy-subdomain") (label ("Subdomain")) (value ,(alist-ref 'subdomain (alist-ref 'wg-easy app-config eq? '()) eq? "wg-easy"))))))
|
||||
'())
|
||||
,@(if (member 'nextcloud selected-apps)
|
||||
`((Fieldset
|
||||
(@ (title "NextCloud"))
|
||||
(Field (@ (name "nextcloud-subdomain") (label ("Subdomain"))
|
||||
(value ,(alist-ref 'subdomain (alist-ref 'nextcloud app-config eq? '()) eq? "nextcloud"))))
|
||||
(Field (@ (name "nextcloud-admin-user") (label ("Admin Username"))
|
||||
(value ,(alist-ref 'admin-user (alist-ref 'nextcloud app-config eq? '()) eq? "admin"))))
|
||||
(Field (@ (name "nextcloud-admin-password") (label ("Admin Password")) (type "password")
|
||||
(value ,(alist-ref 'admin-password (alist-ref 'nextcloud app-config eq? '()) eq? ""))))))
|
||||
'())
|
||||
(Fieldset
|
||||
(@ (title "Log Viewer"))
|
||||
(Field (@ (name "log-viewer-subdomain") (label ("Subdomain"))
|
||||
(value ,(alist-ref 'subdomain (alist-ref 'log-viewer app-config eq? '()) eq? "logs"))))
|
||||
(Field (@ (name "log-viewer-user") (label ("Username"))
|
||||
(value ,(alist-ref 'user (alist-ref 'log-viewer app-config eq? '()) eq? ""))))
|
||||
(Field (@ (name "log-viewer-password") (label ("Password")) (type "password")
|
||||
(value ,(alist-ref 'password (alist-ref 'log-viewer app-config eq? '()) eq? "")))))
|
||||
(Form-Nav (@ (back-to "/config/wizard/apps")))))))))
|
||||
|
||||
(post "/config/wizard/apps2-submit"
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
(update-user-app-config
|
||||
db
|
||||
(session-user-id)
|
||||
`((wg-easy . ((subdomain . ,(alist-ref 'wg-easy-subdomain (current-params)))))
|
||||
(nextcloud . ((subdomain . ,(alist-ref 'nextcloud-subdomain (current-params)))
|
||||
(admin-user . ,(alist-ref 'nextcloud-admin-user (current-params)))
|
||||
(admin-password . ,(alist-ref 'nextcloud-admin-password (current-params)))))
|
||||
(log-viewer . ((subdomain . ,(alist-ref 'log-viewer-subdomain (current-params)))
|
||||
(user . ,(alist-ref 'log-viewer-user (current-params)))
|
||||
(password . ,(alist-ref 'log-viewer-password (current-params)))))))))
|
||||
(redirect "/config/wizard/machine"))
|
||||
|
||||
(get/widgets
|
||||
("/config/wizard/machine")
|
||||
(let ((config (with-db/transaction
|
||||
(lambda (db)
|
||||
(get-user-service-config db (session-user-id))))))
|
||||
`(App
|
||||
(Configuration-Wizard
|
||||
(@ (step "Machine"))
|
||||
(form
|
||||
(@ (action "/config/wizard/machine-submit")
|
||||
(method POST))
|
||||
(VStack
|
||||
(Fieldset
|
||||
(@ (title "Region"))
|
||||
(Field (@ (element select) (name "region"))
|
||||
(option (@ (value "")) "")
|
||||
,@(map (lambda (r)
|
||||
`(option (@ (value ,(alist-ref 'slug r))) ,(alist-ref 'name r)))
|
||||
(get-digital-ocean-regions (alist-ref 'digitalocean-api-token config)))))
|
||||
(Form-Nav (@ (back-to ,(conc "/config/wizard/apps2"))))))))))
|
||||
|
||||
(post "/config/wizard/machine-submit"
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
(update-user-service-config
|
||||
db
|
||||
(session-user-id)
|
||||
`((digitalocean-region . ,(alist-ref 'region (current-params)))))))
|
||||
(redirect "/config/wizard/machine2"))
|
||||
|
||||
(get/widgets
|
||||
("/config/wizard/machine2")
|
||||
(let* ((config (with-db/transaction
|
||||
(lambda (db)
|
||||
(get-user-service-config db (session-user-id)))))
|
||||
(region (alist-ref 'digitalocean-region config))
|
||||
(all-sizes (get-digital-ocean-sizes (alist-ref 'digitalocean-api-token config)))
|
||||
(sizes (filter (lambda (s) (member region (alist-ref 'regions s))) all-sizes)))
|
||||
`(App
|
||||
(Configuration-Wizard
|
||||
(@ (step "Machine"))
|
||||
(form
|
||||
(@ (action "/config/wizard/machine2-submit")
|
||||
(method POST))
|
||||
(VStack
|
||||
(Fieldset
|
||||
(@ (title "Size"))
|
||||
(Field (@ (element select) (name "size") (input-style ((max-width "100%"))))
|
||||
,@(map (lambda (s) `(option (@ (value ,(alist-ref 'slug s))
|
||||
,@(if (equal? (alist-ref 'slug s) "s-2vcpu-2gb") `((selected "selected")) '()))
|
||||
"$" ,(alist-ref 'price_monthly s)
|
||||
" (CPU: ",(alist-ref 'vcpus s)
|
||||
" Mem: " ,(/ (alist-ref 'memory s) 1024)
|
||||
" Disk: " ,(alist-ref 'disk s)
|
||||
") " ,(alist-ref 'description s)))
|
||||
sizes)))
|
||||
(Form-Nav (@ (back-to ,(conc "/config/wizard/machine"))))))))))
|
||||
|
||||
(post "/config/wizard/machine2-submit"
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
(update-user-service-config
|
||||
db
|
||||
(session-user-id)
|
||||
`((digitalocean-size . ,(alist-ref 'size (current-params)))))))
|
||||
(redirect "/config/wizard/review"))
|
||||
|
||||
(get/widgets
|
||||
("/config/wizard/review")
|
||||
(let* ((results
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
`((selected-apps . ,(map
|
||||
car
|
||||
(filter cdr
|
||||
(get-user-selected-apps db (session-user-id)))))
|
||||
(app-config . ,(get-user-app-config db (session-user-id)))
|
||||
(service-config . ,(get-user-service-config db (session-user-id)))))))
|
||||
(selected-apps (cons 'log-viewer (alist-ref 'selected-apps results)))
|
||||
(app-config (alist-ref 'app-config results))
|
||||
(config (alist-ref 'config app-config))
|
||||
(root-domain (alist-ref 'root-domain app-config))
|
||||
(service-config (alist-ref 'service-config results)))
|
||||
`(App
|
||||
(Configuration-Wizard
|
||||
(@ (step "Review"))
|
||||
(h2 "Root Domain")
|
||||
,root-domain
|
||||
(h2 "Apps")
|
||||
(ul ,@(map (lambda (app) `(li ,app " @ "
|
||||
,(alist-ref 'subdomain (alist-ref app config))
|
||||
"."
|
||||
,root-domain))
|
||||
selected-apps))
|
||||
(h2 "Machine")
|
||||
(ul (li "Region: " ,(alist-ref 'digitalocean-region service-config))
|
||||
(li "Size: " ,(alist-ref 'digitalocean-size service-config)))
|
||||
(form
|
||||
(@ (action "/config/wizard/review-submit") (method POST))
|
||||
(VStack
|
||||
(Form-Nav (@ (back-to ,(conc "/config/wizard/machine2")) (submit-button "Launch")))))))))
|
||||
|
||||
(post "/config/wizard/review-submit"
|
||||
(let* ((results
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
`((selected-apps . ,(map
|
||||
car
|
||||
(filter cdr
|
||||
(get-user-selected-apps db (session-user-id)))))
|
||||
(app-config . ,(get-user-app-config db (session-user-id)))
|
||||
(service-config . ,(get-user-service-config db (session-user-id)))
|
||||
(terraform-state . ,(get-user-terraform-state db (session-user-id)))))))
|
||||
(selected-apps (cons 'log-viewer (alist-ref 'selected-apps results)))
|
||||
(app-config (alist-ref 'app-config results))
|
||||
(config (alist-ref 'config app-config))
|
||||
(root-domain (alist-ref 'root-domain app-config))
|
||||
(service-config (alist-ref 'service-config results))
|
||||
(terraform-state (alist-ref 'terraform-state results))
|
||||
(dir (deployment-directory (session-get "user-id"))))
|
||||
(dir (deployment-directory (session-user-id))))
|
||||
(setup-deploy-files dir (alist-ref 'state terraform-state) (alist-ref 'backup terraform-state))
|
||||
(with-output-to-file (string-append dir "/config/apps.config")
|
||||
(lambda ()
|
||||
@@ -859,7 +896,7 @@ h1, h2, h3, h4, h5, h6 {
|
||||
("datacenter" . ,(alist-ref 'digitalocean-region service-config))
|
||||
("flatcar_stable_version" . "4230.2.3")))
|
||||
(display "ssh_keys=[\"") (display (with-input-from-file (string-append dir "/config/ssh-keys") read-string)) (print "\"]"))))
|
||||
(let* ((user-id (session-get "user-id"))
|
||||
(let* ((user-id (session-user-id))
|
||||
(deployment-id (with-db/transaction (lambda (db) (create-deployment db user-id))))
|
||||
(dir (deployment-directory user-id)))
|
||||
(thread-start!
|
||||
@@ -900,22 +937,15 @@ h1, h2, h3, h4, h5, h6 {
|
||||
(update-user-terraform-state db user-id
|
||||
(with-input-from-file (string-append dir "/terraform.tfstate") read-string)
|
||||
(with-input-from-file (string-append dir "/terraform.tfstate.backup") read-string))))))))))))
|
||||
(schematra:redirect "/config/wizard/success"))
|
||||
(redirect "/config/wizard/success"))
|
||||
|
||||
(define (progress-status->text status)
|
||||
(case status
|
||||
((queued) "queued")
|
||||
((in-progress) "in progress")
|
||||
((complete) "complete")
|
||||
((failed) "failed")))
|
||||
|
||||
(get
|
||||
(get/widgets
|
||||
("/config/wizard/success")
|
||||
(let* ((res (with-db/transaction
|
||||
(lambda (db)
|
||||
`((status . ,(get-most-recent-deployment-status db (session-get "user-id")))
|
||||
(progress . ,(get-most-recent-deployment-progress db (session-get "user-id")))))))
|
||||
(output (with-input-from-file (string-append (deployment-directory (session-get "user-id")) "/make-out") read-string))
|
||||
`((status . ,(get-most-recent-deployment-status db (session-user-id)))
|
||||
(progress . ,(get-most-recent-deployment-progress db (session-user-id)))))))
|
||||
(output (with-input-from-file (string-append (deployment-directory (session-user-id)) "/make-out") read-string))
|
||||
(progress (alist-ref 'progress res))
|
||||
(status (alist-ref 'status res)))
|
||||
`(VStack
|
||||
@@ -932,7 +962,7 @@ h1, h2, h3, h4, h5, h6 {
|
||||
(pre ,output)
|
||||
)))
|
||||
|
||||
(get
|
||||
(get/widgets
|
||||
("/dashboard")
|
||||
`(App
|
||||
(Main-Container
|
||||
@@ -945,7 +975,8 @@ h1, h2, h3, h4, h5, h6 {
|
||||
" - ",(alist-ref 'status deployment)))
|
||||
(with-db/transaction
|
||||
(lambda (db)
|
||||
(get-user-deployments db (session-get "user-id"))))))))))
|
||||
(get-user-deployments db (session-user-id))))))))))
|
||||
|
||||
(schematra:schematra-install)
|
||||
(schematra:schematra-start)
|
||||
(schematra-install)
|
||||
|
||||
))
|
||||
|
||||
428
src/test.scm
Normal file
428
src/test.scm
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user