Skip to content

Commit a4a4a52

Browse files
committed
Add .gitignore entries for googleAuth.json, details.txt, and test.js
Update package.json to include date-fns dependency Remove unnecessary "type" and "function" properties in checkDateTimeAvailability.json and createAppointment.json Update package-lock.json to include date-fns dependency
1 parent 1b52034 commit a4a4a52

8 files changed

+291
-165
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ auth.jsons
88
calendar_auth.json
99
auth.json
1010
clinetAuth.json
11-
googleAuth.json
11+
googleAuth.json
12+
details.txt
13+
test.js

calander.js

+154-66
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
import { google } from "googleapis";
22
import fs from "fs";
33
import path from "path";
4+
import {
5+
parse,
6+
addHours,
7+
isValid,
8+
startOfHour,
9+
addDays,
10+
setHours,
11+
} from "date-fns";
412

5-
//const KEYFILEPATH = "auth.json";
13+
const SERVICE_ACCOUNT_PATH = "auth.json";
14+
const TIME_ZONE = "America/New_York";
15+
const APPOINTMENT_DURATION_HOURS = 1;
616
const CALENDAR_ID = "primary";
17+
const CHECK_DAYS_AHEAD = 7;
18+
const BUSINESS_START_HOUR = 9; // Business hours start at 9 AM
19+
const BUSINESS_END_HOUR = 17; // Business hours end at 5 PM
720

21+
// Load service account credentials
822
const serviceAccountCredentials = JSON.parse(
9-
fs.readFileSync(path.join("auth.json"), "utf8")
23+
fs.readFileSync(path.join(SERVICE_ACCOUNT_PATH), "utf8")
1024
);
1125

