package hugo import ( "bytes" "html/template" "io/ioutil" "net/http" "os" "path/filepath" "strings" "github.com/hacdias/caddy-filemanager" "github.com/spf13/hugo/parser" ) type editor struct { Name string Class string IsPost bool Mode string Content string FrontMatter interface{} } // GET handles the GET method on editor page func (h Hugo) GET(w http.ResponseWriter, r *http.Request, filename string) (int, error) { // Check if the file exists. if _, err := os.Stat(filename); os.IsNotExist(err) { return http.StatusNotFound, err } else if os.IsPermission(err) { return http.StatusForbidden, err } else if err != nil { return http.StatusInternalServerError, err } // Open the file and check if there was some error while opening file, err := ioutil.ReadFile(filename) if os.IsPermission(err) { return http.StatusForbidden, err } else if err != nil { return http.StatusInternalServerError, err } page := &filemanager.Page{ Info: &filemanager.PageInfo{ IsDir: false, Config: &h.FileManager.Configs[0], Name: strings.Replace(filename, h.Config.Root, "", 1), }, } // Create a new editor variable and set the extension data := new(editor) data.Mode = strings.TrimPrefix(filepath.Ext(filename), ".") data.Name = strings.Replace(filename, h.Config.Root, "", 1) data.IsPost = false data.Mode = sanitizeMode(data.Mode) var parserPage parser.Page // Handle the content depending on the file extension switch data.Mode { case "markdown", "asciidoc", "rst": if hasFrontMatterRune(file) { // Starts a new buffer and parses the file using Hugo's functions buffer := bytes.NewBuffer(file) parserPage, err = parser.ReadFrom(buffer) if err != nil { return http.StatusInternalServerError, err } if strings.Contains(string(parserPage.FrontMatter()), "date") { data.IsPost = true } // Parses the page content and the frontmatter data.Content = strings.TrimSpace(string(parserPage.Content())) data.FrontMatter, data.Name, err = Pretty(parserPage.FrontMatter()) data.Class = "complete" } else { // The editor will handle only content data.Class = "content-only" data.Content = string(file) } case "json", "toml", "yaml": // Defines the class and declares an error data.Class = "frontmatter-only" // Checks if the file already has the frontmatter rune and parses it if hasFrontMatterRune(file) { data.FrontMatter, _, err = Pretty(file) } else { data.FrontMatter, _, err = Pretty(appendFrontMatterRune(file, data.Mode)) } // Check if there were any errors if err != nil { return http.StatusInternalServerError, err } default: // The editor will handle only content data.Class = "content-only" data.Content = string(file) } // Create the functions map, then the template, check for erros and // execute the template if there aren't errors functions := template.FuncMap{ "SplitCapitalize": SplitCapitalize, "Defined": Defined, } var code int page.Info.Data = data templates := []string{"frontmatter", "editor"} for _, t := range templates { code, err = page.AddTemplate(t, Asset, functions) if err != nil { return code, err } } templates = []string{"actions", "base"} for _, t := range templates { code, err = page.AddTemplate(t, filemanager.Asset, nil) if err != nil { return code, err } } return page.PrintAsHTML(w) } func hasFrontMatterRune(file []byte) bool { return strings.HasPrefix(string(file), "---") || strings.HasPrefix(string(file), "+++") || strings.HasPrefix(string(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 } func sanitizeMode(extension string) string { switch extension { case "md", "markdown", "mdown", "mmark": return "markdown" case "asciidoc", "adoc", "ad": return "asciidoc" case "rst": return "rst" case "html", "htm": return "html" case "js": return "javascript" default: return extension } }