mirror of
https://github.com/pixelfed/pixelfed.git
synced 2024-11-27 08:43:17 +00:00
commit
a2c56c4e71
26 changed files with 228 additions and 74 deletions
|
@ -19,6 +19,14 @@
|
||||||
- Updated ApiV1Controller, improve follow count cache invalidation. ([4b6effb9](https://github.com/pixelfed/pixelfed/commit/4b6effb9))
|
- Updated ApiV1Controller, improve follow count cache invalidation. ([4b6effb9](https://github.com/pixelfed/pixelfed/commit/4b6effb9))
|
||||||
- Updated web routes, fix atom feeds for account usernames containing a dot. ([8c54ab57](https://github.com/pixelfed/pixelfed/commit/8c54ab57))
|
- Updated web routes, fix atom feeds for account usernames containing a dot. ([8c54ab57](https://github.com/pixelfed/pixelfed/commit/8c54ab57))
|
||||||
- Updated atom feeds, include media alt text. Fixes #3184. ([5d9b6863](https://github.com/pixelfed/pixelfed/commit/5d9b6863))
|
- Updated atom feeds, include media alt text. Fixes #3184. ([5d9b6863](https://github.com/pixelfed/pixelfed/commit/5d9b6863))
|
||||||
|
- Updated ApiV1Controller, add custom_emoji endpoint. ([16e72518](https://github.com/pixelfed/pixelfed/commit/16e72518))
|
||||||
|
- Updated InternalApiController, redirect remote post and profiles to Metro 2.0. ([3c35158e](https://github.com/pixelfed/pixelfed/commit/3c35158e))
|
||||||
|
- Updated BaseApiController, improve favourites endpoint. ([f063cb01](https://github.com/pixelfed/pixelfed/commit/f063cb01))
|
||||||
|
- Updated ApiV1Controller, invalidate status reply cache on new reply. ([3c261bbf](https://github.com/pixelfed/pixelfed/commit/3c261bbf))
|
||||||
|
- Updated PublicApiController, add bookmark state to timeline endpoints. ([c0b1e042](https://github.com/pixelfed/pixelfed/commit/c0b1e042))
|
||||||
|
- Updated ApiV1Controller, fix private status replies returning 404. ([73226360](https://github.com/pixelfed/pixelfed/commit/73226360))
|
||||||
|
- Updated StatusService, use BookmarkService for bookmarked state. ([a7d71551](https://github.com/pixelfed/pixelfed/commit/a7d71551))
|
||||||
|
- Updated Apis, added ReblogService to improve reblogged state for api entities ([6cfd6be5](https://github.com/pixelfed/pixelfed/commit/6cfd6be5))
|
||||||
- ([](https://github.com/pixelfed/pixelfed/commit/))
|
- ([](https://github.com/pixelfed/pixelfed/commit/))
|
||||||
|
|
||||||
## [v0.11.2 (2022-01-09)](https://github.com/pixelfed/pixelfed/compare/v0.11.1...v0.11.2)
|
## [v0.11.2 (2022-01-09)](https://github.com/pixelfed/pixelfed/compare/v0.11.1...v0.11.2)
|
||||||
|
|
|
@ -360,6 +360,7 @@ class AdminController extends Controller
|
||||||
|
|
||||||
if($request->has('cc')) {
|
if($request->has('cc')) {
|
||||||
Cache::forget('pf:admin:custom_emoji:stats');
|
Cache::forget('pf:admin:custom_emoji:stats');
|
||||||
|
Cache::forget('pf:custom_emoji');
|
||||||
return redirect(route('admin.custom-emoji'));
|
return redirect(route('admin.custom-emoji'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,6 +464,7 @@ class AdminController extends Controller
|
||||||
$request->emoji->storeAs('public/emoji', $fileName);
|
$request->emoji->storeAs('public/emoji', $fileName);
|
||||||
$emoji->media_path = 'emoji/' . $fileName;
|
$emoji->media_path = 'emoji/' . $fileName;
|
||||||
$emoji->save();
|
$emoji->save();
|
||||||
|
Cache::forget('pf:custom_emoji');
|
||||||
return redirect(route('admin.custom-emoji'));
|
return redirect(route('admin.custom-emoji'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,6 +473,7 @@ class AdminController extends Controller
|
||||||
abort_unless(config('federation.custom_emoji.enabled'), 404);
|
abort_unless(config('federation.custom_emoji.enabled'), 404);
|
||||||
$emoji = CustomEmoji::findOrFail($id);
|
$emoji = CustomEmoji::findOrFail($id);
|
||||||
Storage::delete("public/{$emoji->media_path}");
|
Storage::delete("public/{$emoji->media_path}");
|
||||||
|
Cache::forget('pf:custom_emoji');
|
||||||
$emoji->delete();
|
$emoji->delete();
|
||||||
return redirect(route('admin.custom-emoji'));
|
return redirect(route('admin.custom-emoji'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,7 @@ use App\Services\{
|
||||||
NotificationService,
|
NotificationService,
|
||||||
MediaPathService,
|
MediaPathService,
|
||||||
PublicTimelineService,
|
PublicTimelineService,
|
||||||
|
ReblogService,
|
||||||
RelationshipService,
|
RelationshipService,
|
||||||
SearchApiV2Service,
|
SearchApiV2Service,
|
||||||
StatusService,
|
StatusService,
|
||||||
|
@ -77,6 +78,7 @@ use App\Util\Localization\Localization;
|
||||||
use App\Util\Media\License;
|
use App\Util\Media\License;
|
||||||
use App\Jobs\MediaPipeline\MediaSyncLicensePipeline;
|
use App\Jobs\MediaPipeline\MediaSyncLicensePipeline;
|
||||||
use App\Services\DiscoverService;
|
use App\Services\DiscoverService;
|
||||||
|
use App\Services\CustomEmojiService;
|
||||||
|
|
||||||
class ApiV1Controller extends Controller
|
class ApiV1Controller extends Controller
|
||||||
{
|
{
|
||||||
|
@ -920,7 +922,7 @@ class ApiV1Controller extends Controller
|
||||||
*/
|
*/
|
||||||
public function customEmojis()
|
public function customEmojis()
|
||||||
{
|
{
|
||||||
return response()->json([]);
|
return response(CustomEmojiService::all())->header('Content-Type', 'application/json');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1645,6 +1647,7 @@ class ApiV1Controller extends Controller
|
||||||
|
|
||||||
if($pid) {
|
if($pid) {
|
||||||
$status['favourited'] = (bool) LikeService::liked($pid, $s['id']);
|
$status['favourited'] = (bool) LikeService::liked($pid, $s['id']);
|
||||||
|
$status['reblogged'] = (bool) ReblogService::get($pid, $status['id']);
|
||||||
}
|
}
|
||||||
return $status;
|
return $status;
|
||||||
})
|
})
|
||||||
|
@ -1675,6 +1678,7 @@ class ApiV1Controller extends Controller
|
||||||
|
|
||||||
if($pid) {
|
if($pid) {
|
||||||
$status['favourited'] = (bool) LikeService::liked($pid, $s['id']);
|
$status['favourited'] = (bool) LikeService::liked($pid, $s['id']);
|
||||||
|
$status['reblogged'] = (bool) ReblogService::get($pid, $status['id']);
|
||||||
}
|
}
|
||||||
return $status;
|
return $status;
|
||||||
})
|
})
|
||||||
|
@ -1797,6 +1801,7 @@ class ApiV1Controller extends Controller
|
||||||
|
|
||||||
if($user) {
|
if($user) {
|
||||||
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $k);
|
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $k);
|
||||||
|
$status['reblogged'] = (bool) ReblogService::get($user->profile_id, $status['id']);
|
||||||
}
|
}
|
||||||
return $status;
|
return $status;
|
||||||
})
|
})
|
||||||
|
@ -1838,7 +1843,7 @@ class ApiV1Controller extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
$res['favourited'] = LikeService::liked($user->profile_id, $res['id']);
|
$res['favourited'] = LikeService::liked($user->profile_id, $res['id']);
|
||||||
$res['reblogged'] = false;
|
$res['reblogged'] = ReblogService::get($user->profile_id, $res['id']);
|
||||||
return response()->json($res);
|
return response()->json($res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2109,6 +2114,7 @@ class ApiV1Controller extends Controller
|
||||||
$status->in_reply_to_profile_id = $parent->profile_id;
|
$status->in_reply_to_profile_id = $parent->profile_id;
|
||||||
$status->save();
|
$status->save();
|
||||||
StatusService::del($parent->id);
|
StatusService::del($parent->id);
|
||||||
|
Cache::forget('status:replies:all:' . $parent->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($ids) {
|
if($ids) {
|
||||||
|
@ -2236,7 +2242,7 @@ class ApiV1Controller extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusService::del($status->id);
|
StatusService::del($status->id);
|
||||||
|
ReblogService::add($user->profile_id, $status->id);
|
||||||
$res = StatusService::getMastodon($status->id);
|
$res = StatusService::getMastodon($status->id);
|
||||||
$res['reblogged'] = true;
|
$res['reblogged'] = true;
|
||||||
|
|
||||||
|
@ -2276,6 +2282,7 @@ class ApiV1Controller extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
UndoSharePipeline::dispatch($reblog);
|
UndoSharePipeline::dispatch($reblog);
|
||||||
|
ReblogService::del($user->profile_id, $status->id);
|
||||||
|
|
||||||
$res = StatusService::getMastodon($status->id);
|
$res = StatusService::getMastodon($status->id);
|
||||||
$res['reblogged'] = true;
|
$res['reblogged'] = true;
|
||||||
|
@ -2512,12 +2519,25 @@ class ApiV1Controller extends Controller
|
||||||
|
|
||||||
$limit = $request->input('limit', 3);
|
$limit = $request->input('limit', 3);
|
||||||
$pid = $request->user()->profile_id;
|
$pid = $request->user()->profile_id;
|
||||||
$status = StatusService::getMastodon($id);
|
$status = StatusService::getMastodon($id, false);
|
||||||
|
|
||||||
abort_if(!$status || !in_array($status['visibility'], ['public', 'unlisted']), 404);
|
abort_if(!$status, 404);
|
||||||
|
|
||||||
|
if($status['visibility'] == 'private') {
|
||||||
|
if($pid != $status['account']['id']) {
|
||||||
|
abort_unless(FollowerService::follows($pid, $status['account']['id']), 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$sortBy = $request->input('sort', 'all');
|
$sortBy = $request->input('sort', 'all');
|
||||||
|
|
||||||
|
if($sortBy == 'all' && $status['replies_count'] && $request->has('refresh_cache')) {
|
||||||
|
if(!Cache::has('status:replies:all-rc:' . $id)) {
|
||||||
|
Cache::forget('status:replies:all:' . $id);
|
||||||
|
Cache::put('status:replies:all-rc:' . $id, true, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if($sortBy == 'all' && !$request->has('cursor')) {
|
if($sortBy == 'all' && !$request->has('cursor')) {
|
||||||
$ids = Cache::remember('status:replies:all:' . $id, 86400, function() use($id) {
|
$ids = Cache::remember('status:replies:all:' . $id, 86400, function() use($id) {
|
||||||
return DB::table('statuses')
|
return DB::table('statuses')
|
||||||
|
|
|
@ -259,27 +259,29 @@ class BaseApiController extends Controller
|
||||||
|
|
||||||
public function accountLikes(Request $request)
|
public function accountLikes(Request $request)
|
||||||
{
|
{
|
||||||
$user = $request->user();
|
|
||||||
abort_if(!$request->user(), 403);
|
abort_if(!$request->user(), 403);
|
||||||
|
$this->validate($request, [
|
||||||
|
'page' => 'sometimes|int|min:1|max:20',
|
||||||
|
'limit' => 'sometimes|int|min:1|max:10'
|
||||||
|
]);
|
||||||
|
|
||||||
$limit = 10;
|
$user = $request->user();
|
||||||
$page = (int) $request->input('page', 1);
|
$limit = $request->input('limit', 10);
|
||||||
|
|
||||||
if($page > 20) {
|
$res = \DB::table('likes')
|
||||||
return [];
|
->whereProfileId($user->profile_id)
|
||||||
}
|
|
||||||
|
|
||||||
$favourites = $user->profile->likes()
|
|
||||||
->latest()
|
->latest()
|
||||||
->simplePaginate($limit)
|
->simplePaginate($limit)
|
||||||
->pluck('status_id');
|
->map(function($id) {
|
||||||
|
$status = StatusService::get($id->status_id, false);
|
||||||
$statuses = Status::find($favourites)->reverse();
|
$status['favourited'] = true;
|
||||||
|
return $status;
|
||||||
$resource = new Fractal\Resource\Collection($statuses, new StatusStatelessTransformer());
|
})
|
||||||
$res = $this->fractal->createData($resource)->toArray();
|
->filter(function($post) {
|
||||||
|
return $post && isset($post['account']);
|
||||||
return response()->json($res, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
|
})
|
||||||
|
->values();
|
||||||
|
return response()->json($res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function archive(Request $request, $id)
|
public function archive(Request $request, $id)
|
||||||
|
|
|
@ -6,6 +6,7 @@ use App\Bookmark;
|
||||||
use App\Status;
|
use App\Status;
|
||||||
use Auth;
|
use Auth;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use App\Services\BookmarkService;
|
||||||
|
|
||||||
class BookmarkController extends Controller
|
class BookmarkController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -28,7 +29,10 @@ class BookmarkController extends Controller
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!$bookmark->wasRecentlyCreated) {
|
if (!$bookmark->wasRecentlyCreated) {
|
||||||
|
BookmarkService::del($profile->id, $status->id);
|
||||||
$bookmark->delete();
|
$bookmark->delete();
|
||||||
|
} else {
|
||||||
|
BookmarkService::add($profile->id, $status->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->ajax()) {
|
if ($request->ajax()) {
|
||||||
|
|
|
@ -43,6 +43,7 @@ use App\Services\SnowflakeService;
|
||||||
use App\Services\StatusService;
|
use App\Services\StatusService;
|
||||||
use App\Services\UserFilterService;
|
use App\Services\UserFilterService;
|
||||||
use App\Services\DiscoverService;
|
use App\Services\DiscoverService;
|
||||||
|
use App\Services\BookmarkService;
|
||||||
|
|
||||||
class InternalApiController extends Controller
|
class InternalApiController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -316,16 +317,21 @@ class InternalApiController extends Controller
|
||||||
|
|
||||||
public function bookmarks(Request $request)
|
public function bookmarks(Request $request)
|
||||||
{
|
{
|
||||||
$res = Bookmark::whereProfileId($request->user()->profile_id)
|
$pid = $request->user()->profile_id;
|
||||||
|
$res = Bookmark::whereProfileId($pid)
|
||||||
->orderByDesc('created_at')
|
->orderByDesc('created_at')
|
||||||
->simplePaginate(10)
|
->simplePaginate(10)
|
||||||
->map(function($bookmark) {
|
->map(function($bookmark) use($pid) {
|
||||||
$status = StatusService::get($bookmark->status_id);
|
$status = StatusService::get($bookmark->status_id, false);
|
||||||
$status['bookmarked_at'] = $bookmark->created_at->format('c');
|
$status['bookmarked_at'] = $bookmark->created_at->format('c');
|
||||||
|
|
||||||
|
if($status) {
|
||||||
|
BookmarkService::add($pid, $status['id']);
|
||||||
|
}
|
||||||
return $status;
|
return $status;
|
||||||
})
|
})
|
||||||
->filter(function($bookmark) {
|
->filter(function($bookmark) {
|
||||||
return isset($bookmark['id']);
|
return $bookmark && isset($bookmark['id']);
|
||||||
})
|
})
|
||||||
->values();
|
->values();
|
||||||
|
|
||||||
|
@ -410,26 +416,12 @@ class InternalApiController extends Controller
|
||||||
|
|
||||||
public function remoteProfile(Request $request, $id)
|
public function remoteProfile(Request $request, $id)
|
||||||
{
|
{
|
||||||
$profile = Profile::whereNull('status')
|
return redirect('/i/web/profile/' . $id);
|
||||||
->whereNotNull('domain')
|
|
||||||
->findOrFail($id);
|
|
||||||
$user = Auth::user();
|
|
||||||
|
|
||||||
return view('profile.remote', compact('profile', 'user'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function remoteStatus(Request $request, $profileId, $statusId)
|
public function remoteStatus(Request $request, $profileId, $statusId)
|
||||||
{
|
{
|
||||||
$user = Profile::whereNull('status')
|
return redirect('/i/web/post/' . $statusId);
|
||||||
->whereNotNull('domain')
|
|
||||||
->findOrFail($profileId);
|
|
||||||
|
|
||||||
$status = Status::whereProfileId($user->id)
|
|
||||||
->whereNull('reblog_of_id')
|
|
||||||
->whereIn('visibility', ['public', 'unlisted'])
|
|
||||||
->findOrFail($statusId);
|
|
||||||
$template = $status->in_reply_to_id ? 'status.reply' : 'status.remote';
|
|
||||||
return view($template, compact('user', 'status'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function requestEmailVerification(Request $request)
|
public function requestEmailVerification(Request $request)
|
||||||
|
|
|
@ -27,10 +27,12 @@ use App\Transformer\Api\{
|
||||||
};
|
};
|
||||||
use App\Services\{
|
use App\Services\{
|
||||||
AccountService,
|
AccountService,
|
||||||
|
BookmarkService,
|
||||||
FollowerService,
|
FollowerService,
|
||||||
LikeService,
|
LikeService,
|
||||||
PublicTimelineService,
|
PublicTimelineService,
|
||||||
ProfileService,
|
ProfileService,
|
||||||
|
ReblogService,
|
||||||
RelationshipService,
|
RelationshipService,
|
||||||
StatusService,
|
StatusService,
|
||||||
SnowflakeService,
|
SnowflakeService,
|
||||||
|
@ -327,6 +329,8 @@ class PublicApiController extends Controller
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $s->id);
|
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $s->id);
|
||||||
|
$status['bookmarked'] = (bool) BookmarkService::get($user->profile_id, $s->id);
|
||||||
|
$status['reblogged'] = (bool) ReblogService::get($user->profile_id, $s->id);
|
||||||
return $status;
|
return $status;
|
||||||
})
|
})
|
||||||
->filter(function($s) use($filtered) {
|
->filter(function($s) use($filtered) {
|
||||||
|
@ -369,6 +373,8 @@ class PublicApiController extends Controller
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $s->id);
|
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $s->id);
|
||||||
|
$status['bookmarked'] = (bool) BookmarkService::get($user->profile_id, $s->id);
|
||||||
|
$status['reblogged'] = (bool) ReblogService::get($user->profile_id, $s->id);
|
||||||
return $status;
|
return $status;
|
||||||
})
|
})
|
||||||
->filter(function($s) use($filtered) {
|
->filter(function($s) use($filtered) {
|
||||||
|
@ -398,6 +404,8 @@ class PublicApiController extends Controller
|
||||||
$status = StatusService::get($k);
|
$status = StatusService::get($k);
|
||||||
if($user) {
|
if($user) {
|
||||||
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $k);
|
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $k);
|
||||||
|
$status['bookmarked'] = (bool) BookmarkService::get($user->profile_id, $k);
|
||||||
|
$status['reblogged'] = (bool) ReblogService::get($user->profile_id, $k);
|
||||||
$status['relationship'] = RelationshipService::get($user->profile_id, $status['account']['id']);
|
$status['relationship'] = RelationshipService::get($user->profile_id, $status['account']['id']);
|
||||||
}
|
}
|
||||||
return $status;
|
return $status;
|
||||||
|
@ -481,7 +489,7 @@ class PublicApiController extends Controller
|
||||||
if($min || $max) {
|
if($min || $max) {
|
||||||
$dir = $min ? '>' : '<';
|
$dir = $min ? '>' : '<';
|
||||||
$id = $min ?? $max;
|
$id = $min ?? $max;
|
||||||
$timeline = Status::select(
|
return Status::select(
|
||||||
'id',
|
'id',
|
||||||
'uri',
|
'uri',
|
||||||
'caption',
|
'caption',
|
||||||
|
@ -508,13 +516,27 @@ class PublicApiController extends Controller
|
||||||
->with('profile', 'hashtags', 'mentions')
|
->with('profile', 'hashtags', 'mentions')
|
||||||
->where('id', $dir, $id)
|
->where('id', $dir, $id)
|
||||||
->whereIn('profile_id', $following)
|
->whereIn('profile_id', $following)
|
||||||
->whereNotIn('profile_id', $filtered)
|
|
||||||
->whereIn('visibility',['public', 'unlisted', 'private'])
|
->whereIn('visibility',['public', 'unlisted', 'private'])
|
||||||
->orderBy('created_at', 'desc')
|
->orderBy('created_at', 'desc')
|
||||||
->limit($limit)
|
->limit($limit)
|
||||||
->get();
|
->get()
|
||||||
|
->map(function($s) use ($user) {
|
||||||
|
$status = StatusService::get($s->id);
|
||||||
|
if(!$status) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $s->id);
|
||||||
|
$status['bookmarked'] = (bool) BookmarkService::get($user->profile_id, $s->id);
|
||||||
|
$status['reblogged'] = (bool) ReblogService::get($user->profile_id, $s->id);
|
||||||
|
return $status;
|
||||||
|
})
|
||||||
|
->filter(function($s) use($filtered) {
|
||||||
|
return $s && in_array($s['account']['id'], $filtered) == false;
|
||||||
|
})
|
||||||
|
->values()
|
||||||
|
->toArray();
|
||||||
} else {
|
} else {
|
||||||
$timeline = Status::select(
|
return Status::select(
|
||||||
'id',
|
'id',
|
||||||
'uri',
|
'uri',
|
||||||
'caption',
|
'caption',
|
||||||
|
@ -540,15 +562,26 @@ class PublicApiController extends Controller
|
||||||
})
|
})
|
||||||
->with('profile', 'hashtags', 'mentions')
|
->with('profile', 'hashtags', 'mentions')
|
||||||
->whereIn('profile_id', $following)
|
->whereIn('profile_id', $following)
|
||||||
->whereNotIn('profile_id', $filtered)
|
|
||||||
->whereIn('visibility',['public', 'unlisted', 'private'])
|
->whereIn('visibility',['public', 'unlisted', 'private'])
|
||||||
->orderBy('created_at', 'desc')
|
->orderBy('created_at', 'desc')
|
||||||
->simplePaginate($limit);
|
->limit($limit)
|
||||||
|
->get()
|
||||||
|
->map(function($s) use ($user) {
|
||||||
|
$status = StatusService::get($s->id);
|
||||||
|
if(!$status) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $s->id);
|
||||||
|
$status['bookmarked'] = (bool) BookmarkService::get($user->profile_id, $s->id);
|
||||||
|
$status['reblogged'] = (bool) ReblogService::get($user->profile_id, $s->id);
|
||||||
|
return $status;
|
||||||
|
})
|
||||||
|
->filter(function($s) use($filtered) {
|
||||||
|
return $s && in_array($s['account']['id'], $filtered) == false;
|
||||||
|
})
|
||||||
|
->values()
|
||||||
|
->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
$fractal = new Fractal\Resource\Collection($timeline, new StatusTransformer());
|
|
||||||
$res = $this->fractal->createData($fractal)->toArray();
|
|
||||||
return response()->json($res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function networkTimelineApi(Request $request)
|
public function networkTimelineApi(Request $request)
|
||||||
|
@ -595,6 +628,8 @@ class PublicApiController extends Controller
|
||||||
->map(function($s) use ($user) {
|
->map(function($s) use ($user) {
|
||||||
$status = StatusService::get($s->id);
|
$status = StatusService::get($s->id);
|
||||||
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $s->id);
|
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $s->id);
|
||||||
|
$status['bookmarked'] = (bool) BookmarkService::get($user->profile_id, $s->id);
|
||||||
|
$status['reblogged'] = (bool) ReblogService::get($user->profile_id, $s->id);
|
||||||
return $status;
|
return $status;
|
||||||
});
|
});
|
||||||
$res = $timeline->toArray();
|
$res = $timeline->toArray();
|
||||||
|
@ -618,6 +653,8 @@ class PublicApiController extends Controller
|
||||||
->map(function($s) use ($user) {
|
->map(function($s) use ($user) {
|
||||||
$status = StatusService::get($s->id);
|
$status = StatusService::get($s->id);
|
||||||
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $s->id);
|
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $s->id);
|
||||||
|
$status['bookmarked'] = (bool) BookmarkService::get($user->profile_id, $s->id);
|
||||||
|
$status['reblogged'] = (bool) ReblogService::get($user->profile_id, $s->id);
|
||||||
return $status;
|
return $status;
|
||||||
});
|
});
|
||||||
$res = $timeline->toArray();
|
$res = $timeline->toArray();
|
||||||
|
|
|
@ -25,6 +25,7 @@ use Illuminate\Support\Str;
|
||||||
use App\Services\HashidService;
|
use App\Services\HashidService;
|
||||||
use App\Services\StatusService;
|
use App\Services\StatusService;
|
||||||
use App\Util\Media\License;
|
use App\Util\Media\License;
|
||||||
|
use App\Services\ReblogService;
|
||||||
|
|
||||||
class StatusController extends Controller
|
class StatusController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -245,6 +246,7 @@ class StatusController extends Controller
|
||||||
->get();
|
->get();
|
||||||
foreach ($shares as $share) {
|
foreach ($shares as $share) {
|
||||||
UndoSharePipeline::dispatch($share);
|
UndoSharePipeline::dispatch($share);
|
||||||
|
ReblogService::del($profile->id, $status->id);
|
||||||
$count--;
|
$count--;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -255,6 +257,7 @@ class StatusController extends Controller
|
||||||
$share->save();
|
$share->save();
|
||||||
$count++;
|
$count++;
|
||||||
SharePipeline::dispatch($share);
|
SharePipeline::dispatch($share);
|
||||||
|
ReblogService::add($profile->id, $status->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Cache::forget('status:'.$status->id.':sharedby:userid:'.$user->id);
|
Cache::forget('status:'.$status->id.':sharedby:userid:'.$user->id);
|
||||||
|
|
31
app/Services/BookmarkService.php
Normal file
31
app/Services/BookmarkService.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Bookmark;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\Redis;
|
||||||
|
|
||||||
|
class BookmarkService
|
||||||
|
{
|
||||||
|
const CACHE_KEY = 'pf:services:bookmarks:';
|
||||||
|
|
||||||
|
public static function get($profileId, $statusId)
|
||||||
|
{
|
||||||
|
if (!Redis::zcard(self::CACHE_KEY . $profileId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Redis::zscore(self::CACHE_KEY . $profileId, $statusId) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function add($profileId, $statusId)
|
||||||
|
{
|
||||||
|
return Redis::zadd(self::CACHE_KEY . $profileId, $statusId, $statusId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function del($profileId, $statusId)
|
||||||
|
{
|
||||||
|
return Redis::zrem(self::CACHE_KEY . $profileId, $statusId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -71,8 +71,8 @@ class CustomEmojiService
|
||||||
$emoji->save();
|
$emoji->save();
|
||||||
|
|
||||||
$name = str_replace(':', '', $json['name']);
|
$name = str_replace(':', '', $json['name']);
|
||||||
|
Cache::forget('pf:custom_emoji');
|
||||||
Cache::forget('pf:custom_emoji:' . $name);
|
Cache::forget('pf:custom_emoji:' . $name);
|
||||||
|
|
||||||
if($id) {
|
if($id) {
|
||||||
StatusService::del($id);
|
StatusService::del($id);
|
||||||
}
|
}
|
||||||
|
@ -104,4 +104,28 @@ class CustomEmojiService
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function all()
|
||||||
|
{
|
||||||
|
return Cache::rememberForever('pf:custom_emoji', function() {
|
||||||
|
$pgsql = config('database.default') === 'pgsql';
|
||||||
|
return CustomEmoji::when(!$pgsql, function($q, $pgsql) {
|
||||||
|
return $q->groupBy('shortcode');
|
||||||
|
})
|
||||||
|
->get()
|
||||||
|
->map(function($emojo) {
|
||||||
|
$url = url('storage/' . $emojo->media_path);
|
||||||
|
return [
|
||||||
|
'shortcode' => str_replace(':', '', $emojo->shortcode),
|
||||||
|
'url' => $url,
|
||||||
|
'static_path' => $url,
|
||||||
|
'visible_in_picker' => $emojo->disabled == false
|
||||||
|
];
|
||||||
|
})
|
||||||
|
->when($pgsql, function($collection) {
|
||||||
|
return $collection->unique('shortcode');
|
||||||
|
})
|
||||||
|
->toJson(JSON_UNESCAPED_SLASHES);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
29
app/Services/ReblogService.php
Normal file
29
app/Services/ReblogService.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Redis;
|
||||||
|
|
||||||
|
class ReblogService
|
||||||
|
{
|
||||||
|
const CACHE_KEY = 'pf:services:reblogs:';
|
||||||
|
|
||||||
|
public static function get($profileId, $statusId)
|
||||||
|
{
|
||||||
|
if (!Redis::zcard(self::CACHE_KEY . $profileId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Redis::zscore(self::CACHE_KEY . $profileId, $statusId) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function add($profileId, $statusId)
|
||||||
|
{
|
||||||
|
return Redis::zadd(self::CACHE_KEY . $profileId, $statusId, $statusId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function del($profileId, $statusId)
|
||||||
|
{
|
||||||
|
return Redis::zrem(self::CACHE_KEY . $profileId, $statusId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -165,20 +165,14 @@ class StatusService
|
||||||
public static function isShared($id, $pid = null)
|
public static function isShared($id, $pid = null)
|
||||||
{
|
{
|
||||||
return $pid ?
|
return $pid ?
|
||||||
DB::table('statuses')
|
ReblogService::get($pid, $id) :
|
||||||
->where('reblog_of_id', $id)
|
|
||||||
->where('profile_id', $pid)
|
|
||||||
->exists() :
|
|
||||||
false;
|
false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function isBookmarked($id, $pid = null)
|
public static function isBookmarked($id, $pid = null)
|
||||||
{
|
{
|
||||||
return $pid ?
|
return $pid ?
|
||||||
DB::table('bookmarks')
|
BookmarkService::get($pid, $id) :
|
||||||
->where('status_id', $id)
|
|
||||||
->where('profile_id', $pid)
|
|
||||||
->exists() :
|
|
||||||
false;
|
false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,15 @@ use App\Services\ProfileService;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use App\Services\PollService;
|
use App\Services\PollService;
|
||||||
use App\Models\CustomEmoji;
|
use App\Models\CustomEmoji;
|
||||||
|
use App\Services\BookmarkService;
|
||||||
|
|
||||||
class StatusTransformer extends Fractal\TransformerAbstract
|
class StatusTransformer extends Fractal\TransformerAbstract
|
||||||
{
|
{
|
||||||
public function transform(Status $status)
|
public function transform(Status $status)
|
||||||
{
|
{
|
||||||
|
$pid = request()->user()->profile_id;
|
||||||
$taggedPeople = MediaTagService::get($status->id);
|
$taggedPeople = MediaTagService::get($status->id);
|
||||||
$poll = $status->type === 'poll' ? PollService::get($status->id, request()->user()->profile_id) : null;
|
$poll = $status->type === 'poll' ? PollService::get($status->id, $pid) : null;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'_v' => 1,
|
'_v' => 1,
|
||||||
|
@ -69,6 +71,7 @@ class StatusTransformer extends Fractal\TransformerAbstract
|
||||||
'account' => ProfileService::get($status->profile_id),
|
'account' => ProfileService::get($status->profile_id),
|
||||||
'tags' => StatusHashtagService::statusTags($status->id),
|
'tags' => StatusHashtagService::statusTags($status->id),
|
||||||
'poll' => $poll,
|
'poll' => $poll,
|
||||||
|
'bookmarked' => BookmarkService::get($pid, $status->id),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
BIN
public/js/profile.js
vendored
BIN
public/js/profile.js
vendored
Binary file not shown.
BIN
public/js/rempos.js
vendored
BIN
public/js/rempos.js
vendored
Binary file not shown.
BIN
public/js/rempro.js
vendored
BIN
public/js/rempro.js
vendored
Binary file not shown.
BIN
public/js/spa.js
vendored
BIN
public/js/spa.js
vendored
Binary file not shown.
BIN
public/js/status.js
vendored
BIN
public/js/status.js
vendored
Binary file not shown.
BIN
public/js/timeline.js
vendored
BIN
public/js/timeline.js
vendored
Binary file not shown.
Binary file not shown.
|
@ -10,6 +10,7 @@
|
||||||
"shared": "Shared",
|
"shared": "Shared",
|
||||||
"shares": "Shares",
|
"shares": "Shares",
|
||||||
"unshare": "Unshare",
|
"unshare": "Unshare",
|
||||||
|
"bookmark": "Bookmark",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"copyLink": "Copy Link",
|
"copyLink": "Copy Link",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
|
|
|
@ -13,6 +13,7 @@ return [
|
||||||
'shared' => 'Shared',
|
'shared' => 'Shared',
|
||||||
'shares' => 'Shares',
|
'shares' => 'Shares',
|
||||||
'unshare' => 'Unshare',
|
'unshare' => 'Unshare',
|
||||||
|
'bookmark' => 'Bookmark',
|
||||||
|
|
||||||
'cancel' => 'Cancel',
|
'cancel' => 'Cancel',
|
||||||
'copyLink' => 'Copy Link',
|
'copyLink' => 'Copy Link',
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<nav class="navbar navbar-expand navbar-light navbar-laravel shadow-none border-bottom sticky-top py-1">
|
<nav class="navbar navbar-expand navbar-light navbar-laravel shadow-none border-bottom sticky-top py-1">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand d-flex align-items-center" href="{{ route('timeline.personal') }}" title="Logo">
|
<a class="navbar-brand d-flex align-items-center" href="/" title="Logo">
|
||||||
<img src="/img/pixelfed-icon-color.svg" height="30px" class="px-2" loading="eager" alt="Pixelfed logo">
|
<img src="/img/pixelfed-icon-color.svg" height="30px" class="px-2" loading="eager" alt="Pixelfed logo">
|
||||||
<span class="font-weight-bold mb-0 d-none d-sm-block" style="font-size:20px;">{{ config_cache('app.name') }}</span>
|
<span class="font-weight-bold mb-0 d-none d-sm-block" style="font-size:20px;">{{ config_cache('app.name') }}</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -18,13 +18,13 @@
|
||||||
|
|
||||||
<ul class="navbar-nav ml-auto">
|
<ul class="navbar-nav ml-auto">
|
||||||
<li>
|
<li>
|
||||||
<a class="nav-link font-weight-bold text-dark" href="{{ route('login') }}" title="Login">
|
<a class="nav-link font-weight-bold text-dark" href="/login" title="Login">
|
||||||
{{ __('Login') }}
|
{{ __('Login') }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@if(config_cache('pixelfed.open_registration') && in_array(config_cache('system.user_mode'), ['default', 'admin']))
|
@if(config_cache('pixelfed.open_registration') && in_array(config_cache('system.user_mode'), ['default', 'admin']))
|
||||||
<li>
|
<li>
|
||||||
<a class="ml-3 nav-link font-weight-bold text-dark" href="{{ route('register') }}" title="Register">
|
<a class="ml-3 nav-link font-weight-bold text-dark" href="/register" title="Register">
|
||||||
{{ __('Register') }}
|
{{ __('Register') }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -71,13 +71,13 @@
|
||||||
</span>
|
</span>
|
||||||
My Feed
|
My Feed
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item lead" href="{{route('timeline.public')}}">
|
<a class="dropdown-item lead" href="/i/web/timeline/local">
|
||||||
<span style="width: 50px;margin-right:14px;">
|
<span style="width: 50px;margin-right:14px;">
|
||||||
<span class="fal fa-stream text-lighter fa-lg"></span>
|
<span class="fal fa-stream text-lighter fa-lg"></span>
|
||||||
</span>
|
</span>
|
||||||
Public Feed
|
Public Feed
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item lead" href="{{route('timeline.network')}}">
|
<a class="dropdown-item lead" href="/i/web/timeline/global">
|
||||||
<span style="width: 50px;margin-right:14px;">
|
<span style="width: 50px;margin-right:14px;">
|
||||||
<span class="fal fa-globe text-lighter fa-lg"></span>
|
<span class="fal fa-globe text-lighter fa-lg"></span>
|
||||||
</span>
|
</span>
|
||||||
|
@ -90,7 +90,7 @@
|
||||||
</span>
|
</span>
|
||||||
Home
|
Home
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item lead" href="{{route('timeline.public')}}">
|
<a class="dropdown-item lead" href="/i/web/timeline/local">
|
||||||
<span style="width: 50px;margin-right:14px;">
|
<span style="width: 50px;margin-right:14px;">
|
||||||
<span class="fas fa-stream text-lighter fa-lg"></span>
|
<span class="fas fa-stream text-lighter fa-lg"></span>
|
||||||
</span>
|
</span>
|
||||||
|
@ -98,12 +98,13 @@
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<a class="dropdown-item lead" href="{{route('discover')}}">
|
<a class="dropdown-item lead" href="/i/web/discover">
|
||||||
<span style="width: 50px;margin-right:14px;">
|
<span style="width: 50px;margin-right:14px;">
|
||||||
<span class="fal fa-compass text-lighter fa-lg"></span>
|
<span class="fal fa-compass text-lighter fa-lg"></span>
|
||||||
</span>
|
</span>
|
||||||
{{__('navmenu.discover')}}
|
{{__('navmenu.discover')}}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
@if(config_cache('instance.stories.enabled'))
|
@if(config_cache('instance.stories.enabled'))
|
||||||
<a class="dropdown-item lead" href="/i/stories/new">
|
<a class="dropdown-item lead" href="/i/stories/new">
|
||||||
<span style="width: 50px;margin-right:14px;">
|
<span style="width: 50px;margin-right:14px;">
|
||||||
|
@ -119,14 +120,14 @@
|
||||||
</span>
|
</span>
|
||||||
{{__('navmenu.myProfile')}}
|
{{__('navmenu.myProfile')}}
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item lead" href="{{route('settings')}}">
|
<a class="dropdown-item lead" href="/settings/home">
|
||||||
<span style="width: 50px;margin-right:14px;">
|
<span style="width: 50px;margin-right:14px;">
|
||||||
<span class="fal fa-cog text-lighter fa-lg"></span>
|
<span class="fal fa-cog text-lighter fa-lg"></span>
|
||||||
</span>
|
</span>
|
||||||
{{__('navmenu.settings')}}
|
{{__('navmenu.settings')}}
|
||||||
</a>
|
</a>
|
||||||
@if(Auth::user()->is_admin == true)
|
@if(Auth::user()->is_admin == true)
|
||||||
<a class="dropdown-item lead" href="{{ route('admin.home') }}">
|
<a class="dropdown-item lead" href="/i/admin/dashboard">
|
||||||
<span style="width: 50px;margin-right:14px;">
|
<span style="width: 50px;margin-right:14px;">
|
||||||
<span class="fal fa-shield-alt text-lighter fa-lg"></span>
|
<span class="fal fa-shield-alt text-lighter fa-lg"></span>
|
||||||
</span>
|
</span>
|
||||||
|
@ -134,7 +135,7 @@
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<a class="dropdown-item lead" href="{{ route('logout') }}"
|
<a class="dropdown-item lead" href="/logout"
|
||||||
onclick="event.preventDefault();
|
onclick="event.preventDefault();
|
||||||
document.getElementById('logout-form').submit();">
|
document.getElementById('logout-form').submit();">
|
||||||
<span style="width: 50px;margin-right:14px;" class="text-lighter">
|
<span style="width: 50px;margin-right:14px;" class="text-lighter">
|
||||||
|
@ -143,7 +144,7 @@
|
||||||
<span class="text-lighter">{{ __('navmenu.logout') }}</span>
|
<span class="text-lighter">{{ __('navmenu.logout') }}</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
|
<form id="logout-form" action="/logout" method="POST" style="display: none;">
|
||||||
@csrf
|
@csrf
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
1
storage/app/public/emoji/.gitignore
vendored
1
storage/app/public/emoji/.gitignore
vendored
|
@ -1,2 +1,3 @@
|
||||||
*
|
*
|
||||||
|
!missing.png
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
|
BIN
storage/app/public/emoji/missing.png
Normal file
BIN
storage/app/public/emoji/missing.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 81 B |
Loading…
Reference in a new issue