better error pages

This commit is contained in:
Henrique Dias 2016-03-12 13:03:31 +00:00
parent 012cd383a0
commit b57bcb6b0e
13 changed files with 112 additions and 91 deletions

File diff suppressed because one or more lines are too long

View File

@ -186,7 +186,7 @@ $(document).on('page:browse', function() {
if (request.status == 200) {
$.pjax({
url: request.Location,
url: response.location,
container: '#content'
})
}

View File

@ -0,0 +1,8 @@
{{ define "content" }}
<main role="main" class="container browse error">
<h1>{{ .Title }}</h1>
<code>{{ .Message }}</code>
<p><strong>If this error persists contact us on <a href="https://gitter.im/hacdias/caddy-hugo">Gitter chat</a> or open an issue at <a href="https://github.com/hacdias/caddy-hugo/issues/new">GitHub</a>.</strong></p>
</main>
{{ end }}

View File

@ -18,6 +18,7 @@ import (
"github.com/hacdias/caddy-hugo/routes/assets"
"github.com/hacdias/caddy-hugo/routes/browse"
"github.com/hacdias/caddy-hugo/routes/editor"
"github.com/hacdias/caddy-hugo/routes/errors"
"github.com/hacdias/caddy-hugo/routes/git"
"github.com/hacdias/caddy-hugo/tools/commands"
"github.com/hacdias/caddy-hugo/tools/hugo"
@ -143,6 +144,10 @@ func (h CaddyHugo) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
code, err = git.ServeHTTP(w, r, h.Config)
}
if code != 0 && code != 200 {
code, err = errors.ServeHTTP(w, r, code, err)
}
return code, err
}

View File

@ -10,6 +10,11 @@ import (
var conf *config.Config
type response struct {
Message string `json:"message"`
Location string `json:"location"`
}
// ServeHTTP is used to serve the content of Browse page using Browse middleware
// from Caddy. It handles the requests for DELETE, POST, GET and PUT related to
// /browse interface.

View File

@ -5,7 +5,7 @@ import (
"os"
"strings"
"github.com/hacdias/caddy-hugo/tools/server"
s "github.com/hacdias/caddy-hugo/tools/server"
)
// DELETE handles the delete requests on browse pages
@ -31,17 +31,11 @@ func DELETE(w http.ResponseWriter, r *http.Request) (int, error) {
// Check for errors
if err != nil {
return server.RespondJSON(w, map[string]string{
"message": "Something went wrong.",
}, 500, nil)
return s.RespondJSON(w, &response{err.Error(), ""}, http.StatusInternalServerError, err)
}
} else {
return server.RespondJSON(w, map[string]string{
"message": "File not found.",
}, 404, nil)
return s.RespondJSON(w, &response{"File not found.", ""}, http.StatusNotFound, nil)
}
return server.RespondJSON(w, map[string]string{
"message": message,
}, 200, nil)
return s.RespondJSON(w, &response{message, ""}, http.StatusOK, nil)
}

View File

@ -11,7 +11,7 @@ import (
"strings"
"github.com/hacdias/caddy-hugo/tools/commands"
"github.com/hacdias/caddy-hugo/tools/server"
s "github.com/hacdias/caddy-hugo/tools/server"
)
// POST handles the POST method on browse page. It's used to create new files,
@ -36,15 +36,11 @@ func POST(w http.ResponseWriter, r *http.Request) (int, error) {
// Check if filename and archetype are specified in
// the request
if _, ok := info["filename"]; !ok {
return server.RespondJSON(w, map[string]string{
"message": "Filename not specified.",
}, 500, nil)
return s.RespondJSON(w, &response{"Filename not specified.", ""}, http.StatusBadRequest, nil)
}
if _, ok := info["archetype"]; !ok {
return server.RespondJSON(w, map[string]string{
"message": "Archtype not specified.",
}, 500, nil)
return s.RespondJSON(w, &response{"Archtype not specified.", ""}, http.StatusBadRequest, nil)
}
// Sanitize the file name path
@ -66,9 +62,7 @@ func POST(w http.ResponseWriter, r *http.Request) (int, error) {
}
if err := commands.Run(conf.Hugo, args, conf.Path); err != nil {
return server.RespondJSON(w, map[string]string{
"message": "Something went wrong.",
}, 500, err)
return s.RespondJSON(w, &response{"Something went wrong.", ""}, http.StatusInternalServerError, err)
}
} else {
var err error
@ -83,26 +77,19 @@ func POST(w http.ResponseWriter, r *http.Request) (int, error) {
}
if err != nil {
return server.RespondJSON(w, map[string]string{
"message": "Something went wrong.",
}, 500, err)
return s.RespondJSON(w, &response{"Something went wrong.", ""}, http.StatusInternalServerError, err)
}
}
return server.RespondJSON(w, map[string]string{
"location": url,
"message": "File created.",
}, 200, nil)
return s.RespondJSON(w, &response{"File created!", url}, http.StatusOK, nil)
}
func upload(w http.ResponseWriter, r *http.Request) (int, error) {
// Parse the multipart form in the request
err := r.ParseMultipartForm(100000)
if err != nil {
return server.RespondJSON(w, map[string]string{
"message": "Something went wrong.",
}, 500, err)
return s.RespondJSON(w, &response{"Something went wrong.", ""}, http.StatusInternalServerError, err)
}
// For each file header in the multipart form
@ -112,29 +99,23 @@ func upload(w http.ResponseWriter, r *http.Request) (int, error) {
// Open the first file
var infile multipart.File
if infile, err = hdr.Open(); nil != err {
return server.RespondJSON(w, map[string]string{
"message": "Something went wrong.",
}, 500, err)
return s.RespondJSON(w, &response{"Something went wrong.", ""}, http.StatusInternalServerError, err)
}
// Create the file
var outfile *os.File
if outfile, err = os.Create(conf.Path + r.URL.Path + hdr.Filename); nil != err {
return server.RespondJSON(w, map[string]string{
"message": "Something went wrong.",
}, 500, err)
return s.RespondJSON(w, &response{"Something went wrong.", ""}, http.StatusInternalServerError, err)
}
// Copy the file content
if _, err = io.Copy(outfile, infile); nil != err {
return server.RespondJSON(w, map[string]string{
"message": "Something went wrong.",
}, 500, err)
return s.RespondJSON(w, &response{"Something went wrong.", ""}, http.StatusInternalServerError, err)
}
defer outfile.Close()
}
}
return server.RespondJSON(w, nil, 200, nil)
return s.RespondJSON(w, nil, http.StatusOK, nil)
}

