1
0
Эх сурвалжийг харах

Update config() to config_cache()

Daniel Supernault 4 жил өмнө
parent
commit
53134208fe

+ 8 - 8
app/Http/Controllers/FederationController.php

@@ -79,7 +79,7 @@ class FederationController extends Controller
 
     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);
 
         $profile = Profile::whereNull('domain')
@@ -99,7 +99,7 @@ class FederationController extends Controller
 
     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);
 
         $headers = $request->headers->all();
@@ -110,7 +110,7 @@ class FederationController extends Controller
 
     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);
 
         $headers = $request->headers->all();
@@ -121,13 +121,13 @@ class FederationController extends Controller
 
     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')
             ->whereUsername($username)
             ->whereIsPrivate(false)
             ->firstOrFail();
-            
+
         if($profile->status != null) {
             abort(404);
         }
@@ -139,12 +139,12 @@ class FederationController extends Controller
             'totalItems' => 0,
             'orderedItems' => []
         ];
-        return response()->json($obj); 
+        return response()->json($obj);
     }
 
     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')
             ->whereUsername($username)
@@ -163,6 +163,6 @@ class FederationController extends Controller
             'orderedItems' => []
         ];
 
-        return response()->json($obj); 
+        return response()->json($obj);
     }
 }

+ 225 - 225
app/Http/Controllers/ProfileController.php

