diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0327239a9..e2a3ae897 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
### Added
- Autocomplete Support (hashtags + mentions) ([de514f7d](https://github.com/pixelfed/pixelfed/commit/de514f7d))
- Creative Commons Licenses ([552e950](https://github.com/pixelfed/pixelfed/commit/552e950))
+- Add Network Timeline ([af7face4](https://github.com/pixelfed/pixelfed/commit/af7face4))
### Updated
- Updated AdminController, fix variable name in updateSpam method. ([6edaf940](https://github.com/pixelfed/pixelfed/commit/6edaf940))
diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php
index 85ee74281..36cdd258a 100644
--- a/app/Http/Controllers/AccountController.php
+++ b/app/Http/Controllers/AccountController.php
@@ -2,9 +2,9 @@
namespace App\Http\Controllers;
-use Auth;
-use Cache;
-use Mail;
+use Auth;
+use Cache;
+use Mail;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Str;
use Carbon\Carbon;
@@ -81,7 +81,7 @@ class AccountController extends Controller
if ($recentAttempt > 0) {
return redirect()->back()->with('error', 'A verification email has already been sent recently. Please check your email, or try again later.');
- }
+ }
EmailVerification::whereUserId(Auth::id())->delete();
@@ -247,7 +247,7 @@ class AccountController extends Controller
switch ($type) {
case 'user':
$profile = Profile::findOrFail($item);
- if ($profile->id == $user->id || $profile->user->is_admin == true) {
+ if ($profile->id == $user->id || ($profile->user && $profile->user->is_admin == true)) {
return abort(403);
}
$class = get_class($profile);
@@ -394,7 +394,7 @@ class AccountController extends Controller
$request->session()->pull('sudoModeAttempts');
Auth::logout();
return redirect(route('login'));
- }
+ }
return view('auth.sudo');
}
@@ -485,7 +485,7 @@ class AccountController extends Controller
}
} else {
return false;
- }
+ }
}
public function accountRestored(Request $request)
diff --git a/app/Http/Controllers/PublicApiController.php b/app/Http/Controllers/PublicApiController.php
index 7e1d6623e..23231b218 100644
--- a/app/Http/Controllers/PublicApiController.php
+++ b/app/Http/Controllers/PublicApiController.php
@@ -223,7 +223,7 @@ class PublicApiController extends Controller
{
if($profile->is_private == true && Auth::check() == false) {
abort(404);
- }
+ }
switch ($status->scope) {
case 'public':
@@ -248,7 +248,7 @@ class PublicApiController extends Controller
case 'draft':
abort(404);
break;
-
+
default:
abort(404);
break;
@@ -291,11 +291,11 @@ class PublicApiController extends Controller
$dir = $min ? '>' : '<';
$id = $min ?? $max;
$timeline = Status::select(
- 'id',
+ 'id',
'uri',
'caption',
'rendered',
- 'profile_id',
+ 'profile_id',
'type',
'in_reply_to_id',
'reblog_of_id',
@@ -320,11 +320,11 @@ class PublicApiController extends Controller
->get();
} else {
$timeline = Status::select(
- 'id',
+ 'id',
'uri',
'caption',
'rendered',
- 'profile_id',
+ 'profile_id',
'type',
'in_reply_to_id',
'reblog_of_id',
@@ -351,7 +351,6 @@ class PublicApiController extends Controller
$fractal = new Fractal\Resource\Collection($timeline, new StatusTransformer());
$res = $this->fractal->createData($fractal)->toArray();
return response()->json($res);
-
}
public function homeTimelineApi(Request $request)
@@ -372,7 +371,7 @@ class PublicApiController extends Controller
$max = $request->input('max_id');
$limit = $request->input('limit') ?? 3;
$user = $request->user();
-
+
$key = 'user:last_active_at:id:'.$user->id;
$ttl = now()->addMinutes(5);
Cache::remember($key, $ttl, function() use($user) {
@@ -396,7 +395,7 @@ class PublicApiController extends Controller
// ->orWhere('status', '!=', null)
// ->pluck('id');
// });
-
+
// $private = $private->diff($following)->flatten();
// $filters = UserFilter::whereUserId($pid)
@@ -411,11 +410,11 @@ class PublicApiController extends Controller
$dir = $min ? '>' : '<';
$id = $min ?? $max;
$timeline = Status::select(
- 'id',
+ 'id',
'uri',
'caption',
'rendered',
- 'profile_id',
+ 'profile_id',
'type',
'in_reply_to_id',
'reblog_of_id',
@@ -440,11 +439,11 @@ class PublicApiController extends Controller
->get();
} else {
$timeline = Status::select(
- 'id',
+ 'id',
'uri',
'caption',
'rendered',
- 'profile_id',
+ 'profile_id',
'type',
'in_reply_to_id',
'reblog_of_id',
@@ -470,12 +469,96 @@ class PublicApiController extends Controller
$fractal = new Fractal\Resource\Collection($timeline, new StatusTransformer());
$res = $this->fractal->createData($fractal)->toArray();
return response()->json($res);
-
}
public function networkTimelineApi(Request $request)
{
- return response()->json([]);
+ abort_if(!Auth::check(), 403);
+ abort_if(config('federation.network_timeline') == false, 404);
+
+ $this->validate($request,[
+ 'page' => 'nullable|integer|max:40',
+ 'min_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
+ 'max_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
+ 'limit' => 'nullable|integer|max:30'
+ ]);
+
+ $page = $request->input('page');
+ $min = $request->input('min_id');
+ $max = $request->input('max_id');
+ $limit = $request->input('limit') ?? 3;
+ $user = $request->user();
+
+ $key = 'user:last_active_at:id:'.$user->id;
+ $ttl = now()->addMinutes(5);
+ Cache::remember($key, $ttl, function() use($user) {
+ $user->last_active_at = now();
+ $user->save();
+ return;
+ });
+
+ if($min || $max) {
+ $dir = $min ? '>' : '<';
+ $id = $min ?? $max;
+ $timeline = Status::select(
+ 'id',
+ 'uri',
+ 'caption',
+ 'rendered',
+ 'profile_id',
+ 'type',
+ 'in_reply_to_id',
+ 'reblog_of_id',
+ 'is_nsfw',
+ 'scope',
+ 'local',
+ 'reply_count',
+ 'comments_disabled',
+ 'place_id',
+ 'likes_count',
+ 'reblogs_count',
+ 'created_at',
+ 'updated_at'
+ )->where('id', $dir, $id)
+ ->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
+ ->whereNotNull('uri')
+ ->whereScope('public')
+ // ->where('created_at', '>', now()->subMonths(3))
+ ->orderBy('created_at', 'desc')
+ ->limit($limit)
+ ->get();
+ } else {
+ $timeline = Status::select(
+ 'id',
+ 'uri',
+ 'caption',
+ 'rendered',
+ 'profile_id',
+ 'type',
+ 'in_reply_to_id',
+ 'reblog_of_id',
+ 'is_nsfw',
+ 'scope',
+ 'local',
+ 'reply_count',
+ 'comments_disabled',
+ 'created_at',
+ 'place_id',
+ 'likes_count',
+ 'reblogs_count',
+ 'updated_at'
+ )->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
+ ->with('profile', 'hashtags', 'mentions')
+ ->whereNotNull('uri')
+ ->whereScope('public')
+ ->where('created_at', '>', now()->subMonths(3))
+ ->orderBy('created_at', 'desc')
+ ->simplePaginate($limit);
+ }
+
+ $fractal = new Fractal\Resource\Collection($timeline, new StatusTransformer());
+ $res = $this->fractal->createData($fractal)->toArray();
+ return response()->json($res);
}
public function relationships(Request $request)
@@ -489,7 +572,7 @@ class PublicApiController extends Controller
'id.*' => 'required|integer'
]);
$ids = collect($request->input('id'));
- $filtered = $ids->filter(function($v) {
+ $filtered = $ids->filter(function($v) {
return $v != Auth::user()->profile->id;
});
$relations = Profile::whereNull('status')->findOrFail($filtered->all());
@@ -569,10 +652,10 @@ class PublicApiController extends Controller
$limit = $request->limit ?? 9;
$max_id = $request->max_id;
$min_id = $request->min_id;
- $scope = $request->only_media == true ?
+ $scope = $request->only_media == true ?
['photo', 'photo:album', 'video', 'video:album'] :
['photo', 'photo:album', 'video', 'video:album', 'share', 'reply'];
-
+
if($profile->is_private) {
if(!Auth::check()) {
return response()->json([]);
@@ -605,11 +688,11 @@ class PublicApiController extends Controller
$dir = '>';
$id = 1;
$timeline = Status::select(
- 'id',
+ 'id',
'uri',
'caption',
'rendered',
- 'profile_id',
+ 'profile_id',
'type',
'in_reply_to_id',
'reblog_of_id',
@@ -643,11 +726,11 @@ class PublicApiController extends Controller
$dir = $min_id ? '>' : '<';
$id = $min_id ?? $max_id;
$timeline = Status::select(
- 'id',
+ 'id',
'uri',
'caption',
'rendered',
- 'profile_id',
+ 'profile_id',
'type',
'in_reply_to_id',
'reblog_of_id',
diff --git a/app/Http/Controllers/TimelineController.php b/app/Http/Controllers/TimelineController.php
index 52267b2d7..ba03a5d63 100644
--- a/app/Http/Controllers/TimelineController.php
+++ b/app/Http/Controllers/TimelineController.php
@@ -2,37 +2,32 @@
namespace App\Http\Controllers;
-use Auth, Cache;
-use App\Follower;
-use App\Profile;
-use App\Status;
-use App\User;
-use App\UserFilter;
use Illuminate\Http\Request;
class TimelineController extends Controller
{
- public function __construct()
- {
- $this->middleware('auth');
- $this->middleware('twofactor');
- }
+ public function __construct()
+ {
+ $this->middleware('auth');
+ $this->middleware('twofactor');
+ }
- public function local(Request $request)
- {
- $this->validate($request, [
- 'layout' => 'nullable|string|in:grid,feed'
- ]);
- $layout = $request->input('layout', 'feed');
- return view('timeline.local', compact('layout'));
- }
+ public function local(Request $request)
+ {
+ $this->validate($request, [
+ 'layout' => 'nullable|string|in:grid,feed'
+ ]);
+ $layout = $request->input('layout', 'feed');
+ return view('timeline.local', compact('layout'));
+ }
- public function network(Request $request)
- {
- $this->validate($request, [
- 'layout' => 'nullable|string|in:grid,feed'
- ]);
- $layout = $request->input('layout', 'feed');
- return view('timeline.network', compact('layout'));
- }
+ public function network(Request $request)
+ {
+ abort_if(config('federation.network_timeline') == false, 404);
+ $this->validate($request, [
+ 'layout' => 'nullable|string|in:grid,feed'
+ ]);
+ $layout = $request->input('layout', 'feed');
+ return view('timeline.network', compact('layout'));
+ }
}
diff --git a/config/federation.php b/config/federation.php
index 81e687fe3..0e51d7dfe 100644
--- a/config/federation.php
+++ b/config/federation.php
@@ -10,7 +10,6 @@ return [
| ActivityPub configuration
|
*/
-
'activitypub' => [
'enabled' => env('ACTIVITY_PUB', false),
'outbox' => env('AP_OUTBOX', true),
@@ -41,4 +40,6 @@ return [
'enabled' => env('WEBFINGER', true)
],
-];
\ No newline at end of file
+ 'network_timeline' => env('PF_NETWORK_TIMELINE', false)
+
+];
diff --git a/public/js/mode-dot.js b/public/js/mode-dot.js
index 3770f2662..74719c40f 100644
Binary files a/public/js/mode-dot.js and b/public/js/mode-dot.js differ
diff --git a/public/js/network-timeline.js b/public/js/network-timeline.js
new file mode 100644
index 000000000..07715e9e6
Binary files /dev/null and b/public/js/network-timeline.js differ
diff --git a/public/js/profile-directory.js b/public/js/profile-directory.js
index ec442eacf..78d265d64 100644
Binary files a/public/js/profile-directory.js and b/public/js/profile-directory.js differ
diff --git a/public/js/profile.js b/public/js/profile.js
index 4cc3b0c00..d38395de2 100644
Binary files a/public/js/profile.js and b/public/js/profile.js differ
diff --git a/public/js/quill.js b/public/js/quill.js
index d18b5786f..c729e43a2 100644
Binary files a/public/js/quill.js and b/public/js/quill.js differ
diff --git a/public/js/rempos.js b/public/js/rempos.js
index 001c24a72..6d6761210 100644
Binary files a/public/js/rempos.js and b/public/js/rempos.js differ
diff --git a/public/js/rempro.js b/public/js/rempro.js
index dec7b851c..e7aad28e7 100644
Binary files a/public/js/rempro.js and b/public/js/rempro.js differ
diff --git a/public/js/search.js b/public/js/search.js
index d0c96a5d6..44ab6760a 100644
Binary files a/public/js/search.js and b/public/js/search.js differ
diff --git a/public/js/status.js b/public/js/status.js
index 493beead1..eb60eb2c2 100644
Binary files a/public/js/status.js and b/public/js/status.js differ
diff --git a/public/js/story-compose.js b/public/js/story-compose.js
index 1fcbde913..0ec660912 100644
Binary files a/public/js/story-compose.js and b/public/js/story-compose.js differ
diff --git a/public/js/theme-monokai.js b/public/js/theme-monokai.js
index 37080367b..88f12f95b 100644
Binary files a/public/js/theme-monokai.js and b/public/js/theme-monokai.js differ
diff --git a/public/js/timeline.js b/public/js/timeline.js
index 5ebe82173..03f70edcd 100644
Binary files a/public/js/timeline.js and b/public/js/timeline.js differ
diff --git a/public/js/vendor.js b/public/js/vendor.js
index d76fb694c..9ded13190 100644
Binary files a/public/js/vendor.js and b/public/js/vendor.js differ
diff --git a/public/mix-manifest.json b/public/mix-manifest.json
index 77222962e..6e8e03661 100644
Binary files a/public/mix-manifest.json and b/public/mix-manifest.json differ
diff --git a/resources/assets/js/components/NetworkTimeline.vue b/resources/assets/js/components/NetworkTimeline.vue
new file mode 100644
index 000000000..8737480b4
--- /dev/null
+++ b/resources/assets/js/components/NetworkTimeline.vue
@@ -0,0 +1,2197 @@
+
+
+
+ Error: Problem rendering preview.
+
+
+ For information about COVID-19, {{config.features.label.covid.org}}
+
+
+
+
+ Hello, {{profile.acct}}
+ Start following people to build your timeline. {{profile.username || 'loading...'}} {{profile.display_name || 'loading...'}} Comments
+
+
+
+ No comments yet
+
+
+
+
+
+ The network timeline may contain unmoderated and/or NSFW content from other servers. View the timeline documentation for more info.Suggestions For You
+
+ #{{hashtagPostsName}}
+
+
+
+ + {{s.account.username}} + + + + + + +
++ + {{s.favourites_count == 1 ? '1 like' : s.favourites_count + ' likes'}} +
+