Compare commits

...

2 Commits

4 changed files with 54 additions and 30 deletions

View File

@ -11,7 +11,7 @@ import { prisma } from "@/lib/prisma";
* *
* The function performs the following steps: * The function performs the following steps:
* 1. Retrieves the server session using `getServerSession`. * 1. Retrieves the server session using `getServerSession`.
* 2. Checks if the user is authenticated by verifying the presence of `session.user.username`. * 2. Checks if the user is authenticated by verifying the presence of `session.user.id`.
* - If not authenticated, returns a 401 response with an error message. * - If not authenticated, returns a 401 response with an error message.
* 3. Attempts to fetch the calendars associated with the authenticated user from the database. * 3. Attempts to fetch the calendars associated with the authenticated user from the database.
* - If successful, returns the calendars in a JSON response. * - If successful, returns the calendars in a JSON response.
@ -20,14 +20,14 @@ import { prisma } from "@/lib/prisma";
export async function GET(req: NextRequest) { export async function GET(req: NextRequest) {
const session = await getServerSession(authOptions); const session = await getServerSession(authOptions);
if (!session?.user?.username) { if (!session?.user?.id) {
return NextResponse.json({ error: "Non authentifié" }, { status: 401 }); return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
} }
try { try {
const calendars = await prisma.calendar.findMany({ const calendars = await prisma.calendar.findMany({
where: { where: {
userId: session.user.username, userId: session.user.id,
}, },
include: { include: {
events: { events: {

View File

@ -3,6 +3,9 @@ import Imap from 'imap';
import nodemailer from 'nodemailer'; import nodemailer from 'nodemailer';
import { parseEmailHeaders, decodeEmailBody } from '@/lib/email-parser'; import { parseEmailHeaders, decodeEmailBody } from '@/lib/email-parser';
import { cookies } from 'next/headers'; import { cookies } from 'next/headers';
import { getServerSession } from 'next-auth/next';
import { authOptions } from '@/lib/auth';
import { prisma } from '@/lib/prisma';
interface StoredCredentials { interface StoredCredentials {
email: string; email: string;
@ -92,11 +95,20 @@ function getStoredCredentials(): StoredCredentials | null {
} }
export async function GET(request: Request) { export async function GET(request: Request) {
const session = await getServerSession(authOptions);
if (!session?.user?.id) {
return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
}
try { try {
const credentials = getStoredCredentials(); const userCredentials = await prisma.emailCredentials.findUnique({
if (!credentials) { where: { userId: session.user.id }
});
if (!userCredentials) {
return NextResponse.json( return NextResponse.json(
{ error: 'No stored credentials found' }, { error: 'No email credentials configured' },
{ status: 401 } { status: 401 }
); );
} }
@ -110,10 +122,10 @@ export async function GET(request: Request) {
return new Promise((resolve) => { return new Promise((resolve) => {
const imap = new Imap({ const imap = new Imap({
user: credentials.email, user: userCredentials.email,
password: credentials.password, password: userCredentials.password,
host: credentials.host, host: userCredentials.host,
port: credentials.port, port: userCredentials.port,
tls: true, tls: true,
tlsOptions: { rejectUnauthorized: false }, tlsOptions: { rejectUnauthorized: false },
authTimeout: 30000, authTimeout: 30000,

View File

@ -27,50 +27,43 @@ export function CalendarWidget() {
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
useEffect(() => { useEffect(() => {
console.log("Calendar Widget - Session Status:", status);
console.log("Calendar Widget - Session Data:", session);
if (status === "loading") { if (status === "loading") {
console.log("Calendar Widget - Session is loading");
return; return;
} }
if (status !== "authenticated" || !session) { if (status !== "authenticated" || !session) {
console.log("Calendar Widget - Not authenticated, skipping fetch");
setLoading(false); setLoading(false);
return; return;
} }
const fetchUpcomingEvents = async () => { const fetchUpcomingEvents = async () => {
try { try {
console.log("Calendar Widget - Starting to fetch events");
setLoading(true); setLoading(true);
// Fetch calendars with events
console.log("Calendar Widget - Making API request to /api/calendars");
const response = await fetch('/api/calendars'); const response = await fetch('/api/calendars');
if (!response.ok) { if (!response.ok) {
console.error("Calendar Widget - API response not OK:", response.status, response.statusText);
throw new Error("Impossible de charger les événements"); throw new Error("Impossible de charger les événements");
} }
const calendarsData = await response.json(); const calendarsData = await response.json();
console.log("Calendar Widget - Raw calendars data:", calendarsData);
if (!Array.isArray(calendarsData)) { if (!Array.isArray(calendarsData)) {
console.error("Calendar Widget - Calendars data is not an array:", calendarsData);
throw new Error("Format de données invalide"); throw new Error("Format de données invalide");
} }
// Get current date at the start of the day
const now = new Date(); const now = new Date();
now.setHours(0, 0, 0, 0); now.setHours(0, 0, 0, 0);
// Extract all events and add calendar info
const allEvents = calendarsData.flatMap((calendar) => { const allEvents = calendarsData.flatMap((calendar) => {
console.log("Calendar Widget - Processing calendar:", calendar.name, "Events:", calendar.events?.length || 0); return (calendar.events || []).map((event: {
return (calendar.events || []).map((event) => { id: string;
title: string;
start: string;
end: string;
isAllDay: boolean;
calendarId: string;
}) => {
const startDate = new Date(event.start); const startDate = new Date(event.start);
const endDate = new Date(event.end); const endDate = new Date(event.end);
return { return {
@ -86,27 +79,22 @@ export function CalendarWidget() {
}); });
}); });
// Filter for upcoming events (today and future)
const upcomingEvents = allEvents const upcomingEvents = allEvents
.filter(event => event.start >= now) .filter(event => event.start >= now)
.sort((a, b) => a.start.getTime() - b.start.getTime()) .sort((a, b) => a.start.getTime() - b.start.getTime())
.slice(0, 5); .slice(0, 5);
console.log("Calendar Widget - Final upcoming events:", upcomingEvents);
setEvents(upcomingEvents); setEvents(upcomingEvents);
setError(null); setError(null);
} catch (err) { } catch (err) {
console.error("Calendar Widget - Error in fetchUpcomingEvents:", err);
setError("Impossible de charger les événements à venir"); setError("Impossible de charger les événements à venir");
} finally { } finally {
setLoading(false); setLoading(false);
} }
}; };
// Initial fetch
fetchUpcomingEvents(); fetchUpcomingEvents();
// Set up an interval to refresh events every 5 minutes
const intervalId = setInterval(fetchUpcomingEvents, 300000); const intervalId = setInterval(fetchUpcomingEvents, 300000);
return () => clearInterval(intervalId); return () => clearInterval(intervalId);

View File

@ -41,3 +41,27 @@ model Event {
@@index([calendarId]) @@index([calendarId])
@@index([userId]) @@index([userId])
} }
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
calendars Calendar[]
emailCredentials EmailCredentials?
}
model EmailCredentials {
id String @id @default(cuid())
userId String @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
email String
password String
host String
port Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}