Skip to content

Commit

Permalink
Pick out useful commits from last year's hotfixes (#219)
Browse files Browse the repository at this point in the history
* Comment out unused hack for 2 years

* Don't require all people to be resolved to do invites: carry on anyway

* Transform auditorium IDs to the expected stream name format

Supersedes:

- 8a2246a
- be110ff

* Don't miss physical talks in the scheduler

* Prevent log spam by ignored events in physical talk rooms

* Don't send 'ending in 1 min' announcements to physical talks, they're more spammy than useful
  • Loading branch information
reivilibre authored Feb 1, 2024
1 parent cd74dbf commit d1e8b57
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 16 deletions.
4 changes: 2 additions & 2 deletions src/Conference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -855,8 +855,8 @@ export class Conference {
const until = Date.now() + inNextMinutes * 60000;

const upcomingTalks: ITalk[] = [];
for (const t of Object.values(this.talks)) {
const talk = await t.getDefinition();
// Use this.backend.talks because we care about physical talks here too.
for (const talk of this.backend.talks.values()) {
const talkEventTime = lambda(talk);
// If null is returned then the talk does not have this event, so don't return it as upcoming.
if (talkEventTime === null) continue;
Expand Down
17 changes: 12 additions & 5 deletions src/Scheduler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,8 @@ export class Scheduler {
} else {
await this.client.sendHtmlText(confAud.roomId, `<h3>The talk will end shortly</h3>`);
}
} else if (task.type === ScheduledTaskType.TalkStart1H && confTalk !== undefined) {
} else if (task.type === ScheduledTaskType.TalkStart1H) {
if (confTalk === undefined) return;
// This stage is skipped entirely for physical auditoriums' talks, because it only serves to nag
// TODO Do we need to ensure that coordinators have checked in?

Expand Down Expand Up @@ -445,11 +446,15 @@ export class Scheduler {
await this.client.sendHtmlText(confTalk.roomId, `<h3>Your talk ends in about 5 minutes</h3><p>The next talk will start automatically after yours.</p>`);
}
await this.client.sendHtmlText(confAud.roomId, `<h3>This talk ends in about 5 minutes</h3>` + (task.talk.qa_startTime !== null ? `<p>Ask questions here for the speakers!</p>`: ''));
} else if (task.type === ScheduledTaskType.TalkLivestreamEnd1M && confTalk !== undefined) {
} else if (task.type === ScheduledTaskType.TalkLivestreamEnd1M) {
if (confTalk === undefined) return;
await this.client.sendHtmlText(confTalk.roomId, `<h3>Your talk ends in about 1 minute!</h3><p>The next talk will start automatically after yours. Wrap it up!</p>`);
} else if (task.type === ScheduledTaskType.TalkEnd1M) {
// It's a bit spammy for a physical talk.
if (confTalk === undefined) return;
await this.client.sendHtmlText(confAud.roomId, `<h3>This talk ends in about 1 minute!</h3>`);
} else if (task.type === ScheduledTaskType.TalkCheckin45M && confTalk !== undefined) {
} else if (task.type === ScheduledTaskType.TalkCheckin45M) {
if (confTalk === undefined) return;
// TODO This is skipped entirely for physical talks, but do we want to ensure coordinators are checked-in?

if (!task.talk.prerecorded) return;
Expand Down Expand Up @@ -486,7 +491,8 @@ export class Scheduler {
const resolved = (await resolveIdentifiers(this.client, userIds)).filter(p => p.mxid).map(p => p.mxid!);
await this.checkins.expectCheckinFrom(resolved);
}
} else if (task.type === ScheduledTaskType.TalkCheckin30M && confTalk !== undefined) {
} else if (task.type === ScheduledTaskType.TalkCheckin30M) {
if (confTalk === undefined) return;
// TODO This is skipped entirely for physical talks, but do we want to ensure coordinators are checked-in?

if (!task.talk.prerecorded) return;
Expand Down Expand Up @@ -523,7 +529,8 @@ export class Scheduler {
const resolved = (await resolveIdentifiers(this.client, userIds)).filter(p => p.mxid).map(p => p.mxid!);
await this.checkins.expectCheckinFrom(resolved);
} // else no complaints
} else if (task.type === ScheduledTaskType.TalkCheckin15M && confTalk !== undefined) {
} else if (task.type === ScheduledTaskType.TalkCheckin15M) {
if (confTalk === undefined) return;
// TODO This is skipped entirely for physical talks, but do we want to ensure coordinators are checked-in?

if (!task.talk.prerecorded) return;
Expand Down
7 changes: 4 additions & 3 deletions src/commands/InviteCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,13 @@ export class InviteCommand implements ICommand {
} else if (args[0] && args[0] === "coordinators-support") {
let people: IPerson[] = [];
for (const aud of this.conference.storedAuditoriums) {
if (!(await aud.getId()).startsWith("D.")) {
// This hack was not wanted in 2023 or 2024.
// if (!(await aud.getId()).startsWith("D.")) {
// HACK: Only invite coordinators for D.* auditoriums.
// TODO: Make invitations for support rooms more configurable.
// https://github.com/matrix-org/this.conference-bot/issues/76
continue;
}
// continue;
// }

const inviteTargets = await this.conference.getInviteTargetsForAuditorium(aud, true);
people.push(...inviteTargets.filter(i => i.role === Role.Coordinator));
Expand Down
15 changes: 10 additions & 5 deletions src/commands/actions/people.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import { LogService, MatrixClient } from "matrix-bot-sdk";
import { LogLevel, LogService, MatrixClient } from "matrix-bot-sdk";
import { ResolvedPersonIdentifier, resolveIdentifiers } from "../../invites";
import { Auditorium } from "../../models/Auditorium";
import { Conference } from "../../Conference";
import { asyncFilter } from "../../utils";
import { InterestRoom } from "../../models/InterestRoom";
import { ConferenceMatrixClient } from "../../ConferenceMatrixClient";
import { logMessage } from "../../LogProxy";

export interface IAction {
(client: MatrixClient, roomId: string, people: ResolvedPersonIdentifier[]): Promise<void>;
Expand Down Expand Up @@ -60,9 +61,12 @@ export async function doAuditoriumResolveAction(
? await conference.getInviteTargetsForAuditorium(realAud)
: await conference.getModeratorsForAuditorium(realAud);
const resolvedAudPeople = audPeople.map(p => allPossiblePeople.find(b => p.id === b.person.id));
if (resolvedAudPeople.some(p => !p)) throw new Error(`Failed to resolve all targets for auditorium ${audId}`);
if (resolvedAudPeople.some(p => !p)) {
logMessage(LogLevel.WARN, "people", `Failed to resolve all targets for auditorium ${audId}. Inviting others anyway.`, client);
}

await action(client, realAud.roomId, resolvedAudPeople as ResolvedPersonIdentifier[]);
const resolvedAudPeopleOnly = resolvedAudPeople.filter(p => !!p);
await action(client, realAud.roomId, resolvedAudPeopleOnly as ResolvedPersonIdentifier[]);

if (!skipTalks) {
const talks = await asyncFilter(
Expand All @@ -80,10 +84,11 @@ export async function doAuditoriumResolveAction(
const unresolveable = talkPeople.filter(
p => allPossiblePeople.find(b => p.id === b.person.id) === undefined
)
throw new Error(`Failed to resolve all targets for talk ${await talk.getId()}: ` + JSON.stringify(unresolveable));
logMessage(LogLevel.WARN, "people", `Failed to resolve all targets for talk ${await talk.getId()}: ` + JSON.stringify(unresolveable), client);
}

await action(client, talk.roomId, resolvedTalkPeople as ResolvedPersonIdentifier[]);
const resolvedTalkPeopleOnly = resolvedTalkPeople.filter(p => !!p);
await action(client, talk.roomId, resolvedTalkPeopleOnly as ResolvedPersonIdentifier[]);
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion src/web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,16 @@ export function renderAuditoriumWidget(req: Request, res: Response, conference:
return res.sendStatus(404);
}

//let sid = audId.toLowerCase().replace(/[^a-z0-9]/g, '');

// HACK for FOSDEM 2023 and FOSDEM 2024: transform auditorium IDs to the livestream ID
// 1. 'K1.105A (Words)' -> 'k1.105a'
// 2. 'k1.105a' -> 'k1105a'
let sid = audId.toLowerCase().replace(/\s+\(.+\)$/, '').replace(/[^a-z0-9]/g, '');

const streamUrl = template(auditoriumUrl, {
id: audId.toLowerCase(),
sId: audId.toLowerCase().replace(/[^a-z0-9]/g, ''),
sId: sid
});

return res.render('auditorium.liquid', {
Expand Down

0 comments on commit d1e8b57

Please sign in to comment.