view client/src/store/importschedule.js @ 2377:fdec7a652f34

client: imports: avoid error when cron string cannot be parsed when trying to edit imports To prefill the form fields that generate the cron string, the currently stored cron string needs to be parsed back. This parsing only handles numerical values for each of the six cron fields. In case of something like */15 the regular expression does not match, leading to a null value. The cronMode select now has an empty option for cases where the cronString does not match any known pattern.
author Markus Kottlaender <markus@intevation.de>
date Fri, 22 Feb 2019 12:28:14 +0100
parents a5b87a695469
children dc4fae4bdb8f
line wrap: on
line source

/* 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):
 * Thomas Junk <thomas.junk@intevation.de>
 */

import Vue from "vue";
import { HTTP } from "@/lib/http";

/* eslint-disable no-unused-vars */
/* eslint-disable no-unreachable */

const IMPORTTYPES = {
  BOTTLENECK: "bottleneck",
  WATERWAYAXIS: "waterwayaxis",
  GAUGEMEASUREMENT: "gaugemeasurement",
  FAIRWAYAVAILABILITY: "fairwayavailability",
  WATERWAYAREA: "waterwayarea",
  FAIRWAYDIMENSION: "fairwaydimension",
  WATERWAYGAUGES: "waterwaygauges",
  DISTANCEMARKSVIRTUAL: "distancemarksvirtual",
  DISTANCEMARKSASHORE: "distancemarksashore"
};

const KINDIMPORTTYPE = {
  bn: "bottleneck",
  fa: "fairwayavailability",
  gm: "gaugemeasurement",
  wx: "waterwayaxis",
  wa: "waterwayarea",
  fd: "fairwaydimension",
  wg: "waterwaygauges",
  dmv: "distancemarksvirtual",
  dma: "distancemarksashore"
};

const IMPORTTYPEKIND = {
  bottleneck: "bn",
  fairwayavailability: "fa",
  gaugemeasurement: "gm",
  waterwayaxis: "wx",
  waterwayarea: "wa",
  fairwaydimension: "fd",
  waterwaygauges: "wg",
  distancemarksvirtual: "dmv",
  distancemarksashore: "dma"
};

const initializeCurrentSchedule = () => {
  return {
    id: null,
    importType: null,
    schedule: null,
    import_: null,
    importSource: null,
    eMailNotification: false,
    scheduled: false,
    easyCron: true,
    cronString: "0 */15 * * * *",
    cronMode: "15minutes",
    minutes: 0,
    month: 1,
    hour: 0,
    day: 0,
    dayOfMonth: 1,
    simple: null,
    url: null,
    insecure: false,
    triggerActive: true,
    featureType: null,
    sortBy: "hydro_scamin",
    username: "",
    password: "",
    LOS: 3,
    minWidth: null,
    maxWidth: null,
    depth: null,
    sourceOrganization: null
  };
};

// initial state
const init = () => {
  return {
    schedules: [],
    importScheduleDetailVisible: false,
    currentSchedule: initializeCurrentSchedule()
  };
};

