changeset 1479:858af4614209

merge with bulkreview
author Thomas Junk <thomas.junk@intevation.de>
date Tue, 04 Dec 2018 09:56:11 +0100
parents d7152eb11d58 (current diff) a966789972d7 (diff)
children 9b81ac91a43e
files
diffstat 6 files changed, 149 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/components/map/contextbox/Staging.vue	Mon Dec 03 20:46:35 2018 +0100
+++ b/client/src/components/map/contextbox/Staging.vue	Tue Dec 04 09:56:11 2018 +0100
@@ -85,6 +85,7 @@
  * Markus Kottländer <markus@intevation.de>
  */
 import { mapState } from "vuex";
+import { HTTP } from "../../../lib/http.js";
 import { STATES } from "../../../store/imports.js";
 import { displayError, displayInfo } from "../../../lib/errors.js";
 
@@ -93,13 +94,7 @@
     return {};
   },
   mounted() {
-    this.$store.dispatch("imports/getStaging").catch(error => {
-      const { status, data } = error.response;
-      displayError({
-        title: this.$gettext("Backend Error"),
-        message: `${status}: ${data.message || data}`
-      });
-    });
+    this.loadData();
   },
   computed: {
     ...mapState("application", ["searchQuery"]),
@@ -115,16 +110,55 @@
   },
   STATES: STATES,
   methods: {
+    loadData() {
+      this.$store.dispatch("imports/getStaging").catch(error => {
+        const { status, data } = error.response;
+        displayError({
+          title: "Backend Error",
+          message: `${status}: ${data.message || data}`
+        });
+      });
+    },
     confirmReview() {
-      const message = this.staging
-        .map(x => {
-          return x.id + ": " + x.status;
+      const reviewResults = this.staging
+        .filter(x => x.status !== STATES.NEEDSAPPROVAL)
+        .map(r => {
+          return {
+            id: r.id,
+            state: r.status
+          };
+        });
+      if (!reviewResults.length) return;
+      HTTP.patch("/imports", reviewResults, {
+        headers: {
+          "X-Gemma-Auth": localStorage.getItem("token"),
+          "Content-type": "application/json"
+        }
+      })
+        .then(response => {
+          const messages = response.data
+            .map(x => {
+              if (x.message) return x.message;
+              if (x.error) return x.error;
+            })
+            .join("\n\n");
+          displayInfo({
+            title: "Staging Area",
+            message: messages,
+            options: {
+              timeout: 0,
+              buttons: [{ text: "Ok", action: null, bold: true }]
+            }
+          });
+          this.loadData();
         })
-        .join("\n");
-      displayInfo({
-        title: this.$gettext("Staging Area"),
-        message: message
-      });
+        .catch(error => {
+          const { status, data } = error.response;
+          displayError({
+            title: "Backend Error",
+            message: `${status}: ${data.message || data}`
+          });
+        });
     },
     needsApproval(item) {
       return item.status === STATES.NEEDSAPPROVAL;
--- a/client/src/lib/errors.js	Mon Dec 03 20:46:35 2018 +0100
+++ b/client/src/lib/errors.js	Tue Dec 04 09:56:11 2018 +0100
@@ -14,21 +14,26 @@
 
 import app from "../main";
 
-const displayOptions = {
-  timeout: 2000,
+let displayOptions = {
+  timeout: 2500,
   showProgressBar: false,
-  closeOnClick: false,
+  closeOnClick: true,
   pauseOnHover: true,
   oneAtTime: true,
-  bodyMaxLength: 250
+  bodyMaxLength: 1024
 };
 
-const displayError = ({ title, message }) => {
+const displayError = ({ title, message, options }) => {
+  if (!options) options = {};
+  const mergedOptions = { ...displayOptions, ...options };
+  app.$snotify.info(message, title, mergedOptions);
   app.$snotify.error(message, title, displayOptions);
 };
 
-const displayInfo = ({ title, message }) => {
-  app.$snotify.info(message, title, displayOptions);
+const displayInfo = ({ title, message, options }) => {
+  if (!options) options = {};
+  const mergedOptions = { ...displayOptions, ...options };
+  app.$snotify.info(message, title, mergedOptions);
 };
 
 export { displayError, displayInfo };
--- a/client/src/store/imports.js	Mon Dec 03 20:46:35 2018 +0100
+++ b/client/src/store/imports.js	Tue Dec 04 09:56:11 2018 +0100
@@ -17,9 +17,9 @@
 /* eslint-disable no-unused-vars */
 /* eslint-disable no-unreachable */
 const STATES = {
-  NEEDSAPPROVAL: "NEEDSAPPROVAL",
-  APPROVED: "APPROVED",
-  REJECTED: "REJECTED"
+  NEEDSAPPROVAL: "pending",
+  APPROVED: "accepted",
+  REJECTED: "declined"
 };
 
 const SCHEDULES = {
--- a/pkg/controllers/importqueue.go	Mon Dec 03 20:46:35 2018 +0100
+++ b/pkg/controllers/importqueue.go	Tue Dec 04 09:56:11 2018 +0100
@@ -334,6 +334,39 @@
 INSERT INTO waterway.import_logs (import_id, msg) VALUES ($1, $2)`
 )
 
+func reviewImports(
+	reviews interface{},
+	req *http.Request,
+	conn *sql.Conn,
+) (JSONResult, error) {
+
+	rs := *reviews.(*[]models.Review)
+
+	type reviewResult struct {
+		ID      int64  `json:"id"`
+		Message string `json:"message,omitempty"`
+		Error   string `json:"error,omitempty"`
+	}
+
+	results := make([]reviewResult, len(rs))
+
+	for i := range rs {
+		rev := &rs[i]
+		msg, err := decideImport(req, conn, rev.ID, string(rev.State))
+		var errString string
+		if err != nil {
+			errString = err.Error()
+		}
+		results[i] = reviewResult{
+			ID:      rev.ID,
+			Message: msg,
+			Error:   errString,
+		}
+	}
+
+	return JSONResult{Result: results}, nil
+}
+
 func reviewImport(
 	_ interface{},
 	req *http.Request,
@@ -344,6 +377,27 @@
 	id, _ := strconv.ParseInt(vars["id"], 10, 64)
 	state := vars["state"]
 
+	var msg string
+	if msg, err = decideImport(req, conn, id, state); err != nil {
+		return
+	}
+
+	result := struct {
+		Message string `json:"message"`
+	}{
+		Message: msg,
+	}
+
+	jr = JSONResult{Result: &result}
+	return
+}
+
+func decideImport(
+	req *http.Request,
+	conn *sql.Conn,
+	id int64,
+	state string,
+) (message string, err error) {
 	ctx := req.Context()
 	var tx *sql.Tx
 	if tx, err = conn.BeginTx(ctx, nil); err != nil {
@@ -357,18 +411,12 @@
 	err = tx.QueryRowContext(ctx, isPendingSQL, id).Scan(&pending, &kind)
 	switch {
 	case err == sql.ErrNoRows:
-		err = JSONError{
-			Code:    http.StatusNotFound,
-			Message: fmt.Sprintf("Cannot find import #%d.", id),
-		}
+		err = fmt.Errorf("Cannot find import #%d.", id)
 		return
 	case err != nil:
 		return
 	case !pending:
-		err = JSONError{
-			Code:    http.StatusBadRequest,
-			Message: fmt.Sprintf("Import %d is not pending.", id),
-		}
+		err = fmt.Errorf("Import %d is not pending.", id)
 		return
 	}
 
@@ -407,13 +455,8 @@
 		return
 	}
 
-	result := struct {
-		Message string `json:"message"`
-	}{
-		Message: fmt.Sprintf("Import #%d successfully changed to state '%s'.",
-			id, state),
-	}
+	message = fmt.Sprintf(
+		"Import #%d successfully changed to state '%s'.", id, state)
 
-	jr = JSONResult{Result: &result}
 	return
 }
--- a/pkg/controllers/routes.go	Mon Dec 03 20:46:35 2018 +0100
+++ b/pkg/controllers/routes.go	Tue Dec 04 09:56:11 2018 +0100
@@ -182,6 +182,11 @@
 		Handle: importLogs,
 	})).Methods(http.MethodGet)
 
+	api.Handle("/imports", waterwayAdmin(&JSONHandler{
+		Input:  func() interface{} { return &[]models.Review{} },
+		Handle: reviewImports,
+	})).Methods(http.MethodPatch)
+
 	api.Handle("/imports/{id:[0-9]+}", waterwayAdmin(&JSONHandler{
 		Handle: deleteImport,
 	})).Methods(http.MethodDelete)
--- a/pkg/models/import.go	Mon Dec 03 20:46:35 2018 +0100
+++ b/pkg/models/import.go	Tue Dec 04 09:56:11 2018 +0100
@@ -15,6 +15,7 @@
 
 import (
 	"encoding/json"
+	"errors"
 	"time"
 )
 
@@ -36,8 +37,29 @@
 		Kind    string     `json:"kind"`
 		Message string     `json:"message"`
 	}
+
+	ReviewState string
+
+	Review struct {
+		ID    int64       `json:"id"`
+		State ReviewState `json:"state"`
+	}
 )
 
+var errInvalidReviewState = errors.New("state is wether 'accepted' nor 'declined'")
+
+func (rs *ReviewState) UnmarshalJSON(data []byte) error {
+	var s string
+	if err := json.Unmarshal(data, &s); err != nil {
+		return err
+	}
+	if s != "accepted" && s != "declined" {
+		return errInvalidReviewState
+	}
+	*rs = ReviewState(s)
+	return nil
+}
+
 func (it ImportTime) MarshalJSON() ([]byte, error) {
 	return json.Marshal(it.Format("2006-01-02T15:04:05"))
 }