498 lines
16 KiB
JavaScript
498 lines
16 KiB
JavaScript
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);
|
|
}
|
|
};
|
|
|
|
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();
|