github-leaderboard/server/jobs/calculate-user-points.ts

85 lines
2.1 KiB
TypeScript

import db from "@server/db";
import { repositories, users } from "@server/models";
import { eq } from "drizzle-orm";
type CalculateUserPointsType = {
userId: number;
};
const weights = {
followers: 20,
following: 10,
achievements: 100,
repositories: 1,
contributorsAmount: 25,
stars: 10,
forks: 10,
languagesKnown: 50,
commits: 1,
lineOfCodes: 0.01,
};
export const calculateUserPoints = async (data: CalculateUserPointsType) => {
const [user] = await db.select().from(users).where(eq(users.id, data.userId));
if (!user) {
throw new Error("User not found!");
}
let points = 0;
let totalCommits = 0;
let totalLineOfCodes = 0;
// User statistics
points += user.followers * weights.followers;
points += user.following * weights.following;
points += user.achievements
? user.achievements?.length * weights.achievements
: 0;
// User repositories
const repos = await db
.select()
.from(repositories)
.where(eq(repositories.userId, user.id));
points += repos.length * weights.repositories;
// Languages known
const languages = new Set(
repos.flatMap((i) => i.languages?.map((j) => j.lang))
);
points += languages.size * weights.languagesKnown;
// Activities
repos.forEach((repo) => {
const contributors = repo.contributors?.filter(
(i) => i.author?.login !== user.username
);
points += contributors
? contributors.length * weights.contributorsAmount
: 0;
points += repo.stars * weights.stars;
points += repo.forks * weights.forks;
const contrib = repo.contributors?.find(
(i) => i.author?.login === user.username
);
const commits = contrib?.commits || 0;
const lineOfCodes = contrib?.additions || 0;
points += commits * weights.commits;
points += lineOfCodes * weights.lineOfCodes;
totalCommits += commits;
totalLineOfCodes += lineOfCodes;
});
await db
.update(users)
.set({
points: Math.round(points),
commits: totalCommits,
lineOfCodes: totalLineOfCodes,
})
.where(eq(users.id, user.id));
};