Просмотр исходного кода

:construction: Continued filtering logic for initial survey answers

juan-filtering-match-pool
tomit4 2 лет назад
Родитель
Сommit
9966fff8ce

+ 1
- 53
backend/db/data-generator/mock.js Просмотреть файл

431
         // TODO: remove from mock data once bare bones matching logic can show poorly matched matches...
431
         // TODO: remove from mock data once bare bones matching logic can show poorly matched matches...
432
         {
432
         {
433
             tag_association_id: 50,
433
             tag_association_id: 50,
434
-            profile_id: 136,
434
+            profile_id: 139,
435
             grouping_id: 2,
435
             grouping_id: 2,
436
             tag_id: 7,
436
             tag_id: 7,
437
             is_deleted: false,
437
             is_deleted: false,
682
             can_edit: false,
682
             can_edit: false,
683
             is_active: true,
683
             is_active: true,
684
         },
684
         },
685
-        // NOTE: profile_id 147 is chosen based off of GENERATED data,
686
-        // after running 'npm run generate', replace 147 in mock to next profile_id to be genearted
687
-        // i.e. last profile_id number + 1
688
-        // TODO: remove from mock data once bare bones matching logic can show poorly matched matches...
689
-        {
690
-            membership_id: 3,
691
-            profile_id: 147,
692
-            grouping_id: 2,
693
-            membership_type: 'participant',
694
-            can_edit: false,
695
-            is_active: true,
696
-        },
697
         {
685
         {
698
             membership_id: 4,
686
             membership_id: 4,
699
             profile_id: 46,
687
             profile_id: 46,
768
             target_id: 46,
756
             target_id: 46,
769
             is_deleted: false,
757
             is_deleted: false,
770
         },
758
         },
771
-        // NOTE: profile_id 147 is chosen based off of GENERATED data,
772
-        // after running 'npm run generate', replace 147 in mock to next profile_id to be generated
773
-        // i.e. last profile_id number + 1
774
-        // TODO: remove from mock data once bare bones matching logic can show poorly matched matches...
775
-        {
776
-            match_queue_id: 17,
777
-            profile_id: 147,
778
-            target_id: 46,
779
-            is_deleted: false,
780
-        },
781
-        {
782
-            match_queue_id: 18,
783
-            profile_id: 147,
784
-            target_id: 46,
785
-            is_deleted: false,
786
-        },
787
-        {
788
-            match_queue_id: 19,
789
-            profile_id: 147,
790
-            target_id: 44,
791
-            is_deleted: false,
792
-        },
793
-        {
794
-            match_queue_id: 20,
795
-            profile_id: 147,
796
-            target_id: 43,
797
-            is_deleted: false,
798
-        },
799
-        {
800
-            match_queue_id: 21,
801
-            profile_id: 147,
802
-            target_id: 42,
803
-            is_deleted: false,
804
-        },
805
-        {
806
-            match_queue_id: 22,
807
-            profile_id: 147,
808
-            target_id: 41,
809
-            is_deleted: false,
810
-        },
811
     ],
759
     ],
812
 }
760
 }

+ 9
- 9
backend/db/seeds/04-responses.js Просмотреть файл

12
         responses = [...responses, ...data.responses]
12
         responses = [...responses, ...data.responses]
13
     }
13
     }
14
 }
14
 }
15
-
16
 /**
15
 /**
17
  * Prevent seeding responses for
16
  * Prevent seeding responses for
18
  * profile ids so we can test oboarding
17
  * profile ids so we can test oboarding
19
  */
18
  */
20
-responses = dataSort(responses, 'response_id').filter(
21
-    response => !ignore.includes(response.profile_id),
22
-)
19
+// responses = dataSort(responses, 'response_id').filter(
20
+// response => !ignore.includes(response.profile_id),
21
+// )
23
 
22
 
