diff --git a/src/github/github.service.ts b/src/github/github.service.ts index 88087e7..ed15f36 100644 --- a/src/github/github.service.ts +++ b/src/github/github.service.ts @@ -1,9 +1,10 @@ import { Inject, Injectable, Logger } from "@nestjs/common"; import { ConfigType } from "@nestjs/config"; import { graphql } from "@octokit/graphql"; -import { RateLimit, User } from "@octokit/graphql-schema"; +import { RateLimit, Repository, User } from "@octokit/graphql-schema"; import GithubConfig from "../config/github.config"; +import getRepo from "./gql/get-repo"; import getUser from "./gql/get-user"; @Injectable() @@ -29,6 +30,14 @@ export class GithubService { return user; } + async getRepo (owner: string, repo: string) { + const { query, variables } = getRepo(owner, repo); + + const { repository } = await this.graphqlWithAuth<{ repository: Repository }>(query, variables); + + return repository; + } + async rateLimit () { const { rateLimit } = await this.graphqlWithAuth<{ rateLimit: RateLimit }>(`query { rateLimit { diff --git a/src/github/gql/get-repo.ts b/src/github/gql/get-repo.ts new file mode 100644 index 0000000..7c9a60c --- /dev/null +++ b/src/github/gql/get-repo.ts @@ -0,0 +1,37 @@ +const getRepo = (owner: string, repo: string) => ({ + query: ` +query ($owner: String!, $repo: String!) { + repository( + owner: $owner + name: $repo + ) { + id + name + databaseId + nameWithOwner + owner { + id + login + avatarUrl + } + languages (first: 100, orderBy: { field: SIZE, direction: DESC }) { + edges { + node { + id + color + name + } + size + } + totalSize + totalCount + } + } +}`, + variables: { + owner, + repo, + }, +}); + +export default getRepo; diff --git a/src/social-card/highlight-card/highlight-card.service.ts b/src/social-card/highlight-card/highlight-card.service.ts index ed39e13..e0f6667 100644 --- a/src/social-card/highlight-card/highlight-card.service.ts +++ b/src/social-card/highlight-card/highlight-card.service.ts @@ -18,12 +18,13 @@ interface HighlightCardData { body: string, reactions: number, avatarUrl: string, - repos: Repository[], + repo: Repository, langTotal: number, langs: (Language & { size: number, })[], - updated_at: Date + updated_at: Date, + url: string, } @Injectable() @@ -37,48 +38,36 @@ export class HighlightCardService { ) {} private async getHighlightData (highlightId: number): Promise { - const langs: Record = {}; - const today = (new Date); - const today30daysAgo = new Date((new Date).setDate(today.getDate() - 30)); - const highlightReq = await firstValueFrom(this.httpService.get(`https://api.opensauced.pizza/v1/user/highlights/${highlightId}`)); - const { login, title, highlight: body, updated_at } = highlightReq.data; + const { login, title, highlight: body, updated_at, url } = highlightReq.data; const reactionsReq = await firstValueFrom(this.httpService.get(`https://api.opensauced.pizza/v1/highlights/${highlightId}/reactions`)); const reactions = reactionsReq.data.reduce( (acc, curr) => acc + Number(curr.reaction_count), 0); + const [owner, repoName] = url.replace("https://github.com/", "").split("/"); + const user = await this.githubService.getUser(login); - const langRepos = user.repositories.nodes?.filter(repo => new Date(String(repo?.pushedAt)) > today30daysAgo) as Repository[]; - let langTotal = 0; - - langRepos.forEach(repo => { - repo.languages?.edges?.forEach(edge => { - if (edge?.node.id) { - langTotal += edge.size; - - if (!Object.keys(langs).includes(edge.node.id)) { - langs[edge.node.id] = { - ...edge.node, - size: edge.size, - }; - } else { - langs[edge.node.id].size += edge.size; - } - } - }); - }); + const repo = await this.githubService.getRepo(owner, repoName); + + const langList = repo.languages?.edges?.flatMap(edge => { + if (edge) { + return { + ...edge.node, + size: edge.size, + }; + } + }) as (Language & { size: number })[]; return { title, body, reactions, avatarUrl: `${String(user.avatarUrl)}&size=150`, - langs: Array.from(Object.values(langs)).sort((a, b) => b.size - a.size), - langTotal, - repos: user.topRepositories.nodes?.filter(repo => !repo?.isPrivate && repo?.owner.login !== login) as Repository[], + langs: langList, + langTotal: repo.languages?.totalSize ?? 0, + repo, updated_at: new Date(updated_at), + url, }; } @@ -87,9 +76,9 @@ export class HighlightCardService { const { html } = await import("satori-html"); const satori = (await import("satori")).default; - const { title, body, reactions, avatarUrl, repos, langs, langTotal } = highlightData ? highlightData : await this.getHighlightData(highlightId); + const { title, body, reactions, avatarUrl, repo, langs, langTotal } = highlightData ? highlightData : await this.getHighlightData(highlightId); - const template = html(highlightCardTemplate(avatarUrl, title, body, userLangs(langs, langTotal), userProfileRepos(repos, 2), reactions)); + const template = html(highlightCardTemplate(avatarUrl, title, body, userLangs(langs, langTotal), userProfileRepos([repo], 2), reactions)); const interArrayBuffer = await fs.readFile("node_modules/@fontsource/inter/files/inter-all-400-normal.woff"); diff --git a/src/social-card/templates/shared/user-repos.ts b/src/social-card/templates/shared/user-repos.ts index 4ab9ed2..faedf7d 100644 --- a/src/social-card/templates/shared/user-repos.ts +++ b/src/social-card/templates/shared/user-repos.ts @@ -2,8 +2,9 @@ import repoIconWithName from "./repo-icon-with-name"; import { Repository } from "@octokit/graphql-schema"; const userProfileRepos = (repos: Repository[], limit: number): string => { + const charLimit = limit === 1 ? 60 : repos.length === 1 ? 60 : 15; const repoList = repos.map(({ name, owner: { avatarUrl } }) => - repoIconWithName(`${name.substring(0, 15).replace(/\.+$/, "")}${name.length > 15 ? "..." : ""}`, `${String(avatarUrl)}&size=40`)); + repoIconWithName(`${name.substring(0, charLimit).replace(/\.+$/, "")}${name.length > charLimit ? "..." : ""}`, `${String(avatarUrl)}&size=40`)); return `${repoList.slice(0, limit).join("")}${repoList.length > limit ? `

+${repoList.length - limit}

`