1226
// Google Calendar API client setup
@@ -24,81 +38,89 @@ const auth = new google.auth.JWT(
2438
"111370419970452146902"
2539
);
2640
const calendar = google.calendar({ version: "v3", auth });
27-
console.log("Auth setup complete, proceeding with API calls...");
28-
// Function to check calendar availability
29-
export async function checkDateTimeAvailability(dateTimeToCheck) {
30-
const startDateTime = new Date(dateTimeToCheck);
31-
const endDateTime = new Date(startDateTime.getTime() + 60 * 60000); // Check 1 hour range
32-
33-
const res = await calendar.freebusy.query({
34-
requestBody: {
35-
timeMin: startDateTime.toISOString(),
36-
timeMax: endDateTime.toISOString(),
37-
items: [{ id: CALENDAR_ID }],
38-
},
39-
});
4041

41-
const isAvailable = res.data.calendars[CALENDAR_ID].busy.length === 0;
42-
console.log(
43-
`Checking availability for: ${startDateTime.toISOString()} to ${endDateTime.toISOString()}`
44-
);
45-
console.log(`Availability: ${isAvailable ? "Available" : "Not available"}`);
46-
return isAvailable;
47-
}
48-
49-
// // Function to create a calendar event
50-
async function createAppointment(dateTimeToCheck, summary, description, email) {
51-
if (await checkDateTimeAvailability(dateTimeToCheck)) {
52-
const event = {
53-
summary,
54-
description,
55-
start: {
56-
dateTime: dateTimeToCheck,
57-
timeZone: "America/New_York",
58-
},
59-
end: {
60-
dateTime: new Date(
61-
new Date(dateTimeToCheck).getTime() + 3600000
62-
).toISOString(), // Adds one hour to the start time
63-
timeZone: "America/New_York",
64-
},
65-
attendees: [{ email: email }],
66-
};
67-
68-
try {
69-
const { data } = await calendar.events.insert({
70-
calendarId: CALENDAR_ID,
71-
resource: event,
72-
});
73-
74-
return data.htmlLink; // Return the link to the created calendar event
75-
} catch (error) {
76-
console.error("Error booking appointment:", error);
77-
throw error;
42+
export const checkDateTimeAvailability = async (
43+
date,
44+
numberOfDays = CHECK_DAYS_AHEAD
45+
) => {
46+
let availableSlots = [];
47+
let currentDate = startOfHour(new Date(date)); // Start from the beginning of the hour of the provided date
48+
49+
for (let day = 0; day < numberOfDays; day++) {
50+
for (let hour = BUSINESS_START_HOUR; hour < BUSINESS_END_HOUR; hour++) {
51+
let startDateTime = setHours(addDays(currentDate, day), hour);
52+
let endDateTime = addHours(startDateTime, APPOINTMENT_DURATION_HOURS);
53+
54+
try {
55+
const response = await calendar.freebusy.query({
56+
requestBody: {
57+
timeMin: startDateTime.toISOString(),
58+
timeMax: endDateTime.toISOString(),
59+
items: [{ id: CALENDAR_ID }],
60+
timeZone: TIME_ZONE,
61+
},
62+
});
63+
64+
if (response.data.calendars[CALENDAR_ID].busy.length === 0) {
65+
availableSlots.push(startDateTime);
66+
}
67+
} catch (error) {
68+
console.error("Error checking availability:", error);
69+
throw new Error("Failed to check availability");
70+
}
7871
}
79-
} else {
72+
}
73+
74+
return availableSlots;
75+
};
76+
77+
// Function to create a calendar event
78+
export const createAppointment = async (
79+
dateTime,
80+
summary,
81+
description,
82+
email
83+
) => {
84+
const isAvailable = await checkDateTimeAvailability(dateTime);
85+
if (!isAvailable) {
8086
console.log(
8187
"Time slot not available, looking for the next available slot..."
8288
);
83-
// Find the next available time slot, add an hour and try again:
84-
const nextAttempt = new Date(new Date(dateTimeToCheck).getTime() + 3600000);
85-
return createAppointment(
86-
nextAttempt.toISOString(),
87-
summary,
88-
description,
89-
email
90-
);
89+
const nextAttempt = addHours(dateTime, APPOINTMENT_DURATION_HOURS);
90+
return createAppointment(nextAttempt, summary, description, email);
91+
}
92+
93+
const event = {
94+
summary,
95+
description,
96+
start: { dateTime: dateTime.toISOString(), timeZone: TIME_ZONE },
97+
end: {
98+
dateTime: addHours(dateTime, APPOINTMENT_DURATION_HOURS).toISOString(),
99+
timeZone: TIME_ZONE,
100+
},
101+
attendees: [{ email }],
102+
};
103+
104+
try {
105+
const { data } = await calendar.events.insert({
106+
calendarId: CALENDAR_ID,
107+
resource: event,
108+
});
109+
return data.htmlLink;
110+
} catch (error) {
111+
console.error("Error booking appointment:", error);
112+
throw new Error("Failed to book appointment");
91113
}
92-
}
114+
};
93115

94-
// // Example usage of booking an appointment
95-
export async function setupMeeting(dateTime, summary, description, email) {
116+
// Function to setup a meeting
117+
export const setupMeeting = async (date, time, summary, description, email) => {
118+
const dateTime = parseDateTime(date, time);
96119
try {
97120
const bookingLink = await createAppointment(
98121
dateTime,
99122
summary,
100123
description,
101-
102124
email
103125
);
104126
console.log(
@@ -107,4 +129,70 @@ export async function setupMeeting(dateTime, summary, description, email) {
107129
} catch (error) {
108130
console.error("Failed to schedule the meeting:", error);
109131
}
110-
}
132+
};
133+
134+
const parseDateTime = (date, time) => {
135+
const dateTimeFormats = [
136+
"dd/MM/yyyy HH:mm",
137+
"dd/MM/yyyy hh:mm a",
138+
"dd-MM-yyyy HH:mm",
139+
"dd-MM-yyyy hh:mm a",
140+
"yyyy-MM-dd'T'HH:mm:ssX",
141+
];
142+
143+
for (const formatString of dateTimeFormats) {
144+
const parsedDate = parse(`${date} ${time}`, formatString, new Date());
145+
if (isValid(parsedDate)) {
146+
return parsedDate;
147+
}
148+
}
149+
150+
throw new Error("Invalid date-time value");
151+
};
152+
153+
// Function to send meeting details to user's email
154+
export const sendMeetingDetails = async (
155+
meetingLink,
156+
email,
157+
meetingDetails
158+
) => {
159+
const nodemailer = require("nodemailer");
160+
161+
// Create a transport object
162+
const transporter = nodemailer.createTransport({
163+
host: "smtp.gmail.com",
164+
port: 587,
165+
secure: false, // or 'STARTTLS'
166+
auth: {
167+
168+
pass: "Gil@sapir2309",
169+
},
170+
});
171+
172+
// Define the email message
173+
const mailOptions = {
174+
175+
to: email,
176+
subject: "Meeting Details",
177+
html: `
178+
<p>Dear Participant,</p>
179+
<p>We are pleased to invite you to the following meeting:</p>
180+
<p><strong>Meeting Details:</strong></p>
181+
<ul>
182+
<li><strong>Date:</strong> ${meetingDetails.date}</li>
183+
<li><strong>Time:</strong> ${meetingDetails.time}</li>
184+
<li><strong>Agenda:</strong> ${meetingDetails.agenda}</li>
185+
</ul>
186+
<p>You can join the meeting using this link: <a href="${meetingLink}">${meetingLink}</a></p>
187+
<p>We look forward to your participation.</p>
188+
`,
189+
};
190+
191+
// Send the email
192+
transporter.sendMail(mailOptions, (error, info) => {
193+
if (error) {
194+
return console.log(error);
195+
}
196+
console.log("Email sent: " + info.response);
197+
});
198+
};

checkDateTimeAvailability.json

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
2-
"type": "function",
3-
"function":{
2+
43
"name": "checkDateTimeAvailability",
54
"description": "Checks if the specified date and time are available in the calendar.",
65
"parameters": {
@@ -14,5 +13,5 @@
1413
},
1514
"required": ["dateTimeToCheck"]
1615
}
17-
}
16+
1817
}

createAppointment.json

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
2-
"type": "function",
3-
"function":{
2+
43
"name": "createAppointment",
54
"description": "Creates an appointment in the calendar if the time slot is available.",
65
"parameters": {
@@ -31,5 +30,5 @@
3130
},
3231
"required": ["dateTimeToCheck", "summary", "description", "location", "email"]
3332
}
34-
}
33+
3534
}

0 commit comments

Comments
 (0)