view pkg/controllers/json.go @ 904:e4b72a199258

New default bottleneck colors Mainly to make the stroke color one actually selectable in the ui. In addition the pink does better match the collors used on the ECDIS layer.
author Sascha Wilde <wilde@intevation.de>
date Tue, 02 Oct 2018 13:34:59 +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)
		}
	}
}