diff --git a/app/Http/Controllers/FederationController.php b/app/Http/Controllers/FederationController.php index 98bd9f52b..2511b9984 100644 --- a/app/Http/Controllers/FederationController.php +++ b/app/Http/Controllers/FederationController.php @@ -48,8 +48,8 @@ class FederationController extends Controller { $this->authCheck(); $this->validate($request, [ - 'url' => 'required|string', - ]); + 'url' => 'required|string', + ]); if (config('pixelfed.remote_follow_enabled') !== true) { abort(403); @@ -123,16 +123,15 @@ class FederationController extends Controller { $this->validate($request, ['resource'=>'required|string|min:3|max:255']); - $hash = hash('sha256', $request->input('resource')); - - $webfinger = Cache::remember('api:webfinger:'.$hash, 1440, function () use ($request) { - $resource = $request->input('resource'); - $parsed = Nickname::normalizeProfileUrl($resource); - $username = $parsed['username']; - $user = Profile::whereUsername($username)->firstOrFail(); - - return (new Webfinger($user))->generate(); - }); + $resource = $request->input('resource'); + $hash = hash('sha256', $resource); + $parsed = Nickname::normalizeProfileUrl($resource); + $username = $parsed['username']; + $profile = Profile::whereUsername($username)->firstOrFail(); + if($profile->status != null) { + return ProfileController::accountCheck($profile); + } + $webfinger = (new Webfinger($profile))->generate(); return response()->json($webfinger, 200, [], JSON_PRETTY_PRINT); } @@ -156,13 +155,16 @@ XML; abort(403); } - $user = Profile::whereNull('remote_url')->whereUsername($username)->firstOrFail(); - if($user->is_private) { + $profile = Profile::whereNull('remote_url')->whereUsername($username)->firstOrFail(); + if($profile->status != null) { + return ProfileController::accountCheck($profile); + } + if($profile->is_private) { return response()->json(['error'=>'403', 'msg' => 'private profile'], 403); } - $timeline = $user->statuses()->whereVisibility('public')->orderBy('created_at', 'desc')->paginate(10); + $timeline = $profile->statuses()->whereVisibility('public')->orderBy('created_at', 'desc')->paginate(10); $fractal = new Fractal\Manager(); - $resource = new Fractal\Resource\Item($user, new ProfileOutbox()); + $resource = new Fractal\Resource\Item($profile, new ProfileOutbox()); $res = $fractal->createData($resource)->toArray(); return response(json_encode($res['data']))->header('Content-Type', 'application/activity+json'); @@ -175,6 +177,9 @@ XML; } $profile = Profile::whereNull('domain')->whereUsername($username)->firstOrFail(); + if($profile->status != null) { + return ProfileController::accountCheck($profile); + } $body = $request->getContent(); $bodyDecoded = json_decode($body, true); $signature = $request->header('signature'); @@ -205,6 +210,9 @@ XML; ->whereUsername($username) ->whereIsPrivate(false) ->firstOrFail(); + if($profile->status != null) { + return ProfileController::accountCheck($profile); + } $obj = [ '@context' => 'https://www.w3.org/ns/activitystreams', 'id' => $request->getUri(), @@ -226,6 +234,9 @@ XML; ->whereUsername($username) ->whereIsPrivate(false) ->firstOrFail(); + if($profile->status != null) { + return ProfileController::accountCheck($profile); + } $obj = [ '@context' => 'https://www.w3.org/ns/activitystreams', 'id' => $request->getUri(), diff --git a/app/Http/Controllers/FollowerController.php b/app/Http/Controllers/FollowerController.php index 808effa10..e312a2938 100644 --- a/app/Http/Controllers/FollowerController.php +++ b/app/Http/Controllers/FollowerController.php @@ -37,7 +37,7 @@ class FollowerController extends Controller protected function handleFollowRequest($item) { $user = Auth::user()->profile; - $target = Profile::where('id', '!=', $user->id)->findOrFail($item); + $target = Profile::where('id', '!=', $user->id)->whereNull('status')->findOrFail($item); $private = (bool) $target->is_private; $blocked = UserFilter::whereUserId($target->id) ->whereFilterType('block') diff --git a/app/Http/Controllers/InternalApiController.php b/app/Http/Controllers/InternalApiController.php index fb4cdcde9..e2c6b24ca 100644 --- a/app/Http/Controllers/InternalApiController.php +++ b/app/Http/Controllers/InternalApiController.php @@ -112,6 +112,7 @@ class InternalApiController extends Controller $people = Profile::select('id', 'name', 'username') ->with('avatar') + ->whereNull('status') ->orderByRaw('rand()') ->whereHas('statuses') ->whereNull('domain') @@ -206,6 +207,9 @@ class InternalApiController extends Controller $posts = Status::select('id', 'caption', 'profile_id') ->whereHas('media') + ->whereHas('profile', function($q) { + return $q->whereNull('status'); + }) ->whereIsNsfw(false) ->whereVisibility('public') ->whereNotIn('profile_id', $following) diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 3d5137f49..070fc3086 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -20,7 +20,11 @@ class ProfileController extends Controller public function show(Request $request, $username) { $user = Profile::whereUsername($username)->firstOrFail(); - return $this->buildProfile($request, $user); + if($user->status != null) { + return $this->accountCheck($user); + } else { + return $this->buildProfile($request, $user); + } } // TODO: refactor this mess @@ -30,7 +34,11 @@ class ProfileController extends Controller $loggedIn = Auth::check(); $isPrivate = false; $isBlocked = false; - + + if($user->status != null) { + return ProfileController::accountCheck($user); + } + if ($user->remote_url) { $settings = new \StdClass; $settings->crawlable = false; @@ -118,8 +126,27 @@ class ProfileController extends Controller return false; } + public static function accountCheck(Profile $profile) + { + switch ($profile->status) { + case 'disabled': + case 'delete': + return view('profile.disabled'); + break; + + default: + # code... + break; + } + + return abort(404); + } + public function showActivityPub(Request $request, $user) { + if($user->status != null) { + return ProfileController::accountCheck($user); + } $fractal = new Fractal\Manager(); $resource = new Fractal\Resource\Item($user, new ProfileTransformer); $res = $fractal->createData($resource)->toArray(); @@ -129,6 +156,9 @@ class ProfileController extends Controller public function showAtomFeed(Request $request, $user) { $profile = $user = Profile::whereUsername($user)->firstOrFail(); + if($profile->status != null) { + return $this->accountCheck($profile); + } if($profile->is_private || Auth::check()) { $blocked = $this->blockedProfileCheck($profile); $check = $this->privateProfileCheck($profile, null); @@ -144,7 +174,9 @@ class ProfileController extends Controller public function followers(Request $request, $username) { $profile = $user = Profile::whereUsername($username)->firstOrFail(); - + if($profile->status != null) { + return $this->accountCheck($profile); + } // TODO: fix $profile/$user mismatch in profile & follower templates $owner = Auth::check() && Auth::id() === $user->user_id; $is_following = ($owner == false && Auth::check()) ? $user->followedBy(Auth::user()->profile) : false; @@ -155,7 +187,7 @@ class ProfileController extends Controller return view('profile.private', compact('user', 'is_following')); } } - $followers = $profile->followers()->orderBy('created_at', 'desc')->simplePaginate(12); + $followers = $profile->followers()->whereNull('status')->orderBy('created_at', 'desc')->simplePaginate(12); $is_admin = is_null($user->domain) ? $user->user->is_admin : false; if ($user->remote_url) { $settings = new \StdClass; @@ -172,6 +204,9 @@ class ProfileController extends Controller public function following(Request $request, $username) { $profile = $user = Profile::whereUsername($username)->firstOrFail(); + if($profile->status != null) { + return $this->accountCheck($profile); + } // TODO: fix $profile/$user mismatch in profile & follower templates $owner = Auth::check() && Auth::id() === $user->user_id; $is_following = ($owner == false && Auth::check()) ? $user->followedBy(Auth::user()->profile) : false; @@ -182,7 +217,7 @@ class ProfileController extends Controller return view('profile.private', compact('user', 'is_following')); } } - $following = $profile->following()->orderBy('created_at', 'desc')->simplePaginate(12); + $following = $profile->following()->whereNull('status')->orderBy('created_at', 'desc')->simplePaginate(12); $is_admin = is_null($user->domain) ? $user->user->is_admin : false; if ($user->remote_url) { $settings = new \StdClass; @@ -201,7 +236,10 @@ class ProfileController extends Controller if (Auth::check() === false || $username !== Auth::user()->username) { abort(403); } - $user = Auth::user()->profile; + $user = $profile = Auth::user()->profile; + if($profile->status != null) { + return $this->accountCheck($profile); + } $settings = User::whereUsername($username)->firstOrFail()->settings; $owner = true; $following = false; diff --git a/app/Http/Controllers/PublicApiController.php b/app/Http/Controllers/PublicApiController.php index 6260b2f90..779716fe3 100644 --- a/app/Http/Controllers/PublicApiController.php +++ b/app/Http/Controllers/PublicApiController.php @@ -43,6 +43,9 @@ class PublicApiController extends Controller return []; } else { $profile = Auth::user()->profile; + if($profile->status) { + return []; + } $user = new Fractal\Resource\Item($profile, new AccountTransformer()); return $this->fractal->createData($user)->toArray(); } @@ -54,6 +57,9 @@ class PublicApiController extends Controller return []; } else { $profile = Auth::user()->profile; + if($profile->status) { + return []; + } $likes = $status->likedBy()->orderBy('created_at','desc')->paginate(10); $collection = new Fractal\Resource\Collection($likes, new AccountTransformer()); return $this->fractal->createData($collection)->toArray(); @@ -74,8 +80,8 @@ class PublicApiController extends Controller public function status(Request $request, $username, int $postid) { - $profile = Profile::whereUsername($username)->first(); - $status = Status::whereProfileId($profile->id)->find($postid); + $profile = Profile::whereUsername($username)->whereNull('status')->firstOrFail(); + $status = Status::whereProfileId($profile->id)->findOrFail($postid); $this->scopeCheck($profile, $status); $item = new Fractal\Resource\Item($status, new StatusTransformer()); $res = [ @@ -100,8 +106,8 @@ class PublicApiController extends Controller 'limit' => 'nullable|integer|min:5|max:50' ]); $limit = $request->limit ?? 10; - $profile = Profile::whereUsername($username)->first(); - $status = Status::whereProfileId($profile->id)->find($postId); + $profile = Profile::whereUsername($username)->whereNull('status')->firstOrFail(); + $status = Status::whereProfileId($profile->id)->findOrFail($postId); $this->scopeCheck($profile, $status); if($request->filled('min_id') || $request->filled('max_id')) { if($request->filled('min_id')) { @@ -133,8 +139,8 @@ class PublicApiController extends Controller public function statusLikes(Request $request, $username, $id) { - $profile = Profile::whereUsername($username)->first(); - $status = Status::whereProfileId($profile->id)->find($id); + $profile = Profile::whereUsername($username)->whereNull('status')->firstOrFail(); + $status = Status::whereProfileId($profile->id)->findOrFail($id); $this->scopeCheck($profile, $status); $likes = $this->getLikes($status); return response()->json([ @@ -144,8 +150,8 @@ class PublicApiController extends Controller public function statusShares(Request $request, $username, $id) { - $profile = Profile::whereUsername($username)->first(); - $status = Status::whereProfileId($profile->id)->find($id); + $profile = Profile::whereUsername($username)->whereNull('status')->firstOrFail(); + $status = Status::whereProfileId($profile->id)->findOrFail($id); $this->scopeCheck($profile, $status); $shares = $this->getShares($status); return response()->json([ @@ -210,7 +216,7 @@ class PublicApiController extends Controller // $timeline = Timeline::build()->local(); $pid = Auth::user()->profile->id; - $private = Profile::whereIsPrivate(true)->where('id', '!=', $pid)->pluck('id'); + $private = Profile::whereIsPrivate(true)->orWhereNotNull('status')->where('id', '!=', $pid)->pluck('id'); $filters = UserFilter::whereUserId($pid) ->whereFilterableType('App\Profile') ->whereIn('filter_type', ['mute', 'block']) @@ -272,7 +278,7 @@ class PublicApiController extends Controller $following = Follower::whereProfileId($pid)->pluck('following_id'); $following->push($pid)->toArray(); - $private = Profile::whereIsPrivate(true)->where('id', '!=', $pid)->pluck('id'); + $private = Profile::whereIsPrivate(true)->orWhereNotNull('status')->where('id', '!=', $pid)->pluck('id'); $filters = UserFilter::whereUserId($pid) ->whereFilterableType('App\Profile') ->whereIn('filter_type', ['mute', 'block']) diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php index 5a0af8d1e..36103d528 100644 --- a/app/Http/Controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -22,7 +22,7 @@ class SearchController extends Controller return; } $hash = hash('sha256', $tag); - $tokens = Cache::remember('api:search:tag:'.$hash, 60, function () use ($tag) { + $tokens = Cache::remember('api:search:tag:'.$hash, 5, function () use ($tag) { $tokens = collect([]); $hashtags = Hashtag::select('id', 'name', 'slug')->where('slug', 'like', '%'.$tag.'%')->limit(20)->get(); if($hashtags->count() > 0) { @@ -39,6 +39,7 @@ class SearchController extends Controller $tokens->push($tags); } $users = Profile::select('username', 'name', 'id') + ->whereNull('status') ->where('username', 'like', '%'.$tag.'%') ->limit(20) ->get(); diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index 9f4f116fe..a41295007 100644 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -5,10 +5,8 @@ namespace App\Http\Controllers; use App\AccountLog; use App\Following; use App\UserFilter; -use Auth; -use DB; -use Cache; -use Purify; +use Auth, DB, Cache, Purify; +use Carbon\Carbon; use Illuminate\Http\Request; use App\Http\Controllers\Settings\{ HomeSettings, @@ -137,6 +135,18 @@ class SettingsController extends Controller return view('settings.remove.temporary'); } + public function removeAccountTemporarySubmit(Request $request) + { + $user = Auth::user(); + $profile = $user->profile; + $user->status = 'disabled'; + $profile->status = 'disabled'; + $user->save(); + $profile->save(); + Auth::logout(); + return redirect('/'); + } + public function removeAccountPermanent(Request $request) { return view('settings.remove.permanent'); @@ -148,7 +158,14 @@ class SettingsController extends Controller if($user->is_admin == true) { return abort(400, 'You cannot delete an admin account.'); } - DeleteAccountPipeline::dispatch($user); + $profile = $user->profile; + $ts = Carbon::now()->addMonth(); + $user->status = 'delete'; + $profile->status = 'delete'; + $user->delete_after = $ts; + $profile->delete_after = $ts; + $user->save(); + $profile->save(); Auth::logout(); return redirect('/'); } diff --git a/app/Http/Controllers/StatusController.php b/app/Http/Controllers/StatusController.php index 8c04bbf4a..a32817faa 100644 --- a/app/Http/Controllers/StatusController.php +++ b/app/Http/Controllers/StatusController.php @@ -21,10 +21,22 @@ class StatusController extends Controller { $user = Profile::whereUsername($username)->firstOrFail(); + if($user->status != null) { + return ProfileController::accountCheck($user); + } + $status = Status::whereProfileId($user->id) ->whereNotIn('visibility',['draft','direct']) ->findOrFail($id); + if($status->uri) { + $url = $status->uri; + if(ends_with($url, '/activity')) { + $url = str_replace('/activity', '', $url); + } + return redirect($url); + } + if($status->visibility == 'private' || $user->is_private) { if(!Auth::check()) { abort(403); diff --git a/app/Jobs/StatusPipeline/NewStatusPipeline.php b/app/Jobs/StatusPipeline/NewStatusPipeline.php index 7c1af199f..816b515fb 100644 --- a/app/Jobs/StatusPipeline/NewStatusPipeline.php +++ b/app/Jobs/StatusPipeline/NewStatusPipeline.php @@ -37,11 +37,9 @@ class NewStatusPipeline implements ShouldQueue $status = $this->status; StatusEntityLexer::dispatch($status); - StatusActivityPubDeliver::dispatch($status); - - Cache::forever('post.'.$status->id, $status); - - $redis = Redis::connection(); - $redis->lpush(config('cache.prefix').':user.'.$status->profile_id.'.posts', $status->id); + + // Cache::forever('post.'.$status->id, $status); + // $redis = Redis::connection(); + // $redis->lpush(config('cache.prefix').':user.'.$status->profile_id.'.posts', $status->id); } } diff --git a/app/Jobs/StatusPipeline/StatusActivityPubDeliver.php b/app/Jobs/StatusPipeline/StatusActivityPubDeliver.php index 466dbcd99..1100f0988 100644 --- a/app/Jobs/StatusPipeline/StatusActivityPubDeliver.php +++ b/app/Jobs/StatusPipeline/StatusActivityPubDeliver.php @@ -38,6 +38,10 @@ class StatusActivityPubDeliver implements ShouldQueue { $status = $this->status; + if($status->local == true || $status->url || $status->uri) { + return; + } + $audience = $status->profile->getAudienceInbox(); $profile = $status->profile; @@ -49,7 +53,5 @@ class StatusActivityPubDeliver implements ShouldQueue foreach($audience as $url) { Helpers::sendSignedObject($profile, $url, $activity); } - - // todo: fanout on write } } diff --git a/app/Jobs/StatusPipeline/StatusEntityLexer.php b/app/Jobs/StatusPipeline/StatusEntityLexer.php index 7bf50adc3..e089c8992 100644 --- a/app/Jobs/StatusPipeline/StatusEntityLexer.php +++ b/app/Jobs/StatusPipeline/StatusEntityLexer.php @@ -42,7 +42,6 @@ class StatusEntityLexer implements ShouldQueue */ public function handle() { - $status = $this->status; $this->parseEntities(); } @@ -73,6 +72,7 @@ class StatusEntityLexer implements ShouldQueue $status->entities = json_encode($this->entities); $status->save(); }); + StatusActivityPubDeliver::dispatch($this->status); } public function storeHashtags() diff --git a/app/Listeners/AuthLogin.php b/app/Listeners/AuthLogin.php index a69f86f81..ea29aa88d 100644 --- a/app/Listeners/AuthLogin.php +++ b/app/Listeners/AuthLogin.php @@ -61,5 +61,30 @@ class AuthLogin CreateAvatar::dispatch($profile); }); } + + if($user->status != null) { + $profile = $user->profile; + switch ($user->status) { + case 'disabled': + $profile->status = null; + $user->status = null; + $profile->save(); + $user->save(); + break; + + case 'delete': + $profile->status = null; + $profile->delete_after = null; + $user->status = null; + $user->delete_after = null; + $profile->save(); + $user->save(); + break; + + default: + # code... + break; + } + } } } diff --git a/app/Util/ActivityPub/Helpers.php b/app/Util/ActivityPub/Helpers.php index 2da8c09f8..b1cd2909e 100644 --- a/app/Util/ActivityPub/Helpers.php +++ b/app/Util/ActivityPub/Helpers.php @@ -7,6 +7,7 @@ use App\{ Activity, Follower, Like, + Media, Notification, Profile, Status @@ -281,11 +282,11 @@ class Helpers { public static function profileFirstOrNew($url, $runJobs = false) { $res = self::fetchProfileFromUrl($url); - $domain = parse_url($res['url'], PHP_URL_HOST); + $domain = parse_url($res['id'], PHP_URL_HOST); $username = $res['preferredUsername']; $remoteUsername = "@{$username}@{$domain}"; - $profile = Profile::whereRemoteUrl($res['url'])->first(); + $profile = Profile::whereRemoteUrl($res['id'])->first(); if(!$profile) { $profile = new Profile; $profile->domain = $domain; @@ -295,7 +296,7 @@ class Helpers { $profile->sharedInbox = isset($res['endpoints']) && isset($res['endpoints']['sharedInbox']) ? $res['endpoints']['sharedInbox'] : null; $profile->inbox_url = $res['inbox']; $profile->outbox_url = $res['outbox']; - $profile->remote_url = $res['url']; + $profile->remote_url = $res['id']; $profile->public_key = $res['publicKey']['publicKeyPem']; $profile->key_id = $res['publicKey']['id']; $profile->save(); diff --git a/app/Util/ActivityPub/Inbox.php b/app/Util/ActivityPub/Inbox.php index 83d5578f9..0a3fcd8c5 100644 --- a/app/Util/ActivityPub/Inbox.php +++ b/app/Util/ActivityPub/Inbox.php @@ -32,7 +32,7 @@ class Inbox public function handle() { - $this->authenticatePayload(); + $this->handleVerb(); } public function authenticatePayload() @@ -142,16 +142,11 @@ class Inbox $activity = $this->payload['object']; $actor = $this->actorFirstOrCreate($this->payload['actor']); $inReplyTo = $activity['inReplyTo']; + $url = $activity['id']; - if(!Helpers::statusFirstOrFetch($activity['url'], true)) { - $this->logger->delete(); + if(!Helpers::statusFirstOrFetch($url, true)) { return; } - - $this->logger->to_id = $this->profile->id; - $this->logger->from_id = $actor->id; - $this->logger->processed_at = Carbon::now(); - $this->logger->save(); } public function handleNoteCreate() @@ -164,12 +159,11 @@ class Inbox if(Helpers::userInAudience($this->profile, $this->payload) == false) { //Log::error('AP:inbox:userInAudience:false - Activity#'.$this->logger->id); - $logger = Activity::find($this->logger->id); - $logger->delete(); return; } - if(Status::whereUrl($activity['url'])->exists()) { + $url = $activity['id']; + if(Status::whereUrl($url)->exists()) { return; } @@ -178,18 +172,12 @@ class Inbox $status->profile_id = $actor->id; $status->caption = strip_tags($activity['content']); $status->visibility = $status->scope = 'public'; - $status->url = $activity['url']; + $status->url = $url; $status->save(); return $status; }); Helpers::importNoteAttachment($activity, $status); - - $logger = Activity::find($this->logger->id); - $logger->to_id = $this->profile->id; - $logger->from_id = $actor->id; - $logger->processed_at = Carbon::now(); - $logger->save(); } public function handleFollowActivity() @@ -214,7 +202,6 @@ class Inbox 'local_profile' => empty($actor->domain) ]); if($follower->wasRecentlyCreated == false) { - $this->logger->delete(); return; } // send notification @@ -228,37 +215,53 @@ class Inbox $notification->item_type = "App\Profile"; $notification->save(); - \Cache::forever('notification.'.$notification->id, $notification); - - $redis = Redis::connection(); - - $nkey = config('cache.prefix').':user.'.$target->id.'.notifications'; - $redis->lpush($nkey, $notification->id); - // send Accept to remote profile $accept = [ '@context' => 'https://www.w3.org/ns/activitystreams', - 'id' => $follower->permalink('/accept'), + 'id' => $target->permalink().'#accepts/follows/', 'type' => 'Accept', 'actor' => $target->permalink(), 'object' => [ - 'id' => $this->payload['id'], + 'id' => $actor->permalink('#follows/'.$target->id), 'type' => 'Follow', - 'actor' => $target->permalink(), - 'object' => $actor->permalink() + 'actor' => $actor->permalink(), + 'object' => $target->permalink() ] ]; Helpers::sendSignedObject($target, $actor->inbox_url, $accept); } - $this->logger->to_id = $target->id; - $this->logger->from_id = $actor->id; - $this->logger->processed_at = Carbon::now(); - $this->logger->save(); } public function handleAnnounceActivity() { - + $actor = $this->actorFirstOrCreate($this->payload['actor']); + $activity = $this->payload['object']; + if(!$actor || $actor->domain == null) { + return; + } + if(Helpers::validateLocalUrl($activity) == false) { + return; + } + $parent = Helpers::statusFirstOrFetch($activity, true); + if(!$parent) { + return; + } + $status = Status::firstOrCreate([ + 'profile_id' => $actor->id, + 'in_reply_to_id' => $parent->id, + 'type' => 'reply' + ]); + if($status->wasRecentlyCreated) { + $notification = new Notification(); + $notification->profile_id = $parent->profile->id; + $notification->actor_id = $actor->id; + $notification->action = 'comment'; + $notification->message = $status->toText(); + $notification->rendered = $status->toHtml(); + $notification->item_id = $parent->id; + $notification->item_type = "App\Status"; + $notification->save(); + } } public function handleAcceptActivity() @@ -268,7 +271,19 @@ class Inbox public function handleDeleteActivity() { + $actor = $this->payload['actor']; + $obj = $this->payload['object']; + if(is_string($obj) && Helpers::validateUrl($obj)) { + // actor object detected + } else if (is_array($obj) && isset($obj['type']) && $obj['type'] == 'Tombstone') { + // tombstone detected + $status = Status::whereUri($obj['id'])->first(); + if($status == null) { + return; + } + $status->forceDelete(); + } } public function handleLikeActivity() @@ -289,10 +304,6 @@ class Inbox return; } LikePipeline::dispatch($like); - $this->logger->to_id = $status->profile_id; - $this->logger->from_id = $profile->id; - $this->logger->processed_at = Carbon::now(); - $this->logger->save(); } @@ -306,19 +317,29 @@ class Inbox $actor = $this->payload['actor']; $profile = self::actorFirstOrCreate($actor); $obj = $this->payload['object']; - $status = Helpers::statusFirstOrFetch($obj['object']); switch ($obj['type']) { case 'Like': + $status = Helpers::statusFirstOrFetch($obj['object']); Like::whereProfileId($profile->id) ->whereStatusId($status->id) - ->delete(); + ->forceDelete(); + break; + + case 'Announce': + $parent = Helpers::statusFirstOrFetch($obj['object']); + $status = Status::whereProfileId($profile->id) + ->whereReblogOfId($parent->id) + ->first(); + Notification::whereProfileId($parent->profile->id) + ->whereActorId($profile->id) + ->whereAction('share') + ->whereItemId($status->id) + ->whereItemType('App\Status') + ->forceDelete(); + $status->forceDelete(); break; } - $this->logger->to_id = $status->profile_id; - $this->logger->from_id = $profile->id; - $this->logger->processed_at = Carbon::now(); - $this->logger->save(); } } diff --git a/database/migrations/2018_12_24_032921_add_delete_after_to_user_table.php b/database/migrations/2018_12_24_032921_add_delete_after_to_user_table.php new file mode 100644 index 000000000..70ea6bd2e --- /dev/null +++ b/database/migrations/2018_12_24_032921_add_delete_after_to_user_table.php @@ -0,0 +1,40 @@ +timestamp('delete_after')->nullable(); + }); + + Schema::table('users', function (Blueprint $table) { + $table->timestamp('delete_after')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('profiles', function (Blueprint $table) { + $table->dropColumn('delete_after'); + }); + + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('delete_after'); + }); + } +} diff --git a/package-lock.json b/package-lock.json index 8545e1add..a78060635 100644 --- a/package-lock.json +++ b/package-lock.json @@ -104,11 +104,15 @@ "json-schema-traverse": "^0.3.0" } }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==" + }, "ajv-keywords": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", - "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", - "dev": true + "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=" }, "align-text": { "version": "0.1.4", @@ -164,7 +168,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -199,7 +202,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "requires": { "sprintf-js": "~1.0.2" } @@ -632,6 +634,11 @@ "babel-types": "^6.24.1" } }, + "babel-helper-vue-jsx-merge-props": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz", + "integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==" + }, "babel-helpers": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", @@ -1243,8 +1250,7 @@ "big.js": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", - "dev": true + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" }, "binary-extensions": { "version": "1.11.0", @@ -1253,9 +1259,9 @@ "dev": true }, "blob": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", - "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" }, "block-stream": { "version": "0.0.9", @@ -1328,9 +1334,9 @@ } }, "bootstrap": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.1.3.tgz", - "integrity": "sha512-rDFIzgXcof0jDyjNosjv4Sno77X4KuPeFxG2XZZv1/Kc8DRVGVADdoQyyOVDwPqL36DDmtCQbrpMCqvpPLJQ0w==" + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.2.1.tgz", + "integrity": "sha512-tt/7vIv3Gm2mnd/WeDx36nfGGHleil0Wg8IeB7eMrVkY0fZ5iTaBisSh8oNANc2IBsCc6vCgCNTIM/IEN0+50Q==" }, "bootstrap-vue": { "version": "2.0.0-rc.11", @@ -1651,7 +1657,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -1884,7 +1889,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -1892,8 +1896,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "color-string": { "version": "0.3.0", @@ -2123,7 +2126,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-4.0.0.tgz", "integrity": "sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ==", - "dev": true, "requires": { "is-directory": "^0.3.1", "js-yaml": "^3.9.0", @@ -2134,14 +2136,12 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "js-yaml": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", - "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -2151,7 +2151,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, "requires": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -2842,11 +2841,72 @@ "minimalistic-crypto-utils": "^1.0.0" } }, + "emoji-mart-vue": { + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/emoji-mart-vue/-/emoji-mart-vue-2.6.6.tgz", + "integrity": "sha512-844CI/Sa99G6goiZN6u+zT5XxB4wUhpYYTK8s3FrU2fl9y0ckbqe0uw7EuY0R53hb4bo9uJHVOPywE+C4vu4fg==", + "requires": { + "postcss-loader": "^3.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz", + "integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "postcss": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.7.tgz", + "integrity": "sha512-HThWSJEPkupqew2fnuQMEI2YcTj/8gMV3n80cMdJsKxfIh5tHf7nM5JigNX6LxVMqo6zkgQNAI88hyFvBk41Pg==", + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.5.0" + } + }, + "postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" }, "encodeurl": { "version": "1.0.2", @@ -2872,9 +2932,9 @@ } }, "engine.io-client": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", - "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.3.1.tgz", + "integrity": "sha512-q66JBFuQcy7CSlfAz9L3jH+v7DTT3i6ZEadYcVj2pOs8/0uJHLxKX3WBkGTvULJMdz0tUCyJag0aKT/dpXL9BQ==", "requires": { "component-emitter": "1.2.1", "component-inherit": "0.0.3", @@ -2884,20 +2944,20 @@ "indexof": "0.0.1", "parseqs": "0.0.5", "parseuri": "0.0.5", - "ws": "~3.3.1", + "ws": "~6.1.0", "xmlhttprequest-ssl": "~1.5.4", "yeast": "0.1.2" } }, "engine.io-parser": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", - "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", "requires": { "after": "0.8.2", "arraybuffer.slice": "~0.0.7", "base64-arraybuffer": "0.1.5", - "blob": "0.0.4", + "blob": "0.0.5", "has-binary2": "~1.0.2" } }, @@ -2926,7 +2986,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "requires": { "is-arrayish": "^0.2.1" } @@ -3458,8 +3517,7 @@ "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "fastparse": { "version": "1.1.1", @@ -4563,8 +4621,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-unicode": { "version": "2.0.1", @@ -4945,7 +5002,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", - "dev": true, "requires": { "import-from": "^2.1.0" } @@ -4954,7 +5010,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", - "dev": true, "requires": { "resolve-from": "^3.0.0" } @@ -5141,8 +5196,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-binary-path": { "version": "1.0.1", @@ -5222,8 +5276,7 @@ "is-directory": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=" }, "is-dotfile": { "version": "1.0.3", @@ -5477,8 +5530,7 @@ "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, "json-schema": { "version": "0.2.3", @@ -5507,8 +5559,7 @@ "json5": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, "jsonfile": { "version": "3.0.1", @@ -5544,9 +5595,9 @@ "dev": true }, "laravel-echo": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/laravel-echo/-/laravel-echo-1.4.0.tgz", - "integrity": "sha512-O0vkToCCpxuH9dYAlugTLQzG0BmxvGrjXim0LHZ0VPsFu/Y+sXnV9GvYbmcBq1rcJymQc/6GHMUCDY01lN26lQ==" + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/laravel-echo/-/laravel-echo-1.5.2.tgz", + "integrity": "sha512-Xw9QsxJKapv0C2UTnXRRIM1+epL3+qaSRGd7V8pXEuIHnxjcdpk2I7YLauDzYhBNMKEKWtlE/sv9Wgs+hYKnbg==" }, "laravel-mix": { "version": "2.1.14", @@ -5638,7 +5689,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", - "dev": true, "requires": { "big.js": "^3.1.3", "emojis-list": "^2.0.0", @@ -6642,6 +6692,11 @@ } } }, + "opencollective-postinstall": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.1.tgz", + "integrity": "sha512-saQQ9hjLwu/oS0492eyYotoh+bra1819cfAT5rjY/e4REWwuc8IgZ844Oo44SiftWcJuBiqp0SA0BFVbmLX0IQ==" + }, "opn": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", @@ -6964,9 +7019,9 @@ } }, "popper.js": { - "version": "1.14.4", - "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.4.tgz", - "integrity": "sha1-juwdj/AqWjoVLdQ0FKFce3n9abY=" + "version": "1.14.6", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.6.tgz", + "integrity": "sha512-AGwHGQBKumlk/MDfrSOf0JHhJCImdDMcGNoqKmKkU+68GFazv3CQ6q9r7Ja1sKDZmYWTckY/uLyEznheTDycnA==" }, "portfinder": { "version": "1.0.17", @@ -7662,7 +7717,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.0.0.tgz", "integrity": "sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ==", - "dev": true, "requires": { "cosmiconfig": "^4.0.0", "import-cwd": "^2.0.0" @@ -9591,8 +9645,7 @@ "require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" }, "require-main-filename": { "version": "1.0.1", @@ -9627,8 +9680,7 @@ "resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" }, "resolve-url": { "version": "0.2.1", @@ -9759,7 +9811,8 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "safe-regex": { "version": "1.1.0", @@ -10208,30 +10261,30 @@ } }, "socket.io-client": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", - "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.2.0.tgz", + "integrity": "sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA==", "requires": { "backo2": "1.0.2", "base64-arraybuffer": "0.1.5", "component-bind": "1.0.0", "component-emitter": "1.2.1", "debug": "~3.1.0", - "engine.io-client": "~3.2.0", + "engine.io-client": "~3.3.1", "has-binary2": "~1.0.2", "has-cors": "1.1.0", "indexof": "0.0.1", "object-component": "0.0.3", "parseqs": "0.0.5", "parseuri": "0.0.5", - "socket.io-parser": "~3.2.0", + "socket.io-parser": "~3.3.0", "to-array": "0.1.4" } }, "socket.io-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", - "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", + "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", "requires": { "component-emitter": "1.2.1", "debug": "~3.1.0", @@ -10307,8 +10360,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-resolve": { "version": "0.5.2", @@ -10441,8 +10493,7 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sshpk": { "version": "1.14.2", @@ -10636,7 +10687,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -10657,9 +10707,9 @@ } }, "sweetalert": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sweetalert/-/sweetalert-2.1.0.tgz", - "integrity": "sha512-9YKj0SvjKyBfRWco50UOsIbXVeifYbxzT9Qda7EsqC01eafHGCSG0IR7g942ufjzt7lnwO8ZZBwr6emXv2fQrg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/sweetalert/-/sweetalert-2.1.2.tgz", + "integrity": "sha512-iWx7X4anRBNDa/a+AdTmvAzQtkN1+s4j/JJRWlHpYE8Qimkohs8/XnFcWeYHH2lMA8LRCa5tj2d244If3S/hzA==", "requires": { "es6-object-assign": "^1.1.0", "promise-polyfill": "^6.0.2" @@ -10989,11 +11039,6 @@ } } }, - "ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" - }, "union-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", @@ -11127,7 +11172,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, "requires": { "punycode": "^2.1.0" }, @@ -11135,8 +11179,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" } } }, @@ -11263,11 +11306,19 @@ } }, "vue": { - "version": "2.5.17", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.5.17.tgz", - "integrity": "sha512-mFbcWoDIJi0w0Za4emyLiW72Jae0yjANHbCVquMKijcavBGypqlF7zHRgMa5k4sesdv7hv2rB4JPdZfR+TPfhQ==", + "version": "2.5.21", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.5.21.tgz", + "integrity": "sha512-Aejvyyfhn0zjVeLvXd70h4hrE4zZDx1wfZqia6ekkobLmUZ+vNFQer53B4fu0EjWBSiqApxPejzkO1Znt3joxQ==", "dev": true }, + "vue-content-loader": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/vue-content-loader/-/vue-content-loader-0.2.1.tgz", + "integrity": "sha1-DrMy4qcmQ9V/sgnXLWUmVzsZH1o=", + "requires": { + "babel-helper-vue-jsx-merge-props": "^2.0.3" + } + }, "vue-functional-data-merge": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/vue-functional-data-merge/-/vue-functional-data-merge-2.0.7.tgz", @@ -11347,9 +11398,9 @@ } }, "vue-loading-overlay": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/vue-loading-overlay/-/vue-loading-overlay-3.1.0.tgz", - "integrity": "sha512-EJOaqxfkSwt6LRoKYnWWPch6fLRRzHWFxLBnRHjXHIK/fP0MSmbBLh9ZRpxarXJeDBiyykQevDXa7h7809JaAA==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/vue-loading-overlay/-/vue-loading-overlay-3.1.1.tgz", + "integrity": "sha512-6Iv0V/S++/LDRR3bgIZDJwBTgMVupuj+hjDb2YzTrEXbSEygtD10eJwZdMnEenLcD3ZAFz5D30qkNUYow9W2kw==" }, "vue-style-loader": { "version": "3.1.2", @@ -11362,9 +11413,9 @@ } }, "vue-template-compiler": { - "version": "2.5.17", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.5.17.tgz", - "integrity": "sha512-63uI4syCwtGR5IJvZM0LN5tVsahrelomHtCxvRkZPJ/Tf3ADm1U1wG6KWycK3qCfqR+ygM5vewUvmJ0REAYksg==", + "version": "2.5.21", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.5.21.tgz", + "integrity": "sha512-Vmk5Cv7UcmI99B9nXJEkaK262IQNnHp5rJYo+EwYpe2epTAXqcVyExhV6pk8jTkxQK2vRc8v8KmZBAwdmUZvvw==", "dev": true, "requires": { "de-indent": "^1.0.2", @@ -11747,13 +11798,11 @@ "dev": true }, "ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.2.tgz", + "integrity": "sha512-rfUqzvz0WxmSXtJpPMX2EeASXabOrSMk1ruMOV3JBTBjo4ac2lDjGGsbQSyxj8Odhw5fBib8ZKEjDNvgouNKYw==", "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" + "async-limiter": "~1.0.0" } }, "xmlhttprequest": { diff --git a/package.json b/package.json index 6c173a69e..e29fcd2dc 100644 --- a/package.json +++ b/package.json @@ -12,29 +12,32 @@ }, "devDependencies": { "axios": "^0.18", - "bootstrap": "^4.1.3", + "bootstrap": "^4.2.1", "cross-env": "^5.2.0", "jquery": "^3.2", "laravel-mix": "^2.1.14", "lodash": "^4.17.11", - "popper.js": "^1.14.4", - "vue": "^2.5.17" + "popper.js": "^1.14.6", + "vue": "^2.5.21", + "vue-template-compiler": "^2.5.21" }, "dependencies": { "bootstrap-vue": "^2.0.0-rc.11", + "emoji-mart-vue": "^2.6.6", "filesize": "^3.6.1", "infinite-scroll": "^3.0.4", - "laravel-echo": "^1.4.0", + "laravel-echo": "^1.5.2", "opencollective": "^1.0.3", "opencollective-postinstall": "^2.0.1", "plyr": "^3.4.7", "pusher-js": "^4.2.2", "readmore-js": "^2.2.1", - "socket.io-client": "^2.1.1", - "sweetalert": "^2.1.0", + "socket.io-client": "^2.2.0", + "sweetalert": "^2.1.2", "twitter-text": "^2.0.5", + "vue-content-loader": "^0.2.1", "vue-infinite-loading": "^2.4.3", - "vue-loading-overlay": "^3.1.0", + "vue-loading-overlay": "^3.1.1", "vue-timeago": "^5.0.0" }, "collective": { diff --git a/public/css/app.css b/public/css/app.css index c67c44c2b..3b4cd8d33 100644 Binary files a/public/css/app.css and b/public/css/app.css differ diff --git a/public/js/app.js b/public/js/app.js index 5b053d40f..fec8c511d 100644 Binary files a/public/js/app.js and b/public/js/app.js differ diff --git a/public/js/components.js b/public/js/components.js index 5391eb0d1..176e33265 100644 Binary files a/public/js/components.js and b/public/js/components.js differ diff --git a/public/mix-manifest.json b/public/mix-manifest.json index d536dcc40..54baaeb40 100644 Binary files a/public/mix-manifest.json and b/public/mix-manifest.json differ diff --git a/resources/assets/js/components.js b/resources/assets/js/components.js index e1cbe2415..50aa36bda 100644 --- a/resources/assets/js/components.js +++ b/resources/assets/js/components.js @@ -2,7 +2,7 @@ window.Vue = require('vue'); import BootstrapVue from 'bootstrap-vue' import InfiniteLoading from 'vue-infinite-loading'; import Loading from 'vue-loading-overlay'; -import VueTimeago from 'vue-timeago' +import VueTimeago from 'vue-timeago'; Vue.use(BootstrapVue); Vue.use(InfiniteLoading); @@ -36,8 +36,8 @@ require('./components/commentform'); require('./components/searchform'); require('./components/bookmarkform'); require('./components/statusform'); -require('./components/embed'); -require('./components/notifications'); +//require('./components/embed'); +//require('./components/notifications'); // import Echo from "laravel-echo" @@ -78,12 +78,16 @@ Vue.component( require('./components/presenter/VideoAlbumPresenter.vue') ); - Vue.component( 'mixed-album-presenter', require('./components/presenter/MixedAlbumPresenter.vue') ); +// Vue.component( +// 'micro', +// require('./components/Micro.vue') +// ); + Vue.component( 'follow-suggestions', require('./components/FollowSuggestions.vue') @@ -114,11 +118,6 @@ Vue.component( require('./components/Timeline.vue') ); -// Vue.component( -// 'micro', -// require('./components/Micro.vue') -// ); - Vue.component( 'passport-clients', require('./components/passport/Clients.vue') diff --git a/resources/assets/js/components/Timeline.vue b/resources/assets/js/components/Timeline.vue index 1a68ca3c7..baf48c9c8 100644 --- a/resources/assets/js/components/Timeline.vue +++ b/resources/assets/js/components/Timeline.vue @@ -3,7 +3,9 @@
-
+
+ Loading... +
@@ -101,7 +103,9 @@
-
+
+ Loading... +
@@ -142,7 +146,9 @@

-
+
+ Loading... +
diff --git a/resources/lang/en/profile.php b/resources/lang/en/profile.php index 73e4e3207..7851852a2 100644 --- a/resources/lang/en/profile.php +++ b/resources/lang/en/profile.php @@ -9,4 +9,7 @@ return [ 'privateProfileWarning' => 'This Account is Private', 'alreadyFollow' => 'Already follow :username?', 'loginToSeeProfile' => 'to see their photos and videos.', + + 'status.disabled.header' => 'Profile Unavailable', + 'status.disabled.body' => 'Sorry, this profile is not available at the moment. Please try again shortly.', ]; diff --git a/resources/views/profile/disabled.blade.php b/resources/views/profile/disabled.blade.php new file mode 100644 index 000000000..f18c0e8d5 --- /dev/null +++ b/resources/views/profile/disabled.blade.php @@ -0,0 +1,18 @@ +@extends('layouts.app',['title' => "Account Temporarily Unavailable"]) + +@section('content') +
+
+
+
+

+ {{__('profile.status.disabled.header')}} +

+

+ {{__('profile.status.disabled.body')}} +

+
+
+
+
+@endsection \ No newline at end of file diff --git a/resources/views/settings/home.blade.php b/resources/views/settings/home.blade.php index 7a82d9a8b..aadee58d6 100644 --- a/resources/views/settings/home.blade.php +++ b/resources/views/settings/home.blade.php @@ -82,8 +82,9 @@

-
- +
diff --git a/resources/views/settings/remove/permanent.blade.php b/resources/views/settings/remove/permanent.blade.php index 91eb5987f..b95aa2894 100644 --- a/resources/views/settings/remove/permanent.blade.php +++ b/resources/views/settings/remove/permanent.blade.php @@ -22,7 +22,7 @@

@csrf -
+
diff --git a/resources/views/settings/remove/temporary.blade.php b/resources/views/settings/remove/temporary.blade.php new file mode 100644 index 000000000..21ec25ace --- /dev/null +++ b/resources/views/settings/remove/temporary.blade.php @@ -0,0 +1,30 @@ +@extends('settings.template') + +@section('section') + +
+

Temporarily Disable Your Account

+
+
+
+

Hi {{Auth::user()->username}},

+ +

You can disable your account instead of deleting it. This means your account will be hidden until you reactivate it by logging back in.

+ +

You can only disable your account once a week.

+ +

Keeping Your Data Safe

+

Nothing is more important to us than the safety and security of this community. People put their trust in us by sharing moments of their lives on Pixelfed. So we will never make any compromises when it comes to safeguarding your data.

+ +

When you press the button below, your photos, comments and likes will be hidden until you reactivate your account by logging back in.

+ +

+ + @csrf + +

+

+
+ + +@endsection \ No newline at end of file diff --git a/routes/api.php b/routes/api.php index 852967954..74c67eaf9 100644 --- a/routes/api.php +++ b/routes/api.php @@ -12,3 +12,5 @@ use Illuminate\Http\Request; | is assigned the "api" middleware group. Enjoy building your API! | */ + +Route::post('/users/{username}/inbox', 'FederationController@userInbox'); diff --git a/routes/web.php b/routes/web.php index 9356e4c9a..8aebe6e90 100644 --- a/routes/web.php +++ b/routes/web.php @@ -76,6 +76,7 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::post('follow', 'FollowerController@store')->middleware('throttle:250,1440'); Route::post('bookmark', 'BookmarkController@store')->middleware('throttle:250,1440'); Route::get('lang/{locale}', 'SiteController@changeLocale'); + Route::get('restored', 'AccountController@accountRestored'); Route::get('verify-email', 'AccountController@verifyEmail'); Route::post('verify-email', 'AccountController@sendVerifyEmail')->middleware('throttle:10,1440'); @@ -133,12 +134,12 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::get('privacy/blocked-instances', 'SettingsController@blockedInstances')->name('settings.privacy.blocked-instances'); // Todo: Release in 0.7.2 - // Route::group(['prefix' => 'remove', 'middleware' => 'dangerzone'], function() { - // Route::get('request/temporary', 'SettingsController@removeAccountTemporary')->name('settings.remove.temporary'); - // Route::post('request/temporary', 'SettingsController@removeAccountTemporarySubmit'); - // Route::get('request/permanent', 'SettingsController@removeAccountPermanent')->name('settings.remove.permanent'); - // Route::post('request/permanent', 'SettingsController@removeAccountPermanentSubmit'); - // }); + Route::group(['prefix' => 'remove', 'middleware' => 'dangerzone'], function() { + Route::get('request/temporary', 'SettingsController@removeAccountTemporary')->name('settings.remove.temporary'); + Route::post('request/temporary', 'SettingsController@removeAccountTemporarySubmit'); + Route::get('request/permanent', 'SettingsController@removeAccountPermanent')->name('settings.remove.permanent'); + Route::post('request/permanent', 'SettingsController@removeAccountPermanentSubmit'); + }); Route::group(['prefix' => 'security', 'middleware' => 'dangerzone'], function() { Route::get(