initial commit - code moved to separate repo
This commit is contained in:
480
src/helpers/calendar.js
Normal file
480
src/helpers/calendar.js
Normal file
@ -0,0 +1,480 @@
|
||||
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<OAuth2Client|null>}
|
||||
// */
|
||||
// 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<void>}
|
||||
// */
|
||||
// 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);
|
||||
}
|
||||
};
|
||||
|
||||
exports.GenerateICS = GenerateICS;
|
||||
exports.createEvent = createEvent;
|
||||
|
||||
createEvent();
|
Reference in New Issue
Block a user