24
 exports.seed = async knex => {
23
 exports.seed = async knex => {
25
     await knex('responses').del()
24
     await knex('responses').del()
26
     let responsesToPush = []
25
     let responsesToPush = []
27
-    let len = responses.length
26
+    const len = responses.length
28
     for (let i = 1; i <= len; i += 1) {
27
     for (let i = 1; i <= len; i += 1) {
29
         responsesToPush.push(responses.shift())
28
         responsesToPush.push(responses.shift())
30
-        if (i % batchSize === 0 || i > responses.length) {
31
-            // await knex('responses').insert(responsesToPush)
32
-            responsesToPush = []
33
-        }
29
+        // if (i % batchSize === 0 || i > responses.length) {
30
+        // await knex('responses').insert(responsesToPush)
31
+        // responsesToPush = []
32
+        // }
34
     }
33
     }
34
+    await knex('responses').insert(responsesToPush)
35
 }
35
 }

+ 26
- 17
backend/lib/routes/filter/get.js Просмотреть файл

1
 'use strict'
1
 'use strict'
2
 
2
 
3
+// NOTE: Current Implementation does not require this route
4
+// (see Auth.vue in components/onboarding and queue route with filter.js)
3
 const Joi = require('joi')
5
 const Joi = require('joi')
4
 const apiSchema = require('../../schemas/api')
6
 const apiSchema = require('../../schemas/api')
5
 const errorSchema = require('../../schemas/errors')
7
 const errorSchema = require('../../schemas/errors')
10
     handlerType: 'filter',
12
     handlerType: 'filter',
11
     docs: {
13
     docs: {
12
         description: 'Filter match pool',
14
         description: 'Filter match pool',
13
-        notes: 'Returns filtered subset of match pool'
14
-    }
15
+        notes: 'Returns filtered subset of match pool',
16
+    },
15
 }
17
 }
16
 
18
 
17
 const validators = {
19
 const validators = {
18
     query: Joi.object({
20
     query: Joi.object({
19
         match_pool: Joi.array().items(profileSchema.single),
21
         match_pool: Joi.array().items(profileSchema.single),
20
         distance: Joi.string(),
22
         distance: Joi.string(),
21
-        presence: Joi.string()
22
-    })
23
+        presence: Joi.string(),
24
+    }),
23
 }
25
 }
24
 
26
 
25
 const responseSchemas = {
27
 const responseSchemas = {
26
     filteredMatchPool: filterSchema.matchPool, // array of profiles
28
     filteredMatchPool: filterSchema.matchPool, // array of profiles
27
-    error: errorSchema.single
29
+    error: errorSchema.single,
28
 }
30
 }
29
 
31
 
30
 module.exports = {
32
 module.exports = {
31
     method: 'GET',
33
     method: 'GET',
32
     path: '/',
34
     path: '/',
33
-    options:{
35
+    options: {
34
         ...pluginConfig.docs,
36
         ...pluginConfig.docs,
35
         tags: ['api'],
37
         tags: ['api'],
36
         auth: false,
38
         auth: false,
38
         handler: async function (request, h) {
40
         handler: async function (request, h) {
39
             const { filterService } = request.server.services()
41
             const { filterService } = request.server.services()
40
             let matchPool = request.query.match_pool
42
             let matchPool = request.query.match_pool
41
-            matchPool = filterService.byDistance(matchPool, request.query.distance)
42
-            matchPool = filterService.byPresence(matchPool, request.query.presence)
43
-      
43
+            matchPool = filterService.byDistance(
44
+                matchPool,
45
+                request.query.distance,
46
+            )
47
+            matchPool = filterService.byPresence(
48
+                matchPool,
49
+                request.query.presence,
50
+            )
44
             try {
51
             try {
45
-                return h.response(({
46
-                    ok:true,
47
-                    handler: pluginConfig.handlerType,
48
-                    data: matchPool
49
-                })).code(200)
52
+                return h
53
+                    .response({
54
+                        ok: true,
55
+                        handler: pluginConfig.handlerType,
56
+                        data: matchPool,
57
+                    })
58
+                    .code(200)
50
             } catch (err) {
59
             } catch (err) {
51
                 return h
60
                 return h
52
                     .response({
61
                     .response({
53
                         ok: false,
62
                         ok: false,
54
                         handler: pluginConfig.handlerType,
63
                         handler: pluginConfig.handlerType,
55
-                        data: {error: `${err}`}
64
+                        data: { error: `${err}` },
56
                     })
65
                     })
57
                     .code(409)
66
                     .code(409)
58
             }
67
             }
59
         },
68
         },
60
         validate: {
69
         validate: {
61
             ...validators,
70
             ...validators,
62
-            failAction: 'log'
71
+            failAction: 'log',
63
         },
72
         },
64
 
73
 
65
         response: {
74
         response: {
77
             },
86
             },
78
         },
87
         },
79
     },
88
     },
