(wip) - show repeating events in calendar (admin)

script to get jwt signature for Apple ID
This commit is contained in:
Dobromir Popov
2024-04-15 22:12:35 +03:00
parent 2b7eab0de9
commit f06fed455b
8 changed files with 80 additions and 97 deletions

View File

@ -1,67 +0,0 @@
#!/bin/node
# https://gist.githubusercontent.com/balazsorban44/09613175e7b37ec03f676dcefb7be5eb/raw/b0d31aa0c7f58e0088fdf59ec30cad1415a3475b/apple-gen-secret.mjs
import { SignJWT } from "jose"
import { createPrivateKey } from "crypto"
if (process.argv.includes("--help") || process.argv.includes("-h")) {
console.log(`
Creates a JWT from the components found at Apple.
By default, the JWT has a 6 months expiry date.
Read more: https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens#3262048
Usage:
node apple.mjs [--kid] [--iss] [--private_key] [--sub] [--expires_in] [--exp]
Options:
--help Print this help message
--kid, --key_id The key id of the private key
--iss, --team_id The Apple team ID
--private_key The private key to use to sign the JWT. (Starts with -----BEGIN PRIVATE KEY-----)
--sub, --client_id The client id to use in the JWT.
--expires_in Number of seconds from now when the JWT should expire. Defaults to 6 months.
--exp Future date in seconds when the JWT expires
`)
} else {
const args = process.argv.slice(2).reduce((acc, arg, i) => {
if (arg.match(/^--\w/)) {
const key = arg.replace(/^--/, "").toLowerCase()
acc[key] = process.argv[i + 3]
}
return acc
}, {})
const {
team_id,
iss = team_id,
private_key,
client_id,
sub = client_id,
key_id,
kid = key_id,
expires_in = 86400 * 180,
exp = Math.ceil(Date.now() / 1000) + expires_in,
} = args
/**
* How long is the secret valid in seconds.
* @default 15780000
*/
const expiresAt = Math.ceil(Date.now() / 1000) + expires_in
const expirationTime = exp ?? expiresAt
console.log(`
Apple client secret generated. Valid until: ${new Date(expirationTime * 1000)}
${await new SignJWT({})
.setAudience("https://appleid.apple.com")
.setIssuer(iss)
.setIssuedAt()
.setExpirationTime(expirationTime)
.setSubject(sub)
.setProtectedHeader({ alg: "ES256", kid })
.sign(createPrivateKey(private_key.replace(/\\n/g, "\n")))}`)
}

View File

