Skip to content

Commit 6502a92

Browse files
committed
introduced openplanner additional* fields to configure custom talks & breaks
1 parent 232b9d5 commit 6502a92

File tree

1 file changed

+69
-38
lines changed
  • cloud/functions/src/crawlers/openplanner

1 file changed

+69
-38
lines changed

cloud/functions/src/crawlers/openplanner/crawler.ts

Lines changed: 69 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
import {BreakTimeslotWithPotentiallyUnknownIcon, FullEvent} from "../../models/Event";
22
import {z} from "zod";
3-
import {EVENT_DESCRIPTOR_PARSER, EVENT_FEATURES_CONFIG_PARSER, RATINGS_CONFIG_PARSER} from "../crawler-parsers";
4-
import {CrawlerKind, TALK_TRACK_FALLBACK_COLORS} from "../crawl";
3+
import {
4+
BREAK_PARSER,
5+
BREAK_TIME_SLOT_PARSER,
6+
EVENT_DESCRIPTOR_PARSER,
7+
EVENT_FEATURES_CONFIG_PARSER,
8+
RATINGS_CONFIG_PARSER, ROOM_PARSER,
9+
SPEAKER_PARSER,
10+
TALK_PARSER,
11+
TALKS_TIME_SLOT_PARSER, THEMABLE_LANGUAGE_PARSER,
12+
THEMABLE_TALK_FORMAT_PARSER,
13+
THEMABLE_TALK_TRACK_PARSER
14+
} from "../crawler-parsers";
15+
import {CrawlerKind, TALK_FORMAT_FALLBACK_COLORS, TALK_TRACK_FALLBACK_COLORS} from "../crawl";
516
import {ISO_DATETIME_PARSER} from "../../utils/zod-parsers";
617
import {
718
DailySchedule,
@@ -11,14 +22,43 @@ import {
1122
Speaker,
1223
Talk,
1324
TalkFormat,
14-
TalksTimeSlot,
25+
TalksTimeSlot, ThemedTalkFormat,
1526
ThemedTrack,
1627
} from "../../../../../shared/daily-schedule.firestore";
1728
import {match, P} from "ts-pattern";
1829
import {Temporal} from "@js-temporal/polyfill";
1930
import {ISODatetime} from "../../../../../shared/type-utils";
2031
import {fillUnknownBreakIcons} from "../utils";
2132

33+
const OPENPLANNER_SESSION_PARSER = z.object({
34+
speakers: z.array(z.string()),
35+
tags: z.array(z.string()),
36+
title: z.string(),
37+
id: z.string(),
38+
categoryName: z.string().nullish(),
39+
categoryId: z.string().nullish(), // talkTrack
40+
formatId: z.string().nullish(), // talkFormat
41+
abstract: z.string().nullish(),
42+
trackId: z.string(), // room
43+
trackTitle: z.string(),
44+
startTime: ISO_DATETIME_PARSER.optional(),
45+
endTime: ISO_DATETIME_PARSER.optional(),
46+
type: z.literal('undefined').optional().default('undefined'),
47+
});
48+
49+
const OPENPLANNER_SPEAKER_PARSER = z.object({
50+
id: z.string(),
51+
name: z.string(),
52+
photoUrl: z.string().optional(),
53+
socials: z.array(z.object({
54+
icon: z.union([z.literal(""), z.literal("site"), z.literal("twitter"), z.literal("linkedin"), z.literal("github")]),
55+
link: z.string(),
56+
name: z.string().optional(),
57+
})),
58+
bio: z.string().nullish(),
59+
company: z.string().nullish()
60+
})
61+
2262
export const OPENPLANNER_DESCRIPTOR_PARSER = EVENT_DESCRIPTOR_PARSER.omit({
2363
id: true,
2464
days: true,
@@ -37,6 +77,16 @@ export const OPENPLANNER_DESCRIPTOR_PARSER = EVENT_DESCRIPTOR_PARSER.omit({
3777
openPlannerGeneratedJson: z.string(),
3878
language: z.string(),
3979
ratings: RATINGS_CONFIG_PARSER,
80+
additionalBreakTimeslots: z.array(BREAK_TIME_SLOT_PARSER.omit({ type: true, id: true })).optional().default([]),
81+
additionalSessions: z.record(z.string(), OPENPLANNER_SESSION_PARSER
82+
.omit({ type: true })
83+
.extend({
84+
type: z.literal('talk').optional().default('talk')
85+
})).optional().default({}),
86+
additionalSpeakers: z.record(z.string(), OPENPLANNER_SPEAKER_PARSER).optional().default({}),
87+
additionalTalkFormats: z.array(THEMABLE_TALK_FORMAT_PARSER).optional().default([]),
88+
additionalTalkTracks: z.array(THEMABLE_TALK_TRACK_PARSER).optional().default([]),
89+
additionalRooms: z.array(ROOM_PARSER).optional().default([]),
4090
})
4191

4292
export const OPENPLANNER_GENERATED_SCHEDULE_PARSER = EVENT_DESCRIPTOR_PARSER.omit({
@@ -50,32 +100,8 @@ export const OPENPLANNER_GENERATED_SCHEDULE_PARSER = EVENT_DESCRIPTOR_PARSER.omi
50100
}).extend({
51101
features: EVENT_FEATURES_CONFIG_PARSER.omit({ ratings: true }).extend({
52102
}),
53-
sessions: z.record(z.string(), z.object({
54-
speakers: z.array(z.string()),
55-
tags: z.array(z.string()),
56-
title: z.string(),
57-
id: z.string(),
58-
categoryName: z.string().nullish(),
59-
categoryId: z.string().nullish(), // talkTrack
60-
formatId: z.string().nullish(), // talkFormat
61-
abstract: z.string().nullish(),
62-
trackId: z.string(), // room
63-
trackTitle: z.string(),
64-
startTime: ISO_DATETIME_PARSER.optional(),
65-
endTime: ISO_DATETIME_PARSER.optional(),
66-
})),
67-
speakers: z.record(z.string(), z.object({
68-
id: z.string(),
69-
name: z.string(),
70-
photoUrl: z.string().optional(),
71-
socials: z.array(z.object({
72-
icon: z.union([z.literal(""), z.literal("site"), z.literal("twitter"), z.literal("linkedin"), z.literal("github")]),
73-
link: z.string(),
74-
name: z.string().optional(),
75-
})),
76-
bio: z.string().nullish(),
77-
company: z.string().nullish()
78-
}))
103+
sessions: z.record(z.string(), OPENPLANNER_SESSION_PARSER),
104+
speakers: z.record(z.string(), OPENPLANNER_SPEAKER_PARSER),
79105
})
80106

81107
export const OPENPLANNER_CRAWLER: CrawlerKind<typeof OPENPLANNER_DESCRIPTOR_PARSER> = {
@@ -88,12 +114,12 @@ export const OPENPLANNER_CRAWLER: CrawlerKind<typeof OPENPLANNER_DESCRIPTOR_PARS
88114
.then(data => OPENPLANNER_GENERATED_SCHEDULE_PARSER.parse(data));
89115

90116
const talks: DetailedTalk[] = [],
91-
tracks: ThemedTrack[] = openPlannerSchedule.talkTracks,
92-
formats: TalkFormat[] = openPlannerSchedule.talkFormats,
93-
rooms: Room[] = openPlannerSchedule.rooms,
117+
tracks: ThemedTrack[] = openPlannerSchedule.talkTracks.concat(descriptor.additionalTalkTracks),
118+
formats: TalkFormat[] = openPlannerSchedule.talkFormats.concat(descriptor.additionalTalkFormats),
119+
rooms: Room[] = openPlannerSchedule.rooms.concat(descriptor.additionalRooms),
94120
timezone = openPlannerSchedule.timezone;
95121

96-
const speakers = Object.values(openPlannerSchedule.speakers).map(openPlannerSpeaker => {
122+
const speakers = Object.values({ ...openPlannerSchedule.speakers, ...descriptor.additionalSpeakers }).map(openPlannerSpeaker => {
97123
const speaker: Speaker = {
98124
id: openPlannerSpeaker.id,
99125
fullName: openPlannerSpeaker.name,
@@ -117,7 +143,7 @@ export const OPENPLANNER_CRAWLER: CrawlerKind<typeof OPENPLANNER_DESCRIPTOR_PARS
117143
return speaker;
118144
})
119145

120-
let trackFallbackColors = 0
146+
let trackFallbackColors = 0, formatFallbackColors = 0;
121147
const UNKNOWN_TRACK_ID = 'unknown'
122148
// Auto-appending an 'unknown' track as openplanner's category might be nullable (ex: on sunnytech, for keynotes)
123149
// => in that case, we'll use this special 'unknown' track name
@@ -128,7 +154,7 @@ export const OPENPLANNER_CRAWLER: CrawlerKind<typeof OPENPLANNER_DESCRIPTOR_PARS
128154
})
129155

130156
const dailySchedules = openPlannerSchedule.days.map((day, dayIndex) => {
131-
const dailyRawSessions = Object.values(openPlannerSchedule.sessions)
157+
const dailyRawSessions = Object.values({ ...openPlannerSchedule.sessions, ...descriptor.additionalSessions })
132158
.filter(session => session.startTime && session.endTime && session.startTime.startsWith(day.localDate))
133159

134160
const { talkTimeslots, breakTimeslots: breakTimeslotsWithPotentiallyUnknownIcons } = dailyRawSessions.reduce(({talkTimeslots, breakTimeslots}, session) => {
@@ -140,7 +166,7 @@ export const OPENPLANNER_CRAWLER: CrawlerKind<typeof OPENPLANNER_DESCRIPTOR_PARS
140166

141167
const timeslotId = `${start}--${end}` as const
142168

143-
const room = match(rooms.find(r => r.id === session.trackId))
169+
const room = match(rooms.find(r => r.id === session.trackId)) // track is room in openplanner
144170
.with(P.nullish, () => {
145171
const newRoom: Room = {
146172
id: session.trackId,
@@ -151,7 +177,7 @@ export const OPENPLANNER_CRAWLER: CrawlerKind<typeof OPENPLANNER_DESCRIPTOR_PARS
151177
return newRoom;
152178
}).otherwise(room => room)
153179

154-
if(!session.formatId) {
180+
if(!session.formatId && session.type !== 'talk') {
155181
const breakSlot: BreakTimeslotWithPotentiallyUnknownIcon = {
156182
type: 'break',
157183
start, end,
@@ -242,7 +268,12 @@ export const OPENPLANNER_CRAWLER: CrawlerKind<typeof OPENPLANNER_DESCRIPTOR_PARS
242268

243269
const breakTimeslots = fillUnknownBreakIcons(
244270
{ isFirst: dayIndex === 0, isLast: dayIndex === openPlannerSchedule.days.length-1 },
245-
timezone, breakTimeslotsWithPotentiallyUnknownIcons, talkTimeslots);
271+
timezone, breakTimeslotsWithPotentiallyUnknownIcons, talkTimeslots)
272+
.concat((descriptor.additionalBreakTimeslots || []).map(partialTimeslot => ({
273+
...partialTimeslot,
274+
id: `${partialTimeslot.start as ISODatetime}--${partialTimeslot.end as ISODatetime}`,
275+
type: 'break'
276+
})))
246277

247278
const dailySchedule: DailySchedule = {
248279
day: day.id,

0 commit comments

Comments
 (0)