Add compare handler
This commit is contained in:
parent
ec93617ca8
commit
763c1f77d1
3 changed files with 169 additions and 3 deletions
119
compare.go
Normal file
119
compare.go
Normal file
|
@ -0,0 +1,119 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func handleCompare(w http.ResponseWriter, r *http.Request) *appError {
|
||||
// types
|
||||
type Comparisions map[string]map[string]string
|
||||
type ComparisionsJSON [][]string
|
||||
|
||||
// vars
|
||||
mimeType := r.FormValue("mimeType")
|
||||
if mimeType == "" {
|
||||
mimeType = "json"
|
||||
}
|
||||
claims := getClaims(r)
|
||||
var header string
|
||||
var data []byte
|
||||
|
||||
// Get measurements for comparision
|
||||
measService := MeasurementService{}
|
||||
opt := r.URL.Query()
|
||||
opt.Del("mimeType")
|
||||
opt.Del("token")
|
||||
opt.Add("Genus", mux.Vars(r)["genus"])
|
||||
measurementsEntity, appErr := measService.list(&opt, &claims)
|
||||
if appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
measurementsPayload := (measurementsEntity).(*MeasurementsPayload)
|
||||
|
||||
// Assemble matrix
|
||||
characteristic_ids := strings.Split(opt.Get("characteristic_ids"), ",")
|
||||
strain_ids := strings.Split(opt.Get("strain_ids"), ",")
|
||||
|
||||
comparisions := make(Comparisions)
|
||||
for _, characteristic_id := range characteristic_ids {
|
||||
characteristic_id_int, _ := strconv.ParseInt(characteristic_id, 10, 0)
|
||||
values := make(map[string]string)
|
||||
for _, strain_id := range strain_ids {
|
||||
strain_id_int, _ := strconv.ParseInt(strain_id, 10, 0)
|
||||
for _, m := range *measurementsPayload.Measurements {
|
||||
if (m.CharacteristicId == characteristic_id_int) && (m.StrainId == strain_id_int) {
|
||||
values[strain_id] = m.Value()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
comparisions[characteristic_id] = values
|
||||
}
|
||||
|
||||
// Return, based on mimetype
|
||||
switch mimeType {
|
||||
case "json":
|
||||
header = "application/json"
|
||||
|
||||
comparisionsJSON := make(ComparisionsJSON, 0)
|
||||
for _, characteristic_id := range characteristic_ids {
|
||||
row := []string{characteristic_id}
|
||||
for _, strain_id := range strain_ids {
|
||||
row = append(row, comparisions[characteristic_id][strain_id])
|
||||
}
|
||||
comparisionsJSON = append(comparisionsJSON, row)
|
||||
}
|
||||
|
||||
data, _ = json.Marshal(comparisionsJSON)
|
||||
case "csv":
|
||||
header = "text/csv"
|
||||
|
||||
// maps to translate ids
|
||||
strains := make(map[string]string)
|
||||
for _, strain := range *measurementsPayload.Strains {
|
||||
strains[fmt.Sprintf("%d", strain.Id)] = strain.StrainName
|
||||
}
|
||||
characteristics := make(map[string]string)
|
||||
for _, characteristic := range *measurementsPayload.Characteristics {
|
||||
characteristics[fmt.Sprintf("%d", characteristic.Id)] = characteristic.CharacteristicName
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
wr := csv.NewWriter(b)
|
||||
|
||||
// Write header row
|
||||
r := []string{""}
|
||||
for _, strain_id := range strain_ids {
|
||||
r = append(r, strains[strain_id])
|
||||
}
|
||||
wr.Write(r)
|
||||
|
||||
// Write data
|
||||
for key, record := range comparisions {
|
||||
r := []string{characteristics[key]}
|
||||
for _, val := range record {
|
||||
r = append(r, val)
|
||||
}
|
||||
wr.Write(r)
|
||||
}
|
||||
wr.Flush()
|
||||
|
||||
data = b.Bytes()
|
||||
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="compare-%d.csv"`, int32(time.Now().Unix())))
|
||||
}
|
||||
|
||||
// Wrap it up
|
||||
w.Header().Set("Content-Type", header)
|
||||
w.Write(data)
|
||||
return nil
|
||||
}
|
|
@ -92,6 +92,8 @@ func Handler() http.Handler {
|
|||
s.Handle("/users/verify/{Nonce}", errorHandler(handleUserVerify)).Methods("GET")
|
||||
s.Handle("/users/lockout", errorHandler(handleUserLockout)).Methods("POST")
|
||||
|
||||
s.Handle("/compare", j.Secure(errorHandler(handleCompare), verifyClaims)).Methods("GET")
|
||||
|
||||
type r struct {
|
||||
f errorHandler
|
||||
m string
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
|
@ -62,6 +63,19 @@ type Measurement struct {
|
|||
CanEdit bool `db:"-" json:"canEdit"`
|
||||
}
|
||||
|
||||
func (m *Measurement) Value() string {
|
||||
if m.TextMeasurementType.Valid {
|
||||
return m.TextMeasurementType.String
|
||||
}
|
||||
if m.TxtValue.Valid {
|
||||
return m.TxtValue.String
|
||||
}
|
||||
if m.NumValue.Valid {
|
||||
return fmt.Sprintf("%f", m.NumValue.Float64)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Measurements []*Measurement
|
||||
|
||||
type MeasurementMeta struct {
|
||||
|
@ -72,9 +86,10 @@ type MeasurementPayload struct {
|
|||
Measurement *Measurement `json:"measurement"`
|
||||
}
|
||||
|
||||
// TODO: Add related models
|
||||
type MeasurementsPayload struct {
|
||||
Measurements *Measurements `json:"measurements"`
|
||||
Strains *Strains `json:"strains"`
|
||||
Characteristics *Characteristics `json:"characteristics"`
|
||||
Measurements *Measurements `json:"measurements"`
|
||||
}
|
||||
|
||||
func (m *MeasurementPayload) marshal() ([]byte, error) {
|
||||
|
@ -105,8 +120,30 @@ func (m MeasurementService) list(val *url.Values, claims *Claims) (entity, *appE
|
|||
return nil, newJSONError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
char_opts, err := characteristicOptsFromMeasurements(opt)
|
||||
if err != nil {
|
||||
return nil, newJSONError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
characteristics, err := listCharacteristics(*char_opts, claims)
|
||||
if err != nil {
|
||||
return nil, newJSONError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
strain_opts, err := strainOptsFromMeasurements(opt)
|
||||
if err != nil {
|
||||
return nil, newJSONError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
strains, err := listStrains(*strain_opts, claims)
|
||||
if err != nil {
|
||||
return nil, newJSONError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
payload := MeasurementsPayload{
|
||||
Measurements: measurements,
|
||||
Characteristics: characteristics,
|
||||
Strains: strains,
|
||||
Measurements: measurements,
|
||||
}
|
||||
|
||||
return &payload, nil
|
||||
|
@ -212,3 +249,11 @@ func getMeasurement(id int64, genus string, claims *Claims) (*Measurement, error
|
|||
|
||||
return &measurement, nil
|
||||
}
|
||||
|
||||
func characteristicOptsFromMeasurements(opt MeasurementListOptions) (*ListOptions, error) {
|
||||
return &ListOptions{Genus: opt.Genus, Ids: opt.Characteristics}, nil
|
||||
}
|
||||
|
||||
func strainOptsFromMeasurements(opt MeasurementListOptions) (*ListOptions, error) {
|
||||
return &ListOptions{Genus: opt.Genus, Ids: opt.Strains}, nil
|
||||
}
|
||||
|
|
Reference in a new issue