...
 
Commits (3)
......@@ -6,7 +6,6 @@ import (
"dmpapi/params"
"fmt"
"github.com/gorilla/mux"
"log"
"net/http"
)
......@@ -20,12 +19,6 @@ func (e AppError) Error() string {
return fmt.Sprintf("%s (%s)", e.message, e.error.Error())
}
func (err AppError) Handle(w http.ResponseWriter) {
// http.Error(w, err.Error(), err.Code)
http.Error(w, "", err.code)
writeErrorResponse(w, err)
}
func NewError(err error, msg string, status int) AppError {
return AppError{
error: err,
......@@ -46,20 +39,20 @@ func (app *App) GetWrapper(getter dataGetter) http.HandlerFunc {
qParams, err := params.PrepParams(r.URL.Query())
if err != nil {
NewError(err, "invalid query parameters", http.StatusBadRequest).Handle(w)
writeErrorResponse(w, NewError(err, "invalid query parameters", http.StatusBadRequest))
return
}
username, password, _ := r.BasicAuth()
userCtx, err := app.Authenticate(username, password)
if err != nil {
NewError(err, "Failed to connect", http.StatusUnauthorized).Handle(w)
writeErrorResponse(w, NewError(err, "Failed to connect", http.StatusUnauthorized))
return
}
data, err := getter(userCtx, mux.Vars(r), qParams)
if err != nil {
NewError(err, "Failed to retrieve data", http.StatusInternalServerError).Handle(w)
writeErrorResponse(w, NewError(err, "Failed to retrieve data", http.StatusInternalServerError))
return
}
......@@ -75,29 +68,27 @@ func PutWrapper(app *App, decoder dataDecoder, putter dataPutter) http.HandlerFu
qParams, err := params.PrepParams(r.URL.Query())
if err != nil {
NewError(err, "invalid query parameters", http.StatusBadRequest).Handle(w)
writeErrorResponse(w, NewError(err, "invalid query parameters", http.StatusBadRequest))
return
}
username, password, _ := r.BasicAuth()
userCtx, err := app.Authenticate(username, password)
if err != nil {
NewError(err, "Failed to connect", http.StatusUnauthorized).Handle(w)
writeErrorResponse(w, NewError(err, "Failed to connect", http.StatusUnauthorized))
return
}
data, err := decoder(w, r)
if err != nil {
NewError(err, "Failed to decode payload", http.StatusBadRequest).Handle(w)
writeErrorResponse(w, NewError(err, "Failed to decode payload", http.StatusBadRequest))
return
}
log.Println("PutWrapper: ", data)
if err := putter(userCtx, mux.Vars(r), qParams, data); err != nil {
NewError(err, "Failed to put data", http.StatusInternalServerError).Handle(w)
writeErrorResponse(w, NewError(err, "Failed to put data", http.StatusInternalServerError))
return
}
// TODO: writePutResponse
writePutResponse(w)
}
}
......@@ -3,14 +3,15 @@ package db
import (
"bytes"
"context"
"encoding/csv"
"encoding/json"
"fmt"
"log"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"reflect"
"strconv"
"strings"
)
var (
......@@ -19,6 +20,7 @@ var (
"DOUBTFUL": true,
"BAD": true,
}
CAUSES = map[string]bool{
"": true,
"BATTERY_LOW": true,
......@@ -49,7 +51,7 @@ func getTags(strct interface{}, name string) []string {
}
type Encodabler interface {
Encode() (*bytes.Buffer, error)
String() string
}
type DataFlags []struct {
......@@ -59,24 +61,57 @@ type DataFlags []struct {
Comment string `json:"quality_comment"`
}
func (t DataFlags) Encode() (*bytes.Buffer, error) {
file := &bytes.Buffer{}
writer := csv.NewWriter(file)
func (t DataFlags) String() string {
rows := make([]string, len(t)+1)
rows[0] = strings.Join(getTags(t[0], "json"), ", ")
for i, row := range t {
converted := []string{strconv.Itoa(row.ID), row.Flag, row.Cause, row.Comment}
rows[i+1] = strings.Join(converted, ", ")
}
return strings.Join(rows, "\n")
}
func makeRequest(req *http.Request) error {
if err := writer.Write(getTags(t[0], "json")); err != nil {
log.Fatal(err)
return nil, err
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return err
}
for _, row := range t {
converted := []string{strconv.Itoa(row.ID), row.Flag, row.Cause, row.Comment}
if err := writer.Write(converted); err != nil {
log.Fatal(err)
return nil, err
defer res.Body.Close()
if res.StatusCode < 200 || res.StatusCode > 299 {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
return fmt.Errorf("Upload failed with code %v: %v", res.StatusCode, string(body))
}
return nil
}
func postFileRequest(u *url.URL, content []byte) (*http.Request, error) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("file", "file")
if err != nil {
return nil, err
}
writer.Flush()
return file, nil
if _, err := part.Write(content); err != nil {
return nil, err
}
if writer.Close() != nil {
return nil, err
}
req, err := http.NewRequest("POST", u.String(), body)
if err != nil {
return nil, err
}
req.Header.Add("Content-Type", writer.FormDataContentType())
return req, nil
}
func (db *DBOracle) PutLoggerFlags(userCtx context.Context, pParams map[string]string, qParams map[string]string, data Encodabler) error {
......@@ -91,19 +126,24 @@ func (db *DBOracle) PutLoggerFlags(userCtx context.Context, pParams map[string]s
return fmt.Errorf("No DEVICE_ID found for logger id: %s", pParams["id"])
}
file, err := data.Encode()
uploadURL, _ := url.Parse(LEVEL2A_URL + deviceID)
content := data.String()
req, err := postFileRequest(uploadURL, []byte(content))
if err != nil {
return err
}
log.Println(file)
uploadURL, _ := url.Parse(LEVEL2A_URL + deviceID)
log.Println(uploadURL)
if err := makeRequest(req); err != nil {
return err
}
return nil
}
func DecodeDataFlags(w http.ResponseWriter, r *http.Request) (Encodabler, error) {
// TODO: add consistency checks
// r.Body = http.MaxBytesReader(w, r.Body, 10<<20)
r.Body = http.MaxBytesReader(w, r.Body, 10<<20)
dec := json.NewDecoder(r.Body)
......@@ -125,20 +165,21 @@ func DecodeDataFlags(w http.ResponseWriter, r *http.Request) (Encodabler, error)
func checkLevel2a(data DataFlags) error {
for i, row := range data {
line := i + 2
if _, ok := FLAGS[row.Flag]; !ok {
return fmt.Errorf("line %v: invalid quality_flag '%s'", i, row.Flag)
return fmt.Errorf("line %v: invalid quality_flag '%s'", line, row.Flag)
}
if _, ok := CAUSES[row.Cause]; !ok {
return fmt.Errorf("line %v: invalid quality_cause: '%s'", i, row.Cause)
return fmt.Errorf("line %v: invalid quality_cause: '%s'", line, row.Cause)
}
if (row.Flag != "OK") && (row.Cause == "") {
return fmt.Errorf("line %v: quality_cause needed if quality_flag is not 'OK'")
return fmt.Errorf("line %v: quality_cause needed if quality_flag is not 'OK'", line)
}
if row.Cause == "OTHER" {
return fmt.Errorf("line %v: quality_comment needed if quality_cause is set to 'OTHER'")
if row.Cause == "OTHER" && (row.Comment == "") {
return fmt.Errorf("line %v: quality_comment needed if quality_cause is set to 'OTHER'", line)
}
}
return nil
......
......@@ -8,8 +8,13 @@ import (
)
const (
LOGGER_QUERY = "SELECT l.LOGGER_ID, l.DEVICE_ID, l.NAME, l.LABEL, l.RESPONSIBLE_PERSON, l.UNTERSUCHUNGSGEBIET_ID FROM LOGGER.UNI_EXP_LOGGER l"
LOGGER_WHERE_QUERY = "WHERE l.LOGGER_ID = :1"
LOGGER_QUERY = `SELECT
l.LOGGER_ID, l.DEVICE_ID, l.NAME, l.LABEL, l.RESPONSIBLE_PERSON, l.UNTERSUCHUNGSGEBIET_ID
FROM
LOGGER.UNI_EXP_LOGGER l
WHERE
l.DEVICE_ID IS NOT NULL`
LOGGER_WHERE_QUERY = "AND l.LOGGER_ID = :1"
LOGGER_PAGE_QUERY = "ORDER BY l.LOGGER_ID OFFSET :1 ROWS FETCH NEXT :2 ROWS ONLY"
)
......
......@@ -115,6 +115,7 @@ func PrepParams(params map[string][]string) (map[string]string, error) {
return nil, err
}
// TODO: check interval [0, 1]
out["bad"] = getDefault(out, "badMax", "0.5")
out["doubt"] = getDefault(out, "doubtMax", "0.5")
......
......@@ -22,7 +22,8 @@ func (e Envelope) Encode(w http.ResponseWriter) {
}
}
func writeErrorResponse(w http.ResponseWriter, err error) {
func writeErrorResponse(w http.ResponseWriter, err AppError) {
http.Error(w, "", err.code)
out := Envelope{
Pagination: nil,
Data: nil,
......@@ -42,3 +43,7 @@ func writeGetResponse(w http.ResponseWriter, paging map[string]string, data inte
}
out.Encode(w)
}
func writePutResponse(w http.ResponseWriter) {
w.WriteHeader(http.StatusOK)
}