! Copyright (C) 2007, 2010, 2023 Slava Pestov, Raghu Ranganathan. ! See https://factorcode.org/license.txt for BSD license. USING: accessors calendar db db.tuples db.types furnace.actions furnace.auth furnace.boilerplate furnace.recaptcha furnace.redirection furnace.syndication furnace.utilities html.forms http.server.dispatchers http.server.responses kernel math.parser namespaces present sequences smtp sorting splitting urls validators xmode.catalog literals ; IN: webapps.pastebin TUPLE: pastebin < dispatcher ; SYMBOL: can-delete-pastes? SYMBOL: pastebin-email-from SYMBOL: pastebin-email-to CONSTANT: paste-mode-names $[ "text" mode-names remove "text" prefix ] 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 : ( id -- paste ) \ paste-state new swap >>id ; : pastes ( -- pastes ) f select-tuples [ date>> ] sort-by reverse ; TUPLE: annotation < entity parent ; \ annotation "ANNOTATIONS" { { "parent" "PARENT" INTEGER +not-null+ } } define-persistent : ( parent id -- annotation ) \ annotation new swap >>id swap >>parent ; : lookup-annotation ( id -- annotation ) [ f ] dip select-tuple ; : paste ( id -- paste/f ) [ select-tuple ] keep over [ f select-tuples >>annotations ] [ drop ] if ; ! ! ! ! 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 ! ! ! : ( -- action ) [ pastes "pastes" set-value ] >>init { pastebin "pastebin" } >>template ; : ( -- action ) [ pastebin-url ] >>url [ "Factor Pastebin" ] >>title [ pastes ] >>entries ; ! ! ! ! PASTES ! ! ! : ( -- action ) [ validate-integer-id "id" value paste from-object "id" value "new-annotation" [ "parent" set-value paste-mode-names "modes" set-value "factor" "mode" set-value ] nest-form ] >>init { pastebin "paste" } >>template ; : ( -- action ) [ validate-integer-id "id" value paste from-object ] >>init [ "contents" value ] >>display ; : ( -- action ) [ validate-integer-id ] >>init [ "id" value paste-url ] >>url [ "Paste " "id" value number>string append ] >>title [ "id" value f 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 ; : email-on-paste ( url -- ) pastebin-email-to get-global [ drop ] [ swap >>to swap adjust-url present >>body pastebin-email-from get-global >>from "New paste!" >>subject send-email ] if-empty ; : ( -- action ) [ "factor" "mode" set-value paste-mode-names "modes" set-value ] >>init { pastebin "new-paste" } >>template [ paste-mode-names "modes" set-value validate-entity ] >>validate [ f [ deposit-entity-slots ] [ insert-tuple ] [ id>> paste-url [ email-on-paste ] [ ] bi ] tri ] >>submit ; : ( -- action ) [ validate-integer-id ] >>validate [ [ "id" value delete-tuples "id" value f delete-tuples ] with-transaction pastebin-url ] >>submit "delete pastes" >>description { can-delete-pastes? } >>capabilities ; ! ! ! ! ANNOTATIONS ! ! ! : ( -- action ) [ paste-mode-names "modes" set-value { { "parent" [ v-integer ] } } validate-params validate-entity ] >>validate [ "parent" value f [ deposit-entity-slots ] [ insert-tuple ] [ entity-url ] tri ] >>submit ; : ( -- action ) [ validate-integer-id "id" value lookup-annotation from-object ] >>init [ "contents" value ] >>display ; : ( -- action ) [ { { "id" [ v-number ] } } validate-params ] >>validate [ "id" value lookup-annotation [ delete-tuples ] [ parent>> paste-url ] bi ] >>submit "delete annotations" >>description { can-delete-pastes? } >>capabilities ; : ( -- responder ) pastebin new-dispatcher "" add-responder "list.atom" add-responder "paste" add-responder "paste.txt" add-responder "paste.atom" add-responder "new-paste" add-responder "delete-paste" add-responder "new-annotation" add-responder "annotation.txt" add-responder "delete-annotation" add-responder { pastebin "pastebin-common" } >>template ;