1 ! Copyright (C) 2008 Slava Pestov
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors kernel hashtables calendar random assocs
4 namespaces splitting sequences sorting math.order present
5 io.files io.encodings.ascii
7 html.components html.forms
9 http.server.dispatchers
18 db.types db.tuples lcs farkup urls ;
21 : wiki-url ( rest path -- url )
22 [ "$wiki/" % % "/" % % ] "" make
25 : view-url ( title -- url ) "view" wiki-url ;
27 : edit-url ( title -- url ) "edit" wiki-url ;
29 : revisions-url ( title -- url ) "revisions" wiki-url ;
31 : revision-url ( id -- url ) "revision" wiki-url ;
33 : user-edits-url ( author -- url ) "user-edits" wiki-url ;
35 TUPLE: wiki < dispatcher ;
37 SYMBOL: can-delete-wiki-articles?
39 can-delete-wiki-articles? define-capability
41 TUPLE: article title revision ;
44 { "title" "TITLE" { VARCHAR 256 } +not-null+ +user-assigned-id+ }
45 { "revision" "REVISION" INTEGER +not-null+ } ! revision id
48 : <article> ( title -- article ) article new swap >>title ;
50 TUPLE: revision id title author date content ;
52 revision "REVISIONS" {
53 { "id" "ID" INTEGER +db-assigned-id+ }
54 { "title" "TITLE" { VARCHAR 256 } +not-null+ } ! article id
55 { "author" "AUTHOR" { VARCHAR 256 } +not-null+ } ! uid
56 { "date" "DATE" TIMESTAMP +not-null+ }
57 { "content" "CONTENT" TEXT +not-null+ }
60 M: revision feed-entry-title
61 [ title>> ] [ drop " by " ] [ author>> ] tri 3append ;
63 M: revision feed-entry-date date>> ;
65 M: revision feed-entry-url id>> revision-url ;
67 : reverse-chronological-order ( seq -- sorted )
68 [ [ date>> ] compare invert-comparison ] sort ;
70 : <revision> ( id -- revision )
71 revision new swap >>id ;
73 : validate-title ( -- )
74 { { "title" [ v-one-line ] } } validate-params ;
76 : validate-author ( -- )
77 { { "author" [ v-username ] } } validate-params ;
79 : <main-article-action> ( -- action )
81 [ "Front Page" view-url <redirect> ] >>display ;
83 : latest-revision ( title -- revision/f )
84 <article> select-tuple
85 dup [ revision>> <revision> select-tuple ] when ;
87 : <view-article-action> ( -- action )
97 "title" value dup latest-revision [
99 { wiki "view" } <chloe-content>
105 : <view-revision-action> ( -- action )
112 "id" value <revision>
113 select-tuple from-object
114 URL" $wiki/view/" adjust-url present relative-link-prefix set
117 { wiki "view" } >>template ;
119 : <random-article-action> ( -- action )
122 article new select-tuples random
123 [ title>> ] [ "Front Page" ] if*
127 : amend-article ( revision article -- )
128 swap id>> >>revision update-tuple ;
130 : add-article ( revision -- )
131 [ title>> ] [ id>> ] bi article boa insert-tuple ;
133 : add-revision ( revision -- )
136 dup title>> <article> select-tuple
137 [ amend-article ] [ add-article ] if*
140 : <edit-article-action> ( -- action )
147 "title" value <article> select-tuple [
148 revision>> <revision> select-tuple from-object
152 { wiki "edit" } >>template
156 { { "content" [ v-required ] } } validate-params
159 "title" value >>title
161 logged-in-user get username>> >>author
162 "content" value >>content
163 [ add-revision ] [ title>> view-url <redirect> ] bi
167 "edit wiki articles" >>description ;
169 : list-revisions ( -- seq )
170 f <revision> "title" value >>title select-tuples
171 reverse-chronological-order ;
173 : <list-revisions-action> ( -- action )
180 list-revisions "revisions" set-value
183 { wiki "revisions" } >>template ;
185 : <list-revisions-feed-action> ( -- action )
190 [ validate-title ] >>init
192 [ "Revisions of " "title" value append ] >>title
194 [ "title" value revisions-url ] >>url
196 [ list-revisions ] >>entries ;
198 : <rollback-action> ( -- action )
201 [ validate-integer-id ] >>validate
204 "id" value <revision> select-tuple clone f >>id
205 [ add-revision ] [ title>> view-url <redirect> ] bi
208 : list-changes ( -- seq )
209 f <revision> select-tuples
210 reverse-chronological-order ;
212 : <list-changes-action> ( -- action )
214 [ list-changes "changes" set-value ] >>init
215 { wiki "changes" } >>template ;
217 : <list-changes-feed-action> ( -- action )
219 [ URL" $wiki/changes" ] >>url
220 [ "All changes" ] >>title
221 [ list-changes ] >>entries ;
223 : <delete-action> ( -- action )
226 [ validate-title ] >>validate
229 "title" value <article> delete-tuples
230 f <revision> "title" value >>title delete-tuples
231 URL" $wiki" <redirect>
235 "delete wiki articles" >>description
236 { can-delete-wiki-articles? } >>capabilities ;
238 : <diff-action> ( -- action )
242 { "old-id" [ v-integer ] }
243 { "new-id" [ v-integer ] }
247 [ value <revision> select-tuple ] bi@
249 [ [ title>> "title" set-value ] [ "old" [ from-object ] nest-form ] bi ]
250 [ "new" [ from-object ] nest-form ] bi*
252 [ [ content>> string-lines ] bi@ diff "diff" set-value ]
256 { wiki "diff" } >>template ;
258 : <list-articles-action> ( -- action )
262 f <article> select-tuples
263 [ [ title>> ] compare ] sort
267 { wiki "articles" } >>template ;
269 : list-user-edits ( -- seq )
270 f <revision> "author" value >>author select-tuples
271 reverse-chronological-order ;
273 : <user-edits-action> ( -- action )
280 list-user-edits "user-edits" set-value
283 { wiki "user-edits" } >>template ;
285 : <user-edits-feed-action> ( -- action )
288 [ validate-author ] >>init
289 [ "Edits by " "author" value append ] >>title
290 [ "author" value user-edits-url ] >>url
291 [ list-user-edits ] >>entries ;
293 : <article-boilerplate> ( responder -- responder' )
295 { wiki "page-common" } >>template ;
297 : init-sidebar ( -- )
298 "Sidebar" latest-revision [ "sidebar" [ from-object ] nest-form ] when*
299 "Footer" latest-revision [ "footer" [ from-object ] nest-form ] when* ;
301 : <wiki> ( -- dispatcher )
303 <main-article-action> <article-boilerplate> "" add-responder
304 <view-article-action> <article-boilerplate> "view" add-responder
305 <view-revision-action> <article-boilerplate> "revision" add-responder
306 <random-article-action> "random" add-responder
307 <list-revisions-action> <article-boilerplate> "revisions" add-responder
308 <list-revisions-feed-action> "revisions.atom" add-responder
309 <diff-action> <article-boilerplate> "diff" add-responder
310 <edit-article-action> <article-boilerplate> "edit" add-responder
311 <rollback-action> "rollback" add-responder
312 <user-edits-action> "user-edits" add-responder
313 <list-articles-action> "articles" add-responder
314 <list-changes-action> "changes" add-responder
315 <user-edits-feed-action> "user-edits.atom" add-responder
316 <list-changes-feed-action> "changes.atom" add-responder
317 <delete-action> "delete" add-responder
319 [ init-sidebar ] >>init
320 { wiki "wiki-common" } >>template ;
323 "resource:extra/webapps/wiki/initial-content" directory* keys
325 [ ascii file-contents ] [ file-name "." split1 drop ] bi