mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 11:29:46 +00:00
Remove @/config.ts import from utils/note.ts
This commit is contained in:
parent
c07c88f2f5
commit
0e667995c1
5 changed files with 44 additions and 13 deletions
|
|
@ -324,7 +324,8 @@ export class DittoRelayStore implements NRelay {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async prewarmLinkPreview(event: NostrEvent, signal?: AbortSignal): Promise<void> {
|
private async prewarmLinkPreview(event: NostrEvent, signal?: AbortSignal): Promise<void> {
|
||||||
const { firstUrl } = parseNoteContent(stripimeta(event.content, event.tags), []);
|
const { firstUrl } = parseNoteContent(stripimeta(event.content, event.tags), [], this.opts);
|
||||||
|
|
||||||
if (firstUrl) {
|
if (firstUrl) {
|
||||||
await unfurlCardCached(firstUrl, signal);
|
await unfurlCardCached(firstUrl, signal);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,35 @@
|
||||||
|
import { DittoConf } from '@ditto/conf';
|
||||||
import { assertEquals } from '@std/assert';
|
import { assertEquals } from '@std/assert';
|
||||||
|
|
||||||
import { eventFixture } from '@/test.ts';
|
import { eventFixture } from '@/test.ts';
|
||||||
import { getMediaLinks, parseNoteContent, stripimeta } from '@/utils/note.ts';
|
import { getMediaLinks, parseNoteContent, stripimeta } from '@/utils/note.ts';
|
||||||
|
|
||||||
Deno.test('parseNoteContent', () => {
|
Deno.test('parseNoteContent', () => {
|
||||||
const { html, links, firstUrl } = parseNoteContent('Hello, world!', []);
|
const conf = new DittoConf(new Map());
|
||||||
|
const { html, links, firstUrl } = parseNoteContent('Hello, world!', [], { conf });
|
||||||
|
|
||||||
assertEquals(html, 'Hello, world!');
|
assertEquals(html, 'Hello, world!');
|
||||||
assertEquals(links, []);
|
assertEquals(links, []);
|
||||||
assertEquals(firstUrl, undefined);
|
assertEquals(firstUrl, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test('parseNoteContent parses URLs', () => {
|
Deno.test('parseNoteContent parses URLs', () => {
|
||||||
const { html } = parseNoteContent('check out my website: https://alexgleason.me', []);
|
const conf = new DittoConf(new Map());
|
||||||
|
const { html } = parseNoteContent('check out my website: https://alexgleason.me', [], { conf });
|
||||||
|
|
||||||
assertEquals(html, 'check out my website: <a href="https://alexgleason.me">https://alexgleason.me</a>');
|
assertEquals(html, 'check out my website: <a href="https://alexgleason.me">https://alexgleason.me</a>');
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test('parseNoteContent parses bare URLs', () => {
|
Deno.test('parseNoteContent parses bare URLs', () => {
|
||||||
const { html } = parseNoteContent('have you seen ditto.pub?', []);
|
const conf = new DittoConf(new Map());
|
||||||
|
const { html } = parseNoteContent('have you seen ditto.pub?', [], { conf });
|
||||||
|
|
||||||
assertEquals(html, 'have you seen <a href="http://ditto.pub">ditto.pub</a>?');
|
assertEquals(html, 'have you seen <a href="http://ditto.pub">ditto.pub</a>?');
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test('parseNoteContent parses mentions with apostrophes', () => {
|
Deno.test('parseNoteContent parses mentions with apostrophes', () => {
|
||||||
|
const conf = new DittoConf(new Map());
|
||||||
|
|
||||||
const { html } = parseNoteContent(
|
const { html } = parseNoteContent(
|
||||||
`did you see nostr:nprofile1qqsqgc0uhmxycvm5gwvn944c7yfxnnxm0nyh8tt62zhrvtd3xkj8fhgprdmhxue69uhkwmr9v9ek7mnpw3hhytnyv4mz7un9d3shjqgcwaehxw309ahx7umywf5hvefwv9c8qtmjv4kxz7gpzemhxue69uhhyetvv9ujumt0wd68ytnsw43z7s3al0v's speech?`,
|
`did you see nostr:nprofile1qqsqgc0uhmxycvm5gwvn944c7yfxnnxm0nyh8tt62zhrvtd3xkj8fhgprdmhxue69uhkwmr9v9ek7mnpw3hhytnyv4mz7un9d3shjqgcwaehxw309ahx7umywf5hvefwv9c8qtmjv4kxz7gpzemhxue69uhhyetvv9ujumt0wd68ytnsw43z7s3al0v's speech?`,
|
||||||
[{
|
[{
|
||||||
|
|
@ -29,7 +38,9 @@ Deno.test('parseNoteContent parses mentions with apostrophes', () => {
|
||||||
acct: 'alex@gleasonator.dev',
|
acct: 'alex@gleasonator.dev',
|
||||||
url: 'https://gleasonator.dev/@alex',
|
url: 'https://gleasonator.dev/@alex',
|
||||||
}],
|
}],
|
||||||
|
{ conf },
|
||||||
);
|
);
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
html,
|
html,
|
||||||
'did you see <span class="h-card"><a class="u-url mention" href="https://gleasonator.dev/@alex" rel="ugc">@<span>alex@gleasonator.dev</span></a></span>'s speech?',
|
'did you see <span class="h-card"><a class="u-url mention" href="https://gleasonator.dev/@alex" rel="ugc">@<span>alex@gleasonator.dev</span></a></span>'s speech?',
|
||||||
|
|
@ -37,6 +48,8 @@ Deno.test('parseNoteContent parses mentions with apostrophes', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test('parseNoteContent parses mentions with commas', () => {
|
Deno.test('parseNoteContent parses mentions with commas', () => {
|
||||||
|
const conf = new DittoConf(new Map());
|
||||||
|
|
||||||
const { html } = parseNoteContent(
|
const { html } = parseNoteContent(
|
||||||
`Sim. Hi nostr:npub1q3sle0kvfsehgsuexttt3ugjd8xdklxfwwkh559wxckmzddywnws6cd26p and nostr:npub1gujeqakgt7fyp6zjggxhyy7ft623qtcaay5lkc8n8gkry4cvnrzqd3f67z, any chance to have Cobrafuma as PWA?`,
|
`Sim. Hi nostr:npub1q3sle0kvfsehgsuexttt3ugjd8xdklxfwwkh559wxckmzddywnws6cd26p and nostr:npub1gujeqakgt7fyp6zjggxhyy7ft623qtcaay5lkc8n8gkry4cvnrzqd3f67z, any chance to have Cobrafuma as PWA?`,
|
||||||
[{
|
[{
|
||||||
|
|
@ -50,7 +63,9 @@ Deno.test('parseNoteContent parses mentions with commas', () => {
|
||||||
acct: 'patrick@patrickdosreis.com',
|
acct: 'patrick@patrickdosreis.com',
|
||||||
url: 'https://gleasonator.dev/@patrick@patrickdosreis.com',
|
url: 'https://gleasonator.dev/@patrick@patrickdosreis.com',
|
||||||
}],
|
}],
|
||||||
|
{ conf },
|
||||||
);
|
);
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
html,
|
html,
|
||||||
'Sim. Hi <span class="h-card"><a class="u-url mention" href="https://gleasonator.dev/@alex" rel="ugc">@<span>alex@gleasonator.dev</span></a></span> and <span class="h-card"><a class="u-url mention" href="https://gleasonator.dev/@patrick@patrickdosreis.com" rel="ugc">@<span>patrick@patrickdosreis.com</span></a></span>, any chance to have Cobrafuma as PWA?',
|
'Sim. Hi <span class="h-card"><a class="u-url mention" href="https://gleasonator.dev/@alex" rel="ugc">@<span>alex@gleasonator.dev</span></a></span> and <span class="h-card"><a class="u-url mention" href="https://gleasonator.dev/@patrick@patrickdosreis.com" rel="ugc">@<span>patrick@patrickdosreis.com</span></a></span>, any chance to have Cobrafuma as PWA?',
|
||||||
|
|
@ -58,19 +73,26 @@ Deno.test('parseNoteContent parses mentions with commas', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test("parseNoteContent doesn't parse invalid nostr URIs", () => {
|
Deno.test("parseNoteContent doesn't parse invalid nostr URIs", () => {
|
||||||
const { html } = parseNoteContent('nip19 has URIs like nostr:npub and nostr:nevent, etc.', []);
|
const conf = new DittoConf(new Map());
|
||||||
|
const { html } = parseNoteContent('nip19 has URIs like nostr:npub and nostr:nevent, etc.', [], { conf });
|
||||||
assertEquals(html, 'nip19 has URIs like nostr:npub and nostr:nevent, etc.');
|
assertEquals(html, 'nip19 has URIs like nostr:npub and nostr:nevent, etc.');
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test('parseNoteContent renders empty for non-profile nostr URIs', () => {
|
Deno.test('parseNoteContent renders empty for non-profile nostr URIs', () => {
|
||||||
|
const conf = new DittoConf(new Map());
|
||||||
|
|
||||||
const { html } = parseNoteContent(
|
const { html } = parseNoteContent(
|
||||||
'nostr:nevent1qgsr9cvzwc652r4m83d86ykplrnm9dg5gwdvzzn8ameanlvut35wy3gpz3mhxue69uhhztnnwashymtnw3ezucm0d5qzqru8mkz2q4gzsxg99q7pdneyx7n8p5u0afe3ntapj4sryxxmg4gpcdvgce',
|
'nostr:nevent1qgsr9cvzwc652r4m83d86ykplrnm9dg5gwdvzzn8ameanlvut35wy3gpz3mhxue69uhhztnnwashymtnw3ezucm0d5qzqru8mkz2q4gzsxg99q7pdneyx7n8p5u0afe3ntapj4sryxxmg4gpcdvgce',
|
||||||
[],
|
[],
|
||||||
|
{ conf },
|
||||||
);
|
);
|
||||||
|
|
||||||
assertEquals(html, '');
|
assertEquals(html, '');
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test("parseNoteContent doesn't fuck up links to my own post", () => {
|
Deno.test("parseNoteContent doesn't fuck up links to my own post", () => {
|
||||||
|
const conf = new DittoConf(new Map());
|
||||||
|
|
||||||
const { html } = parseNoteContent(
|
const { html } = parseNoteContent(
|
||||||
'Check this post: https://gleasonator.dev/@alex@gleasonator.dev/posts/a8badb480d88f9e7b6a090342279ef47ed0e0a3989ed85f898dfedc6be94225f',
|
'Check this post: https://gleasonator.dev/@alex@gleasonator.dev/posts/a8badb480d88f9e7b6a090342279ef47ed0e0a3989ed85f898dfedc6be94225f',
|
||||||
[{
|
[{
|
||||||
|
|
@ -79,7 +101,9 @@ Deno.test("parseNoteContent doesn't fuck up links to my own post", () => {
|
||||||
acct: 'alex@gleasonator.dev',
|
acct: 'alex@gleasonator.dev',
|
||||||
url: 'https://gleasonator.dev/@alex',
|
url: 'https://gleasonator.dev/@alex',
|
||||||
}],
|
}],
|
||||||
|
{ conf },
|
||||||
);
|
);
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
html,
|
html,
|
||||||
'Check this post: <a href="https://gleasonator.dev/@alex@gleasonator.dev/posts/a8badb480d88f9e7b6a090342279ef47ed0e0a3989ed85f898dfedc6be94225f">https://gleasonator.dev/@alex@gleasonator.dev/posts/a8badb480d88f9e7b6a090342279ef47ed0e0a3989ed85f898dfedc6be94225f</a>',
|
'Check this post: <a href="https://gleasonator.dev/@alex@gleasonator.dev/posts/a8badb480d88f9e7b6a090342279ef47ed0e0a3989ed85f898dfedc6be94225f">https://gleasonator.dev/@alex@gleasonator.dev/posts/a8badb480d88f9e7b6a090342279ef47ed0e0a3989ed85f898dfedc6be94225f</a>',
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ import linkifyStr from 'linkify-string';
|
||||||
import linkify from 'linkifyjs';
|
import linkify from 'linkifyjs';
|
||||||
import { nip19, nip27 } from 'nostr-tools';
|
import { nip19, nip27 } from 'nostr-tools';
|
||||||
|
|
||||||
import { Conf } from '@/config.ts';
|
|
||||||
import { html } from '@/utils/html.ts';
|
import { html } from '@/utils/html.ts';
|
||||||
import { getUrlMediaType, isPermittedMediaType } from '@/utils/media.ts';
|
import { getUrlMediaType, isPermittedMediaType } from '@/utils/media.ts';
|
||||||
|
|
||||||
import { MastodonMention } from '@ditto/mastoapi/types';
|
import type { DittoConf } from '@ditto/conf';
|
||||||
|
import type { MastodonMention } from '@ditto/mastoapi/types';
|
||||||
|
|
||||||
linkify.registerCustomProtocol('nostr', true);
|
linkify.registerCustomProtocol('nostr', true);
|
||||||
linkify.registerCustomProtocol('wss');
|
linkify.registerCustomProtocol('wss');
|
||||||
|
|
@ -21,8 +21,14 @@ interface ParsedNoteContent {
|
||||||
firstUrl: string | undefined;
|
firstUrl: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ParseNoteContentOpts {
|
||||||
|
conf: DittoConf;
|
||||||
|
}
|
||||||
|
|
||||||
/** Convert Nostr content to Mastodon API HTML. Also return parsed data. */
|
/** Convert Nostr content to Mastodon API HTML. Also return parsed data. */
|
||||||
function parseNoteContent(content: string, mentions: MastodonMention[]): ParsedNoteContent {
|
function parseNoteContent(content: string, mentions: MastodonMention[], opts: ParseNoteContentOpts): ParsedNoteContent {
|
||||||
|
const { conf } = opts;
|
||||||
|
|
||||||
const links = linkify.find(content).filter(({ type }) => type === 'url');
|
const links = linkify.find(content).filter(({ type }) => type === 'url');
|
||||||
const firstUrl = links.find(isNonMediaLink)?.href;
|
const firstUrl = links.find(isNonMediaLink)?.href;
|
||||||
|
|
||||||
|
|
@ -30,7 +36,7 @@ function parseNoteContent(content: string, mentions: MastodonMention[]): ParsedN
|
||||||
render: {
|
render: {
|
||||||
hashtag: ({ content }) => {
|
hashtag: ({ content }) => {
|
||||||
const tag = content.replace(/^#/, '');
|
const tag = content.replace(/^#/, '');
|
||||||
const href = Conf.local(`/tags/${tag}`);
|
const href = conf.local(`/tags/${tag}`);
|
||||||
return html`<a class="mention hashtag" href="${href}" rel="tag"><span>#</span>${tag}</a>`;
|
return html`<a class="mention hashtag" href="${href}" rel="tag"><span>#</span>${tag}</a>`;
|
||||||
},
|
},
|
||||||
url: ({ attributes, content }) => {
|
url: ({ attributes, content }) => {
|
||||||
|
|
@ -49,7 +55,7 @@ function parseNoteContent(content: string, mentions: MastodonMention[]): ParsedN
|
||||||
const npub = nip19.npubEncode(pubkey);
|
const npub = nip19.npubEncode(pubkey);
|
||||||
const acct = mention?.acct ?? npub;
|
const acct = mention?.acct ?? npub;
|
||||||
const name = mention?.acct ?? npub.substring(0, 8);
|
const name = mention?.acct ?? npub.substring(0, 8);
|
||||||
const href = mention?.url ?? Conf.local(`/@${acct}`);
|
const href = mention?.url ?? conf.local(`/@${acct}`);
|
||||||
return html`<span class="h-card"><a class="u-url mention" href="${href}" rel="ugc">@<span>${name}</span></a></span>${extra}`;
|
return html`<span class="h-card"><a class="u-url mention" href="${href}" rel="ugc">@<span>${name}</span></a></span>${extra}`;
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return '';
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ function renderAccount(event: Omit<DittoEvent, 'id' | 'sig'>, opts: ToAccountOpt
|
||||||
const parsed05 = stats?.nip05 ? parseNip05(stats.nip05) : undefined;
|
const parsed05 = stats?.nip05 ? parseNip05(stats.nip05) : undefined;
|
||||||
const acct = parsed05?.handle || npub;
|
const acct = parsed05?.handle || npub;
|
||||||
|
|
||||||
const { html } = parseNoteContent(about || '', []);
|
const { html } = parseNoteContent(about || '', [], { conf: Conf });
|
||||||
|
|
||||||
const fields = _fields
|
const fields = _fields
|
||||||
?.slice(0, Conf.profileFields.maxFields)
|
?.slice(0, Conf.profileFields.maxFields)
|
||||||
|
|
@ -84,7 +84,7 @@ function renderAccount(event: Omit<DittoEvent, 'id' | 'sig'>, opts: ToAccountOpt
|
||||||
discoverable: true,
|
discoverable: true,
|
||||||
display_name: name ?? '',
|
display_name: name ?? '',
|
||||||
emojis: renderEmojis(event),
|
emojis: renderEmojis(event),
|
||||||
fields: fields.map((field) => ({ ...field, value: parseNoteContent(field.value, []).html })),
|
fields: fields.map((field) => ({ ...field, value: parseNoteContent(field.value, [], { conf: Conf }).html })),
|
||||||
follow_requests_count: 0,
|
follow_requests_count: 0,
|
||||||
followers_count: stats?.followers_count ?? 0,
|
followers_count: stats?.followers_count ?? 0,
|
||||||
following_count: stats?.following_count ?? 0,
|
following_count: stats?.following_count ?? 0,
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ async function renderStatus(
|
||||||
|
|
||||||
const mentions = event.mentions?.map((event) => renderMention(event)) ?? [];
|
const mentions = event.mentions?.map((event) => renderMention(event)) ?? [];
|
||||||
|
|
||||||
const { html, links, firstUrl } = parseNoteContent(stripimeta(event.content, event.tags), mentions);
|
const { html, links, firstUrl } = parseNoteContent(stripimeta(event.content, event.tags), mentions, { conf: Conf });
|
||||||
|
|
||||||
const [card, relatedEvents] = await Promise
|
const [card, relatedEvents] = await Promise
|
||||||
.all([
|
.all([
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue