Update config() to config_cache()

This commit is contained in:
Daniel Supernault 2021-05-11 18:17:03 -06:00
parent 27b722e7a7
commit 53134208fe
No known key found for this signature in database
GPG key ID: 0DEF1C662C9033F7
9 changed files with 889 additions and 884 deletions

View file

@ -79,7 +79,7 @@ class FederationController extends Controller
public function userOutbox(Request $request, $username) public function userOutbox(Request $request, $username)
{ {
abort_if(!config('federation.activitypub.enabled'), 404); abort_if(!config_cache('federation.activitypub.enabled'), 404);
abort_if(!config('federation.activitypub.outbox'), 404); abort_if(!config('federation.activitypub.outbox'), 404);
$profile = Profile::whereNull('domain') $profile = Profile::whereNull('domain')
@ -99,7 +99,7 @@ class FederationController extends Controller
public function userInbox(Request $request, $username) public function userInbox(Request $request, $username)
{ {
abort_if(!config('federation.activitypub.enabled'), 404); abort_if(!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();
@ -110,7 +110,7 @@ class FederationController extends Controller
public function sharedInbox(Request $request) public function sharedInbox(Request $request)
{ {
abort_if(!config('federation.activitypub.enabled'), 404); abort_if(!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();
@ -121,13 +121,13 @@ class FederationController extends Controller
public function userFollowing(Request $request, $username) public function userFollowing(Request $request, $username)
{ {
abort_if(!config('federation.activitypub.enabled'), 404); abort_if(!config_cache('federation.activitypub.enabled'), 404);
$profile = Profile::whereNull('remote_url') $profile = Profile::whereNull('remote_url')
->whereUsername($username) ->whereUsername($username)
->whereIsPrivate(false) ->whereIsPrivate(false)
->firstOrFail(); ->firstOrFail();
if($profile->status != null) { if($profile->status != null) {
abort(404); abort(404);
} }
@ -139,12 +139,12 @@ class FederationController extends Controller
'totalItems' => 0, 'totalItems' => 0,
'orderedItems' => [] 'orderedItems' => []
]; ];
return response()->json($obj); return response()->json($obj);
} }
public function userFollowers(Request $request, $username) public function userFollowers(Request $request, $username)
{ {
abort_if(!config('federation.activitypub.enabled'), 404); abort_if(!config_cache('federation.activitypub.enabled'), 404);
$profile = Profile::whereNull('remote_url') $profile = Profile::whereNull('remote_url')
->whereUsername($username) ->whereUsername($username)
@ -163,6 +163,6 @@ class FederationController extends Controller
'orderedItems' => [] 'orderedItems' => []
]; ];
return response()->json($obj); return response()->json($obj);
} }
} }

View file

@ -20,229 +20,229 @@ use App\Transformer\ActivityPub\ProfileTransformer;
class ProfileController extends Controller class ProfileController extends Controller
{ {
public function show(Request $request, $username) public function show(Request $request, $username)
{ {
$user = Profile::whereNull('domain') $user = Profile::whereNull('domain')
->whereNull('status') ->whereNull('status')
->whereUsername($username) ->whereUsername($username)
->firstOrFail(); ->firstOrFail();
if($request->wantsJson() && config('federation.activitypub.enabled')) {
return $this->showActivityPub($request, $user);
}
return $this->buildProfile($request, $user);
}
protected function buildProfile(Request $request, $user) if($request->wantsJson() && config_cache('federation.activitypub.enabled')) {
{ return $this->showActivityPub($request, $user);
$username = $user->username; }
$loggedIn = Auth::check(); return $this->buildProfile($request, $user);
$isPrivate = false; }
$isBlocked = false;
if(!$loggedIn) {
$key = 'profile:settings:' . $user->id;
$ttl = now()->addHours(6);
$settings = Cache::remember($key, $ttl, function() use($user) {
return $user->user->settings;
});
if ($user->is_private == true) { protected function buildProfile(Request $request, $user)
abort(404); {
} $username = $user->username;
$loggedIn = Auth::check();
$isPrivate = false;
$isBlocked = false;
if(!$loggedIn) {
$key = 'profile:settings:' . $user->id;
$ttl = now()->addHours(6);
$settings = Cache::remember($key, $ttl, function() use($user) {
return $user->user->settings;
});
$owner = false; if ($user->is_private == true) {
$is_following = false; abort(404);
}
$is_admin = $user->user->is_admin; $owner = false;
$profile = $user; $is_following = false;
$settings = [
'crawlable' => $settings->crawlable,
'following' => [
'count' => $settings->show_profile_following_count,
'list' => $settings->show_profile_following
],
'followers' => [
'count' => $settings->show_profile_follower_count,
'list' => $settings->show_profile_followers
]
];
$ui = $request->has('ui') && $request->input('ui') == 'memory' ? 'profile.memory' : 'profile.show';
return view($ui, compact('profile', 'settings')); $is_admin = $user->user->is_admin;
} else { $profile = $user;
$key = 'profile:settings:' . $user->id; $settings = [
$ttl = now()->addHours(6); 'crawlable' => $settings->crawlable,
$settings = Cache::remember($key, $ttl, function() use($user) { 'following' => [
return $user->user->settings; 'count' => $settings->show_profile_following_count,
}); 'list' => $settings->show_profile_following
],
'followers' => [
'count' => $settings->show_profile_follower_count,
'list' => $settings->show_profile_followers
]
];
$ui = $request->has('ui') && $request->input('ui') == 'memory' ? 'profile.memory' : 'profile.show';
if ($user->is_private == true) { return view($ui, compact('profile', 'settings'));
$isPrivate = $this->privateProfileCheck($user, $loggedIn); } else {
} $key = 'profile:settings:' . $user->id;
$ttl = now()->addHours(6);
$settings = Cache::remember($key, $ttl, function() use($user) {
return $user->user->settings;
});
$isBlocked = $this->blockedProfileCheck($user); if ($user->is_private == true) {
$isPrivate = $this->privateProfileCheck($user, $loggedIn);
}
$owner = $loggedIn && Auth::id() === $user->user_id; $isBlocked = $this->blockedProfileCheck($user);
$is_following = ($owner == false && Auth::check()) ? $user->followedBy(Auth::user()->profile) : false;
if ($isPrivate == true || $isBlocked == true) { $owner = $loggedIn && Auth::id() === $user->user_id;
$requested = Auth::check() ? FollowRequest::whereFollowerId(Auth::user()->profile_id) $is_following = ($owner == false && Auth::check()) ? $user->followedBy(Auth::user()->profile) : false;
->whereFollowingId($user->id)
->exists() : false;
return view('profile.private', compact('user', 'is_following', 'requested'));
}
$is_admin = is_null($user->domain) ? $user->user->is_admin : false; if ($isPrivate == true || $isBlocked == true) {
$profile = $user; $requested = Auth::check() ? FollowRequest::whereFollowerId(Auth::user()->profile_id)
$settings = [ ->whereFollowingId($user->id)
'crawlable' => $settings->crawlable, ->exists() : false;
'following' => [ return view('profile.private', compact('user', 'is_following', 'requested'));
'count' => $settings->show_profile_following_count, }
'list' => $settings->show_profile_following
],
'followers' => [
'count' => $settings->show_profile_follower_count,
'list' => $settings->show_profile_followers
]
];
$ui = $request->has('ui') && $request->input('ui') == 'memory' ? 'profile.memory' : 'profile.show';
return view($ui, compact('profile', 'settings'));
}
}
public function permalinkRedirect(Request $request, $username) $is_admin = is_null($user->domain) ? $user->user->is_admin : false;
{ $profile = $user;
$user = Profile::whereNull('domain')->whereUsername($username)->firstOrFail(); $settings = [
'crawlable' => $settings->crawlable,
'following' => [
'count' => $settings->show_profile_following_count,
'list' => $settings->show_profile_following
],
'followers' => [
'count' => $settings->show_profile_follower_count,
'list' => $settings->show_profile_followers
]
];
$ui = $request->has('ui') && $request->input('ui') == 'memory' ? 'profile.memory' : 'profile.show';
return view($ui, compact('profile', 'settings'));
}
}
if ($request->wantsJson() && config('federation.activitypub.enabled')) { public function permalinkRedirect(Request $request, $username)
return $this->showActivityPub($request, $user); {
} $user = Profile::whereNull('domain')->whereUsername($username)->firstOrFail();
return redirect($user->url()); if ($request->wantsJson() && config_cache('federation.activitypub.enabled')) {
} return $this->showActivityPub($request, $user);
}
protected function privateProfileCheck(Profile $profile, $loggedIn) return redirect($user->url());
{ }
if (!Auth::check()) {
return true;
}
$user = Auth::user()->profile; protected function privateProfileCheck(Profile $profile, $loggedIn)
if($user->id == $profile->id || !$profile->is_private) { {
return false; if (!Auth::check()) {
} return true;
}
$follows = Follower::whereProfileId($user->id)->whereFollowingId($profile->id)->exists(); $user = Auth::user()->profile;
if ($follows == false) { if($user->id == $profile->id || !$profile->is_private) {
return true; return false;
} }
return false;
}
public static function accountCheck(Profile $profile) $follows = Follower::whereProfileId($user->id)->whereFollowingId($profile->id)->exists();
{ if ($follows == false) {
switch ($profile->status) { return true;
case 'disabled': }
case 'suspended':
case 'delete':
return view('profile.disabled');
break;
default:
break;
}
return abort(404);
}
protected function blockedProfileCheck(Profile $profile) return false;
{ }
$pid = Auth::user()->profile->id;
$blocks = UserFilter::whereUserId($profile->id)
->whereFilterType('block')
->whereFilterableType('App\Profile')
->pluck('filterable_id')
->toArray();
if (in_array($pid, $blocks)) {
return true;
}
return false; public static function accountCheck(Profile $profile)
} {
switch ($profile->status) {
case 'disabled':
case 'suspended':
case 'delete':
return view('profile.disabled');
break;
public function showActivityPub(Request $request, $user) default:
{ break;
abort_if(!config('federation.activitypub.enabled'), 404); }
abort_if($user->domain, 404); return abort(404);
}
$fractal = new Fractal\Manager(); protected function blockedProfileCheck(Profile $profile)
$resource = new Fractal\Resource\Item($user, new ProfileTransformer); {
$res = $fractal->createData($resource)->toArray(); $pid = Auth::user()->profile->id;
return response(json_encode($res['data']))->header('Content-Type', 'application/activity+json'); $blocks = UserFilter::whereUserId($profile->id)
} ->whereFilterType('block')
->whereFilterableType('App\Profile')
->pluck('filterable_id')
->toArray();
if (in_array($pid, $blocks)) {
return true;
}
public function showAtomFeed(Request $request, $user) return false;
{ }
abort_if(!config('federation.atom.enabled'), 404);
$profile = $user = Profile::whereNull('status')->whereNull('domain')->whereUsername($user)->whereIsPrivate(false)->firstOrFail(); public function showActivityPub(Request $request, $user)
if($profile->status != null) { {
return $this->accountCheck($profile); abort_if(!config_cache('federation.activitypub.enabled'), 404);
} abort_if($user->domain, 404);
if($profile->is_private || Auth::check()) {
$blocked = $this->blockedProfileCheck($profile);
$check = $this->privateProfileCheck($profile, null);
if($check || $blocked) {
return redirect($profile->url());
}
}
$items = $profile->statuses()->whereHas('media')->whereIn('visibility',['public', 'unlisted'])->orderBy('created_at', 'desc')->take(10)->get();
return response()->view('atom.user', compact('profile', 'items'))
->header('Content-Type', 'application/atom+xml');
}
public function meRedirect() $fractal = new Fractal\Manager();
{ $resource = new Fractal\Resource\Item($user, new ProfileTransformer);
abort_if(!Auth::check(), 404); $res = $fractal->createData($resource)->toArray();
return redirect(Auth::user()->url()); return response(json_encode($res['data']))->header('Content-Type', 'application/activity+json');
} }
public function embed(Request $request, $username) public function showAtomFeed(Request $request, $user)
{ {
$res = view('profile.embed-removed'); abort_if(!config('federation.atom.enabled'), 404);
if(strlen($username) > 15 || strlen($username) < 2) { $profile = $user = Profile::whereNull('status')->whereNull('domain')->whereUsername($user)->whereIsPrivate(false)->firstOrFail();
return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']); if($profile->status != null) {
} return $this->accountCheck($profile);
}
if($profile->is_private || Auth::check()) {
$blocked = $this->blockedProfileCheck($profile);
$check = $this->privateProfileCheck($profile, null);
if($check || $blocked) {
return redirect($profile->url());
}
}
$items = $profile->statuses()->whereHas('media')->whereIn('visibility',['public', 'unlisted'])->orderBy('created_at', 'desc')->take(10)->get();
return response()->view('atom.user', compact('profile', 'items'))
->header('Content-Type', 'application/atom+xml');
}
$profile = Profile::whereUsername($username) public function meRedirect()
->whereIsPrivate(false) {
->whereNull('status') abort_if(!Auth::check(), 404);
->whereNull('domain') return redirect(Auth::user()->url());
->first(); }
if(!$profile) { public function embed(Request $request, $username)
return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']); {
} $res = view('profile.embed-removed');
$content = Cache::remember('profile:embed:'.$profile->id, now()->addHours(12), function() use($profile) { if(strlen($username) > 15 || strlen($username) < 2) {
return View::make('profile.embed')->with(compact('profile'))->render(); return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']);
}); }
return response($content)->withHeaders(['X-Frame-Options' => 'ALLOWALL']);
}
public function stories(Request $request, $username) $profile = Profile::whereUsername($username)
{ ->whereIsPrivate(false)
abort_if(!config('instance.stories.enabled') || !$request->user(), 404); ->whereNull('status')
$profile = Profile::whereNull('domain')->whereUsername($username)->firstOrFail(); ->whereNull('domain')
$pid = $profile->id; ->first();
$authed = Auth::user()->profile;
abort_if($pid != $authed->id && $profile->followedBy($authed) == false, 404); if(!$profile) {
$exists = Story::whereProfileId($pid) return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']);
->where('expires_at', '>', now()) }
->count();
abort_unless($exists > 0, 404); $content = Cache::remember('profile:embed:'.$profile->id, now()->addHours(12), function() use($profile) {
return view('profile.story', compact('pid', 'profile')); return View::make('profile.embed')->with(compact('profile'))->render();
} });
return response($content)->withHeaders(['X-Frame-Options' => 'ALLOWALL']);
}
public function stories(Request $request, $username)
{
abort_if(!config('instance.stories.enabled') || !$request->user(), 404);
$profile = Profile::whereNull('domain')->whereUsername($username)->firstOrFail();
$pid = $profile->id;
$authed = Auth::user()->profile;
abort_if($pid != $authed->id && $profile->followedBy($authed) == false, 404);
$exists = Story::whereProfileId($pid)
->where('expires_at', '>', now())
->count();
abort_unless($exists > 0, 404);
return view('profile.story', compact('pid', 'profile'));
}
} }

View file

@ -12,348 +12,348 @@ use App\Util\ActivityPub\Helpers;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use App\Transformer\Api\{ use App\Transformer\Api\{
AccountTransformer, AccountTransformer,
HashtagTransformer, HashtagTransformer,
StatusTransformer, StatusTransformer,
}; };
use App\Services\WebfingerService; use App\Services\WebfingerService;
class SearchController extends Controller class SearchController extends Controller
{ {
public $tokens = []; public $tokens = [];
public $term = ''; public $term = '';
public $hash = ''; public $hash = '';
public $cacheKey = 'api:search:tag:'; public $cacheKey = 'api:search:tag:';
public function __construct() public function __construct()
{ {
$this->middleware('auth'); $this->middleware('auth');
} }
public function searchAPI(Request $request) public function searchAPI(Request $request)
{ {
$this->validate($request, [ $this->validate($request, [
'q' => 'required|string|min:3|max:120', 'q' => 'required|string|min:3|max:120',
'src' => 'required|string|in:metro', 'src' => 'required|string|in:metro',
'v' => 'required|integer|in:2', 'v' => 'required|integer|in:2',
'scope' => 'required|in:all,hashtag,profile,remote,webfinger' 'scope' => 'required|in:all,hashtag,profile,remote,webfinger'
]); ]);
$scope = $request->input('scope') ?? 'all'; $scope = $request->input('scope') ?? 'all';
$this->term = e(urldecode($request->input('q'))); $this->term = e(urldecode($request->input('q')));
$this->hash = hash('sha256', $this->term); $this->hash = hash('sha256', $this->term);
switch ($scope) { switch ($scope) {
case 'all': case 'all':
$this->getHashtags(); $this->getHashtags();
$this->getPosts(); $this->getPosts();
$this->getProfiles(); $this->getProfiles();
// $this->getPlaces(); // $this->getPlaces();
break; break;
case 'hashtag': case 'hashtag':
$this->getHashtags(); $this->getHashtags();
break; break;
case 'profile': case 'profile':
$this->getProfiles(); $this->getProfiles();
break; break;
case 'webfinger': case 'webfinger':
$this->webfingerSearch(); $this->webfingerSearch();
break; break;
case 'remote': case 'remote':
$this->remoteLookupSearch(); $this->remoteLookupSearch();
break; break;
case 'place': case 'place':
$this->getPlaces(); $this->getPlaces();
break; break;
default: default:
break; break;
} }
return response()->json($this->tokens, 200, [], JSON_PRETTY_PRINT); return response()->json($this->tokens, 200, [], JSON_PRETTY_PRINT);
} }
protected function getPosts() protected function getPosts()
{ {
$tag = $this->term; $tag = $this->term;
$hash = hash('sha256', $tag); $hash = hash('sha256', $tag);
if( Helpers::validateUrl($tag) != false && if( Helpers::validateUrl($tag) != false &&
Helpers::validateLocalUrl($tag) != true && Helpers::validateLocalUrl($tag) != true &&
config('federation.activitypub.enabled') == true && config_cache('federation.activitypub.enabled') == true &&
config('federation.activitypub.remoteFollow') == true config('federation.activitypub.remoteFollow') == true
) { ) {
$remote = Helpers::fetchFromUrl($tag); $remote = Helpers::fetchFromUrl($tag);
if( isset($remote['type']) && if( isset($remote['type']) &&
$remote['type'] == 'Note') { $remote['type'] == 'Note') {
$item = Helpers::statusFetch($tag); $item = Helpers::statusFetch($tag);
$this->tokens['posts'] = [[ $this->tokens['posts'] = [[
'count' => 0, 'count' => 0,
'url' => $item->url(), 'url' => $item->url(),
'type' => 'status', 'type' => 'status',
'value' => "by {$item->profile->username} <span class='float-right'>{$item->created_at->diffForHumans(null, true, true)}</span>", 'value' => "by {$item->profile->username} <span class='float-right'>{$item->created_at->diffForHumans(null, true, true)}</span>",
'tokens' => [$item->caption], 'tokens' => [$item->caption],
'name' => $item->caption, 'name' => $item->caption,
'thumb' => $item->thumb(), 'thumb' => $item->thumb(),
]]; ]];
} }
} else { } else {
$posts = Status::select('id', 'profile_id', 'caption', 'created_at') $posts = Status::select('id', 'profile_id', 'caption', 'created_at')
->whereHas('media') ->whereHas('media')
->whereNull('in_reply_to_id') ->whereNull('in_reply_to_id')
->whereNull('reblog_of_id') ->whereNull('reblog_of_id')
->whereProfileId(Auth::user()->profile_id) ->whereProfileId(Auth::user()->profile_id)
->where('caption', 'like', '%'.$tag.'%') ->where('caption', 'like', '%'.$tag.'%')
->latest() ->latest()
->limit(10) ->limit(10)
->get(); ->get();
if($posts->count() > 0) { if($posts->count() > 0) {
$posts = $posts->map(function($item, $key) { $posts = $posts->map(function($item, $key) {
return [ return [
'count' => 0, 'count' => 0,
'url' => $item->url(), 'url' => $item->url(),
'type' => 'status', 'type' => 'status',
'value' => "by {$item->profile->username} <span class='float-right'>{$item->created_at->diffForHumans(null, true, true)}</span>", 'value' => "by {$item->profile->username} <span class='float-right'>{$item->created_at->diffForHumans(null, true, true)}</span>",
'tokens' => [$item->caption], 'tokens' => [$item->caption],
'name' => $item->caption, 'name' => $item->caption,
'thumb' => $item->thumb(), 'thumb' => $item->thumb(),
'filter' => $item->firstMedia()->filter_class 'filter' => $item->firstMedia()->filter_class
]; ];
}); });
$this->tokens['posts'] = $posts; $this->tokens['posts'] = $posts;
} }
} }
} }
protected function getHashtags() protected function getHashtags()
{ {
$tag = $this->term; $tag = $this->term;
$key = $this->cacheKey . 'hashtags:' . $this->hash; $key = $this->cacheKey . 'hashtags:' . $this->hash;
$ttl = now()->addMinutes(1); $ttl = now()->addMinutes(1);
$tokens = Cache::remember($key, $ttl, function() use($tag) { $tokens = Cache::remember($key, $ttl, function() use($tag) {
$htag = Str::startsWith($tag, '#') == true ? mb_substr($tag, 1) : $tag; $htag = Str::startsWith($tag, '#') == true ? mb_substr($tag, 1) : $tag;
$hashtags = Hashtag::select('id', 'name', 'slug') $hashtags = Hashtag::select('id', 'name', 'slug')
->where('slug', 'like', '%'.$htag.'%') ->where('slug', 'like', '%'.$htag.'%')
->whereHas('posts') ->whereHas('posts')
->limit(20) ->limit(20)
->get(); ->get();
if($hashtags->count() > 0) { if($hashtags->count() > 0) {
$tags = $hashtags->map(function ($item, $key) { $tags = $hashtags->map(function ($item, $key) {
return [ return [
'count' => $item->posts()->count(), 'count' => $item->posts()->count(),
'url' => $item->url(), 'url' => $item->url(),
'type' => 'hashtag', 'type' => 'hashtag',
'value' => $item->name, 'value' => $item->name,
'tokens' => '', 'tokens' => '',
'name' => null, 'name' => null,
]; ];
}); });
return $tags; return $tags;
} }
}); });
$this->tokens['hashtags'] = $tokens; $this->tokens['hashtags'] = $tokens;
} }
protected function getPlaces() protected function getPlaces()
{ {
$tag = $this->term; $tag = $this->term;
// $key = $this->cacheKey . 'places:' . $this->hash; // $key = $this->cacheKey . 'places:' . $this->hash;
// $ttl = now()->addHours(12); // $ttl = now()->addHours(12);
// $tokens = Cache::remember($key, $ttl, function() use($tag) { // $tokens = Cache::remember($key, $ttl, function() use($tag) {
$htag = Str::contains($tag, ',') == true ? explode(',', $tag) : [$tag]; $htag = Str::contains($tag, ',') == true ? explode(',', $tag) : [$tag];
$hashtags = Place::select('id', 'name', 'slug', 'country') $hashtags = Place::select('id', 'name', 'slug', 'country')
->where('name', 'like', '%'.$htag[0].'%') ->where('name', 'like', '%'.$htag[0].'%')
->paginate(20); ->paginate(20);
$tags = []; $tags = [];
if($hashtags->count() > 0) { if($hashtags->count() > 0) {
$tags = $hashtags->map(function ($item, $key) { $tags = $hashtags->map(function ($item, $key) {
return [ return [
'count' => null, 'count' => null,
'url' => $item->url(), 'url' => $item->url(),
'type' => 'place', 'type' => 'place',
'value' => $item->name . ', ' . $item->country, 'value' => $item->name . ', ' . $item->country,
'tokens' => '', 'tokens' => '',
'name' => null, 'name' => null,
'city' => $item->name, 'city' => $item->name,
'country' => $item->country 'country' => $item->country
]; ];
}); });
// return $tags; // return $tags;
} }
// }); // });
$this->tokens['places'] = $tags; $this->tokens['places'] = $tags;
$this->tokens['placesPagination'] = [ $this->tokens['placesPagination'] = [
'total' => $hashtags->total(), 'total' => $hashtags->total(),
'current_page' => $hashtags->currentPage(), 'current_page' => $hashtags->currentPage(),
'last_page' => $hashtags->lastPage() 'last_page' => $hashtags->lastPage()
]; ];
} }
protected function getProfiles() protected function getProfiles()
{ {
$tag = $this->term; $tag = $this->term;
$remoteKey = $this->cacheKey . 'profiles:remote:' . $this->hash; $remoteKey = $this->cacheKey . 'profiles:remote:' . $this->hash;
$key = $this->cacheKey . 'profiles:' . $this->hash; $key = $this->cacheKey . 'profiles:' . $this->hash;
$remoteTtl = now()->addMinutes(15); $remoteTtl = now()->addMinutes(15);
$ttl = now()->addHours(2); $ttl = now()->addHours(2);
if( Helpers::validateUrl($tag) != false && if( Helpers::validateUrl($tag) != false &&
Helpers::validateLocalUrl($tag) != true && Helpers::validateLocalUrl($tag) != true &&
config('federation.activitypub.enabled') == true && config_cache('federation.activitypub.enabled') == true &&
config('federation.activitypub.remoteFollow') == true config('federation.activitypub.remoteFollow') == true
) { ) {
$remote = Helpers::fetchFromUrl($tag); $remote = Helpers::fetchFromUrl($tag);
if( isset($remote['type']) && if( isset($remote['type']) &&
$remote['type'] == 'Person' $remote['type'] == 'Person'
) { ) {
$this->tokens['profiles'] = Cache::remember($remoteKey, $remoteTtl, function() use($tag) { $this->tokens['profiles'] = Cache::remember($remoteKey, $remoteTtl, function() use($tag) {
$item = Helpers::profileFirstOrNew($tag); $item = Helpers::profileFirstOrNew($tag);
$tokens = [[ $tokens = [[
'count' => 1, 'count' => 1,
'url' => $item->url(), 'url' => $item->url(),
'type' => 'profile', 'type' => 'profile',
'value' => $item->username, 'value' => $item->username,
'tokens' => [$item->username], 'tokens' => [$item->username],
'name' => $item->name, 'name' => $item->name,
'entity' => [ 'entity' => [
'id' => (string) $item->id, 'id' => (string) $item->id,
'following' => $item->followedBy(Auth::user()->profile), 'following' => $item->followedBy(Auth::user()->profile),
'follow_request' => $item->hasFollowRequestById(Auth::user()->profile_id), 'follow_request' => $item->hasFollowRequestById(Auth::user()->profile_id),
'thumb' => $item->avatarUrl(), 'thumb' => $item->avatarUrl(),
'local' => (bool) !$item->domain, 'local' => (bool) !$item->domain,
'post_count' => $item->statuses()->count() 'post_count' => $item->statuses()->count()
] ]
]]; ]];
return $tokens; return $tokens;
}); });
} }
} }
else { else {
$this->tokens['profiles'] = Cache::remember($key, $ttl, function() use($tag) { $this->tokens['profiles'] = Cache::remember($key, $ttl, function() use($tag) {
if(Str::startsWith($tag, '@')) { if(Str::startsWith($tag, '@')) {
$tag = substr($tag, 1); $tag = substr($tag, 1);
} }
$users = Profile::select('status', 'domain', 'username', 'name', 'id') $users = Profile::select('status', 'domain', 'username', 'name', 'id')
->whereNull('status') ->whereNull('status')
->where('username', 'like', '%'.$tag.'%') ->where('username', 'like', '%'.$tag.'%')
->limit(20) ->limit(20)
->orderBy('domain') ->orderBy('domain')
->get(); ->get();
if($users->count() > 0) { if($users->count() > 0) {
return $users->map(function ($item, $key) { return $users->map(function ($item, $key) {
return [ return [
'count' => 0, 'count' => 0,
'url' => $item->url(), 'url' => $item->url(),
'type' => 'profile', 'type' => 'profile',
'value' => $item->username, 'value' => $item->username,
'tokens' => [$item->username], 'tokens' => [$item->username],
'name' => $item->name, 'name' => $item->name,
'avatar' => $item->avatarUrl(), 'avatar' => $item->avatarUrl(),
'id' => (string) $item->id, 'id' => (string) $item->id,
'entity' => [ 'entity' => [
'id' => (string) $item->id, 'id' => (string) $item->id,
'following' => $item->followedBy(Auth::user()->profile), 'following' => $item->followedBy(Auth::user()->profile),
'follow_request' => $item->hasFollowRequestById(Auth::user()->profile_id), 'follow_request' => $item->hasFollowRequestById(Auth::user()->profile_id),
'thumb' => $item->avatarUrl(), 'thumb' => $item->avatarUrl(),
'local' => (bool) !$item->domain, 'local' => (bool) !$item->domain,
'post_count' => $item->statuses()->count() 'post_count' => $item->statuses()->count()
] ]
]; ];
}); });
} }
}); });
} }
} }
public function results(Request $request) public function results(Request $request)
{ {
$this->validate($request, [ $this->validate($request, [
'q' => 'required|string|min:1', 'q' => 'required|string|min:1',
]); ]);
return view('search.results');
}
protected function webfingerSearch() return view('search.results');
{ }
$wfs = WebfingerService::lookup($this->term);
if(empty($wfs)) { protected function webfingerSearch()
return; {
} $wfs = WebfingerService::lookup($this->term);
$this->tokens['profiles'] = [ if(empty($wfs)) {
[ return;
'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']
]
]
];
return;
}
protected function remotePostLookup() $this->tokens['profiles'] = [
{ [
$tag = $this->term; 'count' => 1,
$hash = hash('sha256', $tag); 'url' => $wfs['url'],
$local = Helpers::validateLocalUrl($tag); 'type' => 'profile',
$valid = Helpers::validateUrl($tag); '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;
}
if($valid == false || $local == true) { protected function remotePostLookup()
return; {
} $tag = $this->term;
$hash = hash('sha256', $tag);
if(Status::whereUri($tag)->whereLocal(false)->exists()) { $local = Helpers::validateLocalUrl($tag);
$item = Status::whereUri($tag)->first(); $valid = Helpers::validateUrl($tag);
$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' => $item->firstMedia()->remote_url,
'timestamp' => $item->created_at->diffForHumans()
]];
}
$remote = Helpers::fetchFromUrl($tag); if($valid == false || $local == true) {
return;
}
if(isset($remote['type']) && $remote['type'] == 'Note') { if(Status::whereUri($tag)->whereLocal(false)->exists()) {
$item = Helpers::statusFetch($tag); $item = Status::whereUri($tag)->first();
$this->tokens['posts'] = [[ $this->tokens['posts'] = [[
'count' => 0, 'count' => 0,
'url' => "/i/web/post/_/$item->profile_id/$item->id", 'url' => "/i/web/post/_/$item->profile_id/$item->id",
'type' => 'status', 'type' => 'status',
'username' => $item->profile->username, 'username' => $item->profile->username,
'caption' => $item->rendered ?? $item->caption, 'caption' => $item->rendered ?? $item->caption,
'thumb' => $item->firstMedia()->remote_url, 'thumb' => $item->firstMedia()->remote_url,
'timestamp' => $item->created_at->diffForHumans() 'timestamp' => $item->created_at->diffForHumans()
]]; ]];
} }
}
protected function remoteLookupSearch() $remote = Helpers::fetchFromUrl($tag);
{
if(!Helpers::validateUrl($this->term)) { if(isset($remote['type']) && $remote['type'] == 'Note') {
return; $item = Helpers::statusFetch($tag);
} $this->tokens['posts'] = [[
$this->getProfiles(); 'count' => 0,
$this->remotePostLookup(); 'url' => "/i/web/post/_/$item->profile_id/$item->id",
} 'type' => 'status',
} 'username' => $item->profile->username,
'caption' => $item->rendered ?? $item->caption,
'thumb' => $item->firstMedia()->remote_url,
'timestamp' => $item->created_at->diffForHumans()
]];
}
}
protected function remoteLookupSearch()
{
if(!Helpers::validateUrl($this->term)) {
return;
}
$this->getProfiles();
$this->remotePostLookup();
}
}