80
-}
89
+}

+ 7
- 3
backend/lib/routes/profile/score.js Просмотреть файл

53
             const distanceUnit = request.query.unit
53
             const distanceUnit = request.query.unit
54
                 ? request.query.unit
54
                 ? request.query.unit
55
                 : 'mile'
55
                 : 'mile'
56
-            const duration = request.query.duration
57
-            const presence = request.query.presence
56
+            const duration = request.query.duration.includes('-')
57
+                ? request.query.duration.split('-')[0]
58
+                : request.query.duration
59
+            const presence =
60
+                request.query.presence === 'in_person'
61
+                    ? 'onsite'
62
+                    : request.query.presence
58
             const certifications = request.query.certifications
63
             const certifications = request.query.certifications
59
-
60
             const scoredProfiles = await profileService.scoreProfilesFor(
64
             const scoredProfiles = await profileService.scoreProfilesFor(
61
                 profileId,
65
                 profileId,
62
                 maxDistanceMiles,
66
                 maxDistanceMiles,

+ 32
- 16
backend/lib/services/filter.js Просмотреть файл

29
         })
29
         })
30
     }
30
     }
31
 
31
 
32
-    byDuration(profileList, duration) {
33
-        return profileList.filter(profile => {
34
-            // TODO find duration
35
-            return profile.duration === duration
36
-        })
37
-    }
38
-
39
     byPresence(profileList, presence) {
32
     byPresence(profileList, presence) {
40
-        return profileList.filter(profile => {
41
-            // TODO find presence
42
-            return profile.presence === presence
43
-        })
33
+        const matchingProfiles = []
34
+        for (const profile of profileList) {
35
+            for (const response of profile.responses) {
36
+                if (
37
+                    response.response_key_id === 15 &&
38
+                    response.val === presence
39
+                ) {
40
+                    matchingProfiles.push(profile)
41
+                }
42
+            }
43
+        }
44
+        return matchingProfiles
44
     }
45
     }
45
 
46
 
46
-    byCertifications(profileList, certifications) {
47
-        return profileList.filter(profile => {
48
-            // TODO find certifications
49
-            return profile.certifications === certifications
50
-        })
47
+    byDuration(profileList, duration) {
48
+        const matchingProfiles = []
49
+        for (const profile of profileList) {
50
+            for (const response of profile.responses) {
51
+                if (
52
+                    response.response_key_id === 14 &&
53
+                    response.val === duration
54
+                ) {
55
+                    matchingProfiles.push(profile)
56
+                }
57
+            }
58
+        }
59
+        return matchingProfiles
51
     }
60
     }
61
+
62
+    // TODO: Implement filtering by matching certification
63
+    // byCertifications(profileList, certifications) {
64
+    // return profileList.filter(profile => {
65
+    // return profile.certifications === certifications
66
+    // })
67
+    // }
52
 }
68
 }

+ 24
- 13
backend/lib/services/profile/index.js Просмотреть файл

4
 const profiler = require('./profiler')
4
 const profiler = require('./profiler')
5
 const scoring = require('./scorer')
5
 const scoring = require('./scorer')
6
 const zipcoder = require('./zipcoder')
6
 const zipcoder = require('./zipcoder')
7
-const filter = require('../filter')
7
+const Filter = require('../filter')
8
+const filter = new Filter()
8
 
9
 
