! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel accessors sequences sorting math math.order calendar alarms logging concurrency.combinators namespaces db.types db.tuples db fry locals hashtables syndication urls xml.writer validators html.forms html.components http.server http.server.dispatchers furnace furnace.actions furnace.redirection furnace.boilerplate furnace.auth.login furnace.auth furnace.syndication ; IN: webapps.planet TUPLE: planet < dispatcher ; SYMBOL: can-administer-planet? can-administer-planet? define-capability TUPLE: planet-admin < dispatcher ; TUPLE: blog id name www-url feed-url ; M: blog link-title name>> ; M: blog link-href www-url>> ; blog "BLOGS" { { "id" "ID" INTEGER +db-assigned-id+ } { "name" "NAME" { VARCHAR 256 } +not-null+ } { "www-url" "WWWURL" URL +not-null+ } { "feed-url" "FEEDURL" URL +not-null+ } } define-persistent TUPLE: posting < entry id ; posting "POSTINGS" { { "id" "ID" INTEGER +db-assigned-id+ } { "title" "TITLE" { VARCHAR 256 } +not-null+ } { "url" "LINK" URL +not-null+ } { "description" "DESCRIPTION" TEXT +not-null+ } { "date" "DATE" TIMESTAMP +not-null+ } } define-persistent : ( id -- todo ) blog new swap >>id ; : blogroll ( -- seq ) f select-tuples [ [ name>> ] compare ] sort ; : postings ( -- seq ) posting new select-tuples [ [ date>> ] compare invert-comparison ] sort ; : ( -- action ) [ blogroll "blogroll" set-value ] >>init { planet "admin" } >>template ; : ( -- action ) [ blogroll "blogroll" set-value postings "postings" set-value ] >>init { planet "planet" } >>template ; : ( -- action ) [ "Planet Factor" ] >>title [ URL" $planet" ] >>url [ postings ] >>entries ; :: ( entry name -- entry' ) posting new name ": " entry title>> 3append >>title entry url>> >>url entry description>> >>description entry date>> >>date ; : fetch-feed ( url -- feed ) download-feed entries>> ; \ fetch-feed DEBUG add-error-logging : fetch-blogroll ( blogroll -- entries ) [ [ feed-url>> fetch-feed ] parallel-map ] [ [ name>> ] map ] bi [ '[ _ ] map ] 2map concat ; : sort-entries ( entries -- entries' ) [ [ date>> ] compare invert-comparison ] sort ; : update-cached-postings ( -- ) blogroll fetch-blogroll sort-entries 8 short head [ posting new delete-tuples [ insert-tuple ] each ] with-transaction ; : ( -- action ) [ update-cached-postings URL" $planet/admin" ] >>submit ; : ( -- action ) [ validate-integer-id ] >>validate [ "id" value delete-tuples URL" $planet/admin" ] >>submit ; : validate-blog ( -- ) { { "name" [ v-one-line ] } { "www-url" [ v-url ] } { "feed-url" [ v-url ] } } validate-params ; : deposit-blog-slots ( blog -- ) { "name" "www-url" "feed-url" } to-object ; : ( -- action ) { planet "new-blog" } >>template [ validate-blog ] >>validate [ f [ deposit-blog-slots ] [ insert-tuple ] bi URL" $planet/admin" ] >>submit ; : ( -- action ) [ validate-integer-id "id" value select-tuple from-object ] >>init { planet "edit-blog" } >>template [ validate-integer-id validate-blog ] >>validate [ f [ deposit-blog-slots ] [ "id" value >>id ] [ update-tuple ] tri "$planet/admin" >>path "id" value "id" set-query-param ] >>submit ; : ( -- responder ) planet-admin new-dispatcher "" add-responder "update" add-responder "new-blog" add-responder "edit-blog" add-responder "delete-blog" add-responder "administer Planet Factor" >>description { can-administer-planet? } >>capabilities ; : ( -- responder ) planet new-dispatcher "" add-responder "feed.xml" add-responder "admin" add-responder { planet "planet-common" } >>template ; : start-update-task ( db -- ) '[ _ [ update-cached-postings ] with-db ] 10 minutes every drop ;