Как я могу проверить, существует ли уже электронная почта, используя MERN - PullRequest
0 голосов
/ 01 ноября 2019

У меня есть представление регистрации, и я пытаюсь проверить, существует ли уже электронная почта, я отменил код реакции, чтобы вы могли получить представление о структуре.

Письма настроены какуникален в схеме.

AuthController

const { check, validationResult } = require("express-validator");
const jwt = require("jsonwebtoken");
const passport = require("passport");
require("../passport");

const Users = require("../models/user");

let validations = [
  check("email")
    .isEmail()
    .withMessage("The email you have entered is not valid")
    .contains("@")
    .withMessage("The email you have entered does not contain an @"),

  check("password")
    .isLength({ min: 5 })
    .withMessage("The password must have at least 5 characters")
];

// Throw error if the key doesn't exist
if (!process.env.JWT_SECRET) {
  console.error("Cannot find JWT key");
}

function generateWebToken(user) {
  return jwt.sign(user, process.env.JWT_SECRET, {
    subject: user.email,
    expiresIn: "7d",
    algorithm: "HS256"
  });
}

/* POST register a user if one doesn't already exist */
module.exports.register = [
  ...validations,
  (req, res) => {
    // Get validation errors from the request
    const errors = validationResult(req);
    // Return the errors
    if (!errors.isEmpty()) {
      return res.status(422).json({ error: errors.array() });
    }

    let hashedPassword = Users.hashPassword(req.body.password);

    Users.findOne({ email: req.body.email })
      .then(function(user) {
        if (user) {
          return res
            .status(400)
            .send(`An account with the email ${req.body.email} already exists`);
        } else {
          Users.create({
            email: req.body.email,
            password: hashedPassword
          })
            .then(function(user) {
              res.status(201).json(user);
            })
            .catch(function(err) {
              console.error(err);
              res.status(500).send(`Error ${err}`);
            });
        }
      })
      .catch(function(err) {
        console.error(err);
        res.status(500).send(`Error ${err}`);
      });
  }
];

Register.js (реагирующий компонент)

import React, { Component } from "react";

const initalState = {
  email: "",
  password: "",
  emailErr: "",
  passwordErr: ""
};

class Register extends Component {
  constructor(props) {
    super(props);
    this.state = {
      initalState,

      successMsg: ""
    };

    this.handleSubmit = this.handleSubmit.bind(this);
  }

  validate = () => {
    let emailErr = "";
    let passwordErr = "";

    // Email validation
    if (!this.state.email) {
      emailErr = "Please enter an email";
    }

    // Password validation
    if (!this.state.password) {
      passwordErr = "Please enter your password";
    }

    if (emailErr || passwordErr) {
      this.setState({ emailErr, passwordErr });
      return false;
    }

    return true;
  };

  onEmailChange(event) {
    this.setState({ email: event.target.value });
  }

  onPasswordChange(event) {
    this.setState({ password: event.target.value });
  }

  handleSubmit(event) {
    event.preventDefault();
    const isValid = this.validate();

    if (isValid) {
      fetch("/api/auth/register", {
        method: "POST",
        body: JSON.stringify(this.state),
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json"
        }
      })
        .then(res => res.json())
        .then(this.setState({ successMsg: true }), this.setState(initalState));
    }
  }

  render() {
    return (
      <>
        <div className='block md:flex md:flex-column h-full'>
          <div className='p-12 w-full text-center text-gray-800'>
            <h1 className='title'>Register</h1>

            {this.state.successMsg && (
              <div
                className='w-full m-auto max-w-lg mb-10 bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative'
                role='alert'
              >
                <strong className='font-bold'>Holy smokes! </strong>
                <span className='block sm:inline'>
                  Account has been created
                </span>
              </div>
            )}

            <form className='w-full m-auto max-w-lg'>
              <div className='flex flex-wrap -mx-3'>
                <div className='w-full px-3 mb-6'>
                  <label htmlFor='email'>Email Address</label>

                  <input
                    id='email'
                    type='text'
                    placeholder='johndoe@example.co.uk'
                    value={this.state.email || ""}
                    onChange={this.onEmailChange.bind(this)}
                  />

                  <p className='my-2 text-red-500 text-xs'>
                    {this.state.emailErr}
                  </p>
                </div>
              </div>

              <div className='flex flex-wrap -mx-3'>
                <div className='w-full px-3 mb-6'>
                  <label htmlFor='password'>Password</label>

                  <input
                    id='password'
                    type='password'
                    placeholder='*********'
                    value={this.state.password || ""}
                    onChange={this.onPasswordChange.bind(this)}
                  />

                  <p className='my-2 text-red-500 text-xs'>
                    {this.state.passwordErr}
                  </p>
                </div>
              </div>

              <div className='flex'>
                <button
                  className='btn'
                  type='button'
                  onClick={this.handleSubmit.bind(this)}
                >
                  Send
                </button>
              </div>
            </form>
          </div>
        </div>
      </>
    );
  }
}