View File

@ -30,9 +30,7 @@ func PUT(w http.ResponseWriter, r *http.Request) (int, error) {
// Check if filename and archetype are specified in
// the request
if _, ok := info["filename"]; !ok {
return server.RespondJSON(w, map[string]string{
"message": "Filename not specified.",
}, 400, nil)
return server.RespondJSON(w, &response{"Filename not specified.", ""}, http.StatusBadRequest, nil)
}
// Sanitize the file name path
@ -43,12 +41,8 @@ func PUT(w http.ResponseWriter, r *http.Request) (int, error) {
// Renames the file/folder
if err := os.Rename(old, new); err != nil {
return server.RespondJSON(w, map[string]string{
"message": "Something went wrong.",
}, 500, err)
return server.RespondJSON(w, &response{err.Error(), ""}, http.StatusInternalServerError, err)
}
return server.RespondJSON(w, map[string]string{
"message": "File renamed.",
}, 200, nil)
return server.RespondJSON(w, &response{"File renamed.", ""}, http.StatusOK, nil)
}

View File

@ -37,9 +37,9 @@ func GET(w http.ResponseWriter, r *http.Request) (int, error) {
// Check if the file exists.
if _, err := os.Stat(filename); os.IsNotExist(err) {
return http.StatusNotFound, nil
return http.StatusNotFound, err
} else if os.IsPermission(err) {
return http.StatusForbidden, nil
return http.StatusForbidden, err
} else if err != nil {
return http.StatusInternalServerError, err
}
@ -47,7 +47,7 @@ func GET(w http.ResponseWriter, r *http.Request) (int, error) {
// Open the file and check if there was some error while opening
file, err := ioutil.ReadFile(filename)
if os.IsPermission(err) {
return http.StatusForbidden, nil
return http.StatusForbidden, err
} else if err != nil {
return http.StatusInternalServerError, err
}

View File

@ -26,6 +26,10 @@ type info struct {
Content map[string]interface{}
}
type response struct {
Message string `json:"message"`
}
// POST handles the POST method on editor page
func POST(w http.ResponseWriter, r *http.Request) (int, error) {
// Get the JSON information sent using a buffer
@ -34,9 +38,7 @@ func POST(w http.ResponseWriter, r *http.Request) (int, error) {
err := json.Unmarshal(rawBuffer.Bytes(), &data)
if err != nil {
return server.RespondJSON(w, map[string]string{
"message": "Error decrypting json.",
}, http.StatusInternalServerError, err)
return server.RespondJSON(w, &response{"Error decrypting json."}, http.StatusInternalServerError, err)
}
// Initializes the file content to write
@ -46,9 +48,7 @@ func POST(w http.ResponseWriter, r *http.Request) (int, error) {
case "frontmatter-only":
f, code, err := parseFrontMatterOnlyFile()
if err != nil {
return server.RespondJSON(w, map[string]string{
"message": err.Error(),
}, code, err)
return server.RespondJSON(w, &response{err.Error()}, code, err)
}
file = f
@ -61,25 +61,19 @@ func POST(w http.ResponseWriter, r *http.Request) (int, error) {
case "complete":
f, code, err := parseCompleteFile()
if err != nil {
return server.RespondJSON(w, map[string]string{
"message": err.Error(),
}, code, err)
return server.RespondJSON(w, &response{err.Error()}, code, err)
}
file = f
default:
return server.RespondJSON(w, map[string]string{
"message": "Invalid content type.",
}, http.StatusBadRequest, nil)
return server.RespondJSON(w, &response{"Invalid content type."}, http.StatusBadRequest, nil)
}
// Write the file
err = ioutil.WriteFile(filename, file, 0666)
if err != nil {
return server.RespondJSON(w, map[string]string{
"message": err.Error(),
}, http.StatusInternalServerError, err)
return server.RespondJSON(w, &response{err.Error()}, http.StatusInternalServerError, err)
}
if data.Regenerate {

51
routes/errors/errors.go Normal file
View File

@ -0,0 +1,51 @@
package errors
import (
"net/http"
"strconv"
"text/template"
"github.com/hacdias/caddy-hugo/tools/server"
"github.com/hacdias/caddy-hugo/tools/templates"
"github.com/hacdias/caddy-hugo/tools/variables"
)
type errorInformation struct {
Title string `json:"title"`
Message string `json:"message"`
err error
}
// ServeHTTP is used to serve the content of GIT API.
func ServeHTTP(w http.ResponseWriter, r *http.Request, code int, err error) (int, error) {
page := new(errorInformation)
page.Title = strconv.Itoa(code) + " " + http.StatusText(code)
page.err = err
if err != nil {
page.Message = err.Error()
}
switch r.Method {
case "GET":
functions := template.FuncMap{
"Defined": variables.Defined,
}
tpl, err := templates.Get(r, functions, "error")
if err != nil {
return http.StatusInternalServerError, err
}
err = tpl.Execute(w, page)
if err != nil {
return http.StatusInternalServerError, err
}
return 0, page.err
default:
return server.RespondJSON(w, page, code, err)
}
}

View File

@ -7,16 +7,18 @@ import (
"os/exec"
"strings"
"github.com/hacdias/caddy-hugo/tools/server"
s "github.com/hacdias/caddy-hugo/tools/server"
)
type postError struct {
Message string `json:"message"`
}
// POST handles the POST method on GIT page which is only an API.
func POST(w http.ResponseWriter, r *http.Request) (int, error) {
// Check if git is installed on the computer
if _, err := exec.LookPath("git"); err != nil {
return server.RespondJSON(w, map[string]string{
"message": "Git is not installed on your computer.",
}, 400, nil)
return s.RespondJSON(w, &postError{"Git is not installed on your computer."}, 400, nil)
}
// Get the JSON information sent using a buffer
@ -29,9 +31,7 @@ func POST(w http.ResponseWriter, r *http.Request) (int, error) {
// Check if command was sent
if _, ok := info["command"]; !ok {
return server.RespondJSON(w, map[string]string{
"message": "Command not specified.",
}, 400, nil)
return s.RespondJSON(w, &postError{"Command not specified."}, 400, nil)
}
command := info["command"].(string)
@ -42,9 +42,7 @@ func POST(w http.ResponseWriter, r *http.Request) (int, error) {
}
if len(args) == 0 {
return server.RespondJSON(w, map[string]string{
"message": "Command not specified.",
}, 400, nil)
return s.RespondJSON(w, &postError{"Command not specified."}, 400, nil)
}
cmd := exec.Command("git", args...)
@ -52,12 +50,8 @@ func POST(w http.ResponseWriter, r *http.Request) (int, error) {
output, err := cmd.CombinedOutput()
if err != nil {
return server.RespondJSON(w, map[string]string{
"message": err.Error(),
}, 500, err)
return s.RespondJSON(w, &postError{err.Error()}, 500, err)
}
return server.RespondJSON(w, map[string]string{
"message": string(output),
}, 200, nil)
return s.RespondJSON(w, &postError{string(output)}, 200, nil)
}

View File

@ -2,12 +2,11 @@ package server
import (
"encoding/json"
"errors"
"net/http"
)
// RespondJSON used to send JSON responses to the web server
func RespondJSON(w http.ResponseWriter, message map[string]string, code int, err error) (int, error) {
func RespondJSON(w http.ResponseWriter, message interface{}, code int, err error) (int, error) {
if message == nil {
message = map[string]string{}
}
@ -18,10 +17,6 @@ func RespondJSON(w http.ResponseWriter, message map[string]string, code int, err
return 500, msgErr
}
if code == 500 && err != nil {
err = errors.New(message["message"])
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
w.Write(msg)