view pkg/controllers/json.go @ 955:920fba3f593f

chore: upgrading packages to latest
author Thomas Junk <thomas.junk@intevation.de>
date Tue, 16 Oct 2018 11:13:06 +0200
parents 8bb2e48e2dfd
children 7934b5c1a910
line wrap: on
line source

package controllers

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"

	"github.com/jackc/pgx"

	"gemma.intevation.de/gemma/pkg/auth"
)

type JSONResult struct {
	Code   int
	Result interface{}
}

type JSONHandler struct {
	Input  func() interface{}
	Handle func(interface{}, *http.Request, *sql.Conn) (JSONResult, error)
	NoConn bool
}

type JSONError struct {
	Code    int
	Message string
}

func (je JSONError) Error() string {
	return fmt.Sprintf("%d: %s", je.Code, je.Message)
}

func (j *JSONHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

	var input interface{}
	if j.Input != nil {
		input = j.Input()
		defer req.Body.Close()
		if err := json.NewDecoder(req.Body).Decode(input); err != nil {
			http.Error(rw, "error: "+err.Error(), http.StatusBadRequest)
			return
		}
	}

	var jr JSONResult
	var err error

	if token, ok := auth.GetToken(req); ok && !j.NoConn {
		if session := auth.Sessions.Session(token); session != nil {
			err = auth.RunAs(session.User, req.Context(), func(conn *sql.Conn) error {
				jr, err = j.Handle(input, req, conn)
				return err
			})
		} else {
			err = auth.ErrNoSuchToken
		}
	} else {
		jr, err = j.Handle(input, req, nil)
	}

	if err != nil {
		log.Printf("error: %v\n", err)
		switch e := err.(type) {
		case pgx.PgError:
			var res = struct {
				Result  string `json:"result"`
				Code    string `json:"code"`
				Message string `json:"message"`
			}{
				Result:  "failure",
				Code:    e.Code,
				Message: e.Message,
			}
			rw.Header().Set("Content-Type", "application/json")
			rw.WriteHeader(http.StatusInternalServerError)
			if err := json.NewEncoder(rw).Encode(&res); err != nil {
				log.Printf("error: %v\n", err)
			}
		case JSONError:
			rw.Header().Set("Content-Type", "application/json")
			if e.Code == 0 {
				e.Code = http.StatusInternalServerError
			}
			rw.WriteHeader(e.Code)
			var res = struct {
				Message string `json:"message"`
			}{
				Message: e.Message,
			}
			if err := json.NewEncoder(rw).Encode(&res); err != nil {
				log.Printf("error: %v\n", err)
			}
		default:
			http.Error(rw,
				"error: "+err.Error(),
				http.StatusInternalServerError)
		}
		return
	}

	if jr.Code == 0 {
		jr.Code = http.StatusOK
	}

	if jr.Code != http.StatusNoContent {
		rw.Header().Set("Content-Type", "application/json")
	}
	rw.WriteHeader(jr.Code)
	if jr.Code != http.StatusNoContent {
		var err error
		if r, ok := jr.Result.(io.Reader); ok {
			_, err = io.Copy(rw, r)
		} else {
			err = json.NewEncoder(rw).Encode(jr.Result)
		}
		if err != nil {
			log.Printf("error: %v\n", err)
		}
	}
}