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.ts 3.1KB

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