const importschedule = {
  init,
  namespaced: true,
  state: init(),
  mutations: {
    clearCurrentSchedule: state => {
      state.currentSchedule = initializeCurrentSchedule();
    },
    setImportScheduleDetailInvisible: state => {
      state.importScheduleDetailVisible = false;
    },
    setImportScheduleDetailVisible: state => {
      state.importScheduleDetailVisible = true;
    },
    setSchedules: (state, schedules) => {
      state.schedules = schedules;
    },
    unmarshallCurrentSchedule: (state, payload) => {
      const { kind, config, id } = payload;
      const eMailNotification = config["send-email"];
      const { cron, url } = config;
      Vue.set(state.currentSchedule, "import_", KINDIMPORTTYPE[kind]);
      Vue.set(state.currentSchedule, "id", id);
      if (cron) {
        Vue.set(state.currentSchedule, "scheduled", true);
        Vue.set(state.currentSchedule, "cronString", cron);

        // simple weekly  or monthly?
        if (cron === "0 0 0 * * 0") {
          Vue.set(state.currentSchedule, "simple", "weekly");
          Vue.set(state.currentSchedule, "easyCron", true);
        } else if (cron === "0 0 0 1 * *") {
          Vue.set(state.currentSchedule, "simple", "monthly");
          Vue.set(state.currentSchedule, "easyCron", true);
        } else {
          Vue.set(state.currentSchedule, "easyCron", false);
        }

        // set cronMode from cronString
        Vue.set(state.currentSchedule, "cronMode", null);
        if (cron === "0 */15 * * * *")
          Vue.set(state.currentSchedule, "cronMode", "15minutes");
        else if (/^0 \d{1,2} \* \* \* \*$/.test(cron))
          Vue.set(state.currentSchedule, "cronMode", "hour");
        else if (/^0 \d{1,2} \d{1,2} \* \* \*$/.test(cron))
          Vue.set(state.currentSchedule, "cronMode", "day");
        else if (/^0 \d{1,2} \d{1,2} \* \* \d{1}$/.test(cron))
          Vue.set(state.currentSchedule, "cronMode", "week");
        else if (/^0 \d{1,2} \d{1,2} \d{1,2} \* \*$/.test(cron))
          Vue.set(state.currentSchedule, "cronMode", "month");
        else if (/^0 \d{1,2} \d{1,2} \d{1,2} \d{1,2} \*$/.test(cron))
          Vue.set(state.currentSchedule, "cronMode", "year");

        // set minute, hour, etc from cronString
        let cronConf = cron.match(
          /0 (\d{1,2}|\*) (\d{1,2}|\*) (\d{1,2}|\*) (\d{1,2}|\*) (\d{1}|\*)/
        );

        // if cronString could not be parsed/matched (cronConf is null),
        // skip prefilling those values
        if (cronConf) {
          // remove first element which is the whole matched string
          cronConf.shift();
          cronConf = cronConf.map(field =>
            field === "*" ? null : Number(field)
          );
          Vue.set(state.currentSchedule, "minutes", cronConf[0]);
          Vue.set(state.currentSchedule, "hour", cronConf[1]);
          Vue.set(state.currentSchedule, "dayOfMonth", cronConf[2]);
          Vue.set(state.currentSchedule, "month", cronConf[3]);
          Vue.set(state.currentSchedule, "day", cronConf[4]);
        }
      }
      if (eMailNotification) {
        Vue.set(state.currentSchedule, "eMailNotification", eMailNotification);
      }
      if (url) {
        Vue.set(state.currentSchedule, "url", url);
      }
      let { insecure, user, password, los, depth } = config;
      let sortBy = config["sort-by"];
      let minWidth = config["min-width"];
      let maxWidth = config["max-width"];
      let sourceOrganization = config["source-organization"];
      const featureType = config["feature-type"];
      insecure = insecure == "true";
      if (insecure) {
        Vue.set(state.currentSchedule, "insecure", insecure);
      }
      if (featureType) {
        Vue.set(state.currentSchedule, "featureType", featureType);
      }
      if (sortBy) {
        Vue.set(state.currentSchedule, "sortBy", sortBy);
      }
      if (user) {
        Vue.set(state.currentSchedule, "username", user);
      }
      if (password) {
        Vue.set(state.currentSchedule, "password", password);
      }
      if (los) {
        Vue.set(state.currentSchedule, "LOS", los);
      }
      if (minWidth) {
        Vue.set(state.currentSchedule, "minWidth", minWidth);
      }
      if (maxWidth) {
        Vue.set(state.currentSchedule, "maxWidth", maxWidth);
      }
      if (depth) {
        Vue.set(state.currentSchedule, "depth", depth);
      }
      if (sourceOrganization) {
        Vue.set(
          state.currentSchedule,
          "sourceOrganization",
          sourceOrganization
        );
      }
    }
  },
  actions: {
    loadSchedule({ commit }, id) {
      return new Promise((resolve, reject) => {
        HTTP.get("/imports/config/" + id, {
          headers: { "X-Gemma-Auth": localStorage.getItem("token") }
        })
          .then(response => {
            commit("unmarshallCurrentSchedule", response.data);
            resolve(response);
          })
          .catch(error => {
            reject(error);
          });
      });
    },
    updateCurrentSchedule({ commit }, payload) {
      const { data, id } = payload;
      return new Promise((resolve, reject) => {
        HTTP.patch("imports/config/" + id, data, {
          headers: {
            "X-Gemma-Auth": localStorage.getItem("token")
          }
        })
          .then(response => {
            resolve(response);
          })
          .catch(error => {
            reject(error);
          });
      });
    },
    saveCurrentSchedule({ commit }, data) {
      return new Promise((resolve, reject) => {
        HTTP.post("imports/config", data, {
          headers: {
            "X-Gemma-Auth": localStorage.getItem("token")
          }
        })
          .then(response => {
            resolve(response);
          })
          .catch(error => {
            reject(error);
          });
      });
    },
    loadSchedules({ commit }) {
      return new Promise((resolve, reject) => {
        HTTP.get("/imports/config", {
          headers: { "X-Gemma-Auth": localStorage.getItem("token") }
        })
          .then(response => {
            commit("setSchedules", response.data);
            resolve(response);
          })
          .catch(error => {
            reject(error);
          });
      });
    },
    deleteSchedule({ commit }, id) {
      return new Promise((resolve, reject) => {
        HTTP.delete("imports/config/" + id, {
          headers: {
            "X-Gemma-Auth": localStorage.getItem("token")
          }
        })
          .then(response => {
            resolve(response);
          })
          .catch(error => {
            reject(error);
          });
      });
    },
    triggerImport({ commit }, { type, data }) {
      return new Promise((resolve, reject) => {
        HTTP.post("imports/" + type, data, {
          headers: {
            "X-Gemma-Auth": localStorage.getItem("token")
          }
        })
          .then(response => {
            resolve(response);
          })
          .catch(error => {
            reject(error);
          });
      });
    }
  }
};

export {
  importschedule,
  initializeCurrentSchedule,
  IMPORTTYPES,
  IMPORTTYPEKIND
};