mirror of
https://github.com/pixelfed/pixelfed.git
synced 2024-11-09 16:24:51 +00:00
Update activitpub setting, use config_cache()
This commit is contained in:
parent
40478f258a
commit
5071aaf408
10 changed files with 833 additions and 839 deletions
|
@ -2,57 +2,42 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Jobs\InboxPipeline\{
|
use App\Jobs\InboxPipeline\DeleteWorker;
|
||||||
DeleteWorker,
|
use App\Jobs\InboxPipeline\InboxValidator;
|
||||||
InboxWorker,
|
use App\Jobs\InboxPipeline\InboxWorker;
|
||||||
InboxValidator
|
use App\Profile;
|
||||||
};
|
|
||||||
use App\Jobs\RemoteFollowPipeline\RemoteFollowPipeline;
|
|
||||||
use App\{
|
|
||||||
AccountLog,
|
|
||||||
Like,
|
|
||||||
Profile,
|
|
||||||
Status,
|
|
||||||
User
|
|
||||||
};
|
|
||||||
use App\Util\Lexer\Nickname;
|
|
||||||
use App\Util\Webfinger\Webfinger;
|
|
||||||
use Auth;
|
|
||||||
use Cache;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use League\Fractal;
|
|
||||||
use App\Util\Site\Nodeinfo;
|
|
||||||
use App\Util\ActivityPub\{
|
|
||||||
Helpers,
|
|
||||||
HttpSignature,
|
|
||||||
Outbox
|
|
||||||
};
|
|
||||||
use Zttp\Zttp;
|
|
||||||
use App\Services\InstanceService;
|
|
||||||
use App\Services\AccountService;
|
use App\Services\AccountService;
|
||||||
|
use App\Services\InstanceService;
|
||||||
|
use App\Status;
|
||||||
|
use App\Util\Lexer\Nickname;
|
||||||
|
use App\Util\Site\Nodeinfo;
|
||||||
|
use App\Util\Webfinger\Webfinger;
|
||||||
|
use Cache;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class FederationController extends Controller
|
class FederationController extends Controller
|
||||||
{
|
{
|
||||||
public function nodeinfoWellKnown()
|
public function nodeinfoWellKnown()
|
||||||
{
|
{
|
||||||
abort_if(!config('federation.nodeinfo.enabled'), 404);
|
abort_if(! config('federation.nodeinfo.enabled'), 404);
|
||||||
|
|
||||||
return response()->json(Nodeinfo::wellKnown(), 200, [], JSON_UNESCAPED_SLASHES)
|
return response()->json(Nodeinfo::wellKnown(), 200, [], JSON_UNESCAPED_SLASHES)
|
||||||
->header('Access-Control-Allow-Origin','*');
|
->header('Access-Control-Allow-Origin', '*');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function nodeinfo()
|
public function nodeinfo()
|
||||||
{
|
{
|
||||||
abort_if(!config('federation.nodeinfo.enabled'), 404);
|
abort_if(! config('federation.nodeinfo.enabled'), 404);
|
||||||
|
|
||||||
return response()->json(Nodeinfo::get(), 200, [], JSON_UNESCAPED_SLASHES)
|
return response()->json(Nodeinfo::get(), 200, [], JSON_UNESCAPED_SLASHES)
|
||||||
->header('Access-Control-Allow-Origin','*');
|
->header('Access-Control-Allow-Origin', '*');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function webfinger(Request $request)
|
public function webfinger(Request $request)
|
||||||
{
|
{
|
||||||
if (!config('federation.webfinger.enabled') ||
|
if (! config('federation.webfinger.enabled') ||
|
||||||
!$request->has('resource') ||
|
! $request->has('resource') ||
|
||||||
!$request->filled('resource')
|
! $request->filled('resource')
|
||||||
) {
|
) {
|
||||||
return response('', 400);
|
return response('', 400);
|
||||||
}
|
}
|
||||||
|
@ -60,55 +45,56 @@ class FederationController extends Controller
|
||||||
$resource = $request->input('resource');
|
$resource = $request->input('resource');
|
||||||
$domain = config('pixelfed.domain.app');
|
$domain = config('pixelfed.domain.app');
|
||||||
|
|
||||||
if(config('federation.activitypub.sharedInbox') &&
|
if (config('federation.activitypub.sharedInbox') &&
|
||||||
$resource == 'acct:' . $domain . '@' . $domain) {
|
$resource == 'acct:'.$domain.'@'.$domain) {
|
||||||
$res = [
|
$res = [
|
||||||
'subject' => 'acct:' . $domain . '@' . $domain,
|
'subject' => 'acct:'.$domain.'@'.$domain,
|
||||||
'aliases' => [
|
'aliases' => [
|
||||||
'https://' . $domain . '/i/actor'
|
'https://'.$domain.'/i/actor',
|
||||||
],
|
],
|
||||||
'links' => [
|
'links' => [
|
||||||
[
|
[
|
||||||
'rel' => 'http://webfinger.net/rel/profile-page',
|
'rel' => 'http://webfinger.net/rel/profile-page',
|
||||||
'type' => 'text/html',
|
'type' => 'text/html',
|
||||||
'href' => 'https://' . $domain . '/site/kb/instance-actor'
|
'href' => 'https://'.$domain.'/site/kb/instance-actor',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'rel' => 'self',
|
'rel' => 'self',
|
||||||
'type' => 'application/activity+json',
|
'type' => 'application/activity+json',
|
||||||
'href' => 'https://' . $domain . '/i/actor'
|
'href' => 'https://'.$domain.'/i/actor',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
return response()->json($res, 200, [], JSON_UNESCAPED_SLASHES);
|
return response()->json($res, 200, [], JSON_UNESCAPED_SLASHES);
|
||||||
}
|
}
|
||||||
$hash = hash('sha256', $resource);
|
$hash = hash('sha256', $resource);
|
||||||
$key = 'federation:webfinger:sha256:' . $hash;
|
$key = 'federation:webfinger:sha256:'.$hash;
|
||||||
if($cached = Cache::get($key)) {
|
if ($cached = Cache::get($key)) {
|
||||||
return response()->json($cached, 200, [], JSON_UNESCAPED_SLASHES);
|
return response()->json($cached, 200, [], JSON_UNESCAPED_SLASHES);
|
||||||
}
|
}
|
||||||
if(strpos($resource, $domain) == false) {
|
if (strpos($resource, $domain) == false) {
|
||||||
return response('', 400);
|
return response('', 400);
|
||||||
}
|
}
|
||||||
$parsed = Nickname::normalizeProfileUrl($resource);
|
$parsed = Nickname::normalizeProfileUrl($resource);
|
||||||
if(empty($parsed) || $parsed['domain'] !== $domain) {
|
if (empty($parsed) || $parsed['domain'] !== $domain) {
|
||||||
return response('', 400);
|
return response('', 400);
|
||||||
}
|
}
|
||||||
$username = $parsed['username'];
|
$username = $parsed['username'];
|
||||||
$profile = Profile::whereNull('domain')->whereUsername($username)->first();
|
$profile = Profile::whereNull('domain')->whereUsername($username)->first();
|
||||||
if(!$profile || $profile->status !== null) {
|
if (! $profile || $profile->status !== null) {
|
||||||
return response('', 400);
|
return response('', 400);
|
||||||
}
|
}
|
||||||
$webfinger = (new Webfinger($profile))->generate();
|
$webfinger = (new Webfinger($profile))->generate();
|
||||||
Cache::put($key, $webfinger, 1209600);
|
Cache::put($key, $webfinger, 1209600);
|
||||||
|
|
||||||
return response()->json($webfinger, 200, [], JSON_UNESCAPED_SLASHES)
|
return response()->json($webfinger, 200, [], JSON_UNESCAPED_SLASHES)
|
||||||
->header('Access-Control-Allow-Origin','*');
|
->header('Access-Control-Allow-Origin', '*');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hostMeta(Request $request)
|
public function hostMeta(Request $request)
|
||||||
{
|
{
|
||||||
abort_if(!config('federation.webfinger.enabled'), 404);
|
abort_if(! config('federation.webfinger.enabled'), 404);
|
||||||
|
|
||||||
$path = route('well-known.webfinger');
|
$path = route('well-known.webfinger');
|
||||||
$xml = '<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Link rel="lrdd" type="application/xrd+xml" template="'.$path.'?resource={uri}"/></XRD>';
|
$xml = '<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Link rel="lrdd" type="application/xrd+xml" template="'.$path.'?resource={uri}"/></XRD>';
|
||||||
|
@ -118,19 +104,19 @@ class FederationController extends Controller
|
||||||
|
|
||||||
public function userOutbox(Request $request, $username)
|
public function userOutbox(Request $request, $username)
|
||||||
{
|
{
|
||||||
abort_if(!config_cache('federation.activitypub.enabled'), 404);
|
abort_if(! (bool) config_cache('federation.activitypub.enabled'), 404);
|
||||||
|
|
||||||
if(!$request->wantsJson()) {
|
if (! $request->wantsJson()) {
|
||||||
return redirect('/' . $username);
|
return redirect('/'.$username);
|
||||||
}
|
}
|
||||||
|
|
||||||
$id = AccountService::usernameToId($username);
|
$id = AccountService::usernameToId($username);
|
||||||
abort_if(!$id, 404);
|
abort_if(! $id, 404);
|
||||||
$account = AccountService::get($id);
|
$account = AccountService::get($id);
|
||||||
abort_if(!$account || !isset($account['statuses_count']), 404);
|
abort_if(! $account || ! isset($account['statuses_count']), 404);
|
||||||
$res = [
|
$res = [
|
||||||
'@context' => 'https://www.w3.org/ns/activitystreams',
|
'@context' => 'https://www.w3.org/ns/activitystreams',
|
||||||
'id' => 'https://' . config('pixelfed.domain.app') . '/users/' . $username . '/outbox',
|
'id' => 'https://'.config('pixelfed.domain.app').'/users/'.$username.'/outbox',
|
||||||
'type' => 'OrderedCollection',
|
'type' => 'OrderedCollection',
|
||||||
'totalItems' => $account['statuses_count'] ?? 0,
|
'totalItems' => $account['statuses_count'] ?? 0,
|
||||||
];
|
];
|
||||||
|
@ -140,135 +126,145 @@ class FederationController extends Controller
|
||||||
|
|
||||||
public function userInbox(Request $request, $username)
|
public function userInbox(Request $request, $username)
|
||||||
{
|
{
|
||||||
abort_if(!config_cache('federation.activitypub.enabled'), 404);
|
abort_if(! (bool) config_cache('federation.activitypub.enabled'), 404);
|
||||||
abort_if(!config('federation.activitypub.inbox'), 404);
|
abort_if(! config('federation.activitypub.inbox'), 404);
|
||||||
|
|
||||||
$headers = $request->headers->all();
|
$headers = $request->headers->all();
|
||||||
$payload = $request->getContent();
|
$payload = $request->getContent();
|
||||||
if(!$payload || empty($payload)) {
|
if (! $payload || empty($payload)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$obj = json_decode($payload, true, 8);
|
$obj = json_decode($payload, true, 8);
|
||||||
if(!isset($obj['id'])) {
|
if (! isset($obj['id'])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$domain = parse_url($obj['id'], PHP_URL_HOST);
|
$domain = parse_url($obj['id'], PHP_URL_HOST);
|
||||||
if(in_array($domain, InstanceService::getBannedDomains())) {
|
if (in_array($domain, InstanceService::getBannedDomains())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($obj['type']) && $obj['type'] === 'Delete') {
|
if (isset($obj['type']) && $obj['type'] === 'Delete') {
|
||||||
if(isset($obj['object']) && isset($obj['object']['type']) && isset($obj['object']['id'])) {
|
if (isset($obj['object']) && isset($obj['object']['type']) && isset($obj['object']['id'])) {
|
||||||
if($obj['object']['type'] === 'Person') {
|
if ($obj['object']['type'] === 'Person') {
|
||||||
if(Profile::whereRemoteUrl($obj['object']['id'])->exists()) {
|
if (Profile::whereRemoteUrl($obj['object']['id'])->exists()) {
|
||||||
dispatch(new DeleteWorker($headers, $payload))->onQueue('inbox');
|
dispatch(new DeleteWorker($headers, $payload))->onQueue('inbox');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($obj['object']['type'] === 'Tombstone') {
|
if ($obj['object']['type'] === 'Tombstone') {
|
||||||
if(Status::whereObjectUrl($obj['object']['id'])->exists()) {
|
if (Status::whereObjectUrl($obj['object']['id'])->exists()) {
|
||||||
dispatch(new DeleteWorker($headers, $payload))->onQueue('delete');
|
dispatch(new DeleteWorker($headers, $payload))->onQueue('delete');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($obj['object']['type'] === 'Story') {
|
if ($obj['object']['type'] === 'Story') {
|
||||||
dispatch(new DeleteWorker($headers, $payload))->onQueue('story');
|
dispatch(new DeleteWorker($headers, $payload))->onQueue('story');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else if( isset($obj['type']) && in_array($obj['type'], ['Follow', 'Accept'])) {
|
} elseif (isset($obj['type']) && in_array($obj['type'], ['Follow', 'Accept'])) {
|
||||||
dispatch(new InboxValidator($username, $headers, $payload))->onQueue('follow');
|
dispatch(new InboxValidator($username, $headers, $payload))->onQueue('follow');
|
||||||
} else {
|
} else {
|
||||||
dispatch(new InboxValidator($username, $headers, $payload))->onQueue('high');
|
dispatch(new InboxValidator($username, $headers, $payload))->onQueue('high');
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sharedInbox(Request $request)
|
public function sharedInbox(Request $request)
|
||||||
{
|
{
|
||||||
abort_if(!config_cache('federation.activitypub.enabled'), 404);
|
abort_if(! (bool) config_cache('federation.activitypub.enabled'), 404);
|
||||||
abort_if(!config('federation.activitypub.sharedInbox'), 404);
|
abort_if(! config('federation.activitypub.sharedInbox'), 404);
|
||||||
|
|
||||||
$headers = $request->headers->all();
|
$headers = $request->headers->all();
|
||||||
$payload = $request->getContent();
|
$payload = $request->getContent();
|
||||||
|
|
||||||
if(!$payload || empty($payload)) {
|
if (! $payload || empty($payload)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$obj = json_decode($payload, true, 8);
|
$obj = json_decode($payload, true, 8);
|
||||||
if(!isset($obj['id'])) {
|
if (! isset($obj['id'])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$domain = parse_url($obj['id'], PHP_URL_HOST);
|
$domain = parse_url($obj['id'], PHP_URL_HOST);
|
||||||
if(in_array($domain, InstanceService::getBannedDomains())) {
|
if (in_array($domain, InstanceService::getBannedDomains())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($obj['type']) && $obj['type'] === 'Delete') {
|
if (isset($obj['type']) && $obj['type'] === 'Delete') {
|
||||||
if(isset($obj['object']) && isset($obj['object']['type']) && isset($obj['object']['id'])) {
|
if (isset($obj['object']) && isset($obj['object']['type']) && isset($obj['object']['id'])) {
|
||||||
if($obj['object']['type'] === 'Person') {
|
if ($obj['object']['type'] === 'Person') {
|
||||||
if(Profile::whereRemoteUrl($obj['object']['id'])->exists()) {
|
if (Profile::whereRemoteUrl($obj['object']['id'])->exists()) {
|
||||||
dispatch(new DeleteWorker($headers, $payload))->onQueue('inbox');
|
dispatch(new DeleteWorker($headers, $payload))->onQueue('inbox');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($obj['object']['type'] === 'Tombstone') {
|
if ($obj['object']['type'] === 'Tombstone') {
|
||||||
if(Status::whereObjectUrl($obj['object']['id'])->exists()) {
|
if (Status::whereObjectUrl($obj['object']['id'])->exists()) {
|
||||||
dispatch(new DeleteWorker($headers, $payload))->onQueue('delete');
|
dispatch(new DeleteWorker($headers, $payload))->onQueue('delete');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($obj['object']['type'] === 'Story') {
|
if ($obj['object']['type'] === 'Story') {
|
||||||
dispatch(new DeleteWorker($headers, $payload))->onQueue('story');
|
dispatch(new DeleteWorker($headers, $payload))->onQueue('story');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else if( isset($obj['type']) && in_array($obj['type'], ['Follow', 'Accept'])) {
|
} elseif (isset($obj['type']) && in_array($obj['type'], ['Follow', 'Accept'])) {
|
||||||
dispatch(new InboxWorker($headers, $payload))->onQueue('follow');
|
dispatch(new InboxWorker($headers, $payload))->onQueue('follow');
|
||||||
} else {
|
} else {
|
||||||
dispatch(new InboxWorker($headers, $payload))->onQueue('shared');
|
dispatch(new InboxWorker($headers, $payload))->onQueue('shared');
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function userFollowing(Request $request, $username)
|
public function userFollowing(Request $request, $username)
|
||||||
{
|
{
|
||||||
abort_if(!config_cache('federation.activitypub.enabled'), 404);
|
abort_if(! (bool) config_cache('federation.activitypub.enabled'), 404);
|
||||||
|
|
||||||
$id = AccountService::usernameToId($username);
|
$id = AccountService::usernameToId($username);
|
||||||
abort_if(!$id, 404);
|
abort_if(! $id, 404);
|
||||||
$account = AccountService::get($id);
|
$account = AccountService::get($id);
|
||||||
abort_if(!$account || !isset($account['following_count']), 404);
|
abort_if(! $account || ! isset($account['following_count']), 404);
|
||||||
$obj = [
|
$obj = [
|
||||||
'@context' => 'https://www.w3.org/ns/activitystreams',
|
'@context' => 'https://www.w3.org/ns/activitystreams',
|
||||||
'id' => $request->getUri(),
|
'id' => $request->getUri(),
|
||||||
'type' => 'OrderedCollection',
|
'type' => 'OrderedCollection',
|
||||||
'totalItems' => $account['following_count'] ?? 0,
|
'totalItems' => $account['following_count'] ?? 0,
|
||||||
];
|
];
|
||||||
|
|
||||||
return response()->json($obj)->header('Content-Type', 'application/activity+json');
|
return response()->json($obj)->header('Content-Type', 'application/activity+json');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function userFollowers(Request $request, $username)
|
public function userFollowers(Request $request, $username)
|
||||||
{
|
{
|
||||||
abort_if(!config_cache('federation.activitypub.enabled'), 404);
|
abort_if(! (bool) config_cache('federation.activitypub.enabled'), 404);
|
||||||
$id = AccountService::usernameToId($username);
|
$id = AccountService::usernameToId($username);
|
||||||
abort_if(!$id, 404);
|
abort_if(! $id, 404);
|
||||||
$account = AccountService::get($id);
|
$account = AccountService::get($id);
|
||||||
abort_if(!$account || !isset($account['followers_count']), 404);
|
abort_if(! $account || ! isset($account['followers_count']), 404);
|
||||||
$obj = [
|
$obj = [
|
||||||
'@context' => 'https://www.w3.org/ns/activitystreams',
|
'@context' => 'https://www.w3.org/ns/activitystreams',
|
||||||
'id' => $request->getUri(),
|
'id' => $request->getUri(),
|
||||||
'type' => 'OrderedCollection',
|
'type' => 'OrderedCollection',
|
||||||
'totalItems' => $account['followers_count'] ?? 0,
|
'totalItems' => $account['followers_count'] ?? 0,
|
||||||
];
|
];
|
||||||
|
|
||||||
return response()->json($obj)->header('Content-Type', 'application/activity+json');
|
return response()->json($obj)->header('Content-Type', 'application/activity+json');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,368 +2,367 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Auth;
|
|
||||||
use App\Hashtag;
|
use App\Hashtag;
|
||||||
use App\Place;
|
use App\Place;
|
||||||
use App\Profile;
|
use App\Profile;
|
||||||
|
use App\Services\WebfingerService;
|
||||||
use App\Status;
|
use App\Status;
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Util\ActivityPub\Helpers;
|
use App\Util\ActivityPub\Helpers;
|
||||||
|
use Auth;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use App\Transformer\Api\{
|
|
||||||
AccountTransformer,
|
|
||||||
HashtagTransformer,
|
|
||||||
StatusTransformer,
|
|
||||||
};
|
|
||||||
use App\Services\WebfingerService;
|
|
||||||
|
|
||||||
class SearchController extends Controller
|
class SearchController extends Controller
|
||||||
{
|
{
|
||||||
public $tokens = [];
|
public $tokens = [];
|
||||||
public $term = '';
|
|
||||||
public $hash = '';
|
|
||||||
public $cacheKey = 'api:search:tag:';
|
|
||||||
|
|
||||||
public function __construct()
|
public $term = '';
|
||||||
{
|
|
||||||
$this->middleware('auth');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function searchAPI(Request $request)
|
public $hash = '';
|
||||||
{
|
|
||||||
$this->validate($request, [
|
|
||||||
'q' => 'required|string|min:3|max:120',
|
|
||||||
'src' => 'required|string|in:metro',
|
|
||||||
'v' => 'required|integer|in:2',
|
|
||||||
'scope' => 'required|in:all,hashtag,profile,remote,webfinger'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$scope = $request->input('scope') ?? 'all';
|
public $cacheKey = 'api:search:tag:';
|
||||||
$this->term = e(urldecode($request->input('q')));
|
|
||||||
$this->hash = hash('sha256', $this->term);
|
|
||||||
|
|
||||||
switch ($scope) {
|
public function __construct()
|
||||||
case 'all':
|
{
|
||||||
$this->getHashtags();
|
$this->middleware('auth');
|
||||||
$this->getPosts();
|
}
|
||||||
$this->getProfiles();
|
|
||||||
// $this->getPlaces();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'hashtag':
|
public function searchAPI(Request $request)
|
||||||
$this->getHashtags();
|
{
|
||||||
break;
|
$this->validate($request, [
|
||||||
|
'q' => 'required|string|min:3|max:120',
|
||||||
|
'src' => 'required|string|in:metro',
|
||||||
|
'v' => 'required|integer|in:2',
|
||||||
|
'scope' => 'required|in:all,hashtag,profile,remote,webfinger',
|
||||||
|
]);
|
||||||
|
|
||||||
case 'profile':
|
$scope = $request->input('scope') ?? 'all';
|
||||||
$this->getProfiles();
|
$this->term = e(urldecode($request->input('q')));
|
||||||
break;
|
$this->hash = hash('sha256', $this->term);
|
||||||
|
|
||||||
case 'webfinger':
|
switch ($scope) {
|
||||||
$this->webfingerSearch();
|
case 'all':
|
||||||
break;
|
$this->getHashtags();
|
||||||
|
$this->getPosts();
|
||||||
|
$this->getProfiles();
|
||||||
|
// $this->getPlaces();
|
||||||
|
break;
|
||||||
|
|
||||||
case 'remote':
|
case 'hashtag':
|
||||||
$this->remoteLookupSearch();
|
$this->getHashtags();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'place':
|
case 'profile':
|
||||||
$this->getPlaces();
|
$this->getProfiles();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
case 'webfinger':
|
||||||
break;
|
$this->webfingerSearch();
|
||||||
}
|
break;
|
||||||
|
|
||||||
return response()->json($this->tokens, 200, [], JSON_PRETTY_PRINT);
|
case 'remote':
|
||||||
}
|
$this->remoteLookupSearch();
|
||||||
|
break;
|
||||||
|
|
||||||
protected function getPosts()
|
case 'place':
|
||||||
{
|
$this->getPlaces();
|
||||||
$tag = $this->term;
|
break;
|
||||||
$hash = hash('sha256', $tag);
|
|
||||||
if( Helpers::validateUrl($tag) != false &&
|
|
||||||
Helpers::validateLocalUrl($tag) != true &&
|
|
||||||
config_cache('federation.activitypub.enabled') == true &&
|
|
||||||
config('federation.activitypub.remoteFollow') == true
|
|
||||||
) {
|
|
||||||
$remote = Helpers::fetchFromUrl($tag);
|
|
||||||
if( isset($remote['type']) &&
|
|
||||||
$remote['type'] == 'Note') {
|
|
||||||
$item = Helpers::statusFetch($tag);
|
|
||||||
$this->tokens['posts'] = [[
|
|
||||||
'count' => 0,
|
|
||||||
'url' => $item->url(),
|
|
||||||
'type' => 'status',
|
|
||||||
'value' => "by {$item->profile->username} <span class='float-right'>{$item->created_at->diffForHumans(null, true, true)}</span>",
|
|
||||||
'tokens' => [$item->caption],
|
|
||||||
'name' => $item->caption,
|
|
||||||
'thumb' => $item->thumb(),
|
|
||||||
]];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$posts = Status::select('id', 'profile_id', 'caption', 'created_at')
|
|
||||||
->whereHas('media')
|
|
||||||
->whereNull('in_reply_to_id')
|
|
||||||
->whereNull('reblog_of_id')
|
|
||||||
->whereProfileId(Auth::user()->profile_id)
|
|
||||||
->where('caption', 'like', '%'.$tag.'%')
|
|
||||||
->latest()
|
|
||||||
->limit(10)
|
|
||||||
->get();
|
|
||||||
|
|
||||||
if($posts->count() > 0) {
|
default:
|
||||||
$posts = $posts->map(function($item, $key) {
|
break;
|
||||||
return [
|
}
|
||||||
'count' => 0,
|
|
||||||
'url' => $item->url(),
|
|
||||||
'type' => 'status',
|
|
||||||
'value' => "by {$item->profile->username} <span class='float-right'>{$item->created_at->diffForHumans(null, true, true)}</span>",
|
|
||||||
'tokens' => [$item->caption],
|
|
||||||
'name' => $item->caption,
|
|
||||||
'thumb' => $item->thumb(),
|
|
||||||
'filter' => $item->firstMedia()->filter_class
|
|
||||||
];
|
|
||||||
});
|
|
||||||
$this->tokens['posts'] = $posts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getHashtags()
|
return response()->json($this->tokens, 200, [], JSON_PRETTY_PRINT);
|
||||||
{
|
}
|
||||||
$tag = $this->term;
|
|
||||||
$key = $this->cacheKey . 'hashtags:' . $this->hash;
|
|
||||||
$ttl = now()->addMinutes(1);
|
|
||||||
$tokens = Cache::remember($key, $ttl, function() use($tag) {
|
|
||||||
$htag = Str::startsWith($tag, '#') == true ? mb_substr($tag, 1) : $tag;
|
|
||||||
$hashtags = Hashtag::select('id', 'name', 'slug')
|
|
||||||
->where('slug', 'like', '%'.$htag.'%')
|
|
||||||
->whereHas('posts')
|
|
||||||
->limit(20)
|
|
||||||
->get();
|
|
||||||
if($hashtags->count() > 0) {
|
|
||||||
$tags = $hashtags->map(function ($item, $key) {
|
|
||||||
return [
|
|
||||||
'count' => $item->posts()->count(),
|
|
||||||
'url' => $item->url(),
|
|
||||||
'type' => 'hashtag',
|
|
||||||
'value' => $item->name,
|
|
||||||
'tokens' => '',
|
|
||||||
'name' => null,
|
|
||||||
];
|
|
||||||
});
|
|
||||||
return $tags;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$this->tokens['hashtags'] = $tokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getPlaces()
|
protected function getPosts()
|
||||||
{
|
{
|
||||||
$tag = $this->term;
|
$tag = $this->term;
|
||||||
// $key = $this->cacheKey . 'places:' . $this->hash;
|
$hash = hash('sha256', $tag);
|
||||||
// $ttl = now()->addHours(12);
|
if (Helpers::validateUrl($tag) != false &&
|
||||||
// $tokens = Cache::remember($key, $ttl, function() use($tag) {
|
Helpers::validateLocalUrl($tag) != true &&
|
||||||
$htag = Str::contains($tag, ',') == true ? explode(',', $tag) : [$tag];
|
(bool) config_cache('federation.activitypub.enabled') == true &&
|
||||||
$hashtags = Place::select('id', 'name', 'slug', 'country')
|
config('federation.activitypub.remoteFollow') == true
|
||||||
->where('name', 'like', '%'.$htag[0].'%')
|
) {
|
||||||
->paginate(20);
|
$remote = Helpers::fetchFromUrl($tag);
|
||||||
$tags = [];
|
if (isset($remote['type']) &&
|
||||||
if($hashtags->count() > 0) {
|
in_array($remote['type'], ['Note', 'Question'])
|
||||||
$tags = $hashtags->map(function ($item, $key) {
|
) {
|
||||||
return [
|
$item = Helpers::statusFetch($tag);
|
||||||
'count' => null,
|
$this->tokens['posts'] = [[
|
||||||
'url' => $item->url(),
|
'count' => 0,
|
||||||
'type' => 'place',
|
'url' => $item->url(),
|
||||||
'value' => $item->name . ', ' . $item->country,
|
'type' => 'status',
|
||||||
'tokens' => '',
|
'value' => "by {$item->profile->username} <span class='float-right'>{$item->created_at->diffForHumans(null, true, true)}</span>",
|
||||||
'name' => null,
|
'tokens' => [$item->caption],
|
||||||
'city' => $item->name,
|
'name' => $item->caption,
|
||||||
'country' => $item->country
|
'thumb' => $item->thumb(),
|
||||||
];
|
]];
|
||||||
});
|
}
|
||||||
// return $tags;
|
} else {
|
||||||
}
|
$posts = Status::select('id', 'profile_id', 'caption', 'created_at')
|
||||||
// });
|
->whereHas('media')
|
||||||
$this->tokens['places'] = $tags;
|
->whereNull('in_reply_to_id')
|
||||||
$this->tokens['placesPagination'] = [
|
->whereNull('reblog_of_id')
|
||||||
'total' => $hashtags->total(),
|
->whereProfileId(Auth::user()->profile_id)
|
||||||
'current_page' => $hashtags->currentPage(),
|
->where('caption', 'like', '%'.$tag.'%')
|
||||||
'last_page' => $hashtags->lastPage()
|
->latest()
|
||||||
];
|
->limit(10)
|
||||||
}
|
->get();
|
||||||
|
|
||||||
protected function getProfiles()
|
if ($posts->count() > 0) {
|
||||||
{
|
$posts = $posts->map(function ($item, $key) {
|
||||||
$tag = $this->term;
|
return [
|
||||||
$remoteKey = $this->cacheKey . 'profiles:remote:' . $this->hash;
|
'count' => 0,
|
||||||
$key = $this->cacheKey . 'profiles:' . $this->hash;
|
'url' => $item->url(),
|
||||||
$remoteTtl = now()->addMinutes(15);
|
'type' => 'status',
|
||||||
$ttl = now()->addHours(2);
|
'value' => "by {$item->profile->username} <span class='float-right'>{$item->created_at->diffForHumans(null, true, true)}</span>",
|
||||||
if( Helpers::validateUrl($tag) != false &&
|
'tokens' => [$item->caption],
|
||||||
Helpers::validateLocalUrl($tag) != true &&
|
'name' => $item->caption,
|
||||||
config_cache('federation.activitypub.enabled') == true &&
|
'thumb' => $item->thumb(),
|
||||||
config('federation.activitypub.remoteFollow') == true
|
'filter' => $item->firstMedia()->filter_class,
|
||||||
) {
|
];
|
||||||
$remote = Helpers::fetchFromUrl($tag);
|
});
|
||||||
if( isset($remote['type']) &&
|
$this->tokens['posts'] = $posts;
|
||||||
$remote['type'] == 'Person'
|
}
|
||||||
) {
|
}
|
||||||
$this->tokens['profiles'] = Cache::remember($remoteKey, $remoteTtl, function() use($tag) {
|
}
|
||||||
$item = Helpers::profileFirstOrNew($tag);
|
|
||||||
$tokens = [[
|
|
||||||
'count' => 1,
|
|
||||||
'url' => $item->url(),
|
|
||||||
'type' => 'profile',
|
|
||||||
'value' => $item->username,
|
|
||||||
'tokens' => [$item->username],
|
|
||||||
'name' => $item->name,
|
|
||||||
'entity' => [
|
|
||||||
'id' => (string) $item->id,
|
|
||||||
'following' => $item->followedBy(Auth::user()->profile),
|
|
||||||
'follow_request' => $item->hasFollowRequestById(Auth::user()->profile_id),
|
|
||||||
'thumb' => $item->avatarUrl(),
|
|
||||||
'local' => (bool) !$item->domain,
|
|
||||||
'post_count' => $item->statuses()->count()
|
|
||||||
]
|
|
||||||
]];
|
|
||||||
return $tokens;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
protected function getHashtags()
|
||||||
$this->tokens['profiles'] = Cache::remember($key, $ttl, function() use($tag) {
|
{
|
||||||
if(Str::startsWith($tag, '@')) {
|
$tag = $this->term;
|
||||||
$tag = substr($tag, 1);
|
$key = $this->cacheKey.'hashtags:'.$this->hash;
|
||||||
}
|
$ttl = now()->addMinutes(1);
|
||||||
$users = Profile::select('status', 'domain', 'username', 'name', 'id')
|
$tokens = Cache::remember($key, $ttl, function () use ($tag) {
|
||||||
->whereNull('status')
|
$htag = Str::startsWith($tag, '#') == true ? mb_substr($tag, 1) : $tag;
|
||||||
->where('username', 'like', '%'.$tag.'%')
|
$hashtags = Hashtag::select('id', 'name', 'slug')
|
||||||
->limit(20)
|
->where('slug', 'like', '%'.$htag.'%')
|
||||||
->orderBy('domain')
|
->whereHas('posts')
|
||||||
->get();
|
->limit(20)
|
||||||
|
->get();
|
||||||
|
if ($hashtags->count() > 0) {
|
||||||
|
$tags = $hashtags->map(function ($item, $key) {
|
||||||
|
return [
|
||||||
|
'count' => $item->posts()->count(),
|
||||||
|
'url' => $item->url(),
|
||||||
|
'type' => 'hashtag',
|
||||||
|
'value' => $item->name,
|
||||||
|
'tokens' => '',
|
||||||
|
'name' => null,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
if($users->count() > 0) {
|
return $tags;
|
||||||
return $users->map(function ($item, $key) {
|
}
|
||||||
return [
|
});
|
||||||
'count' => 0,
|
$this->tokens['hashtags'] = $tokens;
|
||||||
'url' => $item->url(),
|
}
|
||||||
'type' => 'profile',
|
|
||||||
'value' => $item->username,
|
|
||||||
'tokens' => [$item->username],
|
|
||||||
'name' => $item->name,
|
|
||||||
'avatar' => $item->avatarUrl(),
|
|
||||||
'id' => (string) $item->id,
|
|
||||||
'entity' => [
|
|
||||||
'id' => (string) $item->id,
|
|
||||||
'following' => $item->followedBy(Auth::user()->profile),
|
|
||||||
'follow_request' => $item->hasFollowRequestById(Auth::user()->profile_id),
|
|
||||||
'thumb' => $item->avatarUrl(),
|
|
||||||
'local' => (bool) !$item->domain,
|
|
||||||
'post_count' => $item->statuses()->count()
|
|
||||||
]
|
|
||||||
];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function results(Request $request)
|
protected function getPlaces()
|
||||||
{
|
{
|
||||||
$this->validate($request, [
|
$tag = $this->term;
|
||||||
'q' => 'required|string|min:1',
|
// $key = $this->cacheKey . 'places:' . $this->hash;
|
||||||
]);
|
// $ttl = now()->addHours(12);
|
||||||
|
// $tokens = Cache::remember($key, $ttl, function() use($tag) {
|
||||||
|
$htag = Str::contains($tag, ',') == true ? explode(',', $tag) : [$tag];
|
||||||
|
$hashtags = Place::select('id', 'name', 'slug', 'country')
|
||||||
|
->where('name', 'like', '%'.$htag[0].'%')
|
||||||
|
->paginate(20);
|
||||||
|
$tags = [];
|
||||||
|
if ($hashtags->count() > 0) {
|
||||||
|
$tags = $hashtags->map(function ($item, $key) {
|
||||||
|
return [
|
||||||
|
'count' => null,
|
||||||
|
'url' => $item->url(),
|
||||||
|
'type' => 'place',
|
||||||
|
'value' => $item->name.', '.$item->country,
|
||||||
|
'tokens' => '',
|
||||||
|
'name' => null,
|
||||||
|
'city' => $item->name,
|
||||||
|
'country' => $item->country,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
// return $tags;
|
||||||
|
}
|
||||||
|
// });
|
||||||
|
$this->tokens['places'] = $tags;
|
||||||
|
$this->tokens['placesPagination'] = [
|
||||||
|
'total' => $hashtags->total(),
|
||||||
|
'current_page' => $hashtags->currentPage(),
|
||||||
|
'last_page' => $hashtags->lastPage(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
return view('search.results');
|
protected function getProfiles()
|
||||||
}
|
{
|
||||||
|
$tag = $this->term;
|
||||||
|
$remoteKey = $this->cacheKey.'profiles:remote:'.$this->hash;
|
||||||
|
$key = $this->cacheKey.'profiles:'.$this->hash;
|
||||||
|
$remoteTtl = now()->addMinutes(15);
|
||||||
|
$ttl = now()->addHours(2);
|
||||||
|
if (Helpers::validateUrl($tag) != false &&
|
||||||
|
Helpers::validateLocalUrl($tag) != true &&
|
||||||
|
(bool) config_cache('federation.activitypub.enabled') == true &&
|
||||||
|
config('federation.activitypub.remoteFollow') == true
|
||||||
|
) {
|
||||||
|
$remote = Helpers::fetchFromUrl($tag);
|
||||||
|
if (isset($remote['type']) &&
|
||||||
|
$remote['type'] == 'Person'
|
||||||
|
) {
|
||||||
|
$this->tokens['profiles'] = Cache::remember($remoteKey, $remoteTtl, function () use ($tag) {
|
||||||
|
$item = Helpers::profileFirstOrNew($tag);
|
||||||
|
$tokens = [[
|
||||||
|
'count' => 1,
|
||||||
|
'url' => $item->url(),
|
||||||
|
'type' => 'profile',
|
||||||
|
'value' => $item->username,
|
||||||
|
'tokens' => [$item->username],
|
||||||
|
'name' => $item->name,
|
||||||
|
'entity' => [
|
||||||
|
'id' => (string) $item->id,
|
||||||
|
'following' => $item->followedBy(Auth::user()->profile),
|
||||||
|
'follow_request' => $item->hasFollowRequestById(Auth::user()->profile_id),
|
||||||
|
'thumb' => $item->avatarUrl(),
|
||||||
|
'local' => (bool) ! $item->domain,
|
||||||
|
'post_count' => $item->statuses()->count(),
|
||||||
|
],
|
||||||
|
]];
|
||||||
|
|
||||||
protected function webfingerSearch()
|
return $tokens;
|
||||||
{
|
});
|
||||||
$wfs = WebfingerService::lookup($this->term);
|
}
|
||||||
|
} else {
|
||||||
|
$this->tokens['profiles'] = Cache::remember($key, $ttl, function () use ($tag) {
|
||||||
|
if (Str::startsWith($tag, '@')) {
|
||||||
|
$tag = substr($tag, 1);
|
||||||
|
}
|
||||||
|
$users = Profile::select('status', 'domain', 'username', 'name', 'id')
|
||||||
|
->whereNull('status')
|
||||||
|
->where('username', 'like', '%'.$tag.'%')
|
||||||
|
->limit(20)
|
||||||
|
->orderBy('domain')
|
||||||
|
->get();
|
||||||
|
|
||||||
if(empty($wfs)) {
|
if ($users->count() > 0) {
|
||||||
return;
|
return $users->map(function ($item, $key) {
|
||||||
}
|
return [
|
||||||
|
'count' => 0,
|
||||||
|
'url' => $item->url(),
|
||||||
|
'type' => 'profile',
|
||||||
|
'value' => $item->username,
|
||||||
|
'tokens' => [$item->username],
|
||||||
|
'name' => $item->name,
|
||||||
|
'avatar' => $item->avatarUrl(),
|
||||||
|
'id' => (string) $item->id,
|
||||||
|
'entity' => [
|
||||||
|
'id' => (string) $item->id,
|
||||||
|
'following' => $item->followedBy(Auth::user()->profile),
|
||||||
|
'follow_request' => $item->hasFollowRequestById(Auth::user()->profile_id),
|
||||||
|
'thumb' => $item->avatarUrl(),
|
||||||
|
'local' => (bool) ! $item->domain,
|
||||||
|
'post_count' => $item->statuses()->count(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->tokens['profiles'] = [
|
public function results(Request $request)
|
||||||
[
|
{
|
||||||
'count' => 1,
|
$this->validate($request, [
|
||||||
'url' => $wfs['url'],
|
'q' => 'required|string|min:1',
|
||||||
'type' => 'profile',
|
]);
|
||||||
'value' => $wfs['username'],
|
|
||||||
'tokens' => [$wfs['username']],
|
|
||||||
'name' => $wfs['display_name'],
|
|
||||||
'entity' => [
|
|
||||||
'id' => (string) $wfs['id'],
|
|
||||||
'following' => null,
|
|
||||||
'follow_request' => null,
|
|
||||||
'thumb' => $wfs['avatar'],
|
|
||||||
'local' => (bool) $wfs['local']
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function remotePostLookup()
|
return view('search.results');
|
||||||
{
|
}
|
||||||
$tag = $this->term;
|
|
||||||
$hash = hash('sha256', $tag);
|
|
||||||
$local = Helpers::validateLocalUrl($tag);
|
|
||||||
$valid = Helpers::validateUrl($tag);
|
|
||||||
|
|
||||||
if($valid == false || $local == true) {
|
protected function webfingerSearch()
|
||||||
return;
|
{
|
||||||
}
|
$wfs = WebfingerService::lookup($this->term);
|
||||||
|
|
||||||
if(Status::whereUri($tag)->whereLocal(false)->exists()) {
|
if (empty($wfs)) {
|
||||||
$item = Status::whereUri($tag)->first();
|
return;
|
||||||
$media = $item->firstMedia();
|
}
|
||||||
$url = null;
|
|
||||||
if($media) {
|
|
||||||
$url = $media->remote_url;
|
|
||||||
}
|
|
||||||
$this->tokens['posts'] = [[
|
|
||||||
'count' => 0,
|
|
||||||
'url' => "/i/web/post/_/$item->profile_id/$item->id",
|
|
||||||
'type' => 'status',
|
|
||||||
'username' => $item->profile->username,
|
|
||||||
'caption' => $item->rendered ?? $item->caption,
|
|
||||||
'thumb' => $url,
|
|
||||||
'timestamp' => $item->created_at->diffForHumans()
|
|
||||||
]];
|
|
||||||
}
|
|
||||||
|
|
||||||
$remote = Helpers::fetchFromUrl($tag);
|
$this->tokens['profiles'] = [
|
||||||
|
[
|
||||||
|
'count' => 1,
|
||||||
|
'url' => $wfs['url'],
|
||||||
|
'type' => 'profile',
|
||||||
|
'value' => $wfs['username'],
|
||||||
|
'tokens' => [$wfs['username']],
|
||||||
|
'name' => $wfs['display_name'],
|
||||||
|
'entity' => [
|
||||||
|
'id' => (string) $wfs['id'],
|
||||||
|
'following' => null,
|
||||||
|
'follow_request' => null,
|
||||||
|
'thumb' => $wfs['avatar'],
|
||||||
|
'local' => (bool) $wfs['local'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
if(isset($remote['type']) && $remote['type'] == 'Note') {
|
}
|
||||||
$item = Helpers::statusFetch($tag);
|
|
||||||
$media = $item->firstMedia();
|
|
||||||
$url = null;
|
|
||||||
if($media) {
|
|
||||||
$url = $media->remote_url;
|
|
||||||
}
|
|
||||||
$this->tokens['posts'] = [[
|
|
||||||
'count' => 0,
|
|
||||||
'url' => "/i/web/post/_/$item->profile_id/$item->id",
|
|
||||||
'type' => 'status',
|
|
||||||
'username' => $item->profile->username,
|
|
||||||
'caption' => $item->rendered ?? $item->caption,
|
|
||||||
'thumb' => $url,
|
|
||||||
'timestamp' => $item->created_at->diffForHumans()
|
|
||||||
]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function remoteLookupSearch()
|
protected function remotePostLookup()
|
||||||
{
|
{
|
||||||
if(!Helpers::validateUrl($this->term)) {
|
$tag = $this->term;
|
||||||
return;
|
$hash = hash('sha256', $tag);
|
||||||
}
|
$local = Helpers::validateLocalUrl($tag);
|
||||||
$this->getProfiles();
|
$valid = Helpers::validateUrl($tag);
|
||||||
$this->remotePostLookup();
|
|
||||||
}
|
if ($valid == false || $local == true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Status::whereUri($tag)->whereLocal(false)->exists()) {
|
||||||
|
$item = Status::whereUri($tag)->first();
|
||||||
|
$media = $item->firstMedia();
|
||||||
|
$url = null;
|
||||||
|
if ($media) {
|
||||||
|
$url = $media->remote_url;
|
||||||
|
}
|
||||||
|
$this->tokens['posts'] = [[
|
||||||
|
'count' => 0,
|
||||||
|
'url' => "/i/web/post/_/$item->profile_id/$item->id",
|
||||||
|
'type' => 'status',
|
||||||
|
'username' => $item->profile->username,
|
||||||
|
'caption' => $item->rendered ?? $item->caption,
|
||||||
|
'thumb' => $url,
|
||||||
|
'timestamp' => $item->created_at->diffForHumans(),
|
||||||
|
]];
|
||||||
|
}
|
||||||
|
|
||||||
|
$remote = Helpers::fetchFromUrl($tag);
|
||||||
|
|
||||||
|
if (isset($remote['type']) && $remote['type'] == 'Note') {
|
||||||
|
$item = Helpers::statusFetch($tag);
|
||||||
|
$media = $item->firstMedia();
|
||||||
|
$url = null;
|
||||||
|
if ($media) {
|
||||||
|
$url = $media->remote_url;
|
||||||
|
}
|
||||||
|
$this->tokens['posts'] = [[
|
||||||
|
'count' => 0,
|
||||||
|
'url' => "/i/web/post/_/$item->profile_id/$item->id",
|
||||||
|
'type' => 'status',
|
||||||
|
'username' => $item->profile->username,
|
||||||
|
'caption' => $item->rendered ?? $item->caption,
|
||||||
|
'thumb' => $url,
|
||||||
|
'timestamp' => $item->created_at->diffForHumans(),
|
||||||
|
]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function remoteLookupSearch()
|
||||||
|
{
|
||||||
|
if (! Helpers::validateUrl($this->term)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->getProfiles();
|
||||||
|
$this->remotePostLookup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ class StatusController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->wantsJson() && config_cache('federation.activitypub.enabled')) {
|
if ($request->wantsJson() && (bool) config_cache('federation.activitypub.enabled')) {
|
||||||
return $this->showActivityPub($request, $status);
|
return $this->showActivityPub($request, $status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,15 @@
|
||||||
|
|
||||||
namespace App\Jobs\SharePipeline;
|
namespace App\Jobs\SharePipeline;
|
||||||
|
|
||||||
use Cache, Log;
|
use App\Jobs\HomeFeedPipeline\FeedInsertPipeline;
|
||||||
use Illuminate\Support\Facades\Redis;
|
use App\Notification;
|
||||||
use App\{Status, Notification};
|
use App\Services\ReblogService;
|
||||||
|
use App\Services\StatusService;
|
||||||
|
use App\Status;
|
||||||
|
use App\Transformer\ActivityPub\Verb\Announce;
|
||||||
|
use App\Util\ActivityPub\HttpSignature;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Pool;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
@ -12,141 +18,136 @@ use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use League\Fractal;
|
use League\Fractal;
|
||||||
use League\Fractal\Serializer\ArraySerializer;
|
use League\Fractal\Serializer\ArraySerializer;
|
||||||
use App\Transformer\ActivityPub\Verb\Announce;
|
|
||||||
use GuzzleHttp\{Pool, Client, Promise};
|
|
||||||
use App\Util\ActivityPub\HttpSignature;
|
|
||||||
use App\Services\ReblogService;
|
|
||||||
use App\Services\StatusService;
|
|
||||||
use App\Jobs\HomeFeedPipeline\FeedInsertPipeline;
|
|
||||||
|
|
||||||
class SharePipeline implements ShouldQueue
|
class SharePipeline implements ShouldQueue
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
protected $status;
|
protected $status;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the job if its models no longer exist.
|
* Delete the job if its models no longer exist.
|
||||||
*
|
*
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
public $deleteWhenMissingModels = true;
|
public $deleteWhenMissingModels = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new job instance.
|
* Create a new job instance.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct(Status $status)
|
public function __construct(Status $status)
|
||||||
{
|
{
|
||||||
$this->status = $status;
|
$this->status = $status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the job.
|
* Execute the job.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$status = $this->status;
|
$status = $this->status;
|
||||||
$parent = Status::find($this->status->reblog_of_id);
|
$parent = Status::find($this->status->reblog_of_id);
|
||||||
if(!$parent) {
|
if (! $parent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$actor = $status->profile;
|
$actor = $status->profile;
|
||||||
$target = $parent->profile;
|
$target = $parent->profile;
|
||||||
|
|
||||||
if ($status->uri !== null) {
|
if ($status->uri !== null) {
|
||||||
// Ignore notifications to remote statuses
|
// Ignore notifications to remote statuses
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($target->id === $status->profile_id) {
|
if ($target->id === $status->profile_id) {
|
||||||
$this->remoteAnnounceDeliver();
|
$this->remoteAnnounceDeliver();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReblogService::addPostReblog($parent->profile_id, $status->id);
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
$parent->reblogs_count = $parent->reblogs_count + 1;
|
ReblogService::addPostReblog($parent->profile_id, $status->id);
|
||||||
$parent->save();
|
|
||||||
StatusService::del($parent->id);
|
|
||||||
|
|
||||||
Notification::firstOrCreate(
|
$parent->reblogs_count = $parent->reblogs_count + 1;
|
||||||
[
|
$parent->save();
|
||||||
'profile_id' => $target->id,
|
StatusService::del($parent->id);
|
||||||
'actor_id' => $actor->id,
|
|
||||||
'action' => 'share',
|
|
||||||
'item_type' => 'App\Status',
|
|
||||||
'item_id' => $status->reblog_of_id ?? $status->id,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
FeedInsertPipeline::dispatch($status->id, $status->profile_id)->onQueue('feed');
|
Notification::firstOrCreate(
|
||||||
|
[
|
||||||
|
'profile_id' => $target->id,
|
||||||
|
'actor_id' => $actor->id,
|
||||||
|
'action' => 'share',
|
||||||
|
'item_type' => 'App\Status',
|
||||||
|
'item_id' => $status->reblog_of_id ?? $status->id,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
return $this->remoteAnnounceDeliver();
|
FeedInsertPipeline::dispatch($status->id, $status->profile_id)->onQueue('feed');
|
||||||
}
|
|
||||||
|
|
||||||
public function remoteAnnounceDeliver()
|
return $this->remoteAnnounceDeliver();
|
||||||
{
|
}
|
||||||
if(config('app.env') !== 'production' || config_cache('federation.activitypub.enabled') == false) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
$status = $this->status;
|
|
||||||
$profile = $status->profile;
|
|
||||||
|
|
||||||
$fractal = new Fractal\Manager();
|
public function remoteAnnounceDeliver()
|
||||||
$fractal->setSerializer(new ArraySerializer());
|
{
|
||||||
$resource = new Fractal\Resource\Item($status, new Announce());
|
if (config('app.env') !== 'production' || (bool) config_cache('federation.activitypub.enabled') == false) {
|
||||||
$activity = $fractal->createData($resource)->toArray();
|
return true;
|
||||||
|
}
|
||||||
|
$status = $this->status;
|
||||||
|
$profile = $status->profile;
|
||||||
|
|
||||||
$audience = $status->profile->getAudienceInbox();
|
$fractal = new Fractal\Manager();
|
||||||
|
$fractal->setSerializer(new ArraySerializer());
|
||||||
|
$resource = new Fractal\Resource\Item($status, new Announce());
|
||||||
|
$activity = $fractal->createData($resource)->toArray();
|
||||||
|
|
||||||
if(empty($audience) || $status->scope != 'public') {
|
$audience = $status->profile->getAudienceInbox();
|
||||||
// Return on profiles with no remote followers
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$payload = json_encode($activity);
|
if (empty($audience) || $status->scope != 'public') {
|
||||||
|
// Return on profiles with no remote followers
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$client = new Client([
|
$payload = json_encode($activity);
|
||||||
'timeout' => config('federation.activitypub.delivery.timeout')
|
|
||||||
]);
|
|
||||||
|
|
||||||
$version = config('pixelfed.version');
|
$client = new Client([
|
||||||
$appUrl = config('app.url');
|
'timeout' => config('federation.activitypub.delivery.timeout'),
|
||||||
$userAgent = "(Pixelfed/{$version}; +{$appUrl})";
|
]);
|
||||||
|
|
||||||
$requests = function($audience) use ($client, $activity, $profile, $payload, $userAgent) {
|
$version = config('pixelfed.version');
|
||||||
foreach($audience as $url) {
|
$appUrl = config('app.url');
|
||||||
$headers = HttpSignature::sign($profile, $url, $activity, [
|
$userAgent = "(Pixelfed/{$version}; +{$appUrl})";
|
||||||
'Content-Type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
|
||||||
'User-Agent' => $userAgent,
|
|
||||||
]);
|
|
||||||
yield function() use ($client, $url, $headers, $payload) {
|
|
||||||
return $client->postAsync($url, [
|
|
||||||
'curl' => [
|
|
||||||
CURLOPT_HTTPHEADER => $headers,
|
|
||||||
CURLOPT_POSTFIELDS => $payload,
|
|
||||||
CURLOPT_HEADER => true
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$pool = new Pool($client, $requests($audience), [
|
$requests = function ($audience) use ($client, $activity, $profile, $payload, $userAgent) {
|
||||||
'concurrency' => config('federation.activitypub.delivery.concurrency'),
|
foreach ($audience as $url) {
|
||||||
'fulfilled' => function ($response, $index) {
|
$headers = HttpSignature::sign($profile, $url, $activity, [
|
||||||
},
|
'Content-Type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||||
'rejected' => function ($reason, $index) {
|
'User-Agent' => $userAgent,
|
||||||
}
|
]);
|
||||||
]);
|
yield function () use ($client, $url, $headers, $payload) {
|
||||||
|
return $client->postAsync($url, [
|
||||||
|
'curl' => [
|
||||||
|
CURLOPT_HTTPHEADER => $headers,
|
||||||
|
CURLOPT_POSTFIELDS => $payload,
|
||||||
|
CURLOPT_HEADER => true,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
$promise = $pool->promise();
|
$pool = new Pool($client, $requests($audience), [
|
||||||
|
'concurrency' => config('federation.activitypub.delivery.concurrency'),
|
||||||
|
'fulfilled' => function ($response, $index) {
|
||||||
|
},
|
||||||
|
'rejected' => function ($reason, $index) {
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
$promise->wait();
|
$promise = $pool->promise();
|
||||||
|
|
||||||
}
|
$promise->wait();
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,15 @@
|
||||||
|
|
||||||
namespace App\Jobs\SharePipeline;
|
namespace App\Jobs\SharePipeline;
|
||||||
|
|
||||||
use Cache, Log;
|
use App\Jobs\HomeFeedPipeline\FeedRemovePipeline;
|
||||||
use Illuminate\Support\Facades\Redis;
|
use App\Notification;
|
||||||
use App\{Status, Notification};
|
use App\Services\ReblogService;
|
||||||
|
use App\Services\StatusService;
|
||||||
|
use App\Status;
|
||||||
|
use App\Transformer\ActivityPub\Verb\UndoAnnounce;
|
||||||
|
use App\Util\ActivityPub\HttpSignature;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Pool;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
@ -12,128 +18,125 @@ use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use League\Fractal;
|
use League\Fractal;
|
||||||
use League\Fractal\Serializer\ArraySerializer;
|
use League\Fractal\Serializer\ArraySerializer;
|
||||||
use App\Transformer\ActivityPub\Verb\UndoAnnounce;
|
|
||||||
use GuzzleHttp\{Pool, Client, Promise};
|
|
||||||
use App\Util\ActivityPub\HttpSignature;
|
|
||||||
use App\Services\ReblogService;
|
|
||||||
use App\Services\StatusService;
|
|
||||||
use App\Jobs\HomeFeedPipeline\FeedRemovePipeline;
|
|
||||||
|
|
||||||
class UndoSharePipeline implements ShouldQueue
|
class UndoSharePipeline implements ShouldQueue
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
protected $status;
|
|
||||||
public $deleteWhenMissingModels = true;
|
|
||||||
|
|
||||||
public function __construct(Status $status)
|
protected $status;
|
||||||
{
|
|
||||||
$this->status = $status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handle()
|
public $deleteWhenMissingModels = true;
|
||||||
{
|
|
||||||
$status = $this->status;
|
|
||||||
$actor = $status->profile;
|
|
||||||
$parent = Status::find($status->reblog_of_id);
|
|
||||||
|
|
||||||
FeedRemovePipeline::dispatch($status->id, $status->profile_id)->onQueue('feed');
|
public function __construct(Status $status)
|
||||||
|
{
|
||||||
|
$this->status = $status;
|
||||||
|
}
|
||||||
|
|
||||||
if($parent) {
|
public function handle()
|
||||||
$target = $parent->profile_id;
|
{
|
||||||
ReblogService::removePostReblog($parent->profile_id, $status->id);
|
$status = $this->status;
|
||||||
|
$actor = $status->profile;
|
||||||
|
$parent = Status::find($status->reblog_of_id);
|
||||||
|
|
||||||
if($parent->reblogs_count > 0) {
|
FeedRemovePipeline::dispatch($status->id, $status->profile_id)->onQueue('feed');
|
||||||
$parent->reblogs_count = $parent->reblogs_count - 1;
|
|
||||||
$parent->save();
|
|
||||||
StatusService::del($parent->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
$notification = Notification::whereProfileId($target)
|
if ($parent) {
|
||||||
->whereActorId($status->profile_id)
|
$target = $parent->profile_id;
|
||||||
->whereAction('share')
|
ReblogService::removePostReblog($parent->profile_id, $status->id);
|
||||||
->whereItemId($status->reblog_of_id)
|
|
||||||
->whereItemType('App\Status')
|
|
||||||
->first();
|
|
||||||
|
|
||||||
if($notification) {
|
if ($parent->reblogs_count > 0) {
|
||||||
$notification->forceDelete();
|
$parent->reblogs_count = $parent->reblogs_count - 1;
|
||||||
}
|
$parent->save();
|
||||||
}
|
StatusService::del($parent->id);
|
||||||
|
}
|
||||||
|
|
||||||
if ($status->uri != null) {
|
$notification = Notification::whereProfileId($target)
|
||||||
return;
|
->whereActorId($status->profile_id)
|
||||||
}
|
->whereAction('share')
|
||||||
|
->whereItemId($status->reblog_of_id)
|
||||||
|
->whereItemType('App\Status')
|
||||||
|
->first();
|
||||||
|
|
||||||
if(config('app.env') !== 'production' || config_cache('federation.activitypub.enabled') == false) {
|
if ($notification) {
|
||||||
return $status->delete();
|
$notification->forceDelete();
|
||||||
} else {
|
}
|
||||||
return $this->remoteAnnounceDeliver();
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function remoteAnnounceDeliver()
|
if ($status->uri != null) {
|
||||||
{
|
return;
|
||||||
if(config('app.env') !== 'production' || config_cache('federation.activitypub.enabled') == false) {
|
}
|
||||||
|
|
||||||
|
if (config('app.env') !== 'production' || (bool) config_cache('federation.activitypub.enabled') == false) {
|
||||||
|
return $status->delete();
|
||||||
|
} else {
|
||||||
|
return $this->remoteAnnounceDeliver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function remoteAnnounceDeliver()
|
||||||
|
{
|
||||||
|
if (config('app.env') !== 'production' || (bool) config_cache('federation.activitypub.enabled') == false) {
|
||||||
$status->delete();
|
$status->delete();
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$status = $this->status;
|
return 1;
|
||||||
$profile = $status->profile;
|
}
|
||||||
|
|
||||||
$fractal = new Fractal\Manager();
|
$status = $this->status;
|
||||||
$fractal->setSerializer(new ArraySerializer());
|
$profile = $status->profile;
|
||||||
$resource = new Fractal\Resource\Item($status, new UndoAnnounce());
|
|
||||||
$activity = $fractal->createData($resource)->toArray();
|
|
||||||
|
|
||||||
$audience = $status->profile->getAudienceInbox();
|
$fractal = new Fractal\Manager();
|
||||||
|
$fractal->setSerializer(new ArraySerializer());
|
||||||
|
$resource = new Fractal\Resource\Item($status, new UndoAnnounce());
|
||||||
|
$activity = $fractal->createData($resource)->toArray();
|
||||||
|
|
||||||
if(empty($audience) || $status->scope != 'public') {
|
$audience = $status->profile->getAudienceInbox();
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$payload = json_encode($activity);
|
if (empty($audience) || $status->scope != 'public') {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
$client = new Client([
|
$payload = json_encode($activity);
|
||||||
'timeout' => config('federation.activitypub.delivery.timeout')
|
|
||||||
]);
|
|
||||||
|
|
||||||
$version = config('pixelfed.version');
|
$client = new Client([
|
||||||
$appUrl = config('app.url');
|
'timeout' => config('federation.activitypub.delivery.timeout'),
|
||||||
$userAgent = "(Pixelfed/{$version}; +{$appUrl})";
|
]);
|
||||||
|
|
||||||
$requests = function($audience) use ($client, $activity, $profile, $payload, $userAgent) {
|
$version = config('pixelfed.version');
|
||||||
foreach($audience as $url) {
|
$appUrl = config('app.url');
|
||||||
$headers = HttpSignature::sign($profile, $url, $activity, [
|
$userAgent = "(Pixelfed/{$version}; +{$appUrl})";
|
||||||
'Content-Type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
|
||||||
'User-Agent' => $userAgent,
|
|
||||||
]);
|
|
||||||
yield function() use ($client, $url, $headers, $payload) {
|
|
||||||
return $client->postAsync($url, [
|
|
||||||
'curl' => [
|
|
||||||
CURLOPT_HTTPHEADER => $headers,
|
|
||||||
CURLOPT_POSTFIELDS => $payload,
|
|
||||||
CURLOPT_HEADER => true
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$pool = new Pool($client, $requests($audience), [
|
$requests = function ($audience) use ($client, $activity, $profile, $payload, $userAgent) {
|
||||||
'concurrency' => config('federation.activitypub.delivery.concurrency'),
|
foreach ($audience as $url) {
|
||||||
'fulfilled' => function ($response, $index) {
|
$headers = HttpSignature::sign($profile, $url, $activity, [
|
||||||
},
|
'Content-Type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||||
'rejected' => function ($reason, $index) {
|
'User-Agent' => $userAgent,
|
||||||
}
|
]);
|
||||||
]);
|
yield function () use ($client, $url, $headers, $payload) {
|
||||||
|
return $client->postAsync($url, [
|
||||||
|
'curl' => [
|
||||||
|
CURLOPT_HTTPHEADER => $headers,
|
||||||
|
CURLOPT_POSTFIELDS => $payload,
|
||||||
|
CURLOPT_HEADER => true,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
$promise = $pool->promise();
|
$pool = new Pool($client, $requests($audience), [
|
||||||
|
'concurrency' => config('federation.activitypub.delivery.concurrency'),
|
||||||
|
'fulfilled' => function ($response, $index) {
|
||||||
|
},
|
||||||
|
'rejected' => function ($reason, $index) {
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
$promise->wait();
|
$promise = $pool->promise();
|
||||||
|
|
||||||
$status->delete();
|
$promise->wait();
|
||||||
|
|
||||||
return 1;
|
$status->delete();
|
||||||
}
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,126 +2,122 @@
|
||||||
|
|
||||||
namespace App\Jobs\StatusPipeline;
|
namespace App\Jobs\StatusPipeline;
|
||||||
|
|
||||||
use DB, Cache, Storage;
|
use App\AccountInterstitial;
|
||||||
use App\{
|
use App\Bookmark;
|
||||||
AccountInterstitial,
|
use App\CollectionItem;
|
||||||
Bookmark,
|
use App\DirectMessage;
|
||||||
CollectionItem,
|
use App\Jobs\MediaPipeline\MediaDeletePipeline;
|
||||||
DirectMessage,
|
use App\Like;
|
||||||
Like,
|
use App\Media;
|
||||||
Media,
|
use App\MediaTag;
|
||||||
MediaTag,
|
use App\Mention;
|
||||||
Mention,
|
use App\Notification;
|
||||||
Notification,
|
use App\Report;
|
||||||
Report,
|
use App\Services\CollectionService;
|
||||||
Status,
|
use App\Services\NotificationService;
|
||||||
StatusArchived,
|
use App\Services\StatusService;
|
||||||
StatusHashtag,
|
use App\Status;
|
||||||
StatusView
|
use App\StatusArchived;
|
||||||
};
|
use App\StatusHashtag;
|
||||||
|
use App\StatusView;
|
||||||
|
use App\Transformer\ActivityPub\Verb\DeleteNote;
|
||||||
|
use App\Util\ActivityPub\HttpSignature;
|
||||||
|
use Cache;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Pool;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use League\Fractal;
|
use League\Fractal;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use League\Fractal\Serializer\ArraySerializer;
|
use League\Fractal\Serializer\ArraySerializer;
|
||||||
use App\Transformer\ActivityPub\Verb\DeleteNote;
|
|
||||||
use App\Util\ActivityPub\Helpers;
|
|
||||||
use GuzzleHttp\Pool;
|
|
||||||
use GuzzleHttp\Client;
|
|
||||||
use GuzzleHttp\Promise;
|
|
||||||
use App\Util\ActivityPub\HttpSignature;
|
|
||||||
use App\Services\CollectionService;
|
|
||||||
use App\Services\StatusService;
|
|
||||||
use App\Services\NotificationService;
|
|
||||||
use App\Jobs\MediaPipeline\MediaDeletePipeline;
|
|
||||||
|
|
||||||
class StatusDelete implements ShouldQueue
|
class StatusDelete implements ShouldQueue
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
protected $status;
|
protected $status;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the job if its models no longer exist.
|
* Delete the job if its models no longer exist.
|
||||||
*
|
*
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
public $deleteWhenMissingModels = true;
|
public $deleteWhenMissingModels = true;
|
||||||
|
|
||||||
public $timeout = 900;
|
public $timeout = 900;
|
||||||
|
|
||||||
public $tries = 2;
|
public $tries = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new job instance.
|
* Create a new job instance.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct(Status $status)
|
public function __construct(Status $status)
|
||||||
{
|
{
|
||||||
$this->status = $status;
|
$this->status = $status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the job.
|
* Execute the job.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$status = $this->status;
|
$status = $this->status;
|
||||||
$profile = $this->status->profile;
|
$profile = $this->status->profile;
|
||||||
|
|
||||||
StatusService::del($status->id, true);
|
StatusService::del($status->id, true);
|
||||||
if($profile) {
|
if ($profile) {
|
||||||
if(in_array($status->type, ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])) {
|
if (in_array($status->type, ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])) {
|
||||||
$profile->status_count = $profile->status_count - 1;
|
$profile->status_count = $profile->status_count - 1;
|
||||||
$profile->save();
|
$profile->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Cache::forget('pf:atom:user-feed:by-id:' . $status->profile_id);
|
Cache::forget('pf:atom:user-feed:by-id:'.$status->profile_id);
|
||||||
|
|
||||||
if(config_cache('federation.activitypub.enabled') == true) {
|
if ((bool) config_cache('federation.activitypub.enabled') == true) {
|
||||||
return $this->fanoutDelete($status);
|
return $this->fanoutDelete($status);
|
||||||
} else {
|
} else {
|
||||||
return $this->unlinkRemoveMedia($status);
|
return $this->unlinkRemoveMedia($status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function unlinkRemoveMedia($status)
|
public function unlinkRemoveMedia($status)
|
||||||
{
|
{
|
||||||
Media::whereStatusId($status->id)
|
Media::whereStatusId($status->id)
|
||||||
->get()
|
->get()
|
||||||
->each(function($media) {
|
->each(function ($media) {
|
||||||
MediaDeletePipeline::dispatch($media);
|
MediaDeletePipeline::dispatch($media);
|
||||||
});
|
});
|
||||||
|
|
||||||
if($status->in_reply_to_id) {
|
if ($status->in_reply_to_id) {
|
||||||
$parent = Status::findOrFail($status->in_reply_to_id);
|
$parent = Status::findOrFail($status->in_reply_to_id);
|
||||||
--$parent->reply_count;
|
$parent->reply_count--;
|
||||||
$parent->save();
|
$parent->save();
|
||||||
StatusService::del($parent->id);
|
StatusService::del($parent->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bookmark::whereStatusId($status->id)->delete();
|
Bookmark::whereStatusId($status->id)->delete();
|
||||||
|
|
||||||
CollectionItem::whereObjectType('App\Status')
|
CollectionItem::whereObjectType('App\Status')
|
||||||
->whereObjectId($status->id)
|
->whereObjectId($status->id)
|
||||||
->get()
|
->get()
|
||||||
->each(function($col) {
|
->each(function ($col) {
|
||||||
CollectionService::removeItem($col->collection_id, $col->object_id);
|
CollectionService::removeItem($col->collection_id, $col->object_id);
|
||||||
$col->delete();
|
$col->delete();
|
||||||
});
|
});
|
||||||
|
|
||||||
$dms = DirectMessage::whereStatusId($status->id)->get();
|
$dms = DirectMessage::whereStatusId($status->id)->get();
|
||||||
foreach($dms as $dm) {
|
foreach ($dms as $dm) {
|
||||||
$not = Notification::whereItemType('App\DirectMessage')
|
$not = Notification::whereItemType('App\DirectMessage')
|
||||||
->whereItemId($dm->id)
|
->whereItemId($dm->id)
|
||||||
->first();
|
->first();
|
||||||
if($not) {
|
if ($not) {
|
||||||
NotificationService::del($not->profile_id, $not->id);
|
NotificationService::del($not->profile_id, $not->id);
|
||||||
$not->forceDeleteQuietly();
|
$not->forceDeleteQuietly();
|
||||||
}
|
}
|
||||||
|
@ -130,11 +126,11 @@ class StatusDelete implements ShouldQueue
|
||||||
Like::whereStatusId($status->id)->delete();
|
Like::whereStatusId($status->id)->delete();
|
||||||
|
|
||||||
$mediaTags = MediaTag::where('status_id', $status->id)->get();
|
$mediaTags = MediaTag::where('status_id', $status->id)->get();
|
||||||
foreach($mediaTags as $mtag) {
|
foreach ($mediaTags as $mtag) {
|
||||||
$not = Notification::whereItemType('App\MediaTag')
|
$not = Notification::whereItemType('App\MediaTag')
|
||||||
->whereItemId($mtag->id)
|
->whereItemId($mtag->id)
|
||||||
->first();
|
->first();
|
||||||
if($not) {
|
if ($not) {
|
||||||
NotificationService::del($not->profile_id, $not->id);
|
NotificationService::del($not->profile_id, $not->id);
|
||||||
$not->forceDeleteQuietly();
|
$not->forceDeleteQuietly();
|
||||||
}
|
}
|
||||||
|
@ -142,85 +138,85 @@ class StatusDelete implements ShouldQueue
|
||||||
}
|
}
|
||||||
Mention::whereStatusId($status->id)->forceDelete();
|
Mention::whereStatusId($status->id)->forceDelete();
|
||||||
|
|
||||||
Notification::whereItemType('App\Status')
|
Notification::whereItemType('App\Status')
|
||||||
->whereItemId($status->id)
|
->whereItemId($status->id)
|
||||||
->forceDelete();
|
->forceDelete();
|
||||||
|
|
||||||
Report::whereObjectType('App\Status')
|
Report::whereObjectType('App\Status')
|
||||||
->whereObjectId($status->id)
|
->whereObjectId($status->id)
|
||||||
->delete();
|
->delete();
|
||||||
|
|
||||||
StatusArchived::whereStatusId($status->id)->delete();
|
StatusArchived::whereStatusId($status->id)->delete();
|
||||||
StatusHashtag::whereStatusId($status->id)->delete();
|
StatusHashtag::whereStatusId($status->id)->delete();
|
||||||
StatusView::whereStatusId($status->id)->delete();
|
StatusView::whereStatusId($status->id)->delete();
|
||||||
Status::whereInReplyToId($status->id)->update(['in_reply_to_id' => null]);
|
Status::whereInReplyToId($status->id)->update(['in_reply_to_id' => null]);
|
||||||
|
|
||||||
AccountInterstitial::where('item_type', 'App\Status')
|
AccountInterstitial::where('item_type', 'App\Status')
|
||||||
->where('item_id', $status->id)
|
->where('item_id', $status->id)
|
||||||
->delete();
|
->delete();
|
||||||
|
|
||||||
$status->delete();
|
$status->delete();
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fanoutDelete($status)
|
|
||||||
{
|
|
||||||
$profile = $status->profile;
|
|
||||||
|
|
||||||
if(!$profile) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$audience = $status->profile->getAudienceInbox();
|
|
||||||
|
|
||||||
$fractal = new Fractal\Manager();
|
|
||||||
$fractal->setSerializer(new ArraySerializer());
|
|
||||||
$resource = new Fractal\Resource\Item($status, new DeleteNote());
|
|
||||||
$activity = $fractal->createData($resource)->toArray();
|
|
||||||
|
|
||||||
$this->unlinkRemoveMedia($status);
|
|
||||||
|
|
||||||
$payload = json_encode($activity);
|
|
||||||
|
|
||||||
$client = new Client([
|
|
||||||
'timeout' => config('federation.activitypub.delivery.timeout')
|
|
||||||
]);
|
|
||||||
|
|
||||||
$version = config('pixelfed.version');
|
|
||||||
$appUrl = config('app.url');
|
|
||||||
$userAgent = "(Pixelfed/{$version}; +{$appUrl})";
|
|
||||||
|
|
||||||
$requests = function($audience) use ($client, $activity, $profile, $payload, $userAgent) {
|
|
||||||
foreach($audience as $url) {
|
|
||||||
$headers = HttpSignature::sign($profile, $url, $activity, [
|
|
||||||
'Content-Type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
|
||||||
'User-Agent' => $userAgent,
|
|
||||||
]);
|
|
||||||
yield function() use ($client, $url, $headers, $payload) {
|
|
||||||
return $client->postAsync($url, [
|
|
||||||
'curl' => [
|
|
||||||
CURLOPT_HTTPHEADER => $headers,
|
|
||||||
CURLOPT_POSTFIELDS => $payload,
|
|
||||||
CURLOPT_HEADER => true
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$pool = new Pool($client, $requests($audience), [
|
|
||||||
'concurrency' => config('federation.activitypub.delivery.concurrency'),
|
|
||||||
'fulfilled' => function ($response, $index) {
|
|
||||||
},
|
|
||||||
'rejected' => function ($reason, $index) {
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
$promise = $pool->promise();
|
|
||||||
|
|
||||||
$promise->wait();
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function fanoutDelete($status)
|
||||||
|
{
|
||||||
|
$profile = $status->profile;
|
||||||
|
|
||||||
|
if (! $profile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$audience = $status->profile->getAudienceInbox();
|
||||||
|
|
||||||
|
$fractal = new Fractal\Manager();
|
||||||
|
$fractal->setSerializer(new ArraySerializer());
|
||||||
|
$resource = new Fractal\Resource\Item($status, new DeleteNote());
|
||||||
|
$activity = $fractal->createData($resource)->toArray();
|
||||||
|
|
||||||
|
$this->unlinkRemoveMedia($status);
|
||||||
|
|
||||||
|
$payload = json_encode($activity);
|
||||||
|
|
||||||
|
$client = new Client([
|
||||||
|
'timeout' => config('federation.activitypub.delivery.timeout'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$version = config('pixelfed.version');
|
||||||
|
$appUrl = config('app.url');
|
||||||
|
$userAgent = "(Pixelfed/{$version}; +{$appUrl})";
|
||||||
|
|
||||||
|
$requests = function ($audience) use ($client, $activity, $profile, $payload, $userAgent) {
|
||||||
|
foreach ($audience as $url) {
|
||||||
|
$headers = HttpSignature::sign($profile, $url, $activity, [
|
||||||
|
'Content-Type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||||
|
'User-Agent' => $userAgent,
|
||||||
|
]);
|
||||||
|
yield function () use ($client, $url, $headers, $payload) {
|
||||||
|
return $client->postAsync($url, [
|
||||||
|
'curl' => [
|
||||||
|
CURLOPT_HTTPHEADER => $headers,
|
||||||
|
CURLOPT_POSTFIELDS => $payload,
|
||||||
|
CURLOPT_HEADER => true,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$pool = new Pool($client, $requests($audience), [
|
||||||
|
'concurrency' => config('federation.activitypub.delivery.concurrency'),
|
||||||
|
'fulfilled' => function ($response, $index) {
|
||||||
|
},
|
||||||
|
'rejected' => function ($reason, $index) {
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
$promise = $pool->promise();
|
||||||
|
|
||||||
|
$promise->wait();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,16 @@
|
||||||
namespace App\Jobs\StatusPipeline;
|
namespace App\Jobs\StatusPipeline;
|
||||||
|
|
||||||
use App\Hashtag;
|
use App\Hashtag;
|
||||||
|
use App\Jobs\HomeFeedPipeline\FeedInsertPipeline;
|
||||||
use App\Jobs\MentionPipeline\MentionPipeline;
|
use App\Jobs\MentionPipeline\MentionPipeline;
|
||||||
use App\Mention;
|
use App\Mention;
|
||||||
use App\Profile;
|
use App\Profile;
|
||||||
|
use App\Services\AdminShadowFilterService;
|
||||||
|
use App\Services\PublicTimelineService;
|
||||||
|
use App\Services\StatusService;
|
||||||
|
use App\Services\UserFilterService;
|
||||||
use App\Status;
|
use App\Status;
|
||||||
use App\StatusHashtag;
|
use App\StatusHashtag;
|
||||||
use App\Services\PublicTimelineService;
|
|
||||||
use App\Util\Lexer\Autolink;
|
use App\Util\Lexer\Autolink;
|
||||||
use App\Util\Lexer\Extractor;
|
use App\Util\Lexer\Extractor;
|
||||||
use App\Util\Sentiment\Bouncer;
|
use App\Util\Sentiment\Bouncer;
|
||||||
|
@ -19,18 +23,15 @@ use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use App\Services\StatusService;
|
|
||||||
use App\Services\UserFilterService;
|
|
||||||
use App\Services\AdminShadowFilterService;
|
|
||||||
use App\Jobs\HomeFeedPipeline\FeedInsertPipeline;
|
|
||||||
use App\Jobs\HomeFeedPipeline\HashtagInsertFanoutPipeline;
|
|
||||||
|
|
||||||
class StatusEntityLexer implements ShouldQueue
|
class StatusEntityLexer implements ShouldQueue
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
protected $status;
|
protected $status;
|
||||||
|
|
||||||
protected $entities;
|
protected $entities;
|
||||||
|
|
||||||
protected $autolink;
|
protected $autolink;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,12 +61,12 @@ class StatusEntityLexer implements ShouldQueue
|
||||||
$profile = $this->status->profile;
|
$profile = $this->status->profile;
|
||||||
$status = $this->status;
|
$status = $this->status;
|
||||||
|
|
||||||
if(in_array($status->type, ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])) {
|
if (in_array($status->type, ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])) {
|
||||||
$profile->status_count = $profile->status_count + 1;
|
$profile->status_count = $profile->status_count + 1;
|
||||||
$profile->save();
|
$profile->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
if($profile->no_autolink == false) {
|
if ($profile->no_autolink == false) {
|
||||||
$this->parseEntities();
|
$this->parseEntities();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,16 +104,16 @@ class StatusEntityLexer implements ShouldQueue
|
||||||
$status = $this->status;
|
$status = $this->status;
|
||||||
|
|
||||||
foreach ($tags as $tag) {
|
foreach ($tags as $tag) {
|
||||||
if(mb_strlen($tag) > 124) {
|
if (mb_strlen($tag) > 124) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
DB::transaction(function () use ($status, $tag) {
|
DB::transaction(function () use ($status, $tag) {
|
||||||
$slug = str_slug($tag, '-', false);
|
$slug = str_slug($tag, '-', false);
|
||||||
|
|
||||||
$hashtag = Hashtag::firstOrCreate([
|
$hashtag = Hashtag::firstOrCreate([
|
||||||
'slug' => $slug
|
'slug' => $slug,
|
||||||
], [
|
], [
|
||||||
'name' => $tag
|
'name' => $tag,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
StatusHashtag::firstOrCreate(
|
StatusHashtag::firstOrCreate(
|
||||||
|
@ -136,11 +137,11 @@ class StatusEntityLexer implements ShouldQueue
|
||||||
foreach ($mentions as $mention) {
|
foreach ($mentions as $mention) {
|
||||||
$mentioned = Profile::whereUsername($mention)->first();
|
$mentioned = Profile::whereUsername($mention)->first();
|
||||||
|
|
||||||
if (empty($mentioned) || !isset($mentioned->id)) {
|
if (empty($mentioned) || ! isset($mentioned->id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$blocks = UserFilterService::blocks($mentioned->id);
|
$blocks = UserFilterService::blocks($mentioned->id);
|
||||||
if($blocks && in_array($status->profile_id, $blocks)) {
|
if ($blocks && in_array($status->profile_id, $blocks)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,8 +162,8 @@ class StatusEntityLexer implements ShouldQueue
|
||||||
$status = $this->status;
|
$status = $this->status;
|
||||||
StatusService::refresh($status->id);
|
StatusService::refresh($status->id);
|
||||||
|
|
||||||
if(config('exp.cached_home_timeline')) {
|
if (config('exp.cached_home_timeline')) {
|
||||||
if( $status->in_reply_to_id === null &&
|
if ($status->in_reply_to_id === null &&
|
||||||
in_array($status->scope, ['public', 'unlisted', 'private'])
|
in_array($status->scope, ['public', 'unlisted', 'private'])
|
||||||
) {
|
) {
|
||||||
FeedInsertPipeline::dispatch($status->id, $status->profile_id)->onQueue('feed');
|
FeedInsertPipeline::dispatch($status->id, $status->profile_id)->onQueue('feed');
|
||||||
|
@ -179,28 +180,28 @@ class StatusEntityLexer implements ShouldQueue
|
||||||
'photo:album',
|
'photo:album',
|
||||||
'video',
|
'video',
|
||||||
'video:album',
|
'video:album',
|
||||||
'photo:video:album'
|
'photo:video:album',
|
||||||
];
|
];
|
||||||
|
|
||||||
if(config_cache('pixelfed.bouncer.enabled')) {
|
if (config_cache('pixelfed.bouncer.enabled')) {
|
||||||
Bouncer::get($status);
|
Bouncer::get($status);
|
||||||
}
|
}
|
||||||
|
|
||||||
Cache::forget('pf:atom:user-feed:by-id:' . $status->profile_id);
|
Cache::forget('pf:atom:user-feed:by-id:'.$status->profile_id);
|
||||||
$hideNsfw = config('instance.hide_nsfw_on_public_feeds');
|
$hideNsfw = config('instance.hide_nsfw_on_public_feeds');
|
||||||
if( $status->uri == null &&
|
if ($status->uri == null &&
|
||||||
$status->scope == 'public' &&
|
$status->scope == 'public' &&
|
||||||
in_array($status->type, $types) &&
|
in_array($status->type, $types) &&
|
||||||
$status->in_reply_to_id === null &&
|
$status->in_reply_to_id === null &&
|
||||||
$status->reblog_of_id === null &&
|
$status->reblog_of_id === null &&
|
||||||
($hideNsfw ? $status->is_nsfw == false : true)
|
($hideNsfw ? $status->is_nsfw == false : true)
|
||||||
) {
|
) {
|
||||||
if(AdminShadowFilterService::canAddToPublicFeedByProfileId($status->profile_id)) {
|
if (AdminShadowFilterService::canAddToPublicFeedByProfileId($status->profile_id)) {
|
||||||
PublicTimelineService::add($status->id);
|
PublicTimelineService::add($status->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(config_cache('federation.activitypub.enabled') == true && config('app.env') == 'production') {
|
if ((bool) config_cache('federation.activitypub.enabled') == true && config('app.env') == 'production') {
|
||||||
StatusActivityPubDeliver::dispatch($status);
|
StatusActivityPubDeliver::dispatch($status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ class LandingService
|
||||||
'media_types' => config_cache('pixelfed.media_types'),
|
'media_types' => config_cache('pixelfed.media_types'),
|
||||||
],
|
],
|
||||||
'features' => [
|
'features' => [
|
||||||
'federation' => config_cache('federation.activitypub.enabled'),
|
'federation' => (bool) config_cache('federation.activitypub.enabled'),
|
||||||
'timelines' => [
|
'timelines' => [
|
||||||
'local' => true,
|
'local' => true,
|
||||||
'network' => (bool) config_cache('federation.network_timeline'),
|
'network' => (bool) config_cache('federation.network_timeline'),
|
||||||
|
|
|
@ -2,34 +2,32 @@
|
||||||
|
|
||||||
namespace App\Util\ActivityPub;
|
namespace App\Util\ActivityPub;
|
||||||
|
|
||||||
use App\Profile;
|
|
||||||
use App\Status;
|
|
||||||
use League\Fractal;
|
|
||||||
use App\Http\Controllers\ProfileController;
|
use App\Http\Controllers\ProfileController;
|
||||||
use App\Transformer\ActivityPub\ProfileOutbox;
|
use App\Status;
|
||||||
use App\Transformer\ActivityPub\Verb\CreateNote;
|
use App\Transformer\ActivityPub\Verb\CreateNote;
|
||||||
|
use League\Fractal;
|
||||||
|
|
||||||
class Outbox {
|
class Outbox
|
||||||
|
{
|
||||||
|
public static function get($profile)
|
||||||
|
{
|
||||||
|
abort_if(! (bool) config_cache('federation.activitypub.enabled'), 404);
|
||||||
|
abort_if(! config('federation.activitypub.outbox'), 404);
|
||||||
|
|
||||||
public static function get($profile)
|
if ($profile->status != null) {
|
||||||
{
|
|
||||||
abort_if(!config_cache('federation.activitypub.enabled'), 404);
|
|
||||||
abort_if(!config('federation.activitypub.outbox'), 404);
|
|
||||||
|
|
||||||
if($profile->status != null) {
|
|
||||||
return ProfileController::accountCheck($profile);
|
return ProfileController::accountCheck($profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($profile->is_private) {
|
if ($profile->is_private) {
|
||||||
return ['error'=>'403', 'msg' => 'private profile'];
|
return ['error' => '403', 'msg' => 'private profile'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$timeline = $profile
|
$timeline = $profile
|
||||||
->statuses()
|
->statuses()
|
||||||
->whereScope('public')
|
->whereScope('public')
|
||||||
->orderBy('created_at', 'desc')
|
->orderBy('created_at', 'desc')
|
||||||
->take(10)
|
->take(10)
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
$count = Status::whereProfileId($profile->id)->count();
|
$count = Status::whereProfileId($profile->id)->count();
|
||||||
|
|
||||||
|
@ -38,14 +36,14 @@ class Outbox {
|
||||||
$res = $fractal->createData($resource)->toArray();
|
$res = $fractal->createData($resource)->toArray();
|
||||||
|
|
||||||
$outbox = [
|
$outbox = [
|
||||||
'@context' => 'https://www.w3.org/ns/activitystreams',
|
'@context' => 'https://www.w3.org/ns/activitystreams',
|
||||||
'_debug' => 'Outbox only supports latest 10 objects, pagination is not supported',
|
'_debug' => 'Outbox only supports latest 10 objects, pagination is not supported',
|
||||||
'id' => $profile->permalink('/outbox'),
|
'id' => $profile->permalink('/outbox'),
|
||||||
'type' => 'OrderedCollection',
|
'type' => 'OrderedCollection',
|
||||||
'totalItems' => $count,
|
'totalItems' => $count,
|
||||||
'orderedItems' => $res['data']
|
'orderedItems' => $res['data'],
|
||||||
];
|
];
|
||||||
return $outbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return $outbox;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -298,7 +298,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td><span class="badge badge-primary">FEDERATION</span></td>
|
<td><span class="badge badge-primary">FEDERATION</span></td>
|
||||||
<td><strong>ACTIVITY_PUB</strong></td>
|
<td><strong>ACTIVITY_PUB</strong></td>
|
||||||
<td><span>{{config_cache('federation.activitypub.enabled') ? '✅ true' : '❌ false' }}</span></td>
|
<td><span>{{(bool) config_cache('federation.activitypub.enabled') ? '✅ true' : '❌ false' }}</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><span class="badge badge-primary">FEDERATION</span></td>
|
<td><span class="badge badge-primary">FEDERATION</span></td>
|
||||||
|
|
Loading…
Reference in a new issue