Merge pull request #250 from cloudflare/fix-wrong-account-url

fix wrong account url being used
pull/287/head
Sven Sauleau 2023-02-15 11:53:14 +00:00 zatwierdzone przez GitHub
commit 0d2c8b4504
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
6 zmienionych plików z 89 dodań i 28 usunięć

Wyświetl plik

@ -5,6 +5,7 @@ import { Avatar } from '../avatar'
import type { Account, MastodonStatus } from '~/types'
import styles from '../../utils/innerHtmlContent.scss?inline'
import { MediaGallery } from '../MediaGallery.tsx'
import { useAccountUrl } from '~/utils/useAccountUrl'
type Props = {
status: MastodonStatus
@ -17,7 +18,7 @@ export default component$((props: Props) => {
const status = props.status.reblog ?? props.status
const reblogger = props.status.reblog && props.status.account
const accountUrl = `/@${status.account.username}`
const accountUrl = useAccountUrl(status.account)
const statusUrl = `${accountUrl}/${status.id}`
const handleContentClick = $(() => nav(statusUrl))
@ -65,13 +66,15 @@ export default component$((props: Props) => {
)
})
export const RebloggerLink = ({ account }: { account: Account | null }) => {
export const RebloggerLink = component$(({ account }: { account: Account | null }) => {
const accountUrl = useAccountUrl(account)
return (
account && (
<div class="flex text-wildebeest-500 py-3">
<p>
<i class="fa fa-retweet mr-3 w-4 inline-block" />
<a class="no-underline" href={account.url}>
<a class="no-underline" href={accountUrl}>
{account.display_name}
</a>
&nbsp;boosted
@ -79,4 +82,4 @@ export const RebloggerLink = ({ account }: { account: Account | null }) => {
</div>
)
)
}
})

Wyświetl plik

@ -1,7 +1,8 @@
import { component$ } from '@builder.io/qwik'
import type { Account } from '~/types'
import { useAccountUrl } from '~/utils/useAccountUrl'
type AvatarDetails = Pick<Account, 'display_name' | 'avatar' | 'url'>
type AvatarDetails = Partial<Pick<Account, 'id'>> & Pick<Account, 'display_name' | 'avatar' | 'url'>
type Props = {
primary: AvatarDetails
@ -9,13 +10,16 @@ type Props = {
}
export const Avatar = component$<Props>(({ primary, secondary }) => {
const primaryUrl = useAccountUrl(primary)
const secondaryUrl = useAccountUrl(secondary)
return (
<div class={`relative ${secondary && 'pr-2 pb-2'}`}>
<a href={primary.url}>
<a href={primaryUrl}>
<img class="rounded h-12 w-12" src={primary.avatar} alt={`Avatar of ${primary.display_name}`} />
</a>
{secondary && (
<a href={secondary.url}>
<a href={secondaryUrl}>
<img
class="absolute right-0 bottom-0 rounded h-6 w-6"
src={secondary.avatar}

Wyświetl plik

@ -14,6 +14,7 @@ import { getErrorHtml } from '~/utils/getErrorHtml/getErrorHtml'
import styles from '../../../../utils/innerHtmlContent.scss?inline'
import { getTextContent } from 'wildebeest/backend/src/activitypub/objects'
import { getDocumentHead } from '~/utils/getDocumentHead'
import { useAccountUrl } from '~/utils/useAccountUrl'
export const statusLoader = loader$<
{ DATABASE: D1Database },
@ -72,7 +73,7 @@ export default component$(() => {
})
export const AccountCard = component$<{ status: MastodonStatus }>(({ status }) => {
const accountUrl = `/@${status.account.username}`
const accountUrl = useAccountUrl(status.account)
return (
<div class="flex">

Wyświetl plik

@ -0,0 +1,46 @@
import { useSignal, useTask$ } from '@builder.io/qwik'
import { parseHandle } from 'wildebeest/backend/src/utils/parse'
import { Account } from '~/types'
import { useDomain } from './useDomain'
/**
* Hook to get a url to use for links for the provided account.
*
* Note: using account.url is not sufficient since we want to distinguish
* between local and remote accounts and change the url accordingly
*
* @param account the target account or null
* @returns url to be used for the target account (or undefined if)
*/
export function useAccountUrl(
account: (Partial<Pick<Account, 'id'>> & Pick<Account, 'url'>) | null
): string | undefined {
if (!account?.id) {
return account?.url
}
const isLocal = useAccountIsLocal(account?.id)
if (account && isLocal.value) {
const url = new URL(account.url)
return url.pathname
}
return account?.url
}
function useAccountIsLocal(accountId: string | undefined) {
const domain = useDomain()
const isLocal = useSignal(false)
useTask$(({ track }) => {
track(() => accountId)
if (accountId) {
const handle = parseHandle(accountId)
isLocal.value = handle.domain === null || handle.domain === domain
}
})
return isLocal
}

Wyświetl plik

@ -1,8 +1,10 @@
import { useLocation } from '@builder.io/qwik-city'
import { adjustLocalHostDomain } from 'wildebeest/backend/src/utils/adjustLocalHostDomain'
export const useDomain = () => {
const location = useLocation()
const url = new URL(location.href)
const domain = url.hostname
return domain
const adjustedDomain = adjustLocalHostDomain(domain)
return adjustedDomain
}

Wyświetl plik

@ -1,26 +1,31 @@
import { test, expect } from '@playwright/test'
test('Navigation to and view of an account (with 1 post)', async ({ page }) => {
await page.goto('http://127.0.0.1:8788/explore')
await page.getByRole('article').getByRole('link', { name: 'Ben, just Ben', exact: true }).click()
await page.getByRole('link', { name: 'Ben, just Ben', exact: true }).click()
await page.waitForLoadState('networkidle')
await page.getByRole('link', { name: 'Ben, just Ben', exact: true }).click()
const navigationsVia = ['name link', 'avatar'] as const
await expect(page.getByTestId('account-info').getByRole('img', { name: 'Header of Ben, just Ben' })).toBeVisible()
await expect(page.getByTestId('account-info').getByRole('img', { name: 'Avatar of Ben, just Ben' })).toBeVisible()
await expect(page.getByTestId('account-info').getByRole('heading', { name: 'Ben, just Ben' })).toBeVisible()
await expect(page.getByTestId('account-info').getByText('Joined')).toBeVisible()
await expect(page.getByTestId('account-info').getByTestId('stats')).toHaveText('1Posts0Following0Followers')
navigationsVia.forEach((via) =>
test(`Navigation via ${via} to and view of an account (with 1 post)`, async ({ page }) => {
await page.goto('http://127.0.0.1:8788/explore')
await page.getByRole('article').getByRole('link', { name: 'Ben, just Ben', exact: true }).click()
await page.getByRole('link', { name: 'Ben, just Ben', exact: true }).click()
await page.waitForLoadState('networkidle')
const linkOption =
via === 'name link' ? { name: 'Ben, just Ben', exact: true } : { name: 'Avatar of Ben, just Ben' }
await page.getByRole('link', linkOption).click()
await expect(page.getByTestId('account-info').getByRole('img', { name: 'Header of Ben, just Ben' })).toBeVisible()
await expect(page.getByTestId('account-info').getByRole('img', { name: 'Avatar of Ben, just Ben' })).toBeVisible()
await expect(page.getByTestId('account-info').getByRole('heading', { name: 'Ben, just Ben' })).toBeVisible()
await expect(page.getByTestId('account-info').getByText('Joined')).toBeVisible()
await expect(page.getByTestId('account-info').getByTestId('stats')).toHaveText('1Posts0Following0Followers')
expect(await page.getByTestId('account-statuses').getByRole('article').count()).toBe(1)
await expect(
page.getByTestId('account-statuses').getByRole('article').getByRole('img', { name: 'Avatar of Ben, just Ben' })
).toBeVisible()
await expect(page.getByTestId('account-statuses').getByRole('article')).toContainText(
'A very simple update: all good!'
)
})
expect(await page.getByTestId('account-statuses').getByRole('article').count()).toBe(1)
await expect(
page.getByTestId('account-statuses').getByRole('article').getByRole('img', { name: 'Avatar of Ben, just Ben' })
).toBeVisible()
await expect(page.getByTestId('account-statuses').getByRole('article')).toContainText(
'A very simple update: all good!'
)
})
)
test('Navigation to and view of an account (with 2 posts)', async ({ page }) => {
await page.goto('http://127.0.0.1:8788/explore')