(in-package :cl-user) (restas:define-module #:assboard.web (:use :cl :hunchentoot :assboard.utils)) (in-package #:assboard.web) ;; Parameters (setf (who:html-mode) :html5) (defclass renderer () ()) (restas::register-pkgmodule-traits 'assboard.web :render-method (lambda () (make-instance 'assboard.web::renderer))) ;; Rendering (defgeneric finalize-page (data) (:documentation "Final rendering step")) (defgeneric render-route-data (route data) (:documentation "Process route-specific data")) (defmethod finalize-page ((data list)) (who:with-html-output-to-string (out nil :prologue t) (:html (:head (:meta :charset "utf-8") (:meta :http-equiv "X-UA-Compatible" :content "IE=edge") (:meta :name "viewport" :content "width=device-width, initial-scale=1") (:title (who:str (getf data :title))) (:link :rel "stylesheet" :href (restas:genurl 'static/css :file "styles.css"))) (:body (who:str (getf data :menu)) (who:str (getf data :content)))))) (defmethod render-route-data (route data) (list* :title (getf data :title "AssBoard") data)) (defmethod restas:render-object ((designer renderer) (object list)) (let ((full-data (render-route-data (restas:route-symbol restas:*route*) object))) (finalize-page full-data))) (defun posts-list (posts) (who:with-html-output-to-string (out) (:ul (loop for post in posts :do (who:htm (:li (:a :href (restas:genurl 'posting :id (data::posting-id post)) (who:str (data::posting-title post))) " by " (:a :href (restas:genurl 'author :author (data::posting-author post)) (who:str (data::posting-author post))))))))) (defmethod render-route-data ((route (eql 'index)) (posts list)) (list :title "AssBoard" :content (who:with-html-output-to-string (out) (:h1 "AssBoard open postings") (who:str (posts-list posts))))) (restas:define-route index ("") (pomo:query-dao 'data::posting (:select 'id 'author 'status 'title 'maintainer 'created-on :from 'posting))) (defmethod restas:render-object ((designer renderer) (object data::posting)) (finalize-page (list :title (format nil "~A by ~A @ AssBoard" (data::posting-title object) (data::posting-author object)) :content (who:with-html-output-to-string (out) (:h1 (who:str (data::posting-title object))) (:div (cl-markdown:markdown (data::posting-body object) :stream out)))))) (restas:define-route posting ("posting/:id/") (let ((post (pomo:get-dao 'data::posting id))) (if post post hunchentoot:+HTTP-NOT-FOUND+))) (defmethod render-route-data ((route (eql 'author)) (data list)) (list :title (format nil "~A's postings @ AssBoard" (getf data :author)) :content (who:with-html-output-to-string (out) (:h1 (who:str (getf data :author)) "'s postings") (who:str (posts-list (getf data :posts)))))) (restas:define-route author ("author/:author/") (let ((posts (pomo:query-dao 'data::posting (:select 'id 'author 'status 'title 'maintainer 'created-on :from 'posting :where (:= 'author author))))) (if posts (list :author author :posts posts) hunchentoot:+HTTP-NOT-FOUND+))) (restas:define-route static/css ("css/:file" :content-type "text/css") (let ((css-path (merge-pathnames "css/" +project-path+))) (merge-pathnames file css-path)))