[PLUGIN][Directory] Add options to sort by nickname, created, modified and activity, ascending or descending

This commit is contained in:
Hugo Sales 2022-01-01 20:49:17 +00:00
parent acc84d757c
commit 175c98b043
Signed by: someonewithpc
GPG Key ID: 7D0C7EAFC9D835A0

View File

@ -25,11 +25,113 @@ namespace Plugin\Directory\Controller;
use App\Core\DB\DB;
use App\Entity\Actor;
use App\Util\Exception\BugFoundException;
use App\Util\Exception\ClientException;
use Component\Feed\Util\FeedController;
use function App\Core\I18n\_m;
use Symfony\Component\HttpFoundation\Request;
class Directory extends FeedController
{
const PER_PAGE = 32;
const ALLOWED_FIELDS = ['nickname', 'created', 'modified', 'activity', 'subscribers'];
private function impl(Request $request, string $template, int $actor_type): array
{
$page = $this->int('page') ?? 1;
$limit = self::PER_PAGE;
$offset = self::PER_PAGE * ($page - 1);
$order_by_qs = $this->string('order_by');
if (!\is_null($order_by_qs) && mb_detect_encoding($order_by_qs, 'ASCII', strict: true) !== false) {
$order_by_op = substr($order_by_qs, -1);
if (\in_array($order_by_op, ['^', '<'])) {
$order_by_field = substr($order_by_qs, 0, -1);
$order_by_op = 'ASC';
} else if (\in_array($order_by_op, ['v', '>'])) {
$order_by_field = substr($order_by_qs, 0, -1);
$order_by_op = 'DESC';
} else {
$order_by_field = $order_by_qs;
$order_by_op = 'ASC';
}
if (!\in_array($order_by_field, self::ALLOWED_FIELDS)) {
throw new ClientException(_m('Invalid order by given: {order_by}', ['{order_by}' => $order_by_field]));
}
} else {
$order_by_field = 'nickname';
$order_by_op = 'ASC';
}
$order_by = [$order_by_field => $order_by_op];
$route = $request->get('_route');
$query_fn = function (int $actor_type, string $table, string $join_field) use ($limit, $offset) {
return function (string $func, string $order) use ($actor_type, $table, $join_field, $limit, $offset) {
return DB::sql(
<<<EOQ
select {select}
from actor actr
join (
select tbl.{$join_field}, {$func}(tbl.created) as created
from {$table} tbl
group by tbl.{$join_field}
) actor_activity on actr.id = actor_activity.{$join_field}
where actr.type = :type
order by actor_activity.{$order}
limit :limit offset :offset
EOQ,
[
'type' => $actor_type,
'limit' => $limit,
'offset' => $offset,
],
['actr' => Actor::class]
);
};
};
$person_activity_query = $query_fn(actor_type: Actor::PERSON, table: 'activity', join_field: 'actor_id');
$group_activity_query = $query_fn(actor_type: Actor::GROUP, table: 'group_inbox', join_field: 'group_id');
switch ($order_by_field) {
case 'nickname':
case 'created':
$actors = DB::findBy(Actor::class, ['type' => $actor_type], order_by: $order_by, limit: $limit, offset: $offset);
break;
case 'modified':
$query = match ($actor_type) {
Actor::PERSON => $person_activity_query,
Actor::GROUP => $group_activity_query,
default => throw new BugFoundException("Unimplemented for actor type: {$actor_type}"),
};
$actors = $query(func: $order_by_op === 'ASC' ? 'MAX' : 'MIN', order: "created {$order_by_op}");
break;
case 'activity':
$query = match ($actor_type) {
Actor::PERSON => $person_activity_query,
Actor::GROUP => $group_activity_query,
default => throw new BugFoundException("Unimplemented for actor type: {$actor_type}"),
};
$actors = $query(func: 'COUNT', order: "created {$order_by_op}");
break;
default:
throw new BugFoundException("Unkown order by found, but should have been validated: {$order_by_field}");
}
return [
'_template' => $template,
'actors' => $actors,
'page' => $page,
];
}
/**
* people stream
*
@ -37,10 +139,7 @@ class Directory extends FeedController
*/
public function people(Request $request): array
{
return [
'_template' => 'directory/people.html.twig',
'actors' => DB::findBy(Actor::class, ['type' => Actor::PERSON], order_by: ['created' => 'DESC', 'nickname' => 'ASC']),
];
return $this->impl($request, 'directory/people.html.twig', Actor::PERSON);
}
/**
@ -50,9 +149,6 @@ class Directory extends FeedController
*/
public function groups(Request $request): array
{
return [
'_template' => 'directory/groups.html.twig',
'groups' => DB::findBy(Actor::class, ['type' => Actor::GROUP], order_by: ['created' => 'DESC', 'nickname' => 'ASC']),
];
return $this->impl($request, 'directory/groups.html.twig', Actor::GROUP);
}
}