9
 module.exports = class ProfileService extends Schmervice.Service {
10
 module.exports = class ProfileService extends Schmervice.Service {
10
     constructor(...args) {
11
     constructor(...args) {
251
         certifications,
252
         certifications,
252
     ) {
253
     ) {
253
         const { Profile } = this.server.models()
254
         const { Profile } = this.server.models()
254
-
255
         await this._setScoreLookup()
255
         await this._setScoreLookup()
256
 
256
 
257
         // Our User Profile to score for
257
         // Our User Profile to score for
275
             distanceUnit,
275
             distanceUnit,
276
             userZip,
276
             userZip,
277
         )
277
         )
278
+
278
         matchPool = filter.byDistance(matchPool, maxDistance)
279
         matchPool = filter.byDistance(matchPool, maxDistance)
279
         matchPool = filter.byDuration(matchPool, duration)
280
         matchPool = filter.byDuration(matchPool, duration)
280
         matchPool = filter.byPresence(matchPool, presence)
281
         matchPool = filter.byPresence(matchPool, presence)
281
-        matchPool = filter.byCertifications(matchPool, certifications)
282
+        // TODO: Incorporate filtering by certifications (see filter.js)
283
+        // matchPool = filter.byCertifications(matchPool, certifications)
282
 
284
 
283
         const scoredProfilesWithDistance = scoring.scoreAll(
285
         const scoredProfilesWithDistance = scoring.scoreAll(
284
             matchPool,
286
             matchPool,
292
     }
294
     }
293
 
295
 
294
     async calcProfileDistances(matchPool, distanceUnit, userZip) {
296
     async calcProfileDistances(matchPool, distanceUnit, userZip) {
295
-        await Promise.all(
297
+        const returnVal = await Promise.all(
296
             matchPool.map(async profile => {
298
             matchPool.map(async profile => {
297
                 const targetZip = zipcoder.getZipCodeFromProfile(profile)
299
                 const targetZip = zipcoder.getZipCodeFromProfile(profile)
298
                 if (!userZip || !targetZip)
300
                 if (!userZip || !targetZip)
299
                     return { ...profile, distance: [9999, distanceUnit] }
301
                     return { ...profile, distance: [9999, distanceUnit] }
300
-
301
                 const distance = await this._compareDistance(
302
                 const distance = await this._compareDistance(
302
                     userZip,
303
                     userZip,
303
                     targetZip,
304
                     targetZip,
309
                 }
310
                 }
310
             }),
311
             }),
311
         )
312
         )
313
+        return returnVal
312
     }
314
     }
313
 
315
 
314
     /**
316
     /**
323
             parseInt(zipCode),
325
             parseInt(zipCode),
324
         )
326
         )
325
         if (!zipInfo) {
327
         if (!zipInfo) {
326
-            console.error('zip:', zipCode)
327
-        }
328
-        return {
329
-            latitude: parseFloat(zipInfo.latitude),
330
-            longitude: parseFloat(zipInfo.longitude),
328
+            throw new Error(
329
+                `ERROR :=> no zipInfo found for zipCode: ${zipCode}`,
330
+            )
331
+        } else {
332
+            return {
333
+                latitude: parseFloat(zipInfo.latitude),
334
+                longitude: parseFloat(zipInfo.longitude),
335
+            }
331
         }
336
         }
332
     }
337
     }
333
     /**
338
     /**
338
      * @param {number} distance in miles
343
      * @param {number} distance in miles
339
      */
344
      */
340
     async _compareDistance(start_zip, end_zip, distanceUnit) {
345
     async _compareDistance(start_zip, end_zip, distanceUnit) {
341
-        if (!start_zip || !end_zip || isNaN(start_zip) || isNaN(end_zip)) return
346
+        if (
347
+            !start_zip ||
348
+            !end_zip ||
349
+            Number.isNaN(start_zip) ||
350
+            Number.isNaN(end_zip)
351
+        )
352
+            return
342
         const start = await this._latLonForZip(start_zip)
353
         const start = await this._latLonForZip(start_zip)
343
         const end = await this._latLonForZip(end_zip)
354
         const end = await this._latLonForZip(end_zip)
344
         return haversine(start, end, { unit: distanceUnit })
355
         return haversine(start, end, { unit: distanceUnit })
355
         await this._setTagLookup()
366
         await this._setTagLookup()
356
         let associations = groupingId
367
         let associations = groupingId
357
             ? await TagAssociation.query()
368
             ? await TagAssociation.query()
358
-                .where('grouping_id', groupingId)
359
-                .andWhere('profile_id', profileId)
369
+                  .where('grouping_id', groupingId)
370
+                  .andWhere('profile_id', profileId)
360
             : await TagAssociation.query().andWhere('profile_id', profileId)
371
             : await TagAssociation.query().andWhere('profile_id', profileId)
361
         return associations
372
         return associations
362
             .map(assoc => ({
373
             .map(assoc => ({

+ 32
- 1
frontend/src/components/onboarding/Auth.vue Просмотреть файл

8
 import { authenticator } from '../../services/auth.service.js'
8
 import { authenticator } from '../../services/auth.service.js'
9
 import { createProfileForUserId } from '../../services/profile.service'
9
 import { createProfileForUserId } from '../../services/profile.service'
10
 import { signupUser } from '../../services/user.service.js'
10
 import { signupUser } from '../../services/user.service.js'
11
+import { scoreSurveyByProfileId } from '@/services'
11
 
12
 
12
 export default {
13
 export default {
13
     name: 'Auth',
14
     name: 'Auth',
81
         },
82
         },
82
         async createProfileForNewUser(userId, responses) {
83
         async createProfileForNewUser(userId, responses) {
83
             try {
84
             try {
84
-                await createProfileForUserId(userId, responses)
85
+                const newProfileForNewUser = await createProfileForUserId(
86
+                    userId,
87
+                    responses,
88
+                )
89
+                if (!newProfileForNewUser)
90
+                    throw Error(
91
+                        `ERROR: Unable to create newProfile for userId: ${userId}`,
92
+                    )
93
+
94
+                // NOTE: Populates matchQueue table with bare bone
95
+                // minimum filtered results of possible matches
96
+                // Based off of initial survey answers
97
+                const createdProfileId = newProfileForNewUser.profile_id
98
+                const maxDistance = this.responses
99
+                    .find(response => {
100
+                        return response.response_key_id === 19
101
+                    })
102
+                    .val.split(' ')[0]
103
+                const presence = this.responses.find(response => {
104
+                    return response.response_key_id === 15
105
+                }).val
106
+
107
+                // NOTE: duration hard coded for now as bare bones
108
+                // survey doesn't have duration as one of its steps...
109
+                const duration = 'full-time'
110
+                await scoreSurveyByProfileId(
111
+                    createdProfileId,
112
+                    maxDistance,
113
+                    duration,
114
+                    presence,
115
+                )
85
             } catch (err) {
116
             } catch (err) {
86
                 throw new Error(err)
117
                 throw new Error(err)
87
             }
118
             }

+ 0
- 3
frontend/src/services/auth.service.js Просмотреть файл

1
 import { db } from '../utils/db.js'
1
 import { db } from '../utils/db.js'
2
 
2
 
3
 class Authenticator {
3
 class Authenticator {
4
-    constructor() {
5
-        this.currentUser = null
6
-    }
7
     async sendEmail(answered) {
4
     async sendEmail(answered) {
8
         return await db.post('/user/send-email/', answered)
5
         return await db.post('/user/send-email/', answered)
9
     }
6
     }

+ 5
- 5
frontend/src/views/SurveyCompleteView.vue Просмотреть файл

108
         },
108
         },
109
         // changeAnswers() {},
109
         // changeAnswers() {},
110
     },
110
     },
111
+    /* 
112
+    NOTE: Incomplete logic for adjusting matchQueue results based 
113
+    off of further completion of survey, commented out for now as 
114
+    to not overwrite methods
111
     methods: {
115
     methods: {
112
         changeAnswers() {
116
         changeAnswers() {
113
             console.log('change answers')
117
             console.log('change answers')
129
                 survey,
133
                 survey,
130
             )
134
             )
131
             if (!userProfile) return
135
             if (!userProfile) return
132
-
133
-            /**
134
-             * Login only after there is a user and
135
-             * that user has a profile and all responses
136
-             */
137
             this._setLoginForProfile(userProfile)
136
             this._setLoginForProfile(userProfile)
138
 
137
 
139
             this.$router.push({ name: 'HomeView' })
138
             this.$router.push({ name: 'HomeView' })
157
             }
156
             }
158
         },
157
         },
159
     },
158
     },
159
+    */
160
 }
160
 }
161
 </script>
161
 </script>
162
 <style>
162
 <style>

Загрузка…
Отмена
Сохранить