@@ -6,10 +6,14 @@ const walletConstants = require("../constants/wallets");
6
6
7
7
const firestore = require ( "../utils/firestore" ) ;
8
8
const { fetchWallet, createWallet } = require ( "../models/wallets" ) ;
9
+ const { arraysHaveCommonItem } = require ( "../utils/array" ) ;
10
+ const { ALLOWED_FILTER_PARAMS } = require ( "../constants/users" ) ;
11
+ const { BATCH_SIZE_IN_CLAUSE } = require ( "../constants/firebase" ) ;
9
12
const userModel = firestore . collection ( "users" ) ;
10
13
const joinModel = firestore . collection ( "applicants" ) ;
11
14
const itemModel = firestore . collection ( "itemTags" ) ;
12
-
15
+ const userStatusModel = firestore . collection ( "usersStatus" ) ;
16
+ const { ITEM_TAG , USER_STATE } = ALLOWED_FILTER_PARAMS ;
13
17
/**
14
18
* Adds or updates the user data
15
19
*
@@ -126,7 +130,7 @@ const getSuggestedUsers = async (skill) => {
126
130
* @param query { search, next, prev, size, page }: Filter for users
127
131
* @return {Promise<userModel|Array> }
128
132
*/
129
- const fetchUsers = async ( query ) => {
133
+ const fetchPaginatedUsers = async ( query ) => {
130
134
try {
131
135
// INFO: default user size set to 100
132
136
// INFO: https://github.com/Real-Dev-Squad/website-backend/pull/873#discussion_r1064229932
@@ -175,6 +179,45 @@ const fetchUsers = async (query) => {
175
179
}
176
180
} ;
177
181
182
+ const fetchUsers = async ( usernames = [ ] ) => {
183
+ try {
184
+ const dbQuery = userModel ;
185
+ const filterdUsersWithDetails = [ ] ;
186
+
187
+ const groups = [ ] ;
188
+ for ( let i = 0 ; i < usernames . length ; i += BATCH_SIZE_IN_CLAUSE ) {
189
+ groups . push ( usernames . slice ( i , i + BATCH_SIZE_IN_CLAUSE ) ) ;
190
+ }
191
+
192
+ // For each group, write a separate query
193
+ const promises = groups . map ( ( group ) => {
194
+ return dbQuery . where ( "github_id" , "in" , group ) . get ( ) ;
195
+ } ) ;
196
+
197
+ const snapshots = await Promise . all ( promises ) ;
198
+
199
+ snapshots . forEach ( ( snapshot ) => {
200
+ snapshot . forEach ( ( doc ) => {
201
+ filterdUsersWithDetails . push ( {
202
+ id : doc . id ,
203
+ ...doc . data ( ) ,
204
+ phone : undefined ,
205
+ email : undefined ,
206
+ tokens : undefined ,
207
+ chaincode : undefined ,
208
+ } ) ;
209
+ } ) ;
210
+ } ) ;
211
+
212
+ return {
213
+ filterdUsersWithDetails,
214
+ } ;
215
+ } catch ( err ) {
216
+ logger . error ( "Error retrieving user data" , err ) ;
217
+ throw err ;
218
+ }
219
+ } ;
220
+
178
221
/**
179
222
* Fetches the user data from the the provided username or userId
180
223
*
@@ -292,9 +335,67 @@ const fetchUserSkills = async (id) => {
292
335
}
293
336
} ;
294
337
338
+ /**
339
+ * Fetches user data based on the filter query
340
+ *
341
+ * @param {Object } query - Object with query parameters
342
+ * @param {Array } query.levelId - Array of levelIds to filter the users on
343
+ * @param {Array } query.levelName - Array of levelNames to filter the users on
344
+ * @param {Array } query.levelNumber - Array of levelNumbers to filter the users on
345
+ * @param {Array } query.tagId - Array of tagIds to filter the users on
346
+ * @param {Array } query.state - Array of states to filter the users on
347
+ * @return {Promise<Array> } - Array of user documents that match the filter criteria
348
+ */
349
+
350
+ const getUsersBasedOnFilter = async ( query ) => {
351
+ const allQueryKeys = Object . keys ( query ) ;
352
+ const doesTagQueryExist = arraysHaveCommonItem ( ITEM_TAG , allQueryKeys ) ;
353
+ const doesStateQueryExist = arraysHaveCommonItem ( USER_STATE , allQueryKeys ) ;
354
+
355
+ const calls = {
356
+ item : itemModel ,
357
+ state : userStatusModel ,
358
+ } ;
359
+ calls . item = calls . item . where ( "itemType" , "==" , "USER" ) . where ( "tagType" , "==" , "SKILL" ) ;
360
+
361
+ Object . entries ( query ) . forEach ( ( [ key , value ] ) => {
362
+ const isTagKey = ITEM_TAG . includes ( key ) ;
363
+ const isStateKey = USER_STATE . includes ( key ) ;
364
+ const isValueArray = Array . isArray ( value ) ;
365
+
366
+ if ( isTagKey ) {
367
+ calls . item = isValueArray ? calls . item . where ( key , "in" , value ) : calls . item . where ( key , "==" , value ) ;
368
+ } else if ( isStateKey ) {
369
+ calls . state = isValueArray
370
+ ? calls . state . where ( "currentStatus.state" , "in" , value )
371
+ : calls . state . where ( "currentStatus.state" , "==" , value ) ;
372
+ }
373
+ } ) ;
374
+
375
+ const tagItems = doesTagQueryExist ? ( await calls . item . get ( ) ) . docs . map ( ( doc ) => ( { id : doc . id , ...doc . data ( ) } ) ) : [ ] ;
376
+ const stateItems = doesStateQueryExist
377
+ ? ( await calls . state . get ( ) ) . docs . map ( ( doc ) => ( { id : doc . id , ...doc . data ( ) } ) )
378
+ : [ ] ;
379
+ let finalItems = [ ] ;
380
+
381
+ if ( doesTagQueryExist && doesStateQueryExist ) {
382
+ const stateItemIds = new Set ( stateItems . map ( ( item ) => item . userId ) ) ;
383
+ finalItems = tagItems . filter ( ( item ) => stateItemIds . has ( item . itemId ) ) . map ( ( item ) => item . itemId ) ;
384
+ } else if ( doesStateQueryExist ) {
385
+ finalItems = stateItems . map ( ( item ) => item . userId ) ;
386
+ } else if ( doesTagQueryExist ) {
387
+ finalItems = tagItems . map ( ( item ) => item . itemId ) ;
388
+ }
389
+
390
+ finalItems = [ ...new Set ( finalItems ) ] ;
391
+ const userRefs = finalItems . map ( ( itemId ) => userModel . doc ( itemId ) ) ;
392
+ const userDocs = ( await firestore . getAll ( ...userRefs ) ) . map ( ( doc ) => ( { id : doc . id , ...doc . data ( ) } ) ) ;
393
+ return userDocs ;
394
+ } ;
395
+
295
396
module . exports = {
296
397
addOrUpdate,
297
- fetchUsers ,
398
+ fetchPaginatedUsers ,
298
399
fetchUser,
299
400
setIncompleteUserDetails,
300
401
initializeUser,
@@ -304,4 +405,6 @@ module.exports = {
304
405
getJoinData,
305
406
getSuggestedUsers,
306
407
fetchUserSkills,
408
+ fetchUsers,
409
+ getUsersBasedOnFilter,
307
410
} ;
0 commit comments