@@ -20,229 +20,229 @@ use App\Transformer\ActivityPub\ProfileTransformer;
 
 class ProfileController extends Controller
 {
-    public function show(Request $request, $username)
-    {
-        $user = Profile::whereNull('domain')
-            ->whereNull('status')
-            ->whereUsername($username)
-            ->firstOrFail();
-        
-        if($request->wantsJson() && config('federation.activitypub.enabled')) {
-            return $this->showActivityPub($request, $user);
-        }
-        return $this->buildProfile($request, $user);
-    }
-
-    protected function buildProfile(Request $request, $user)
-    {
-        $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;
-            });
-
-            if ($user->is_private == true) {
-                abort(404);
-            }
-
-            $owner = false;
-            $is_following = false;
-
-            $is_admin = $user->user->is_admin;
-            $profile = $user;
-            $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'));
-        } else {
-            $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) {
-                $isPrivate = $this->privateProfileCheck($user, $loggedIn);
-            }
-
-            $isBlocked = $this->blockedProfileCheck($user);
-
-            $owner = $loggedIn && Auth::id() === $user->user_id;
-            $is_following = ($owner == false && Auth::check()) ? $user->followedBy(Auth::user()->profile) : false;
-
-            if ($isPrivate == true || $isBlocked == true) {
-                $requested = Auth::check() ? FollowRequest::whereFollowerId(Auth::user()->profile_id)
-                    ->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;
-            $profile = $user;
-            $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'));
-        }
-    }
-
-    public function permalinkRedirect(Request $request, $username)
-    {
-        $user = Profile::whereNull('domain')->whereUsername($username)->firstOrFail();
-
-        if ($request->wantsJson() && config('federation.activitypub.enabled')) {
-            return $this->showActivityPub($request, $user);
-        }
-
-        return redirect($user->url());
-    }
-
-    protected function privateProfileCheck(Profile $profile, $loggedIn)
-    {
-        if (!Auth::check()) {
-            return true;
-        }
-
-        $user = Auth::user()->profile;
-        if($user->id == $profile->id || !$profile->is_private) {
-            return false;
-        }
-
-        $follows = Follower::whereProfileId($user->id)->whereFollowingId($profile->id)->exists();
-        if ($follows == false) {
-            return true;
-        }
-        
-        return false;
-    }
-
-    public static function accountCheck(Profile $profile)   
-    {   
-        switch ($profile->status) { 
-            case 'disabled':    
-            case 'suspended':   
-            case 'delete':  
-                return view('profile.disabled');    
-                break;  
-                
-            default:    
-                break;  
-        }   
-        return abort(404);  
-    }
-
-    protected function blockedProfileCheck(Profile $profile)
-    {
-        $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 function showActivityPub(Request $request, $user)
-    {
-        abort_if(!config('federation.activitypub.enabled'), 404);
-        abort_if($user->domain, 404);
-
-        $fractal = new Fractal\Manager();
-        $resource = new Fractal\Resource\Item($user, new ProfileTransformer);
-        $res = $fractal->createData($resource)->toArray();
-        return response(json_encode($res['data']))->header('Content-Type', 'application/activity+json');
-    }
-
-    public function showAtomFeed(Request $request, $user)
-    {
-        abort_if(!config('federation.atom.enabled'), 404);
-
-        $profile = $user = Profile::whereNull('status')->whereNull('domain')->whereUsername($user)->whereIsPrivate(false)->firstOrFail();
-        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');
-    }
-
-    public function meRedirect()
-    {
-        abort_if(!Auth::check(), 404);
-        return redirect(Auth::user()->url());
-    }
-
-    public function embed(Request $request, $username)
-    {
-        $res = view('profile.embed-removed');
-
-        if(strlen($username) > 15 || strlen($username) < 2) {
-            return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']);
-        }
-
-        $profile = Profile::whereUsername($username)
-            ->whereIsPrivate(false)
-            ->whereNull('status')
-            ->whereNull('domain')
-            ->first();
-
-        if(!$profile) {
-            return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']);
-        }
-
-        $content = Cache::remember('profile:embed:'.$profile->id, now()->addHours(12), function() use($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'));
-    }
+	public function show(Request $request, $username)
+	{
+		$user = Profile::whereNull('domain')
+			->whereNull('status')
+			->whereUsername($username)
+			->firstOrFail();
+
+		if($request->wantsJson() && config_cache('federation.activitypub.enabled')) {
+			return $this->showActivityPub($request, $user);
+		}
+		return $this->buildProfile($request, $user);
+	}
+
+	protected function buildProfile(Request $request, $user)
+	{
+		$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;
+			});
+
+			if ($user->is_private == true) {
+				abort(404);
+			}
+
+			$owner = false;
+			$is_following = false;
+
+			$is_admin = $user->user->is_admin;
+			$profile = $user;
+			$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'));
+		} else {
+			$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) {
+				$isPrivate = $this->privateProfileCheck($user, $loggedIn);
+			}
+
+			$isBlocked = $this->blockedProfileCheck($user);
+
+			$owner = $loggedIn && Auth::id() === $user->user_id;
+			$is_following = ($owner == false && Auth::check()) ? $user->followedBy(Auth::user()->profile) : false;
+
+			if ($isPrivate == true || $isBlocked == true) {
+				$requested = Auth::check() ? FollowRequest::whereFollowerId(Auth::user()->profile_id)
+					->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;
+			$profile = $user;
+			$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'));
+		}
+	}
+
+	public function permalinkRedirect(Request $request, $username)
+	{
+		$user = Profile::whereNull('domain')->whereUsername($username)->firstOrFail();
+
+		if ($request->wantsJson() && config_cache('federation.activitypub.enabled')) {
+			return $this->showActivityPub($request, $user);
+		}
+
+		return redirect($user->url());
+	}
+
+	protected function privateProfileCheck(Profile $profile, $loggedIn)
+	{
+		if (!Auth::check()) {
+			return true;
+		}
+
+		$user = Auth::user()->profile;
+		if($user->id == $profile->id || !$profile->is_private) {
+			return false;
+		}
+
+		$follows = Follower::whereProfileId($user->id)->whereFollowingId($profile->id)->exists();
+		if ($follows == false) {
+			return true;
+		}
+
+		return false;
+	}
+
+	public static function accountCheck(Profile $profile)
+	{
+		switch ($profile->status) {
+			case 'disabled':
+			case 'suspended':
+			case 'delete':
+				return view('profile.disabled');
+				break;
+
+			default:
+				break;
+		}
+		return abort(404);
+	}
+
+	protected function blockedProfileCheck(Profile $profile)
+	{
+		$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 function showActivityPub(Request $request, $user)
+	{
+		abort_if(!config_cache('federation.activitypub.enabled'), 404);
+		abort_if($user->domain, 404);
+
+		$fractal = new Fractal\Manager();
+		$resource = new Fractal\Resource\Item($user, new ProfileTransformer);
+		$res = $fractal->createData($resource)->toArray();
+		return response(json_encode($res['data']))->header('Content-Type', 'application/activity+json');
+	}
+
+	public function showAtomFeed(Request $request, $user)
+	{
+		abort_if(!config('federation.atom.enabled'), 404);
+
+		$profile = $user = Profile::whereNull('status')->whereNull('domain')->whereUsername($user)->whereIsPrivate(false)->firstOrFail();
+		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');
+	}
+
+	public function meRedirect()
+	{
+		abort_if(!Auth::check(), 404);
+		return redirect(Auth::user()->url());
+	}
+
+	public function embed(Request $request, $username)
+	{
+		$res = view('profile.embed-removed');
+
+		if(strlen($username) > 15 || strlen($username) < 2) {
+			return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']);
+		}
+
+		$profile = Profile::whereUsername($username)
+			->whereIsPrivate(false)
+			->whereNull('status')
+			->whereNull('domain')
+			->first();
+
+		if(!$profile) {
+			return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']);
+		}
+
+		$content = Cache::remember('profile:embed:'.$profile->id, now()->addHours(12), function() use($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'));
+	}
 }

+ 340 - 340
app/Http/Controllers/SearchController.php

@@ -12,348 +12,348 @@ use App\Util\ActivityPub\Helpers;
 use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Str;
 use App\Transformer\Api\{
-    AccountTransformer,
-    HashtagTransformer,
-    StatusTransformer,
+	AccountTransformer,
+	HashtagTransformer,
+	StatusTransformer,
 };
 use App\Services\WebfingerService;
 
 class SearchController extends Controller
 {
-    public $tokens = [];
-    public $term = '';
-    public $hash = '';
-    public $cacheKey = 'api:search:tag:';
-
-    public function __construct()
-    {
-        $this->middleware('auth');
-    }
-
-    public function searchAPI(Request $request)
-    {
-        $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';
-        $this->term = e(urldecode($request->input('q')));
-        $this->hash = hash('sha256', $this->term);
-
-        switch ($scope) {
-            case 'all':
-                $this->getHashtags();
-                $this->getPosts();
-                $this->getProfiles();
-                // $this->getPlaces();
-                break;
-
-            case 'hashtag':
-                $this->getHashtags();
-                break;
-
-            case 'profile':
-                $this->getProfiles();
-                break;
-
-            case 'webfinger':
-                $this->webfingerSearch();
-                break;
-
-            case 'remote':
-                $this->remoteLookupSearch();
-                break;
-
-            case 'place':
-                $this->getPlaces();
-                break;
-
-            default:
-                break;
-        }
-
-        return response()->json($this->tokens, 200, [], JSON_PRETTY_PRINT);
-    }
-
-    protected function getPosts()
-    {
-        $tag = $this->term;
-        $hash = hash('sha256', $tag);
-        if( Helpers::validateUrl($tag) != false && 
-            Helpers::validateLocalUrl($tag) != true && 
-            config('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) {
-                $posts = $posts->map(function($item, $key) {
-                    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()
-    {
-        $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()
-    {
-        $tag = $this->term;
-        // $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()
-        ];
-    }
-
-    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 && 
-            config('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()
-                        ]
-                    ]];
-                    return $tokens;
-                });
-            }
-        } 
-
-        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($users->count() > 0) {
-                    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()
-                            ]
-                        ];
-                    });
-                }
-            });
-        }
-    }
-
-    public function results(Request $request)
-    {
-        $this->validate($request, [
-            'q' => 'required|string|min:1',
-        ]);
-        
-        return view('search.results');
-    }
-
-    protected function webfingerSearch()
-    {
-        $wfs = WebfingerService::lookup($this->term);
-
-        if(empty($wfs)) {
-            return;
-        }
-
-        $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']
-                ]
-            ]
-        ];
-        return;
-    }
-
-    protected function remotePostLookup()
-    {
-        $tag = $this->term;
-        $hash = hash('sha256', $tag);
-        $local = Helpers::validateLocalUrl($tag);
-        $valid = Helpers::validateUrl($tag);
-
-        if($valid == false || $local == true) {
-            return;
-        } 
-            
-        if(Status::whereUri($tag)->whereLocal(false)->exists()) {
-            $item = Status::whereUri($tag)->first();
-            $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(isset($remote['type']) && $remote['type'] == 'Note') {
-            $item = Helpers::statusFetch($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()
-            ]];
-        }
-    }
-
-    protected function remoteLookupSearch()
-    {
-        if(!Helpers::validateUrl($this->term)) {
-            return;
-        }
-        $this->getProfiles();
-        $this->remotePostLookup();
-    }
-}
+	public $tokens = [];
+	public $term = '';
+	public $hash = '';
+	public $cacheKey = 'api:search:tag:';
+
+	public function __construct()
+	{
+		$this->middleware('auth');
+	}
+
+	public function searchAPI(Request $request)
+	{
+		$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';
+		$this->term = e(urldecode($request->input('q')));
+		$this->hash = hash('sha256', $this->term);
+
+		switch ($scope) {
+			case 'all':
+				$this->getHashtags();
+				$this->getPosts();
+				$this->getProfiles();
+				// $this->getPlaces();
+				break;
+
+			case 'hashtag':
+				$this->getHashtags();
+				break;
+
+			case 'profile':
+				$this->getProfiles();
+				break;
+
+			case 'webfinger':
+				$this->webfingerSearch();
+				break;
+
+			case 'remote':
+				$this->remoteLookupSearch();
+				break;
+
+			case 'place':
+				$this->getPlaces();
+				break;
+
+			default:
+				break;
+		}
+
+		return response()->json($this->tokens, 200, [], JSON_PRETTY_PRINT);
+	}
+
+	protected function getPosts()
+	{
+		$tag = $this->term;
+		$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) {
+				$posts = $posts->map(function($item, $key) {
+					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()
+	{
+		$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()
+	{
+		$tag = $this->term;
+		// $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()
+		];
+	}
+
+	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 &&
+			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()
+						]
+					]];
+					return $tokens;
+				});
+			}
+		}
+
+		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($users->count() > 0) {
+					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()
+							]
+						];
+					});
+				}
+			});
+		}
+	}
+
+	public function results(Request $request)
+	{
+		$this->validate($request, [
+			'q' => 'required|string|min:1',
+		]);
+
+		return view('search.results');
+	}
+
+	protected function webfingerSearch()
+	{
+		$wfs = WebfingerService::lookup($this->term);
+
+		if(empty($wfs)) {
+			return;
+		}
+
+		$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']
+				]
+			]
+		];
+		return;
+	}
+
+	protected function remotePostLookup()
+	{
+		$tag = $this->term;
+		$hash = hash('sha256', $tag);
+		$local = Helpers::validateLocalUrl($tag);
+		$valid = Helpers::validateUrl($tag);
+
+		if($valid == false || $local == true) {
+			return;
+		}
+
+		if(Status::whereUri($tag)->whereLocal(false)->exists()) {
+			$item = Status::whereUri($tag)->first();
+			$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(isset($remote['type']) && $remote['type'] == 'Note') {
+			$item = Helpers::statusFetch($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()
+			]];
+		}
+	}
+
+	protected function remoteLookupSearch()
+	{
+		if(!Helpers::validateUrl($this->term)) {
+			return;
+		}
+		$this->getProfiles();
+		$this->remotePostLookup();
+	}
+}

