1 | import similarity from 'string-similarity';
|
2 |
|
3 | import {
|
4 | addEntity as addScore,
|
5 | getEntity as getScore,
|
6 | updateEntity as updateScore,
|
7 | } from '../../Services/Score';
|
8 | import {
|
9 | getEntity as getActivity,
|
10 | updateEntity as updateActivity,
|
11 | } from '../../Services/Activity';
|
12 | import { getUser } from '../../Services/User';
|
13 | import { notifyMatchedActivity } from '../../Services/Notifier';
|
14 |
|
15 | const DEFAULT_VALUES = {
|
16 | distance: '50',
|
17 | unit: 'km',
|
18 | };
|
19 |
|
20 | const getDefinedUser = (user) => {
|
21 | const userIsDefined = user != null && user !== undefined;
|
22 | return userIsDefined;
|
23 | };
|
24 |
|
25 | const fillActivities = async (user) => {
|
26 | const activities = await Promise.all(user.activitiesID.map(getActivity));
|
27 | return { ...user, activities };
|
28 | };
|
29 |
|
30 | const hasActivities = user => user && user.activitiesID && user.activitiesID.length > 0;
|
31 |
|
32 | const getCurrentUser = (users, key) => users
|
33 | .filter(getDefinedUser)
|
34 | .filter(user => user.userID === key);
|
35 |
|
36 | const isNotCurrentUser = (user, key) => user.userID !== key;
|
37 |
|
38 | const isRequest = activity => activity.type === 'request';
|
39 |
|
40 | const isSerach = activity => activity.type === 'search';
|
41 |
|
42 | const isActive = activity => activity.active;
|
43 |
|
44 | const hasPositiveScore = (users, userID) => users.map(user => user.userID).includes(userID);
|
45 |
|
46 | const hasSearchActivity = (user) => {
|
47 | if (user.activities && user.activities.length > 0) return false;
|
48 |
|
49 | return user.activities.filter(isSerach).length > 0;
|
50 | };
|
51 |
|
52 | const hasRequestActivity = user => user.activities.filter(isRequest).length > 0;
|
53 |
|
54 | const getScoreActivities = (request, searchActivities) =>
|
55 | searchActivities.map(search => getScoreActivity(search, request));
|
56 |
|
57 | const getScoreActivity = (search, request) => {
|
58 | const scoreName = similarity.compareTwoStrings(search.name, request.name);
|
59 |
|
60 | const scoreDescription = similarity.compareTwoStrings(search.description, request.description);
|
61 |
|
62 | const scoreActivity = similarity.compareTwoStrings(search.activity, request.activity);
|
63 |
|
64 | const scoreSkills = similarity.compareTwoStrings(
|
65 | search.skills.toString(),
|
66 | request.skills.toString()
|
67 | );
|
68 |
|
69 | const scoreSkillDescription = similarity.compareTwoStrings(
|
70 | search.skills.toString(),
|
71 | request.description
|
72 | );
|
73 |
|
74 | const scoreDescriptionSkill = similarity.compareTwoStrings(
|
75 | search.description,
|
76 | request.skills.toString()
|
77 | );
|
78 |
|
79 | const total = scoreName
|
80 | + scoreDescription
|
81 | + scoreActivity
|
82 | + scoreSkills
|
83 | + scoreSkillDescription
|
84 | + scoreDescriptionSkill;
|
85 |
|
86 | console.log('-------------------------------------------------------------------------');
|
87 | console.log(`[${search.userID} | ${request.userID}]`);
|
88 | console.log('-------------------------------------------------------------------------');
|
89 | console.log('scoreName:', scoreName);
|
90 | console.log('scoreDescription:', scoreDescription);
|
91 | console.log('scoreActivity:', scoreActivity);
|
92 | console.log('scoreSkills:', scoreSkills);
|
93 | console.log('scoreSkillDescription:', scoreSkillDescription);
|
94 | console.log('scoreDescriptionSkill:', scoreDescriptionSkill);
|
95 | console.log('SEARCH ACTIVITY ID:', search.activityID);
|
96 | console.log('REQUEST ACTIVITY ID:', request.activityID);
|
97 | console.log('-------------------------------------------------------------------------');
|
98 | console.log('TOTAL:', total / 6);
|
99 | console.log('-------------------------------------------------------------------------');
|
100 | console.log('*************************************************************************');
|
101 |
|
102 | return {
|
103 | score: total / 6,
|
104 | activitySearchID: search.activityID,
|
105 | activityRequestID: request.activityID,
|
106 | scoreID: search.activityID + request.activityID,
|
107 | };
|
108 | };
|
109 |
|
110 | export default () => ({
|
111 | execMatchingWorkflow: async (location, getCloseUsersLocations) => {
|
112 | const matchedUsers = await getCloseUsersLocations({
|
113 | id: location.collectionID,
|
114 | key: location.key,
|
115 | distance: location.distance || DEFAULT_VALUES.distance,
|
116 | unit: location.unit || DEFAULT_VALUES.unit,
|
117 | });
|
118 |
|
119 | if (!matchedUsers) return matchedUsers;
|
120 |
|
121 | const users = await Promise.all(matchedUsers
|
122 | .map(user => user.userName)
|
123 | .map(getUser));
|
124 |
|
125 | const currentUser = getCurrentUser(users, location.key)[0];
|
126 |
|
127 | if (!hasActivities(currentUser)) return matchedUsers;
|
128 |
|
129 | const currentUserWithSearchActivities = await fillActivities(currentUser);
|
130 |
|
131 | if (!hasSearchActivity(currentUserWithSearchActivities)) return matchedUsers;
|
132 |
|
133 | const usersWithActivities = await Promise.all(users
|
134 | .filter(getDefinedUser)
|
135 | .filter(user => isNotCurrentUser(user, location.key))
|
136 | .filter(hasActivities)
|
137 | .map(fillActivities));
|
138 |
|
139 | const usersWithRequestActivitiesActive = usersWithActivities
|
140 | .filter(hasRequestActivity);
|
141 |
|
142 | const userWithMatchedActivities = usersWithRequestActivitiesActive.map((user) => {
|
143 | const userScores = user.activities
|
144 | .filter(isRequest)
|
145 | .map((request) => {
|
146 | const requestScores = getScoreActivities(request, currentUserWithSearchActivities.activities);
|
147 | return requestScores;
|
148 | });
|
149 | const mergedUserScores = [].concat(...userScores);
|
150 | return { ...user, scores: mergedUserScores };
|
151 | });
|
152 |
|
153 | const userWithPositiveMatchedActivities = [].concat(...userWithMatchedActivities
|
154 | .map((user) => {
|
155 | const positivesScores = user.scores.filter(score => score.score > 0.5);
|
156 | return { ...user, scores: positivesScores };
|
157 | }));
|
158 |
|
159 | userWithPositiveMatchedActivities.forEach(user =>
|
160 | user.scores.forEach(async (score) => {
|
161 | const existingScore = await getScore(score.scoreID);
|
162 |
|
163 | const searchActivity = currentUserWithSearchActivities.activities
|
164 | .filter(activity => activity.activityID === score.activitySearchID)[0];
|
165 | const matchedActivitiesID = searchActivity.matchedActivitiesID
|
166 | ? searchActivity.matchedActivitiesID
|
167 | : [];
|
168 |
|
169 | if (!existingScore) {
|
170 | addScore(score);
|
171 |
|
172 | updateActivity({
|
173 | activityID: score.activitySearchID,
|
174 | matchedActivitiesID: [...matchedActivitiesID, score.activityRequestID],
|
175 | });
|
176 |
|
177 | notifyMatchedActivity(currentUserWithSearchActivities, searchActivity, user);
|
178 | } else if (score.socre !== existingScore.score) {
|
179 | updateScore(score);
|
180 | }
|
181 | }));
|
182 |
|
183 | return matchedUsers.filter(user => hasPositiveScore(userWithPositiveMatchedActivities, user.userName));
|
184 | },
|
185 | acceptToMeetWorkflow: async () => {
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 | },
|
193 | });
|