You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pixelfed/tests/Feature/DirectMessage/helpers.php

144 lines
5.0 KiB
PHTML

<?php
use App\Models\Follower;
use App\Models\Profile;
use App\Models\User;
use App\Models\UserSetting;
use App\Util\ActivityPub\Inbox;
use Illuminate\Support\Facades\Cache;
2 days ago
use Illuminate\Support\Facades\DB;
if (! function_exists('dmLocalUser')) {
/**
* A local user. By default they take messages from everyone, so a test
* about requests has to ask for that explicitly.
*/
function dmLocalUser(bool $publicDm = true, array $attributes = []): User
{
$user = User::factory()->create(array_merge(['created_at' => now()->subYear()], $attributes));
$user->refresh();
UserSetting::updateOrCreate(['user_id' => $user->id], ['public_dm' => $publicDm]);
return $user;
}
function dmProfile(User $user): Profile
{
return Profile::findOrFail($user->profile_id);
}
function dmRemoteProfile(string $username = 'alice', string $domain = 'remote.example'): Profile
{
$actor = "https://{$domain}/users/{$username}";
return Profile::factory()->remote()->create([
'domain' => $domain,
'username' => "@{$username}@{$domain}",
'remote_url' => $actor,
'key_id' => "{$actor}#main-key",
'inbox_url' => "{$actor}/inbox",
'sharedInbox' => "https://{$domain}/inbox",
'last_fetched_at' => now(),
]);
}
/**
* Seed the DNS and banned-domain caches so URL validation passes without
* a network lookup. Call after factories, the lazy refresh can flush the
* cache.
*/
function dmSeedHosts(array $hosts = ['remote.example', 'other.example']): void
{
$hosts[] = config('pixelfed.domain.app');
foreach ($hosts as $host) {
Cache::put('helpers:url:public-ips:'.hash('xxh128', $host), ['203.0.113.40'], 3600);
}
Cache::put('instances:banned:domains', [], 1209600);
}
/**
* Give $b the id right after $a, the way two profiles created in the same
* millisecond end up. Ids that close are equal once compared as floats,
* so anything that orders or matches ids has to cope with it.
*/
function dmNeighbour(Profile $a, Profile $b): Profile
{
DB::table('profiles')->where('id', $b->id)->update(['id' => $a->id + 1]);
return Profile::findOrFail($a->id + 1);
}
function dmFollow(Profile $follower, Profile $target): void
{
Follower::create([
'profile_id' => $follower->id,
'following_id' => $target->id,
'local_profile' => $follower->domain === null,
'local_following' => $target->domain === null,
]);
}
/**
* A direct Note the way Mastodon sends one: addressed to people only,
* a Mention for each of them, and the thread identifiers.
*
* @param array<int, Profile> $recipients
*/
function dmNote(Profile $author, string $path, array $recipients, array $overrides = []): array
{
$id = $author->remote_url.'/statuses/'.$path;
$to = array_map(fn (Profile $profile) => $profile->permalink(), $recipients);
$mentions = implode(' ', array_map(
fn (Profile $profile) => '<span class="h-card"><a href="'.$profile->permalink().'" class="u-url mention">@<span>'.ltrim(explode('@', ltrim($profile->username, '@'))[0], '@').'</span></a></span>',
$recipients
));
return array_merge([
'id' => $id,
'type' => 'Note',
'attributedTo' => $author->remote_url,
'url' => "https://{$author->domain}/@user/{$path}",
'content' => "<p>{$mentions} hello there</p>",
'published' => now()->subMinute()->toAtomString(),
'inReplyTo' => null,
'to' => $to,
'cc' => [],
'sensitive' => false,
'conversation' => "tag:{$author->domain},2026-09-21:objectId=1:objectType=Conversation",
'context' => "https://{$author->domain}/contexts/1",
'attachment' => [],
'tag' => array_map(fn (Profile $profile) => [
'type' => 'Mention',
'href' => $profile->permalink(),
'name' => '@'.ltrim($profile->username, '@'),
], $recipients),
], $overrides);
}
function dmDeliver(Profile $actor, array $object, string $type = 'Create'): void
{
$payload = [
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => $object['id'].'/activity',
'type' => $type,
'actor' => $actor->remote_url,
'object' => $object,
];
if ($type === 'Create') {
$payload['to'] = $object['to'] ?? [];
$payload['cc'] = $object['cc'] ?? [];
}
$headers = [
'signature' => ['keyId="'.$actor->key_id.'",algorithm="rsa-sha256",headers="(request-target) host date digest",signature="dGVzdA=="'],
'date' => [now()->toRfc7231String()],
];
(new Inbox($headers, null, $payload))->handle();
}
}