262 lines
6.4 KiB
Factor
262 lines
6.4 KiB
Factor
! Copyright (C) 2007, 2010 Slava Pestov
|
|
! See http://factorcode.org/license.txt for BSD license.
|
|
USING: namespaces assocs sorting sequences kernel accessors
|
|
hashtables db.types db.tuples db combinators
|
|
calendar calendar.format math.parser math.order syndication urls
|
|
xml.writer xmode.catalog validators
|
|
html.forms
|
|
html.components
|
|
html.templates.chloe
|
|
http.server
|
|
http.server.dispatchers
|
|
http.server.redirection
|
|
http.server.responses
|
|
furnace
|
|
furnace.actions
|
|
furnace.redirection
|
|
furnace.auth
|
|
furnace.auth.login
|
|
furnace.boilerplate
|
|
furnace.recaptcha
|
|
furnace.syndication
|
|
furnace.conversations ;
|
|
IN: webapps.pastebin
|
|
|
|
TUPLE: pastebin < dispatcher ;
|
|
|
|
SYMBOL: can-delete-pastes?
|
|
|
|
can-delete-pastes? define-capability
|
|
|
|
! ! !
|
|
! DOMAIN MODEL
|
|
! ! !
|
|
|
|
TUPLE: entity id summary author mode date contents ;
|
|
|
|
entity f
|
|
{
|
|
{ "id" "ID" INTEGER +db-assigned-id+ }
|
|
{ "summary" "SUMMARY" { VARCHAR 256 } +not-null+ }
|
|
{ "author" "AUTHOR" { VARCHAR 256 } +not-null+ }
|
|
{ "mode" "MODE" { VARCHAR 256 } +not-null+ }
|
|
{ "date" "DATE" DATETIME +not-null+ }
|
|
{ "contents" "CONTENTS" TEXT +not-null+ }
|
|
} define-persistent
|
|
|
|
GENERIC: entity-url ( entity -- url )
|
|
|
|
M: entity feed-entry-title summary>> ;
|
|
|
|
M: entity feed-entry-date date>> ;
|
|
|
|
M: entity feed-entry-url entity-url ;
|
|
|
|
TUPLE: paste-state < entity annotations ;
|
|
|
|
\ paste-state "PASTES" { } define-persistent
|
|
|
|
: <paste-state> ( id -- paste )
|
|
\ paste-state new
|
|
swap >>id ;
|
|
|
|
: pastes ( -- pastes )
|
|
f <paste-state> select-tuples
|
|
[ date>> ] sort-with
|
|
reverse ;
|
|
|
|
TUPLE: annotation < entity parent ;
|
|
|
|
\ annotation "ANNOTATIONS"
|
|
{
|
|
{ "parent" "PARENT" INTEGER +not-null+ }
|
|
} define-persistent
|
|
|
|
: <annotation> ( parent id -- annotation )
|
|
\ annotation new
|
|
swap >>id
|
|
swap >>parent ;
|
|
|
|
: lookup-annotation ( id -- annotation )
|
|
[ f ] dip <annotation> select-tuple ;
|
|
|
|
: paste ( id -- paste )
|
|
[ <paste-state> select-tuple ]
|
|
[ f <annotation> select-tuples ]
|
|
bi >>annotations ;
|
|
|
|
! ! !
|
|
! LINKS, ETC
|
|
! ! !
|
|
|
|
CONSTANT: pastebin-url URL" $pastebin/"
|
|
|
|
: paste-url ( id -- url )
|
|
"$pastebin/paste" >url swap "id" set-query-param ;
|
|
|
|
M: paste-state entity-url
|
|
id>> paste-url ;
|
|
|
|
: annotation-url ( parent id -- url )
|
|
"$pastebin/paste" >url
|
|
swap number>string >>anchor
|
|
swap "id" set-query-param ;
|
|
|
|
M: annotation entity-url
|
|
[ parent>> ] [ id>> ] bi annotation-url ;
|
|
|
|
! ! !
|
|
! PASTE LIST
|
|
! ! !
|
|
|
|
: <pastebin-action> ( -- action )
|
|
<page-action>
|
|
[ pastes "pastes" set-value ] >>init
|
|
{ pastebin "pastebin" } >>template ;
|
|
|
|
: <pastebin-feed-action> ( -- action )
|
|
<feed-action>
|
|
[ pastebin-url ] >>url
|
|
[ "Factor Pastebin" ] >>title
|
|
[ pastes ] >>entries ;
|
|
|
|
! ! !
|
|
! PASTES
|
|
! ! !
|
|
|
|
: <paste-action> ( -- action )
|
|
<page-action>
|
|
[
|
|
validate-integer-id
|
|
"id" value paste from-object
|
|
|
|
"id" value
|
|
"new-annotation" [
|
|
"parent" set-value
|
|
mode-names "modes" set-value
|
|
"factor" "mode" set-value
|
|
] nest-form
|
|
] >>init
|
|
|
|
{ pastebin "paste" } >>template ;
|
|
|
|
: <raw-paste-action> ( -- action )
|
|
<action>
|
|
[ validate-integer-id "id" value paste from-object ] >>init
|
|
[ "contents" value "text/plain" <content> ] >>display ;
|
|
|
|
: <paste-feed-action> ( -- action )
|
|
<feed-action>
|
|
[ validate-integer-id ] >>init
|
|
[ "id" value paste-url ] >>url
|
|
[ "Paste " "id" value number>string append ] >>title
|
|
[ "id" value f <annotation> select-tuples ] >>entries ;
|
|
|
|
: validate-entity ( -- )
|
|
{
|
|
{ "summary" [ v-one-line ] }
|
|
{ "author" [ v-one-line ] }
|
|
{ "mode" [ v-mode ] }
|
|
{ "contents" [ v-required ] }
|
|
} validate-params
|
|
validate-recaptcha ;
|
|
|
|
: deposit-entity-slots ( tuple -- )
|
|
now >>date
|
|
{ "summary" "author" "mode" "contents" } to-object ;
|
|
|
|
: <new-paste-action> ( -- action )
|
|
<page-action>
|
|
[
|
|
"factor" "mode" set-value
|
|
mode-names "modes" set-value
|
|
] >>init
|
|
|
|
{ pastebin "new-paste" } >>template
|
|
|
|
[
|
|
mode-names "modes" set-value
|
|
validate-entity
|
|
] >>validate
|
|
|
|
[
|
|
f <paste-state>
|
|
[ deposit-entity-slots ]
|
|
[ insert-tuple ]
|
|
[ id>> paste-url <redirect> ]
|
|
tri
|
|
] >>submit ;
|
|
|
|
: <delete-paste-action> ( -- action )
|
|
<action>
|
|
|
|
[ validate-integer-id ] >>validate
|
|
|
|
[
|
|
[
|
|
"id" value <paste-state> delete-tuples
|
|
"id" value f <annotation> delete-tuples
|
|
] with-transaction
|
|
pastebin-url <redirect>
|
|
] >>submit
|
|
|
|
<protected>
|
|
"delete pastes" >>description
|
|
{ can-delete-pastes? } >>capabilities ;
|
|
|
|
! ! !
|
|
! ANNOTATIONS
|
|
! ! !
|
|
|
|
: <new-annotation-action> ( -- action )
|
|
<action>
|
|
[
|
|
mode-names "modes" set-value
|
|
{ { "parent" [ v-integer ] } } validate-params
|
|
validate-entity
|
|
] >>validate
|
|
|
|
[
|
|
"parent" value f <annotation>
|
|
[ deposit-entity-slots ]
|
|
[ insert-tuple ]
|
|
[ entity-url <redirect> ]
|
|
tri
|
|
] >>submit ;
|
|
|
|
: <raw-annotation-action> ( -- action )
|
|
<action>
|
|
[ validate-integer-id "id" value lookup-annotation from-object ] >>init
|
|
[ "contents" value "text/plain" <content> ] >>display ;
|
|
|
|
: <delete-annotation-action> ( -- action )
|
|
<action>
|
|
|
|
[ { { "id" [ v-number ] } } validate-params ] >>validate
|
|
|
|
[
|
|
f "id" value lookup-annotation
|
|
[ delete-tuples ]
|
|
[ parent>> paste-url <redirect> ]
|
|
bi
|
|
] >>submit
|
|
|
|
<protected>
|
|
"delete annotations" >>description
|
|
{ can-delete-pastes? } >>capabilities ;
|
|
|
|
: <pastebin> ( -- responder )
|
|
pastebin new-dispatcher
|
|
<pastebin-action> "" add-responder
|
|
<pastebin-feed-action> "list.atom" add-responder
|
|
<paste-action> "paste" add-responder
|
|
<raw-paste-action> "paste.txt" add-responder
|
|
<paste-feed-action> "paste.atom" add-responder
|
|
<new-paste-action> "new-paste" add-responder
|
|
<delete-paste-action> "delete-paste" add-responder
|
|
<new-annotation-action> "new-annotation" add-responder
|
|
<raw-annotation-action> "annotation.txt" add-responder
|
|
<delete-annotation-action> "delete-annotation" add-responder
|
|
<boilerplate>
|
|
{ pastebin "pastebin-common" } >>template ;
|