diff --git a/src/components/charts/CombinedContributionChart.js b/src/components/charts/CombinedContributionChart.js
index 52d71e5..c4708cb 100644
--- a/src/components/charts/CombinedContributionChart.js
+++ b/src/components/charts/CombinedContributionChart.js
@@ -3,7 +3,7 @@ import { useFetchGithubCommits } from '@/hooks/githubQueries/useFetchGithubCommi
import { Tooltip } from 'primereact/tooltip';
import { formatDateTime } from "@/utils/time";
-const CombinedContributionChart = ({ username, session }) => {
+const CombinedContributionChart = ({ session }) => {
const [contributionData, setContributionData] = useState({});
const [totalContributions, setTotalContributions] = useState(0);
@@ -88,7 +88,7 @@ const CombinedContributionChart = ({ username, session }) => {
setTotalContributions(totalCommits + Object.values(activityData).reduce((a, b) => a + b, 0));
}, [prepareProgressData]);
- const { data, isLoading, isFetching } = useFetchGithubCommits(username, handleNewCommit);
+ const { data, isLoading, isFetching } = useFetchGithubCommits(session, handleNewCommit);
// Initialize from cached data if available
useEffect(() => {
diff --git a/src/components/profile/UserProfile.js b/src/components/profile/UserProfile.js
index a8f562c..6963822 100644
--- a/src/components/profile/UserProfile.js
+++ b/src/components/profile/UserProfile.js
@@ -134,7 +134,7 @@ const UserProfile = () => {
)}
{account && account?.provider === "github" ? (
-
+
) : (
)}
diff --git a/src/components/profile/progress/UserProgress.js b/src/components/profile/progress/UserProgress.js
index 1ed5c3f..6ea37e7 100644
--- a/src/components/profile/progress/UserProgress.js
+++ b/src/components/profile/progress/UserProgress.js
@@ -148,9 +148,9 @@ const UserProgress = () => {
const result = await signIn("github", {
redirect: false,
// Pass existing user data for linking
- userId: session.user.id,
- pubkey: session.user.pubkey,
- privkey: session.user.privkey
+ userId: session?.user?.id,
+ pubkey: session?.user?.pubkey,
+ privkey: session?.user?.privkey || null
});
if (result?.ok) {
diff --git a/src/hooks/githubQueries/useFetchGithubCommits.js b/src/hooks/githubQueries/useFetchGithubCommits.js
index f5c5da8..7adca7d 100644
--- a/src/hooks/githubQueries/useFetchGithubCommits.js
+++ b/src/hooks/githubQueries/useFetchGithubCommits.js
@@ -1,19 +1,23 @@
import { useQuery } from '@tanstack/react-query';
import { getAllCommits } from '@/lib/github';
-export function useFetchGithubCommits(username, onCommitReceived) {
+export function useFetchGithubCommits(session, onCommitReceived) {
+ const accessToken = session?.account?.access_token;
+
return useQuery({
- queryKey: ['githubCommits', username],
+ queryKey: ['githubCommits', accessToken],
queryFn: async () => {
+ if (!accessToken) return { commits: [], contributionData: {}, totalCommits: 0 };
+
const today = new Date();
const oneYearAgo = new Date(today);
- oneYearAgo.setDate(today.getDate() - 364); // Exactly 52 weeks
+ oneYearAgo.setDate(today.getDate() - 364);
const commits = [];
const contributionData = {};
let totalCommits = 0;
- for await (const commit of getAllCommits(username, oneYearAgo)) {
+ for await (const commit of getAllCommits(accessToken, oneYearAgo)) {
commits.push(commit);
const date = commit.commit.author.date.split('T')[0];
contributionData[date] = (contributionData[date] || 0) + 1;
diff --git a/src/lib/github.js b/src/lib/github.js
index 779260c..aba8482 100644
--- a/src/lib/github.js
+++ b/src/lib/github.js
@@ -20,8 +20,29 @@ const octokit = new ThrottledOctokit({
},
});
-export async function* getAllCommits(username, since) {
- // Create time windows of 1 month each
+export async function* getAllCommits(accessToken, since) {
+ const auth = accessToken || process.env.NEXT_PUBLIC_GITHUB_ACCESS_KEY;
+
+ const octokit = new ThrottledOctokit({
+ auth,
+ throttle: {
+ onRateLimit: (retryAfter, options, octokit, retryCount) => {
+ octokit.log.warn(`Request quota exhausted for request ${options.method} ${options.url}`);
+ if (retryCount < 2) {
+ octokit.log.info(`Retrying after ${retryAfter} seconds!`);
+ return true;
+ }
+ },
+ onSecondaryRateLimit: (retryAfter, options, octokit) => {
+ octokit.log.warn(`Secondary rate limit hit for request ${options.method} ${options.url}`);
+ return true;
+ },
+ },
+ });
+
+ // First, get the authenticated user's information
+ const { data: user } = await octokit.users.getAuthenticated();
+
const endDate = new Date();
let currentDate = new Date(since);
@@ -29,7 +50,6 @@ export async function* getAllCommits(username, since) {
let nextDate = new Date(currentDate);
nextDate.setMonth(nextDate.getMonth() + 1);
- // If next date would be in the future, use current date instead
if (nextDate > endDate) {
nextDate = endDate;
}
@@ -39,7 +59,7 @@ export async function* getAllCommits(username, since) {
while (true) {
try {
const { data } = await octokit.search.commits({
- q: `author:${username} committer-date:${currentDate.toISOString().split('T')[0]}..${nextDate.toISOString().split('T')[0]}`,
+ q: `author:${user.login} committer-date:${currentDate.toISOString().split('T')[0]}..${nextDate.toISOString().split('T')[0]}`,
per_page: 100,
page,
});
@@ -58,7 +78,6 @@ export async function* getAllCommits(username, since) {
}
}
- // Move to next time window
currentDate = nextDate;
}
}
diff --git a/src/pages/api/auth/[...nextauth].js b/src/pages/api/auth/[...nextauth].js
index 03d43dd..c3bd5ef 100644
--- a/src/pages/api/auth/[...nextauth].js
+++ b/src/pages/api/auth/[...nextauth].js
@@ -166,7 +166,7 @@ export const authOptions = {
],
callbacks: {
// Move email handling to the signIn callback
- async signIn({ user, account, profile, email }) {
+ async signIn({ user, account }) {
// Only handle email provider sign ins
if (account?.provider === "email") {
try {
@@ -230,7 +230,8 @@ export const authOptions = {
userLessons: fullUser.userLessons,
purchased: fullUser.purchased,
nip05: fullUser.nip05,
- lightningAddress: fullUser.lightningAddress
+ lightningAddress: fullUser.lightningAddress,
+ githubUsername: token.githubUsername
};
// Add GitHub account info to session if it exists
@@ -247,10 +248,10 @@ export const authOptions = {
}
return session;
},
- async jwt({ token, user, account, profile }) {
+ async jwt({ token, user, account, profile, session }) {
+ console.log("JWT", token, user, account, profile, session);
// If we are linking a github account to an existing email or anon account (we have privkey)
if (account?.provider === "github" && user?.id && user?.pubkey && user?.privkey) {
- console.log("Linking GitHub account to existing user", account, profile);
try {
// First update the user's profile with GitHub info
const updatedUser = await updateUser(user.id, {
@@ -260,22 +261,64 @@ export const authOptions = {
image: profile?.avatar_url,
});
- console.log("Updated user", updatedUser);
-
// Get the updated user
const existingUser = await getUserById(updatedUser?.id);
if (existingUser) {
token.user = existingUser;
}
+
+ // add github username to token
+ token.githubUsername = profile?.login || profile?.name;
} catch (error) {
console.error("Error linking GitHub account:", error);
}
}
- // If we are linking a github account to a nostr account (we do not have privkey)
- if (account?.provider === "github" && account?.userId && account?.pubkey) {
+ // nostr login (we have no privkey)
+ if (account?.provider === "github" && user?.id && user?.pubkey) {
+ console.log("GITHUB LOGIN");
try {
- // I think we just need auth + account in session and thats it?
+ // First check if there's already a GitHub account linked
+ const existingGithubAccount = await prisma.account.findFirst({
+ where: {
+ userId: user.id,
+ provider: 'github'
+ }
+ });
+
+ // add github username to token
+ token.githubUsername = profile?.login || profile?.name;
+
+ if (!existingGithubAccount) {
+ console.log("No existing GitHub account found");
+ // Update user profile with GitHub info
+ const updatedUser = await updateUser(user.id, {
+ name: profile?.login || profile?.name,
+ username: profile?.login || profile?.name,
+ avatar: profile?.avatar_url,
+ image: profile?.avatar_url,
+ email: profile?.email // Add email if user wants it
+ });
+
+ // Create the GitHub account link
+ await prisma.account.create({
+ data: {
+ userId: user.id,
+ type: account.type,
+ provider: account.provider,
+ providerAccountId: account.providerAccountId,
+ access_token: account.access_token,
+ token_type: account.token_type,
+ scope: account.scope
+ }
+ });
+
+ // Get the updated user
+ const existingUser = await getUserById(updatedUser?.id);
+ if (existingUser) {
+ token.user = existingUser;
+ }
+ }
} catch (error) {
console.error("Error linking GitHub account:", error);
}