1
0
Fork 1
mirror of https://github.com/pixelfed/pixelfed.git synced 2025-02-24 07:00:46 +00:00

Merge pull request #5720 from pixelfed/staging

Update DirectMessageController, fix performance issue
This commit is contained in:
daniel 2025-02-10 02:46:50 -07:00 committed by GitHub
commit 2f2a361804
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 177 additions and 325 deletions

View file

@ -3007,39 +3007,49 @@ class ApiV1Controller extends Controller
'scope' => 'nullable|in:inbox,sent,requests',
]);
return [];
$limit = $request->input('limit', 20);
$scope = $request->input('scope', 'inbox');
$user = $request->user();
if ($user->has_roles && ! UserRoleService::can('can-direct-message', $user->id)) {
return [];
}
$pid = $user->profile_id;
if (config('database.default') == 'pgsql') {
$dms = DirectMessage::when($scope === 'inbox', function ($q, $scope) use ($pid) {
return $q->whereIsHidden(false)->where('to_id', $pid)->orWhere('from_id', $pid);
$dms = DirectMessage::when($scope === 'inbox', function ($q) use ($pid) {
return $q->whereIsHidden(false)
->where(function ($query) use ($pid) {
$query->where('to_id', $pid)
->orWhere('from_id', $pid);
});
})
->when($scope === 'sent', function ($q, $scope) use ($pid) {
return $q->whereFromId($pid)->groupBy(['to_id', 'id']);
->when($scope === 'sent', function ($q) use ($pid) {
return $q->whereFromId($pid)
->groupBy(['to_id', 'id']);
})
->when($scope === 'requests', function ($q, $scope) use ($pid) {
return $q->whereToId($pid)->whereIsHidden(true);
->when($scope === 'requests', function ($q) use ($pid) {
return $q->whereToId($pid)
->whereIsHidden(true);
});
} else {
$dms = Conversation::when($scope === 'inbox', function ($q, $scope) use ($pid) {
$dms = Conversation::when($scope === 'inbox', function ($q) use ($pid) {
return $q->whereIsHidden(false)
->where('to_id', $pid)
->orWhere('from_id', $pid)
->where(function ($query) use ($pid) {
$query->where('to_id', $pid)
->orWhere('from_id', $pid);
})
->orderByDesc('status_id')
->groupBy(['to_id', 'from_id']);
})
->when($scope === 'sent', function ($q, $scope) use ($pid) {
return $q->whereFromId($pid)->groupBy('to_id');
->when($scope === 'sent', function ($q) use ($pid) {
return $q->whereFromId($pid)
->groupBy('to_id');
})
->when($scope === 'requests', function ($q, $scope) use ($pid) {
return $q->whereToId($pid)->whereIsHidden(true);
->when($scope === 'requests', function ($q) use ($pid) {
return $q->whereToId($pid)
->whereIsHidden(true);
});
}
@ -3047,7 +3057,8 @@ class ApiV1Controller extends Controller
->simplePaginate($limit)
->map(function ($dm) use ($pid) {
$from = $pid == $dm->to_id ? $dm->from_id : $dm->to_id;
$res = [
return [
'id' => $dm->id,
'unread' => false,
'accounts' => [
@ -3055,17 +3066,16 @@ class ApiV1Controller extends Controller
],
'last_status' => StatusService::getDirectMessage($dm->status_id),
];
return $res;
})
->filter(function ($dm) {
if (! $dm || empty($dm['last_status']) || ! isset($dm['accounts']) || ! count($dm['accounts']) || ! isset($dm['accounts'][0]) || ! isset($dm['accounts'][0]['id'])) {
return false;
}
return true;
return $dm
&& ! empty($dm['last_status'])
&& isset($dm['accounts'])
&& count($dm['accounts'])
&& isset($dm['accounts'][0])
&& isset($dm['accounts'][0]['id']);
})
->unique(function ($item, $key) {
->unique(function ($item) {
return $item['accounts'][0]['id'];
})
->values();
@ -3500,7 +3510,7 @@ class ApiV1Controller extends Controller
return [];
}
$defaultCaption = "";
$defaultCaption = '';
$content = $request->filled('status') ? strip_tags($request->input('status')) : $defaultCaption;
$cw = $user->profile->cw == true ? true : $request->boolean('sensitive', false);
$spoilerText = $cw && $request->filled('spoiler_text') ? $request->input('spoiler_text') : null;

View file

@ -30,7 +30,6 @@ class DirectMessageController extends Controller
{
public function __construct()
{
abort(404);
$this->middleware('auth');
}
@ -45,257 +44,93 @@ class DirectMessageController extends Controller
if ($user->has_roles && ! UserRoleService::can('can-direct-message', $user->id)) {
return [];
}
$profile = $user->profile_id;
$action = $request->input('a', 'inbox');
$page = $request->input('page');
$page = $request->input('page', 1);
$limit = 8;
$offset = ($page - 1) * $limit;
$baseQuery = DirectMessage::select(
'id', 'type', 'to_id', 'from_id', 'status_id',
'is_hidden', 'meta', 'created_at', 'read_at'
)->with(['author', 'status', 'recipient']);
if (config('database.default') == 'pgsql') {
if ($action == 'inbox') {
$dms = DirectMessage::select('id', 'type', 'to_id', 'from_id', 'id', 'status_id', 'is_hidden', 'meta', 'created_at', 'read_at')
->whereToId($profile)
->with(['author', 'status'])
$query = match ($action) {
'inbox' => $baseQuery->whereToId($profile)
->whereIsHidden(false)
->when($page, function ($q, $page) {
if ($page > 1) {
return $q->offset($page * 8 - 8);
}
})
->latest()
->get()
->unique('from_id')
->take(8)
->map(function ($r) use ($profile) {
return $r->from_id !== $profile ? [
'id' => (string) $r->from_id,
'name' => $r->author->name,
'username' => $r->author->username,
'avatar' => $r->author->avatarUrl(),
'url' => $r->author->url(),
'isLocal' => (bool) ! $r->author->domain,
'domain' => $r->author->domain,
'timeAgo' => $r->created_at->diffForHumans(null, true, true),
'lastMessage' => $r->status->caption,
'messages' => [],
] : [
'id' => (string) $r->to_id,
'name' => $r->recipient->name,
'username' => $r->recipient->username,
'avatar' => $r->recipient->avatarUrl(),
'url' => $r->recipient->url(),
'isLocal' => (bool) ! $r->recipient->domain,
'domain' => $r->recipient->domain,
'timeAgo' => $r->created_at->diffForHumans(null, true, true),
'lastMessage' => $r->status->caption,
'messages' => [],
];
})->values();
}
if ($action == 'sent') {
$dms = DirectMessage::select('id', 'type', 'to_id', 'from_id', 'id', 'status_id', 'is_hidden', 'meta', 'created_at', 'read_at')
->whereFromId($profile)
->with(['author', 'status'])
->orderBy('id', 'desc')
->when($page, function ($q, $page) {
if ($page > 1) {
return $q->offset($page * 8 - 8);
}
})
->get()
->unique('to_id')
->take(8)
->map(function ($r) use ($profile) {
return $r->from_id !== $profile ? [
'id' => (string) $r->from_id,
'name' => $r->author->name,
'username' => $r->author->username,
'avatar' => $r->author->avatarUrl(),
'url' => $r->author->url(),
'isLocal' => (bool) ! $r->author->domain,
'domain' => $r->author->domain,
'timeAgo' => $r->created_at->diffForHumans(null, true, true),
'lastMessage' => $r->status->caption,
'messages' => [],
] : [
'id' => (string) $r->to_id,
'name' => $r->recipient->name,
'username' => $r->recipient->username,
'avatar' => $r->recipient->avatarUrl(),
'url' => $r->recipient->url(),
'isLocal' => (bool) ! $r->recipient->domain,
'domain' => $r->recipient->domain,
'timeAgo' => $r->created_at->diffForHumans(null, true, true),
'lastMessage' => $r->status->caption,
'messages' => [],
];
});
}
if ($action == 'filtered') {
$dms = DirectMessage::select('id', 'type', 'to_id', 'from_id', 'id', 'status_id', 'is_hidden', 'meta', 'created_at', 'read_at')
->whereToId($profile)
->with(['author', 'status'])
->orderBy('created_at', 'desc'),
'sent' => $baseQuery->whereFromId($profile)
->orderBy('created_at', 'desc'),
'filtered' => $baseQuery->whereToId($profile)
->whereIsHidden(true)
->orderBy('id', 'desc')
->when($page, function ($q, $page) {
if ($page > 1) {
return $q->offset($page * 8 - 8);
}
})
->get()
->unique('from_id')
->take(8)
->map(function ($r) use ($profile) {
return $r->from_id !== $profile ? [
'id' => (string) $r->from_id,
'name' => $r->author->name,
'username' => $r->author->username,
'avatar' => $r->author->avatarUrl(),
'url' => $r->author->url(),
'isLocal' => (bool) ! $r->author->domain,
'domain' => $r->author->domain,
'timeAgo' => $r->created_at->diffForHumans(null, true, true),
'lastMessage' => $r->status->caption,
'messages' => [],
] : [
'id' => (string) $r->to_id,
'name' => $r->recipient->name,
'username' => $r->recipient->username,
'avatar' => $r->recipient->avatarUrl(),
'url' => $r->recipient->url(),
'isLocal' => (bool) ! $r->recipient->domain,
'domain' => $r->recipient->domain,
'timeAgo' => $r->created_at->diffForHumans(null, true, true),
'lastMessage' => $r->status->caption,
'messages' => [],
];
});
}
} elseif (config('database.default') == 'mysql') {
if ($action == 'inbox') {
$dms = DirectMessage::selectRaw('*, max(created_at) as createdAt')
->whereToId($profile)
->with(['author', 'status'])
->orderBy('created_at', 'desc'),
default => throw new \InvalidArgumentException('Invalid action')
};
$dms = $query->offset($offset)
->limit($limit)
->get();
$dms = $action === 'sent' ?
$dms->unique('to_id') :
$dms->unique('from_id');
} else {
$query = match ($action) {
'inbox' => $baseQuery->whereToId($profile)
->whereIsHidden(false)
->groupBy('from_id')
->latest()
->when($page, function ($q, $page) {
if ($page > 1) {
return $q->offset($page * 8 - 8);
}
})
->limit(8)
->get()
->map(function ($r) use ($profile) {
return $r->from_id !== $profile ? [
'id' => (string) $r->from_id,
'name' => $r->author->name,
'username' => $r->author->username,
'avatar' => $r->author->avatarUrl(),
'url' => $r->author->url(),
'isLocal' => (bool) ! $r->author->domain,
'domain' => $r->author->domain,
'timeAgo' => $r->created_at->diffForHumans(null, true, true),
'lastMessage' => $r->status->caption,
'messages' => [],
] : [
'id' => (string) $r->to_id,
'name' => $r->recipient->name,
'username' => $r->recipient->username,
'avatar' => $r->recipient->avatarUrl(),
'url' => $r->recipient->url(),
'isLocal' => (bool) ! $r->recipient->domain,
'domain' => $r->recipient->domain,
'timeAgo' => $r->created_at->diffForHumans(null, true, true),
'lastMessage' => $r->status->caption,
'messages' => [],
];
});
}
if ($action == 'sent') {
$dms = DirectMessage::selectRaw('*, max(created_at) as createdAt')
->whereFromId($profile)
->with(['author', 'status'])
->groupBy('to_id')
->orderBy('createdAt', 'desc')
->when($page, function ($q, $page) {
if ($page > 1) {
return $q->offset($page * 8 - 8);
}
})
->limit(8)
->get()
->map(function ($r) use ($profile) {
return $r->from_id !== $profile ? [
'id' => (string) $r->from_id,
'name' => $r->author->name,
'username' => $r->author->username,
'avatar' => $r->author->avatarUrl(),
'url' => $r->author->url(),
'isLocal' => (bool) ! $r->author->domain,
'domain' => $r->author->domain,
'timeAgo' => $r->created_at->diffForHumans(null, true, true),
'lastMessage' => $r->status->caption,
'messages' => [],
] : [
'id' => (string) $r->to_id,
'name' => $r->recipient->name,
'username' => $r->recipient->username,
'avatar' => $r->recipient->avatarUrl(),
'url' => $r->recipient->url(),
'isLocal' => (bool) ! $r->recipient->domain,
'domain' => $r->recipient->domain,
'timeAgo' => $r->created_at->diffForHumans(null, true, true),
'lastMessage' => $r->status->caption,
'messages' => [],
];
});
}
if ($action == 'filtered') {
$dms = DirectMessage::selectRaw('*, max(created_at) as createdAt')
->whereToId($profile)
->with(['author', 'status'])
->groupBy('from_id', 'id', 'type', 'to_id', 'status_id',
'is_hidden', 'meta', 'created_at', 'read_at')
->orderBy('created_at', 'desc'),
'sent' => $baseQuery->whereFromId($profile)
->groupBy('to_id', 'id', 'type', 'from_id', 'status_id',
'is_hidden', 'meta', 'created_at', 'read_at')
->orderBy('created_at', 'desc'),
'filtered' => $baseQuery->whereToId($profile)
->whereIsHidden(true)
->groupBy('from_id')
->orderBy('createdAt', 'desc')
->when($page, function ($q, $page) {
if ($page > 1) {
return $q->offset($page * 8 - 8);
}
})
->limit(8)
->get()
->map(function ($r) use ($profile) {
return $r->from_id !== $profile ? [
'id' => (string) $r->from_id,
'name' => $r->author->name,
'username' => $r->author->username,
'avatar' => $r->author->avatarUrl(),
'url' => $r->author->url(),
'isLocal' => (bool) ! $r->author->domain,
'domain' => $r->author->domain,
'timeAgo' => $r->created_at->diffForHumans(null, true, true),
'lastMessage' => $r->status->caption,
'messages' => [],
] : [
'id' => (string) $r->to_id,
'name' => $r->recipient->name,
'username' => $r->recipient->username,
'avatar' => $r->recipient->avatarUrl(),
'url' => $r->recipient->url(),
'isLocal' => (bool) ! $r->recipient->domain,
'domain' => $r->recipient->domain,
'timeAgo' => $r->created_at->diffForHumans(null, true, true),
'lastMessage' => $r->status->caption,
'messages' => [],
];
});
}
->groupBy('from_id', 'id', 'type', 'to_id', 'status_id',
'is_hidden', 'meta', 'created_at', 'read_at')
->orderBy('created_at', 'desc'),
default => throw new \InvalidArgumentException('Invalid action')
};
$dms = $query->offset($offset)
->limit($limit)
->get();
}
return response()->json($dms->all());
$mappedDms = $dms->map(function ($r) use ($action) {
if ($action === 'sent') {
return [
'id' => (string) $r->to_id,
'name' => $r->recipient->name,
'username' => $r->recipient->username,
'avatar' => $r->recipient->avatarUrl(),
'url' => $r->recipient->url(),
'isLocal' => (bool) ! $r->recipient->domain,
'domain' => $r->recipient->domain,
'timeAgo' => $r->created_at->diffForHumans(null, true, true),
'lastMessage' => $r->status->caption,
'messages' => [],
];
}
return [
'id' => (string) $r->from_id,
'name' => $r->author->name,
'username' => $r->author->username,
'avatar' => $r->author->avatarUrl(),
'url' => $r->author->url(),
'isLocal' => (bool) ! $r->author->domain,
'domain' => $r->author->domain,
'timeAgo' => $r->created_at->diffForHumans(null, true, true),
'lastMessage' => $r->status->caption,
'messages' => [],
];
});
return response()->json($mappedDms->values());
}
public function create(Request $request)
@ -411,90 +246,97 @@ class DirectMessageController extends Controller
'max_id' => 'sometimes|integer',
'min_id' => 'sometimes|integer',
]);
$user = $request->user();
abort_if($user->has_roles && ! UserRoleService::can('can-direct-message', $user->id), 403, 'Invalid permissions for this action');
abort_if(
$user->has_roles && ! UserRoleService::can('can-direct-message', $user->id),
403,
'Invalid permissions for this action'
);
$uid = $user->profile_id;
$pid = $request->input('pid');
$max_id = $request->input('max_id');
$min_id = $request->input('min_id');
$r = Profile::findOrFail($pid);
$profile = Profile::findOrFail($pid);
$query = DirectMessage::select(
'id',
'is_hidden',
'from_id',
'to_id',
'type',
'status_id',
'meta',
'created_at',
'read_at'
)->with(['status' => function ($q) {
$q->select('id', 'caption', 'profile_id');
}])->where(function ($q) use ($pid, $uid) {
$q->where(function ($query) use ($pid, $uid) {
$query->where('from_id', $pid)
->where('to_id', $uid)
->where('is_hidden', false);
})->orWhere(function ($query) use ($pid, $uid) {
$query->where('from_id', $uid)
->where('to_id', $pid);
});
});
if ($min_id) {
$res = DirectMessage::select('*')
->where('id', '>', $min_id)
->where(function ($query) use ($pid, $uid) {
$query->where('from_id', $pid)->where('to_id', $uid);
})->orWhere(function ($query) use ($pid, $uid) {
$query->where('from_id', $uid)->where('to_id', $pid);
})
$res = $query->where('id', '>', $min_id)
->orderBy('id', 'asc')
->take(8)
->get()
->reverse();
} elseif ($max_id) {
$res = DirectMessage::select('*')
->where('id', '<', $max_id)
->where(function ($query) use ($pid, $uid) {
$query->where('from_id', $pid)->where('to_id', $uid);
})->orWhere(function ($query) use ($pid, $uid) {
$query->where('from_id', $uid)->where('to_id', $pid);
})
$res = $query->where('id', '<', $max_id)
->orderBy('id', 'desc')
->take(8)
->get();
} else {
$res = DirectMessage::where(function ($query) use ($pid, $uid) {
$query->where('from_id', $pid)->where('to_id', $uid);
})->orWhere(function ($query) use ($pid, $uid) {
$query->where('from_id', $uid)->where('to_id', $pid);
})
->orderBy('id', 'desc')
$res = $query->orderBy('id', 'desc')
->take(8)
->get();
}
$res = $res->filter(function ($s) {
return $s && $s->status;
})
->map(function ($s) use ($uid) {
return [
'id' => (string) $s->id,
'hidden' => (bool) $s->is_hidden,
'isAuthor' => $uid == $s->from_id,
'type' => $s->type,
'text' => $s->status->caption,
'media' => $s->status->firstMedia() ? $s->status->firstMedia()->url() : null,
'carousel' => MediaService::get($s->status_id),
'created_at' => $s->created_at->format('c'),
'timeAgo' => $s->created_at->diffForHumans(null, null, true),
'seen' => $s->read_at != null,
'reportId' => (string) $s->status_id,
'meta' => json_decode($s->meta, true),
];
})
->values();
$messages = $res->filter(function ($message) {
return $message && $message->status;
})->map(function ($message) use ($uid) {
return [
'id' => (string) $message->id,
'hidden' => (bool) $message->is_hidden,
'isAuthor' => $uid == $message->from_id,
'type' => $message->type,
'text' => $message->status->caption,
'media' => $message->status->firstMedia() ? $message->status->firstMedia()->url() : null,
'carousel' => MediaService::get($message->status_id),
'created_at' => $message->created_at->format('c'),
'timeAgo' => $message->created_at->diffForHumans(null, null, true),
'seen' => $message->read_at != null,
'reportId' => (string) $message->status_id,
'meta' => is_string($message->meta) ? json_decode($message->meta, true) : $message->meta,
];
})->values();
$filters = UserFilterService::mutes($uid);
$w = [
'id' => (string) $r->id,
'name' => $r->name,
'username' => $r->username,
'avatar' => $r->avatarUrl(),
'url' => $r->url(),
'muted' => in_array($r->id, $filters),
'isLocal' => (bool) ! $r->domain,
'domain' => $r->domain,
'created_at' => $r->created_at->format('c'),
'updated_at' => $r->updated_at->format('c'),
'timeAgo' => $r->created_at->diffForHumans(null, true, true),
return response()->json([
'id' => (string) $profile->id,
'name' => $profile->name,
'username' => $profile->username,
'avatar' => $profile->avatarUrl(),
'url' => $profile->url(),
'muted' => in_array($profile->id, $filters),
'isLocal' => (bool) ! $profile->domain,
'domain' => $profile->domain,
'created_at' => $profile->created_at->format('c'),
'updated_at' => $profile->updated_at->format('c'),
'timeAgo' => $profile->created_at->diffForHumans(null, true, true),
'lastMessage' => '',
'messages' => $res,
];
return response()->json($w, 200, [], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
'messages' => $messages,
], 200, [], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
public function delete(Request $request)