@openeventkit/event-site 2.1.18 → 2.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/jest.yml +1 -1
- package/babel.config.json +9 -9
- package/gatsby-node.js +67 -125
- package/jest.setup.js +2 -0
- package/netlify.toml +1 -1
- package/package.json +25 -16
- package/src/__mocks__/@mdx-js/mdx.js +32 -0
- package/src/__mocks__/@mdx-js/react.js +15 -0
- package/src/__mocks__/rehype-external-links.js +3 -0
- package/src/__mocks__/remark-gfm.js +3 -0
- package/src/actions/fetch-entities-actions.js +45 -87
- package/src/actions/update-data-actions.js +2 -2
- package/src/actions/user-actions.js +578 -430
- package/src/cms/config/collections/configurationsCollection/siteSettings/index.js +2 -0
- package/src/cms/config/collections/configurationsCollection/siteSettings/typeDefs.js +10 -0
- package/src/cms/preview-templates/ContentPagePreview.js +27 -29
- package/src/components/AvatarEditorModal/index.js +10 -0
- package/src/components/CertificatePDF.js +313 -0
- package/src/components/CertificateSection.js +139 -0
- package/src/components/FullSchedule.js +83 -66
- package/src/components/Mdx.js +39 -0
- package/src/components/__tests__/Mdx.test.jsx +70 -0
- package/src/content/site-settings/index.json +1 -1
- package/src/content/sponsors.json +1 -1
- package/src/i18n/locales/en.json +9 -1
- package/src/pages/a/[...].js +3 -0
- package/src/reducers/user-reducer.js +89 -27
- package/src/routes/authorization-callback-route.js +20 -2
- package/src/styles/rsvp-page.module.scss +63 -0
- package/src/templates/full-profile-page.js +61 -2
- package/src/templates/marketing-page-template/MainColumn.js +40 -42
- package/src/templates/rsvp-page.js +144 -0
- package/src/utils/alerts.js +1 -1
- package/src/utils/build-json/BaseAPIRequest.js +25 -0
- package/src/utils/build-json/EventsAPIRequest.js +171 -0
- package/src/utils/build-json/SpeakersAPIRequest.js +62 -0
- package/src/utils/build-json/SummitAPIRequest.js +115 -0
- package/src/utils/build-json/constants.js +5 -0
- package/src/utils/certificateSettings.js +45 -0
- package/src/utils/customErrorHandler.js +40 -1
- package/src/utils/rsvpConstants.js +7 -0
- package/src/utils/useMarketingSettings.js +48 -1
- package/src/utils/useSiteSettings.js +11 -0
- package/src/workers/feeds.worker.js +85 -90
- package/src/workers/sync_strategies/activity_synch_strategy.js +147 -102
- package/src/workers/sync_strategies/speaker_synch_strategy.js +3 -3
- package/src/workers/sync_strategies/track_synch_strategy.js +149 -48
- package/src/workers/synch.worker.js +123 -88
- package/static/fonts/fonts.css +120 -20
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-200.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-200italic.ttf +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-200italic.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-300.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-300italic.ttf +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-300italic.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-400.ttf +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-400.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-400italic.ttf +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-400italic.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-500.ttf +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-500.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-500italic.ttf +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-500italic.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-600.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-600italic.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-700.ttf +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-700.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-700italic.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-800.ttf +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-800.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-800italic.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-900.ttf +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-900.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v18-latin-900italic.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v12-latin-300.woff +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v12-latin-300.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v12-latin-300italic.woff +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v12-latin-300italic.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v12-latin-600.woff +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v12-latin-600.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v12-latin-600italic.woff +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v12-latin-600italic.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v12-latin-700.woff +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v12-latin-700.woff2 +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v12-latin-700italic.woff +0 -0
- package/static/fonts/nunito-sans/nunito-sans-v12-latin-700italic.woff2 +0 -0
|
@@ -4,7 +4,8 @@ import {insertSorted, intCheck, rebuildIndex} from "../../utils/arrayUtils";
|
|
|
4
4
|
import {
|
|
5
5
|
BUCKET_EVENTS_DATA_KEY,
|
|
6
6
|
BUCKET_EVENTS_IDX_DATA_KEY,
|
|
7
|
-
BUCKET_SPEAKERS_DATA_KEY,
|
|
7
|
+
BUCKET_SPEAKERS_DATA_KEY,
|
|
8
|
+
BUCKET_SPEAKERS_IDX_DATA_KEY,
|
|
8
9
|
BUCKET_SUMMIT_DATA_KEY,
|
|
9
10
|
saveFile
|
|
10
11
|
} from "../../utils/dataUpdatesUtils";
|
|
@@ -15,123 +16,167 @@ import moment from "moment-timezone";
|
|
|
15
16
|
*/
|
|
16
17
|
class ActivitySynchStrategy extends AbstractSynchStrategy{
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
_removeEventById(entity_id, eventsData){
|
|
20
|
+
// was deleted ( un - published)
|
|
21
|
+
// try to get from index
|
|
22
|
+
const idx = this.allIDXEvents[entity_id] ?? -1;
|
|
23
|
+
console.log(`ActivitySynchStrategy::_removeEventById unpublished presentation ${entity_id} idx ${idx}`);
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
// Remove from array and index
|
|
26
|
+
const pruned = eventsData.filter(e => e.id !== entity_id);
|
|
27
|
+
delete this.allIDXEvents[entity_id];
|
|
28
|
+
return pruned;
|
|
29
|
+
}
|
|
21
30
|
|
|
22
|
-
|
|
31
|
+
_touchSummitTimestamp() {
|
|
32
|
+
this.summit = {
|
|
33
|
+
...this.summit,
|
|
34
|
+
timestamp: moment().unix(),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
23
37
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
/** Standard result payload + log */
|
|
39
|
+
_result(payload, entity, eventsData) {
|
|
40
|
+
const res = {
|
|
41
|
+
payload,
|
|
42
|
+
entity: entity,
|
|
43
|
+
summit: this.summit,
|
|
44
|
+
eventsData,
|
|
45
|
+
allIDXEvents: this.allIDXEvents,
|
|
46
|
+
allSpeakers: this.allSpeakers,
|
|
47
|
+
allIDXSpeakers: this.allIDXSpeakers,
|
|
48
|
+
};
|
|
49
|
+
console.log("ActivitySynchStrategy::process done", res);
|
|
50
|
+
return res;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async _persistAll(eventsData) {
|
|
54
|
+
this._touchSummitTimestamp();
|
|
55
|
+
const localNowUtc = Date.now();
|
|
56
|
+
|
|
57
|
+
await Promise.all([
|
|
58
|
+
saveFile(this.summit.id, BUCKET_SUMMIT_DATA_KEY, this.summit, localNowUtc),
|
|
59
|
+
saveFile(this.summit.id, BUCKET_EVENTS_DATA_KEY, eventsData, localNowUtc),
|
|
60
|
+
saveFile(this.summit.id, BUCKET_EVENTS_IDX_DATA_KEY, this.allIDXEvents, localNowUtc),
|
|
61
|
+
saveFile(this.summit.id, BUCKET_SPEAKERS_DATA_KEY, this.allSpeakers, localNowUtc),
|
|
62
|
+
saveFile(this.summit.id, BUCKET_SPEAKERS_IDX_DATA_KEY, this.allIDXSpeakers, localNowUtc),
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async _handleDeleteOrUnpublish(entityId, payload, eventsData) {
|
|
67
|
+
console.log(
|
|
68
|
+
`ActivitySynchStrategy::_handleDeleteOrUnpublish delete/unpublish presentation ${entityId}`
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// Remove and rebuild index
|
|
72
|
+
const newEventsData = this._removeEventById(entityId, eventsData);
|
|
73
|
+
this.allIDXEvents = rebuildIndex(newEventsData);
|
|
74
|
+
|
|
75
|
+
// Persist
|
|
76
|
+
try {
|
|
77
|
+
console.log("ActivitySynchStrategy::_handleDeleteOrUnpublish updating cache files (delete)");
|
|
78
|
+
await this._persistAll(newEventsData);
|
|
79
|
+
} catch (e) {
|
|
80
|
+
console.error(e);
|
|
28
81
|
}
|
|
29
82
|
|
|
30
|
-
|
|
83
|
+
// No entity on delete/unpublish
|
|
84
|
+
return this._result(payload, null, newEventsData);
|
|
85
|
+
}
|
|
31
86
|
|
|
32
|
-
|
|
87
|
+
/** Insert/update a single person (speaker/moderator) into arrays + index */
|
|
88
|
+
_upsertSpeaker(person) {
|
|
89
|
+
if (!person) return;
|
|
90
|
+
const idx = this.allIDXSpeakers[person.id] ?? -1;
|
|
91
|
+
if (idx === -1 || !this.allSpeakers[idx]) {
|
|
92
|
+
this.allSpeakers.push(person);
|
|
93
|
+
this.allIDXSpeakers[person.id] = this.allSpeakers.length - 1;
|
|
94
|
+
} else {
|
|
95
|
+
this.allSpeakers[idx] = person;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
33
98
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
99
|
+
/** Apply speakers & moderator coming from an entity */
|
|
100
|
+
_applyPeopleFromEntity(entity) {
|
|
101
|
+
if (Array.isArray(entity?.speakers)) {
|
|
102
|
+
for (const s of entity.speakers) this._upsertSpeaker(s);
|
|
103
|
+
}
|
|
104
|
+
if (entity?.moderator) this._upsertSpeaker(entity.moderator);
|
|
105
|
+
}
|
|
39
106
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// Remove from array and index
|
|
43
|
-
eventsData = eventsData.filter(e => e.id !== entity_id);
|
|
44
|
-
delete this.allIDXEvents[entity_id];
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
// Entity is published or updated
|
|
48
|
-
|
|
49
|
-
// Remove any existing version of this event
|
|
50
|
-
eventsData = eventsData.filter(e => e.id !== entity.id);
|
|
51
|
-
|
|
52
|
-
// Re-insert the updated entity into sorted position
|
|
53
|
-
|
|
54
|
-
this.allIDXEvents[entity.id] = insertSorted(eventsData, entity, (a, b) => {
|
|
55
|
-
if (a.start_date === b.start_date) {
|
|
56
|
-
if (a.end_date === b.end_date) {
|
|
57
|
-
return intCheck(a.id, b.id);
|
|
58
|
-
}
|
|
59
|
-
return intCheck(a.end_date, b.end_date);
|
|
60
|
-
}
|
|
61
|
-
return intCheck(a.start_date, b.start_date);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
// Rebuild the full event index to be safe
|
|
65
|
-
|
|
66
|
-
this.allIDXEvents = rebuildIndex(eventsData);
|
|
67
|
-
|
|
68
|
-
// Update speakers
|
|
69
|
-
if (entity.speakers) {
|
|
70
|
-
console.log(`ActivitySynchStrategy::process updating speakers`, entity.speakers);
|
|
71
|
-
for (const speaker of entity.speakers) {
|
|
72
|
-
const idx = this.allIDXSpeakers[speaker.id] ?? -1;
|
|
73
|
-
if (idx === -1 || !this.allSpeakers[idx]) {
|
|
74
|
-
console.log(`ActivitySynchStrategy::process speaker does not exists, inserting it at end`, speaker);
|
|
75
|
-
this.allSpeakers.push(speaker);
|
|
76
|
-
this.allIDXSpeakers[speaker.id] = this.allSpeakers.length - 1;
|
|
77
|
-
} else {
|
|
78
|
-
console.log(`ActivitySynchStrategy::process updating speaker at idx ${idx}`, speaker);
|
|
79
|
-
this.allSpeakers[idx] = speaker;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
107
|
+
async _handleUpsert(entity, payload, eventsData) {
|
|
108
|
+
console.log("ActivitySynchStrategy::process upsert", { id: entity?.id });
|
|
83
109
|
|
|
84
|
-
|
|
85
|
-
if (entity.moderator) {
|
|
86
|
-
console.log(`ActivitySynchStrategy::process updating moderator`, entity.moderator);
|
|
87
|
-
const idx = this.allIDXSpeakers[entity.moderator.id] ?? -1;
|
|
88
|
-
if (idx === -1 || !this.allSpeakers[idx]) {
|
|
89
|
-
console.log(`ActivitySynchStrategy::process moderator does not exists, inserting it at end`, entity.moderator);
|
|
90
|
-
this.allSpeakers.push(entity.moderator);
|
|
91
|
-
this.allIDXSpeakers[entity.moderator.id] = this.allSpeakers.length - 1;
|
|
92
|
-
} else {
|
|
93
|
-
console.log(`ActivitySynchStrategy::process updating moderator at idx ${idx}`, entity.moderator);
|
|
94
|
-
this.allSpeakers[idx] = entity.moderator;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
110
|
+
// Entity is published or updated
|
|
97
111
|
|
|
98
|
-
|
|
112
|
+
// Remove any existing version of this event
|
|
113
|
+
const without = eventsData.filter(e => e.id !== entity.id);
|
|
99
114
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
// Persist everything
|
|
109
|
-
try {
|
|
110
|
-
const localNowUtc = Date.now();
|
|
111
|
-
|
|
112
|
-
await saveFile(this.summit.id, BUCKET_SUMMIT_DATA_KEY, this.summit, localNowUtc);
|
|
113
|
-
await saveFile(this.summit.id, BUCKET_EVENTS_DATA_KEY, eventsData, localNowUtc);
|
|
114
|
-
await saveFile(this.summit.id, BUCKET_EVENTS_IDX_DATA_KEY, this.allIDXEvents, localNowUtc);
|
|
115
|
-
await saveFile(this.summit.id, BUCKET_SPEAKERS_DATA_KEY, this.allSpeakers, localNowUtc);
|
|
116
|
-
await saveFile(this.summit.id, BUCKET_SPEAKERS_IDX_DATA_KEY, this.allIDXSpeakers, localNowUtc);
|
|
117
|
-
} catch (e) {
|
|
118
|
-
console.error(e);
|
|
115
|
+
// Re-insert the updated entity into sorted position
|
|
116
|
+
|
|
117
|
+
this.allIDXEvents[entity.id] = insertSorted(without, entity, (a, b) => {
|
|
118
|
+
if (a.start_date === b.start_date) {
|
|
119
|
+
if (a.end_date === b.end_date) {
|
|
120
|
+
return intCheck(a.id, b.id);
|
|
121
|
+
}
|
|
122
|
+
return intCheck(a.end_date, b.end_date);
|
|
119
123
|
}
|
|
124
|
+
return intCheck(a.start_date, b.start_date);
|
|
125
|
+
});
|
|
120
126
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
entity,
|
|
124
|
-
summit: this.summit,
|
|
125
|
-
eventsData,
|
|
126
|
-
allIDXEvents: this.allIDXEvents,
|
|
127
|
-
allSpeakers: this.allSpeakers,
|
|
128
|
-
allIDXSpeakers: this.allIDXSpeakers,
|
|
129
|
-
};
|
|
127
|
+
// Rebuild full index for safety/consistency
|
|
128
|
+
this.allIDXEvents = rebuildIndex(without);
|
|
130
129
|
|
|
131
|
-
console.log(`ActivitySynchStrategy::process done`, res);
|
|
132
130
|
|
|
133
|
-
|
|
131
|
+
// Update speakers & moderator
|
|
132
|
+
this._applyPeopleFromEntity(entity);
|
|
133
|
+
|
|
134
|
+
// Persist
|
|
135
|
+
try {
|
|
136
|
+
console.log("ActivitySynchStrategy::process updating cache files (upsert)");
|
|
137
|
+
await this._persistAll(without);
|
|
138
|
+
} catch (e) {
|
|
139
|
+
console.error(e);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
return this._result(payload, entity, without);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async process(payload){
|
|
147
|
+
|
|
148
|
+
console.log(`ActivitySynchStrategy::process`, payload);
|
|
149
|
+
|
|
150
|
+
const {entity_operator, entity_id} = payload;
|
|
151
|
+
|
|
152
|
+
let eventsData = [...this.allEvents];
|
|
153
|
+
|
|
154
|
+
switch (entity_operator) {
|
|
155
|
+
case 'INSERT':
|
|
156
|
+
case 'UPDATE':{
|
|
157
|
+
let entity = await fetchEventById(this.summit.id, entity_id, this.accessToken);
|
|
158
|
+
if(this.accessToken) {
|
|
159
|
+
const streaming_info = await fetchStreamingInfoByEventId(this.summit.id, entity_id, this.accessToken);
|
|
160
|
+
if(streaming_info) entity = {...entity, ...streaming_info};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if(!entity){
|
|
164
|
+
// was deleted ( un - published)
|
|
165
|
+
return this._handleDeleteOrUnpublish(entity_id, payload, eventsData);
|
|
166
|
+
}
|
|
167
|
+
// Normal upsert flow
|
|
168
|
+
return this._handleUpsert(entity, payload, eventsData);
|
|
169
|
+
}
|
|
170
|
+
case 'DELETE':{
|
|
171
|
+
// was hard deleted
|
|
172
|
+
return this._handleDeleteOrUnpublish(entity_id, payload, eventsData);
|
|
173
|
+
}
|
|
134
174
|
}
|
|
175
|
+
|
|
176
|
+
// Unknown op
|
|
177
|
+
const msg = `ActivitySynchStrategy::process unknown entity_operator '${entity_operator}'`;
|
|
178
|
+
console.warn(msg);
|
|
179
|
+
throw new Error(msg);
|
|
135
180
|
}
|
|
136
181
|
}
|
|
137
182
|
|
|
@@ -36,7 +36,7 @@ class SpeakerSynchStrategy extends AbstractSynchStrategy {
|
|
|
36
36
|
this.allIDXSpeakers = rebuildIndex(this.allSpeakers);
|
|
37
37
|
|
|
38
38
|
// Update events where speaker is listed
|
|
39
|
-
for (const eventId of entity.
|
|
39
|
+
for (const eventId of entity.presentations || []) {
|
|
40
40
|
const res = getIndexedItem(this.allIDXEvents, eventsData, eventId);
|
|
41
41
|
if (!res || !Array.isArray(res.item.speakers)) {
|
|
42
42
|
console.log(`SpeakerSynchStrategy::process: event ${eventId} not found or invalid`);
|
|
@@ -54,7 +54,7 @@ class SpeakerSynchStrategy extends AbstractSynchStrategy {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
// Update events where speaker is moderator
|
|
57
|
-
for (const eventId of entity.
|
|
57
|
+
for (const eventId of entity.moderated_presentations || []) {
|
|
58
58
|
const res = getIndexedItem(this.allIDXEvents, eventsData, eventId);
|
|
59
59
|
if (!res) {
|
|
60
60
|
console.log(`SpeakerSynchStrategy::process: moderator event ${eventId} not found`);
|
|
@@ -111,4 +111,4 @@ class SpeakerSynchStrategy extends AbstractSynchStrategy {
|
|
|
111
111
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
export default SpeakerSynchStrategy;
|
|
114
|
+
export default SpeakerSynchStrategy;
|
|
@@ -1,76 +1,177 @@
|
|
|
1
1
|
import AbstractSynchStrategy from "./abstract_synch_strategy";
|
|
2
2
|
import {fetchTrackById} from "../../actions/fetch-entities-actions";
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
BUCKET_EVENTS_DATA_KEY,
|
|
5
|
+
BUCKET_EVENTS_IDX_DATA_KEY,
|
|
6
|
+
BUCKET_SUMMIT_DATA_KEY,
|
|
7
|
+
saveFile
|
|
7
8
|
} from "../../utils/dataUpdatesUtils";
|
|
8
9
|
import moment from "moment-timezone";
|
|
10
|
+
import {rebuildIndex} from "../../utils/arrayUtils";
|
|
11
|
+
|
|
9
12
|
/**
|
|
10
13
|
* TrackSynchStrategy
|
|
11
14
|
*/
|
|
12
|
-
class TrackSynchStrategy extends AbstractSynchStrategy{
|
|
15
|
+
class TrackSynchStrategy extends AbstractSynchStrategy {
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
_normalizeTracks(tracks) {
|
|
19
|
+
const base = Array.isArray(tracks) ? tracks : [];
|
|
20
|
+
return base.map(t => ({
|
|
21
|
+
...t,
|
|
22
|
+
subtracks: Array.isArray(t?.subtracks) ? t.subtracks : []
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
_touchSummitTimestamp() {
|
|
27
|
+
this.summit = {
|
|
28
|
+
...this.summit,
|
|
29
|
+
timestamp: moment().unix(),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
_stripEntityEverywhere(tracks, entityId) {
|
|
34
|
+
return this._normalizeTracks(tracks)
|
|
35
|
+
.filter(t => t.id !== entityId) // remove it from top level ...
|
|
36
|
+
// then remove it from subtracks
|
|
37
|
+
.map(t => ({ ...t, subtracks: t.subtracks.filter(st => st?.id !== entityId) }));
|
|
38
|
+
}
|
|
13
39
|
|
|
14
|
-
|
|
40
|
+
async _persistAll() {
|
|
41
|
+
this._touchSummitTimestamp();
|
|
42
|
+
const localNowUtc = Date.now();
|
|
43
|
+
|
|
44
|
+
await Promise.all([
|
|
45
|
+
saveFile(this.summit.id, BUCKET_EVENTS_DATA_KEY, this.allEvents, localNowUtc),
|
|
46
|
+
saveFile(this.summit.id, BUCKET_SUMMIT_DATA_KEY, this.summit, localNowUtc),
|
|
47
|
+
saveFile(this.summit.id, BUCKET_EVENTS_IDX_DATA_KEY, this.allIDXEvents, localNowUtc),
|
|
48
|
+
]);
|
|
49
|
+
}
|
|
15
50
|
|
|
16
|
-
|
|
51
|
+
_result(payload, entity) {
|
|
52
|
+
return {
|
|
53
|
+
payload,
|
|
54
|
+
entity: entity,
|
|
55
|
+
summit: this.summit,
|
|
56
|
+
eventsData: this.allEvents,
|
|
57
|
+
allIDXEvents: this.allIDXEvents,
|
|
58
|
+
allSpeakers: this.allSpeakers,
|
|
59
|
+
allIDXSpeakers: this.allIDXSpeakers
|
|
60
|
+
};
|
|
61
|
+
}
|
|
17
62
|
|
|
18
|
-
|
|
63
|
+
_upsertIntoParentSubtracks(tracks, parentId, entity) {
|
|
64
|
+
if (parentId === entity.id) {
|
|
65
|
+
console.warn(`TrackSynchStrategy::_upsertIntoParentSubtracks ignored self-parent for ${entity.id}`);
|
|
66
|
+
return tracks;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let found = false;
|
|
70
|
+
const normalizedEntity = { ...entity, subtracks: Array.isArray(entity.subtracks) ? entity.subtracks : [] };
|
|
71
|
+
const next = tracks.map(t => {
|
|
72
|
+
if (t.id !== parentId) return t;
|
|
73
|
+
// found the parent
|
|
74
|
+
found = true;
|
|
75
|
+
// get current idx if exists as subtrack ...
|
|
76
|
+
const idx = t.subtracks.findIndex(st => st?.id === entity.id);
|
|
77
|
+
const subtracks = idx === -1
|
|
78
|
+
? [...t.subtracks, { ...normalizedEntity }] // not found it as subtrack .. then add it
|
|
79
|
+
: t.subtracks.map(st => (st?.id === entity.id ? { ...st, ...normalizedEntity } : st));// else update it
|
|
80
|
+
return { ...t, subtracks };
|
|
81
|
+
});
|
|
82
|
+
if (!found) {
|
|
83
|
+
console.warn(`TrackSynchStrategy::_upsertIntoParentSubtracks parent ${parentId} not found for track ${entity.id}`);
|
|
84
|
+
}
|
|
85
|
+
return next;
|
|
86
|
+
}
|
|
19
87
|
|
|
20
|
-
|
|
88
|
+
async _handleUpsert(entity, payload) {
|
|
89
|
+
// remove it from top level and subtracks
|
|
90
|
+
let tracks = this._stripEntityEverywhere(this.summit?.tracks, entity.id);
|
|
91
|
+
// top level re insert
|
|
92
|
+
const normalizedEntity = { ...entity, subtracks: Array.isArray(entity.subtracks) ? entity.subtracks : [] };
|
|
93
|
+
tracks.push(normalizedEntity)
|
|
21
94
|
|
|
22
|
-
|
|
23
|
-
|
|
95
|
+
if (entity.parent_id > 0) {
|
|
96
|
+
// re insert or update it
|
|
97
|
+
tracks = this._upsertIntoParentSubtracks(tracks, entity.parent_id, entity);
|
|
98
|
+
}
|
|
24
99
|
|
|
25
|
-
|
|
100
|
+
// update summit racks
|
|
26
101
|
|
|
27
|
-
|
|
28
|
-
...this.summit,
|
|
29
|
-
timestamp : moment().unix(),
|
|
30
|
-
tracks : this.summit.tracks.map(t => {
|
|
31
|
-
if(t?.id === entity_id) return {...t, ...entity};
|
|
102
|
+
this.summit = { ...this.summit, tracks };
|
|
32
103
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
104
|
+
// update events
|
|
105
|
+
this.allEvents = this.allEvents.map(ev => {
|
|
106
|
+
if (ev?.track?.id === entity.id) return ({...ev, track: entity});
|
|
107
|
+
return ev;
|
|
37
108
|
})
|
|
38
|
-
};
|
|
39
|
-
// update events
|
|
40
|
-
this.allEvents = this.allEvents.map(ev => {
|
|
41
|
-
if (ev?.track?.id === entity_id) return ({...ev, track: entity});
|
|
42
|
-
return ev;
|
|
43
|
-
})
|
|
44
109
|
|
|
45
|
-
|
|
46
|
-
|
|
110
|
+
// Rebuild index to keep positions in sync
|
|
111
|
+
this.allIDXEvents = rebuildIndex(this.allEvents);
|
|
112
|
+
// Persist
|
|
113
|
+
try {
|
|
114
|
+
console.log("TrackSynchStrategy::process updating cache files (upsert)");
|
|
115
|
+
await this._persistAll();
|
|
116
|
+
} catch (e) {
|
|
117
|
+
console.error(e);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return this._result(payload, entity);
|
|
121
|
+
}
|
|
47
122
|
|
|
48
|
-
|
|
49
|
-
|
|
123
|
+
async _handleDelete(entityId, payload) {
|
|
124
|
+
console.log(
|
|
125
|
+
`TrackSynchStrategy::_handleDelete delete track ${entityId}`
|
|
126
|
+
);
|
|
127
|
+
// remove track from top level / childs
|
|
128
|
+
let tracks = this._stripEntityEverywhere(this.summit?.tracks, entityId);
|
|
129
|
+
// clean orphan childs ...
|
|
130
|
+
tracks = tracks.map(t => (t?.parent_id === entityId ? { ...t, parent_id: 0 } : t));
|
|
131
|
+
|
|
132
|
+
this.summit = {
|
|
133
|
+
...this.summit,
|
|
134
|
+
tracks: [...tracks],
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// update events remove events with that track
|
|
138
|
+
this.allEvents = this.allEvents.filter(ev => ev.track?.id !== entityId);
|
|
139
|
+
// Rebuild index to keep positions in sync
|
|
140
|
+
this.allIDXEvents = rebuildIndex(this.allEvents);
|
|
141
|
+
// Persist
|
|
142
|
+
try {
|
|
143
|
+
console.log("TrackSynchStrategy::_handleDelete updating cache files (delete)");
|
|
144
|
+
await this._persistAll();
|
|
145
|
+
} catch (e) {
|
|
146
|
+
console.error(e);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// No entity on delete/unpublish
|
|
150
|
+
return this._result(payload, null);
|
|
151
|
+
}
|
|
50
152
|
|
|
51
|
-
|
|
52
|
-
await saveFile(this.summit.id, BUCKET_SUMMIT_DATA_KEY, this.summit, localNowUtc);
|
|
153
|
+
async process(payload) {
|
|
53
154
|
|
|
54
|
-
|
|
55
|
-
catch (e){
|
|
56
|
-
console.log(e);
|
|
57
|
-
}
|
|
155
|
+
console.log(`TrackSynchStrategy::process`, payload);
|
|
58
156
|
|
|
59
|
-
|
|
60
|
-
payload,
|
|
61
|
-
entity,
|
|
62
|
-
summit : this.summit,
|
|
63
|
-
eventsData: this.allEvents,
|
|
64
|
-
allIDXEvents : this.allIDXEvents,
|
|
65
|
-
allSpeakers : this.allSpeakers,
|
|
66
|
-
allIDXSpeakers : this.allIDXSpeakers
|
|
67
|
-
};
|
|
157
|
+
const {entity_operator, entity_id} = payload;
|
|
68
158
|
|
|
69
|
-
|
|
159
|
+
switch (entity_operator) {
|
|
160
|
+
case 'INSERT':
|
|
161
|
+
case 'UPDATE':{
|
|
162
|
+
const entity = await fetchTrackById(this.summit.id, entity_id, this.accessToken);
|
|
163
|
+
if (!entity) return Promise.reject('TrackSynchStrategy::process entity not found.');
|
|
164
|
+
return this._handleUpsert(entity, payload);
|
|
165
|
+
}
|
|
166
|
+
case 'DELETE':{
|
|
167
|
+
return this._handleDelete(entity_id, payload);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
70
170
|
|
|
71
|
-
|
|
171
|
+
const msg = `TrackSynchStrategy::process unknown entity_operator '${entity_operator}'`;
|
|
172
|
+
console.warn(msg);
|
|
173
|
+
throw new Error(msg);
|
|
72
174
|
}
|
|
73
|
-
}
|
|
74
175
|
}
|
|
75
176
|
|
|
76
177
|
export default TrackSynchStrategy;
|