Skip to content

Instantly share code, notes, and snippets.

@kanjieater
Created April 19, 2024 02:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kanjieater/2f7d796a81ce0b682f24b8f5092b3dee to your computer and use it in GitHub Desktop.
Save kanjieater/2f7d796a81ce0b682f24b8f5092b3dee to your computer and use it in GitHub Desktop.
Find inactive users on tadoku
const logsBaseUrl = "https://tadoku.app/api/internal/immersion/contests/32b33801-c412-4187-9d78-31d58cd06588/logs";
const pageSize = 10; // Adjust page size as needed
const includeDeleted = false; // Include deleted as per your example
// Function to check if a date is older than one month
function isOlderThanOneMonth(dateString) {
const oneMonthAgo = new Date();
oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1);
const logDate = new Date(dateString);
return logDate < oneMonthAgo;
}
async function fetchLogs() {
let allLogs = [];
let nextPageToken = "0";
try {
do {
const url = `${logsBaseUrl}?page_size=${pageSize}&page=${nextPageToken}&include_deleted=${includeDeleted}`;
const response = await fetch(url);
if (!response.ok) throw new Error(`Failed to fetch logs: ${response.statusText}`);
const logsData = await response.json();
const logs = logsData.logs;
allLogs = allLogs.concat(logs);
nextPageToken = logsData.next_page_token;
} while (nextPageToken);
return allLogs;
} catch (error) {
console.error("Error fetching logs:", error);
return [];
}
}
async function fetchReadersAndLogs() {
try {
const logs = await fetchLogs();
// Now, process the data to find active, inactive, and dead users
const activeUsers = [];
const inactiveUsers = [];
const deadUsers = [];
// Fetch leaderboard data to match with user IDs
const leaderboardUrl = "https://tadoku.app/api/internal/immersion/contests/32b33801-c412-4187-9d78-31d58cd06588/leaderboard?page_size=50&page=0";
const leaderboardResponse = await fetch(leaderboardUrl);
if (!leaderboardResponse.ok) throw new Error(`Failed to fetch leaderboard: ${leaderboardResponse.statusText}`);
const leaderboardData = await leaderboardResponse.json();
const leaderboardEntries = leaderboardData.entries;
leaderboardEntries.forEach(entry => {
const lastActivityDate = logs.filter(log => log.user_id === entry.user_id)
.map(log => new Date(log.created_at))
.sort((a, b) => b - a)[0];
if (!lastActivityDate) {
deadUsers.push({ username: entry.user_display_name, lastReadDate: null });
} else {
const userHasLogged = logs.some(log => log.user_id === entry.user_id && !isOlderThanOneMonth(log.created_at));
if (userHasLogged) {
activeUsers.push({ username: entry.user_display_name, lastReadDate: lastActivityDate });
} else {
const twoMonthsAgo = new Date();
twoMonthsAgo.setMonth(twoMonthsAgo.getMonth() - 2);
if (lastActivityDate < twoMonthsAgo) {
deadUsers.push({ username: entry.user_display_name, lastReadDate: lastActivityDate });
} else {
inactiveUsers.push({ username: entry.user_display_name, lastReadDate: lastActivityDate });
}
}
}
});
console.log("Active Users:", activeUsers);
console.log("Inactive Users:", inactiveUsers);
console.log("Dead Users:", deadUsers);
return { activeUsers, inactiveUsers, deadUsers };
} catch (error) {
console.error("Error fetching data:", error);
return { activeUsers: [], inactiveUsers: [], deadUsers: [] };
}
}
async function applyStyling(inactiveUsers, deadUsers) {
// Apply strike-through and color change for inactive and dead users
inactiveUsers.forEach(user => {
const username = user.username;
const lastReadDate = user.lastReadDate;
const userElements = document.querySelectorAll(`tr td:nth-child(2) .reset.text-lg`);
userElements.forEach(element => {
if (element.textContent.trim() === username) {
element.style.color = "#ffbf47"; // Yellowish color for inactive users
if (lastReadDate) {
element.textContent += ` (Last read: ${lastReadDate.toDateString()})`;
}
}
});
});
deadUsers.forEach(user => {
const username = user.username;
const lastReadDate = user.lastReadDate;
const userElements = document.querySelectorAll(`tr td:nth-child(2) .reset.text-lg`);
userElements.forEach(element => {
if (element.textContent.trim() === username) {
element.style.color = "tomato"; // Tomato color for dead users
element.style.textDecoration = "line-through";
if (lastReadDate) {
element.textContent += ` (Last read: ${lastReadDate.toDateString()})`;
}
}
});
});
console.log("Styling applied.");
// Print final lists of dead users and inactive users with "@" in front of their names
console.log("Styling applied.\n");
// Build final lists of dead users and inactive users with "@" in front of their names
let finalOutput = ":sob: Inactive Users:\n";
inactiveUsers.forEach(user => finalOutput += `@${user.username}\n`);
finalOutput += "\n:headstone: Dead Users:\n";
deadUsers.forEach(user => finalOutput += `@${user.username}\n`);
// Print the final block
console.log(finalOutput);
}
async function applyUserStyling() {
const { inactiveUsers, deadUsers } = await fetchReadersAndLogs();
applyStyling(inactiveUsers, deadUsers);
}
applyUserStyling();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment