more updates
parent
8c19482190
commit
af4aaf07df
|
@ -1,4 +1,4 @@
|
||||||
package http
|
package filemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -7,13 +7,12 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
fm "github.com/hacdias/filemanager"
|
|
||||||
"github.com/hacdias/filemanager/frontmatter"
|
"github.com/hacdias/filemanager/frontmatter"
|
||||||
"github.com/spf13/hugo/parser"
|
"github.com/spf13/hugo/parser"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Editor contains the information for the editor page
|
// editor contains the information for the editor page
|
||||||
type Editor struct {
|
type editor struct {
|
||||||
Class string
|
Class string
|
||||||
Mode string
|
Mode string
|
||||||
Visual bool
|
Visual bool
|
||||||
|
@ -24,12 +23,12 @@ type Editor struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getEditor gets the editor based on a FileInfo struct
|
// newEditor gets the editor based on a FileInfo struct
|
||||||
func getEditor(r *http.Request, i *fm.FileInfo) (*Editor, error) {
|
func newEditor(r *http.Request, i *file) (*editor, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// Create a new editor variable and set the mode
|
// Create a new editor variable and set the mode
|
||||||
e := new(Editor)
|
e := new(editor)
|
||||||
e.Mode = editorMode(i.Name)
|
e.Mode = editorMode(i.Name)
|
||||||
e.Class = editorClass(e.Mode)
|
e.Class = editorClass(e.Mode)
|
||||||
|
|
22
file.go
22
file.go
|
@ -13,8 +13,8 @@ import (
|
||||||
humanize "github.com/dustin/go-humanize"
|
humanize "github.com/dustin/go-humanize"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FileInfo contains the information about a particular file or directory.
|
// file contains the information about a particular file or directory.
|
||||||
type FileInfo struct {
|
type file struct {
|
||||||
Name string
|
Name string
|
||||||
Size int64
|
Size int64
|
||||||
URL string
|
URL string
|
||||||
|
@ -30,11 +30,11 @@ type FileInfo struct {
|
||||||
UserAllowed bool // Indicates if the user has enough permissions
|
UserAllowed bool // Indicates if the user has enough permissions
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetInfo retrieves the file information and the error, if there is any.
|
// getFile retrieves the file information and the error, if there is any.
|
||||||
func GetInfo(url *url.URL, c *Config, u *User) (*FileInfo, error) {
|
func getFile(url *url.URL, c *Config, u *User) (*file, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
i := &FileInfo{URL: c.PrefixURL + url.Path}
|
i := &file{URL: c.PrefixURL + url.Path}
|
||||||
i.VirtualPath = strings.Replace(url.Path, c.BaseURL, "", 1)
|
i.VirtualPath = strings.Replace(url.Path, c.BaseURL, "", 1)
|
||||||
i.VirtualPath = strings.TrimPrefix(i.VirtualPath, "/")
|
i.VirtualPath = strings.TrimPrefix(i.VirtualPath, "/")
|
||||||
i.VirtualPath = "/" + i.VirtualPath
|
i.VirtualPath = "/" + i.VirtualPath
|
||||||
|
@ -75,7 +75,7 @@ var textExtensions = [...]string{
|
||||||
|
|
||||||
// RetrieveFileType obtains the mimetype and a simplified internal Type
|
// RetrieveFileType obtains the mimetype and a simplified internal Type
|
||||||
// using the first 512 bytes from the file.
|
// using the first 512 bytes from the file.
|
||||||
func (i *FileInfo) RetrieveFileType() error {
|
func (i *file) RetrieveFileType() error {
|
||||||
i.Mimetype = mime.TypeByExtension(i.Extension)
|
i.Mimetype = mime.TypeByExtension(i.Extension)
|
||||||
|
|
||||||
if i.Mimetype == "" {
|
if i.Mimetype == "" {
|
||||||
|
@ -126,7 +126,7 @@ func (i *FileInfo) RetrieveFileType() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads the file.
|
// Reads the file.
|
||||||
func (i *FileInfo) Read() error {
|
func (i *file) Read() error {
|
||||||
if len(i.Content) != 0 {
|
if len(i.Content) != 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -140,22 +140,22 @@ func (i *FileInfo) Read() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// StringifyContent returns the string version of Raw
|
// StringifyContent returns the string version of Raw
|
||||||
func (i FileInfo) StringifyContent() string {
|
func (i file) StringifyContent() string {
|
||||||
return string(i.Content)
|
return string(i.Content)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HumanSize returns the size of the file as a human-readable string
|
// HumanSize returns the size of the file as a human-readable string
|
||||||
// in IEC format (i.e. power of 2 or base 1024).
|
// in IEC format (i.e. power of 2 or base 1024).
|
||||||
func (i FileInfo) HumanSize() string {
|
func (i file) HumanSize() string {
|
||||||
return humanize.IBytes(uint64(i.Size))
|
return humanize.IBytes(uint64(i.Size))
|
||||||
}
|
}
|
||||||
|
|
||||||
// HumanModTime returns the modified time of the file as a human-readable string.
|
// HumanModTime returns the modified time of the file as a human-readable string.
|
||||||
func (i FileInfo) HumanModTime(format string) string {
|
func (i file) HumanModTime(format string) string {
|
||||||
return i.ModTime.Format(format)
|
return i.ModTime.Format(format)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanBeEdited checks if the extension of a file is supported by the editor
|
// CanBeEdited checks if the extension of a file is supported by the editor
|
||||||
func (i FileInfo) CanBeEdited() bool {
|
func (i file) CanBeEdited() bool {
|
||||||
return i.Type == "text"
|
return i.Type == "text"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package page
|
package filemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
|
@ -1,4 +1,4 @@
|
||||||
package page
|
package filemanager
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package http
|
package filemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -7,21 +7,18 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
fm "github.com/hacdias/filemanager"
|
|
||||||
"github.com/hacdias/filemanager/assets"
|
|
||||||
"github.com/hacdias/filemanager/page"
|
|
||||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ServeHTTP starts FileManager.
|
// ServeHTTP starts FileManager.
|
||||||
func ServeHTTP(w http.ResponseWriter, r *http.Request, c *fm.Config) (int, error) {
|
func (c *Config) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
var (
|
var (
|
||||||
fi *fm.FileInfo
|
fi *file
|
||||||
user *fm.User
|
user *User
|
||||||
code int
|
code int
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
/* TODO: readd this
|
||||||
// Checks if the URL matches the Assets URL. Returns the asset if the
|
// Checks if the URL matches the Assets URL. Returns the asset if the
|
||||||
// method is GET and Status Forbidden otherwise.
|
// method is GET and Status Forbidden otherwise.
|
||||||
if strings.HasPrefix(r.URL.Path, c.BaseURL+assets.BaseURL) {
|
if strings.HasPrefix(r.URL.Path, c.BaseURL+assets.BaseURL) {
|
||||||
|
@ -30,7 +27,7 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request, c *fm.Config) (int, error
|
||||||
}
|
}
|
||||||
|
|
||||||
return http.StatusForbidden, nil
|
return http.StatusForbidden, nil
|
||||||
}
|
} */
|
||||||
|
|
||||||
// Obtains the user.
|
// Obtains the user.
|
||||||
username, _, _ := r.BasicAuth()
|
username, _, _ := r.BasicAuth()
|
||||||
|
@ -91,7 +88,7 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request, c *fm.Config) (int, error
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if preProccessPUT(w, r, c, user) != nil {
|
if c.preProccessPUT(w, r, user) != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +108,7 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request, c *fm.Config) (int, error
|
||||||
// Checks if the User is allowed to access this file
|
// Checks if the User is allowed to access this file
|
||||||
if !user.Allowed(strings.TrimPrefix(r.URL.Path, c.BaseURL)) {
|
if !user.Allowed(strings.TrimPrefix(r.URL.Path, c.BaseURL)) {
|
||||||
if r.Method == http.MethodGet {
|
if r.Method == http.MethodGet {
|
||||||
return page.PrintErrorHTML(
|
return printError(
|
||||||
w, http.StatusForbidden,
|
w, http.StatusForbidden,
|
||||||
errors.New("You don't have permission to access this page"),
|
errors.New("You don't have permission to access this page"),
|
||||||
)
|
)
|
||||||
|
@ -121,20 +118,20 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request, c *fm.Config) (int, error
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.URL.Query().Get("search") != "" {
|
if r.URL.Query().Get("search") != "" {
|
||||||
return search(w, r, c, user)
|
return c.search(w, r, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.URL.Query().Get("command") != "" {
|
if r.URL.Query().Get("command") != "" {
|
||||||
return command(w, r, c, user)
|
return c.command(w, r, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Method == http.MethodGet {
|
if r.Method == http.MethodGet {
|
||||||
// Gets the information of the directory/file
|
// Gets the information of the directory/file
|
||||||
fi, err = fm.GetInfo(r.URL, c, user)
|
fi, err = getFile(r.URL, c, user)
|
||||||
code = errorToHTTPCode(err, false)
|
code = errorToHTTPCode(err, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if r.Method == http.MethodGet {
|
if r.Method == http.MethodGet {
|
||||||
return page.PrintErrorHTML(w, code, err)
|
return printError(w, code, err)
|
||||||
}
|
}
|
||||||
return code, err
|
return code, err
|
||||||
}
|
}
|
||||||
|
@ -148,20 +145,20 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request, c *fm.Config) (int, error
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case r.URL.Query().Get("download") != "":
|
case r.URL.Query().Get("download") != "":
|
||||||
code, err = download(w, r, c, fi)
|
code, err = c.download(w, r, fi)
|
||||||
case r.URL.Query().Get("raw") == "true" && !fi.IsDir:
|
case r.URL.Query().Get("raw") == "true" && !fi.IsDir:
|
||||||
http.ServeFile(w, r, fi.Path)
|
http.ServeFile(w, r, fi.Path)
|
||||||
code, err = 0, nil
|
code, err = 0, nil
|
||||||
case !fi.IsDir && r.URL.Query().Get("checksum") != "":
|
case !fi.IsDir && r.URL.Query().Get("checksum") != "":
|
||||||
code, err = checksum(w, r, c, fi)
|
code, err = c.checksum(w, r, fi)
|
||||||
case fi.IsDir:
|
case fi.IsDir:
|
||||||
code, err = serveListing(w, r, c, user, fi)
|
code, err = c.serveListing(w, r, user, fi)
|
||||||
default:
|
default:
|
||||||
code, err = serveSingle(w, r, c, user, fi)
|
code, err = c.serveSingle(w, r, user, fi)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
code, err = page.PrintErrorHTML(w, code, err)
|
code, err = printError(w, code, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return code, err
|
return code, err
|
||||||
|
@ -169,21 +166,3 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request, c *fm.Config) (int, error
|
||||||
|
|
||||||
return http.StatusNotImplemented, nil
|
return http.StatusNotImplemented, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// errorToHTTPCode converts errors to HTTP Status Code.
|
|
||||||
func errorToHTTPCode(err error, gone bool) int {
|
|
||||||
switch {
|
|
||||||
case os.IsPermission(err):
|
|
||||||
return http.StatusForbidden
|
|
||||||
case os.IsNotExist(err):
|
|
||||||
if !gone {
|
|
||||||
return http.StatusNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
return http.StatusGone
|
|
||||||
case os.IsExist(err):
|
|
||||||
return http.StatusGone
|
|
||||||
default:
|
|
||||||
return http.StatusInternalServerError
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package http
|
package filemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
|
@ -6,17 +6,15 @@ import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
e "errors"
|
"errors"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
fm "github.com/hacdias/filemanager"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// checksum calculates the hash of a filemanager. Supports MD5, SHA1, SHA256 and SHA512.
|
// checksum calculates the hash of a filemanager. Supports MD5, SHA1, SHA256 and SHA512.
|
||||||
func checksum(w http.ResponseWriter, r *http.Request, c *fm.Config, i *fm.FileInfo) (int, error) {
|
func (c *Config) checksum(w http.ResponseWriter, r *http.Request, i *file) (int, error) {
|
||||||
query := r.URL.Query().Get("checksum")
|
query := r.URL.Query().Get("checksum")
|
||||||
|
|
||||||
file, err := os.Open(i.Path)
|
file, err := os.Open(i.Path)
|
||||||
|
@ -38,7 +36,7 @@ func checksum(w http.ResponseWriter, r *http.Request, c *fm.Config, i *fm.FileIn
|
||||||
case "sha512":
|
case "sha512":
|
||||||
h = sha512.New()
|
h = sha512.New()
|
||||||
default:
|
default:
|
||||||
return http.StatusBadRequest, e.New("Unknown HASH type")
|
return http.StatusBadRequest, errors.New("Unknown HASH type")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = io.Copy(h, file)
|
_, err = io.Copy(h, file)
|
|
@ -1,4 +1,4 @@
|
||||||
package http
|
package filemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -9,7 +9,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
fm "github.com/hacdias/filemanager"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var upgrader = websocket.Upgrader{
|
var upgrader = websocket.Upgrader{
|
||||||
|
@ -23,7 +22,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// command handles the requests for VCS related commands: git, svn and mercurial
|
// command handles the requests for VCS related commands: git, svn and mercurial
|
||||||
func command(w http.ResponseWriter, r *http.Request, c *fm.Config, u *fm.User) (int, error) {
|
func (c *Config) command(w http.ResponseWriter, r *http.Request, u *User) (int, error) {
|
||||||
// Upgrades the connection to a websocket and checks for errors.
|
// Upgrades the connection to a websocket and checks for errors.
|
||||||
conn, err := upgrader.Upgrade(w, r, nil)
|
conn, err := upgrader.Upgrade(w, r, nil)
|
||||||
if err != nil {
|
if err != nil {
|
|
@ -1,4 +1,4 @@
|
||||||
package http
|
package filemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
@ -9,13 +9,12 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
fm "github.com/hacdias/filemanager"
|
|
||||||
"github.com/mholt/archiver"
|
"github.com/mholt/archiver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// download creates an archive in one of the supported formats (zip, tar,
|
// download creates an archive in one of the supported formats (zip, tar,
|
||||||
// tar.gz or tar.bz2) and sends it to be downloaded.
|
// tar.gz or tar.bz2) and sends it to be downloaded.
|
||||||
func download(w http.ResponseWriter, r *http.Request, c *fm.Config, i *fm.FileInfo) (int, error) {
|
func (c *Config) download(w http.ResponseWriter, r *http.Request, i *file) (int, error) {
|
||||||
query := r.URL.Query().Get("download")
|
query := r.URL.Query().Get("download")
|
||||||
|
|
||||||
if !i.IsDir {
|
if !i.IsDir {
|
|
@ -1,4 +1,4 @@
|
||||||
package http
|
package filemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -6,17 +6,15 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
fm "github.com/hacdias/filemanager"
|
|
||||||
"github.com/hacdias/filemanager/page"
|
|
||||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// serveListing presents the user with a listage of a directory folder.
|
// serveListing presents the user with a listage of a directory folder.
|
||||||
func serveListing(w http.ResponseWriter, r *http.Request, c *fm.Config, u *fm.User, i *fm.FileInfo) (int, error) {
|
func (c *Config) serveListing(w http.ResponseWriter, r *http.Request, u *User, i *file) (int, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// Loads the content of the directory
|
// Loads the content of the directory
|
||||||
listing, err := fm.GetListing(u, i.VirtualPath, c.PrefixURL+r.URL.Path)
|
listing, err := GetListing(u, i.VirtualPath, c.PrefixURL+r.URL.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorToHTTPCode(err, true), err
|
return errorToHTTPCode(err, true), err
|
||||||
}
|
}
|
||||||
|
@ -79,9 +77,9 @@ func serveListing(w http.ResponseWriter, r *http.Request, c *fm.Config, u *fm.Us
|
||||||
Secure: r.TLS != nil,
|
Secure: r.TLS != nil,
|
||||||
})
|
})
|
||||||
|
|
||||||
page := &page.Page{
|
page := &page{
|
||||||
Minimal: r.Header.Get("Minimal") == "true",
|
Minimal: r.Header.Get("Minimal") == "true",
|
||||||
Info: &page.Info{
|
Info: &pageInfo{
|
||||||
Name: listing.Name,
|
Name: listing.Name,
|
||||||
Path: i.VirtualPath,
|
Path: i.VirtualPath,
|
||||||
IsDir: true,
|
IsDir: true,
|
||||||
|
@ -92,7 +90,7 @@ func serveListing(w http.ResponseWriter, r *http.Request, c *fm.Config, u *fm.Us
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return page.PrintAsHTML(w, "listing")
|
return page.PrintHTML(w, "listing")
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleSortOrder gets and stores for a Listing the 'sort' and 'order',
|
// handleSortOrder gets and stores for a Listing the 'sort' and 'order',
|
|
@ -1,4 +1,4 @@
|
||||||
package http
|
package filemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -10,17 +10,11 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hacdias/filemanager"
|
|
||||||
"github.com/hacdias/filemanager/frontmatter"
|
"github.com/hacdias/filemanager/frontmatter"
|
||||||
)
|
)
|
||||||
|
|
||||||
// preProccessPUT is used to update a file that was edited
|
// preProccessPUT is used to update a file that was edited
|
||||||
func preProccessPUT(
|
func (c *Config) preProccessPUT(w http.ResponseWriter, r *http.Request, u *User) (err error) {
|
||||||
w http.ResponseWriter,
|
|
||||||
r *http.Request,
|
|
||||||
c *filemanager.Config,
|
|
||||||
u *filemanager.User,
|
|
||||||
) (err error) {
|
|
||||||
var (
|
var (
|
||||||
data = map[string]interface{}{}
|
data = map[string]interface{}{}
|
||||||
file []byte
|
file []byte
|
|
@ -1,4 +1,4 @@
|
||||||
package http
|
package filemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -7,7 +7,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
fm "github.com/hacdias/filemanager"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type searchOptions struct {
|
type searchOptions struct {
|
||||||
|
@ -44,7 +43,7 @@ func parseSearch(value string) *searchOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
// search ...
|
// search ...
|
||||||
func search(w http.ResponseWriter, r *http.Request, c *fm.Config, u *fm.User) (int, error) {
|
func (c *Config) search(w http.ResponseWriter, r *http.Request, u *User) (int, error) {
|
||||||
// Upgrades the connection to a websocket and checks for errors.
|
// Upgrades the connection to a websocket and checks for errors.
|
||||||
conn, err := upgrader.Upgrade(w, r, nil)
|
conn, err := upgrader.Upgrade(w, r, nil)
|
||||||
if err != nil {
|
if err != nil {
|
|
@ -1,24 +1,21 @@
|
||||||
package http
|
package filemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
fm "github.com/hacdias/filemanager"
|
|
||||||
"github.com/hacdias/filemanager/page"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// serveSingle serves a single file in an editor (if it is editable), shows the
|
// serveSingle serves a single file in an editor (if it is editable), shows the
|
||||||
// plain file, or downloads it if it can't be shown.
|
// plain file, or downloads it if it can't be shown.
|
||||||
func serveSingle(w http.ResponseWriter, r *http.Request, c *fm.Config, u *fm.User, i *fm.FileInfo) (int, error) {
|
func (c *Config) serveSingle(w http.ResponseWriter, r *http.Request, u *User, i *file) (int, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if err = i.RetrieveFileType(); err != nil {
|
if err = i.RetrieveFileType(); err != nil {
|
||||||
return errorToHTTPCode(err, true), err
|
return errorToHTTPCode(err, true), err
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &page.Page{
|
p := &page{
|
||||||
Info: &page.Info{
|
Info: &pageInfo{
|
||||||
Name: i.Name,
|
Name: i.Name,
|
||||||
Path: i.VirtualPath,
|
Path: i.VirtualPath,
|
||||||
IsDir: false,
|
IsDir: false,
|
||||||
|
@ -30,7 +27,7 @@ func serveSingle(w http.ResponseWriter, r *http.Request, c *fm.Config, u *fm.Use
|
||||||
|
|
||||||
// If the request accepts JSON, we send the file information.
|
// If the request accepts JSON, we send the file information.
|
||||||
if strings.Contains(r.Header.Get("Accept"), "application/json") {
|
if strings.Contains(r.Header.Get("Accept"), "application/json") {
|
||||||
return p.PrintAsJSON(w)
|
return p.PrintJSON(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
if i.Type == "text" {
|
if i.Type == "text" {
|
||||||
|
@ -40,14 +37,14 @@ func serveSingle(w http.ResponseWriter, r *http.Request, c *fm.Config, u *fm.Use
|
||||||
}
|
}
|
||||||
|
|
||||||
if i.CanBeEdited() && u.AllowEdit {
|
if i.CanBeEdited() && u.AllowEdit {
|
||||||
p.Data, err = getEditor(r, i)
|
p.Info.Data, err = newEditor(r, i)
|
||||||
p.Editor = true
|
p.Info.Editor = true
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.PrintAsHTML(w, "frontmatter", "editor")
|
return p.PrintHTML(w, "frontmatter", "editor")
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.PrintAsHTML(w, "single")
|
return p.PrintHTML(w, "single")
|
||||||
}
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package filemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// errorToHTTPCode converts errors to HTTP Status Code.
|
||||||
|
func errorToHTTPCode(err error, gone bool) int {
|
||||||
|
switch {
|
||||||
|
case os.IsPermission(err):
|
||||||
|
return http.StatusForbidden
|
||||||
|
case os.IsNotExist(err):
|
||||||
|
if !gone {
|
||||||
|
return http.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.StatusGone
|
||||||
|
case os.IsExist(err):
|
||||||
|
return http.StatusGone
|
||||||
|
default:
|
||||||
|
return http.StatusInternalServerError
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ type Listing struct {
|
||||||
// The full path of the request relatively to a File System
|
// The full path of the request relatively to a File System
|
||||||
Path string
|
Path string
|
||||||
// The items (files and folders) in the path
|
// The items (files and folders) in the path
|
||||||
Items []FileInfo
|
Items []file
|
||||||
// The number of directories in the listing
|
// The number of directories in the listing
|
||||||
NumDirs int
|
NumDirs int
|
||||||
// The number of files (items that aren't directories) in the listing
|
// The number of files (items that aren't directories) in the listing
|
||||||
|
@ -49,7 +49,7 @@ func GetListing(u *User, filePath string, baseURL string) (*Listing, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
fileinfos []FileInfo
|
fileinfos []*file
|
||||||
dirCount, fileCount int
|
dirCount, fileCount int
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ func GetListing(u *User, filePath string, baseURL string) (*Listing, error) {
|
||||||
// Absolute URL
|
// Absolute URL
|
||||||
url := url.URL{Path: baseURL + name}
|
url := url.URL{Path: baseURL + name}
|
||||||
|
|
||||||
i := FileInfo{
|
i := &file{
|
||||||
Name: f.Name(),
|
Name: f.Name(),
|
||||||
Size: f.Size(),
|
Size: f.Size(),
|
||||||
ModTime: f.ModTime(),
|
ModTime: f.ModTime(),
|
||||||
|
|
|
@ -1,31 +1,29 @@
|
||||||
// Package page is used to render the HTML to the end user
|
package filemanager
|
||||||
package page
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hacdias/filemanager"
|
|
||||||
"github.com/hacdias/filemanager/assets"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Page contains the informations and functions needed to show the Page
|
// page contains the informations and functions needed to show the Page
|
||||||
type Page struct {
|
type page struct {
|
||||||
*Info
|
Info *pageInfo
|
||||||
Minimal bool
|
Minimal bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info contains the information of a Page
|
// pageInfo contains the information of a Page
|
||||||
type Info struct {
|
type pageInfo struct {
|
||||||
Name string
|
Name string
|
||||||
Path string
|
Path string
|
||||||
IsDir bool
|
IsDir bool
|
||||||
User *filemanager.User
|
User *User
|
||||||
Config *filemanager.Config
|
Config *Config
|
||||||
Data interface{}
|
Data interface{}
|
||||||
Editor bool
|
Editor bool
|
||||||
Display string
|
Display string
|
||||||
|
@ -39,7 +37,7 @@ type BreadcrumbMapItem struct {
|
||||||
|
|
||||||
// BreadcrumbMap returns p.Path where every element is a map
|
// BreadcrumbMap returns p.Path where every element is a map
|
||||||
// of URLs and path segment names.
|
// of URLs and path segment names.
|
||||||
func (i Info) BreadcrumbMap() []BreadcrumbMapItem {
|
func (i pageInfo) BreadcrumbMap() []BreadcrumbMapItem {
|
||||||
result := []BreadcrumbMapItem{}
|
result := []BreadcrumbMapItem{}
|
||||||
|
|
||||||
if len(i.Path) == 0 {
|
if len(i.Path) == 0 {
|
||||||
|
@ -76,7 +74,7 @@ func (i Info) BreadcrumbMap() []BreadcrumbMapItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PreviousLink returns the path of the previous folder
|
// PreviousLink returns the path of the previous folder
|
||||||
func (i Info) PreviousLink() string {
|
func (i pageInfo) PreviousLink() string {
|
||||||
path := strings.TrimSuffix(i.Path, "/")
|
path := strings.TrimSuffix(i.Path, "/")
|
||||||
path = strings.TrimPrefix(path, "/")
|
path = strings.TrimPrefix(path, "/")
|
||||||
path = i.Config.AbsoluteURL() + "/" + path
|
path = i.Config.AbsoluteURL() + "/" + path
|
||||||
|
@ -89,8 +87,8 @@ func (i Info) PreviousLink() string {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintAsHTML formats the page in HTML and executes the template
|
// PrintHTML formats the page in HTML and executes the template
|
||||||
func (p Page) PrintAsHTML(w http.ResponseWriter, templates ...string) (int, error) {
|
func (p page) PrintHTML(w http.ResponseWriter, templates ...string) (int, error) {
|
||||||
|
|
||||||
if p.Minimal {
|
if p.Minimal {
|
||||||
templates = append(templates, "minimal")
|
templates = append(templates, "minimal")
|
||||||
|
@ -103,7 +101,8 @@ func (p Page) PrintAsHTML(w http.ResponseWriter, templates ...string) (int, erro
|
||||||
// For each template, add it to the the tpl variable
|
// For each template, add it to the the tpl variable
|
||||||
for i, t := range templates {
|
for i, t := range templates {
|
||||||
// Get the template from the assets
|
// Get the template from the assets
|
||||||
Page, err := assets.Asset("templates/" + t + ".tmpl")
|
//Page, err := assets.Asset("templates/" + t + ".tmpl")
|
||||||
|
Page, err := []byte("Shit"), errors.New("Hello")
|
||||||
|
|
||||||
// Check if there is some error. If so, the template doesn't exist
|
// Check if there is some error. If so, the template doesn't exist
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -137,8 +136,8 @@ func (p Page) PrintAsHTML(w http.ResponseWriter, templates ...string) (int, erro
|
||||||
return http.StatusOK, err
|
return http.StatusOK, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintAsJSON prints the current Page information in JSON
|
// PrintJSON prints the current Page information in JSON
|
||||||
func (p Page) PrintAsJSON(w http.ResponseWriter) (int, error) {
|
func (p page) PrintJSON(w http.ResponseWriter) (int, error) {
|
||||||
marsh, err := json.MarshalIndent(p.Info.Data, "", " ")
|
marsh, err := json.MarshalIndent(p.Info.Data, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
|
@ -151,3 +150,61 @@ func (p Page) PrintAsJSON(w http.ResponseWriter) (int, error) {
|
||||||
|
|
||||||
return http.StatusOK, nil
|
return http.StatusOK, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// printError prints the error page
|
||||||
|
func printError(w http.ResponseWriter, code int, err error) (int, error) {
|
||||||
|
tpl := errorTemplate
|
||||||
|
tpl = strings.Replace(tpl, "TITLE", strconv.Itoa(code)+" "+http.StatusText(code), -1)
|
||||||
|
tpl = strings.Replace(tpl, "CODE", err.Error(), -1)
|
||||||
|
|
||||||
|
_, err = w.Write([]byte(tpl))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusInternalServerError, err
|
||||||
|
}
|
||||||
|
return http.StatusOK, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorTemplate = `<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>TITLE</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
html {
|
||||||
|
background-color: #2196f3;
|
||||||
|
color: #fff;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
background-color: rgba(0,0,0,0.1);
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 1em;
|
||||||
|
display: block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.center {
|
||||||
|
max-width: 40em;
|
||||||
|
margin: 2em auto 0;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #eee;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="center">
|
||||||
|
<h1>TITLE</h1>
|
||||||
|
|
||||||
|
<p>Try reloading the page or hitting the back button. If this error persists, it seems that you may have found a bug! Please create an issue at <a href="https://github.com/hacdias/caddy-filemanager/issues">hacdias/caddy-filemanager</a> repository on GitHub with the code below.</p>
|
||||||
|
|
||||||
|
<code>CODE</code>
|
||||||
|
</div>
|
||||||
|
</html>`
|
|
@ -1,65 +0,0 @@
|
||||||
package page
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const errTemplate = `<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>TITLE</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<style>
|
|
||||||
html {
|
|
||||||
background-color: #2196f3;
|
|
||||||
color: #fff;
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
|
||||||
code {
|
|
||||||
background-color: rgba(0,0,0,0.1);
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 1em;
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
.center {
|
|
||||||
max-width: 40em;
|
|
||||||
margin: 2em auto 0;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #eee;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
line-height: 1.3;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="center">
|
|
||||||
<h1>TITLE</h1>
|
|
||||||
|
|
||||||
<p>Try reloading the page or hitting the back button. If this error persists, it seems that you may have found a bug! Please create an issue at <a href="https://github.com/hacdias/caddy-filemanager/issues">hacdias/caddy-filemanager</a> repository on GitHub with the code below.</p>
|
|
||||||
|
|
||||||
<code>CODE</code>
|
|
||||||
</div>
|
|
||||||
</html>`
|
|
||||||
|
|
||||||
// PrintErrorHTML prints the error page
|
|
||||||
func PrintErrorHTML(w http.ResponseWriter, code int, err error) (int, error) {
|
|
||||||
tpl := errTemplate
|
|
||||||
tpl = strings.Replace(tpl, "TITLE", strconv.Itoa(code)+" "+http.StatusText(code), -1)
|
|
||||||
tpl = strings.Replace(tpl, "CODE", err.Error(), -1)
|
|
||||||
|
|
||||||
_, err = w.Write([]byte(tpl))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return http.StatusInternalServerError, err
|
|
||||||
}
|
|
||||||
return http.StatusOK, nil
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package http
|
package filemanager
|
||||||
|
|
||||||
import "net/http"
|
import "net/http"
|
||||||
|
|
Loading…
Reference in New Issue