View file

@ -70,11 +70,16 @@ class StatusController extends Controller
]); ]);
} }
if ($request->wantsJson() && config('federation.activitypub.enabled')) { if ($request->wantsJson() && config_cache('federation.activitypub.enabled')) {
return $this->showActivityPub($request, $status); return $this->showActivityPub($request, $status);
} }
$template = $status->in_reply_to_id ? 'status.reply' : 'status.show'; $template = $status->in_reply_to_id ? 'status.reply' : 'status.show';
// $template = $status->type === 'video' &&
// $request->has('video_beta') &&
// $request->video_beta == 1 &&
// $request->user() ?
// 'status.show_video' : 'status.show';
return view($template, compact('user', 'status')); return view($template, compact('user', 'status'));
} }
@ -340,7 +345,7 @@ class StatusController extends Controller
public static function mimeTypeCheck($mimes) public static function mimeTypeCheck($mimes)
{ {
$allowed = explode(',', config('pixelfed.media_types')); $allowed = explode(',', config_cache('pixelfed.media_types'));
$count = count($mimes); $count = count($mimes);
$photos = 0; $photos = 0;
$videos = 0; $videos = 0;

View file

@ -18,132 +18,132 @@ use App\Util\ActivityPub\HttpSignature;
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;
$actor = $status->profile; $actor = $status->profile;
$target = $status->parent()->profile; $target = $status->parent()->profile;
if ($status->uri !== null) { if ($status->uri !== null) {
// Ignore notifications to remote statuses // Ignore notifications to remote statuses
return; return;
} }
$exists = Notification::whereProfileId($target->id) $exists = Notification::whereProfileId($target->id)
->whereActorId($status->profile_id) ->whereActorId($status->profile_id)
->whereAction('share') ->whereAction('share')
->whereItemId($status->reblog_of_id) ->whereItemId($status->reblog_of_id)
->whereItemType('App\Status') ->whereItemType('App\Status')
->count(); ->count();
if ($target->id === $status->profile_id) { if ($target->id === $status->profile_id) {
$this->remoteAnnounceDeliver(); $this->remoteAnnounceDeliver();
return true; return true;
} }
if( $exists !== 0) { if( $exists !== 0) {
return true; return true;
} }
$this->remoteAnnounceDeliver(); $this->remoteAnnounceDeliver();
try { try {
$notification = new Notification; $notification = new Notification;
$notification->profile_id = $target->id; $notification->profile_id = $target->id;
$notification->actor_id = $actor->id; $notification->actor_id = $actor->id;
$notification->action = 'share'; $notification->action = 'share';
$notification->message = $status->shareToText(); $notification->message = $status->shareToText();
$notification->rendered = $status->shareToHtml(); $notification->rendered = $status->shareToHtml();
$notification->item_id = $status->reblog_of_id ?? $status->id; $notification->item_id = $status->reblog_of_id ?? $status->id;
$notification->item_type = "App\Status"; $notification->item_type = "App\Status";
$notification->save(); $notification->save();
$redis = Redis::connection(); $redis = Redis::connection();
$key = config('cache.prefix').':user.'.$status->profile_id.'.notifications'; $key = config('cache.prefix').':user.'.$status->profile_id.'.notifications';
$redis->lpush($key, $notification->id); $redis->lpush($key, $notification->id);
} catch (Exception $e) { } catch (Exception $e) {
Log::error($e); Log::error($e);
} }
} }
public function remoteAnnounceDeliver() public function remoteAnnounceDeliver()
{ {
if(config('federation.activitypub.enabled') == false) { if(config_cache('federation.activitypub.enabled') == false) {
return true; return true;
} }
$status = $this->status; $status = $this->status;
$profile = $status->profile; $profile = $status->profile;
$fractal = new Fractal\Manager(); $fractal = new Fractal\Manager();
$fractal->setSerializer(new ArraySerializer()); $fractal->setSerializer(new ArraySerializer());
$resource = new Fractal\Resource\Item($status, new Announce()); $resource = new Fractal\Resource\Item($status, new Announce());
$activity = $fractal->createData($resource)->toArray(); $activity = $fractal->createData($resource)->toArray();
$audience = $status->profile->getAudienceInbox(); $audience = $status->profile->getAudienceInbox();
if(empty($audience) || $status->scope != 'public') { if(empty($audience) || $status->scope != 'public') {
// Return on profiles with no remote followers // Return on profiles with no remote followers
return; return;
} }
$payload = json_encode($activity); $payload = json_encode($activity);
$client = new Client([
'timeout' => config('federation.activitypub.delivery.timeout')
]);
$requests = function($audience) use ($client, $activity, $profile, $payload) { $client = new Client([
foreach($audience as $url) { 'timeout' => config('federation.activitypub.delivery.timeout')
$headers = HttpSignature::sign($profile, $url, $activity); ]);
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) {
'concurrency' => config('federation.activitypub.delivery.concurrency'), foreach($audience as $url) {
'fulfilled' => function ($response, $index) { $headers = HttpSignature::sign($profile, $url, $activity);
}, yield function() use ($client, $url, $headers, $payload) {
'rejected' => function ($reason, $index) { return $client->postAsync($url, [
} 'curl' => [
]); CURLOPT_HTTPHEADER => $headers,
CURLOPT_POSTFIELDS => $payload,
$promise = $pool->promise(); CURLOPT_HEADER => true
]
]);
};
}
};
$promise->wait(); $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();
}
} }

