view client/src/usermanagement/Userdetail.vue @ 904:e4b72a199258

New default bottleneck colors Mainly to make the stroke color one actually selectable in the ui. In addition the pink does better match the collors used on the ECDIS layer.
author Sascha Wilde <wilde@intevation.de>
date Tue, 02 Oct 2018 13:34:59 +0200
parents c0bb673d360e
children ca628dce90dd
line wrap: on
line source

<template>
    <div class="userdetails shadow fadeIn animated">
        <div class="card">
            <div class="card-header shadow-sm text-white bg-info mb-3">
                {{ this.cardHeader }}
                <span @click="closeDetailview" class="pull-right">
                    <i class="fa fa-close"></i>
                </span>
            </div>
            <div class="card-body">
                <form @submit.prevent="save">
                    <div class="formfields">
                        <div v-if="currentUser.isNew" class="form-group row">
                            <label for="user">Username</label>
                            <input type="user" :placeholder="userNamePlaceholder" class="form-control form-control-sm" id="user" aria-describedby="userHelp" v-model="currentUser.user">
                            <div v-show="errors.user" class="text-danger">
                                <small>
                                    <i class="fa fa-warning"></i> {{ errors.user }}</small>
                            </div>
                        </div>
                        <div class="form-group row">
                            <label for="country">Country</label>
                            <select class="form-control form-control-sm" v-on:change="validateCountry" v-model="currentUser.country">
                                <option disabled value="">Please select one</option>
                                <option v-for="country in countries" v-bind:value="country" v-bind:key="country">{{country}}</option>
                            </select>
                            <div v-show="errors.country" class="text-danger">
                                <small>
                                    <i class="fa fa-warning"></i> {{ errors.country }}</small>
                            </div>
                        </div>
                        <div class="form-group row">
                            <label for="email">Email address</label>
                            <input type="email" v-on:change="validateEmailaddress" class="form-control form-control-sm" id="email" aria-describedby="emailHelp" v-model="currentUser.email">
                            <div v-show="errors.email" class="text-danger">
                                <small>
                                    <i class="fa fa-warning"></i> {{ errors.email }}</small>
                            </div>
                        </div>
                        <div class="form-group row">
                            <label for="role">Role</label>
                            <select class="form-control form-control-sm" v-on:change="validateRole" v-model="currentUser.role">
                                <option disabled value="">Please select one</option>
                                <option value="sys_admin">Sysadmin</option>
                                <option value="waterway_admin">Waterway Admin</option>
                                <option value="waterway_user">Waterway User</option>
                            </select>
                            <div v-show="errors.role" class="text-danger">
                                <small>
                                    <i class="fa fa-warning"></i> {{ errors.role }}</small>
                            </div>
                        </div>
                        <div class="form-group row">
                            <PasswordField @fieldchange="passwordChanged" :placeholder="passwordPlaceholder" :label="passwordLabel" :passworderrors="errors.password"></PasswordField>
                        </div>
                        <div class="form-group row">
                            <PasswordField @fieldchange="passwordReChanged" :placeholder="passwordRePlaceholder" :label="passwordReLabel" :passworderrors="errors.passwordre"></PasswordField>
                        </div>
                    </div>
                    <div>
                        <button type="submit" :disabled="submitted" class="shadow-sm btn btn-info pull-right">Submit</button>
                    </div>
                    <div v-if="currentUser.role !='waterway_user' " class="form-group row d-flex flex-row justify-content-start mailbutton">
                        <a @click="sendTestMail" class="btn btn-light"><i class="fa fa-telegram"> Send testmail</i></a>
                        <div v-if="mailsent">Mail was sent</div>
                    </div>
                </form>
            </div>
        </div>
    </div>
</template>

<style lang="scss">
.mailbutton {
  width: 12vw;
}
.formfields {
  width: 10vw;
}

.userdetails {
  margin-top: $offset;
  min-width: 40vw;
  margin-right: auto;
  height: 100%;
}

form {
  margin-left: $offset;
  font-size: $smaller;
}
</style>
<script>
import { HTTP } from "../application/lib/http";
import { displayError } from "../application/lib/errors.js";
import { mapGetters } from "vuex";
import PasswordField from "./Passwordfield";

const emptyErrormessages = () => {
  return {
    email: "",
    country: "",
    role: "",
    password: "",
    passwordre: ""
  };
};

const isEmailValid = email => {
  /**
   *
   * For convenience purposes the same regex used as in the go code
   * cf. types.go
   *
   */
  // eslint-disable-next-line
  return /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/.test(
    email
  );
};

const violatedPasswordRules = password => {
  return (
    // rules according to issue 70
    password.length < 7 ||
    /\W/.test(password) == false ||
    /\d/.test(password) == false
  );
};

export default {
  name: "userdetail",
  components: {
    PasswordField
  },
  data() {
    return {
      mailsent: false,
      passwordLabel: "Password",
      passwordReLabel: "Repeat Password",
      passwordPlaceholder: "password",
      passwordRePlaceholder: "password again",
      password: "",
      passwordre: "",
      currentUser: {},
      path: null,
      submitted: false,
      errors: {
        email: "",
        country: "",
        role: "",
        password: "",
        passwordre: ""
      }
    };
  },
  mounted() {
    this.currentUser = { ...this.user };
    this.path = this.user.name;
  },
  watch: {
    user() {
      this.currentUser = { ...this.user };
      this.path = this.user.name;
      this.clearPassword();
      this.clearErrors();
    }
  },
  computed: {
    cardHeader() {
      if (this.currentUser.isNew) return "N.N";
      return this.currentUser.user;
    },
    userNamePlaceholder() {
      if (this.currentUser.isNew) return "N.N";
      return "";
    },
    ...mapGetters("application", ["countries"]),
    user() {
      return this.$store.getters["usermanagement/currentUser"];
    },
    isFormValid() {
      return (
        isEmailValid(this.currentUser.email) &&
        this.currentUser.country &&
        this.password === this.passwordre &&
        (this.password === "" || !violatedPasswordRules(this.password))
      );
    }
  },
  methods: {
    sendTestMail() {
      if (this.mailsent) return;
      HTTP.get("/testmail/" + this.currentUser.user, {
        headers: {
          "X-Gemma-Auth": localStorage.getItem("token"),
          "Content-type": "text/xml; charset=UTF-8"
        }
      })
        .then(() => {
          this.mailsent = true;
        })
        .catch(error => {
          this.loginFailed = true;
          this.submitted = false;
          const { status, data } = error.response;
          displayError({
            title: "Backend Error",
            message: `${status}: ${data.message || data}`
          });
        });
    },
    passwordChanged(value) {
      this.password = value;
      this.validatePassword();
    },
    passwordReChanged(value) {
      this.passwordre = value;
      this.validatePassword();
    },
    clearErrors() {
      this.errors = emptyErrormessages();
    },
    clearPassword() {
      this.password = "";
      this.passwordre = "";
    },
    closeDetailview() {
      this.$store.commit("usermanagement/clearCurrentUser");
      this.$store.commit("usermanagement/setUserDetailsInvisible");
    },
    validateCountry() {
      this.errors.country = this.currentUser.country
        ? ""
        : "Please choose a country";
    },
    validateRole() {
      this.errors.role = this.currentUser.role ? "" : "Please choose a role";
    },
    validatePassword() {
      this.errors.passwordre =
        this.password === this.passwordre ? "" : "Passwords do not match!";
      this.errors.password =
        this.password === "" || !violatedPasswordRules(this.password)
          ? ""
          : "Password should at least be 8 char long including 1 digit and 1 special char like $";
    },
    validateEmailaddress() {
      this.errors.email = isEmailValid(this.currentUser.email)
        ? ""
        : "invalid email";
    },
    validate() {
      this.validateCountry();
      this.validateRole();
      this.validatePassword();
      this.validateEmailaddress();
    },
    save() {
      this.validate();
      if (!this.isFormValid) return;
      if (this.password) this.currentUser.password = this.password;
      this.submitted = true;
      this.$store
        .dispatch("usermanagement/saveCurrentUser", {
          path: this.user.user,
          user: this.currentUser
        })
        .then(() => {
          this.submitted = false;
          this.$store.dispatch("usermanagement/loadUsers").catch(error => {
            const { status, data } = error.response;
            displayError({
              title: "Backend Error",
              message: `${status}: ${data.message || data}`
            });
          });
        })
        .catch(error => {
          this.submitted = false;
          const { status, data } = error.response;
          displayError({
            title: "Error while saving user",
            message: `${status}: ${data.message || data}`
          });
        });
    }
  }
};
</script>