+ 7 - 2
app/Http/Controllers/StatusController.php

@@ -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);
 		}
 
 		$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'));
 	}
@@ -340,7 +345,7 @@ class StatusController extends Controller
 
 	public static function mimeTypeCheck($mimes)
 	{
-		$allowed = explode(',', config('pixelfed.media_types'));
+		$allowed = explode(',', config_cache('pixelfed.media_types'));
 		$count = count($mimes);
 		$photos = 0;
 		$videos = 0;

+ 128 - 128
app/Jobs/SharePipeline/SharePipeline.php

@@ -18,132 +18,132 @@ use App\Util\ActivityPub\HttpSignature;
 
 class SharePipeline implements ShouldQueue
 {
-    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
-
-    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.
-     *
-     * @return void
-     */
-    public function handle()
-    {
-        $status = $this->status;
-        $actor = $status->profile;
-        $target = $status->parent()->profile;
-
-        if ($status->uri !== null) {
-            // Ignore notifications to remote statuses
-            return;
-        }
-
-        $exists = Notification::whereProfileId($target->id)
-                  ->whereActorId($status->profile_id)
-                  ->whereAction('share')
-                  ->whereItemId($status->reblog_of_id)
-                  ->whereItemType('App\Status')
-                  ->count();
-
-        if ($target->id === $status->profile_id) {
-            $this->remoteAnnounceDeliver();
-            return true;
-        }
-
-        if( $exists !== 0) {
-            return true;
-        }
-
-        $this->remoteAnnounceDeliver();
-
-        try {
-            $notification = new Notification;
-            $notification->profile_id = $target->id;
-            $notification->actor_id = $actor->id;
-            $notification->action = 'share';
-            $notification->message = $status->shareToText();
-            $notification->rendered = $status->shareToHtml();
-            $notification->item_id = $status->reblog_of_id ?? $status->id;
-            $notification->item_type = "App\Status";
-            $notification->save();
-
-            $redis = Redis::connection();
-            $key = config('cache.prefix').':user.'.$status->profile_id.'.notifications';
-            $redis->lpush($key, $notification->id);
-        } catch (Exception $e) {
-            Log::error($e);
-        }
-    }
-
-    public function remoteAnnounceDeliver()
-    {
-        if(config('federation.activitypub.enabled') == false) {
-            return true;
-        }
-        $status = $this->status;
-        $profile = $status->profile;
-
-        $fractal = new Fractal\Manager();
-        $fractal->setSerializer(new ArraySerializer());
-        $resource = new Fractal\Resource\Item($status, new Announce());
-        $activity = $fractal->createData($resource)->toArray();
-
-        $audience = $status->profile->getAudienceInbox();
-
-        if(empty($audience) || $status->scope != 'public') {
-            // Return on profiles with no remote followers
-            return;
-        }
-
-        $payload = json_encode($activity);
-        
-        $client = new Client([
-            'timeout'  => config('federation.activitypub.delivery.timeout')
-        ]);
-
-        $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();
-
-    }
+	use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+	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.
+	 *
+	 * @return void
+	 */
+	public function handle()
+	{
+		$status = $this->status;
+		$actor = $status->profile;
+		$target = $status->parent()->profile;
+
+		if ($status->uri !== null) {
+			// Ignore notifications to remote statuses
+			return;
+		}
+
+		$exists = Notification::whereProfileId($target->id)
+				  ->whereActorId($status->profile_id)
+				  ->whereAction('share')
+				  ->whereItemId($status->reblog_of_id)
+				  ->whereItemType('App\Status')
+				  ->count();
+
+		if ($target->id === $status->profile_id) {
+			$this->remoteAnnounceDeliver();
+			return true;
+		}
+
+		if( $exists !== 0) {
+			return true;
+		}
+
+		$this->remoteAnnounceDeliver();
+
+		try {
+			$notification = new Notification;
+			$notification->profile_id = $target->id;
+			$notification->actor_id = $actor->id;
+			$notification->action = 'share';
+			$notification->message = $status->shareToText();
+			$notification->rendered = $status->shareToHtml();
+			$notification->item_id = $status->reblog_of_id ?? $status->id;
+			$notification->item_type = "App\Status";
+			$notification->save();
+
+			$redis = Redis::connection();
+			$key = config('cache.prefix').':user.'.$status->profile_id.'.notifications';
+			$redis->lpush($key, $notification->id);
+		} catch (Exception $e) {
+			Log::error($e);
+		}
+	}
+
+	public function remoteAnnounceDeliver()
+	{
+		if(config_cache('federation.activitypub.enabled') == false) {
+			return true;
+		}
+		$status = $this->status;
+		$profile = $status->profile;
+
+		$fractal = new Fractal\Manager();
+		$fractal->setSerializer(new ArraySerializer());
+		$resource = new Fractal\Resource\Item($status, new Announce());
+		$activity = $fractal->createData($resource)->toArray();
+
+		$audience = $status->profile->getAudienceInbox();
+
+		if(empty($audience) || $status->scope != 'public') {
+			// Return on profiles with no remote followers
+			return;
+		}
+
+		$payload = json_encode($activity);
+
+		$client = new Client([
+			'timeout'  => config('federation.activitypub.delivery.timeout')
+		]);
+
+		$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();
+
+	}
 }

+ 152 - 152
app/Jobs/StatusPipeline/StatusDelete.php

@@ -4,13 +4,14 @@ namespace App\Jobs\StatusPipeline;
 
 use DB, Storage;
 use App\{
-    AccountInterstitial,
-    MediaTag,
-    Notification,
-    Report,
-    Status,
-    StatusHashtag,
+	AccountInterstitial,
+	MediaTag,
+	Notification,
+	Report,
+	Status,
+	StatusHashtag,
 };
+use App\Models\StatusVideo;
 use Illuminate\Bus\Queueable;
 use Illuminate\Contracts\Queue\ShouldQueue;
 use Illuminate\Foundation\Bus\Dispatchable;
@@ -30,150 +31,149 @@ use App\Services\MediaStorageService;
 
 class StatusDelete implements ShouldQueue
 {
-    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
-
-    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.
-     *
-     * @return void
-     */
-    public function handle()
-    {
-        $status = $this->status;
-        $profile = $this->status->profile;
-
-        StatusService::del($status->id);
-        $count = $profile->statuses()
-        ->getQuery()
-        ->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();
-
-        if(config('federation.activitypub.enabled') == true) {
-            $this->fanoutDelete($status);
-        } else {
-            $this->unlinkRemoveMedia($status);
-        }
-
-    }
-
-    public function unlinkRemoveMedia($status)
-    {
-        foreach ($status->media as $media) {
-            MediaStorageService::delete($media, true);
-        }
-
-        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)
-                ->cursor()
-                ->each(function($tag) {
-                    Notification::where('item_type', 'App\MediaTag')
-                        ->where('item_id', $tag->id)
-                        ->forceDelete();
-                    $tag->delete();
-            });
-
-            AccountInterstitial::where('item_type', 'App\Status')
-                ->where('item_id', $status->id)
-                ->delete();
-
-            $status->forceDelete();
-        });
-
-        return true;
-    }
-
-    protected function fanoutDelete($status)
-    {
-        $audience = $status->profile->getAudienceInbox();
-        $profile = $status->profile;
-
-        $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')
-        ]);
-
-        $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();
-
-    }
+	use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+	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.
+	 *
+	 * @return void
+	 */
+	public function handle()
+	{
+		$status = $this->status;
+		$profile = $this->status->profile;
+
+		StatusService::del($status->id);
+		$count = $profile->statuses()
+		->getQuery()
+		->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();
+
+		if(config_cache('federation.activitypub.enabled') == true) {
+			$this->fanoutDelete($status);
+		} else {
+			$this->unlinkRemoveMedia($status);
+		}
+
+	}
+
+	public function unlinkRemoveMedia($status)
+	{
+		foreach ($status->media as $media) {
+			MediaStorageService::delete($media, true);
+		}
+
+		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)
+				->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();
+		});
+
+		return true;
+	}
+
+	protected function fanoutDelete($status)
+	{
+		$audience = $status->profile->getAudienceInbox();
+		$profile = $status->profile;
+
+		$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')
+		]);
+
+		$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();
+
+	}
 }

