mirror of https://github.com/pixelfed/pixelfed
commit
1b16e5d696
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\{Profile, Status, User};
|
||||
use Cache;
|
||||
|
||||
class InstanceApiController extends Controller {
|
||||
|
||||
protected function getData()
|
||||
{
|
||||
$contact = Cache::remember('api:v1:instance:contact', 1440, function() {
|
||||
$admin = User::whereIsAdmin(true)->first()->profile;
|
||||
return [
|
||||
'id' => $admin->id,
|
||||
'username' => $admin->username,
|
||||
'acct' => $admin->username,
|
||||
'display_name' => e($admin->name),
|
||||
'locked' => (bool) $admin->is_private,
|
||||
'bot' => false,
|
||||
'created_at' => $admin->created_at->format('c'),
|
||||
'note' => e($admin->bio),
|
||||
'url' => $admin->url(),
|
||||
'avatar' => $admin->avatarUrl(),
|
||||
'avatar_static' => $admin->avatarUrl(),
|
||||
'header' => null,
|
||||
'header_static' => null,
|
||||
'moved' => null,
|
||||
'fields' => null,
|
||||
'bot' => null,
|
||||
];
|
||||
});
|
||||
|
||||
$res = [
|
||||
'uri' => config('pixelfed.domain.app'),
|
||||
'title' => config('app.name'),
|
||||
'description' => '',
|
||||
'version' => config('pixelfed.version'),
|
||||
'urls' => [],
|
||||
'stats' => [
|
||||
'user_count' => User::count(),
|
||||
'status_count' => Status::whereNull('uri')->count(),
|
||||
'domain_count' => Profile::whereNotNull('domain')
|
||||
->groupBy('domain')
|
||||
->pluck('domain')
|
||||
->count()
|
||||
],
|
||||
'thumbnail' => '',
|
||||
'languages' => [],
|
||||
'contact_account' => $contact
|
||||
];
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function instance()
|
||||
{
|
||||
$res = Cache::remember('api:v1:instance', 60, function() {
|
||||
return json_encode($this->getData());
|
||||
});
|
||||
|
||||
return response($res)->header('Content-Type', 'application/json');
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs\FollowPipeline;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
use Cache, Log, Redis;
|
||||
use League\Fractal;
|
||||
use League\Fractal\Serializer\ArraySerializer;
|
||||
use App\FollowRequest;
|
||||
use App\Util\ActivityPub\Helpers;
|
||||
use App\Transformer\ActivityPub\Verb\Follow;
|
||||
|
||||
class FollowActivityPubDeliver implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
protected $followRequest;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(FollowRequest $followRequest)
|
||||
{
|
||||
$this->followRequest = $followRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$follow = $this->followRequest;
|
||||
$actor = $follow->actor;
|
||||
$target = $follow->target;
|
||||
|
||||
if($target->domain == null || $target->inbox_url == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fractal = new Fractal\Manager();
|
||||
$fractal->setSerializer(new ArraySerializer());
|
||||
$resource = new Fractal\Resource\Item($follow, new Follow());
|
||||
$activity = $fractal->createData($resource)->toArray();
|
||||
$url = $target->sharedInbox ?? $target->inbox_url;
|
||||
|
||||
Helpers::sendSignedObject($actor, $url, $activity);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Transformer\Api;
|
||||
|
||||
use League\Fractal;
|
||||
|
||||
class AttachmentTransformer extends Fractal\TransformerAbstract
|
||||
{
|
||||
public function transform(Media $media)
|
||||
{
|
||||
return [
|
||||
'id' => $media->id,
|
||||
'type' => $media->activityVerb(),
|
||||
'url' => $media->url(),
|
||||
'remote_url' => null,
|
||||
'preview_url' => $media->thumbnailUrl(),
|
||||
'text_url' => null,
|
||||
'meta' => null,
|
||||
'description' => $media->caption,
|
||||
'license' => $media->license,
|
||||
'is_nsfw' => $media->is_nsfw,
|
||||
'orientation' => $media->orientation,
|
||||
'filter_name' => $media->filter_name,
|
||||
'filter_class' => $media->filter_class,
|
||||
'mime' => $media->mime,
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Transformer\Api;
|
||||
|
||||
use League\Fractal;
|
||||
|
||||
class ContextTransformer extends Fractal\TransformerAbstract
|
||||
{
|
||||
public function transform()
|
||||
{
|
||||
return [
|
||||
'ancestors' => [],
|
||||
'descendants' => []
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Transformer\Api;
|
||||
|
||||
use League\Fractal;
|
||||
|
||||
class FilterTransformer extends Fractal\TransformerAbstract
|
||||
{
|
||||
public function transform()
|
||||
{
|
||||
return [
|
||||
'id' => (string) '',
|
||||
'phrase' => (string) '',
|
||||
'context' => [],
|
||||
'expires_at' => null,
|
||||
'irreversible' => (bool) false,
|
||||
'whole_word' => (bool) false
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Transformer\Api;
|
||||
|
||||
use League\Fractal;
|
||||
|
||||
class ResultsTransformer extends Fractal\TransformerAbstract
|
||||
{
|
||||
|
||||
protected $defaultIncludes = [
|
||||
'account',
|
||||
'mentions',
|
||||
'media_attachments',
|
||||
'tags',
|
||||
];
|
||||
public function transform()
|
||||
{
|
||||
return [
|
||||
'accounts' => [],
|
||||
'statuses' => [],
|
||||
'hashtags' => []
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Util\ActivityPub\Validator;
|
||||
|
||||
use Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class Announce {
|
||||
|
||||
public static function validate($payload)
|
||||
{
|
||||
$valid = Validator::make($payload, [
|
||||
'@context' => 'required',
|
||||
'id' => 'required|string',
|
||||
'type' => [
|
||||
'required',
|
||||
Rule::in(['Announce'])
|
||||
],
|
||||
'actor' => 'required|url|active_url',
|
||||
'published' => 'required|date',
|
||||
'to' => 'required',
|
||||
'cc' => 'required',
|
||||
'object' => 'required|url|active_url'
|
||||
])->passes();
|
||||
|
||||
return $valid;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class UpdateProfilesTableUseTextForBio extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('profiles', function (Blueprint $table) {
|
||||
$table->text('bio')->nullable()->change();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('profiles', function (Blueprint $table) {
|
||||
$table->string('bio')->nullable()->change();
|
||||
});
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\ActivityPub\Verb;
|
||||
|
||||
use Tests\TestCase;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use App\Util\ActivityPub\Validator\Announce;
|
||||
|
||||
class AnnounceTest extends TestCase
|
||||
{
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->validAnnounce = [
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"id" => "https://example.org/users/alice/statuses/100000000000001/activity",
|
||||
"type" => "Announce",
|
||||
"actor" => "https://example.org/users/alice",
|
||||
"published" => "2018-12-31T23:59:59Z",
|
||||
"to" => [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc" => [
|
||||
"https://example.org/users/bob",
|
||||
"https://example.org/users/alice/followers"
|
||||
],
|
||||
"object" => "https://example.org/p/bob/100000000000000",
|
||||
];
|
||||
|
||||
$this->invalidAnnounce = [
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"id" => "https://example.org/users/alice/statuses/100000000000001/activity",
|
||||
"type" => "Announce2",
|
||||
"actor" => "https://example.org/users/alice",
|
||||
"published" => "2018-12-31T23:59:59Z",
|
||||
"to" => [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc" => [
|
||||
"https://example.org/users/bob",
|
||||
"https://example.org/users/alice/followers"
|
||||
],
|
||||
"object" => "https://example.org/p/bob/100000000000000",
|
||||
];
|
||||
|
||||
$this->invalidDate = [
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"id" => "https://example.org/users/alice/statuses/100000000000001/activity",
|
||||
"type" => "Announce",
|
||||
"actor" => "https://example.org/users/alice",
|
||||
"published" => "2018-12-31T23:59:59ZEZE",
|
||||
"to" => [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc" => [
|
||||
"https://example.org/users/bob",
|
||||
"https://example.org/users/alice/followers"
|
||||
],
|
||||
"object" => "https://example.org/p/bob/100000000000000",
|
||||
];
|
||||
|
||||
$this->contextMissing = [
|
||||
"id" => "https://example.org/users/alice/statuses/100000000000001/activity",
|
||||
"type" => "Announce",
|
||||
"actor" => "https://example.org/users/alice",
|
||||
"published" => "2018-12-31T23:59:59Z",
|
||||
"to" => [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc" => [
|
||||
"https://example.org/users/bob",
|
||||
"https://example.org/users/alice/followers"
|
||||
],
|
||||
"object" => "https://example.org/p/bob/100000000000000",
|
||||
];
|
||||
|
||||
$this->audienceMissing = [
|
||||
"id" => "https://example.org/users/alice/statuses/100000000000001/activity",
|
||||
"type" => "Announce",
|
||||
"actor" => "https://example.org/users/alice",
|
||||
"published" => "2018-12-31T23:59:59Z",
|
||||
"object" => "https://example.org/p/bob/100000000000000",
|
||||
];
|
||||
|
||||
$this->audienceMissing2 = [
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"id" => "https://example.org/users/alice/statuses/100000000000001/activity",
|
||||
"type" => "Announce",
|
||||
"actor" => "https://example.org/users/alice",
|
||||
"published" => "2018-12-31T23:59:59Z",
|
||||
"to" => null,
|
||||
"cc" => null,
|
||||
"object" => "https://example.org/p/bob/100000000000000",
|
||||
];
|
||||
|
||||
$this->invalidActor = [
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"id" => "https://example.org/users/alice/statuses/100000000000001/activity",
|
||||
"type" => "Announce",
|
||||
"actor" => "10000",
|
||||
"published" => "2018-12-31T23:59:59Z",
|
||||
"to" => [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc" => [
|
||||
"https://example.org/users/bob",
|
||||
"https://example.org/users/alice/followers"
|
||||
],
|
||||
"object" => "https://example.org/p/bob/100000000000000",
|
||||
];
|
||||
|
||||
$this->invalidActor2 = [
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"id" => "https://example.org/users/alice/statuses/100000000000001/activity",
|
||||
"type" => "Announce",
|
||||
"published" => "2018-12-31T23:59:59Z",
|
||||
"to" => [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc" => [
|
||||
"https://example.org/users/bob",
|
||||
"https://example.org/users/alice/followers"
|
||||
],
|
||||
"object" => "https://example.org/p/bob/100000000000000",
|
||||
];
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function basic_accept()
|
||||
{
|
||||
$this->assertTrue(Announce::validate($this->validAnnounce));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function invalid_accept()
|
||||
{
|
||||
$this->assertFalse(Announce::validate($this->invalidAnnounce));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function invalid_date()
|
||||
{
|
||||
$this->assertFalse(Announce::validate($this->invalidDate));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function context_missing()
|
||||
{
|
||||
$this->assertFalse(Announce::validate($this->contextMissing));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function audience_missing()
|
||||
{
|
||||
$this->assertFalse(Announce::validate($this->audienceMissing));
|
||||
$this->assertFalse(Announce::validate($this->audienceMissing2));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function invalid_actor()
|
||||
{
|
||||
$this->assertFalse(Announce::validate($this->invalidActor));
|
||||
$this->assertFalse(Announce::validate($this->invalidActor2));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue