Skip to content

Commit 95d4c00

Browse files
authored
Merge pull request #396 from Real-Dev-Squad/develop
develop into main
2 parents a24b132 + 3685b64 commit 95d4c00

File tree

9 files changed

+249
-47
lines changed

9 files changed

+249
-47
lines changed

constants/users.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
11
const userStatusEnum = ['ooo', 'idle', 'active']
2-
module.exports = userStatusEnum
2+
const ROLES = {
3+
ADMIN: 'admin',
4+
APPOWNER: 'app_owner',
5+
DEFAULT: 'default',
6+
MEMBER: 'member',
7+
SUPERUSER: 'super_user'
8+
}
9+
module.exports = { userStatusEnum, ROLES }

controllers/members.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
const { fetchMembers, migrateUsers, deleteIsMemberProperty } = require('../models/members')
1+
const { ROLES } = require('../constants/users')
2+
const { fetchUsers, migrateUsers, deleteIsMemberProperty, fetchUsersWithRole } = require('../models/members')
23
const tasks = require('../models/tasks')
34

45
/**
@@ -10,11 +11,11 @@ const tasks = require('../models/tasks')
1011

1112
const getMembers = async (req, res) => {
1213
try {
13-
const allMembers = await fetchMembers()
14+
const allUsers = await fetchUsers()
1415

1516
return res.json({
16-
message: allMembers.length ? 'Members returned successfully!' : 'No member found',
17-
members: allMembers
17+
message: allUsers.length ? 'Members returned successfully!' : 'No member found',
18+
members: allUsers
1819
})
1920
} catch (error) {
2021
logger.error(`Error while fetching all members: ${error}`)
@@ -31,9 +32,9 @@ const getMembers = async (req, res) => {
3132

3233
const getIdleMembers = async (req, res) => {
3334
try {
34-
const allMembers = await fetchMembers()
35+
const onlyMembers = await fetchUsersWithRole(ROLES.MEMBER)
3536
const taskParticipants = await tasks.fetchActiveTaskMembers()
36-
const idleMembers = allMembers?.filter(({ id }) => !taskParticipants.has(id))
37+
const idleMembers = onlyMembers?.filter(({ id }) => !taskParticipants.has(id))
3738
const idleMemberUserNames = idleMembers?.map((member) => member.username)
3839

3940
return res.json({

controllers/tasks.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const getUserTasks = async (req, res) => {
5757
const { username } = req.params
5858
let allTasks = []
5959

60-
if (!Object.values(TASK_STATUS).includes(status)) {
60+
if (status && !Object.values(TASK_STATUS).includes(status)) {
6161
return res.boom.notFound('Status not found!')
6262
}
6363

middlewares/validators/user.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const joi = require('joi')
2-
const userStatusEnum = require('../../constants/users')
2+
const { userStatusEnum } = require('../../constants/users')
33

44
const updateUser = async (req, res, next) => {
55
const schema = joi.object().keys({

models/members.js

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ const firestore = require('../utils/firestore')
77
const userModel = firestore.collection('users')
88

99
/**
10-
* Fetches the data about our members
10+
* Fetches the data about our users
1111
* @return {Promise<userModel|Array>}
1212
*/
1313

14-
const fetchMembers = async () => {
14+
const fetchUsers = async () => {
1515
try {
1616
const snapshot = await userModel.get()
1717

@@ -98,8 +98,37 @@ const deleteIsMemberProperty = async () => {
9898
}
9999
}
100100

101+
/**
102+
* Fetches the data about our users with roles
103+
* @return {Promise<userModel|Array>}
104+
*/
105+
106+
const fetchUsersWithRole = async (role) => {
107+
try {
108+
const snapshot = await userModel.where(`roles.${role}`, '==', true).get()
109+
const onlyMembers = []
110+
111+
if (!snapshot.empty) {
112+
snapshot.forEach((doc) => {
113+
onlyMembers.push({
114+
id: doc.id,
115+
...doc.data(),
116+
phone: undefined,
117+
email: undefined,
118+
tokens: undefined
119+
})
120+
})
121+
}
122+
return onlyMembers
123+
} catch (err) {
124+
logger.error('Error retrieving members data with roles of member', err)
125+
throw err
126+
}
127+
}
128+
101129
module.exports = {
102-
fetchMembers,
130+
fetchUsers,
103131
migrateUsers,
104-
deleteIsMemberProperty
132+
deleteIsMemberProperty,
133+
fetchUsersWithRole
105134
}

models/tasks.js

Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const firestore = require('../utils/firestore')
22
const tasksModel = firestore.collection('tasks')
33
const userUtils = require('../utils/users')
4-
const { fromFirestoreData, toFirestoreData } = require('../utils/tasks')
4+
const { fromFirestoreData, toFirestoreData, buildTasks } = require('../utils/tasks')
55
const { TASK_TYPE, TASK_STATUS } = require('../constants/tasks')
66

77
/**
@@ -43,13 +43,7 @@ const updateTask = async (taskData, taskId = null) => {
4343
const fetchTasks = async () => {
4444
try {
4545
const tasksSnapshot = await tasksModel.get()
46-
const tasks = []
47-
tasksSnapshot.forEach((task) => {
48-
tasks.push({
49-
id: task.id,
50-
...task.data()
51-
})
52-
})
46+
const tasks = buildTasks(tasksSnapshot)
5347
const promises = tasks.map(async (task) => fromFirestoreData(task))
5448
const updatedTasks = await Promise.all(promises)
5549
return updatedTasks
@@ -120,43 +114,26 @@ const fetchUserTasks = async (username, statuses = []) => {
120114
return { userNotFound: true }
121115
}
122116

123-
let tasksSnapshot = []
124-
let assigneeSnapshot = []
117+
let groupTasksSnapshot = []
118+
let featureTasksSnapshot = []
125119

126120
if (statuses && statuses.length) {
127-
tasksSnapshot = await tasksModel.where('participants', 'array-contains', userId)
121+
groupTasksSnapshot = await tasksModel.where('participants', 'array-contains', userId)
128122
.where('status', 'in', statuses)
129123
.get()
130-
assigneeSnapshot = await tasksModel.where('assignee', '==', userId)
124+
featureTasksSnapshot = await tasksModel.where('assignee', '==', userId)
131125
.where('status', 'in', statuses)
132126
.get()
133127
} else {
134-
tasksSnapshot = await tasksModel.where('participants', 'array-contains', userId)
128+
groupTasksSnapshot = await tasksModel.where('participants', 'array-contains', userId)
135129
.get()
136130

137-
assigneeSnapshot = await tasksModel.where('assignee', '==', userId)
131+
featureTasksSnapshot = await tasksModel.where('assignee', '==', userId)
138132
.get()
139133
}
140134

141-
const tasks = []
142-
143-
if (!tasksSnapshot.empty) {
144-
tasksSnapshot.forEach((task) => {
145-
tasks.push({
146-
id: task.id,
147-
...task.data()
148-
})
149-
})
150-
}
151-
152-
if (!assigneeSnapshot.empty) {
153-
assigneeSnapshot.forEach((task) => {
154-
tasks.push({
155-
id: task.id,
156-
...task.data()
157-
})
158-
})
159-
}
135+
const groupTasks = buildTasks(groupTasksSnapshot)
136+
const tasks = buildTasks(featureTasksSnapshot, groupTasks)
160137

161138
const promises = tasks.map(async (task) => fromFirestoreData(task))
162139
const updatedTasks = await Promise.all(promises)

test/fixtures/wallet/wallet.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/* Import fixtures
2+
*
3+
* Sample wallet for tests
4+
*
5+
* @return {Object}
6+
*/
7+
8+
const walletKeys = [
9+
'id',
10+
'data'
11+
]
12+
13+
const walletBodyKeys = [
14+
'message',
15+
'wallet'
16+
]
17+
18+
const walletDataKeys = [
19+
'userId',
20+
'isActive',
21+
'currencies'
22+
]
23+
24+
module.exports = { walletBodyKeys, walletKeys, walletDataKeys }

test/integration/wallet.test.js

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
const chai = require('chai')
2+
const { expect } = chai
3+
const chaiHttp = require('chai-http')
4+
5+
const app = require('../../server')
6+
const authService = require('../../services/authService')
7+
8+
const addUser = require('../utils/addUser')
9+
const cleanDb = require('../utils/cleanDb')
10+
const usersUtils = require('../../utils/users')
11+
12+
const userData = require('../fixtures/user/user')()
13+
const { walletBodyKeys, walletKeys, walletDataKeys } = require('../fixtures/wallet/wallet')
14+
15+
const defaultUser = userData[0]
16+
const newUser = userData[3]
17+
const superUser = userData[4]
18+
19+
const config = require('config')
20+
const cookieName = config.get('userToken.cookieName')
21+
22+
chai.use(chaiHttp)
23+
24+
describe('Wallet', function () {
25+
let authToken
26+
let userId
27+
let userName
28+
29+
beforeEach(async function () {
30+
userId = await addUser(defaultUser)
31+
authToken = authService.generateAuthToken({ userId })
32+
userName = await usersUtils.getUsername(userId)
33+
})
34+
35+
afterEach(async function () {
36+
await cleanDb()
37+
})
38+
39+
describe('GET /wallet', function () {
40+
it('Should return wallet information of the logged in user', function (done) {
41+
chai
42+
.request(app)
43+
.get('/wallet')
44+
.set('cookie', `${cookieName}=${authToken}`)
45+
.end((error, response) => {
46+
if (error) {
47+
return done(error)
48+
}
49+
50+
expect(response).to.have.status(200)
51+
expect(response.body).to.be.a('object')
52+
expect(response.body).to.have.all.keys(...walletBodyKeys)
53+
expect(response.body.message).to.be.equal('Wallet returned successfully for user')
54+
expect(response.body.wallet).to.be.a('object')
55+
expect(response.body.wallet).to.have.all.keys(...walletKeys)
56+
expect(response.body.wallet.data).to.have.all.keys(...walletDataKeys)
57+
58+
return done()
59+
})
60+
})
61+
62+
it('Should return the user their own wallet with 1000 dineros loaded', function (done) {
63+
chai
64+
.request(app)
65+
.get('/wallet')
66+
.set('cookie', `${cookieName}=${authToken}`)
67+
.end((error, response) => {
68+
if (error) {
69+
return done(error)
70+
}
71+
72+
expect(response).to.have.status(200)
73+
expect(response.body.wallet.data.userId).to.be.equal(userId)
74+
expect(response.body.message).to.be.equal('Wallet returned successfully for user')
75+
expect(response.body.wallet.data.currencies.dinero).to.be.equal(1000)
76+
77+
return done()
78+
})
79+
})
80+
81+
it('Without cookie access should be unauthorized', function (done) {
82+
chai
83+
.request(app)
84+
.get('/wallet')
85+
.end((error, response) => {
86+
if (error) {
87+
return done(error)
88+
}
89+
90+
expect(response).to.have.status(401)
91+
expect(response.body.error).to.be.equal('Unauthorized')
92+
expect(response.body.message).to.be.equal('Unauthenticated User')
93+
94+
return done()
95+
})
96+
})
97+
})
98+
99+
describe('GET /wallet/:username', function () {
100+
let newUserId
101+
let newUserAuthToken
102+
103+
let superUserId
104+
let superUserAuthToken
105+
106+
before(async function () {
107+
newUserId = await addUser(newUser)
108+
newUserAuthToken = authService.generateAuthToken({ userId: newUserId })
109+
110+
superUserId = await addUser(superUser)
111+
superUserAuthToken = authService.generateAuthToken({ userId: superUserId })
112+
})
113+
114+
it('Should return wallet when trying to access someone else\'s wallet, using authorized user (super_user)', function (done) {
115+
chai
116+
.request(app)
117+
.get(`/wallet/${userName}`)
118+
.set('cookie', `${cookieName}=${superUserAuthToken}`)
119+
.end((error, response) => {
120+
if (error) {
121+
return done(error)
122+
}
123+
124+
expect(response).to.have.status(200)
125+
expect(response.body.wallet.data.userId).to.be.equal(userId)
126+
expect(response.body.message).to.be.equal('Wallet returned successfully')
127+
128+
return done()
129+
})
130+
})
131+
132+
it('Should return unauthorized error when trying to access someone else\'s wallet when not authorized', function (done) {
133+
chai
134+
.request(app)
135+
.get(`/wallet/${userName}`)
136+
.set('cookie', `${cookieName}=${newUserAuthToken}`)
137+
.end((error, response) => {
138+
if (error) {
139+
return done(error)
140+
}
141+
142+
expect(response).to.have.status(401)
143+
expect(response.body.error).to.be.equal('Unauthorized')
144+
expect(response.body.message).to.be.equal('You are not authorized for this action.')
145+
146+
return done()
147+
})
148+
})
149+
})
150+
})

utils/tasks.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,21 @@ const toFirestoreData = async (task) => {
4545
return updatedTask
4646
}
4747

48+
const buildTasks = (tasks, initialTaskArray = []) => {
49+
if (!tasks.empty) {
50+
tasks.forEach((task) => {
51+
initialTaskArray.push({
52+
id: task.id,
53+
...task.data()
54+
})
55+
})
56+
}
57+
58+
return initialTaskArray
59+
}
60+
4861
module.exports = {
4962
fromFirestoreData,
50-
toFirestoreData
63+
toFirestoreData,
64+
buildTasks
5165
}

0 commit comments

Comments
 (0)