export default Register;

Не уверен, возможно ли просто передать экспресс-проверки или чтолучшее решение для этого.

Ответы [ 2 ]

0 голосов
/ 01 ноября 2019

Вот полное решение для отображения ошибок из регистра API (и экспресс-проверки, и пользователь уже зарегистрировал ошибку)

Я пытался имитировать ваше API и реагировать на приложение, но сильно реорганизовал:

1-) В API мы должны преобразовать ошибки экспресс-проверки в удобочитаемый способ:

Обычно его ошибки проверки находятся в массиве, подобном следующему:

{
    "error": [
        {
            "value": "abcdef@net",
            "msg": "The email you have entered is not valid",
            "param": "email",
            "location": "body"
        },
        {
            "value": "12",
            "msg": "The password must have at least 5 characters",
            "param": "password",
            "location": "body"
        }
    ]
}

С помощью следующего кода:Я преобразовал сообщения об ошибках в этом формате, чтобы легко получить доступ к приложению реагирования по имени поля:

{
    "errors": {
        "email": "The email you have entered is not valid",
        "password": "The password must have at least 5 characters"
    }
}

зарегистрировать маршрут:

const { check, validationResult } = require("express-validator");
const bcrypt = require("bcryptjs");
const { User } = require("../models/user");
const express = require("express");
const router = express.Router();

let validations = [
  check("email")
    .isEmail()
    .withMessage("The email you have entered is not valid"),

  check("password")
    .isLength({ min: 5 })
    .withMessage("The password must have at least 5 characters")
];

router.post("/register", validations, async (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    const err = {};
    errors.array().forEach(error => {
      err[error.param] = error.msg;
    });
    return res.status(422).json({ errors: err });
  }

  const { email, password } = req.body;

  try {
    let user = await User.findOne({ email });
    if (user) return res.status(400).send("User already registered.");

    user = new User({ email, password });
    const salt = await bcrypt.genSalt(10);
    user.password = await bcrypt.hash(user.password, salt);
    user = await user.save();

    res.send(user);
  } catch (err) {
    console.log(err);
    res.status(500).send("Something went wrong");
  }
});

module.exports = router;

На стороне реакции я использовал axios вместо fetch, посколькуобработка ошибок намного проще с помощью axios:

import React, { Component } from "react";
import axios from "axios";

class App extends Component {
  state = {
    email: "",
    password: "",
    fieldErrors: {},
    registerError: null
  };

  handleSubmit = async e => {
    e.preventDefault();

    this.setState({
      fieldErrors: {},
      registerError: null
    })

    const { email, password } = this.state;

    try {
      const response = await axios.post(
        "https://express-validator-auth.herokuapp.com/api/users/register",
        { email, password }
      );
      console.log(response.data);
      alert("Registered");
    } catch (error) {
      if (error.response && error.response.data) {
        if (error.response.data.errors) {
          this.setState({
            fieldErrors: error.response.data.errors
          });
        } else {
          this.setState({
            registerError: error.response.data
          });
        }
      } else {
        console.log(error);
      }
    }
  };

  handleChange = e => {
    this.setState({
      [e.target.name]: e.target.value
    });
  };

  render() {
    const { email, password, fieldErrors, registerError } = this.state;

    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <div className="form-group">
            <label>Email</label>
            <input
              type="text"
              className={
                !fieldErrors.email ? "form-control" : "form-control is-invalid"
              }
              name="email"
              value={email}
              onChange={this.handleChange}
            />
            {fieldErrors.email && (
              <div className="invalid-feedback">{fieldErrors.email}</div>
            )}
          </div>
          <div className="form-group">
            <label>Password</label>
            <input
              type="password"
              className={
                !fieldErrors.password
                  ? "form-control"
                  : "form-control is-invalid"
              }
              name="password"
              value={password}
              onChange={this.handleChange}
            />
            {fieldErrors.password && (
              <div className="invalid-feedback">{fieldErrors.password}</div>
            )}
          </div>
          <button type="submit" className="btn btn-primary">
            Submit
          </button>
          {registerError && (
            <div className="alert alert-danger" role="alert">
              {registerError}
            </div>
          )}
        </form>
        <br />
        {JSON.stringify(this.state)}
      </div>
    );
  }
}

export default App;

Поэтому при возникновении ошибки проверки форма будет выглядеть следующим образом:

enter image description here

И когда «пользователь уже зарегистрирован как ошибка», форма проверки будет выглядеть так:

enter image description here

Доступ к приложению реакции можно получить из следующих кодов:https://codesandbox.io/s/gracious-mccarthy-kluor

0 голосов
/ 01 ноября 2019

Приведенный выше код выглядит хорошо, так как эта строка кода явно проверяет наличие дубликатов электронной почты в MongoDB

>if (user) {
        >  return res
          >  .status(400)
          >  .send(`An account with the email ${req.body.email} already exists`);
       > } else {...
...