You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

user.js 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import {
  2. hashPassword,
  3. verifyPassword,
  4. } from '../utils/helpers/hashPasswordHelpers';
  5. const mongoose = require('mongoose');
  6. const validator = require('validator');
  7. const UserSchema = new mongoose.Schema(
  8. {
  9. fullName: {
  10. type: String,
  11. required: [true, 'Please provide a name.'],
  12. maxlength: [60, 'Name cannot be more than 60 characters'],
  13. trim: true,
  14. },
  15. username: {
  16. type: String,
  17. required: [true, 'Please provide an username.'],
  18. unique: [true, 'Username must be unique.'],
  19. maxlength: [60, 'Name cannot be more than 60 characters'],
  20. trim: true,
  21. },
  22. email: {
  23. type: String,
  24. unique: [true, 'Email must be unique.'],
  25. required: [true, 'Please provide an email.'],
  26. trim: true,
  27. lowercase: true,
  28. validate(value) {
  29. if (!validator.isEmail(value)) {
  30. throw new Error('Email is invalid');
  31. }
  32. },
  33. },
  34. password: {
  35. type: String,
  36. required: [true, 'Please provide a password.'],
  37. minlength: 7,
  38. trim: true,
  39. validate(value) {
  40. if (value.toLowerCase().includes('password')) {
  41. throw new Error('Password cannot contain "password"');
  42. }
  43. },
  44. },
  45. country: {
  46. type: String,
  47. required: [true, 'Please provide a country.'],
  48. trim: true,
  49. },
  50. city: {
  51. type: String,
  52. required: [true, 'Please provide a city.'],
  53. trim: true,
  54. },
  55. address: {
  56. type: String,
  57. required: [true, 'Please provide an address.'],
  58. trim: true,
  59. },
  60. address2: {
  61. type: String,
  62. trim: true,
  63. },
  64. postcode: {
  65. type: String,
  66. required: [true, 'Please provide a postal code.'],
  67. },
  68. },
  69. {
  70. toJSON: { virtuals: true }, // So `res.json()` and other `JSON.stringify()` functions include virtuals
  71. toObject: { virtuals: true }, // So `console.log()` and other functions that use `toObject()` include virtuals
  72. }
  73. );
  74. UserSchema.virtual('orders', {
  75. ref: 'Order',
  76. localField: '_id',
  77. foreignField: 'owner',
  78. });
  79. UserSchema.statics.findByCredentials = async (username, password) => {
  80. const user = await User.findOne({ username });
  81. if (!user) {
  82. throw new Error('Unable to login');
  83. }
  84. const isMatch = await verifyPassword(password, user.password);
  85. if (!isMatch) {
  86. throw new Error('Unable to login');
  87. }
  88. const userData = {
  89. fullName: user.fullName,
  90. email: user.email,
  91. address: user.address,
  92. address2: user.address2,
  93. city: user.city,
  94. country: user.country,
  95. postcode: user.postcode,
  96. orders: user.orders,
  97. _id: user._id,
  98. };
  99. return userData;
  100. };
  101. UserSchema.pre('save', async function (next) {
  102. const user = this;
  103. if (user.isModified('password')) {
  104. user.password = await hashPassword(user.password);
  105. }
  106. next();
  107. });
  108. const User = mongoose.models.User || mongoose.model('User', UserSchema, 'User');
  109. module.exports = User;