Changeset 2522
- Timestamp:
- 02/17/08 20:25:56 (9 months ago)
- Files:
-
- branches/trunk-reorg/bknr/web/src/bknr-web.asd (modified) (1 diff)
- branches/trunk-reorg/bknr/web/src/images/image-handlers.lisp (modified) (7 diffs)
- branches/trunk-reorg/bknr/web/src/images/image.lisp (modified) (1 diff)
- branches/trunk-reorg/bknr/web/src/images/imageproc-handler.lisp (modified) (1 diff)
- branches/trunk-reorg/bknr/web/src/packages.lisp (modified) (6 diffs)
- branches/trunk-reorg/bknr/web/src/rss/parse-atom.lisp (deleted)
- branches/trunk-reorg/bknr/web/src/rss/parse-rss091.lisp (deleted)
- branches/trunk-reorg/bknr/web/src/rss/parse-rss10.lisp (deleted)
- branches/trunk-reorg/bknr/web/src/rss/parse-rss20.lisp (deleted)
- branches/trunk-reorg/bknr/web/src/rss/parse-xml.lisp (deleted)
- branches/trunk-reorg/bknr/web/src/rss/rss.lisp (modified) (8 diffs)
- branches/trunk-reorg/bknr/web/src/rss/test.lisp (deleted)
- branches/trunk-reorg/bknr/web/src/web/handlers.lisp (modified) (1 diff)
- branches/trunk-reorg/bknr/web/src/web/menu.lisp (modified) (1 diff)
- branches/trunk-reorg/bknr/web/src/web/site.lisp (modified) (1 diff)
- branches/trunk-reorg/bknr/web/src/web/tags.lisp (modified) (1 diff)
- branches/trunk-reorg/bknr/web/src/web/template-handler.lisp (modified) (1 diff)
- branches/trunk-reorg/bknr/web/src/web/web-macros.lisp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/trunk-reorg/bknr/web/src/bknr-web.asd
r2451 r2522 50 50 :depends-on ("packages")) 51 51 52 (:module "rss" :components ((:file "rss") 53 (:file "parse-xml") 54 (:file "parse-rss10" 55 :depends-on ("parse-xml" "rss")) 56 (:file "parse-rss091" 57 :depends-on ("parse-xml" "rss")) 58 (:file "parse-atom" 59 :depends-on ("parse-xml" "rss")) 60 (:file "parse-rss20" 61 :depends-on ("parse-xml" "rss"))) 52 (:module "rss" :components ((:file "rss")) 62 53 :depends-on ("packages")) 63 54 branches/trunk-reorg/bknr/web/src/images/image-handlers.lisp
r2497 r2522 11 11 (unless (zerop date) 12 12 (setf (header-out :last-modified) (rfc-1123-date date))) 13 (with-http-body () 13 (let ((stream (send-headers))) 14 (setf (flex:flexi-stream-element-type stream) 'flex:octet) 14 15 (setf (save-alpha-p :image image) t) 15 16 (if (member image-format '(:jpg :jpeg)) 16 (write-image-to-stream *html-stream*image-format :image image :quality quality)17 (write-image-to-stream *html-stream*image-format :image image))18 (finish-output *html-stream*))))17 (write-image-to-stream stream image-format :image image :quality quality) 18 (write-image-to-stream stream image-format :image image)) 19 (finish-output stream)))) 19 20 20 21 (defmethod store-image-xml-info ((image store-image)) … … 53 54 "bknr images") 54 55 55 (defmethod object-list-handler-rss-link ((handler image-page-handler) object)56 "/image-rss")57 58 56 (defmethod object-list-handler-get-objects ((handler image-page-handler) object) 59 57 (all-store-images)) … … 66 64 (let ((results (make-keyword-results (object-list-handler-get-objects handler images)))) 67 65 (with-bknr-page (:title (object-list-handler-title handler images)) 68 (cmslink (object-list-handler-rss-link handler images) "rss")69 66 (image-page results)))) 70 67 … … 115 112 (format nil "bknr keyword images: ~a" keyword)) 116 113 117 (defmethod object-list-handler-rss-link ((handler image-keyword-handler) keyword)118 (format nil "/keyword-rss/~A"119 (string-downcase (symbol-name keyword))))120 121 114 (defclass image-union-handler (image-page-handler keywords-handler) 122 115 ()) … … 127 120 (defmethod object-list-handler-title ((handler image-union-handler) keywords) 128 121 (format nil "bknr union images: ~a" keywords)) 129 130 (defmethod object-list-handler-rss-link ((handler image-union-handler) keywords)131 (format nil "/union-rss/~A" (parse-url)))132 122 133 123 (defclass image-intersection-handler (image-page-handler keywords-handler) … … 140 130 (format nil "bknr intersection images: ~a" keywords)) 141 131 142 (defmethod object-list-handler-rss-link ((handler image-intersection-handler) keywords)143 (format nil "/intersection-rss/~A" (parse-url)))144 145 ;;; rss image feeds146 #|147 (defclass rss-image-handler (object-rss-handler image-page-handler)148 ())149 150 (defmethod create-object-rss-feed ((handler rss-image-handler) object)151 (let* ((url (website-url (page-handler-site handler)))152 (image-items (mapcar #'(lambda (image)153 (store-image-to-rss-item image :url url))154 (subseq (sort (object-list-handler-get-objects handler object)155 #'> :key #'blob-timestamp)156 0 20))))157 (if image-items158 (make-instance 'rss-feed159 :channel (make-instance160 'rss-channel161 :about (render-uri url nil)162 :title (object-list-handler-title handler object)163 :link (render-uri url nil)164 :items (mapcar #'rss-item-link image-items))165 :items image-items)166 (make-instance 'rss-feed :channel (make-instance 'rss-channel167 :about "no such keyword"168 :title "no such keyword")))))169 170 (defclass rss-image-keyword-handler (rss-image-handler image-keyword-handler)171 ())172 173 (defclass rss-image-union-handler (rss-image-handler image-union-handler)174 ())175 176 (defclass rss-image-intersection-handler (rss-image-handler image-intersection-handler)177 ())178 |#179 132 180 133 (defclass xml-image-browser-handler (image-handler xml-object-handler) … … 204 157 ("/image-union" image-union-handler) 205 158 ("/image-intersection" image-intersection-handler) 206 #|207 ("/rss-image" rss-image-handler)208 ("/rss-image-keyword" rss-image-keyword-handler)209 ("/rss-image-union" rss-image-union-handler)210 ("/rss-image-intersection" rss-image-intersection-handler)211 |#212 159 ("/image" imageproc-handler) 213 160 ("/image-import" image-import-handler) branches/trunk-reorg/bknr/web/src/images/image.lisp
r2508 r2522 104 104 (keyword (store-image-with-name (string-downcase (symbol-name image-id)))))) 105 105 106 (defmethod store-image-to-rss-item ((image store-image) &key (url (parse-uri "")))107 (let ((image-url (render-uri (merge-uris (parse-uri (format nil "/image/~a"108 (store-object-id image)))109 url) nil))110 (browse-url (render-uri (merge-uris (parse-uri (format nil "/browse-image/~A"111 (store-object-id image)))112 url) nil)) )113 (make-instance 'rss-item114 :about browse-url115 :title (store-image-name image)116 :link browse-url117 :desc (with-output-to-string (s)118 (html-stream s ((:a :href image-url)119 ((:img :src120 (concatenate 'string121 image-url122 "/thumbnail,,320,200")123 :align "left")))))124 :date (blob-timestamp image))))125 126 106 ;;; import 127 107 (defun import-image (pathname &key name user keywords directory (keywords-from-dir t) (class-name 'store-image) initargs) branches/trunk-reorg/bknr/web/src/images/imageproc-handler.lisp
r2497 r2522 35 35 (not (true-color-p input-image))) 36 36 (true-color-to-palette :dither t :image working-image :colors-wanted 256)) 37 (let ((stream (send-headers))) 38 (setf (flex:flexi-stream-element-type stream) 'flex:octet) 39 (write-image-to-stream stream (image-type-keyword image) :image working-image)) 37 (emit-image-to-browser working-image (image-type-keyword image)) 40 38 (unless (eq working-image input-image) 41 39 (destroy-image working-image))))) branches/trunk-reorg/bknr/web/src/packages.lisp
r2508 r2522 21 21 (defpackage :bknr.rss 22 22 (:use :cl :cl-user :cl-ppcre :bknr.utils :bknr.xml :puri :cxml-xmls :bknr.datastore :bknr.indices :cxml) 23 (:export #:xml-escape 24 #:*img-src-scanner* 25 #:*a-href-scanner* 26 #:*link-href-scanner* 27 #:replace-relative-links 28 #:make-absolute-url 29 30 #:rss-to-xml 31 #:merge-feeds 32 33 ;; channel 23 (:export ;; channel 24 34 25 #:rss-channel 35 26 #:find-rss-channel … … 44 35 #:rss-channel-items 45 36 #:rss-channel-xml 46 47 ;; image48 #:rss-image49 #:rss-image-about50 #:rss-image-title51 #:rss-image-url52 #:rss-image-link53 37 54 38 ;; item … … 66 50 #:rss-item-guid 67 51 #:rss-item-source 68 #:rss-item-encoded-content 69 70 ;; textinput 71 #:rss-textinput 72 #:rss-textinput-about 73 #:rss-textinput-title 74 #:rss-textinput-desc 75 #:rss-textinput-link 76 #:rss-textinput-name 77 78 #:parse-rss091-feed 79 #:parse-rss10-feed 80 #:parse-rss20-feed 81 #:parse-atom-feed 82 83 #:*base-url*)) 52 #:rss-item-encoded-content)) 84 53 85 54 (defpackage :bknr.events … … 293 262 #:website-base-href 294 263 #:website-make-path 295 #:website-rss-feed-url296 264 #:host 297 265 #:publish-site … … 299 267 #:unpublish 300 268 301 #:handler-matches 269 #:handler-matches-p 302 270 #:handle-object 303 271 #:handle-object-form … … 358 326 #:object-list-handler-get-objects 359 327 #:object-list-handler-title 360 #:object-list-handler-rss-link361 328 #:object-list-handler-show-object-xml 362 329 #:object-date-list-handler branches/trunk-reorg/bknr/web/src/rss/rss.lisp
r2451 r2522 5 5 ;; This package aids in the automatic generation of RSS channels. 6 6 7 ;; Class rss-channel models one rss channel. Items are added to a 8 ;; channel by deriving other persistent classes from the (mixin) class 9 ;; rss-item. When an object of such a derived class is created, it is 10 ;; automatically added to its RSS channel. Likewise, it is 11 ;; automatically deleted from the channel when it is deleted. 12 13 ;; The channel that an item is put into is defined by the generic 14 ;; function rss-item-channel which needs to be specialized for each 15 ;; item class. The default method of this generic function specifies 16 ;; nil as channel, which results in the creation of a warning message 17 ;; when an object of this class is created. 18 19 ;; The rss-item-channel method may return the channel either as a 20 ;; string or as a channel object. 21 22 ;; Subclasses of rss-item should provide methods for some of the 23 ;; generic functions (rss-item-channel rss-item-title rss-item-link 24 ;; rss-item-description rss-item-author rss-item-category 25 ;; rss-item-comments rss-item-enclosure rss-item-guid 26 ;; rss-item-source). These functions are called when the RSS file for 27 ;; the channel is generated and provide the 28 29 ;; One rss-item can only be in one channel. 30 31 ;; The channel object has more required elements than the standard 32 ;; specifies in order to make the generated feed documents more widely 33 ;; accepted. 7 ;; See the documentation to class RSS-CHANNEL for an overview. 34 8 35 9 ;;; Paul Graham, On Lisp, p191 … … 49 23 (last-update :update :initform (get-universal-time)) 50 24 (max-item-age :update :initform (* 4 7 3600)) 51 (items :update :initform nil))) 25 (items :update :initform nil)) 26 (:documentation "RSS-CHANNEL models one rss channel. Items are 27 added to a channel by deriving other persistent classes from the mixin 28 class RSS-ITEM. When an object of such a derived class is created, it 29 is automatically added to its RSS channel. Likewise, it is 30 automatically deleted from the channel when it is deleted. 31 32 The channel that an item is put into is defined by the generic 33 function RSS-ITEM-CHANNEL which needs to be specialized for each item 34 class. The default method of this generic function specifies nil as 35 channel, which results in the creation of a warning message when an 36 object of this class is created. 37 38 The RSS-ITEM-CHANNEL method may return the channel either as a string 39 or as a channel object. 40 41 Subclasses of RSS-ITEM should provide methods for some of the generic 42 functions (RSS-ITEM-CHANNEL RSS-ITEM-TITLE RSS-ITEM-LINK 43 RSS-ITEM-DESCRIPTION RSS-ITEM-AUTHOR RSS-ITEM-CATEGORY 44 RSS-ITEM-COMMENTS RSS-ITEM-ENCLOSURE RSS-ITEM-GUID RSS-ITEM-SOURCE). 45 These functions are called when the RSS file for the channel is 46 generated and provide the content in the RSS items. 47 48 One RSS-ITEM can only be in one channel, which is a restriction that 49 may eventually be removed. 50 51 The channel object has more required elements than specified by the 52 standard in order to make the generated feed documents more widely 53 accepted.")) 52 54 53 55 (defmethod prepare-for-snapshot ((channel rss-channel)) 56 "When snapshotting, remove items from CHANNEL that are destroyed." 54 57 (setf (rss-channel-items channel) (remove-if #'object-destroyed-p (rss-channel-items channel)))) 55 58 … … 57 60 58 61 (define-persistent-class rss-item () 59 () )60 61 (defgeneric rss-item-pub-date (item))62 () 63 (:documentation "Mixin class for RSS items. See documentation for 64 class RSS-CHANNEL for an overview.")) 62 65 63 66 (defun make-rss-channel (name title description link &rest args) … … 86 89 (rss-item-xml item)))))) 87 90 88 (defmethod rss-channel-items ((channel rss-channel)) 89 "Return all non-expired items in channel." 90 (let ((expiry-time (- (get-universal-time) (rss-channel-max-item-age channel)))) 91 (remove-if (lambda (item) (or (object-destroyed-p item) 92 (< (rss-item-pub-date item) expiry-time))) 93 (slot-value channel 'items)))) 91 (defgeneric rss-channel-items (channel) 92 (:documentation "Return all non-expired items in channel.") 93 (:method ((channel rss-channel)) 94 (let ((expiry-time (- (get-universal-time) (rss-channel-max-item-age channel)))) 95 (remove-if (lambda (item) (or (object-destroyed-p item) 96 (< (rss-item-pub-date item) expiry-time))) 97 (slot-value channel 'items))))) 94 98 95 99 (deftransaction rss-channel-cleanup (channel) … … 98 102 (setf (slot-value channel 'items) (rss-channel-items channel))) 99 103 100 ;; Internal helper functions to find a channel 104 (defgeneric remove-item (channel item) 105 (:documentation "Remove ITEM from CHANNEL. May only be called 106 within transaction context.") 107 (:method ((channel rss-channel) item) 108 (setf (slot-value channel 'items) (remove item (rss-channel-items channel)))) 109 (:method ((channel string) item) 110 (aif (find-rss-channel channel) 111 (remove-item it item))) 112 (:method ((channel (eql nil)) item) 113 (warn "no RSS channel defined for item ~A" item))) 101 114 102 (defmethod remove-item ((channel rss-channel) item) 103 "Remove item from channel. May only be called within transaction context." 104 (setf (slot-value channel 'items) (remove item (rss-channel-items channel)))) 105 106 (defmethod remove-item ((channel string) item) 107 (aif (find-rss-channel channel) 108 (remove-item it item))) 109 110 (defmethod remove-item ((channel (eql nil)) item) 111 (warn "no RSS channel defined for item ~A" item)) 112 113 (defmethod add-item ((channel rss-channel) item) 114 "Add item to channel. May only be called within transaction context." 115 (setf (slot-value channel 'items) (cons item (rss-channel-items channel)))) 116 117 (defmethod add-item ((channel string) item) 118 (aif (find-rss-channel channel) 119 (add-item it item) 120 (warn "can't find RSS channel ~A to add newly created item ~A to" channel item))) 121 122 (defmethod add-item ((channel (eql nil)) item) 123 (warn "no RSS channel defined for item ~A" item)) 115 (defgeneric add-item (channel item) 116 (:documentation "Add ITEM to CHANNEL. May only be called within 117 transaction context.") 118 (:method ((channel rss-channel) item) 119 (setf (slot-value channel 'items) (cons item (rss-channel-items channel)))) 120 (:method ((channel string) item) 121 (aif (find-rss-channel channel) 122 (add-item it item) 123 (warn "can't find RSS channel ~A to add newly created item ~A to" channel item))) 124 (:method ((channel (eql nil)) item) 125 (warn "no RSS channel defined for item ~A" item))) 124 126 125 127 (defmethod initialize-persistent-instance :after ((rss-item rss-item)) … … 130 132 131 133 (defun item-slot-element (item slot-name) 134 "Cheapo helper function to map from a pseudo slot name to an accessor." 132 135 (let ((accessor (find-symbol (format nil "RSS-ITEM-~A" slot-name) (find-package :bknr.rss)))) 133 136 (aif (funcall accessor item) … … 136 139 137 140 (defun rss-item-xml (item) 141 "Generate RSS XML for ITEM using CXML's unparse functionality." 138 142 (with-element "item" 139 143 (dolist (slot '(title link author category comments enclosure source)) … … 155 159 ;; methods below. 156 160 157 (defmethod rss-item-published (item) 158 t) 161 (defgeneric rss-item-pub-date (item) 162 (:documentation "The default implementation for the publication date 163 delivers the current system date/time as publication date.") 164 (:method (item) 165 (warn "no rss-item-pub-date defined for class ~A, using current date/time" (class-of item)) 166 (get-universal-time))) 159 167 160 (defmethod rss-item-pub-date (item) 161 "The default implementation for the publication date delivers the 162 current system date/time as publication date." 163 (warn "no rss-item-pub-date defined for class ~A, using current date/time" (class-of item)) 164 (get-universal-time)) 168 (defgeneric rss-item-published (item) 169 (:documentation "Return non-nil if the ITEM is published. 170 Non-published items are not put into generated XML by 171 RSS-CHANNEL-XML.") 172 (:method (item) 173 t)) 165 174 166 (defmethod rss-item-channel (item)) 167 (defmethod rss-item-title (item)) 168 (defmethod rss-item-link (item)) 169 (defmethod rss-item-description (item)) 170 (defmethod rss-item-author (item)) 171 (defmethod rss-item-category (item)) 172 (defmethod rss-item-comments (item)) 173 (defmethod rss-item-enclosure (item)) 174 (defmethod rss-item-guid (item)) 175 (defmethod rss-item-source (item)) 176 (defgeneric rss-item-encoded-content (item) 177 (:documentation "Return the content for ITEM in encoded (usually HTML) form as string.") 178 (:method (item) 179 (declare (ignore item)) 180 nil)) 175 (defmacro define-rss-item-field (field-name 176 &key 177 (documentation (format nil "Return the ~(~A~) of the ITEM as a string" field-name)) 178 mandatory) 179 `(defgeneric ,(intern (format nil "RSS-ITEM-~A" field-name)) (item) 180 (:documentation ,(format nil "~A~@[ (optional)~]" 181 documentation (not mandatory))) 182 ,@(unless mandatory 183 '((:method (item) nil))))) 184 185 (define-rss-item-field channel 186 :documentation "Return the channel that the ITEM is published in." 187 :mandatory t) 188 (define-rss-item-field title) 189 (define-rss-item-field link) 190 (define-rss-item-field description) 191 (define-rss-item-field author) 192 (define-rss-item-field category) 193 (define-rss-item-field comments) 194 (define-rss-item-field enclosure) 195 (define-rss-item-field guid) 196 (define-rss-item-field source) 197 (define-rss-item-field encoded-content 198 :documentation "Return the content for ITEM in encoded (usually HTML) form as string.") branches/trunk-reorg/bknr/web/src/web/handlers.lisp
r2516 r2522 504 504 (defgeneric object-date-list-handler-grouped-objects (handler object)) 505 505 506 (def method object-date-list-handler-date ((handler object-date-list-handler)507 object)508 (with-query-params (date)509 (get-daytime (if date510 (or (parse-integer date :junk-allowed t)511 (get-universal-time))512 (get-universal-time)))))506 (defgeneric object-date-list-handler-date (handler object) 507 (:method ((handler object-date-list-handler) object) 508 (with-query-params (date) 509 (get-daytime (if date 510 (or (parse-integer date :junk-allowed t) 511 (get-universal-time)) 512 (get-universal-time)))))) 513 513 514 514 (defclass admin-only-handler () branches/trunk-reorg/bknr/web/src/web/menu.lisp
r2430 r2522 45 45 #+cmu (ext:unix-namestring (merge-pathnames config *default-pathname-defaults*)) 46 46 #+sbcl (sb-int:unix-namestring (merge-pathnames config *default-pathname-defaults*)) 47 #-(or cmu sbcl) (namestring (probe-file (merge-pathnames config *default-pathname-defaults*))) 47 48 *menu-def-classes*))) 48 49 (html branches/trunk-reorg/bknr/web/src/web/site.lisp
r2227 r2522 6 6 (defparameter *thumbnail-max-height* 54) 7 7 8 ;; default billboard to show on home page 9 (defparameter *default-billboard* "main")8 (defparameter *default-billboard* "main" 9 "default billboard to show on home page") 10 10 branches/trunk-reorg/bknr/web/src/web/tags.lisp
r2488 r2522 62 62 63 63 (define-bknr-tag date-field (name &key date (show-time t)) 64 "Generate a date entry widget using HTML <select> elements." 64 65 (unless date 65 66 (setf date (get-universal-time))) branches/trunk-reorg/bknr/web/src/web/template-handler.lisp
r2510 r2522 301 301 `(invoke-with-error-handlers (lambda () ,@body) ,handler)) 302 302 303 (defmethod handler-matches ((handler template-handler))303 (defmethod handler-matches-p ((handler template-handler)) 304 304 (handler-case 305 305 (find-template-pathname handler (script-name)) branches/trunk-reorg/bknr/web/src/web/web-macros.lisp
r2508 r2522 81 81 82 82 (defmacro html-warn (&rest warning) 83 "Generate a warning on the console and write the warning into the 84 currently generated XHTML output as a comment." 83 85 `(progn 84 86 (html (:princ-safe (format nil "<!-- ~a -->~%" (format nil ,@warning))))
