Skip to content

Commit

Permalink
feat: ✨ load events from arma.events
Browse files Browse the repository at this point in the history
Co-authored-by: NeutraleNull <[email protected]>
  • Loading branch information
DerZade and NeutraleNull committed Jan 20, 2025
1 parent a3ed07d commit 041b7df
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 57 deletions.
144 changes: 89 additions & 55 deletions api/src/utils/EventsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,67 @@ export interface ArmaEvent {
attendance: [number, number]
}

const QUERY = `
query GetCommunityEventsWithDetails($communityId: UUID!) {
events(
where: { community: { id: { eq: $communityId } } }
order: [
{ date: DESC } # Sort by date in descending order
]
) {
nodes {
id
title
slug
community {
slug
}
date
attendingUsers: eventUsers(where: { status: { eq: attending } }) {
totalCount
}
potentiallyAttendingUsers: eventUsers(
where: { status: { eq: potentiallyAttending } }
) {
totalCount
}
}
}
}
`;

interface GetCommunityEventsWithDetailsQuery {
__typename?: 'Query'
events?: {
__typename?: 'EventsConnection'
nodes?: Array<{
__typename?: 'Event'
id: string
title: string
slug: string
date?: string | null
community: {
slug: string
}
attendingUsers?: {
__typename?: 'EventUsersConnection'
totalCount: number
} | null
potentiallyAttendingUsers?: {
__typename?: 'EventUsersConnection'
totalCount: number
} | null
}> | null
} | null
};

interface GetCommunityEventsWithDetailsQueryVariables {
communityId: string
};

export class ArmaEventsService {
private static readonly ATTENDANCE_PLUGIN_INTRODUCTION = 1483833600000;
private static readonly FORUM_URI = 'https://forum.gruppe-adler.de';
private static readonly TOPIC_TITLE_REGEX = /^\d{4}-\d{2}-\d{2}\s*,(\s*\w+\s*,)?\s*/i;
private static readonly ARMA_EVENTS_API_URL = 'https://api.arma.events/graphql/';
private static readonly ARMA_EVENTS_GRUPPE_ADLER_ID = 'f52e5ce0-928d-45a9-9381-6f93015950ee';

private static instance: ArmaEventsService | null = null;

Expand Down Expand Up @@ -49,43 +106,47 @@ export class ArmaEventsService {
}

private async fetchEvents (): Promise<ArmaEvent[]> {
const response = await fetch(`${ArmaEventsService.FORUM_URI}/api/events/cid-3`);
const variables: GetCommunityEventsWithDetailsQueryVariables = { communityId: ArmaEventsService.ARMA_EVENTS_GRUPPE_ADLER_ID };
const response = await fetch(ArmaEventsService.ARMA_EVENTS_API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ query: QUERY, variables })
});

if (!response.ok) {
throw new Error(`Error while trying to fetch events. Forum API responded with status code ${response.status}.`);
throw new Error(`Error fetching data from arma.events! Status: ${response.status}`);
}
const { topics } = await response.json() as { topics: Array<{ slug: string, titleRaw: string, tid: number, deleted: 1 | 0, timestamp: number }> };

const rawEvents: Array<Omit<ArmaEvent, 'attendance'> & { tid: number }> = [];
for (const topic of topics) {
if (topic.timestamp < ArmaEventsService.ATTENDANCE_PLUGIN_INTRODUCTION) continue;
if (topic.deleted === 1) {
console.warn(`Skipping topic ${topic.titleRaw} (ID: ${topic.tid}), because it was deleted`);
continue;
}
if (!ArmaEventsService.TOPIC_TITLE_REGEX.test(topic.titleRaw)) {
console.warn(`Skipping topic ${topic.titleRaw} (ID: ${topic.tid}), because its title did not match the required pattern.`);
continue;
}

rawEvents.push({
date: new Date(topic.titleRaw.substr(0, 10)),
title: topic.titleRaw.replace(ArmaEventsService.TOPIC_TITLE_REGEX, ''),
url: `${ArmaEventsService.FORUM_URI}/topic/${topic.slug}`,
tid: topic.tid
});
const result = await response.json() as {
data: GetCommunityEventsWithDetailsQuery
errors?: any
};

if (result.errors) {
console.error(result.errors);
throw new Error(`arma.events GraphQL error occurred! Error: ${JSON.stringify(result.errors)}`);
}

// events sorted with event furthest back in past as first item
// Transform the data to fit ArmaEvent interface
const rawEvents = result.data.events?.nodes?.map((event): ArmaEvent => {
return {
date: new Date(event.date ?? 0),
title: event.title,
url: `https://arma.events/e/${event.community.slug}/${event.slug}`, // Construct URL using slug
attendance: [event.attendingUsers?.totalCount ?? 0, event.potentiallyAttendingUsers?.totalCount ?? 0]
};
}) ?? [];

const sortedEvents = rawEvents.sort((a, b) => a.date.getTime() - b.date.getTime());

// we only want one future event and a max of 10 events;
// if there is no future event we just want the 10 most recent events
const firstFutureEvent = sortedEvents.findIndex(e => ArmaEventsService.isInFuture(e.date)) + 1;
const filteredEvents = sortedEvents.slice(0, firstFutureEvent > 0 ? firstFutureEvent : sortedEvents.length).reverse().slice(0, 10);

const promises = filteredEvents.map(async ({ tid, ...rest }) => await ArmaEventsService.fetchAttendance(tid).then((attendance): ArmaEvent => ({ ...rest, attendance })));

return await Promise.all(promises);
return filteredEvents;
}

/**
Expand All @@ -106,31 +167,4 @@ export class ArmaEventsService {

return dateCopy.getTime() > (new Date()).getTime();
}

/**
* Fetch attendance for given topic id
* @param {number} tid Topic id
* @returns {[number, number]} [Number of firm commitments, Number of "maybes"]
*/
private static async fetchAttendance (tid: number): Promise<[number, number]> {
const response = await fetch(`${ArmaEventsService.FORUM_URI}/api/attendance/${tid}`);

if (!response.ok) {
throw new Error(`Error while trying to fetch attendance for topic ${tid}. Forum API responded with status code ${response.status}.`);
}
const { attendants } = await response.json() as { attendants: Array<{ probability: 0 | 0.5 | 1 }> };

let firm = 0;
let maybe = 0;

for (const { probability } of attendants) {
if (probability === 0.5) {
maybe++;
} else if (probability === 1) {
firm++;
}
}

return [firm, maybe];
}
}
4 changes: 2 additions & 2 deletions frontend/src/components/Home/Events.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@
<a
v-else-if="expanded || small"
class="grad-arma-events__more"
href="https://forum.gruppe-adler.de/category/3"
href="https://arma.events/c/gruppe-adler/events"
target="_blank"
rel="noreferrer"
>
Mehr Events im Forum
Mehr Events auf arma.events
</a>
<span v-else class="grad-arma-events__more" @click="expanded = true" tabindex="0" role="button">Mehr anzeigen</span>
</Container>
Expand Down

0 comments on commit 041b7df

Please sign in to comment.