+ 142 - 142
app/Jobs/StatusPipeline/StatusEntityLexer.php

@@ -21,146 +21,146 @@ use Illuminate\Queue\SerializesModels;
 
 class StatusEntityLexer implements ShouldQueue
 {
-    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
-
-    protected $status;
-    protected $entities;
-    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.
-     *
-     * @return void
-     */
-    public function handle()
-    {
-        $profile = $this->status->profile;
-
-        $count = $profile->statuses()
-        ->getQuery()
-        ->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;
-        $profile->save();
-
-        if($profile->no_autolink == false) {
-            $this->parseEntities();
-        }
-    }
-
-    public function parseEntities()
-    {
-        $this->extractEntities();
-    }
-
-    public function extractEntities()
-    {
-        $this->entities = Extractor::create()->extract($this->status->caption);
-        $this->autolinkStatus();
-    }
-
-    public function autolinkStatus()
-    {
-        $this->autolink = Autolink::create()->autolink($this->status->caption);
-        $this->storeEntities();
-    }
-
-    public function storeEntities()
-    {
-        $this->storeHashtags();
-        DB::transaction(function () {
-            $status = $this->status;
-            $status->rendered = nl2br($this->autolink);
-            $status->entities = json_encode($this->entities);
-            $status->save();
-        });
-    }
-
-    public function storeHashtags()
-    {
-        $tags = array_unique($this->entities['hashtags']);
-        $status = $this->status;
-
-        foreach ($tags as $tag) {
-            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();
-    }
-
-    public function storeMentions()
-    {
-        $mentions = array_unique($this->entities['mentions']);
-        $status = $this->status;
-
-        foreach ($mentions as $mention) {
-            $mentioned = Profile::whereUsername($mention)->first();
-
-            if (empty($mentioned) || !isset($mentioned->id)) {
-                continue;
-            }
-
-            DB::transaction(function () use ($status, $mentioned) {
-                $m = new Mention();
-                $m->status_id = $status->id;
-                $m->profile_id = $mentioned->id;
-                $m->save();
-
-                MentionPipeline::dispatch($status, $m);
-            });
-        }
-        $this->deliver();
-    }
-
-    public function deliver()
-    {
-        $status = $this->status;
-
-        if(config('pixelfed.bouncer.enabled')) {
-            Bouncer::get($status);
-        }
-
-        if($status->uri == null && $status->scope == 'public') {
-            PublicTimelineService::add($status->id);
-        }
-
-        if(config('federation.activitypub.enabled') == true && config('app.env') == 'production') {
-            StatusActivityPubDeliver::dispatch($this->status);
-        }
-    }
+	use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+	protected $status;
+	protected $entities;
+	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.
+	 *
+	 * @return void
+	 */
+	public function handle()
+	{
+		$profile = $this->status->profile;
+
+		$count = $profile->statuses()
+		->getQuery()
+		->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;
+		$profile->save();
+
+		if($profile->no_autolink == false) {
+			$this->parseEntities();
+		}
+	}
+
+	public function parseEntities()
+	{
+		$this->extractEntities();
+	}
+
+	public function extractEntities()
+	{
+		$this->entities = Extractor::create()->extract($this->status->caption);
+		$this->autolinkStatus();
+	}
+
+	public function autolinkStatus()
+	{
+		$this->autolink = Autolink::create()->autolink($this->status->caption);
+		$this->storeEntities();
+	}
+
+	public function storeEntities()
+	{
+		$this->storeHashtags();
+		DB::transaction(function () {
+			$status = $this->status;
+			$status->rendered = nl2br($this->autolink);
+			$status->entities = json_encode($this->entities);
+			$status->save();
+		});
+	}
+
+	public function storeHashtags()
+	{
+		$tags = array_unique($this->entities['hashtags']);
+		$status = $this->status;
+
+		foreach ($tags as $tag) {
+			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();
+	}
+
+	public function storeMentions()
+	{
+		$mentions = array_unique($this->entities['mentions']);
+		$status = $this->status;
+
+		foreach ($mentions as $mention) {
+			$mentioned = Profile::whereUsername($mention)->first();
+
+			if (empty($mentioned) || !isset($mentioned->id)) {
+				continue;
+			}
+
+			DB::transaction(function () use ($status, $mentioned) {
+				$m = new Mention();
+				$m->status_id = $status->id;
+				$m->profile_id = $mentioned->id;
+				$m->save();
+
+				MentionPipeline::dispatch($status, $m);
+			});
+		}
+		$this->deliver();
+	}
+
+	public function deliver()
+	{
+		$status = $this->status;
+
+		if(config('pixelfed.bouncer.enabled')) {
+			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);
+		}
+	}
 }

+ 2 - 2
app/Util/ActivityPub/Outbox.php

@@ -13,7 +13,7 @@ class Outbox {
 
 	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);
 
         if($profile->status != null) {
@@ -48,4 +48,4 @@ class Outbox {
         return $outbox;
 	}
 
-}
+}

+ 1 - 1
app/Util/Site/Config.php

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