From 85fdf5db522a3e3e841fef4c3dd5ff3a570739ca Mon Sep 17 00:00:00 2001 From: ckonstanski Date: Mon, 27 Jul 2026 20:27:17 -0600 Subject: stuff --- .../resume/clojurescript/resume/src/core.cljs | 2 +- lisp/webapps/resume/site.lisp | 194 +++++++++------------ lisp/webapps/webapp-loader.lisp | 172 ------------------ 3 files changed, 86 insertions(+), 282 deletions(-) (limited to 'lisp/webapps') diff --git a/lisp/webapps/resume/clojurescript/resume/src/core.cljs b/lisp/webapps/resume/clojurescript/resume/src/core.cljs index 6f21e53..0e9d9f8 100644 --- a/lisp/webapps/resume/clojurescript/resume/src/core.cljs +++ b/lisp/webapps/resume/clojurescript/resume/src/core.cljs @@ -1337,7 +1337,7 @@ [:th {:scope "col"} "Mod"] [:th {:scope "col"} "Del"]]] [:tbody - (for [contactinfo (get jsonobj "contactinfos")] + (for [contactinfo (get jsonobj "components")] [:tr [:td (get contactinfo "address")] [:td (get contactinfo "city")] diff --git a/lisp/webapps/resume/site.lisp b/lisp/webapps/resume/site.lisp index a8af2d6..8ebce16 100644 --- a/lisp/webapps/resume/site.lisp +++ b/lisp/webapps/resume/site.lisp @@ -3,29 +3,6 @@ (in-package :resume) -(defmacro .base (&optional (start-url "/home")) - `(org-ckons-http::html5 - `(html - (head - ((meta :name "viewport" :content "width=device-width, initial-scale=1, shrink-to-fit=no")) - ((meta :charset "utf-8")) - ((title) ,(title *webapp*)) - ,@(mapcar (lambda (css) - `((link :rel "stylesheet" :href ,(getf css :href) :integrity ,(getf css :integrity) :crossorigin ,(getf css :crossorigin)))) - '((:href "https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" :integrity "sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" :crossorigin "anonymous") - (:href "/static/css/stylesheet.css" :crossorigin "anonymous"))) - ,@(mapcar (lambda (js) - `((script :type "text/javascript" :src ,(getf js :src) :integrity ,(getf js :integrity) :crossorigin ,(getf js :crossorigin)))) - '((:src "https://code.jquery.com/jquery-3.7.1.slim.min.js" :integrity "sha256-kmHvs0B+OpCW5GVHUNjv9rOmY0IvSIRcf7zGUDTDQM8=" :crossorigin "anonymous"))) - ((script :type "text/javascript" :src "/cljs-out/dev-main.js"))) - ((body :onload ,(format nil "resume.core.start(~a)" ,(if start-url - (format nil "'~a'" start-url) - "null"))) - ((div :id "app")) - ,@(mapcar (lambda (js) - `((script :type "text/javascript" :src ,(getf js :src) :integrity ,(getf js :integrity) :crossorigin ,(getf js :crossorigin)))) - '((:src "https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js" :integrity "sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct" :crossorigin "anonymous"))))))) - (defmacro .location () `(location-json location)) @@ -152,91 +129,90 @@ (defmacro .resume-delete () `(resume-delete-json id)) -(defmacro .contactinfo () - `(contactinfo-json)) +;; (defmacro .contactinfo () +;; `(contactinfo-json)) -(defmacro .contactinfo-view () - `(contactinfo-view-json)) +;; (defmacro .contactinfo-view () +;; `(contactinfo-view-json)) -(defmacro .contactinfo-add () - `(contactinfo-add-json)) +;; (defmacro .contactinfo-add () +;; `(contactinfo-add-json)) -(defmacro .contactinfo-add-submit () - `(contactinfo-add-submit-json address city state_id phone email visastatus_id)) +;; (defmacro .contactinfo-add-submit () +;; `(contactinfo-add-submit-json address city state_id phone email visastatus_id)) -(defmacro .contactinfo-modify () - `(contactinfo-modify-json id)) +;; (defmacro .contactinfo-modify () +;; `(contactinfo-modify-json id)) -(defmacro .contactinfo-modify-submit () - `(contactinfo-modify-submit-json id address city state_id phone email visastatus_id)) +;; (defmacro .contactinfo-modify-submit () +;; `(contactinfo-modify-submit-json id address city state_id phone email visastatus_id)) -(defmacro .contactinfo-delete () - `(contactinfo-delete-json id)) +;; (defmacro .contactinfo-delete () +;; `(contactinfo-delete-json id)) -(defmacro .education () - `(education-json)) +;; (defmacro .education () +;; `(education-json)) -(defmacro .education-view () - `(education-view-json)) +;; (defmacro .education-view () +;; `(education-view-json)) -(defmacro .education-add () - `(education-add-json)) +;; (defmacro .education-add () +;; `(education-add-json)) -(defmacro .education-add-submit () - `(education-add-submit-json school major minor degree progress start_date end_date)) +;; (defmacro .education-add-submit () +;; `(education-add-submit-json school major minor degree progress start_date end_date)) -(defmacro .education-modify () - `(education-modify-json id)) +;; (defmacro .education-modify () +;; `(education-modify-json id)) -(defmacro .education-modify-submit () - `(education-modify-submit-json id school major minor degree progress start_date end_date)) +;; (defmacro .education-modify-submit () +;; `(education-modify-submit-json id school major minor degree progress start_date end_date)) -(defmacro .education-delete () - `(education-delete-json id)) +;; (defmacro .education-delete () +;; `(education-delete-json id)) -(defmacro .language () - `(language-json)) +;; (defmacro .language () +;; `(language-json)) -(defmacro .language-view () - `(language-view-json)) +;; (defmacro .language-view () +;; `(language-view-json)) -(defmacro .language-add () - `(language-add-json)) +;; (defmacro .language-add () +;; `(language-add-json)) -(defmacro .language-add-submit () - `(language-add-submit-json name understanding_listening understanding_reading speaking_interaction speaking_production writing)) +;; (defmacro .language-add-submit () +;; `(language-add-submit-json name understanding_listening understanding_reading speaking_interaction speaking_production writing)) -(defmacro .language-modify () - `(language-modify-json id)) +;; (defmacro .language-modify () +;; `(language-modify-json id)) -(defmacro .language-modify-submit () - `(language-modify-submit-json id name understanding_listening understanding_reading speaking_interaction speaking_production writing)) +;; (defmacro .language-modify-submit () +;; `(language-modify-submit-json id name understanding_listening understanding_reading speaking_interaction speaking_production writing)) -(defmacro .language-delete () - `(language-delete-json id)) +;; (defmacro .language-delete () +;; `(language-delete-json id)) -(defmacro .skill () - `(skill-json)) +;; (defmacro .skill () +;; `(skill-json)) -(defmacro .skill-view () - `(skill-view-json)) +;; (defmacro .skill-view () +;; `(skill-view-json)) -(defmacro .skill-add () - `(skill-add-json)) +;; (defmacro .skill-add () +;; `(skill-add-json)) -(defmacro .skill-add-submit () - `(skill-add-submit-json skill)) +;; (defmacro .skill-add-submit () +;; `(skill-add-submit-json skill)) -(defmacro .skill-modify () - `(skill-modify-json id)) +;; (defmacro .skill-modify () +;; `(skill-modify-json id)) -(defmacro .skill-modify-submit () - `(skill-modify-submit-json id skill)) +;; (defmacro .skill-modify-submit () +;; `(skill-modify-submit-json id skill)) -(defmacro .skill-delete () - `(skill-delete-json id)) +;; (defmacro .skill-delete () +;; `(skill-delete-json id)) -(define-endpoint ("/" :method :get) () .base) (define-endpoint ("/location" :method :post) (&post (location :parameter-type 'string)) .location) (define-endpoint ("/home" :method :get) () .home-get) (define-endpoint ("/home" :method :post) (&post (message :parameter-type 'string) (errormsg :parameter-type 'string)) .home-post) @@ -265,7 +241,7 @@ (define-endpoint ("/users/view" :method :get) () .users-view) (define-endpoint ("/users/add" :method :post) () .users-add) (define-endpoint ("/users/add/submit" :method :post) (&post (role_groups :parameter-type 'string) (first_name :parameter-type 'string) (last_name :parameter-type 'string) (email :parameter-type 'string)) .users-add-submit) -(define-endpoint ("/register/:hash" :method :get) (&path (hash 'string)) .base (format nil "/register/~a" hash)) +(define-endpoint ("/register/:hash" :method :get) (&path (hash 'string)) base (format nil "/register/~a" hash)) (define-endpoint ("/users/register" :method :post) (&post (hash :parameter-type 'string)) .users-register) (define-endpoint ("/users/register/form" :method :post) (&post (hash :parameter-type 'string)) .users-register-form) (define-endpoint ("/users/register/submit" :method :post) (&post (hash :parameter-type 'string) (username :parameter-type 'string) (pwd :parameter-type 'string) (pwd2 :parameter-type 'string) (phone :parameter-type 'string)) .users-register-submit) @@ -280,31 +256,31 @@ (define-endpoint ("/resume/modify" :method :post) (&post (id :parameter-type 'integer)) .resume-modify) (define-endpoint ("/resume/modify/submit" :method :post) (&post (id :parameter-type 'integer) (name :parameter-type 'string)) .resume-modify-submit) (define-endpoint ("/resume/delete/:id" :method :delete) (&path (id 'integer)) .resume-delete) -(define-endpoint ("/resume/contactinfo" :method :get) () .contactinfo) -(define-endpoint ("/resume/contactinfo/view" :method :get) () .contactinfo-view) -(define-endpoint ("/resume/contactinfo/add" :method :post) () .contactinfo-add) -(define-endpoint ("/resume/contactinfo/add/submit" :method :post) (&post (address :parameter-type 'string) (city :parameter-type 'string) (state_id :parameter-type 'integer) (phone :parameter-type 'string) (email :parameter-type 'string) (visastatus_id :parameter-type 'integer)) .contactinfo-add-submit) -(define-endpoint ("/resume/contactinfo/modify" :method :post) (&post (id :parameter-type 'integer)) .contactinfo-modify) -(define-endpoint ("/resume/contactinfo/modify/submit" :method :post) (&post (id :parameter-type 'integer) (address :parameter-type 'string) (city :parameter-type 'string) (state_id :parameter-type 'integer) (phone :parameter-type 'string) (email :parameter-type 'string) (visastatus_id :parameter-type 'integer)) .contactinfo-modify-submit) -(define-endpoint ("/resume/contactinfo/delete/:id" :method :delete) (&path (id 'integer)) .contactinfo-delete) -(define-endpoint ("/resume/education" :method :get) () .education) -(define-endpoint ("/resume/education/view" :method :get) () .education-view) -(define-endpoint ("/resume/education/add" :method :post) () .education-add) -(define-endpoint ("/resume/education/add/submit" :method :post) (&post (school :parameter-type 'string) (major :parameter-type 'string) (minor :parameter-type 'string) (degree :parameter-type 'string) (progress :parameter-type 'string) (start_date :parameter-type 'string) (end_date :parameter-type 'string)) .education-add-submit) -(define-endpoint ("/resume/education/modify" :method :post) (&post (id :parameter-type 'integer)) .education-modify) -(define-endpoint ("/resume/education/modify/submit" :method :post) (&post (id :parameter-type 'integer) (school :parameter-type 'string) (major :parameter-type 'string) (minor :parameter-type 'string) (degree :parameter-type 'string) (progress :parameter-type 'string) (start_date :parameter-type 'string) (end_date :parameter-type 'string)) .education-modify-submit) -(define-endpoint ("/resume/education/delete/:id" :method :delete) (&path (id 'integer)) .education-delete) -(define-endpoint ("/resume/language" :method :get) () .language) -(define-endpoint ("/resume/language/view" :method :get) () .language-view) -(define-endpoint ("/resume/language/add" :method :post) () .language-add) -(define-endpoint ("/resume/language/add/submit" :method :post) (&post (name :parameter-type 'string) (understanding_listening :parameter-type 'string) (understanding_reading :parameter-type 'string) (speaking_interaction :parameter-type 'string) (speaking_production :parameter-type 'string) (writing :parameter-type 'string)) .language-add-submit) -(define-endpoint ("/resume/language/modify" :method :post) (&post (id :parameter-type 'integer)) .language-modify) -(define-endpoint ("/resume/language/modify/submit" :method :post) (&post (id :parameter-type 'integer) (name :parameter-type 'string) (understanding_listening :parameter-type 'string) (understanding_reading :parameter-type 'string) (speaking_interaction :parameter-type 'string) (speaking_production :parameter-type 'string) (writing :parameter-type 'string)) .language-modify-submit) -(define-endpoint ("/resume/language/delete/:id" :method :delete) (&path (id 'integer)) .language-delete) -(define-endpoint ("/resume/skill" :method :get) () .skill) -(define-endpoint ("/resume/skill/view" :method :get) () .skill-view) -(define-endpoint ("/resume/skill/add" :method :post) () .skill-add) -(define-endpoint ("/resume/skill/add/submit" :method :post) (&post (skill :parameter-type 'string)) .skill-add-submit) -(define-endpoint ("/resume/skill/modify" :method :post) (&post (id :parameter-type 'integer)) .skill-modify) -(define-endpoint ("/resume/skill/modify/submit" :method :post) (&post (id :parameter-type 'integer) (skill :parameter-type 'string)) .skill-modify-submit) -(define-endpoint ("/resume/skill/delete/:id" :method :delete) (&path (id 'integer)) .skill-delete) +;; (define-endpoint ("/resume/contactinfo" :method :get) () .contactinfo) +;; (define-endpoint ("/resume/contactinfo/view" :method :get) () .contactinfo-view) +;; (define-endpoint ("/resume/contactinfo/add" :method :post) () .contactinfo-add) +;; (define-endpoint ("/resume/contactinfo/add/submit" :method :post) (&post (address :parameter-type 'string) (city :parameter-type 'string) (state_id :parameter-type 'integer) (phone :parameter-type 'string) (email :parameter-type 'string) (visastatus_id :parameter-type 'integer)) .contactinfo-add-submit) +;; (define-endpoint ("/resume/contactinfo/modify" :method :post) (&post (id :parameter-type 'integer)) .contactinfo-modify) +;; (define-endpoint ("/resume/contactinfo/modify/submit" :method :post) (&post (id :parameter-type 'integer) (address :parameter-type 'string) (city :parameter-type 'string) (state_id :parameter-type 'integer) (phone :parameter-type 'string) (email :parameter-type 'string) (visastatus_id :parameter-type 'integer)) .contactinfo-modify-submit) +;; (define-endpoint ("/resume/contactinfo/delete/:id" :method :delete) (&path (id 'integer)) .contactinfo-delete) +;; (define-endpoint ("/resume/education" :method :get) () .education) +;; (define-endpoint ("/resume/education/view" :method :get) () .education-view) +;; (define-endpoint ("/resume/education/add" :method :post) () .education-add) +;; (define-endpoint ("/resume/education/add/submit" :method :post) (&post (school :parameter-type 'string) (major :parameter-type 'string) (minor :parameter-type 'string) (degree :parameter-type 'string) (progress :parameter-type 'string) (start_date :parameter-type 'string) (end_date :parameter-type 'string)) .education-add-submit) +;; (define-endpoint ("/resume/education/modify" :method :post) (&post (id :parameter-type 'integer)) .education-modify) +;; (define-endpoint ("/resume/education/modify/submit" :method :post) (&post (id :parameter-type 'integer) (school :parameter-type 'string) (major :parameter-type 'string) (minor :parameter-type 'string) (degree :parameter-type 'string) (progress :parameter-type 'string) (start_date :parameter-type 'string) (end_date :parameter-type 'string)) .education-modify-submit) +;; (define-endpoint ("/resume/education/delete/:id" :method :delete) (&path (id 'integer)) .education-delete) +;; (define-endpoint ("/resume/language" :method :get) () .language) +;; (define-endpoint ("/resume/language/view" :method :get) () .language-view) +;; (define-endpoint ("/resume/language/add" :method :post) () .language-add) +;; (define-endpoint ("/resume/language/add/submit" :method :post) (&post (name :parameter-type 'string) (understanding_listening :parameter-type 'string) (understanding_reading :parameter-type 'string) (speaking_interaction :parameter-type 'string) (speaking_production :parameter-type 'string) (writing :parameter-type 'string)) .language-add-submit) +;; (define-endpoint ("/resume/language/modify" :method :post) (&post (id :parameter-type 'integer)) .language-modify) +;; (define-endpoint ("/resume/language/modify/submit" :method :post) (&post (id :parameter-type 'integer) (name :parameter-type 'string) (understanding_listening :parameter-type 'string) (understanding_reading :parameter-type 'string) (speaking_interaction :parameter-type 'string) (speaking_production :parameter-type 'string) (writing :parameter-type 'string)) .language-modify-submit) +;; (define-endpoint ("/resume/language/delete/:id" :method :delete) (&path (id 'integer)) .language-delete) +;; (define-endpoint ("/resume/skill" :method :get) () .skill) +;; (define-endpoint ("/resume/skill/view" :method :get) () .skill-view) +;; (define-endpoint ("/resume/skill/add" :method :post) () .skill-add) +;; (define-endpoint ("/resume/skill/add/submit" :method :post) (&post (skill :parameter-type 'string)) .skill-add-submit) +;; (define-endpoint ("/resume/skill/modify" :method :post) (&post (id :parameter-type 'integer)) .skill-modify) +;; (define-endpoint ("/resume/skill/modify/submit" :method :post) (&post (id :parameter-type 'integer) (skill :parameter-type 'string)) .skill-modify-submit) +;; (define-endpoint ("/resume/skill/delete/:id" :method :delete) (&path (id 'integer)) .skill-delete) diff --git a/lisp/webapps/webapp-loader.lisp b/lisp/webapps/webapp-loader.lisp index 41a00da..1fb7d2e 100644 --- a/lisp/webapps/webapp-loader.lisp +++ b/lisp/webapps/webapp-loader.lisp @@ -3,175 +3,3 @@ (in-package :resume) -(defvar *acceptor* nil) -(defvar *dispatch-table* '(#'dispatch-easy-handlers #'default-dispatcher)) -(defvar *webapps* (make-hash-table :test 'equal)) -(defvar *webapp* nil) -(defvar *uri* nil) -(defvar *header-register* nil) -(defvar *sessionid* nil) -(defparameter *port* 3014) -(defparameter *server-root* (namestring (asdf:system-relative-pathname (intern (package-name #.*package*)) "./")) - "The location of the web server root on the filesystem.") - -(defclass webapp () - ((name :initarg :name - :initform nil - :accessor name - :documentation "The name of the webapp as used in the code. A -string used as the key to any webapp config lookup.") - (scheme :initarg :scheme - :initform nil - :accessor scheme) - (url :initarg :url - :initform nil - :accessor url - :documentation "The domain portion of the URL to the -root of the webapp.") - (document-root :initarg :document-root - :initform nil - :accessor document-root - :documentation "The absolute filesystem path to the -webapp's top-level directory which is inside the webapps folder.") - (title :initarg :title - :initform nil - :accessor title - :documentation "The default title that shows up in -the browser title bar.") - (meta-description :initarg :meta-description - :initform nil - :accessor meta-description - :documentation "The text that goes into the META DESCRIPTION -tag, and anywhere else we want to put this text so that it will show -up in Google.") - (databases :initarg :databases - :initform nil - :accessor databases) - (mail-mx :initarg :mail-mx - :initform nil - :accessor mail-mx) - (mail-from :initarg :mail-from - :initform nil - :accessor mail-from) - (mail-postmaster :initarg :mail-postmaster - :initform nil - :accessor mail-postmaster) - (mail-webmaster :initarg :mail-webmaster - :initform nil - :accessor mail-webmaster) - (mail-info :initarg :mail-info - :initform nil - :accessor mail-info) - (mail-login-notify :initarg :mail-login-notify - :initform nil - :accessor mail-login-notify) - (mail-authentication :initarg :mail-authentication - :initform nil - :accessor mail-authentication) - (mail-ssl :initarg :mail-ssl - :initform nil - :accessor mail-ssl)) - (:documentation "")) - -(defmethod get-site-file-path ((webapp webapp)) - (format nil "~a/site" (document-root webapp))) - -(defmethod get-pages-file-paths ((webapp webapp)) - (mapcar (lambda (pages-file) - (ppcre:regex-replace-all "\\.lisp$" (format nil "~a" pages-file) "")) - (remove-if (lambda (x) (equal x "shared")) - (org-ckons-core::shell-wrapper (format nil "find '~a' -maxdepth 1 -type f -iname 'pages*.lisp' |sort" (document-root webapp)))))) - -(defun make-server-path (relative-path) - "Makes a relative filesystem path into a full one, using -`*server-root*' as the base." - (make-document-root-path *server-root* relative-path)) - -(defun make-document-root-path (document-root relative-path) - "Makes a relative filesystem path into a full one, using -`document-root' as the base." - (concatenate 'string document-root relative-path)) - -(defun make-webapp-path (relative-path) - "Makes an absolute filesystem path to a location in the webapps -folder." - (concatenate 'string *server-root* "webapps/" relative-path)) - -(defun get-options-files () - (mapcar (lambda (webapp-directory) - (format nil "~a/conf/options.lisp" webapp-directory)) - (remove-if (lambda (x) (or (org-ckons-core::match-it "webapps/$" x) - (org-ckons-core::match-it "webapps/shared$" x) - (org-ckons-core::match-it "webapps/CVS$" x) - (org-ckons-core::match-it "webapps/\\.$" x) - (org-ckons-core::match-it "webapps/\\.\\.$" x))) - (org-ckons-core::shell-wrapper (format nil "find '~a' -maxdepth 1 -type d |sort" (make-webapp-path "")))))) - -(defun set-webapp (webapp) - "Sets a `webapp' object in `*webapps*'. The lookup key is the webapp -name. If a webapp already exists under this key, it gets overwritten -with the new one." - (setf (gethash (name webapp) *webapps*) webapp)) - -(defun get-webapp (key) - "Gets the webapp object stored under the key `key'." - (gethash key *webapps*)) - -(defun populate-webapps () - (loop for options-file in (get-options-files) - do (with-open-file (input options-file :direction :input) - (let* ((form (read input))) - (set-webapp (make-instance 'webapp - :name (getf form :name) - :scheme (getf form :scheme) - :url (getf form :url) - :document-root (make-webapp-path (getf form :document-root)) - :title (getf form :title) - :meta-description (getf form :meta-description) - :databases (getf form :databases) - :mail-mx (getf form :mail-mx) - :mail-from (getf form :mail-from) - :mail-postmaster (getf form :mail-postmaster) - :mail-webmaster (getf form :mail-webmaster) - :mail-info (getf form :mail-info) - :mail-login-notify (getf form :mail-login-notify) - :mail-authentication (getf form :mail-authentication) - :mail-ssl (getf form :mail-ssl))))))) - -(defun resume () - "Call this to start the server." - (when (null *acceptor*) - (let ((package (string-downcase (package-name #.*package*)))) - (populate-webapps) - (setf (log-manager) (make-instance 'log-manager :message-class 'formatted-message)) - (start-messenger 'text-file-messenger :filename (format nil "/var/log/lisp/~a.log" package)) - (setf *session-secret* (org-ckons-session::generate-sessionid)) - (populate-webapps) - (setf *acceptor* (start (make-instance 'easy-routes:easy-routes-acceptor - :port *port* - :document-root (make-server-path (format nil "webapps/~a/" package)) - :name (format nil "~a-acceptor" package))))))) - -(defmacro with-request-wrapper (uri page-function &rest args) - (let ((package (string-downcase (package-name #.*package*)))) - `(let (output) - (let* ((*webapp* (get-webapp ,package)) - (*uri* ,uri) - (*header-register* (make-instance 'org-ckons-session::header-register)) - (*sessionid* (ensure-user-session-exists))) - (ensure-user-exists) - (setf output (,page-function ,@args)) - (org-ckons-session::ship-headers *header-register*)) - output))) - -(defmacro define-endpoint (template-and-options var-list page-function &rest args) - "Does the grunt work of creating an `easy-routes' route for each page -you wish to publish." - (let ((name (gensym)) - (uri (first template-and-options)) - (method (getf (rest template-and-options) :method))) - `(progn - (org-ckons-core::logger (format nil "Publishing page. URL = [~a], method = [~a]" ,uri ,method)) - (easy-routes:defroute ,name ,template-and-options - ,var-list - (with-request-wrapper ,uri ,page-function ,@args))))) -- cgit v1.3