aboutsummaryrefslogtreecommitdiffstats
path: root/models/User.js
blob: bcf25232b855d9e9f8dff45ad405ade1b8ce899e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
const mongoose = require('mongoose')
const bcrypt = require('bcryptjs')
const { nanoid } = require('nanoid')

const userResponse = u => ({
  _id: u._id,
  email: u.email,
  isVerified: u.isVerified,
  noteList: u.noteList,
  theme: u.theme,
  language: u.language
})

const userSchema = new mongoose.Schema({
  email: {
    type: String,
    trim: true,
    lowercase: true,
    unique: true,
    required: true,
    minlength: 6,
    maxlength: 255,
    validate (value) {
      if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
        throw new Error('Wrong email address')
      }
    }
  },
  password: {
    type: String,
    required: true,
    minlength: 6,
    maxlength: 1024
  },
  isVerified: {
    type: Boolean,
    default: false
  },
  verificationKey: {
    type: String,
    default: () => nanoid(6)
  },
  noteList: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'NoteList',
    required: true
  },
  theme: { type: String, default: () => 'green' },
  language: { type: String, default: () => 'en' },
  created_at: { type: Date, default: Date.now },
  updated_at: { type: Date, default: Date.now }
})

userSchema.statics.findByCredentials = async function (email, password) {
  const user = await User.findOne({ email })

  if (!user) {
    throw new Error('Unable to login')
  }

  const isMatch = await bcrypt.compare(password, user.password)

  if (!isMatch) {
    throw new Error('Unable to login')
  }

  return userResponse(user)
}

userSchema.statics.getVerificationKey = async function (email) {
  const { verificationKey: key } = await User.findOne({ email })

  if (!key) {
    throw new Error('Could not verify user')
  }

  return key
}

userSchema.statics.verifyUser = async function (_id, key) {
  const user = await User.findOneAndUpdate({ _id, verificationKey: key }, { isVerified: true, verificationKey: nanoid(10) }, { new: true })

  if (!user) {
    throw new Error('Could not verify user')
  }

  return userResponse(user)
}

userSchema.statics.saveSettings = async function ({ _id, theme, language }) {
  const user = await User.findOneAndUpdate({ _id }, { theme, language }, { new: true })

  if (!user) {
    throw new Error('Could not save settings')
  }

  return userResponse(user)
}

userSchema.statics.state = async function (_id) {
  const user = await User.findOne({ _id })

  if (!user) {
    return { isLoggedIn: false }
  } else if (!user.isVerified) {
    return { isVerified: false }
  }

  return {}
}

userSchema.pre('save', async function (next) {
  const user = this

  if (user.isModified('password')) {
    user.password = await bcrypt.hash(user.password, 8)
  }

  user.updated_at = Date.now()

  next()
})

const User = mongoose.models.User || mongoose.model('User', userSchema)

export default User