diff --git a/packages/service/src/collector.ts b/packages/service/src/collector.ts index 9b5f31972..0ea0c81b2 100644 --- a/packages/service/src/collector.ts +++ b/packages/service/src/collector.ts @@ -1,5 +1,6 @@ import { ComposedService, type ContentData, type ServiceMetadata } from "./services/abstract.js"; import { ArticleService } from "./services/article-service.js"; +import { GuildService } from "./services/guild-service.js"; import { PackageService } from "./services/package-service.js"; import { type ConnectedService, SocietyStatsService } from "./services/society-stats-service.js"; import { VideoService } from "./services/video-service.js"; @@ -8,7 +9,7 @@ import { VideoService } from "./services/video-service.js"; export class CollectorService extends ComposedService { private readonly stats = new SocietyStatsService(); constructor(private userService: ConnectedService) { - super([new VideoService(), new PackageService(), new ArticleService()]); + super([new VideoService(), new PackageService(), new ArticleService(), new GuildService()]); } async getInformation(metadata: ServiceMetadata): Promise> { diff --git a/packages/service/src/components/content.svelte b/packages/service/src/components/content.svelte index 5b6b1a5bb..0ef27bb87 100644 --- a/packages/service/src/components/content.svelte +++ b/packages/service/src/components/content.svelte @@ -1,10 +1,12 @@ + + + {#if cover} +
+ +
+ {/if} + {members} Members +
+ + diff --git a/packages/service/src/components/package.svelte b/packages/service/src/components/package.svelte index d7c4fc014..1cd372f38 100644 --- a/packages/service/src/components/package.svelte +++ b/packages/service/src/components/package.svelte @@ -15,7 +15,7 @@ export let tags: Array = []; export let connected = false; - + {#if cover}
diff --git a/packages/service/src/components/recipe.svelte b/packages/service/src/components/recipe.svelte index 785688ad6..678286239 100644 --- a/packages/service/src/components/recipe.svelte +++ b/packages/service/src/components/recipe.svelte @@ -16,7 +16,7 @@ export let tags: Array = []; export let connected = false; - +
Read more... diff --git a/packages/service/src/components/video.svelte b/packages/service/src/components/video.svelte index 7e91b6dc3..0f6388224 100644 --- a/packages/service/src/components/video.svelte +++ b/packages/service/src/components/video.svelte @@ -14,7 +14,7 @@ export let tags: Array = []; export let connected = false; - + diff --git a/packages/service/src/services/abstract.ts b/packages/service/src/services/abstract.ts index 945acfb66..1fe104319 100644 --- a/packages/service/src/services/abstract.ts +++ b/packages/service/src/services/abstract.ts @@ -7,7 +7,7 @@ export type ContentData = { type: string; name: string; author: string; - lastUpdate: string; + lastUpdate?: string; keywords: Array; description: string; }; diff --git a/packages/service/src/services/article-service.ts b/packages/service/src/services/article-service.ts index d7d40c25c..e2a0f8632 100644 --- a/packages/service/src/services/article-service.ts +++ b/packages/service/src/services/article-service.ts @@ -1,5 +1,5 @@ import { Memorize, longTermCache } from "../cache.js"; -import {ComposedService, type ContentData, type ServiceInterface, type ServiceMetadata} from "./abstract.js"; +import { ComposedService, type ContentData, type ServiceInterface, type ServiceMetadata } from "./abstract.js"; export const TYPE = "article"; export const RECIPE_TYPE = "recipe"; @@ -10,7 +10,6 @@ export class ArticleService extends ComposedService<{ preview: string }> { } } - export class RecipeService implements ServiceInterface<{ preview: string }> { canHandle(metadata: ServiceMetadata): Promise { return Promise.resolve([RECIPE_TYPE, TYPE].includes(metadata.type)); diff --git a/packages/service/src/services/guild-service.ts b/packages/service/src/services/guild-service.ts new file mode 100644 index 000000000..23eeddf30 --- /dev/null +++ b/packages/service/src/services/guild-service.ts @@ -0,0 +1,135 @@ +import { Memorize, longTermCache } from "../cache.js"; +import type { ContentData, ServiceInterface, ServiceMetadata } from "./abstract.js"; + +export const TYPE = "guild" as const; + +export class GuildService implements ServiceInterface<{ cover: string; members: number }> { + canHandle(metadata: ServiceMetadata): Promise { + return Promise.resolve(metadata.type === TYPE); + } + async getInformation(metadata: ServiceMetadata): Promise<(ContentData & { cover: string; members: number }) | never> { + const guilds = await this.getGuilds(); + let guild: GuildHostGuildNodeResponse | undefined = guilds.data.nodeBySlugId.guilds.edges.find( + (guild) => guild.node.slugId === metadata.identifier, + )?.node; + + if (guild === undefined) { + guild = (await this.getOneGuild(metadata.identifier))?.data.nodeBySlugId; + } + + if (guild === undefined) { + throw new Error("Invalid data service"); + } + + return { + name: guild.name, + description: guild.description, + type: TYPE, + author: "guild.host", + keywords: [], + members: guild.networkMembers.totalCount, + cover: guild.backgroundPhoto + ? `https://ik.imagekit.io/guild/prod/tr:w-600,dpr-1/${guild.backgroundPhoto?.rowId}.${guild.backgroundPhoto?.contentType.toLowerCase()}` + : "", + }; + } + + @Memorize(longTermCache) + private getOneGuild(id: string): Promise { + return fetch("https://guild.host/graphql/1bab259132f26a669a0dbe5184260401be37f259bf888010711abab5438e8e51", { + headers: { + "X-Gqlvars": `{"id":"${id}"}`, + }, + }).then((response) => response.json()); + } + + @Memorize(longTermCache) + private getGuilds(): Promise { + return fetch("https://guild.host/graphql/932d20dc08db4fb8d9f86e17908ba8ccb8b1de931ad51718689570c942c82c71", { + headers: { + "X-Gqlvars": '{"id":"svelte-society"}', + }, + }).then((response) => response.json()); + } + + getAllServiceMetadata(): Promise> { + return this.getGuilds().then((response) => + response.data.nodeBySlugId.guilds.edges.map((guild) => ({ + type: TYPE, + identifier: guild.node.slugId, + })), + ); + } +} + +type GuildHostResponse = { + data: { + nodeBySlugId: { + __typename: "Guild"; + name: string; + slugId: string; + description: string; + networks: { edges: []; pageInfo: { endCursor: null; hasNextPage: boolean } }; + id: string; + guilds: { + edges: Array<{ + node: GuildHostGuildNodeResponse; + cursor: string; + }>; + pageInfo: { endCursor: string; hasNextPage: boolean }; + }; + __isNode: "Guild"; + }; + }; +}; + +type GuildHostGuildNodeResponse = { + __typename: "Guild"; + id: string; + slugId: string; + type: "NETWORK" | "GUILD"; + myMembership: unknown; + minimumDonationAmount?: number; + donationCurrency?: "EUR"; + rowId: string; + name: string; + description: string; + networkMembers: { + totalCount: number; + }; + primaryPhoto: { + rowId: string; + contentType: "PNG" | "WEBP" | "JPEG"; + id: string; + } | null; + backgroundPhoto: { + rowId: string; + contentType: "PNG" | "WEBP" | "JPEG"; + id: string; + } | null; + totalNetworks?: { + edges: Array; + }; + totalGuilds?: { + edges: Array<{ + cursor: string; + }>; + }; + totalEvents?: { + edges: Array<{ + cursor: string; + }>; + }; + totalPresentations?: { + edges: Array<{ + cursor: string; + }>; + }; + __isNode?: "Guild"; +}; + +type GuildHostOneResponse = { + data: { + nodeBySlugId: GuildHostGuildNodeResponse; + }; +}; diff --git a/sites/www/src/routes/(app)/+page.server.ts b/sites/www/src/routes/(app)/+page.server.ts index ea959308c..9016dd67b 100644 --- a/sites/www/src/routes/(app)/+page.server.ts +++ b/sites/www/src/routes/(app)/+page.server.ts @@ -1,4 +1,5 @@ import { CollectorService } from 'sveltesociety.dev-service/src/collector.js'; +import { GuildService } from 'sveltesociety.dev-service/src/services/guild-service'; import { ConnectedService } from 'sveltesociety.dev-service/src/services/society-stats-service.js'; import type { PageServerLoad } from './$types'; @@ -15,7 +16,9 @@ export const load: PageServerLoad = async () => { { type: 'video', identifier: '330781388' }, { type: 'recipe', identifier: 'xxx' }, { type: 'package', identifier: 'svelte' }, - { type: 'package', identifier: 'svelte-atoms' } + { type: 'package', identifier: 'svelte-atoms' }, + { type: 'guild', identifier: 'london-javascript' }, + ...(await new GuildService().getAllServiceMetadata()) ]) }; }; diff --git a/sites/www/src/routes/(app)/+page.svelte b/sites/www/src/routes/(app)/+page.svelte index aeba3783d..53c326622 100644 --- a/sites/www/src/routes/(app)/+page.svelte +++ b/sites/www/src/routes/(app)/+page.svelte @@ -2,6 +2,7 @@ import Package from 'sveltesociety.dev-service/src/components/package.svelte'; import Recipe from 'sveltesociety.dev-service/src/components/recipe.svelte'; import Video from 'sveltesociety.dev-service/src/components/video.svelte'; + import Guild from 'sveltesociety.dev-service/src/components/guild.svelte'; import type { PageData } from './$types'; export let data: PageData; @@ -14,48 +15,13 @@ Home page!
{#each data.items as item} {#if item.type === 'package'} - + {:else if item.type === 'video'} -