breezewiki/src/application-globals.rkt

158 lines
7.8 KiB
Racket

#lang racket/base
(require racket/string
json
(prefix-in easy: net/http-easy)
html-writing
web-server/http
"config.rkt"
"data.rkt"
"xexpr-utils.rkt"
"url-utils.rkt")
(provide
; headers to always send on all http responses
always-headers
; timeout durations for http-easy requests
timeouts
; generates a consistent footer
application-footer
; generates a consistent template for wiki page content to sit in
generate-wiki-page
; generates a minimal but complete redirect to another page
generate-redirect)
(module+ test
(require rackunit
html-writing))
(define always-headers
(list (header #"Referrer-Policy" #"same-origin"))) ; header to not send referers to fandom
(define timeouts (easy:make-timeout-config #:lease 5 #:connect 5))
(define (application-footer source-url #:license [license-in #f])
(define license (or license-in license-default))
`(footer (@ (class "custom-footer"))
(div (@ (class ,(if source-url "custom-footer__cols" "internal-footer")))
(div (p
(img (@ (class "my-logo") (src "/static/breezewiki.svg"))))
(p
(a (@ (href "https://gitdab.com/cadence/breezewiki"))
,(format "~a source code" (config-get 'application_name))))
(p
(a (@ (href "https://docs.breezewiki.com"))
"Documentation and more information"))
(p
(a (@ (href "https://lists.sr.ht/~cadence/breezewiki-discuss"))
"Discussions / Bug reports / Feature requests"))
,(if (config-true? 'instance_is_official)
`(p ,(format "This instance is run by the ~a developer, " (config-get 'application_name))
(a (@ (href "https://cadence.moe/contact"))
"Cadence."))
`(p
,(format "This unofficial instance is based off the ~a source code, but is not controlled by the code developer." (config-get 'application_name)))))
,(if source-url
`(div (p "This page displays proxied content from "
(a (@ (href ,source-url) (rel "noreferrer")) ,source-url)
,(format ". Text content is available under the ~a license, " (license^-text license))
(a (@ (href ,(license^-url license))) "see license info.")
" Media files may have different copying restrictions.")
(p ,(format "Fandom is a trademark of Fandom, Inc. ~a is not affiliated with Fandom." (config-get 'application_name))))
`(div (p "Text content on wikis run by Fandom is available under the Creative Commons Attribution-Share Alike License 3.0 (Unported), "
(a (@ (href "https://www.fandom.com/licensing")) "see license info.")
" Media files and official Fandom documents have different copying restrictions.")
(p ,(format "Fandom is a trademark of Fandom, Inc. ~a is not affiliated with Fandom." (config-get 'application_name))))))))
(define (generate-wiki-page
content
#:source-url source-url
#:wikiname wikiname
#:title title
#:body-class [body-class-in #f]
#:siteinfo [siteinfo-in #f])
(define siteinfo (or siteinfo-in siteinfo-default))
(define body-class (if (not body-class-in)
"skin-fandomdesktop"
body-class-in))
(define (required-styles origin)
(map (λ (dest-path)
(define url (format dest-path origin))
(if (config-true? 'strict_proxy)
(u-proxy-url url)
url))
'(#;"~a/load.php?lang=en&modules=skin.fandomdesktop.styles&only=styles&skin=fandomdesktop"
#;"~a/load.php?lang=en&modules=ext.gadget.dungeonsWiki%2CearthWiki%2Csite-styles%2Csound-styles&only=styles&skin=fandomdesktop"
#;"~a/load.php?lang=en&modules=site.styles&only=styles&skin=fandomdesktop"
; combine the above entries into a single request for potentially extra speed - fandom.com doesn't even do this!
"~a/wikia.php?controller=ThemeApi&method=themeVariables"
"~a/load.php?lang=en&modules=skin.fandomdesktop.styles%7Cext.fandom.PortableInfoboxFandomDesktop.css%7Cext.fandom.GlobalComponents.CommunityHeaderBackground.css%7Cext.gadget.site-styles%2Csound-styles%7Csite.styles&only=styles&skin=fandomdesktop")))
`(html
(head
(meta (@ (name "viewport") (content "width=device-width, initial-scale=1")))
(title ,(format "~a | ~a+~a"
title
(regexp-replace #rx" ?Wiki$" (siteinfo^-sitename siteinfo) "")
(config-get 'application_name)))
,@(map (λ (url)
`(link (@ (rel "stylesheet") (type "text/css") (href ,url))))
(required-styles (format "https://~a.fandom.com" wikiname)))
(link (@ (rel "stylesheet") (type "text/css") (href "/static/main.css")))
(script "const BWData = "
,(jsexpr->string (hasheq 'wikiname wikiname
'strict_proxy (config-true? 'strict_proxy))))
,(if (config-true? 'feature_search_suggestions)
'(script (@ (type "module") (src "/static/search-suggestions.js")))
""))
(body (@ (class ,body-class))
(div (@ (class "main-container"))
(div (@ (class "fandom-community-header__background tileHorizontally header")))
(div (@ (class "page"))
(main (@ (class "page__main"))
(div (@ (class "custom-top"))
(h1 (@ (class "page-title")) ,title)
(nav (@ (class "sitesearch"))
(form (@ (action ,(format "/~a/search" wikiname))
(class "bw-search-form")
(id "bw-pr-search-form"))
(label (@ (for "bw-search-input")) "Search ")
(div (@ (id "bw-pr-search-input"))
(input (@ (type "text") (name "q") (id "bw-search-input") (autocomplete "off"))))
(div (@ (class "bw-ss__container") (id "bw-pr-search-suggestions"))))))
(div (@ (id "content") #;(class "page-content"))
(div (@ (id "mw-content-text"))
,content))
,(application-footer source-url #:license (siteinfo^-license siteinfo))))))))
(module+ test
(define page
(parameterize ([(config-parameter 'strict_proxy) "true"])
(generate-wiki-page
'(template)
#:source-url ""
#:title "test"
#:wikiname "test")))
; check the page is a valid xexp
(check-not-false (xexp->html page))
; check the stylesheet is proxied
(check-true (string-prefix?
(get-attribute 'href
(bits->attributes
((query-selector
(λ (t a c) (eq? t 'link))
page))))
"/proxy?dest=https%3A%2F%2Ftest.fandom.com")))
(define (generate-redirect dest)
(define dest-bytes (string->bytes/utf-8 dest))
(response/output
#:code 302
#:headers (list (header #"Location" dest-bytes))
(λ (out)
(write-html
`(html
(head
(title "Redirecting..."))
(body
"Redirecting to "
(a (@ (href ,dest)) ,dest)
"..."))
out))))