web.lisp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. (in-package :cl-user)
  2. (restas:define-module #:assboard.web
  3. (:use :cl :hunchentoot :assboard.utils))
  4. (in-package #:assboard.web)
  5. ;; Parameters
  6. (setf (who:html-mode) :html5)
  7. (defclass renderer () ())
  8. (restas::register-pkgmodule-traits
  9. 'assboard.web
  10. :render-method (lambda () (make-instance 'assboard.web::renderer)))
  11. ;; Rendering
  12. (defgeneric finalize-page (data)
  13. (:documentation "Final rendering step"))
  14. (defgeneric render-route-data (route data)
  15. (:documentation "Process route-specific data"))
  16. (defmethod finalize-page ((data list))
  17. (who:with-html-output-to-string (out nil :prologue t)
  18. (:html
  19. (:head
  20. (:meta :charset "utf-8")
  21. (:meta :http-equiv "X-UA-Compatible" :content "IE=edge")
  22. (:meta :name "viewport" :content "width=device-width, initial-scale=1")
  23. (:title (who:str (getf data :title)))
  24. (:link :rel "stylesheet" :href (restas:genurl 'static/css :file "styles.css")))
  25. (:body
  26. (who:str (getf data :menu))
  27. (who:str (getf data :content))))))
  28. (defmethod render-route-data (route data)
  29. (list*
  30. :title (getf data :title "AssBoard")
  31. data))
  32. (defmethod restas:render-object ((designer renderer) (object list))
  33. (let ((full-data (render-route-data (restas:route-symbol restas:*route*)
  34. object)))
  35. (finalize-page full-data)))
  36. (defun posts-list (posts)
  37. (who:with-html-output-to-string (out)
  38. (:ul
  39. (loop for post in posts
  40. :do (who:htm
  41. (:li
  42. (:a :href (restas:genurl 'posting :id (data::posting-id post))
  43. (who:str (data::posting-title post)))
  44. " by "
  45. (:a :href (restas:genurl 'author
  46. :author (data::posting-author post))
  47. (who:str (data::posting-author post)))))))))
  48. (defmethod render-route-data ((route (eql 'index)) (posts list))
  49. (list
  50. :title "AssBoard"
  51. :content
  52. (who:with-html-output-to-string (out)
  53. (:h1 "AssBoard open postings")
  54. (who:str (posts-list posts)))))
  55. (restas:define-route index ("")
  56. (pomo:query-dao
  57. 'data::posting
  58. (:select 'id 'author 'status 'title 'maintainer 'created-on
  59. :from 'posting)))
  60. (defmethod restas:render-object ((designer renderer) (object data::posting))
  61. (finalize-page
  62. (list
  63. :title (format nil "~A by ~A @ AssBoard"
  64. (data::posting-title object)
  65. (data::posting-author object))
  66. :content
  67. (who:with-html-output-to-string (out)
  68. (:h1 (who:str (data::posting-title object)))
  69. (:div (cl-markdown:markdown (data::posting-body object) :stream out))))))
  70. (restas:define-route posting ("posting/:id/")
  71. (let ((post (pomo:get-dao 'data::posting id)))
  72. (if post post
  73. hunchentoot:+HTTP-NOT-FOUND+)))
  74. (defmethod render-route-data ((route (eql 'author)) (data list))
  75. (list
  76. :title (format nil "~A's postings @ AssBoard" (getf data :author))
  77. :content
  78. (who:with-html-output-to-string (out)
  79. (:h1 (who:str (getf data :author)) "'s postings")
  80. (who:str (posts-list (getf data :posts))))))
  81. (restas:define-route author ("author/:author/")
  82. (let ((posts (pomo:query-dao
  83. 'data::posting
  84. (:select 'id 'author 'status 'title 'maintainer 'created-on
  85. :from 'posting
  86. :where (:= 'author author)))))
  87. (if posts
  88. (list :author author :posts posts)
  89. hunchentoot:+HTTP-NOT-FOUND+)))
  90. (restas:define-route static/css ("css/:file" :content-type "text/css")
  91. (let ((css-path (merge-pathnames "css/" +project-path+)))
  92. (merge-pathnames file css-path)))