2020-09-05 03:44:20 +09:00
|
|
|
<?php
|
|
|
|
|
2021-10-10 17:26:18 +09:00
|
|
|
declare(strict_types = 1);
|
|
|
|
|
2020-09-05 03:44:20 +09:00
|
|
|
// {{{ License
|
|
|
|
|
|
|
|
// This file is part of GNU social - https://www.gnu.org/software/social
|
|
|
|
//
|
|
|
|
// GNU social is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// GNU social is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Affero General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
|
|
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
// }}}
|
|
|
|
|
|
|
|
namespace Plugin\Directory\Controller;
|
|
|
|
|
|
|
|
use App\Core\DB\DB;
|
2021-12-28 02:10:58 +09:00
|
|
|
use App\Entity\Actor;
|
2022-01-02 05:49:17 +09:00
|
|
|
use App\Util\Exception\BugFoundException;
|
|
|
|
use App\Util\Exception\ClientException;
|
2021-12-23 22:27:31 +09:00
|
|
|
use Component\Feed\Util\FeedController;
|
2022-01-02 05:49:17 +09:00
|
|
|
use function App\Core\I18n\_m;
|
2020-09-05 03:44:20 +09:00
|
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
|
|
|
2021-12-08 08:31:20 +09:00
|
|
|
class Directory extends FeedController
|
2020-09-05 03:44:20 +09:00
|
|
|
{
|
2022-01-02 05:49:17 +09:00
|
|
|
|
|
|
|
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,
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2020-12-02 03:09:01 +09:00
|
|
|
/**
|
2022-01-02 05:02:32 +09:00
|
|
|
* people stream
|
2020-12-02 03:09:01 +09:00
|
|
|
*
|
|
|
|
* @return array template
|
|
|
|
*/
|
2022-01-02 05:02:32 +09:00
|
|
|
public function people(Request $request): array
|
2020-09-05 03:44:20 +09:00
|
|
|
{
|
2022-01-02 05:49:17 +09:00
|
|
|
return $this->impl($request, 'directory/people.html.twig', Actor::PERSON);
|
2020-09-05 03:44:20 +09:00
|
|
|
}
|
|
|
|
|
2020-12-02 09:59:20 +09:00
|
|
|
/**
|
|
|
|
* groups stream
|
|
|
|
*
|
|
|
|
* @return array template
|
|
|
|
*/
|
2021-10-10 17:26:18 +09:00
|
|
|
public function groups(Request $request): array
|
2020-09-05 03:44:20 +09:00
|
|
|
{
|
2022-01-02 05:49:17 +09:00
|
|
|
return $this->impl($request, 'directory/groups.html.twig', Actor::GROUP);
|
2020-09-05 03:44:20 +09:00
|
|
|
}
|
|
|
|
}
|