Improvements
This commit is contained in:
		
							parent
							
								
									f2fbe92591
								
							
						
					
					
						commit
						fe7579966d
					
				|  | @ -1,4 +1,4 @@ | |||
| package filemanager | ||||
| package file | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
|  | @ -18,7 +18,7 @@ type Editor struct { | |||
| } | ||||
| 
 | ||||
| // GetEditor gets the editor based on a FileInfo struct
 | ||||
| func (i *FileInfo) GetEditor() (*Editor, error) { | ||||
| func (i *Info) GetEditor() (*Editor, error) { | ||||
| 	// Create a new editor variable and set the mode
 | ||||
| 	editor := new(Editor) | ||||
| 	editor.Mode = strings.TrimPrefix(filepath.Ext(i.Name()), ".") | ||||
|  | @ -41,44 +41,39 @@ func (i *FileInfo) GetEditor() (*Editor, error) { | |||
| 
 | ||||
| 	// Handle the content depending on the file extension
 | ||||
| 	switch editor.Mode { | ||||
| 	case "markdown", "asciidoc", "rst": | ||||
| 		if !hasFrontMatterRune(i.Content) { | ||||
| 			editor.Class = "content-only" | ||||
| 			editor.Content = i.StringifyContent() | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		// Starts a new buffer and parses the file using Hugo's functions
 | ||||
| 		buffer := bytes.NewBuffer(i.Content) | ||||
| 		page, err = parser.ReadFrom(buffer) | ||||
| 		editor.Class = "complete" | ||||
| 
 | ||||
| 		if err != nil { | ||||
| 			editor.Class = "content-only" | ||||
| 			editor.Content = i.StringifyContent() | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		// Parses the page content and the frontmatter
 | ||||
| 		editor.Content = strings.TrimSpace(string(page.Content())) | ||||
| 		editor.FrontMatter, _, err = frontmatter.Pretty(page.FrontMatter()) | ||||
| 	case "json", "toml", "yaml": | ||||
| 		// Defines the class and declares an error
 | ||||
| 		editor.Class = "frontmatter-only" | ||||
| 
 | ||||
| 		// Checks if the file already has the frontmatter rune and parses it
 | ||||
| 		if hasFrontMatterRune(i.Content) { | ||||
| 		if frontmatter.HasRune(i.Content) { | ||||
| 			editor.FrontMatter, _, err = frontmatter.Pretty(i.Content) | ||||
| 		} else { | ||||
| 			editor.FrontMatter, _, err = frontmatter.Pretty(appendFrontMatterRune(i.Content, editor.Mode)) | ||||
| 			editor.FrontMatter, _, err = frontmatter.Pretty(frontmatter.AppendRune(i.Content, editor.Mode)) | ||||
| 		} | ||||
| 
 | ||||
| 		// Check if there were any errors
 | ||||
| 		if err != nil { | ||||
| 			editor.Class = "content-only" | ||||
| 			editor.Content = i.StringifyContent() | ||||
| 		if err == nil { | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		fallthrough | ||||
| 	case "markdown", "asciidoc", "rst": | ||||
| 		if frontmatter.HasRune(i.Content) { | ||||
| 			// Starts a new buffer and parses the file using Hugo's functions
 | ||||
| 			buffer := bytes.NewBuffer(i.Content) | ||||
| 			page, err = parser.ReadFrom(buffer) | ||||
| 			editor.Class = "complete" | ||||
| 
 | ||||
| 			if err == nil { | ||||
| 				// Parses the page content and the frontmatter
 | ||||
| 				editor.Content = strings.TrimSpace(string(page.Content())) | ||||
| 				editor.FrontMatter, _, err = frontmatter.Pretty(page.FrontMatter()) | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		fallthrough | ||||
| 	default: | ||||
| 		editor.Class = "content-only" | ||||
| 		editor.Content = i.StringifyContent() | ||||
|  | @ -87,29 +82,12 @@ func (i *FileInfo) GetEditor() (*Editor, error) { | |||
| 	return editor, nil | ||||
| } | ||||
| 
 | ||||
| // hasFrontMatterRune checks if the file has the frontmatter rune
 | ||||
| func hasFrontMatterRune(file []byte) bool { | ||||
| 	return strings.HasPrefix(string(file), "---") || | ||||
| 		strings.HasPrefix(string(file), "+++") || | ||||
| 		strings.HasPrefix(string(file), "{") | ||||
| // CanBeEdited checks if the extension of a file is supported by the editor
 | ||||
| func (i Info) CanBeEdited() bool { | ||||
| 	if i.Type == "text" { | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| // appendFrontMatterRune appends the frontmatter rune to a file
 | ||||
| func appendFrontMatterRune(frontmatter []byte, language string) []byte { | ||||
| 	switch language { | ||||
| 	case "yaml": | ||||
| 		return []byte("---\n" + string(frontmatter) + "\n---") | ||||
| 	case "toml": | ||||
| 		return []byte("+++\n" + string(frontmatter) + "\n+++") | ||||
| 	case "json": | ||||
| 		return frontmatter | ||||
| 	} | ||||
| 
 | ||||
| 	return frontmatter | ||||
| } | ||||
| 
 | ||||
| // canBeEdited checks if the extension of a file is supported by the editor
 | ||||
| func canBeEdited(filename string) bool { | ||||
| 	extensions := [...]string{ | ||||
| 		"md", "markdown", "mdown", "mmark", | ||||
| 		"asciidoc", "adoc", "ad", | ||||
|  | @ -122,7 +100,7 @@ func canBeEdited(filename string) bool { | |||
| 	} | ||||
| 
 | ||||
| 	for _, extension := range extensions { | ||||
| 		if strings.HasSuffix(filename, extension) { | ||||
| 		if strings.HasSuffix(i.Name(), extension) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | @ -1,4 +1,4 @@ | |||
| package filemanager | ||||
| package file | ||||
| 
 | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
|  | @ -11,10 +11,11 @@ import ( | |||
| 	humanize "github.com/dustin/go-humanize" | ||||
| 	"github.com/hacdias/caddy-filemanager/config" | ||||
| 	"github.com/hacdias/caddy-filemanager/page" | ||||
| 	"github.com/hacdias/caddy-filemanager/utils" | ||||
| ) | ||||
| 
 | ||||
| // FileInfo contains the information about a particular file or directory
 | ||||
| type FileInfo struct { | ||||
| // Info contains the information about a particular file or directory
 | ||||
| type Info struct { | ||||
| 	os.FileInfo | ||||
| 	URL         string | ||||
| 	Path        string // Relative path to Caddyfile
 | ||||
|  | @ -27,10 +28,10 @@ type FileInfo struct { | |||
| 
 | ||||
| // GetInfo gets the file information and, in case of error, returns the
 | ||||
| // respective HTTP error code
 | ||||
| func GetInfo(url *url.URL, c *config.Config, u *config.User) (*FileInfo, int, error) { | ||||
| func GetInfo(url *url.URL, c *config.Config, u *config.User) (*Info, int, error) { | ||||
| 	var err error | ||||
| 
 | ||||
| 	i := &FileInfo{URL: url.Path} | ||||
| 	i := &Info{URL: url.Path} | ||||
| 	i.VirtualPath = strings.Replace(url.Path, c.BaseURL, "", 1) | ||||
| 	i.VirtualPath = strings.TrimPrefix(i.VirtualPath, "/") | ||||
| 	i.VirtualPath = "/" + i.VirtualPath | ||||
|  | @ -41,50 +42,40 @@ func GetInfo(url *url.URL, c *config.Config, u *config.User) (*FileInfo, int, er | |||
| 
 | ||||
| 	i.FileInfo, err = os.Stat(i.Path) | ||||
| 	if err != nil { | ||||
| 		code := http.StatusInternalServerError | ||||
| 
 | ||||
| 		switch { | ||||
| 		case os.IsPermission(err): | ||||
| 			code = http.StatusForbidden | ||||
| 		case os.IsNotExist(err): | ||||
| 			code = http.StatusGone | ||||
| 		case os.IsExist(err): | ||||
| 			code = http.StatusGone | ||||
| 		} | ||||
| 
 | ||||
| 		return i, code, err | ||||
| 		return i, utils.ErrorToHTTPCode(err, false), err | ||||
| 	} | ||||
| 
 | ||||
| 	return i, 0, nil | ||||
| } | ||||
| 
 | ||||
| func (i *FileInfo) Read() error { | ||||
| func (i *Info) Read() error { | ||||
| 	var err error | ||||
| 	i.Content, err = ioutil.ReadFile(i.Path) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	i.Mimetype = http.DetectContentType(i.Content) | ||||
| 	i.Type = SimplifyMimeType(i.Mimetype) | ||||
| 	i.Type = simplifyMediaType(i.Mimetype) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (i FileInfo) StringifyContent() string { | ||||
| // StringifyContent returns the string version of Raw
 | ||||
| func (i Info) StringifyContent() string { | ||||
| 	return string(i.Content) | ||||
| } | ||||
| 
 | ||||
| // HumanSize returns the size of the file as a human-readable string
 | ||||
| // in IEC format (i.e. power of 2 or base 1024).
 | ||||
| func (i FileInfo) HumanSize() string { | ||||
| func (i Info) HumanSize() string { | ||||
| 	return humanize.IBytes(uint64(i.Size())) | ||||
| } | ||||
| 
 | ||||
| // HumanModTime returns the modified time of the file as a human-readable string.
 | ||||
| func (i FileInfo) HumanModTime(format string) string { | ||||
| func (i Info) HumanModTime(format string) string { | ||||
| 	return i.ModTime().Format(format) | ||||
| } | ||||
| 
 | ||||
| func (i *FileInfo) ServeHTTP(w http.ResponseWriter, r *http.Request, c *config.Config, u *config.User) (int, error) { | ||||
| func (i *Info) ServeHTTP(w http.ResponseWriter, r *http.Request, c *config.Config, u *config.User) (int, error) { | ||||
| 	if i.IsDir() { | ||||
| 		return i.serveListing(w, r, c, u) | ||||
| 	} | ||||
|  | @ -92,7 +83,7 @@ func (i *FileInfo) ServeHTTP(w http.ResponseWriter, r *http.Request, c *config.C | |||
| 	return i.serveSingleFile(w, r, c, u) | ||||
| } | ||||
| 
 | ||||
| func (i *FileInfo) serveSingleFile(w http.ResponseWriter, r *http.Request, c *config.Config, u *config.User) (int, error) { | ||||
| func (i *Info) serveSingleFile(w http.ResponseWriter, r *http.Request, c *config.Config, u *config.User) (int, error) { | ||||
| 	err := i.Read() | ||||
| 	if err != nil { | ||||
| 		code := http.StatusInternalServerError | ||||
|  | @ -129,7 +120,7 @@ func (i *FileInfo) serveSingleFile(w http.ResponseWriter, r *http.Request, c *co | |||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	if (canBeEdited(i.Name()) || i.Type == "text") && u.AllowEdit { | ||||
| 	if i.CanBeEdited() && u.AllowEdit { | ||||
| 		p.Data, err = i.GetEditor() | ||||
| 		if err != nil { | ||||
| 			return http.StatusInternalServerError, err | ||||
|  | @ -141,7 +132,7 @@ func (i *FileInfo) serveSingleFile(w http.ResponseWriter, r *http.Request, c *co | |||
| 	return p.PrintAsHTML(w, "single") | ||||
| } | ||||
| 
 | ||||
| func SimplifyMimeType(name string) string { | ||||
| func simplifyMediaType(name string) string { | ||||
| 	if strings.HasPrefix(name, "video") { | ||||
| 		return "video" | ||||
| 	} | ||||
|  | @ -1,4 +1,4 @@ | |||
| package filemanager | ||||
| package file | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
|  | @ -25,7 +25,7 @@ type Listing struct { | |||
| 	// The full path of the request
 | ||||
| 	Path string | ||||
| 	// The items (files and folders) in the path
 | ||||
| 	Items []FileInfo | ||||
| 	Items []Info | ||||
| 	// The number of directories in the listing
 | ||||
| 	NumDirs int | ||||
| 	// The number of files (items that aren't directories) in the listing
 | ||||
|  | @ -149,7 +149,7 @@ func (l Listing) applySort() { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (i *FileInfo) serveListing(w http.ResponseWriter, r *http.Request, c *config.Config, u *config.User) (int, error) { | ||||
| func (i *Info) serveListing(w http.ResponseWriter, r *http.Request, c *config.Config, u *config.User) (int, error) { | ||||
| 	var err error | ||||
| 
 | ||||
| 	file, err := u.FileSystem.OpenFile(i.VirtualPath, os.O_RDONLY, 0) | ||||
|  | @ -223,7 +223,7 @@ func (i *FileInfo) serveListing(w http.ResponseWriter, r *http.Request, c *confi | |||
| 	return page.PrintAsHTML(w, "listing") | ||||
| } | ||||
| 
 | ||||
| func (i FileInfo) loadDirectoryContents(file http.File, path string, u *config.User) (*Listing, error) { | ||||
| func (i Info) loadDirectoryContents(file http.File, path string, u *config.User) (*Listing, error) { | ||||
| 	files, err := file.Readdir(-1) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
|  | @ -235,7 +235,7 @@ func (i FileInfo) loadDirectoryContents(file http.File, path string, u *config.U | |||
| 
 | ||||
| func directoryListing(files []os.FileInfo, urlPath string, basePath string, u *config.User) Listing { | ||||
| 	var ( | ||||
| 		fileinfos           []FileInfo | ||||
| 		fileinfos           []Info | ||||
| 		dirCount, fileCount int | ||||
| 	) | ||||
| 
 | ||||
|  | @ -251,7 +251,7 @@ func directoryListing(files []os.FileInfo, urlPath string, basePath string, u *c | |||
| 
 | ||||
| 		// Absolute URL
 | ||||
| 		url := url.URL{Path: basePath + name} | ||||
| 		fileinfos = append(fileinfos, FileInfo{ | ||||
| 		fileinfos = append(fileinfos, Info{ | ||||
| 			FileInfo:    f, | ||||
| 			URL:         url.String(), | ||||
| 			UserAllowed: u.Allowed(url.String()), | ||||
|  | @ -16,7 +16,7 @@ import ( | |||
| 
 | ||||
| 	"github.com/hacdias/caddy-filemanager/assets" | ||||
| 	"github.com/hacdias/caddy-filemanager/config" | ||||
| 	"github.com/hacdias/caddy-filemanager/errors" | ||||
| 	"github.com/hacdias/caddy-filemanager/file" | ||||
| 	"github.com/hacdias/caddy-filemanager/page" | ||||
| 	"github.com/mholt/caddy/caddyhttp/httpserver" | ||||
| ) | ||||
|  | @ -32,7 +32,7 @@ type FileManager struct { | |||
| func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { | ||||
| 	var ( | ||||
| 		c    *config.Config | ||||
| 		fi   *FileInfo | ||||
| 		fi   *file.Info | ||||
| 		code int | ||||
| 		err  error | ||||
| 		user *config.User | ||||
|  | @ -71,7 +71,7 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err | |||
| 				} | ||||
| 
 | ||||
| 				if r.Method == http.MethodPut { | ||||
| 					_, err = fi.Update(w, r, c, user) | ||||
| 					_, err = processPUT(w, r, c, user, fi) | ||||
| 					if err != nil { | ||||
| 						return http.StatusInternalServerError, err | ||||
| 					} | ||||
|  | @ -83,7 +83,7 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err | |||
| 
 | ||||
| 			if !user.Allowed(strings.TrimPrefix(r.URL.Path, c.BaseURL)) { | ||||
| 				if r.Method == http.MethodGet { | ||||
| 					return errors.PrintHTML( | ||||
| 					return page.PrintErrorHTML( | ||||
| 						w, | ||||
| 						http.StatusForbidden, | ||||
| 						e.New("You don't have permission to access this page."), | ||||
|  | @ -95,10 +95,10 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err | |||
| 
 | ||||
| 			if r.Method == http.MethodGet { | ||||
| 				// Gets the information of the directory/file
 | ||||
| 				fi, code, err = GetInfo(r.URL, c, user) | ||||
| 				fi, code, err = file.GetInfo(r.URL, c, user) | ||||
| 				if err != nil { | ||||
| 					if r.Method == http.MethodGet { | ||||
| 						return errors.PrintHTML(w, code, err) | ||||
| 						return page.PrintErrorHTML(w, code, err) | ||||
| 					} | ||||
| 					return code, err | ||||
| 				} | ||||
|  | @ -131,7 +131,7 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err | |||
| 
 | ||||
| 				code, err := fi.ServeHTTP(w, r, c, user) | ||||
| 				if err != nil { | ||||
| 					return errors.PrintHTML(w, code, err) | ||||
| 					return page.PrintErrorHTML(w, code, err) | ||||
| 				} | ||||
| 				return code, err | ||||
| 			} | ||||
|  |  | |||
|  | @ -0,0 +1,24 @@ | |||
| package frontmatter | ||||
| 
 | ||||
| import "strings" | ||||
| 
 | ||||
| // HasRune checks if the file has the frontmatter rune
 | ||||
| func HasRune(file []byte) bool { | ||||
| 	return strings.HasPrefix(string(file), "---") || | ||||
| 		strings.HasPrefix(string(file), "+++") || | ||||
| 		strings.HasPrefix(string(file), "{") | ||||
| } | ||||
| 
 | ||||
| // AppendRune appends the frontmatter rune to a file
 | ||||
| func AppendRune(frontmatter []byte, language string) []byte { | ||||
| 	switch language { | ||||
| 	case "yaml": | ||||
| 		return []byte("---\n" + string(frontmatter) + "\n---") | ||||
| 	case "toml": | ||||
| 		return []byte("+++\n" + string(frontmatter) + "\n+++") | ||||
| 	case "json": | ||||
| 		return frontmatter | ||||
| 	} | ||||
| 
 | ||||
| 	return frontmatter | ||||
| } | ||||
|  | @ -1,4 +1,4 @@ | |||
| package errors | ||||
| package page | ||||
| 
 | ||||
| import ( | ||||
| 	"net/http" | ||||
|  | @ -6,7 +6,7 @@ import ( | |||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| const template = `<!DOCTYPE html> | ||||
| const errTemplate = `<!DOCTYPE html> | ||||
| <html> | ||||
| <head> | ||||
|     <title>TITLE</title> | ||||
|  | @ -48,9 +48,9 @@ const template = `<!DOCTYPE html> | |||
|     </div> | ||||
| </html>` | ||||
| 
 | ||||
| // PrintHTML prints the error page
 | ||||
| func PrintHTML(w http.ResponseWriter, code int, err error) (int, error) { | ||||
| 	tpl := template | ||||
| // 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) | ||||
| 
 | ||||
|  | @ -11,11 +11,12 @@ import ( | |||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/hacdias/caddy-filemanager/config" | ||||
| 	"github.com/hacdias/caddy-filemanager/file" | ||||
| 	"github.com/spf13/hugo/parser" | ||||
| ) | ||||
| 
 | ||||
| // Update is used to update a file that was edited
 | ||||
| func (i *FileInfo) Update(w http.ResponseWriter, r *http.Request, c *config.Config, u *config.User) (int, error) { | ||||
| // processPUT is used to update a file that was edited
 | ||||
| func processPUT(w http.ResponseWriter, r *http.Request, c *config.Config, u *config.User, i *file.Info) (int, error) { | ||||
| 	var ( | ||||
| 		data      map[string]interface{} | ||||
| 		file      []byte | ||||
		Loading…
	
		Reference in New Issue