Custom pages: Implement adding custom markdown pages to the site navigation
This commit is contained in:
parent
9f6346a373
commit
fb0d44f132
|
@ -34,4 +34,5 @@ linx-genkey
|
|||
files/
|
||||
meta/
|
||||
binaries/
|
||||
custom_pages/
|
||||
authfile
|
||||
|
|
|
@ -56,6 +56,7 @@ allowhotlink = true
|
|||
- ```-remoteuploads``` -- (optionally) enable remote uploads (/upload?url=https://...)
|
||||
- ```-nologs``` -- (optionally) disable request logs in stdout
|
||||
- ```-force-random-filename``` -- (optionally) force the use of random filenames
|
||||
- ```-custompagespath "custom_pages"``` -- (optionally) specify path to directory containing markdown pages (must end in .md) that will be added to the site navigation (this can be useful for providing contact/support information and so on). For example, custom_pages/My_Page.md will become My Page in the site navigation
|
||||
|
||||
#### Require API Keys for uploads
|
||||
- ```-authfile path/to/authfile``` -- (optionally) require authorization for upload/delete by providing a newline-separated file of scrypted auth keys
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
"github.com/russross/blackfriday"
|
||||
)
|
||||
|
||||
func initializeCustomPages(customPagesDir string) {
|
||||
files, err := ioutil.ReadDir(customPagesDir)
|
||||
if err != nil {
|
||||
log.Fatal("Error reading the custom pages directory: ", err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
fileName := file.Name()
|
||||
|
||||
if len(fileName) <= 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.EqualFold(string(fileName[len(fileName)-3:len(fileName)]), ".md") {
|
||||
contents, err := ioutil.ReadFile(path.Join(customPagesDir, fileName))
|
||||
if err != nil {
|
||||
log.Fatalf("Error reading file %s", fileName)
|
||||
}
|
||||
|
||||
unsafe := blackfriday.MarkdownCommon(contents)
|
||||
html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
|
||||
|
||||
fileName := fileName[0 : len(fileName)-3]
|
||||
customPages[fileName] = string(html)
|
||||
customPagesNames[fileName] = strings.ReplaceAll(fileName, "_", " ")
|
||||
}
|
||||
}
|
||||
}
|
15
pages.go
15
pages.go
|
@ -50,6 +50,21 @@ func apiDocHandler(c web.C, w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func makeCustomPageHandler(fileName string) func(c web.C, w http.ResponseWriter, r *http.Request) {
|
||||
return func(c web.C, w http.ResponseWriter, r *http.Request) {
|
||||
err := renderTemplate(Templates["custom_page.html"], pongo2.Context{
|
||||
"siteurl": getSiteURL(r),
|
||||
"forcerandom": Config.forceRandomFilename,
|
||||
"contents": customPages[fileName],
|
||||
"filename": fileName,
|
||||
"pagename": customPagesNames[fileName],
|
||||
}, r, w)
|
||||
if err != nil {
|
||||
oopsHandler(c, w, r, RespHTML, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func notFoundHandler(c web.C, w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(404)
|
||||
err := renderTemplate(Templates["404.html"], pongo2.Context{}, r, w)
|
||||
|
|
13
server.go
13
server.go
|
@ -70,6 +70,7 @@ var Config struct {
|
|||
s3ForcePathStyle bool
|
||||
forceRandomFilename bool
|
||||
accessKeyCookieExpiry uint64
|
||||
customPagesDir string
|
||||
}
|
||||
|
||||
var Templates = make(map[string]*pongo2.Template)
|
||||
|
@ -80,6 +81,8 @@ var timeStartedStr string
|
|||
var remoteAuthKeys []string
|
||||
var metaStorageBackend backends.MetaStorageBackend
|
||||
var storageBackend backends.StorageBackend
|
||||
var customPages = make(map[string]string)
|
||||
var customPagesNames = make(map[string]string)
|
||||
|
||||
func setup() *web.Mux {
|
||||
mux := web.New()
|
||||
|
@ -227,6 +230,14 @@ func setup() *web.Mux {
|
|||
mux.Get(selifIndexRe, unauthorizedHandler)
|
||||
mux.Get(torrentRe, fileTorrentHandler)
|
||||
|
||||
if Config.customPagesDir != "" {
|
||||
initializeCustomPages(Config.customPagesDir)
|
||||
for fileName := range customPagesNames {
|
||||
mux.Get(Config.sitePath+fileName, makeCustomPageHandler(fileName))
|
||||
mux.Get(Config.sitePath+fileName+"/", makeCustomPageHandler(fileName))
|
||||
}
|
||||
}
|
||||
|
||||
mux.NotFound(notFoundHandler)
|
||||
|
||||
return mux
|
||||
|
@ -298,6 +309,8 @@ func main() {
|
|||
flag.BoolVar(&Config.forceRandomFilename, "force-random-filename", false,
|
||||
"Force all uploads to use a random filename")
|
||||
flag.Uint64Var(&Config.accessKeyCookieExpiry, "access-cookie-expiry", 0, "Expiration time for access key cookies in seconds (set 0 to use session cookies)")
|
||||
flag.StringVar(&Config.customPagesDir, "custompagespath", "",
|
||||
"path to directory containing .md files to render as custom pages")
|
||||
|
||||
iniflags.Parse()
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
|
@ -52,6 +52,7 @@ func populateTemplatesMap(tSet *pongo2.TemplateSet, tMap map[string]*pongo2.Temp
|
|||
"404.html",
|
||||
"oops.html",
|
||||
"access.html",
|
||||
"custom_page.html",
|
||||
|
||||
"display/audio.html",
|
||||
"display/image.html",
|
||||
|
@ -85,6 +86,8 @@ func renderTemplate(tpl *pongo2.Template, context pongo2.Context, r *http.Reques
|
|||
|
||||
context["sitepath"] = Config.sitePath
|
||||
context["selifpath"] = Config.selifPath
|
||||
context["custom_pages_names"] = customPagesNames
|
||||
|
||||
var a string
|
||||
if Config.authFile == "" {
|
||||
a = "none"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{sitename}} - 404 Not Found{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="error-404">
|
||||
<a href="{{ sitepath }}"><img src='{{ sitepath }}static/images/404.jpg'></a>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{sitename}} - API{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<link href="{{ sitepath }}static/css/github-markdown.css" rel="stylesheet" type="text/css">
|
||||
{% endblock %}
|
||||
|
@ -12,16 +14,19 @@
|
|||
<h2>API</h2>
|
||||
|
||||
<h3>Client</h3>
|
||||
<p>To simplify uploading and deleting files, you can use <a target="_blank" href="https://github.com/andreimarcu/linx-client">linx-client</a>, which uses this API.</p>
|
||||
<p>To simplify uploading and deleting files, you can use <a target="_blank"
|
||||
href="https://github.com/andreimarcu/linx-client">linx-client</a>, which uses this API.</p>
|
||||
|
||||
{% if auth != "none" %}
|
||||
<h3>Keys</h3>
|
||||
<p>This instance uses API Keys, therefore you will need to provide a key for uploading and deleting files.<br/> To do so, add the <code>Linx-Api-Key</code> header with your key.</p>
|
||||
<p>This instance uses API Keys, therefore you will need to provide a key for uploading and deleting
|
||||
files.<br /> To do so, add the <code>Linx-Api-Key</code> header with your key.</p>
|
||||
{% endif %}
|
||||
|
||||
<h3>Uploading a file</h3>
|
||||
|
||||
<p>To upload a file, make a PUT request to <code>{{ siteurl }}upload/</code> and you will get the url of your upload back.</p>
|
||||
<p>To upload a file, make a PUT request to <code>{{ siteurl }}upload/</code> and you will get the url of
|
||||
your upload back.</p>
|
||||
|
||||
<p><strong>Optional headers with the request</strong></p>
|
||||
|
||||
|
@ -92,7 +97,8 @@
|
|||
|
||||
<h3>Overwriting a file</h3>
|
||||
|
||||
<p>To overwrite a file you uploaded, simply provide the <code>Linx-Delete-Key</code> header with the original file's deletion key.</p>
|
||||
<p>To overwrite a file you uploaded, simply provide the <code>Linx-Delete-Key</code> header with the
|
||||
original file's deletion key.</p>
|
||||
|
||||
<p><strong>Example</p></strong>
|
||||
|
||||
|
@ -108,7 +114,8 @@
|
|||
|
||||
<h3>Deleting a file</h3>
|
||||
|
||||
<p>To delete a file you uploaded, make a DELETE request to <code>{{ siteurl }}yourfile.ext</code> with the delete key set as the <code>Linx-Delete-Key</code> header.</p>
|
||||
<p>To delete a file you uploaded, make a DELETE request to <code>{{ siteurl }}yourfile.ext</code> with the
|
||||
delete key set as the <code>Linx-Delete-Key</code> header.</p>
|
||||
|
||||
<p><strong>Example</strong></p>
|
||||
|
||||
|
@ -124,7 +131,8 @@ DELETED</code></pre>
|
|||
|
||||
<h3>Information about a file</h3>
|
||||
|
||||
<p>To retrieve information about a file, make a GET request the public url with <code>Accept: application/json</code> headers and you will receive a json response containing:</p>
|
||||
<p>To retrieve information about a file, make a GET request the public url with
|
||||
<code>Accept: application/json</code> headers and you will receive a json response containing:</p>
|
||||
|
||||
<blockquote>
|
||||
<p>“url”: the publicly available upload url<br />
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{sitename}} - Password protected file{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="main" class="oopscontent">
|
||||
<form action="{{ unlockpath }}" method="POST" enctype="multipart/form-data">
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>{% block title %}{{ sitename }}{% endblock %}</title>
|
||||
<meta charset='utf-8' content='text/html' http-equiv='content-type'>
|
||||
|
@ -20,6 +21,9 @@
|
|||
<a href="{{ sitepath }}paste/">Paste</a> |
|
||||
{% endif %}
|
||||
<a href="{{ sitepath }}API/">API</a>
|
||||
{% for custom_file_name, custom_page_name in custom_pages_names sorted %}
|
||||
| <a href="{{ sitepath }}{{ custom_file_name }}/">{{ custom_page_name }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<h2><a href="{{ sitepath }}" title="{{ sitename }}">{{ sitename }}</a></h2>
|
||||
</div>
|
||||
|
@ -33,4 +37,5 @@
|
|||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,19 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{sitename}} - {{ pagename }}{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<link href="{{ sitepath }}static/css/github-markdown.css" rel="stylesheet" type="text/css">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<div id='inner_content'>
|
||||
<div class="normal markdown-body">
|
||||
<h2>{{ pagename }}</h2>
|
||||
|
||||
{{ contents|safe }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "../base.html" %}
|
||||
|
||||
{% block title %}{{ filename }}{% endblock %}
|
||||
{% block title %}{{sitename}} - {{ filename }}{% endblock %}
|
||||
|
||||
{% block bodymore %}{% endblock %}
|
||||
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{sitename}} - Paste{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form id="reply" action='{{ sitepath }}upload' method='post'>
|
||||
<div id="main" class="paste">
|
||||
<div id="info" class="info-flex">
|
||||
<div>
|
||||
{% if not forcerandom %}<span class="hint--top hint--bounce" data-hint="Leave empty for random filename"><input class="codebox" name='filename' id="filename" type='text' value="" placeholder="filename" /></span>{% endif %}.<span class="hint--top hint--bounce" data-hint="Enable syntax highlighting by adding the extension"><input id="extension" class="codebox" name='extension' type='text' value="" placeholder="txt" /></span>
|
||||
{% if not forcerandom %}<span class="hint--top hint--bounce"
|
||||
data-hint="Leave empty for random filename"><input class="codebox" name='filename' id="filename"
|
||||
type='text' value="" placeholder="filename" /></span>{% endif %}.<span
|
||||
class="hint--top hint--bounce" data-hint="Enable syntax highlighting by adding the extension"><input
|
||||
id="extension" class="codebox" name='extension' type='text' value="" placeholder="txt" /></span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="hint--top hint--bounce" data-hint="Require password to access (leave empty to disable)">
|
||||
|
@ -15,7 +21,8 @@
|
|||
<select id="expiry" name="expires">
|
||||
<option disabled>Expires:</option>
|
||||
{% for expiry in expirylist %}
|
||||
<option value="{{ expiry.Seconds }}"{% if forloop.Last %} selected{% endif %}>{{ expiry.Human }}</option>
|
||||
<option value="{{ expiry.Seconds }}" {% if forloop.Last %} selected{% endif %}>{{ expiry.Human }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button type="submit">Paste</button>
|
||||
|
|
Loading…
Reference in New Issue