@ -298,7 +298,7 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
return itemStart && itemEnd &&
(slotStart.getTime() < itemEnd.getTime()) &&
(slotEnd.getTime() > itemStart.getTime());
(slotEnd.getTime() >= itemStart.getTime());
});
slots.push({

View File

@ -17,7 +17,7 @@ import { MdToday } from 'react-icons/md';
import { useSwipeable } from 'react-swipeable';
import axiosInstance from '../../src/axiosSecure';
// import { set, format, addDays } from 'date-fns';
import { isEqual, isSameDay, getHours, getMinutes } from 'date-fns';
// import { isEqual, isSameDay, getHours, getMinutes } from 'date-fns';
import { filter } from 'jszip';
import e from 'express';
@ -170,6 +170,7 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => {
};
const filterEvents = (evts, publisherId, startdate) => {
setDate(startdate); // Assuming setDate is a function that sets some state or context
const filterHHmm = new Date(startdate).getHours() * 100 + new Date(startdate).getMinutes();
// Filter events based on the publisher ID and the start date/time
const existingEvents = evts?.filter(event => {
@ -177,15 +178,15 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => {
const isPublisherMatch = (event.publisher?.id || event.publisherId) === publisherId;
let isDateMatch;
const eventDate = new Date(event.startTime);
if (event.repeatWeekly && event.date) {
// Compare only the time part
const eventDate = new Date(event.startTime);
const isSameHour = getHours(eventDate) === getHours(startdate);
const isSameMinute = getMinutes(eventDate) === getMinutes(startdate);
isDateMatch = isSameHour && isSameMinute;
let evenStarttHHmm = eventDate.getHours() * 100 + eventDate.getMinutes();
let eventEndHHmm = eventDate.getHours() * 100 + eventDate.getMinutes();
isDateMatch = filterHHmm >= evenStarttHHmm && filterHHmm <= eventEndHHmm;
} else if (event.date) {
// Compare the full date
isDateMatch = isSameDay(new Date(event.date), startdate);
// Compare the full date. issameday is not working. do it manually
isDateMatch = eventDate.setHours(0, 0, 0, 0) === new Date(startdate).setHours(0, 0, 0, 0);
}
return isPublisherMatch && isDateMatch;
@ -203,7 +204,7 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => {
maxTime.setHours(maxHour, 0, 0);
const totalHours = maxHour - minHour;
const handleSelect = ({ start, end }) => {
const handleSelect = ({ mode, start, end }) => {
const startdate = typeof start === 'string' ? new Date(start) : start;
const enddate = typeof end === 'string' ? new Date(end) : end;
@ -230,6 +231,7 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => {
setDate(start);
// get exising events for the selected date
//ToDo: properly fix this. filterEvents does not return the expcted results
let existingEvents = filterEvents(evts, publisherId, startdate);
// if existingEvents is empty - create new with the selected range
if (existingEvents.length === 0) {

View File

@ -0,0 +1,40 @@
// pages/api/auth/apple-token.js
import jwt from 'jsonwebtoken';
import fs from 'fs';
import path from 'path';
const dotenv = require("dotenv");
export default async function handler(req, res) {
if (req.method === 'GET') {
try {
const appleKey = fs.readFileSync(path.resolve('./_deploy/appleKey.p8'), 'utf8');
const token = jwt.sign({}, appleKey, {
algorithm: 'ES256',
expiresIn: '180d',
issuer: process.env.APPLE_TEAM_ID,
header: {
alg: 'ES256',
kid: process.env.APPLE_KEY_ID,
},
audience: 'https://appleid.apple.com',
subject: process.env.APPLE_ID,
});
// Redirect to Apple's authentication page, or send the token to the client to do so
console.log(token);
res.status(200).send({
message: 'Generated token for Apple Sign In',
token: token
});
} catch (error) {
console.error('Error signing in with Apple:', error);
res.status(500).send({ error: 'Failed to sign in with Apple' });
}
} else {
// Handle any non-GET requests
res.setHeader('Allow', ['GET']);
res.status(405).end(`Method ${req.method} Not Allowed`);
}
}

View File

@ -161,8 +161,9 @@ export default async function handler(req, res) {
res.status(200).json(publishers);
break;
case "filterPublishersNew":
let includeOldAvailabilities = common.parseBool(req.query.includeOldAvailabilities);
let results = await filterPublishersNew_Available(req.query.select, day,
common.parseBool(req.query.isExactTime), common.parseBool(req.query.isForTheMonth));
common.parseBool(req.query.isExactTime), common.parseBool(req.query.isForTheMonth), includeOldAvailabilities);
res.status(200).json(results);
break;
@ -461,8 +462,8 @@ export async function getMonthlyStatistics(selectFields, filterDate) {
}
export async function filterPublishersNew_Available(selectFields, filterDate, isExactTime = false, isForTheMonth = false, isWithStats = true) {
return data.filterPublishersNew(selectFields, filterDate, isExactTime, isForTheMonth, isWithStats);
export async function filterPublishersNew_Available(selectFields, filterDate, isExactTime = false, isForTheMonth = false, isWithStats = true, includeOldAvailabilities = false) {
return data.filterPublishersNew(selectFields, filterDate, isExactTime, isForTheMonth, isWithStats, includeOldAvailabilities);
}
// availabilites filter:

View File

@ -76,15 +76,15 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
const [modalPub, setModalPub] = useState(null);
// ------------------ no assignments checkbox ------------------
const [isCheckboxChecked, setIsCheckboxChecked] = useState(false);
const [filterShowWithoutAssignments, setFilterShowWithoutAssignments] = useState(false);
const handleCheckboxChange = (event) => {
setIsCheckboxChecked(!isCheckboxChecked); // Toggle the checkbox state
setFilterShowWithoutAssignments(!filterShowWithoutAssignments); // Toggle the checkbox state
};
useEffect(() => {
console.log("checkbox checked: " + isCheckboxChecked);
console.log("checkbox checked: " + filterShowWithoutAssignments);
handleCalDateChange(value); // Call handleCalDateChange whenever isCheckboxChecked changes
}, [isCheckboxChecked]); // Dependency array
}, [filterShowWithoutAssignments]); // Dependency array
const [selectedMonth, setSelectedMonth] = useState(new Date().getMonth());
useEffect(() => {
@ -99,7 +99,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
var date = new Date(common.getDateFromDateTime(selectedDate));//ToDo: check if seting the timezone affects the selectedDate?!
var dateStr = common.getISODateOnly(date);
console.log("Setting date to '" + date.toLocaleDateString() + "' from '" + selectedDate.toLocaleDateString() + "'. ISO: " + date.toISOString(), "locale ISO:", common.getISODateOnly(date));
if (isCheckboxChecked) {
if (filterShowWithoutAssignments) {
console.log(`getting unassigned publishers for ${common.getMonthName(date.getMonth())} ${date.getFullYear()}`);
const { data: availablePubsForDate } = await axiosInstance.get(`/api/?action=getUnassignedPublishers&date=${dateStr}&select=id,firstName,lastName,isActive,desiredShiftsPerMonth`);
setAvailablePubs(availablePubsForDate);
@ -110,7 +110,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
const { data: shiftsForDate } = await axiosInstance.get(`/api/?action=getShiftsForDay&date=${dateStr}`);
setShifts(shiftsForDate);
setIsPublished(shiftsForDate.some(shift => shift.isPublished));
let { data: availablePubsForDate } = await axiosInstance.get(`/api/?action=filterPublishersNew&date=${dateStr}&select=id,firstName,lastName,isActive,desiredShiftsPerMonth`);
let { data: availablePubsForDate } = await axiosInstance.get(`/api/?action=filterPublishersNew&date=${dateStr}&select=id,firstName,lastName,isActive,desiredShiftsPerMonth&includeOldAvailabilities=${filterShowWithoutAssignments}`);
availablePubsForDate.forEach(pub => {
pub.canTransport = pub.availabilities.some(av =>
@ -664,9 +664,10 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
<h2 className="text-lg font-semibold mb-4">Достъпни за този ден: <span className="text-blue-600">{availablePubs.length}</span></h2>
<label className="toggle pb-3">
<input type="checkbox" className="toggle-checkbox" onChange={handleCheckboxChange} />
<input type="checkbox" className="toggle-checkbox" id="filterShowWithoutAssignments" onChange={handleCheckboxChange} />
<span className="toggle-slider m-1">без назначения за месеца</span>
<input type="checkbox" className="toggle-checkbox" id="filterIncludeOldAvailabilities" onChange={handleCheckboxChange} />
<span className="toggle-slider m-1">със стари предпочитания</span>
</label>
<ul className="w-full max-w-md">
{Array.isArray(availablePubs) && availablePubs?.map((pub, index) => {
@ -891,6 +892,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
import axiosServer from '../../../src/axiosServer';
import { start } from 'repl';
import { filter } from 'jszip';
export const getServerSideProps = async (context) => {
const axios = await axiosServer(context);
// const baseUrl = common.getBaseUrl();

View File

@ -6,18 +6,11 @@ const levenshtein = require('fastest-levenshtein');
const fs = typeof window === 'undefined' ? require('fs') : undefined;
const path = typeof window === 'undefined' ? require('path') : undefined;
const { PrismaClient } = require('@prisma/client');
const { PrismaClient, UserRole } = require('@prisma/client');
const DayOfWeek = require("@prisma/client").DayOfWeek;
const winston = require('winston');
// User and auth functions
// import { getSession } from "next-auth/react";
// import { UserRole } from "@prisma/client";
//convert to es6 import
const { getSession } = require("next-auth/react");
const { UserRole } = require("@prisma/client");
// const { set } = require('date-fns');
const logger = winston.createLogger({
level: 'info', // Set the default log level
@ -334,6 +327,18 @@ exports.compareTimes = function (time1, time2) {
const time2String = `${getHours(time2)}:${getMinutes(time2)}`;
return time1String.localeCompare(time2String);
};
exports.normalizeTime = function (date, baseDate) {
// return set(baseDate, {
// hours: getHours(date),
// minutes: getMinutes(date),
// seconds: getSeconds(date),
// milliseconds: 0
// });
//don't use date-fns
let newDate = new Date(baseDate);
newDate.setHours(date.getHours(), date.getMinutes(), date.getSeconds(), 0);
return newDate;
}
exports.getTimeRange = function (start, end) {
start = new Date(start);

View File

@ -228,7 +228,7 @@ async function getAvailabilities(userId) {
}
async function filterPublishersNew(selectFields, filterDate, isExactTime = false, isForTheMonth = false, isWithStats = true) {
async function filterPublishersNew(selectFields, filterDate, isExactTime = false, isForTheMonth = false, isWithStats = true, includeOldAvailabilities = false) {
filterDate = new Date(filterDate); // Convert to date object if not already