const fs = require("fs").promises; const path = require("path"); const process = require("process"); const { google } = require("googleapis"); const { OAuth2Client } = require("google-auth-library"); const http = require("http"); const url = require("url"); // const destroyer = require('server-destroy'); const CON = require("./const"); const TOKEN_PATH = path.join(process.cwd(), "content/token.json"); const CREDENTIALS_PATH = path.join( process.cwd(), "content/client_secret_926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com.json" ); //generates iCalendar file for a single shift GenerateICS = function (shifts) { // https://stackoverflow.com/questions/3665115/create-a-file-in-memory-for-user-to-download-not-through-server var content = "BEGIN:VCALENDAR\n"; content += "VERSION:2.0\n"; content += "PRODID:-//JW Cart//Shift Info//EN\n"; content += "CALSCALE:GREGORIAN\n"; content += "METHOD:PUBLISH\n"; content += "X-WR-CALNAME:Колички София-Изток\n"; content += "X-WR-TIMEZONE:Europe/Sofia\n"; content += "BEGIN:VTIMEZONE\n"; content += "TZID:Europe/Sofia\n"; content += "BEGIN:DAYLIGHT\n"; content += "TZOFFSETFROM:+0200\n"; content += "TZOFFSETTO:+0300\n"; content += "TZNAME:EEST\n"; content += "DTSTART:19700329T020000\n"; content += "RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\n"; content += "END:DAYLIGHT\n"; content += "BEGIN:STANDARD\n"; content += "TZOFFSETFROM:+0300\n"; content += "TZOFFSETTO:+0200\n"; content += "TZNAME:EET\n"; content += "DTSTART:19701025T030000\n"; content += "RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\n"; content += "END:STANDARD\n"; content += "END:VTIMEZONE\n"; content += shifts?.map((shift) => { var content = "BEGIN:VEVENT\n"; content += "DTSTAMP:" + new Date().getTime() + "\n"; content += "UID:" + shift.id + "\n"; content += "DTSTART;TZID=Europe/Sofia:" + CON.GetDateTimeShort(shift.startTime) + "\n"; content += "DTEND;TZID=Europe/Sofia:" + CON.GetDateTimeShort(shift.endTime.getTime()) + "\n"; content += "LOCATION:" + shift.cartEvent.location.name + "\n"; // content += "SUMMARY:" + shift.cartEvent.location.name + "\n"; // Adding a VALARM component for a reminder 1 day before the event content += "BEGIN:VALARM\n"; content += "TRIGGER:-P1D\n"; // Trigger alarm 1 day before the event content += "ACTION:DISPLAY\n"; content += "DESCRIPTION:Reminder\n"; content += "END:VALARM\n"; content += "END:VEVENT"; return content; }) .join("\n"); content += "END:VCALENDAR\n"; //encode content in base64 to be send as attachment return Buffer.from(content).toString("base64"); }; // /** // * Reads previously authorized credentials from the save file. // * // * @return {Promise} // */ // loadSavedCredentialsIfExist = async function loadSavedCredentialsIfExist() { // try { // const content = await fs.readFile(TOKEN_PATH); // const credentials = JSON.parse(content); // return google.auth.fromJSON(credentials); // } catch (err) { // return null; // } // } // /** // * Serializes credentials to a file compatible with GoogleAUth.fromJSON. // * // * @param {OAuth2Client} client // * @return {Promise} // */ // saveCredentials = async function saveCredentials(client) { // const content = await fs.readFile(CREDENTIALS_PATH); // const keys = JSON.parse(content); // const key = keys.installed || keys.web; // const payload = JSON.stringify({ // type: 'authorized_user', // client_id: key.client_id, // client_secret: key.client_secret, // refresh_token: client.credentials.refresh_token, // }); // await fs.writeFile(TOKEN_PATH, payload); // } // /** // * Load or request or authorization to call APIs. // * // */ // authorize = async function authorize() { // let client = await exports.loadSavedCredentialsIfExist(); // if (client) { // return client; // } // client = await exports.authenticate({ // scopes: SCOPES, // keyfilePath: CREDENTIALS_PATH, // }); // if (client.credentials) { // await saveCredentials(client); // } // return client; // } // /** // * Lists the next 10 events on the user's primary calendar. // * @param {google.auth.OAuth2} auth An authorized OAuth2 client. // */ // listEvents = async function listEvents(auth) { // const calendar = google.calendar({ version: 'v3', auth }); // const res = await calendar.events.list({ // calendarId: 'primary', // timeMin: new Date().toISOString(), // maxResults: 10, // singleEvents: true, // orderBy: 'startTime', // }); // const events = res.data.items; // if (!events || events.length === 0) { // console.log('No upcoming events found.'); // return; // } // console.log('Upcoming 10 events:'); // events.map((event, i) => { // const start = event.start.dateTime || event.start.date; // console.log(`${start} - ${event.summary}`); // }); // } // //usage // GetEvents = async function GetEvents(dateTime = new Date()) { // var events = exports.authorize().then(exports.listEvents).catch(console.error); // } // // const calendar = google.calendar({ version: 'v3', auth }); // const eventTest = { // summary: 'Test Event', // start: { // dateTime: '2023-01-01T09:00:00-07:00', // timeZone: 'Europe/Sofia', // }, // end: { // dateTime: '2023-01-01T17:00:00-07:00', // timeZone: 'Europe/Sofia', // }, // }; // const TOKEN_PATH = path.join(process.cwd(), 'content/token.json'); // const CREDENTIALS_PATH = path.join(process.cwd(), 'content/client_secret_926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com.json'); createEvent = async function createEvent(id) { // var eventTest2 = { // 'summary': 'Google I/O 2015', // 'location': '800 Howard St., San Francisco, CA 94103', // 'description': 'A chance to hear more about Google\'s developer products.', // 'start': { // 'dateTime': '2015-05-28T09:00:00-07:00', // 'timeZone': 'America/Los_Angeles', // }, // 'end': { // 'dateTime': '2015-05-28T17:00:00-07:00', // 'timeZone': 'America/Los_Angeles', // }, // 'recurrence': [ // 'RRULE:FREQ=DAILY;COUNT=2' // ], // 'attendees': [ // { 'email': '' }, // ], // 'reminders': { // 'useDefault': false, // 'overrides': [ // { 'method': 'email', 'minutes': 24 * 60 }, // { 'method': 'popup', 'minutes': 10 }, // ], // }, // }; // var errors; // var auth = await exports.authorize().then((auth) => { // const calendar = google.calendar({ version: 'v3', auth }); // const res = calendar.events.insert({ // calendarId: 'primary', // resource: eventTest, // }, (err, event) => { // if (err) { // console.log(`There was an error creating the event: ${err}`); // return; // } // console.log(`Event created: ${event.data.htmlLink}`); // }); // }).catch(console.error).then((err) => { // errors = err; // }); // return errors; // } // authorizeNew = async function authorizeNew() { // let client = await loadSavedCredentialsIfExist(); // if (client) { // return client; // } // // Set up the Google Calendar API client // const calendar = google.calendar({ version: 'v3', auth }); // // Load the client secrets from a JSON file fs.readFile("./path/to/client_secret.json", (err, content) => { if (err) return console.error("Error loading client secret file:", err); // Authorize a client with the loaded credentials authorizeOA(JSON.parse(content), calendar.calendarList.list); }); if (client.credentials) { await saveCredentials(client); } return client; }; // var googletoken = axiosInstance.get("/content/google_token.json"); // console.log("googletoken: " + googletoken); // if (!googletoken) { // toast.error("Google token not found. redirecting to google login"); // const { data, error } = axiosInstance.get('/content/client_secret_926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com.json', // { headers: { 'Content-Type': 'application/json' } }); // console.log("data: " + JSON.stringify(data)); // console.log("error: " + JSON.stringify(error)); // var secrets = data; // const { google } = await import('googleapis'); // const { OAuth2 } = google.auth; // const oAuth2Client = new OAuth2( // secrets.web.client_id, // secrets.web.client_secret, // secrets.web.redirect_uris[0] // ); // const authorizationUrl = oauth2Client.generateAuthUrl({ // // 'online' (default) or 'offline' (gets refresh_token) // access_type: 'offline', // /** Pass in the scopes array defined above. // * Alternatively, if only one scope is needed, you can pass a scope URL as a string */ // scope: scopes, // // Enable incremental authorization. Recommended as a best practice. // include_granted_scopes: true // }); // return { redirect: authorizationUrl }; /** * Create an OAuth2 client with the given credentials, and then execute the * given callback function. * @param {Object} credentials The authorization client credentials. * @param {function} callback The callback to call with the authorized client. */ function authorizeOA(credentials, callback) { const { client_secret, client_id, redirect_uris } = credentials.installed || credentials.web; const oAuth2Client = new OAuth2Client( client_id, client_secret, redirect_uris[0] ); // Check if we have previously stored a token fs.readFile(TOKEN_PATH, (err, token) => { if (err) return getAccessToken(oAuth2Client, callback); oAuth2Client.setCredentials(JSON.parse(token)); callback(oAuth2Client); }); } /** * Get and store new token after prompting for user authorization, and then * execute the given callback with the authorized OAuth2 client. * @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for. * @param {getEventsCallback} callback The callback for the authorized client. */ function getAccessToken(oAuth2Client, callback) { const authUrl = oAuth2Client.generateAuthUrl({ access_type: "offline", scope: ["https://www.googleapis.com/auth/calendar"], }); console.log("Authorize this app by visiting this url:", authUrl); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); rl.question("Enter the code from that page here: ", (code) => { rl.close(); oAuth2Client.getToken(code, (err, token) => { if (err) return console.error("Error retrieving access token", err); oAuth2Client.setCredentials(token); // Store the token to disk for later program executions fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => { if (err) return console.error(err); console.log("Token stored to", TOKEN_PATH); }); callback(oAuth2Client); }); }); } // // /** // // * Lists the next 10 events on the user's primary calendar. // // * @param {google.auth.OAuth2} auth An authorized OAuth2 client. // // * @param {getEventsCallback} callback The callback for the authorized client. // // * // // */ // // function listEvents(auth) { // // const calendar = google.calendar({ version: 'v3', auth }); // // calendar.events.list({ // // calendarId: 'primary', // // timeMin: (new Date()).toISOString(), // // maxResults: 10, // // singleEvents: true, // // orderBy: 'startTime', // // }, (err, res) => { // // if (err) return console.error('The API returned an error: ' + err); // // const events = res.data.items; // // if (events.length) { // // console.log('Upcoming 10 events:'); // // events.map((event, i) => { // // const start = event.start.dateTime || event.start.date; // // console.log(`${start} - ${event.summary}`); // // }); // // } else { // // console.log('No upcoming events found.'); // // } // // }); // // } // // [END calendar_quickstart] // module.exports = { // GenerateICS, // createEvent, // authorize, // TOKEN_PATH, // CREDENTIALS_PATH // } async function importModules() { const openModule = await import('open'); const getPortModule = await import('get-port'); return { open: openModule.default, getPort: getPortModule.default }; } createEvent = async (event) => { const { open, getPort } = await importModules(); event = event || { summary: "Test Event", location: "Online", start: { dateTime: "2022-12-19T09:00:00Z", timeZone: "UTC", }, end: { dateTime: "2022-12-19T10:00:00Z", timeZone: "UTC", }, }; try { const fc = await fs.readFile(CREDENTIALS_PATH); // const auth = new google.auth.fromClientSecret(fc); const secrets = JSON.parse(fc); const { google } = await import("googleapis"); const { OAuth2 } = google.auth; var callbackUrl = secrets.web.redirect_uris[0]; const freePort = await getPort(); const url = new URL(callbackUrl); url.port = freePort; callbackUrl = url.toString(); const oAuth2Client = new OAuth2( secrets.web.client_id, secrets.web.client_secret, callbackUrl ); // Generate the url that will be used for the consent dialog. const authorizeUrl = oAuth2Client.generateAuthUrl({ access_type: "offline", scope: "https://www.googleapis.com/auth/userinfo.profile", }); let doAuth = await new Promise((resolve, reject) => { const server = http .createServer(async (req, res) => { try { if (req.url.indexOf("/oauth2callback") > -1) { // acquire the code from the querystring, and close the web server. const qs = new url.URL(req.url, "http://localhost:3003") .searchParams; const code = qs.get("code"); console.log(`Code is ${code}`); res.end( "Authentication successful! Please return to the console." ); server.destroy(); // Now that we have the code, use that to acquire tokens. const r = await oAuth2Client.getToken(code); // Make sure to set the credentials on the OAuth2 client. oAuth2Client.setCredentials(r.tokens); auth = oAuth2Client; console.info("Tokens acquired."); resolve(oAuth2Client); } } catch (e) { reject(e); } }) .listen(3003, () => { // open the browser to the authorize url to start the workflow open(authorizeUrl, { wait: false }).then((cp) => cp.unref()); console.log( "Server started for auth flow to complete: " + authorizeUrl ); }); // destroyer(server); }); doAuth.then((auth) => { const calendar = google.calendar({ version: "v3", auth: auth }); calendar.events.insert( { auth: auth, calendarId: "primary", resource: event, }, function (err, event) { if (err) { console.log( "There was an error contacting the Calendar service: " + err ); return; } console.log("Event created: %s", event.htmlLink); } ); }); } catch (err) { console.log(err); } }; SaveEventsInGoogleCalendar = async function SaveEventsInGoogleCalendar(events) { // Load client secrets from a local file. try { const content = await fs.readFile(CREDENTIALS_PATH); // Authorize a client with credentials, then call the Google Calendar API. authorize(JSON.parse(content), createEvent); } catch (err) { console.log("Error loading client secret file:", err); } }; exports.GenerateICS = GenerateICS; exports.createEvent = createEvent; exports.SaveEventsInGoogleCalendar = SaveEventsInGoogleCalendar; //createEvent();