diff --git a/README.md b/README.md
index 941dcea..d661a86 100644
--- a/README.md
+++ b/README.md
@@ -3,4 +3,5 @@ FA23: p-reset
### People
Sumi Vora
Vivien Song
-Haram Yoon
\ No newline at end of file
+Haram Yoon
+Mohamed Hamouda
\ No newline at end of file
diff --git a/client/.env b/client/.env
new file mode 100644
index 0000000..19d3d35
--- /dev/null
+++ b/client/.env
@@ -0,0 +1,6 @@
+GOOGLE_CLIENT_ID = 757306875568-76c8a3tmj1hhousioaa6a2587rq2tjir.apps.googleusercontent.com
+GOOGLE_CLIENT_SECRET = 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
+
+NEXTAUTH_URL = http://localhost:3000
+
+JWT_SECRET = c085ce0c5c21a4d774591a20b981013e
diff --git a/client/components/add_event.js b/client/components/add_event.js
new file mode 100644
index 0000000..d234168
--- /dev/null
+++ b/client/components/add_event.js
@@ -0,0 +1,70 @@
+// add_event.jsx
+
+import React, { useState } from "react";
+
+function AddEvent() {
+ const [title, setTitle] = useState("");
+ const [description, setDescription] = useState("");
+ const [startDate, setStartDate] = useState("");
+ const [endDate, setEndDate] = useState("");
+
+ const fullStartDate = `${startDate}:00`;
+ const fullEndDate = `${endDate}:00`;
+
+ const handleSubmit = async () => {
+ const eventBody = {
+ summary: title,
+ description: description,
+ start: { dateTime: fullStartDate, timeZone: "America/Los_Angeles" }, // Adjust timeZone as needed
+ end: { dateTime: fullEndDate, timeZone: "America/Los_Angeles" }
+ };
+
+ try {
+ console.log(eventBody);
+ const response = await fetch("http://localhost:8080/add_event", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify(eventBody),
+ credentials: 'include'
+ });
+
+ if (response.ok) {
+ alert("Event added successfully!");
+ window.location.href = "http://localhost:3000"; // Redirect to homepage
+ } else {
+ alert("Failed to add event. Please try again.");
+ }
+ } catch (error) {
+ console.error("Error adding event:", error);
+ }
+ };
+
+ return (
+
+
+
Add Event
+
+
+ setTitle(e.target.value)} />
+
+
+
+
+
+
+ setStartDate(e.target.value)} />
+
+
+
+ setEndDate(e.target.value)} />
+
+
+
+
+ );
+}
+
+export default AddEvent;
\ No newline at end of file
diff --git a/client/package-lock.json b/client/package-lock.json
index c955cf5..a69c7ef 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -8,16 +8,20 @@
"name": "client",
"version": "0.1.0",
"dependencies": {
- "next": "latest",
- "react": "latest",
+ "@fullcalendar/daygrid": "^6.1.9",
+ "@fullcalendar/react": "^6.1.9",
+ "fullcalendar": "^6.1.9",
+ "next": "^13.5.4",
+ "next-auth": "^4.23.2",
+ "react": "^18.2.0",
"react-dom": "latest"
},
"devDependencies": {
"autoprefixer": "latest",
"eslint": "latest",
"eslint-config-next": "latest",
- "postcss": "latest",
- "tailwindcss": "latest"
+ "postcss": "^8.4.31",
+ "tailwindcss": "^3.3.5"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -45,7 +49,6 @@
"version": "7.23.1",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.1.tgz",
"integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==",
- "dev": true,
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@@ -109,6 +112,79 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/@fullcalendar/core": {
+ "version": "6.1.9",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.9.tgz",
+ "integrity": "sha512-eeG+z9BWerdsU9Ac6j16rpYpPnE0wxtnEHiHrh/u/ADbGTR3hCOjCD9PxQOfhOTHbWOVs7JQunGcksSPu5WZBQ==",
+ "dependencies": {
+ "preact": "~10.12.1"
+ }
+ },
+ "node_modules/@fullcalendar/core/node_modules/preact": {
+ "version": "10.12.1",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz",
+ "integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/preact"
+ }
+ },
+ "node_modules/@fullcalendar/daygrid": {
+ "version": "6.1.9",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.9.tgz",
+ "integrity": "sha512-o/6joH/7lmVHXAkbaa/tUbzWYnGp/LgfdiFyYPkqQbjKEeivNZWF1WhHqFbhx0zbFONSHtrvkjY2bjr+Ef2quQ==",
+ "peerDependencies": {
+ "@fullcalendar/core": "~6.1.9"
+ }
+ },
+ "node_modules/@fullcalendar/interaction": {
+ "version": "6.1.9",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-6.1.9.tgz",
+ "integrity": "sha512-I3FGnv0kKZpIwujg3HllbKrciNjTqeTYy3oJG226oAn7lV6wnrrDYMmuGmA0jPJAGN46HKrQqKN7ItxQRDec4Q==",
+ "peerDependencies": {
+ "@fullcalendar/core": "~6.1.9"
+ }
+ },
+ "node_modules/@fullcalendar/list": {
+ "version": "6.1.9",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/list/-/list-6.1.9.tgz",
+ "integrity": "sha512-OCKdC1Gz26cJ5QsXdQyXVyzVu23ypT2xzyAR+Wc8jEytcJLWXw2a914m/MVax8n8EHuaIYY2exhsy/eaSU0XNA==",
+ "peerDependencies": {
+ "@fullcalendar/core": "~6.1.9"
+ }
+ },
+ "node_modules/@fullcalendar/multimonth": {
+ "version": "6.1.9",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/multimonth/-/multimonth-6.1.9.tgz",
+ "integrity": "sha512-YpH1NL6RzdM1wO2nFJ3pNMo9xhd6i2WuE+e7SnGi7q1lO+ZZ77h5Fja5JKcpuIQUFHpi+m6vTzihIV8DT44NnQ==",
+ "dependencies": {
+ "@fullcalendar/daygrid": "~6.1.9"
+ },
+ "peerDependencies": {
+ "@fullcalendar/core": "~6.1.9"
+ }
+ },
+ "node_modules/@fullcalendar/react": {
+ "version": "6.1.9",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/react/-/react-6.1.9.tgz",
+ "integrity": "sha512-ioxu0V++pYz2u/N1LL1V8DkMyiKGRun0gMAll2tQz3Kzi3r9pTwncGKRb1zO8h0e+TrInU08ywk/l5lBwp7eog==",
+ "peerDependencies": {
+ "@fullcalendar/core": "~6.1.9",
+ "react": "^16.7.0 || ^17 || ^18",
+ "react-dom": "^16.7.0 || ^17 || ^18"
+ }
+ },
+ "node_modules/@fullcalendar/timegrid": {
+ "version": "6.1.9",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/timegrid/-/timegrid-6.1.9.tgz",
+ "integrity": "sha512-le7UV05wVE1Trdr054kgJXTwa+A1pEI8nlCBnPWdcyrL+dTLoPvQ4AWEVCnV7So+4zRYaCqnqGXfCJsj0RQa0g==",
+ "dependencies": {
+ "@fullcalendar/daygrid": "~6.1.9"
+ },
+ "peerDependencies": {
+ "@fullcalendar/core": "~6.1.9"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.11",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
@@ -191,9 +267,9 @@
}
},
"node_modules/@next/env": {
- "version": "13.5.3",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.3.tgz",
- "integrity": "sha512-X4te86vsbjsB7iO4usY9jLPtZ827Mbx+WcwNBGUOIuswuTAKQtzsuoxc/6KLxCMvogKG795MhrR1LDhYgDvasg=="
+ "version": "13.5.4",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.4.tgz",
+ "integrity": "sha512-LGegJkMvRNw90WWphGJ3RMHMVplYcOfRWf2Be3td3sUa+1AaxmsYyANsA+znrGCBjXJNi4XAQlSoEfUxs/4kIQ=="
},
"node_modules/@next/eslint-plugin-next": {
"version": "13.5.3",
@@ -205,9 +281,9 @@
}
},
"node_modules/@next/swc-darwin-arm64": {
- "version": "13.5.3",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.3.tgz",
- "integrity": "sha512-6hiYNJxJmyYvvKGrVThzo4nTcqvqUTA/JvKim7Auaj33NexDqSNwN5YrrQu+QhZJCIpv2tULSHt+lf+rUflLSw==",
+ "version": "13.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.4.tgz",
+ "integrity": "sha512-Df8SHuXgF1p+aonBMcDPEsaahNo2TCwuie7VXED4FVyECvdXfRT9unapm54NssV9tF3OQFKBFOdlje4T43VO0w==",
"cpu": [
"arm64"
],
@@ -220,9 +296,9 @@
}
},
"node_modules/@next/swc-darwin-x64": {
- "version": "13.5.3",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.3.tgz",
- "integrity": "sha512-UpBKxu2ob9scbpJyEq/xPgpdrgBgN3aLYlxyGqlYX5/KnwpJpFuIHU2lx8upQQ7L+MEmz+fA1XSgesoK92ppwQ==",
+ "version": "13.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.4.tgz",
+ "integrity": "sha512-siPuUwO45PnNRMeZnSa8n/Lye5ZX93IJom9wQRB5DEOdFrw0JjOMu1GINB8jAEdwa7Vdyn1oJ2xGNaQpdQQ9Pw==",
"cpu": [
"x64"
],
@@ -235,9 +311,9 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
- "version": "13.5.3",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.3.tgz",
- "integrity": "sha512-5AzM7Yx1Ky+oLY6pHs7tjONTF22JirDPd5Jw/3/NazJ73uGB05NqhGhB4SbeCchg7SlVYVBeRMrMSZwJwq/xoA==",
+ "version": "13.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.4.tgz",
+ "integrity": "sha512-l/k/fvRP/zmB2jkFMfefmFkyZbDkYW0mRM/LB+tH5u9pB98WsHXC0WvDHlGCYp3CH/jlkJPL7gN8nkTQVrQ/2w==",
"cpu": [
"arm64"
],
@@ -250,9 +326,9 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
- "version": "13.5.3",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.3.tgz",
- "integrity": "sha512-A/C1shbyUhj7wRtokmn73eBksjTM7fFQoY2v/0rTM5wehpkjQRLOXI8WJsag2uLhnZ4ii5OzR1rFPwoD9cvOgA==",
+ "version": "13.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.4.tgz",
+ "integrity": "sha512-YYGb7SlLkI+XqfQa8VPErljb7k9nUnhhRrVaOdfJNCaQnHBcvbT7cx/UjDQLdleJcfyg1Hkn5YSSIeVfjgmkTg==",
"cpu": [
"arm64"
],
@@ -265,9 +341,9 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
- "version": "13.5.3",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.3.tgz",
- "integrity": "sha512-FubPuw/Boz8tKkk+5eOuDHOpk36F80rbgxlx4+xty/U71e3wZZxVYHfZXmf0IRToBn1Crb8WvLM9OYj/Ur815g==",
+ "version": "13.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.4.tgz",
+ "integrity": "sha512-uE61vyUSClnCH18YHjA8tE1prr/PBFlBFhxBZis4XBRJoR+txAky5d7gGNUIbQ8sZZ7LVkSVgm/5Fc7mwXmRAg==",
"cpu": [
"x64"
],
@@ -280,9 +356,9 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
- "version": "13.5.3",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.3.tgz",
- "integrity": "sha512-DPw8nFuM1uEpbX47tM3wiXIR0Qa+atSzs9Q3peY1urkhofx44o7E1svnq+a5Q0r8lAcssLrwiM+OyJJgV/oj7g==",
+ "version": "13.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.4.tgz",
+ "integrity": "sha512-qVEKFYML/GvJSy9CfYqAdUexA6M5AklYcQCW+8JECmkQHGoPxCf04iMh7CPR7wkHyWWK+XLt4Ja7hhsPJtSnhg==",
"cpu": [
"x64"
],
@@ -295,9 +371,9 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
- "version": "13.5.3",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.3.tgz",
- "integrity": "sha512-zBPSP8cHL51Gub/YV8UUePW7AVGukp2D8JU93IHbVDu2qmhFAn9LWXiOOLKplZQKxnIPUkJTQAJDCWBWU4UWUA==",
+ "version": "13.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.4.tgz",
+ "integrity": "sha512-mDSQfqxAlfpeZOLPxLymZkX0hYF3juN57W6vFHTvwKlnHfmh12Pt7hPIRLYIShk8uYRsKPtMTth/EzpwRI+u8w==",
"cpu": [
"arm64"
],
@@ -310,9 +386,9 @@
}
},
"node_modules/@next/swc-win32-ia32-msvc": {
- "version": "13.5.3",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.3.tgz",
- "integrity": "sha512-ONcL/lYyGUj4W37D4I2I450SZtSenmFAvapkJQNIJhrPMhzDU/AdfLkW98NvH1D2+7FXwe7yclf3+B7v28uzBQ==",
+ "version": "13.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.4.tgz",
+ "integrity": "sha512-aoqAT2XIekIWoriwzOmGFAvTtVY5O7JjV21giozBTP5c6uZhpvTWRbmHXbmsjZqY4HnEZQRXWkSAppsIBweKqw==",
"cpu": [
"ia32"
],
@@ -325,9 +401,9 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
- "version": "13.5.3",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.3.tgz",
- "integrity": "sha512-2Vz2tYWaLqJvLcWbbTlJ5k9AN6JD7a5CN2pAeIzpbecK8ZF/yobA39cXtv6e+Z8c5UJuVOmaTldEAIxvsIux/Q==",
+ "version": "13.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.4.tgz",
+ "integrity": "sha512-cyRvlAxwlddlqeB9xtPSfNSCRy8BOa4wtMo0IuI9P7Y0XT2qpDrpFKRyZ7kUngZis59mPVla5k8X1oOJ8RxDYg==",
"cpu": [
"x64"
],
@@ -374,6 +450,14 @@
"node": ">= 8"
}
},
+ "node_modules/@panva/hkdf": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.1.1.tgz",
+ "integrity": "sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/@rushstack/eslint-patch": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.5.1.tgz",
@@ -1032,6 +1116,14 @@
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
+ "node_modules/cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -1899,6 +1991,19 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
+ "node_modules/fullcalendar": {
+ "version": "6.1.9",
+ "resolved": "https://registry.npmjs.org/fullcalendar/-/fullcalendar-6.1.9.tgz",
+ "integrity": "sha512-b3y22EqOtV1cGjOlPE6krs1CwQA/8p5lsylllp35tqDLOK7kLIXDQotpXgsDBY4qAKTgdiSauqzdkdvyrbjAgQ==",
+ "dependencies": {
+ "@fullcalendar/core": "~6.1.9",
+ "@fullcalendar/daygrid": "~6.1.9",
+ "@fullcalendar/interaction": "~6.1.9",
+ "@fullcalendar/list": "~6.1.9",
+ "@fullcalendar/multimonth": "~6.1.9",
+ "@fullcalendar/timegrid": "~6.1.9"
+ }
+ },
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@@ -2590,6 +2695,14 @@
"jiti": "bin/jiti.js"
}
},
+ "node_modules/jose": {
+ "version": "4.15.2",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.2.tgz",
+ "integrity": "sha512-IY73F228OXRl9ar3jJagh7Vnuhj/GzBunPiZP13K0lOl7Am9SoWW3kEzq3MCllJMTtZqHTiDXQvoRd4U95aU6A==",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -2740,7 +2853,6 @@
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
@@ -2832,18 +2944,17 @@
"dev": true
},
"node_modules/next": {
- "version": "13.5.3",
- "resolved": "https://registry.npmjs.org/next/-/next-13.5.3.tgz",
- "integrity": "sha512-4Nt4HRLYDW/yRpJ/QR2t1v63UOMS55A38dnWv3UDOWGezuY0ZyFO1ABNbD7mulVzs9qVhgy2+ppjdsANpKP1mg==",
+ "version": "13.5.4",
+ "resolved": "https://registry.npmjs.org/next/-/next-13.5.4.tgz",
+ "integrity": "sha512-+93un5S779gho8y9ASQhb/bTkQF17FNQOtXLKAj3lsNgltEcF0C5PMLLncDmH+8X1EnJH1kbqAERa29nRXqhjA==",
"dependencies": {
- "@next/env": "13.5.3",
+ "@next/env": "13.5.4",
"@swc/helpers": "0.5.2",
"busboy": "1.6.0",
"caniuse-lite": "^1.0.30001406",
- "postcss": "8.4.14",
+ "postcss": "8.4.31",
"styled-jsx": "5.1.1",
- "watchpack": "2.4.0",
- "zod": "3.21.4"
+ "watchpack": "2.4.0"
},
"bin": {
"next": "dist/bin/next"
@@ -2852,15 +2963,15 @@
"node": ">=16.14.0"
},
"optionalDependencies": {
- "@next/swc-darwin-arm64": "13.5.3",
- "@next/swc-darwin-x64": "13.5.3",
- "@next/swc-linux-arm64-gnu": "13.5.3",
- "@next/swc-linux-arm64-musl": "13.5.3",
- "@next/swc-linux-x64-gnu": "13.5.3",
- "@next/swc-linux-x64-musl": "13.5.3",
- "@next/swc-win32-arm64-msvc": "13.5.3",
- "@next/swc-win32-ia32-msvc": "13.5.3",
- "@next/swc-win32-x64-msvc": "13.5.3"
+ "@next/swc-darwin-arm64": "13.5.4",
+ "@next/swc-darwin-x64": "13.5.4",
+ "@next/swc-linux-arm64-gnu": "13.5.4",
+ "@next/swc-linux-arm64-musl": "13.5.4",
+ "@next/swc-linux-x64-gnu": "13.5.4",
+ "@next/swc-linux-x64-musl": "13.5.4",
+ "@next/swc-win32-arm64-msvc": "13.5.4",
+ "@next/swc-win32-ia32-msvc": "13.5.4",
+ "@next/swc-win32-x64-msvc": "13.5.4"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
@@ -2877,27 +2988,31 @@
}
}
},
- "node_modules/next/node_modules/postcss": {
- "version": "8.4.14",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
- "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/postcss"
- }
- ],
+ "node_modules/next-auth": {
+ "version": "4.23.2",
+ "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.23.2.tgz",
+ "integrity": "sha512-VRmInu0r/yZNFQheDFeOKtiugu3bt90Po3owAQDnFQ3YLQFmUKgFjcE2+3L0ny5jsJpBXaKbm7j7W2QTc6Ye2A==",
"dependencies": {
- "nanoid": "^3.3.4",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
+ "@babel/runtime": "^7.20.13",
+ "@panva/hkdf": "^1.0.2",
+ "cookie": "^0.5.0",
+ "jose": "^4.11.4",
+ "oauth": "^0.9.15",
+ "openid-client": "^5.4.0",
+ "preact": "^10.6.3",
+ "preact-render-to-string": "^5.1.19",
+ "uuid": "^8.3.2"
},
- "engines": {
- "node": "^10 || ^12 || >=14"
+ "peerDependencies": {
+ "next": "^12.2.5 || ^13",
+ "nodemailer": "^6.6.5",
+ "react": "^17.0.2 || ^18",
+ "react-dom": "^17.0.2 || ^18"
+ },
+ "peerDependenciesMeta": {
+ "nodemailer": {
+ "optional": true
+ }
}
},
"node_modules/node-releases": {
@@ -2924,6 +3039,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/oauth": {
+ "version": "0.9.15",
+ "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
+ "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA=="
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -3051,6 +3171,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/oidc-token-hash": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz",
+ "integrity": "sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==",
+ "engines": {
+ "node": "^10.13.0 || >=12.0.0"
+ }
+ },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -3060,6 +3188,28 @@
"wrappy": "1"
}
},
+ "node_modules/openid-client": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.6.0.tgz",
+ "integrity": "sha512-uFTkN/iqgKvSnmpVAS/T6SNThukRMBcmymTQ71Ngus1F60tdtKVap7zCrleocY+fogPtpmoxi5Q1YdrgYuTlkA==",
+ "dependencies": {
+ "jose": "^4.15.1",
+ "lru-cache": "^6.0.0",
+ "object-hash": "^2.2.0",
+ "oidc-token-hash": "^5.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
+ "node_modules/openid-client/node_modules/object-hash": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
+ "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
@@ -3200,7 +3350,6 @@
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
- "dev": true,
"funding": [
{
"type": "opencollective",
@@ -3327,6 +3476,26 @@
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true
},
+ "node_modules/preact": {
+ "version": "10.18.1",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.18.1.tgz",
+ "integrity": "sha512-mKUD7RRkQQM6s7Rkmi7IFkoEHjuFqRQUaXamO61E6Nn7vqF/bo7EZCmSyrUnp2UWHw0O7XjZ2eeXis+m7tf4lg==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/preact"
+ }
+ },
+ "node_modules/preact-render-to-string": {
+ "version": "5.2.6",
+ "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz",
+ "integrity": "sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==",
+ "dependencies": {
+ "pretty-format": "^3.8.0"
+ },
+ "peerDependencies": {
+ "preact": ">=10"
+ }
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -3336,6 +3505,11 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/pretty-format": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
+ "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="
+ },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -3449,8 +3623,7 @@
"node_modules/regenerator-runtime": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
- "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==",
- "dev": true
+ "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA=="
},
"node_modules/regexp.prototype.flags": {
"version": "1.5.1",
@@ -3868,9 +4041,9 @@
}
},
"node_modules/tailwindcss": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz",
- "integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==",
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz",
+ "integrity": "sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==",
"dev": true,
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
@@ -3878,10 +4051,10 @@
"chokidar": "^3.5.3",
"didyoumean": "^1.2.2",
"dlv": "^1.1.3",
- "fast-glob": "^3.2.12",
+ "fast-glob": "^3.3.0",
"glob-parent": "^6.0.2",
"is-glob": "^4.0.3",
- "jiti": "^1.18.2",
+ "jiti": "^1.19.1",
"lilconfig": "^2.1.0",
"micromatch": "^4.0.5",
"normalize-path": "^3.0.0",
@@ -4150,6 +4323,14 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true
},
+ "node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/watchpack": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
@@ -4262,8 +4443,7 @@
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/yaml": {
"version": "2.3.2",
@@ -4285,14 +4465,6 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
- },
- "node_modules/zod": {
- "version": "3.21.4",
- "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
- "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==",
- "funding": {
- "url": "https://github.com/sponsors/colinhacks"
- }
}
}
}
diff --git a/client/package.json b/client/package.json
index eb04ea2..709491d 100644
--- a/client/package.json
+++ b/client/package.json
@@ -9,15 +9,19 @@
"lint": "next lint"
},
"dependencies": {
- "react": "latest",
- "react-dom": "latest",
- "next": "latest"
+ "@fullcalendar/daygrid": "^6.1.9",
+ "@fullcalendar/react": "^6.1.9",
+ "fullcalendar": "^6.1.9",
+ "next": "^13.5.4",
+ "next-auth": "^4.23.2",
+ "react": "^18.2.0",
+ "react-dom": "latest"
},
"devDependencies": {
"autoprefixer": "latest",
- "postcss": "latest",
- "tailwindcss": "latest",
"eslint": "latest",
- "eslint-config-next": "latest"
+ "eslint-config-next": "latest",
+ "postcss": "^8.4.31",
+ "tailwindcss": "^3.3.5"
}
}
diff --git a/client/pages/_app.js b/client/pages/_app.js
index 2300201..19eaa91 100644
--- a/client/pages/_app.js
+++ b/client/pages/_app.js
@@ -2,4 +2,4 @@ import '@/styles/globals.css'
export default function App({ Component, pageProps }) {
return
-}
+}
\ No newline at end of file
diff --git a/client/pages/index.js b/client/pages/index.js
index 0d1c7a6..1bec938 100644
--- a/client/pages/index.js
+++ b/client/pages/index.js
@@ -1,31 +1,96 @@
import React, { useEffect, useState } from "react";
+import FullCalendar from '@fullcalendar/react';
+import dayGridPlugin from '@fullcalendar/daygrid';
+import AddEvent from "@/components/add_event";
function index() {
- const [message, setMessage] = useState("Loading"); // set state variable
- const [people, setPeople] = useState([]); // make array for 'people' from server.py
-
- useEffect(() => { // allows us to create side effects in functional components
- fetch("http://localhost:8080/api/home")
- .then( // calls the endpoint
- (response) => response.json() // get response from api, put into json
- ).then(
- (data) => { // retrieve data
- console.log(data); // so we can check console.log and see that we
- // are getting the api endpoint data
- // message initially set to loading in line 5
- setMessage(data.message); // once we get data, set message state variable to data
- setPeople(data.people); // accessing people variable from backend
- });
- }, []);
+ const [userInfo, setUserInfo] = useState(null);
+ const [events, setEvents] = useState([]);
+ const calendarEvents = Array.isArray(events) ?
+ events.map(event => ({
+ title: event.summary,
+ start: new Date(event.start.dateTime),
+ end: new Date(event.end.dateTime),
+ })) : [];
+
+
+
+ useEffect(() => {
+ fetch('http://localhost:8080/user_info', {credentials: 'include'})
+ .then(response => response.json())
+ .then(data => {
+ console.log(data);
+ setUserInfo(data);
+ });
+
+ fetch('http://localhost:8080/events', {credentials: 'include'})
+ .then(response => response.json())
+ .then(data => {
+ console.log("now printing")
+ console.log(data);
+ setEvents(data);
+ });
+}, []);
return(
-
{message}
-
- {people.map((person, index) => ( // grabs person in people array by index and displays
-
{person}
- ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* {userInfo && (
+
+

+
Welcome to P-reset, {userInfo.given_name}!
+
+ )} */}
+ {/* {events.length > 0 && (
+
+
10 Upcoming Events
+
+ {events.map(event => (
+ -
+ {event.summary}: {new Date(event.start.dateTime || event.start.date).toLocaleString()}
+
+ ))}
+
+
+ )} */}
+
+ {/* Calendar Section */}
+
+
+
+
+ {/* Right Side Section for Button and Form */}
+
+
+
);
}
diff --git a/client/styles/globals.css b/client/styles/globals.css
index b5c61c9..b53e26e 100644
--- a/client/styles/globals.css
+++ b/client/styles/globals.css
@@ -1,3 +1,82 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
+
+/* Base button styling */
+.button {
+ display: inline-block;
+ margin: 2.5px;
+ padding: 10px 20px;
+ font-size: 16px;
+ font-weight: 600;
+ border: none;
+ border-radius: 5px;
+ background-color: #007BFF; /* Default blue color */
+ color: #FFFFFF; /* White text color */
+ cursor: pointer;
+ text-align: center;
+ text-decoration: none;
+ transition: background-color 0.3s ease, transform 0.3s ease;
+}
+
+/* Hover effect for the button */
+.button:hover {
+ background-color: #0056b3; /* Slightly darker blue on hover */
+ transform: scale(1.05); /* Slightly enlarge the button on hover */
+}
+
+/* Active state (when button is clicked) */
+.button:active {
+ background-color: #004499; /* Even darker blue on active state */
+ transform: scale(0.95); /* Slightly reduce the button size when clicked */
+}
+
+/* Optional: If you want a different style for a disabled button */
+.button:disabled {
+ background-color: #CCCCCC; /* Grayish background for disabled button */
+ color: #888888; /* Grayish text color for disabled button */
+ cursor: not-allowed;
+}
+
+/* Basic styling for all input elements */
+input, textarea {
+ width: 50%; /* Full width */
+ padding: 10px; /* Add some padding */
+ margin: 8px 0; /* Add some margin for spacing */
+ display: inline-block; /* Make it inline-block */
+ border: 1px solid #ccc; /* Basic border */
+ border-radius: 4px; /* Rounded corners */
+ box-sizing: border-box; /* Box sizing */
+}
+
+input[type="datetime-local"] {
+ width: 200px;
+ padding: 10px;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ background-color: #f9f9f9; /* Light grey background */
+ font-size: 16px; /* Font size */
+ color: #333; /* Text color */
+}
+
+input[type="datetime-local"]:focus {
+ border-color: #4CAF50; /* Green border on focus */
+ background-color: #e9e9e9; /* Slightly darker grey background on focus */
+ outline: none; /* Remove browser default outline */
+}
+
+textarea {
+ resize: vertical; /* Allow vertical resizing only */
+ min-height: 100px; /* Minimum height for the textarea */
+}
+
+div {
+ margin-left: 5px;
+ margin-top: 10px;
+ margin-bottom: 5px;
+ margin-right: 10px;
+}
+
+hr {
+ margin-top: 10px;
+}
\ No newline at end of file
diff --git a/server/.env b/server/.env
new file mode 100644
index 0000000..73d322b
--- /dev/null
+++ b/server/.env
@@ -0,0 +1,2 @@
+CLIENT_ID=757306875568-76c8a3tmj1hhousioaa6a2587rq2tjir.apps.googleusercontent.com
+CLIENT_SECRET=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
\ No newline at end of file
diff --git a/server/.flask_session/2029240f6d1128be89ddc32729463129 b/server/.flask_session/2029240f6d1128be89ddc32729463129
new file mode 100644
index 0000000..ffb2cd9
Binary files /dev/null and b/server/.flask_session/2029240f6d1128be89ddc32729463129 differ
diff --git a/server/.flask_session/77a9375769618bc3960ced8d692a17d0 b/server/.flask_session/77a9375769618bc3960ced8d692a17d0
new file mode 100644
index 0000000..418dbc8
Binary files /dev/null and b/server/.flask_session/77a9375769618bc3960ced8d692a17d0 differ
diff --git a/server/.flask_session/ceb926795b3aee31e24faffd5df9f47e b/server/.flask_session/ceb926795b3aee31e24faffd5df9f47e
new file mode 100644
index 0000000..b5cda9f
Binary files /dev/null and b/server/.flask_session/ceb926795b3aee31e24faffd5df9f47e differ
diff --git a/server/server.py b/server/server.py
index 8ebea6a..4123ff3 100644
--- a/server/server.py
+++ b/server/server.py
@@ -1,18 +1,149 @@
# write flask code in python here
-from flask import Flask, jsonify
+from flask import Flask, redirect, request, jsonify, session, make_response
from flask_cors import CORS
+from google.oauth2.credentials import Credentials
+from google_auth_oauthlib.flow import Flow
+from googleapiclient.discovery import build
+from flask_session import Session
+from datetime import datetime
+from dotenv import load_dotenv
+import os
+os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
+
+load_dotenv()
app = Flask(__name__)
-CORS(app)
-
-# make api requests
-@app.route("/api/home", methods=['GET'])
-def return_home():
- return jsonify({
- 'message': "P-reset starter page!",
- 'people': ['Sumi', 'Vivien', 'Haram', 'Tara'
- 'Angie', 'Abrar', 'Mohamed', 'Grace',
- 'Sadhvi', 'Erin']
- })
+CORS(app, origins=["http://localhost:3000", "http://localhost:3000/add_event"], supports_credentials=True)
+app.config['SESSION_COOKIE_SECURE'] = False
+app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
+
+# Configure session to use filesystem
+app.config['SESSION_TYPE'] = 'filesystem'
+app.config['SESSION_FILE_DIR'] = './.flask_session/'
+app.config['SESSION_PERMANENT'] = False
+app.config['SESSION_COOKIE_NAME'] = 'session'
+
+Session(app)
+
+app.secret_key = 'c085ce0c5c21a4d774591a20b981013e'
+
+CLIENT_ID = os.environ.get('CLIENT_ID', '00000')
+CLIENT_SECRET = os.environ.get('CLIENT_SECRET', '00000')
+REDIRECT_URI = 'http://localhost:8080/google/callback'
+
+
+@app.route('/google/login', methods=['GET'])
+def google_login():
+ flow = Flow.from_client_config(
+ {
+ "web": {
+ "client_id": CLIENT_ID,
+ "client_secret": CLIENT_SECRET,
+ "redirect_uris": [REDIRECT_URI],
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
+ "token_uri": "https://accounts.google.com/o/oauth2/token",
+ }
+ },
+ scopes=["https://www.googleapis.com/auth/calendar", "https://www.googleapis.com/auth/userinfo.profile"],
+ )
+
+ flow.redirect_uri = REDIRECT_URI
+ authorization_url, state = flow.authorization_url(prompt='consent', access_type='offline')
+ session['state'] = state
+ return redirect(authorization_url)
+
+@app.route('/google/callback')
+def google_callback():
+ if 'state' not in session:
+ return "State value missing in session", 400
+ state = session['state']
+ flow = Flow.from_client_config(
+ {
+ "web": {
+ "client_id": CLIENT_ID,
+ "client_secret": CLIENT_SECRET,
+ "redirect_uris": [REDIRECT_URI],
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
+ "token_uri": "https://accounts.google.com/o/oauth2/token",
+ }
+ },
+ state=state,
+ scopes=["https://www.googleapis.com/auth/calendar", "https://www.googleapis.com/auth/userinfo.profile"],
+ )
+ flow.redirect_uri = REDIRECT_URI
+ authorization_response = request.url
+ flow.fetch_token(authorization_response=authorization_response)
+ credentials = flow.credentials
+
+ session['credentials'] = {
+ 'token': credentials.token,
+ 'refresh_token': credentials.refresh_token,
+ 'token_uri': credentials.token_uri,
+ 'client_id': credentials.client_id,
+ 'client_secret': credentials.client_secret,
+ 'scopes': credentials.scopes,
+ }
+
+ return redirect('http://localhost:3000')
+
+
+@app.route('/user_info')
+def get_user_info():
+ #print(session)
+ credentials = session.get("credentials")
+ if not credentials:
+ return jsonify({"error": "Not authenticated"}), 401
+
+ creds = Credentials(**credentials)
+ service = build('oauth2', 'v2', credentials=creds)
+ #print(credentials)
+ user_info = service.userinfo().get().execute()
+
+ return jsonify(user_info)
+
+@app.route('/events', methods=['GET'])
+def get_events():
+ credentials = session.get('credentials')
+ if not credentials:
+ return jsonify({"error": "Not authenticated"}), 401
+
+ creds = Credentials(**credentials)
+ service = build('calendar', 'v3', credentials=creds)
+
+ # Get the current time in RFC3339 format
+ now = datetime.utcnow().isoformat() + 'Z'
+
+ events_result = service.events().list(calendarId='primary', timeMin=now,
+ maxResults=50, singleEvents=True,
+ orderBy='startTime').execute()
+ events = events_result.get('items', [])
+
+ return jsonify(events)
+
+@app.route('/add_event', methods=['POST'])
+def add_event():
+ credentials = session.get('credentials')
+ if not credentials:
+ return jsonify({"error": "Not authenticated"}), 401
+
+ creds = Credentials(**credentials)
+ service = build('calendar', 'v3', credentials=creds)
+
+ event_body = request.json
+ try:
+ event = service.events().insert(calendarId='primary', body=event_body).execute()
+ return jsonify(event)
+ except Exception as e:
+ # Logging the exception
+ print(f"An error occurred: {e}")
+ return jsonify({"error": "Failed to add event", "details": str(e)}), 500
+
+
+@app.route('/logout', methods=['GET'])
+def logout():
+ session.pop('credentials', None)
+ return redirect('http://localhost:3000')
+
+
if __name__ == "__main__":
app.run(debug=True, port=8080)
\ No newline at end of file