changeset 1224:bc4b642c8d04

Started with an upload sounding result to temp upload area.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 19 Nov 2018 17:14:42 +0100
parents a20fcfacda98
children 4d7c44f7044e
files pkg/common/errors.go pkg/controllers/routes.go pkg/controllers/srimports.go pkg/imports/sr.go pkg/misc/tmpfiles.go pkg/models/sr.go
diffstat 6 files changed, 172 insertions(+), 95 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/common/errors.go	Mon Nov 19 17:14:42 2018 +0100
@@ -0,0 +1,31 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2018 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+package common
+
+import (
+	"errors"
+	"fmt"
+	"strings"
+)
+
+func ToError(errs []error) error {
+	var b strings.Builder
+	for i, err := range errs {
+		if i > 0 {
+			fmt.Fprintf(&b, ", ")
+		}
+		fmt.Fprintf(&b, "%v", err)
+	}
+	return errors.New(b.String())
+}
--- a/pkg/controllers/routes.go	Mon Nov 19 16:50:04 2018 +0100
+++ b/pkg/controllers/routes.go	Mon Nov 19 17:14:42 2018 +0100
@@ -160,8 +160,12 @@
 		sysAdmin(http.HandlerFunc(uploadStyle))).Methods(http.MethodPost)
 
 	// Imports
