• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

atlp-rwanda / e-commerce-bitcrafters-bn / 29d11716-6ac4-4755-b55c-36ca76e8cfdd

08 Jun 2024 10:32AM UTC coverage: 93.84% (-0.5%) from 94.373%
29d11716-6ac4-4755-b55c-36ca76e8cfdd

push

circleci

web-flow
feature(charts):Users should be able to chat on the App (#96)

[Delivers #187364758]

384 of 427 branches covered (89.93%)

Branch coverage included in aggregate %.

49 of 56 new or added lines in 5 files covered. (87.5%)

7 existing lines in 3 files now uncovered.

1246 of 1310 relevant lines covered (95.11%)

5.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.24
/src/controllers/UserController.ts
1
import { Request, Response } from 'express'
2
import User, { UserRole } from '../database/models/userModel'
2✔
3

4
import {
2✔
5
  getUserProfileById,
6
  updateUserById,
7
  updateUserProfileById,
8
  getUserById,
9
} from '../services/userServices'
10

11
import {
2✔
12
  validateAndRetrieveToken,
13
  deleteTokenByUserId,
14
  validateRedisToken,
15
} from '../services/tokenServices'
16
import { hashPassword } from '../utils/passwords'
2✔
17
import { generateResetToken, generateToken } from '../utils/jwt'
2✔
18
import { verificationsEmailTemplate } from '../utils/emailTemplates'
2✔
19
import Token from '../database/models/tokenModel'
2✔
20
import sendMail from '../utils/sendEmail'
2✔
21
import { NODEMAILER_BASE_URL } from '../config'
2✔
22
import redisClient from '../utils/redisConfiguration'
2✔
23
/**
24
 * User Controller class
25
 */
26
export default class UserController {
2✔
27
  /**
28
   * Signup method for user registration
29
   * @param {Request} req - Express request object
30
   * @param {Response} res - Express response object
31
   * @returns {Promise<Response>} Promise that resolves to an Express response
32
   */
33
  static async signup(req: Request, res: Response): Promise<Response> {
34
    try {
12✔
35
      const { email, password, username } = req.body
12✔
36
      const existingUser = await User.findOne({ where: { email } })
12✔
37
      if (existingUser) {
12✔
38
        return res.status(409).json({
6✔
39
          message: 'This user already exists',
40
        })
41
      }
42
      const hashedpassword = hashPassword(password)
6✔
43

44
      const newUser = new User({
6✔
45
        username,
46
        email,
47
        password: (await hashedpassword).toString(),
48
        verified: false,
49
      })
50

51
      await newUser.save()
6✔
52

53
      const token = generateToken({
2✔
54
        id: newUser.id,
55
        email: newUser.email,
56
        username: newUser.username,
57
      })
58
      const baseUrl = `${NODEMAILER_BASE_URL}users/verify/${token}`
2✔
59

60
      const html = verificationsEmailTemplate(newUser.username, baseUrl)
2✔
61

62
      Promise.all([
2✔
63
        await sendMail(email, 'Verify Account', html),
64
        await Token.create({
65
          userId: newUser.id,
66
          token,
67
        }),
68
      ])
69

70
      return res.status(201).json({
2✔
71
        message: 'Account Created successfully, verify your email to continue',
72
      })
73
    } catch (error) {
74
      res.status(500).json({ message: 'Internal server error', error })
4✔
75
    }
76
  }
77

78
  /**
79
   * verifyEmail method for verifying a user
80
   * @param {Request} req - Express request object
81
   * @param {Response} res - Express response object
82
   * @returns {Promise<Response>} Promise that resolves to an Express response
83
   */
84
  static async verifyEmail(req: Request, res: Response): Promise<Response> {
85
    try {
26✔
86
      const { token } = req.params
26✔
87

88
      const decodedToken = await validateAndRetrieveToken(token)
26✔
89

90
      if (!decodedToken) {
26✔
91
        return res.status(401).send({ message: 'Invalid token' })
22✔
92
      }
93

94
      const user = await getUserById(decodedToken.id)
4✔
95

96
      if (!user) {
4✔
97
        return res
2✔
98
          .status(400)
99
          .send({ message: 'Invalid token or user not found' })
100
      }
101

102
      await Promise.all([
2✔
103
        user.update({ verified: true }),
104
        deleteTokenByUserId(decodedToken.id),
105
      ])
106

UNCOV
107
      res.status(201).send({ message: 'Email verified successfully' })
×
108
    } catch (error) {
109
      res.status(500).send({ message: 'Internal server error' })
6✔
110
    }
111
  }
112

113
  /**
114
   * updateUser method for updating user information
115
   * @param {Request} req - Express request object
116
   * @param {Response} res - Express response object
117
   * @returns {Promise<Response>} Promise that resolves to an Express response
118
   */
119
  static async updateUser(req: Request, res: Response) {
120
    try {
6✔
121
      const { id } = req.user
6✔
122
      const fieldsToUpdate = req.body
6✔
123
      const { username, email } = req.body
6✔
124
      if (Object.keys(fieldsToUpdate).length === 0) {
6✔
125
        return res.status(400).json({ message: 'nothing to update' })
2✔
126
      }
127

128
      if (username || email) await updateUserById({ username, email }, id)
4!
129
      await updateUserProfileById(fieldsToUpdate, id)
4✔
130

131
      const updateduser = await getUserProfileById(id)
2✔
132
      return res.status(200).json(updateduser)
2✔
133
    } catch (err: unknown) {
134
      const errors = err as Error
2✔
135
      return res.status(500).json(errors.message)
2✔
136
    }
137
  }
138

139
  /**
140
   * getUser method for getting user profile
141
   * @param {Request} req - Express request object
142
   * @param {Response} res - Express response object
143
   * @returns {Promise<Response>} Promise that resolves to an Express response
144
   */
145
  static async getUser(req: Request, res: Response): Promise<Response> {
146
    try {
4✔
147
      const { id } = req.user
4✔
148
      const myprofile = await getUserProfileById(id)
4✔
149
      return res.status(200).json(myprofile)
2✔
150
    } catch (err: unknown) {
151
      return res.status(500).json(err)
2✔
152
    }
153
  }
154

155
  /**
156
   * Handles OTP verification /Two factor authentication.
157
   * @param {Request} req - Express request object
158
   * @param {Response} res - Express response object
159
   * @returns {Promise<Response>} Promise that resolves to an Express response
160
   */
161
  static async twofaVerifyOtp(req: Request, res: Response): Promise<Response> {
162
    const { otp } = req.body
8✔
163
    const { email } = req.params
8✔
164
    try {
8✔
165
      const redisResult = await redisClient.get(email)
8✔
166
      if (!redisResult) {
6✔
167
        return res.status(404).json({ message: 'OTP token not found' })
2✔
168
      }
169
      const [storedOtp, storedToken] = redisResult.split('=')
4✔
170
      if (storedOtp !== otp) {
4✔
171
        return res.status(406).json({ message: 'Invalid One Time Password' })
2✔
172
      }
173
      await redisClient.del(email)
2✔
174
      return res
2✔
175
        .status(200)
176
        .json({ jwt: storedToken, message: 'Login successful' })
177
    } catch (error) {
178
      return res.status(500).json({ message: 'Internal server error' })
2✔
179
    }
180
  }
181

182
  /**
183
   * changeUserRole method for changing user role
184
   * @param {Request} req - Express request object
185
   * @param {Response} res - Express response object
186
   * @returns {Promise<Response>} Promise that resolves to an Express response
187
   */
188
  static async changeUserRole(req: Request, res: Response): Promise<Response> {
189
    try {
16✔
190
      const { userId } = req.params
16✔
191
      const { newRole } = req.body
16✔
192

193
      if (!userId || !newRole) {
16✔
194
        return res.status(400).json({ message: 'Bad request' })
6✔
195
      }
196

197
      if (
10✔
198
        ![UserRole.ADMIN, UserRole.BUYER, UserRole.SELLER].includes(newRole)
199
      ) {
200
        return res.status(400).json({ Message: 'Invalid role set', newRole })
4✔
201
      }
202

203
      const existingUser = await User.findOne({ where: { id: userId } })
6✔
204

205
      if (!existingUser) {
6✔
206
        return res.status(404).json({ message: 'User not found' })
2✔
207
      }
208

209
      existingUser.update({ userRole: newRole })
4✔
210
      return res.status(200).json({
2✔
211
        message: 'User role has been updated.',
212
        existingUser,
213
      })
214
    } catch (error) {
215
      res.status(400).json({ message: 'Error Occured', error })
2✔
216
    }
217
  }
218
  static async resetPasswordLink(
219
    req: Request,
220
    res: Response,
221
  ): Promise<Response> {
222
    try {
6✔
223
      const { email } = req.body
6✔
224
      const user = await User.findOne({ where: { email } })
6✔
225

226
      if (!user) {
4✔
227
        return res.status(404).json({ message: 'User not found' })
2✔
228
      }
229

230
      const token = generateResetToken({
2✔
231
        id: user.id,
232
        email: user.email,
233
        username: user.username,
234
      })
235

236
      const resetLink = `${NODEMAILER_BASE_URL}/users/reset-password/${token}`
×
237

238
      const msg = {
×
239
        to: user.email,
240
        subject: 'Password Reset Request',
241
        html: `<strong>Click on the link to reset your password: <a href="${resetLink}">RESET PASSWORD</a></strong>`,
242
      }
243

244
      await redisClient.setEx(token, 3000, token)
×
245
      await sendMail(msg.to, msg.subject, msg.html)
×
246
      return res.status(200).json({ message: 'Password reset email sent' })
×
247
    } catch (error) {
248
      return res.status(500).json({ error: error.message })
4✔
249
    }
250
  }
251

252
  static async newPassword(req: Request, res: Response): Promise<Response> {
253
    try {
10✔
254
      const { token } = req.params
10✔
255
      const { password } = req.body
10✔
256

257
      const redisToken = await redisClient.get(token)
10✔
258
      if (!redisToken) {
8✔
259
        return res.status(404).json({ message: 'Token not found or expired' })
2✔
260
      }
261

262
      const decodedToken = await validateRedisToken(redisToken)
6✔
263

264
      if (!decodedToken) {
6✔
265
        return res.status(401).json({ message: 'Invalid token' })
2✔
266
      }
267
      const user = await getUserById(decodedToken.id)
4✔
268
      if (!user) {
4✔
269
        return res.status(404).json({ message: 'User not found' })
2✔
270
      }
271

272
      const hashedPassword = await hashPassword(password)
2✔
273
      await user.update({ password: hashedPassword })
2✔
274
      await redisClient.del(token)
2✔
275

276
      return res
2✔
277
        .status(200)
278
        .json({ message: 'Password has been successfully reset' })
279
    } catch (error) {
280
      return res.status(500).json({ message: 'Internal server error' })
2✔
281
    }
282
  }
283
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc