Untitled
unknown
typescript
2 years ago
8.0 kB
7
Indexable
exports.dailyUserScoreCalculation = functions.pubsub.schedule('55 23 * * *').timeZone('Asia/Taipei').onRun(async (context) => {
// Fetch all existing users and store their IDs in a string array
const usersSnapshot = await admin.firestore().collection('Users').get();
const userIds = usersSnapshot.docs.map(doc => doc.id);
// Iterate over users to calculate scores
for (let i = 0; i < userIds.length; i++) {
for (let j = i + 1; j < userIds.length; j++) {
// Check if a score entry already exists for this pair
const scoreEntrySnapshot = await admin.firestore().collection('scores')
.where('user1', 'in', [userIds[i], userIds[j]])
.where('user2', 'in', [userIds[i], userIds[j]])
.get();
if (scoreEntrySnapshot.empty) {
// No entry exists, calculate score
const scoreResult = await calculateMatchScores(userIds[i], userIds[j]);
// Proceed only if score is greater than 0
if (scoreResult.score > 0) {
// Add score entry to Firestore
await admin.firestore().collection('scores').add({
user1: userIds[i],
user2: userIds[j],
score: scoreResult.score
});
}
}
}
}
console.log('Daily user score calculation completed for non-zero scores');
});
async function calculateMatchScores(userIdA: string, userIdB: string): Promise<{ score: number }> {
const db = admin.firestore();
const userADoc = await db.collection('Users').doc(userIdA).get();
const userBDoc = await db.collection('Users').doc(userIdB).get();
const userA = userADoc.data();
const userB = userBDoc.data();
if (!userA || !userB || !userA.favoriteArtists || !userB.favoriteArtists || !userA.similarArtists || !userB.similarArtists) {
console.log(`Incomplete data for users ${userIdA} and ${userIdB}. Returning default score of 0.`);
return { score: 0 };
}
let score = 0;
const userASelectedArtistNames: string[] = userA.favoriteArtists.map((artist: Artist) => artist.name);
const userBSelectedArtistNames: string[] = userB.favoriteArtists.map((artist: Artist) => artist.name);
const sharedSelectedArtists: string[] = userASelectedArtistNames.filter((artistNameA: string) => userBSelectedArtistNames.includes(artistNameA));
score += sharedSelectedArtists.length * 9;
const sharedSelectedSimilarArtistsAB: string[] = userASelectedArtistNames.filter((artistNameA: string) => userB.similarArtists.includes(artistNameA));
score += sharedSelectedSimilarArtistsAB.length * 3;
const sharedSelectedSimilarArtistsBA: string[] = userBSelectedArtistNames.filter((artistNameB: string) => userA.similarArtists.includes(artistNameB));
score += sharedSelectedSimilarArtistsBA.length * 3;
const sharedSimilarArtists: string[] = userA.similarArtists.filter((similarArtist: string) => userB.similarArtists.includes(similarArtist));
score += sharedSimilarArtists.length;
console.log("Score:", score);
return { score };
}
exports.fetchPotentialProfilesWithScoresNew = functions.runWith(runtimeOpts).pubsub.schedule('40 23 * * *')
.timeZone('Asia/Taipei')
.onRun(async (context) => {
console.log("Starting to assign daily profiles based on scores...");
const db = admin.firestore();
const usersSnapshot = await db.collection('Users').get();
let users = usersSnapshot.docs.map(doc => doc.id).filter(id => !["demo1", "demo2", "demo3"].includes(id));
users = shuffleArray(users);
for (let userID of users) {
// Check if the current user already has 3 matches for tomorrow
const alreadyHasThreeMatches = await canBeShownTomorrow(userID);
if (!alreadyHasThreeMatches) {
console.log(`User ${userID} already has 3 or more profiles assigned for tomorrow.`);
continue; // Skip to the next user
}
let potentialProfiles: PotentialProfiles = {}; // Use an interface or type for PotentialProfiles
for (let potentialMatchID of users) {
if (userID === potentialMatchID) continue; // Skip self
const pairId = [userID, potentialMatchID].sort().join('_');
const scoreDoc = await db.collection('newScores').doc(pairId).get();
if (scoreDoc.exists && scoreDoc.data()?.score > 0) {
potentialProfiles[potentialMatchID] = scoreDoc.data()!.score;
}
}
let sortedPotentialProfiles = Object.entries(potentialProfiles)
.map(([id, score]) => ({ id, score }))
.sort((a, b) => b.score - a.score);
let assignedProfiles = [];
for (let profile of sortedPotentialProfiles) {
if (assignedProfiles.length >= 3) break;
const canShow = await canBeShownTomorrow(userID) && await canBeShownTomorrow(profile.id);
const notShownBefore = !(await hasBeenShown(userID, profile.id)) && !(await hasBeenShown(profile.id, userID));
if (canShow && notShownBefore) {
assignedProfiles.push(profile.id);
await addToShownProfilesNew(userID, profile.id);
await addToShownProfilesNew(profile.id, userID);
}
}
//await sendNotificationAboutNewProfiles(userID);
}
console.log("Finished assigning daily profiles based on scores.");
});
async function addToShownProfilesNew(userID: string, profileID: string): Promise<void> {
const interactionsRef = db.collection('Interactions').doc(userID);
const formattedTomorrow = getTomorrowInTaipei(); // Get formatted tomorrow's date in Taipei's timezone
const doc = await interactionsRef.get();
let shownProfiles = doc.exists ? doc.data()?.shownProfiles ?? {} : {};
if (!shownProfiles[formattedTomorrow]) shownProfiles[formattedTomorrow] = [];
shownProfiles[formattedTomorrow].push(profileID);
console.log(`Added profile for ${formattedTomorrow}: ${profileID}`);
await interactionsRef.set({ shownProfiles }, { merge: true });
}
async function canBeShownTomorrow(userID: string): Promise<boolean> {
const formattedTomorrow = getTomorrowInTaipei(); // Get formatted tomorrow's date in Taipei's timezone
const interactionsRef = db.collection('Interactions').doc(userID);
const doc = await interactionsRef.get();
if (!doc.exists) {
// If the document doesn't exist, the user hasn't been shown any profiles for tomorrow, so they can be shown.
return true;
}
const data = doc.data();
if (!data?.shownProfiles || !data?.shownProfiles[formattedTomorrow]) {
// If there's no entry for tomorrow, the user can be shown profiles.
return true;
}
// If there are fewer than 3 entries for tomorrow, the user can be shown more profiles.
return data.shownProfiles[formattedTomorrow].length < 3;
}
async function hasBeenShown(userID: string, profileID: string): Promise<boolean> {
const interactionsRef = db.collection('Interactions').doc(userID);
const doc = await interactionsRef.get();
if (!doc.exists || !doc.data()) return false;
const data = doc.data()!;
// Assume shownProfiles is an object where each key is a string and each value is an array of strings
// This assertion helps TypeScript understand the structure we expect
const shownProfiles: {[key: string]: string[]} = data.shownProfiles || {};
return Object.values(shownProfiles).some((profiles: string[]) => profiles.includes(profileID));
}Editor is loading...
Leave a Comment