diff --git a/README.md b/README.md index fe8ad87a8..d2679abce 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ testing and development. ## Requirements - PHP >= 7.1.3 (7.2+ recommended for stable version) - - MySQL, Postgres (MariaDB and sqlite are not supported yet) + - MySQL >= 5.7, Postgres (MariaDB and sqlite are not supported yet) - Redis - Composer - GD or ImageMagick diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index f56d65880..985df88ed 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -20,14 +20,10 @@ class ProfileController extends Controller $user = Profile::whereUsername($username)->firstOrFail(); $settings = User::whereUsername($username)->firstOrFail()->settings; - $mimes = [ - 'application/activity+json', - 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' - ]; - - if(in_array($request->header('accept'), $mimes) && config('pixelfed.activitypub_enabled')) { + if($request->wantsJson() && config('pixelfed.activitypub_enabled')) { return $this->showActivityPub($request, $user); } + if($user->is_private == true) { $can_access = $this->privateProfileCheck($user); if($can_access !== true) { @@ -48,6 +44,18 @@ class ProfileController extends Controller return view('profile.show', compact('user', 'settings', 'owner', 'is_following', 'is_admin', 'timeline')); } + public function permalinkRedirect(Request $request, $username) + { + $user = Profile::whereUsername($username)->firstOrFail(); + $settings = User::whereUsername($username)->firstOrFail()->settings; + + if($request->wantsJson() && config('pixelfed.activitypub_enabled')) { + return $this->showActivityPub($request, $user); + } + + return redirect($user->url()); + } + protected function privateProfileCheck(Profile $profile) { if(Auth::check() === false) { diff --git a/app/Http/Controllers/StatusController.php b/app/Http/Controllers/StatusController.php index 651d632d5..57a7e41c1 100644 --- a/app/Http/Controllers/StatusController.php +++ b/app/Http/Controllers/StatusController.php @@ -3,33 +3,40 @@ namespace App\Http\Controllers; use Auth, Cache; -use App\Jobs\StatusPipeline\{NewStatusPipeline, StatusDelete}; -use App\Jobs\ImageOptimizePipeline\ImageOptimize; +use League\Fractal; use Illuminate\Http\Request; -use App\{Media, Profile, Status, User}; use Vinkla\Hashids\Facades\Hashids; +use App\{Media, Profile, Status, User}; +use App\Jobs\ImageOptimizePipeline\ImageOptimize; +use App\Transformer\ActivityPub\StatusTransformer; +use App\Jobs\StatusPipeline\{NewStatusPipeline, StatusDelete}; class StatusController extends Controller { public function show(Request $request, $username, int $id) { $user = Profile::whereUsername($username)->firstOrFail(); + $status = Status::whereProfileId($user->id) ->withCount(['likes', 'comments', 'media']) ->findOrFail($id); + if(!$status->media_path && $status->in_reply_to_id) { return redirect($status->url()); } + + if($request->wantsJson() && config('pixelfed.activitypub_enabled')) { + return $this->showActivityPub($request, $status); + } + $replies = Status::whereInReplyToId($status->id)->simplePaginate(30); + return view('status.show', compact('user', 'status', 'replies')); } public function compose() { - if(Auth::check() == false) - { - abort(403); - } + $this->authCheck(); return view('status.compose'); } @@ -156,4 +163,20 @@ class StatusController extends Controller return $response; } + + public function showActivityPub(Request $request, $status) + { + $fractal = new Fractal\Manager(); + $resource = new Fractal\Resource\Item($status, new StatusTransformer); + $res = $fractal->createData($resource)->toArray(); + return response(json_encode($res['data']))->header('Content-Type', 'application/activity+json'); + } + + protected function authCheck() + { + if(Auth::check() == false) + { + abort(403); + } + } } diff --git a/app/Transformer/ActivityPub/ProfileOutbox.php b/app/Transformer/ActivityPub/ProfileOutbox.php index 9d3b487cb..6a0e7cacc 100644 --- a/app/Transformer/ActivityPub/ProfileOutbox.php +++ b/app/Transformer/ActivityPub/ProfileOutbox.php @@ -13,7 +13,7 @@ class ProfileOutbox extends Fractal\TransformerAbstract $count = $profile->statuses()->count(); $statuses = $profile->statuses()->has('media')->orderBy('id','desc')->take(20)->get()->map(function($i, $k) { $item = [ - 'id' => $i->url(), + 'id' => $i->permalink(), // TODO: handle other types 'type' => 'Create', 'actor' => $i->profile->url(), @@ -47,7 +47,7 @@ class ProfileOutbox extends Fractal\TransformerAbstract // TODO: add cc's //"{$notice->getProfile()->getUrl()}/subscribers", ], - 'sensitive' => null, + 'sensitive' => (bool) $i->is_nsfw, 'atomUri' => $i->url(), 'inReplyToAtomUri' => null, 'conversation' => $i->url(), diff --git a/app/Transformer/ActivityPub/ProfileTransformer.php b/app/Transformer/ActivityPub/ProfileTransformer.php index f3b1b84b9..a41313e42 100644 --- a/app/Transformer/ActivityPub/ProfileTransformer.php +++ b/app/Transformer/ActivityPub/ProfileTransformer.php @@ -11,7 +11,16 @@ class ProfileTransformer extends Fractal\TransformerAbstract public function transform(Profile $profile) { return [ - '@context' => 'https://www.w3.org/ns/activitystreams', + '@context' => [ + 'https://www.w3.org/ns/activitystreams', + 'https://w3id.org/security/v1', + [ + "manuallyApprovesFollowers" => "as:manuallyApprovesFollowers", + "featured" => [ + "https://pixelfed.org/ns#featured" => ["@type" => "@id"], + ] + ] + ], 'id' => $profile->permalink(), 'type' => 'Person', 'following' => $profile->permalink('/following'), @@ -23,9 +32,9 @@ class ProfileTransformer extends Fractal\TransformerAbstract 'name' => $profile->name, 'summary' => $profile->bio, 'url' => $profile->url(), - 'manuallyApprovesFollowers' => $profile->is_private, - 'follower_count' => $profile->followers()->count(), - 'following_count' => $profile->following()->count(), + 'manuallyApprovesFollowers' => (bool) $profile->is_private, + // 'follower_count' => $profile->followers()->count(), + // 'following_count' => $profile->following()->count(), 'publicKey' => [ 'id' => $profile->permalink() . '#main-key', 'owner' => $profile->permalink(), @@ -34,7 +43,11 @@ class ProfileTransformer extends Fractal\TransformerAbstract 'endpoints' => [ 'sharedInbox' => config('routes.api.sharedInbox') ], - + 'icon' => [ + 'type' => 'Image', + 'mediaType' => 'image/jpeg', + 'url' => $profile->avatarUrl() + ] ]; } diff --git a/app/Transformer/ActivityPub/StatusTransformer.php b/app/Transformer/ActivityPub/StatusTransformer.php new file mode 100644 index 000000000..4b48b1f65 --- /dev/null +++ b/app/Transformer/ActivityPub/StatusTransformer.php @@ -0,0 +1,62 @@ + [ + 'https://www.w3.org/ns/activitystreams', + 'https://w3id.org/security/v1', + [ + "manuallyApprovesFollowers" => "as:manuallyApprovesFollowers", + "featured" => [ + "https://pixelfed.org/ns#featured" => ["@type" => "@id"], + ] + ] + ], + 'id' => $status->url(), + + // TODO: handle other types + 'type' => 'Note', + + // XXX: CW Title + 'summary' => null, + 'content' => $status->rendered ?? $status->caption, + 'inReplyTo' => null, + + // TODO: fix date format + 'published' => $status->created_at->toAtomString(), + 'url' => $status->url(), + 'attributedTo' => $status->profile->permalink(), + 'to' => [ + // TODO: handle proper scope + 'https://www.w3.org/ns/activitystreams#Public' + ], + 'cc' => [ + // TODO: add cc's + $status->profile->permalink('/followers'), + ], + 'sensitive' => (bool) $status->is_nsfw, + 'atomUri' => $status->url(), + 'inReplyToAtomUri' => null, + 'conversation' => $status->url(), + 'attachment' => $status->media->map(function($media) { + return [ + 'type' => 'Document', + 'mediaType' => $media->mime, + 'url' => $media->url(), + 'name' => null + ]; + }), + 'tag' => [] + ]; + } + +} \ No newline at end of file diff --git a/config/pixelfed.php b/config/pixelfed.php index 0717479d6..527a9f0f7 100644 --- a/config/pixelfed.php +++ b/config/pixelfed.php @@ -23,7 +23,7 @@ return [ | This value is the version of your PixelFed instance. | */ - 'version' => '0.1.5', + 'version' => '0.1.6', /* |-------------------------------------------------------------------------- diff --git a/contrib/nginx.conf b/contrib/nginx.conf index c39103d5a..850d6ed20 100644 --- a/contrib/nginx.conf +++ b/contrib/nginx.conf @@ -7,7 +7,7 @@ server { root /var/www/html/public; location / { - try_files $uri $uri/ /index.php; + try_files $uri $uri/ /$is_args$args; } location ~ \.php$ { diff --git a/resources/assets/sass/custom.scss b/resources/assets/sass/custom.scss index cb6394607..5aa67fb47 100644 --- a/resources/assets/sass/custom.scss +++ b/resources/assets/sass/custom.scss @@ -294,3 +294,7 @@ details summary::-webkit-details-marker { .details-animated[open] > summary { display: none!important; } + +.profile-avatar img { + object-fit: cover; +} diff --git a/resources/lang/en/profile.php b/resources/lang/en/profile.php index 01c79be62..9fb9d10db 100644 --- a/resources/lang/en/profile.php +++ b/resources/lang/en/profile.php @@ -4,5 +4,6 @@ return [ 'emptyTimeline' => 'This user has no posts yet!', 'emptyFollowers' => 'This user has no followers yet!', 'emptyFollowing' => 'This user is not following anyone yet!', + 'emptySaved' => 'You haven’t saved any post yet!', 'savedWarning' => 'Only you can see what you’ve saved', ]; diff --git a/resources/lang/pl/navmenu.php b/resources/lang/pl/navmenu.php index 07a94950d..dda1fbdd9 100644 --- a/resources/lang/pl/navmenu.php +++ b/resources/lang/pl/navmenu.php @@ -9,5 +9,6 @@ return [ 'settings' => 'Ustawienia', 'admin' => 'Administrator', 'logout' => 'Wyloguj się', + 'directMessages' => 'Wiadomości bezpośrednie', ]; diff --git a/resources/lang/pl/notification.php b/resources/lang/pl/notification.php index 7e453397f..d24e0b9e0 100644 --- a/resources/lang/pl/notification.php +++ b/resources/lang/pl/notification.php @@ -2,9 +2,9 @@ return [ - 'likedPhoto' => 'polubił Twoje zdjęcie.', - 'startedFollowingYou' => 'zaczął Cię obserwować.', - 'commented' => 'skomentował Twój wpis', - 'mentionedYou' => 'wspomniał o Tobie.' + 'likedPhoto' => 'polubił(a) Twoje zdjęcie.', + 'startedFollowingYou' => 'zaczął(-ęła) Cię obserwować.', + 'commented' => 'skomentował(a) Twój wpis', + 'mentionedYou' => 'wspomniał(a) o Tobie.' ]; diff --git a/resources/lang/pl/profile.php b/resources/lang/pl/profile.php index cdd0d56ae..74dd75da0 100644 --- a/resources/lang/pl/profile.php +++ b/resources/lang/pl/profile.php @@ -4,5 +4,6 @@ return [ 'emptyTimeline' => 'Ten użytkownik nie opublikował jeszcze niczego!', 'emptyFollowers' => 'Nikt nie obserwuje tego użytkownika!', 'emptyFollowing' => 'Ten użytkownik nie obserwuje nikogo!', - 'savedWarning' => 'Tylko Ty widzisz to, co zapisałeś', + 'emptySaved' => 'Nie zapisałeś(-aś) jeszcze niczego!', + 'savedWarning' => 'Tylko Ty widzisz to, co zapisałeś(-aś)', ]; diff --git a/resources/views/profile/followers.blade.php b/resources/views/profile/followers.blade.php index 670a2c7e7..aa6ef39aa 100644 --- a/resources/views/profile/followers.blade.php +++ b/resources/views/profile/followers.blade.php @@ -5,11 +5,11 @@ @include('profile.partial.user-info')
{{ __('profile.emptyTimeline') }}
+ @if($owner && request()->is('*/saved')) +{{ __('profile.emptySaved') }}
+ @else +{{ __('profile.emptyTimeline') }}
+ @endif