-	api.Handle("/imports/soundingresult",
-		waterwayAdmin(http.HandlerFunc(importSoundingResult))).Methods(http.MethodPost)
+	api.Handle("/imports/soundingresult-upload", waterwayAdmin(&JSONHandler{
+		Handle: uploadSoundingResult,
+	})).Methods(http.MethodPost)
+
+	api.Handle("/imports/soundingresult", waterwayAdmin(
+		http.HandlerFunc(importSoundingResult))).Methods(http.MethodPost)
 
 	// Import queue
 	lsImports := waterwayAdmin(&JSONHandler{
--- a/pkg/controllers/srimports.go	Mon Nov 19 16:50:04 2018 +0100
+++ b/pkg/controllers/srimports.go	Mon Nov 19 17:14:42 2018 +0100
@@ -15,6 +15,7 @@
 
 import (
 	"bufio"
+	"database/sql"
 	"encoding/hex"
 	"io"
 	"io/ioutil"
@@ -35,7 +36,7 @@
 	soundingResultName    = "soundingresult"
 )
 
-func downloadSoundingResult(req *http.Request) (string, error) {
+func fetchSoundingResult(req *http.Request) (string, error) {
 
 	// Check first if we have a token.
 	if token := req.FormValue("token"); token != "" {
@@ -54,6 +55,11 @@
 		}
 	}
 
+	return storeSoundingResult(req)
+}
+
+func storeSoundingResult(req *http.Request) (string, error) {
+
 	// Check for direct upload.
 	f, _, err := req.FormFile(soundingResultName)
 	if err != nil {
@@ -91,7 +97,7 @@
 
 func importSoundingResult(rw http.ResponseWriter, req *http.Request) {
 
-	dir, err := downloadSoundingResult(req)
+	dir, err := fetchSoundingResult(req)
 	if err != nil {
 		log.Printf("error: %v\n", err)
 		http.Error(rw, "error: "+err.Error(), http.StatusInternalServerError)
@@ -116,3 +122,20 @@
 	}
 	SendJSON(rw, http.StatusCreated, &result)
 }
+
+func uploadSoundingResult(
+	_ interface{},
+	req *http.Request,
+	conn *sql.Conn,
+) (jr JSONResult, err error) {
+
+	var dir string
+	if dir, err = storeSoundingResult(req); err != nil {
+		return
+	}
+
+	_ = dir
+	// TODO: Implement me!
+
+	return
+}
--- a/pkg/imports/sr.go	Mon Nov 19 16:50:04 2018 +0100
+++ b/pkg/imports/sr.go	Mon Nov 19 17:14:42 2018 +0100
@@ -20,7 +20,6 @@
 	"crypto/sha1"
 	"database/sql"
 	"encoding/hex"
-	"encoding/json"
 	"errors"
 	"fmt"
 	"io"
@@ -34,26 +33,13 @@
 
 	shp "github.com/jonas-p/go-shp"
 
+	"gemma.intevation.de/gemma/pkg/common"
+	"gemma.intevation.de/gemma/pkg/models"
 	"gemma.intevation.de/gemma/pkg/octree"
 )
 
 type SoundingResult string
 
-const SoundingResultDateFormat = "2006-01-02"
-
-type (
-	SoundingResultDate struct{ time.Time }
-
-	SoundingResultMeta struct {
-		Date           SoundingResultDate `json:"date"`
-		Bottleneck     string             `json:"bottleneck"`
-		EPSG           uint               `json:"epsg"`
-		DepthReference string             `json:"depth-reference"`
-	}
-)
-
-const wgs84 = 4326
-
 const (
 	contourStepWidth = 0.1
 	contourTolerance = 0.1
@@ -93,12 +79,6 @@
 UPDATE waterway.sounding_results SET staging_done = true
 WHERE id = $1`
 
-	checkDepthReferenceSQL = `
-SELECT true FROM depth_references WHERE depth_reference = $1`
-
-	checkBottleneckSQL = `
-SELECT true FROM waterway.bottlenecks WHERE objnam = $1`
-
 	insertPointsSQL = `
 INSERT INTO waterway.sounding_results (
   bottleneck_id,
@@ -182,8 +162,8 @@
 		return err
 	}
 
-	if err := m.validate(conn); err != nil {
-		return err
+	if err := m.Validate(conn, ctx); err != nil {
+		return common.ToError(err)
 	}
 
 	feedback.Info("Looking for '*.xyz'")
@@ -289,18 +269,6 @@
 	return err
 }
 
-func (srd *SoundingResultDate) UnmarshalJSON(data []byte) error {
-	var s string
-	if err := json.Unmarshal(data, &s); err != nil {
-		return err
-	}
-	d, err := time.Parse(SoundingResultDateFormat, s)
-	if err == nil {
-		*srd = SoundingResultDate{d}
-	}
-	return err
-}
-
 func (sr SoundingResult) CleanUp() error {
 	return os.RemoveAll(string(sr))
 }
@@ -315,50 +283,14 @@
 	return nil
 }
 
-func loadMeta(f *zip.File) (*SoundingResultMeta, error) {
+func loadMeta(f *zip.File) (*models.SoundingResultMeta, error) {
 	r, err := f.Open()
 	if err != nil {
 		return nil, err
 	}
 	defer r.Close()
-	var m SoundingResultMeta
-	err = json.NewDecoder(r).Decode(&m)
-	if err == nil {
-		if m.EPSG == 0 {
-			m.EPSG = wgs84
-		}
-	}
-	return &m, err
-}
-
-func (m *SoundingResultMeta) validate(conn *sql.Conn) error {
-
-	var b bool
-	err := conn.QueryRowContext(context.Background(),
-		checkDepthReferenceSQL,
-		m.DepthReference).Scan(&b)
-	switch {
-	case err == sql.ErrNoRows:
-		return fmt.Errorf("Unknown depth reference '%s'\n", m.DepthReference)
-	case err != nil:
-		return err
-	case !b:
-		return errors.New("Unexpected depth reference")
-	}
-
-	err = conn.QueryRowContext(context.Background(),
-		checkBottleneckSQL,
-		m.Bottleneck).Scan(&b)
-	switch {
-	case err == sql.ErrNoRows:
-		return fmt.Errorf("Unknown bottleneck '%s'\n", m.Bottleneck)
-	case err != nil:
-		return err
-	case !b:
-		return errors.New("Unexpected bottleneck")
-	}
-
-	return nil
+	var m models.SoundingResultMeta
+	return &m, m.Decode(r)
 }
 
 func loadXYZReader(r io.Reader, feedback Feedback) (octree.MultiPointZ, error) {
--- a/pkg/misc/tmpfiles.go	Mon Nov 19 16:50:04 2018 +0100
+++ b/pkg/misc/tmpfiles.go	Mon Nov 19 17:14:42 2018 +0100
@@ -15,13 +15,10 @@
 
 import (
 	"encoding/hex"
-	"errors"
-	"fmt"
 	"log"
 	"os"
 	"path/filepath"
 	"sort"
-	"strings"
 	"sync"
 	"time"
 
@@ -58,17 +55,6 @@
 	return filepath.Join(dir, tmpFilesDir)
 }
 
-func toError(errs []error) error {
-	var b strings.Builder
-	for i, err := range errs {
-		if i > 0 {
-			fmt.Fprintf(&b, ", ")
-		}
-		fmt.Fprintf(&b, "%v", err)
-	}
-	return errors.New(b.String())
-}
-
 func cleanupTmpFiles() error {
 	tmpfilesMu.Lock()
 	defer tmpfilesMu.Unlock()
@@ -118,7 +104,7 @@
 	}
 
 	if len(errs) > 0 {
-		return toError(errs)
+		return common.ToError(errs)
 	}
 
 	return nil
@@ -173,7 +159,7 @@
 			files = files[1:]
 		}
 		if len(errs) > 0 {
-			return "", toError(errs)
+			return "", common.ToError(errs)
 		}
 	}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/models/sr.go	Mon Nov 19 17:14:42 2018 +0100
@@ -0,0 +1,101 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2018 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+//  * Bernhard E. Reiter <bernhard.reiter@intevation.de>
+
+package models
+
+import (
+	"context"
+	"database/sql"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"time"
+)
+
+const (
+	SoundingResultDateFormat = "2006-01-02"
+	WGS84                    = 4326
+)
+
+type (
+	SoundingResultDate struct{ time.Time }
+
+	SoundingResultMeta struct {
+		Date           SoundingResultDate `json:"date"`
+		Bottleneck     string             `json:"bottleneck"`
+		EPSG           uint               `json:"epsg"`
+		DepthReference string             `json:"depth-reference"`
+	}
+)
+
+const (
+	checkDepthReferenceSQL = `
+SELECT true FROM depth_references WHERE depth_reference = $1`
+
+	checkBottleneckSQL = `
+SELECT true FROM waterway.bottlenecks WHERE objnam = $1`
+)
+
+func (srd *SoundingResultDate) UnmarshalJSON(data []byte) error {
+	var s string
+	if err := json.Unmarshal(data, &s); err != nil {
+		return err
+	}
+	d, err := time.Parse(SoundingResultDateFormat, s)
+	if err == nil {
+		*srd = SoundingResultDate{d}
+	}
+	return err
+}
+
+func (m *SoundingResultMeta) Decode(r io.Reader) error {
+	err := json.NewDecoder(r).Decode(m)
+	if err == nil && m.EPSG == 0 {
+		m.EPSG = WGS84
+	}
+	return err
+}
+
+func (m *SoundingResultMeta) Validate(conn *sql.Conn, ctx context.Context) []error {
+
+	var errs []error
+
+	var b bool
+	err := conn.QueryRowContext(ctx,
+		checkDepthReferenceSQL,
+		m.DepthReference).Scan(&b)
+	switch {
+	case err == sql.ErrNoRows:
+		errs = append(errs, fmt.Errorf("Unknown depth reference '%s'\n", m.DepthReference))
+	case err != nil:
+		errs = append(errs, err)
+	case !b:
+		errs = append(errs, errors.New("Unexpected depth reference"))
+	}
+
+	err = conn.QueryRowContext(context.Background(),
+		checkBottleneckSQL,
+		m.Bottleneck).Scan(&b)
+	switch {
+	case err == sql.ErrNoRows:
+		errs = append(errs, fmt.Errorf("Unknown bottleneck '%s'\n", m.Bottleneck))
+	case err != nil:
+		errs = append(errs, err)
+	case !b:
+		errs = append(errs, errors.New("Unexpected bottleneck"))
+	}
+
+	return errs
+}