mirror of
https://github.com/aljazceru/hypergolic.git
synced 2025-12-23 00:04:25 +01:00
problem: github rest api has rate limits
solution: parse problem url before publish merit request additional: parse github pull url
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
import Todo from './Todo.svelte';
|
import Todo from './Todo.svelte';
|
||||||
import { isValidUrl } from '@/event_helpers/rockets';
|
import { isValidUrl } from '@/event_helpers/rockets';
|
||||||
import CalculateSats from './CalculateSats.svelte';
|
import CalculateSats from './CalculateSats.svelte';
|
||||||
|
import { isGitHubUrl, parseProblem } from '@/helpers';
|
||||||
|
|
||||||
export let rocketEvent: NDKEvent;
|
export let rocketEvent: NDKEvent;
|
||||||
|
|
||||||
@@ -48,6 +49,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: if (isGitHubUrl(problem)) {
|
||||||
|
parseProblem(problem).then((title) => {
|
||||||
|
if (title) {
|
||||||
|
problem = `${title}\n\n${problem}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function validateSolution(solution: string) {
|
function validateSolution(solution: string) {
|
||||||
if (solution.length > 0) {
|
if (solution.length > 0) {
|
||||||
return isValidUrl(solution);
|
return isValidUrl(solution);
|
||||||
|
|||||||
@@ -28,11 +28,7 @@
|
|||||||
<Breadcrumb.Separator />
|
<Breadcrumb.Separator />
|
||||||
<Breadcrumb.Item>
|
<Breadcrumb.Item>
|
||||||
<Breadcrumb.Page>
|
<Breadcrumb.Page>
|
||||||
{#await parseProblem(merit.Problem())}
|
{merit.Problem().substring(0, 16)}{#if merit.Problem().length > 16}...{/if}
|
||||||
{merit.Problem().substring(0, 16)}{#if merit.Problem().length > 16}...{/if}
|
|
||||||
{:then parsed}
|
|
||||||
{parsed.substring(0, 16)}{#if parsed.length > 16}...{/if}
|
|
||||||
{/await}
|
|
||||||
</Breadcrumb.Page>
|
</Breadcrumb.Page>
|
||||||
</Breadcrumb.Item>
|
</Breadcrumb.Item>
|
||||||
</Breadcrumb.List>
|
</Breadcrumb.List>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
import * as Table from '@/components/ui/table';
|
import * as Table from '@/components/ui/table';
|
||||||
import { MapOfMeritResult, MeritRequest } from '@/event_helpers/merits';
|
import { MapOfMeritResult, MeritRequest } from '@/event_helpers/merits';
|
||||||
import { Rocket, RocketATagFilter } from '@/event_helpers/rockets';
|
import { Rocket, RocketATagFilter } from '@/event_helpers/rockets';
|
||||||
import { parseProblem, unixToRelativeTime } from '@/helpers';
|
import { unixToRelativeTime } from '@/helpers';
|
||||||
import { ndk } from '@/ndk';
|
import { ndk } from '@/ndk';
|
||||||
import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
|
import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
|
||||||
import { Avatar, Name } from '@nostr-dev-kit/ndk-svelte-components';
|
import { Avatar, Name } from '@nostr-dev-kit/ndk-svelte-components';
|
||||||
@@ -115,11 +115,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
<Table.Cell class="hidden text-left md:table-cell">
|
<Table.Cell class="hidden text-left md:table-cell">
|
||||||
{#await parseProblem(merit.Problem())}
|
{merit.Problem().split('\n')[0]}
|
||||||
{merit.Problem()}
|
|
||||||
{:then parsed}
|
|
||||||
{parsed}
|
|
||||||
{/await}
|
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
<Table.Cell class="table-cell">{merit.Sats}</Table.Cell>
|
<Table.Cell class="table-cell">{merit.Sats}</Table.Cell>
|
||||||
<Table.Cell class="table-cell">{merit.Merits}</Table.Cell>
|
<Table.Cell class="table-cell">{merit.Merits}</Table.Cell>
|
||||||
|
|||||||
@@ -11,13 +11,7 @@
|
|||||||
import { Separator } from '$lib/components/ui/separator/index.js';
|
import { Separator } from '$lib/components/ui/separator/index.js';
|
||||||
import * as Table from '@/components/ui/table';
|
import * as Table from '@/components/ui/table';
|
||||||
import { Rocket, RocketATagFilter } from '@/event_helpers/rockets';
|
import { Rocket, RocketATagFilter } from '@/event_helpers/rockets';
|
||||||
import {
|
import { formatReferenceTime, getCuckPrice, getRocketURL, unixToRelativeTime } from '@/helpers';
|
||||||
formatReferenceTime,
|
|
||||||
getCuckPrice,
|
|
||||||
getRocketURL,
|
|
||||||
parseProblem,
|
|
||||||
unixToRelativeTime
|
|
||||||
} from '@/helpers';
|
|
||||||
import { derived } from 'svelte/store';
|
import { derived } from 'svelte/store';
|
||||||
|
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
@@ -123,11 +117,7 @@
|
|||||||
<Card.Header class="pb-3">
|
<Card.Header class="pb-3">
|
||||||
<div class="flex flex-nowrap justify-between">
|
<div class="flex flex-nowrap justify-between">
|
||||||
<Card.Title>
|
<Card.Title>
|
||||||
{#await parseProblem(merit.Problem())}
|
{merit.Problem().split('\n')[0]}
|
||||||
Problem: {merit.Problem().substring(0, 20)}
|
|
||||||
{:then parsed}
|
|
||||||
{parsed}
|
|
||||||
{/await}
|
|
||||||
</Card.Title>{#if merit.Solution()}<a
|
</Card.Title>{#if merit.Solution()}<a
|
||||||
class="flex flex-nowrap text-orange-500 underline decoration-orange-500"
|
class="flex flex-nowrap text-orange-500 underline decoration-orange-500"
|
||||||
href={merit.Solution()}>View Solution <ExternalLink size={18} class="m-1" /></a
|
href={merit.Solution()}>View Solution <ExternalLink size={18} class="m-1" /></a
|
||||||
|
|||||||
@@ -90,51 +90,53 @@ export async function getCuckPrice(): Promise<number | Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function parseProblem(problem: string) {
|
export async function parseProblem(problem: string) {
|
||||||
try {
|
if (!isGitHubUrl(problem)) {
|
||||||
if (isGitHubIssueUrl(problem)) {
|
return;
|
||||||
const apiURL = convertToGitHubApiUrl(problem);
|
|
||||||
if (!apiURL) {
|
|
||||||
return problem;
|
|
||||||
}
|
|
||||||
const response = await fetch(apiURL);
|
|
||||||
const json = await response.json();
|
|
||||||
return json.title;
|
|
||||||
} else {
|
|
||||||
return problem;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Get title error:', error);
|
|
||||||
return problem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const apiURL = convertToGitHubApiUrl(problem);
|
||||||
|
if (!apiURL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(apiURL);
|
||||||
|
if (!response.ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { title } = await response.json();
|
||||||
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isGitHubIssueUrl(url: string): boolean {
|
export function isGitHubUrl(str: string): boolean {
|
||||||
|
let url;
|
||||||
try {
|
try {
|
||||||
const parsedUrl: URL = new URL(url);
|
url = new URL(str);
|
||||||
if (parsedUrl.hostname !== 'github.com') {
|
} catch {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const pathParts: string[] = parsedUrl.pathname.split('/').filter((part) => part !== '');
|
|
||||||
if (pathParts.length !== 4 || pathParts[2] !== 'issues' || !/^[1-9]\d*$/.test(pathParts[3])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const pathParts = url.pathname.split('/').filter(Boolean);
|
||||||
|
|
||||||
|
if (url.hostname !== 'github.com') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (pathParts.length !== 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!['issues', 'pull'].includes(pathParts[2])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!/^[1-9]\d*$/.test(pathParts[3])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertToGitHubApiUrl(issueUrl: URL | string): URL | null {
|
function convertToGitHubApiUrl(issueUrl: string): URL | null {
|
||||||
|
const url = new URL(issueUrl);
|
||||||
|
const [owner, repo, , issueNumber] = url.pathname.split('/').filter(Boolean);
|
||||||
try {
|
try {
|
||||||
const url = new URL(issueUrl);
|
// Whether it's `issues` or `pull`, the API uses `issues`
|
||||||
if (url.hostname !== 'github.com') {
|
|
||||||
throw new Error('Not a valid GitHub URL');
|
|
||||||
}
|
|
||||||
const pathParts = url.pathname.split('/').filter((part) => part !== '');
|
|
||||||
if (pathParts.length !== 4 || pathParts[2] !== 'issues') {
|
|
||||||
throw new Error('Not a valid GitHub issue URL');
|
|
||||||
}
|
|
||||||
const [owner, repo, , issueNumber] = pathParts;
|
|
||||||
return new URL(`https://api.github.com/repos/${owner}/${repo}/issues/${issueNumber}`);
|
return new URL(`https://api.github.com/repos/${owner}/${repo}/issues/${issueNumber}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('URL conversion error:', error);
|
console.error('URL conversion error:', error);
|
||||||
|
|||||||
Reference in New Issue
Block a user