View file

@ -4,13 +4,14 @@ namespace App\Jobs\StatusPipeline;
use DB, Storage; use DB, Storage;
use App\{ use App\{
AccountInterstitial, AccountInterstitial,
MediaTag, MediaTag,
Notification, Notification,
Report, Report,
Status, Status,
StatusHashtag, StatusHashtag,
}; };
use App\Models\StatusVideo;
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;
@ -30,150 +31,149 @@ use App\Services\MediaStorageService;
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.
*
* @var bool
*/
public $deleteWhenMissingModels = true;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Status $status)
{
$this->status = $status;
}
/** /**
* Execute the job. * Delete the job if its models no longer exist.
* *
* @return void * @var bool
*/ */
public function handle() public $deleteWhenMissingModels = true;
{
$status = $this->status;
$profile = $this->status->profile;
StatusService::del($status->id); /**
$count = $profile->statuses() * Create a new job instance.
->getQuery() *
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album']) * @return void
->whereNull('in_reply_to_id') */
->whereNull('reblog_of_id') public function __construct(Status $status)
->count(); {
$this->status = $status;
}
$profile->status_count = ($count - 1); /**
$profile->save(); * Execute the job.
*
* @return void
*/
public function handle()
{
$status = $this->status;
$profile = $this->status->profile;
if(config('federation.activitypub.enabled') == true) { StatusService::del($status->id);
$this->fanoutDelete($status); $count = $profile->statuses()
} else { ->getQuery()
$this->unlinkRemoveMedia($status); ->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
} ->whereNull('in_reply_to_id')
->whereNull('reblog_of_id')
->count();
} $profile->status_count = ($count - 1);
$profile->save();
public function unlinkRemoveMedia($status) if(config_cache('federation.activitypub.enabled') == true) {
{ $this->fanoutDelete($status);
foreach ($status->media as $media) { } else {
MediaStorageService::delete($media, true); $this->unlinkRemoveMedia($status);
} }
if($status->in_reply_to_id) { }
DB::transaction(function() use($status) {
$parent = Status::findOrFail($status->in_reply_to_id);
--$parent->reply_count;
$parent->save();
});
}
DB::transaction(function() use($status) {
$comments = Status::where('in_reply_to_id', $status->id)->get();
foreach ($comments as $comment) {
$comment->in_reply_to_id = null;
$comment->save();
Notification::whereItemType('App\Status')
->whereItemId($comment->id)
->delete();
}
$status->likes()->delete();
Notification::whereItemType('App\Status')
->whereItemId($status->id)
->delete();
StatusHashtag::whereStatusId($status->id)->delete();
Report::whereObjectType('App\Status')
->whereObjectId($status->id)
->delete();
MediaTag::where('status_id', $status->id) public function unlinkRemoveMedia($status)
->cursor() {
->each(function($tag) { foreach ($status->media as $media) {
Notification::where('item_type', 'App\MediaTag') MediaStorageService::delete($media, true);
->where('item_id', $tag->id) }
->forceDelete();
$tag->delete();
});
AccountInterstitial::where('item_type', 'App\Status') if($status->in_reply_to_id) {
->where('item_id', $status->id) DB::transaction(function() use($status) {
->delete(); $parent = Status::findOrFail($status->in_reply_to_id);
--$parent->reply_count;
$parent->save();
});
}
DB::transaction(function() use($status) {
$comments = Status::where('in_reply_to_id', $status->id)->get();
foreach ($comments as $comment) {
$comment->in_reply_to_id = null;
$comment->save();
Notification::whereItemType('App\Status')
->whereItemId($comment->id)
->delete();
}
$status->likes()->delete();
Notification::whereItemType('App\Status')
->whereItemId($status->id)
->delete();
StatusHashtag::whereStatusId($status->id)->delete();
Report::whereObjectType('App\Status')
->whereObjectId($status->id)
->delete();
MediaTag::where('status_id', $status->id)
->cursor()
->each(function($tag) {
Notification::where('item_type', 'App\MediaTag')
->where('item_id', $tag->id)
->forceDelete();
$tag->delete();
});
StatusVideo::whereStatusId($status->id)->delete();
AccountInterstitial::where('item_type', 'App\Status')
->where('item_id', $status->id)
->delete();
$status->forceDelete(); $status->forceDelete();
}); });
return true; return true;
} }
protected function fanoutDelete($status) protected function fanoutDelete($status)
{ {
$audience = $status->profile->getAudienceInbox(); $audience = $status->profile->getAudienceInbox();
$profile = $status->profile; $profile = $status->profile;
$fractal = new Fractal\Manager(); $fractal = new Fractal\Manager();
$fractal->setSerializer(new ArraySerializer()); $fractal->setSerializer(new ArraySerializer());
$resource = new Fractal\Resource\Item($status, new DeleteNote()); $resource = new Fractal\Resource\Item($status, new DeleteNote());
$activity = $fractal->createData($resource)->toArray(); $activity = $fractal->createData($resource)->toArray();
$this->unlinkRemoveMedia($status); $this->unlinkRemoveMedia($status);
$payload = json_encode($activity);
$client = new Client([
'timeout' => config('federation.activitypub.delivery.timeout')
]);
$requests = function($audience) use ($client, $activity, $profile, $payload) { $payload = json_encode($activity);
foreach($audience as $url) {
$headers = HttpSignature::sign($profile, $url, $activity);
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), [ $client = new Client([
'concurrency' => config('federation.activitypub.delivery.concurrency'), 'timeout' => config('federation.activitypub.delivery.timeout')
'fulfilled' => function ($response, $index) { ]);
},
'rejected' => function ($reason, $index) {
}
]);
$promise = $pool->promise();
$promise->wait(); $requests = function($audience) use ($client, $activity, $profile, $payload) {
foreach($audience as $url) {
$headers = HttpSignature::sign($profile, $url, $activity);
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();
}
} }

View file

@ -21,146 +21,146 @@ use Illuminate\Queue\SerializesModels;
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;
/**
* Delete the job if its models no longer exist.
*
* @var bool
*/
public $deleteWhenMissingModels = true;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Status $status)
{
$this->status = $status;
}
/** /**
* Execute the job. * Delete the job if its models no longer exist.
* *
* @return void * @var bool
*/ */
public function handle() public $deleteWhenMissingModels = true;
{
$profile = $this->status->profile;
$count = $profile->statuses() /**
->getQuery() * Create a new job instance.
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album']) *
->whereNull('in_reply_to_id') * @return void
->whereNull('reblog_of_id') */
->count(); public function __construct(Status $status)
{
$this->status = $status;
}
$profile->status_count = $count; /**
$profile->save(); * Execute the job.
*
* @return void
*/
public function handle()
{
$profile = $this->status->profile;
if($profile->no_autolink == false) { $count = $profile->statuses()
$this->parseEntities(); ->getQuery()
} ->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
} ->whereNull('in_reply_to_id')
->whereNull('reblog_of_id')
->count();
public function parseEntities() $profile->status_count = $count;
{ $profile->save();
$this->extractEntities();
}
public function extractEntities() if($profile->no_autolink == false) {
{ $this->parseEntities();
$this->entities = Extractor::create()->extract($this->status->caption); }
$this->autolinkStatus(); }
}
public function autolinkStatus() public function parseEntities()
{ {
$this->autolink = Autolink::create()->autolink($this->status->caption); $this->extractEntities();
$this->storeEntities(); }
}
public function storeEntities() public function extractEntities()
{ {
$this->storeHashtags(); $this->entities = Extractor::create()->extract($this->status->caption);
DB::transaction(function () { $this->autolinkStatus();
$status = $this->status; }
$status->rendered = nl2br($this->autolink);
$status->entities = json_encode($this->entities);
$status->save();
});
}
public function storeHashtags() public function autolinkStatus()
{ {
$tags = array_unique($this->entities['hashtags']); $this->autolink = Autolink::create()->autolink($this->status->caption);
$status = $this->status; $this->storeEntities();
}
foreach ($tags as $tag) { public function storeEntities()
if(mb_strlen($tag) > 124) { {
continue; $this->storeHashtags();
} DB::transaction(function () {
DB::transaction(function () use ($status, $tag) { $status = $this->status;
$slug = str_slug($tag, '-', false); $status->rendered = nl2br($this->autolink);
$hashtag = Hashtag::firstOrCreate( $status->entities = json_encode($this->entities);
['name' => $tag, 'slug' => $slug] $status->save();
); });
StatusHashtag::firstOrCreate( }
[
'status_id' => $status->id,
'hashtag_id' => $hashtag->id,
'profile_id' => $status->profile_id,
'status_visibility' => $status->visibility,
]
);
});
}
$this->storeMentions();
}
public function storeMentions() public function storeHashtags()
{ {
$mentions = array_unique($this->entities['mentions']); $tags = array_unique($this->entities['hashtags']);
$status = $this->status; $status = $this->status;
foreach ($mentions as $mention) { foreach ($tags as $tag) {
$mentioned = Profile::whereUsername($mention)->first(); if(mb_strlen($tag) > 124) {
continue;
}
DB::transaction(function () use ($status, $tag) {
$slug = str_slug($tag, '-', false);
$hashtag = Hashtag::firstOrCreate(
['name' => $tag, 'slug' => $slug]
);
StatusHashtag::firstOrCreate(
[
'status_id' => $status->id,
'hashtag_id' => $hashtag->id,
'profile_id' => $status->profile_id,
'status_visibility' => $status->visibility,
]
);
});
}
$this->storeMentions();
}
if (empty($mentioned) || !isset($mentioned->id)) { public function storeMentions()
continue; {
} $mentions = array_unique($this->entities['mentions']);
$status = $this->status;
DB::transaction(function () use ($status, $mentioned) { foreach ($mentions as $mention) {
$m = new Mention(); $mentioned = Profile::whereUsername($mention)->first();
$m->status_id = $status->id;
$m->profile_id = $mentioned->id;
$m->save();
MentionPipeline::dispatch($status, $m); if (empty($mentioned) || !isset($mentioned->id)) {
}); continue;
} }
$this->deliver();
}
public function deliver() DB::transaction(function () use ($status, $mentioned) {
{ $m = new Mention();
$status = $this->status; $m->status_id = $status->id;
$m->profile_id = $mentioned->id;
$m->save();
if(config('pixelfed.bouncer.enabled')) { MentionPipeline::dispatch($status, $m);
Bouncer::get($status); });
} }
$this->deliver();
}
if($status->uri == null && $status->scope == 'public') { public function deliver()
PublicTimelineService::add($status->id); {
} $status = $this->status;
if(config('federation.activitypub.enabled') == true && config('app.env') == 'production') { if(config('pixelfed.bouncer.enabled')) {
StatusActivityPubDeliver::dispatch($this->status); Bouncer::get($status);
} }
}
if($status->uri == null && $status->scope == 'public') {
PublicTimelineService::add($status->id);
}
if(config_cache('federation.activitypub.enabled') == true && config('app.env') == 'production') {
StatusActivityPubDeliver::dispatch($this->status);
}
}
} }

View file

@ -13,7 +13,7 @@ class Outbox {
public static function get($profile) public static function get($profile)
{ {
abort_if(!config('federation.activitypub.enabled'), 404); abort_if(!config_cache('federation.activitypub.enabled'), 404);
abort_if(!config('federation.activitypub.outbox'), 404); abort_if(!config('federation.activitypub.outbox'), 404);
if($profile->status != null) { if($profile->status != null) {
@ -48,4 +48,4 @@ class Outbox {
return $outbox; return $outbox;
} }
} }

View file

@ -27,7 +27,7 @@ class Config {
], ],
'activitypub' => [ 'activitypub' => [
'enabled' => config('federation.activitypub.enabled'), 'enabled' => config_cache('federation.activitypub.enabled'),
'remote_follow' => config('federation.activitypub.remoteFollow') 'remote_follow' => config('federation.activitypub.remoteFollow')
], ],