File edit modal
This commit is contained in:
@@ -7,14 +7,19 @@ function EditWindow() {
|
||||
)
|
||||
|
||||
let clone = document.getElementById("tpl_edit_file").content.cloneNode(true)
|
||||
this.notification = clone.querySelector(".edit_file_notification")
|
||||
this.fileNameField = clone.querySelector(".edit_file_name_field")
|
||||
|
||||
clone.querySelector(".btn_delete_file").addEventListener("click", () => { this.deleteFile() })
|
||||
clone.querySelector(".edit_file_name_form").addEventListener("submit", e => { this.renameFile(e) })
|
||||
|
||||
this.modal.setBody(clone)
|
||||
|
||||
this.btnEdit = document.getElementById("btn_edit")
|
||||
this.btnEdit.addEventListener("click", () => { this.toggle() })
|
||||
}
|
||||
|
||||
EditWindow.prototype.toggle = function() {
|
||||
EditWindow.prototype.toggle = function () {
|
||||
if (this.visible) {
|
||||
this.modal.close()
|
||||
this.btnEdit.classList.remove("button_highlight")
|
||||
@@ -26,9 +31,11 @@ EditWindow.prototype.toggle = function() {
|
||||
}
|
||||
}
|
||||
|
||||
EditWindow.prototype.setFile = function(file) {
|
||||
EditWindow.prototype.setFile = function (file) {
|
||||
this.file = file
|
||||
this.modal.setTitle("Editing "+file.name)
|
||||
this.modal.setTitle("Editing " + file.name)
|
||||
this.notification.style.display = "none"
|
||||
this.fileNameField.value = file.name
|
||||
|
||||
if (this.file.can_edit) {
|
||||
this.btnEdit.style.display = ""
|
||||
@@ -37,16 +44,44 @@ EditWindow.prototype.setFile = function(file) {
|
||||
}
|
||||
}
|
||||
|
||||
EditWindow.prototype.deleteFile = function() {
|
||||
if (!confirm("Are you sure you want to delete '"+this.file.name+"'?")) {
|
||||
EditWindow.prototype.notify = function (success, content) {
|
||||
this.notification.style.display = ""
|
||||
this.notification.classList = "edit_file_notification " + (success ? "highlight_green" : "highlight_red")
|
||||
this.notification.innerHTML = content
|
||||
}
|
||||
|
||||
EditWindow.prototype.deleteFile = async function () {
|
||||
if (!confirm("Are you sure you want to delete '" + this.file.name + "'?")) {
|
||||
return
|
||||
}
|
||||
|
||||
fetch(
|
||||
this.file.get_href, {method: "DELETE"}
|
||||
).then(resp => {
|
||||
this.modal.setBody(document.createTextNode("This file has been deleted"))
|
||||
}).catch(err => {
|
||||
alert("Error! Could not delete file")
|
||||
})
|
||||
try {
|
||||
const resp = await fetch(this.file.get_href, { method: "DELETE" });
|
||||
if (resp.status >= 400) {
|
||||
throw (await resp.json()).message
|
||||
}
|
||||
|
||||
this.notify(true, "This file has been deleted, you can close the page")
|
||||
} catch (err) {
|
||||
this.notify(false, "Could not delete file: " + err)
|
||||
}
|
||||
}
|
||||
|
||||
EditWindow.prototype.renameFile = async function (e) {
|
||||
e.preventDefault()
|
||||
|
||||
const form = new FormData()
|
||||
form.append("action", "rename")
|
||||
form.append("name", this.fileNameField.value)
|
||||
|
||||
try {
|
||||
const resp = await fetch(this.file.get_href, { method: "POST", body: form });
|
||||
if (resp.status >= 400) {
|
||||
throw (await resp.json()).message
|
||||
}
|
||||
|
||||
this.notify(true, "File name has been changed. Reload the page to see the changes")
|
||||
} catch (err) {
|
||||
this.notify(false, "Could not change file name: " + err)
|
||||
}
|
||||
}
|
||||
|
@@ -59,11 +59,11 @@ function Viewer(type, viewToken, data) {
|
||||
this.initialized = true
|
||||
}
|
||||
|
||||
Viewer.prototype.getFile = function() {
|
||||
Viewer.prototype.getFile = function () {
|
||||
return this.file
|
||||
}
|
||||
|
||||
Viewer.prototype.setFile = function(file) {
|
||||
Viewer.prototype.setFile = function (file) {
|
||||
this.file = file
|
||||
|
||||
if (this.isList) {
|
||||
@@ -85,10 +85,9 @@ Viewer.prototype.setFile = function(file) {
|
||||
if (file.view_href !== "") {
|
||||
fetch(file.view_href, {
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/x-www-form-urlencoded"},
|
||||
body: "token="+this.viewToken
|
||||
}
|
||||
)
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body: "token=" + this.viewToken
|
||||
})
|
||||
}
|
||||
|
||||
// Clean up the previous viewer if possible
|
||||
@@ -108,8 +107,8 @@ Viewer.prototype.setFile = function(file) {
|
||||
}
|
||||
|
||||
if (file.abuse_type !== "") {
|
||||
this.viewerScript = new AbuseViewer(this,file)
|
||||
}else if (file.mime_type.startsWith("image")) {
|
||||
this.viewerScript = new AbuseViewer(this, file)
|
||||
} else if (file.mime_type.startsWith("image")) {
|
||||
this.viewerScript = new ImageViewer(this, file)
|
||||
} else if (
|
||||
file.mime_type.startsWith("video") ||
|
||||
@@ -140,7 +139,7 @@ Viewer.prototype.setFile = function(file) {
|
||||
this.viewerScript.render(this.divFilepreview)
|
||||
}
|
||||
|
||||
Viewer.prototype.renderSponsors = function() {
|
||||
Viewer.prototype.renderSponsors = function () {
|
||||
// Check if the ad is enabled
|
||||
if (document.querySelector(".sponsors_banner") == null) { return }
|
||||
|
||||
@@ -151,10 +150,10 @@ Viewer.prototype.renderSponsors = function() {
|
||||
let bannerHeight = document.querySelector(".sponsors_banner").offsetHeight
|
||||
|
||||
if (window.innerWidth < bannerWidth) {
|
||||
scaleWidth = window.innerWidth/bannerWidth
|
||||
scaleWidth = window.innerWidth / bannerWidth
|
||||
}
|
||||
if (window.innerHeight < minWindowHeight) {
|
||||
scaleHeight = window.innerHeight/minWindowHeight
|
||||
scaleHeight = window.innerHeight / minWindowHeight
|
||||
}
|
||||
|
||||
// The smaller scale is the scale we'll use
|
||||
@@ -165,19 +164,22 @@ Viewer.prototype.renderSponsors = function() {
|
||||
// width of the viewport - the width of the ad to calculate the amount of
|
||||
// pixels around the ad. We multiply the ad size by the scale we calcualted
|
||||
// to account for the smaller size.
|
||||
let offset = (window.innerWidth - (bannerWidth*scale)) / 2
|
||||
let offset = (window.innerWidth - (bannerWidth * scale)) / 2
|
||||
|
||||
document.querySelector(".sponsors").style.height = (bannerHeight*scale)+"px"
|
||||
document.querySelector(".sponsors_banner").style.marginLeft = offset+"px"
|
||||
document.querySelector(".sponsors_banner").style.transform = "scale("+scale+")"
|
||||
document.querySelector(".sponsors").style.height = (bannerHeight * scale) + "px"
|
||||
document.querySelector(".sponsors_banner").style.marginLeft = offset + "px"
|
||||
document.querySelector(".sponsors_banner").style.transform = "scale(" + scale + ")"
|
||||
}
|
||||
|
||||
Viewer.prototype.keyboardEvent = function(evt) {
|
||||
Viewer.prototype.keyboardEvent = function (evt) {
|
||||
if (evt.ctrlKey || evt.altKey || evt.metaKey) {
|
||||
return // prevent custom shortcuts from interfering with system shortcuts
|
||||
}
|
||||
if (document.activeElement.type && document.activeElement.type === "text") {
|
||||
return // Prevent shortcuts from interfering with input fields
|
||||
}
|
||||
|
||||
console.debug("Key pressed: "+evt.keyCode)
|
||||
console.debug("Key pressed: " + evt.keyCode)
|
||||
switch (evt.keyCode) {
|
||||
case 65: // A or left arrow key go to previous file
|
||||
case 37:
|
||||
@@ -231,13 +233,13 @@ function escapeHTML(str) {
|
||||
function fileFromAPIResp(resp) {
|
||||
resp.date_created = new Date(resp.date_upload)
|
||||
resp.date_last_view = new Date(resp.date_last_view)
|
||||
resp.icon_href = apiEndpoint+"/file/"+resp.id+"/thumbnail"
|
||||
resp.get_href = apiEndpoint+"/file/"+resp.id
|
||||
resp.download_href = apiEndpoint+"/file/"+resp.id+"?download"
|
||||
resp.view_href = apiEndpoint+"/file/"+resp.id+"/view"
|
||||
resp.timeseries_href = apiEndpoint+"/file/"+resp.id+"/timeseries"
|
||||
resp.stats_href = apiEndpoint+"/file/"+resp.id+"/stats"
|
||||
resp.link = domainURL()+"/u/"+resp.id
|
||||
resp.icon_href = apiEndpoint + "/file/" + resp.id + "/thumbnail"
|
||||
resp.get_href = apiEndpoint + "/file/" + resp.id
|
||||
resp.download_href = apiEndpoint + "/file/" + resp.id + "?download"
|
||||
resp.view_href = apiEndpoint + "/file/" + resp.id + "/view"
|
||||
resp.timeseries_href = apiEndpoint + "/file/" + resp.id + "/timeseries"
|
||||
resp.stats_href = apiEndpoint + "/file/" + resp.id + "/stats"
|
||||
resp.link = domainURL() + "/u/" + resp.id
|
||||
if (resp.description === undefined) {
|
||||
resp.description = ""
|
||||
}
|
||||
@@ -247,11 +249,11 @@ function fileFromAPIResp(resp) {
|
||||
function fileFromSkyNet(resp) {
|
||||
let file = fileFromAPIResp(resp)
|
||||
file.icon_href = "/res/img/mime/empty.png"
|
||||
file.get_href = "https://skydrain.net/file/"+resp.id
|
||||
file.download_href = "https://skydrain.net/file/"+resp.id+"?attachment=1"
|
||||
file.get_href = "https://siasky.net/file/" + resp.id
|
||||
file.download_href = "https://siasky.net/file/" + resp.id + "?attachment=1"
|
||||
file.view_href = ""
|
||||
file.timeseries_href = ""
|
||||
file.stats_href = ""
|
||||
file.link = domainURL()+"/s/"+resp.id
|
||||
file.link = domainURL() + "/s/" + resp.id
|
||||
return file
|
||||
}
|
||||
|
@@ -244,7 +244,15 @@
|
||||
</template>
|
||||
|
||||
<template id="tpl_edit_file">
|
||||
<h3>Delete file</h3>
|
||||
<div class="edit_file_notification" style="display: none;"></div>
|
||||
<h3>Rename</h3>
|
||||
<form class="edit_file_name_form" style="display: flex; width: 100%">
|
||||
<input class="edit_file_name_field" type="text" style="flex: 1 1 auto"/>
|
||||
<button class="edit_file_name_submit" role="submit" style="flex: 0 0 auto">
|
||||
<i class="icon">save</i> Save
|
||||
</button>
|
||||
</form>
|
||||
<h3>Delete</h3>
|
||||
<p>
|
||||
When you delete a file it cannot be recovered.
|
||||
Nobody will be able to download it and the link will
|
||||
|
@@ -1,40 +1,33 @@
|
||||
{{ define "filesystem" }}<!DOCTYPE html>
|
||||
{{define "filesystem"}}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
{{template "meta_tags" .Title}}
|
||||
<title>{{.Title}}</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
{{template "user_style" .}}
|
||||
<style>{{template "file_manager.css" .}}</style>
|
||||
<script>var apiEndpoint = '{{.APIEndpoint}}';</script>
|
||||
|
||||
<link rel="icon" sizes="32x32" href="/res/img/pixeldrain_32.png" />
|
||||
<link rel="icon" sizes="128x128" href="/res/img/pixeldrain_128.png" />
|
||||
<link rel="icon" sizes="152x152" href="/res/img/pixeldrain_152.png" />
|
||||
<link rel="icon" sizes="180x180" href="/res/img/pixeldrain_180.png" />
|
||||
<link rel="icon" sizes="192x192" href="/res/img/pixeldrain_192.png" />
|
||||
<link rel="icon" sizes="196x196" href="/res/img/pixeldrain_196.png" />
|
||||
<link rel="icon" sizes="256x256" href="/res/img/pixeldrain_256.png" />
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="/res/img/pixeldrain_152.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/res/img/pixeldrain_180.png" />
|
||||
<link rel="shortcut icon" sizes="196x196" href="/res/img/pixeldrain_196.png" />
|
||||
<meta name="theme-color" content="#75AD38"/>
|
||||
|
||||
{{ template "opengraph" .OGData }}
|
||||
<script>
|
||||
const initialNode = {{.Other}};
|
||||
window.api_endpoint = '{{.APIEndpoint}}';
|
||||
</script>
|
||||
|
||||
<link rel='stylesheet' href='/res/svelte/filesystem.css'>
|
||||
<script defer src='/res/svelte/filesystem.js'></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{{template "page_top" .}}
|
||||
|
||||
<h1>{{ .Title}}</h1>
|
||||
|
||||
<div class="page_content">
|
||||
<div class="limit_width">
|
||||
<h2>
|
||||
<a href="/fs">Buckets</a>
|
||||
{{ range $node := .Other.Path }}
|
||||
/ <a href="{{ $node.HREF }}">{{ $node.Name }}</a>
|
||||
{{ end }}
|
||||
{{ if ne .Other.Base.Name "" }}
|
||||
/ {{ .Other.Base.Name }}
|
||||
{{ end }}
|
||||
</h2>
|
||||
|
||||
{{ range $node := .Other.Children }}
|
||||
<a class="node" href="{{ $node.HREF }}"><div>
|
||||
<img src="{{ $node.Icon }}"/>
|
||||
<span>{{ $node.Name }}</span>
|
||||
</div></a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "page_bottom" .}}
|
||||
{{template "analytics"}}
|
||||
</body>
|
||||
<body></body>
|
||||
</html>
|
||||
{{ end }}
|
||||
{{end}}
|
||||
|
@@ -1,33 +0,0 @@
|
||||
{{define "filesystem_svelte"}}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{.Title}}</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
{{template "user_style" .}}
|
||||
|
||||
<link rel="icon" sizes="32x32" href="/res/img/pixeldrain_32.png" />
|
||||
<link rel="icon" sizes="128x128" href="/res/img/pixeldrain_128.png" />
|
||||
<link rel="icon" sizes="152x152" href="/res/img/pixeldrain_152.png" />
|
||||
<link rel="icon" sizes="180x180" href="/res/img/pixeldrain_180.png" />
|
||||
<link rel="icon" sizes="192x192" href="/res/img/pixeldrain_192.png" />
|
||||
<link rel="icon" sizes="196x196" href="/res/img/pixeldrain_196.png" />
|
||||
<link rel="icon" sizes="256x256" href="/res/img/pixeldrain_256.png" />
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="/res/img/pixeldrain_152.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/res/img/pixeldrain_180.png" />
|
||||
<link rel="shortcut icon" sizes="196x196" href="/res/img/pixeldrain_196.png" />
|
||||
<meta name="theme-color" content="#75AD38"/>
|
||||
|
||||
{{ template "opengraph" .OGData }}
|
||||
<script>
|
||||
const initialNode = {{.Other}};
|
||||
window.api_endpoint = '{{.APIEndpoint}}';
|
||||
</script>
|
||||
|
||||
<link rel='stylesheet' href='/res/svelte/filesystem.css'>
|
||||
<script defer src='/res/svelte/filesystem.js'></script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
{{end}}
|
@@ -13,8 +13,7 @@ let new_bucket_name
|
||||
const get_buckets = async () => {
|
||||
loading = true;
|
||||
try {
|
||||
let resp = await fs_get_buckets();
|
||||
buckets = resp.buckets;
|
||||
buckets = await fs_get_buckets();
|
||||
} catch (err) {
|
||||
alert(err);
|
||||
} finally {
|
||||
|
@@ -28,7 +28,7 @@ func (wc *WebController) adminGlobalsForm(td *TemplateData, r *http.Request) (f
|
||||
return f
|
||||
}
|
||||
var globalsMap = make(map[string]string)
|
||||
for _, v := range globals.Globals {
|
||||
for _, v := range globals {
|
||||
f.Fields = append(f.Fields, Field{
|
||||
Name: v.Key,
|
||||
DefaultValue: v.Value,
|
||||
|
@@ -225,7 +225,7 @@ func (wc *WebController) serveSkynetViewer(w http.ResponseWriter, r *http.Reques
|
||||
|
||||
// Get the first few bytes from the file to probe the content type and
|
||||
// length
|
||||
rq, err := http.NewRequest("GET", "https://skydrain.net/file/"+p.ByName("id"), nil)
|
||||
rq, err := http.NewRequest("GET", "https://siasky.net/file/"+p.ByName("id"), nil)
|
||||
if err != nil {
|
||||
log.Warn("Failed to make request to sia portal: %s", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
@@ -3,123 +3,12 @@ package webcontroller
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"fornaxian.tech/pixeldrain_server/api/restapi/apitype"
|
||||
"github.com/Fornaxian/log"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
type filesystemPath struct {
|
||||
Path []filesystemNode
|
||||
Base filesystemNode
|
||||
Children []filesystemNode
|
||||
}
|
||||
|
||||
type filesystemNode struct {
|
||||
HREF string
|
||||
Icon string
|
||||
Name string
|
||||
Type string
|
||||
FileSize int64
|
||||
FileType string
|
||||
}
|
||||
|
||||
func convFilesystemNode(bucketID string, v apitype.FilesystemNode) (node filesystemNode) {
|
||||
node = filesystemNode{
|
||||
HREF: "/fs/" + bucketID + v.Path,
|
||||
Type: v.Type,
|
||||
Name: v.Name,
|
||||
FileSize: v.FileSize,
|
||||
FileType: v.FileType,
|
||||
}
|
||||
if node.Type == "dir" {
|
||||
node.Icon = "/res/img/mime/folder.png"
|
||||
} else {
|
||||
node.Icon = "/res/img/mime/empty.png"
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
func (wc *WebController) serveFilesystem(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||
var err error
|
||||
var td = wc.newTemplateData(w, r)
|
||||
var path = strings.TrimPrefix(p.ByName("path"), "/")
|
||||
var fsPath filesystemPath
|
||||
|
||||
if path == "" {
|
||||
buckets, err := td.PixelAPI.GetFilesystemBuckets()
|
||||
if err != nil {
|
||||
if err.Error() == "not_found" {
|
||||
wc.templates.Get().ExecuteTemplate(w, "404", td)
|
||||
} else if err.Error() == "authentication_required" {
|
||||
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
||||
} else {
|
||||
log.Error("Failed to get buckets: %s", err)
|
||||
wc.templates.Get().ExecuteTemplate(w, "500", td)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range buckets.Buckets {
|
||||
fsPath.Children = append(fsPath.Children, filesystemNode{
|
||||
HREF: "/fs/" + v.ID,
|
||||
Icon: "/res/img/mime/folder-remote.png",
|
||||
Type: "dir",
|
||||
Name: v.Name,
|
||||
FileSize: 0,
|
||||
FileType: "inode/directory",
|
||||
})
|
||||
}
|
||||
} else {
|
||||
log.Info("getting path %s", path)
|
||||
node, err := td.PixelAPI.GetFilesystemPath(path)
|
||||
if err != nil {
|
||||
if err.Error() == "not_found" || err.Error() == "path_not_found" {
|
||||
wc.templates.Get().ExecuteTemplate(w, "404", td)
|
||||
} else {
|
||||
log.Error("Failed to get path: %s", err)
|
||||
wc.templates.Get().ExecuteTemplate(w, "500", td)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if node.Base.Type == "file" {
|
||||
http.Redirect(w, r, "/api/filesystem/"+path, http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range node.Parents {
|
||||
fsPath.Path = append(fsPath.Path, convFilesystemNode(node.Bucket.ID, v))
|
||||
}
|
||||
|
||||
fsPath.Base = convFilesystemNode(node.Bucket.ID, node.Base)
|
||||
|
||||
for _, v := range node.Base.Children {
|
||||
fsPath.Children = append(fsPath.Children, convFilesystemNode(node.Bucket.ID, v))
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(fsPath.Children, func(i, j int) (less bool) {
|
||||
// Directories always come first. Make sure we're comparing apples with
|
||||
// apples
|
||||
if fsPath.Children[i].Type != fsPath.Children[j].Type {
|
||||
return fsPath.Children[i].Type == "dir"
|
||||
}
|
||||
|
||||
return fsPath.Children[i].Name < fsPath.Children[j].Name
|
||||
})
|
||||
|
||||
td.Title = "Filesystem"
|
||||
td.Other = fsPath
|
||||
err = wc.templates.Get().ExecuteTemplate(w, "filesystem", td)
|
||||
if err != nil && !strings.Contains(err.Error(), "broken pipe") {
|
||||
log.Error("Error executing template filesystem: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (wc *WebController) serveDirectory(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||
var err error
|
||||
var td = wc.newTemplateData(w, r)
|
||||
@@ -138,7 +27,7 @@ func (wc *WebController) serveDirectory(w http.ResponseWriter, r *http.Request,
|
||||
|
||||
td.Title = fmt.Sprintf("%s ~ pixeldrain", node.Base.Name)
|
||||
td.Other = node
|
||||
err = wc.templates.Get().ExecuteTemplate(w, "filesystem_svelte", td)
|
||||
err = wc.templates.Get().ExecuteTemplate(w, "filesystem", td)
|
||||
if err != nil && !strings.Contains(err.Error(), "broken pipe") {
|
||||
log.Error("Error executing template filesystem: %s", err)
|
||||
}
|
||||
|
@@ -114,6 +114,7 @@ func New(
|
||||
{GET, "u/:id" /* */, wc.serveFileViewer},
|
||||
{GET, "u/:id/preview" /* */, wc.serveFilePreview},
|
||||
{GET, "l/:id" /* */, wc.serveListViewer},
|
||||
{GET, "d/*path" /* */, wc.serveDirectory},
|
||||
{GET, "s/:id" /* */, wc.serveSkynetViewer},
|
||||
{GET, "t" /* */, wc.serveTemplate("text_editor", false)},
|
||||
{GET, "donation" /* */, wc.serveMarkdown("donation.md", false)},
|
||||
@@ -150,10 +151,6 @@ func New(
|
||||
{GET, "user/password_reset_confirm" /**/, wc.serveForm(wc.passwordResetConfirmForm, false)},
|
||||
{PST, "user/password_reset_confirm" /**/, wc.serveForm(wc.passwordResetConfirmForm, false)},
|
||||
|
||||
// Filesystem
|
||||
{GET, "fs/*path", wc.serveFilesystem},
|
||||
{GET, "d/*path", wc.serveDirectory},
|
||||
|
||||
{GET, "patreon_activate" /* */, wc.serveForm(wc.patreonLinkForm, true)},
|
||||
{PST, "patreon_activate" /* */, wc.serveForm(wc.patreonLinkForm, true)},
|
||||
|
||||
|
Reference in New Issue
Block a user