school-schedule-sync
Version:
Synchronization between JSON schedule and Google Calendar
85 lines • 4.64 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.sync = sync;
const fs_1 = __importDefault(require("fs"));
const google_api_wrapper_1 = require("@anmiles/google-api-wrapper");
const logger_1 = require("@anmiles/logger");
const zod_tools_1 = require("@anmiles/zod-tools");
const calendar_1 = require("googleapis/build/src/apis/calendar");
require("@anmiles/prototypes");
const types_1 = require("./types");
const getFirstDay_1 = require("./utils/getFirstDay");
const paths_1 = require("./utils/paths");
const fullScopes = [
'https://www.googleapis.com/auth/calendar.calendars.readonly',
'https://www.googleapis.com/auth/calendar.calendarlist.readonly',
'https://www.googleapis.com/auth/calendar.events.owned',
];
async function sync(profile, calendarName) {
const YEAR = new Date().getFullYear();
const TIMEZONE = Intl.DateTimeFormat().resolvedOptions().timeZone;
const scheduleJSON = fs_1.default.readJSON((0, paths_1.getScheduleFile)());
const schedule = (0, zod_tools_1.validate)(scheduleJSON, types_1.scheduleSchema);
const calendarAPI = await (0, google_api_wrapper_1.getAPI)((auth) => (0, calendar_1.calendar)({ version: 'v3', auth }), profile, { temporary: true, scopes: fullScopes });
const allCalendars = await calendarAPI.getItems((api) => api.calendarList, {}, { hideProgress: true });
if (allCalendars.length === 0) {
throw new Error(`There are no available calendars for profile '${profile}'`);
}
const selectedCalendars = calendarName
? schedule.calendars.filter((calendar) => calendar.name === calendarName)
: schedule.calendars;
if (selectedCalendars.length === 0) {
throw new Error(`There is no calendar '${calendarName}' for profile '${profile}'`);
}
for (const calendar of selectedCalendars) {
(0, logger_1.info)(`Calendar '${calendar.name}'...`);
const calendarId = allCalendars.find((c) => c.summary === calendar.name)?.id;
if (!calendarId) {
throw new Error(`Unknown calendar '${calendar.name}' for profile '${profile}'`);
}
(0, logger_1.log)('Clearing calendar...');
const allEvents = await calendarAPI.getItems((api) => api.events, { calendarId }, { hideProgress: true });
await allEvents.forEachAsync(async (event) => {
(0, logger_1.log)(` ${event.summary}`);
await calendarAPI.api.events.delete({ calendarId, eventId: event.id ?? '' });
});
(0, logger_1.log)('Creating events...');
const sectionsOrLessons = calendar.type === 'sections'
? calendar.days
: calendar.days.map((day) => day.map((name, index) => {
const time = calendar.lessonTimes?.[index] ?? schedule.defaults.lessonTimes?.[index];
if (!time) {
throw new Error(`Cannot find time described for lesson #${index + 1} in calendar '${calendar.name}'`);
}
return { name, ...time };
}));
await sectionsOrLessons.forEachAsync(async (events, weekDay) => {
const firstDay = (0, getFirstDay_1.getFirstDay)(weekDay, YEAR);
(0, logger_1.log)(` #${weekDay + 1}`);
await events.forEachAsync(async (event) => {
const [startHour, startMinute] = event.startTime.split(':').map((str) => parseInt(str)).toTuple(2);
const startDate = new Date(firstDay);
startDate.setHours(startHour);
startDate.setMinutes(startMinute);
const endDate = new Date(startDate);
endDate.setMinutes(endDate.getMinutes() + event.length);
const dayAbbr = firstDay.toLocaleDateString('en-US', { weekday: 'short' }).slice(0, 2).toUpperCase();
(0, logger_1.log)(` ${event.startTime} ${event.name}`);
await calendarAPI.api.events.insert({
calendarId,
requestBody: {
start: { dateTime: startDate.toISOString(), timeZone: TIMEZONE },
end: { dateTime: endDate.toISOString(), timeZone: TIMEZONE },
summary: event.name,
location: event.location,
recurrence: [`RRULE:FREQ=WEEKLY;WKST=MO;UNTIL=${YEAR + 1}0525T000000Z;BYDAY=${dayAbbr}`],
},
}, {});
});
});
}
}
//# sourceMappingURL=sync.js.map