[COMPONENT][Subscription] Start component
This commit is contained in:
parent
5fa8056899
commit
6cfb69d64b
@ -39,6 +39,7 @@ use Component\Collection\Util\ActorControllerTrait;
|
|||||||
use Component\Collection\Util\Controller\FeedController;
|
use Component\Collection\Util\Controller\FeedController;
|
||||||
use Component\Group\Entity\GroupMember;
|
use Component\Group\Entity\GroupMember;
|
||||||
use Component\Group\Entity\LocalGroup;
|
use Component\Group\Entity\LocalGroup;
|
||||||
|
use Component\Subscription\Entity\Subscription;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
@ -91,7 +92,7 @@ class Group extends FeedController
|
|||||||
'group_id' => $group->getId(),
|
'group_id' => $group->getId(),
|
||||||
'nickname' => $nickname,
|
'nickname' => $nickname,
|
||||||
]));
|
]));
|
||||||
DB::persist(E\Subscription::create([
|
DB::persist(Subscription::create([
|
||||||
'subscriber' => $group->getId(),
|
'subscriber' => $group->getId(),
|
||||||
'subscribed' => $group->getId(),
|
'subscribed' => $group->getId(),
|
||||||
]));
|
]));
|
||||||
@ -115,7 +116,7 @@ class Group extends FeedController
|
|||||||
} else {
|
} else {
|
||||||
if (!\is_null($actor)
|
if (!\is_null($actor)
|
||||||
&& \is_null(Cache::get(
|
&& \is_null(Cache::get(
|
||||||
E\Subscription::cacheKeys($actor, $group)['subscribed'],
|
Subscription::cacheKeys($actor, $group)['subscribed'],
|
||||||
fn () => DB::findOneBy('subscription', [
|
fn () => DB::findOneBy('subscription', [
|
||||||
'subscriber' => $actor->getId(),
|
'subscriber' => $actor->getId(),
|
||||||
'subscribed' => $group->getId(),
|
'subscribed' => $group->getId(),
|
||||||
@ -125,14 +126,14 @@ class Group extends FeedController
|
|||||||
$subscribe_form = Form::create([['subscribe', SubmitType::class, ['label' => _m('Subscribe to this group')]]]);
|
$subscribe_form = Form::create([['subscribe', SubmitType::class, ['label' => _m('Subscribe to this group')]]]);
|
||||||
$subscribe_form->handleRequest($request);
|
$subscribe_form->handleRequest($request);
|
||||||
if ($subscribe_form->isSubmitted() && $subscribe_form->isValid()) {
|
if ($subscribe_form->isSubmitted() && $subscribe_form->isValid()) {
|
||||||
DB::persist(E\Subscription::create([
|
DB::persist(Subscription::create([
|
||||||
'subscriber' => $actor->getId(),
|
'subscriber' => $actor->getId(),
|
||||||
'subscribed' => $group->getId(),
|
'subscribed' => $group->getId(),
|
||||||
]));
|
]));
|
||||||
DB::flush();
|
DB::flush();
|
||||||
Cache::delete(E\Actor::cacheKeys($group->getId())['subscriber']);
|
Cache::delete(E\Actor::cacheKeys($group->getId())['subscriber']);
|
||||||
Cache::delete(E\Actor::cacheKeys($actor->getId())['subscribed']);
|
Cache::delete(E\Actor::cacheKeys($actor->getId())['subscribed']);
|
||||||
Cache::delete(E\Subscription::cacheKeys($actor, $group)['subscribed']);
|
Cache::delete(Subscription::cacheKeys($actor, $group)['subscribed']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,23 +21,25 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
namespace App\Controller;
|
namespace Component\Subscription\Controller;
|
||||||
|
|
||||||
use App\Core\Controller\ActorController;
|
use function App\Core\I18n\_m;
|
||||||
|
use Component\Collection\Util\ActorControllerTrait;
|
||||||
|
use Component\Collection\Util\Controller\CircleController;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of an actor's subscribers
|
* Collection of an actor's subscribers
|
||||||
*/
|
*/
|
||||||
class Subscribers extends ActorController
|
class Subscribers extends CircleController
|
||||||
{
|
{
|
||||||
|
use ActorControllerTrait;
|
||||||
public function subscribersByActorId(Request $request, int $id)
|
public function subscribersByActorId(Request $request, int $id)
|
||||||
{
|
{
|
||||||
return $this->handleActorById(
|
return $this->handleActorById(
|
||||||
$id,
|
$id,
|
||||||
fn ($actor) => [
|
fn ($actor) => [
|
||||||
'_template' => 'subscribers/view.html.twig',
|
'actor' => $actor,
|
||||||
'actor' => $actor,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -47,8 +49,12 @@ class Subscribers extends ActorController
|
|||||||
return $this->handleActorByNickname(
|
return $this->handleActorByNickname(
|
||||||
$nickname,
|
$nickname,
|
||||||
fn ($actor) => [
|
fn ($actor) => [
|
||||||
'_template' => 'subscribers/view.html.twig',
|
'_template' => 'collection/actors.html.twig',
|
||||||
'actor' => $actor,
|
'title' => _m('Subscribers'),
|
||||||
|
'empty_message' => _m('No subscribers'),
|
||||||
|
'sort_options' => [],
|
||||||
|
'page' => $this->int('page') ?? 1,
|
||||||
|
'actors' => $actor->getSubscribers(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -21,23 +21,25 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
namespace App\Controller;
|
namespace Component\Subscription\Controller;
|
||||||
|
|
||||||
use App\Core\Controller\ActorController;
|
use function App\Core\I18n\_m;
|
||||||
|
use Component\Collection\Util\ActorControllerTrait;
|
||||||
|
use Component\Collection\Util\Controller\CircleController;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of an actor's subscriptions
|
* Collection of an actor's subscriptions
|
||||||
*/
|
*/
|
||||||
class Subscriptions extends ActorController
|
class Subscriptions extends CircleController
|
||||||
{
|
{
|
||||||
|
use ActorControllerTrait;
|
||||||
public function subscriptionsByActorId(Request $request, int $id)
|
public function subscriptionsByActorId(Request $request, int $id)
|
||||||
{
|
{
|
||||||
return $this->handleActorById(
|
return $this->handleActorById(
|
||||||
$id,
|
$id,
|
||||||
fn ($actor) => [
|
fn ($actor) => [
|
||||||
'_template' => 'subscriptions/view.html.twig',
|
'actor' => $actor,
|
||||||
'actor' => $actor,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -47,8 +49,12 @@ class Subscriptions extends ActorController
|
|||||||
return $this->handleActorByNickname(
|
return $this->handleActorByNickname(
|
||||||
$nickname,
|
$nickname,
|
||||||
fn ($actor) => [
|
fn ($actor) => [
|
||||||
'_template' => 'subscriptions/view.html.twig',
|
'_template' => 'collection/actors.html.twig',
|
||||||
'actor' => $actor,
|
'title' => _m('Subscribers'),
|
||||||
|
'empty_message' => _m('No subscribers'),
|
||||||
|
'sort_options' => [],
|
||||||
|
'page' => $this->int('page') ?? 1,
|
||||||
|
'actors' => $actor->getSubscribers(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -9,10 +9,10 @@ use App\Core\VisibilityScope;
|
|||||||
use App\Entity\Actor;
|
use App\Entity\Actor;
|
||||||
use App\Entity\LocalUser;
|
use App\Entity\LocalUser;
|
||||||
use App\Entity\Note;
|
use App\Entity\Note;
|
||||||
use App\Entity\Subscription;
|
|
||||||
use Component\Group\Entity\GroupInbox;
|
use Component\Group\Entity\GroupInbox;
|
||||||
use Component\Group\Entity\GroupMember;
|
use Component\Group\Entity\GroupMember;
|
||||||
use Component\Group\Entity\LocalGroup;
|
use Component\Group\Entity\LocalGroup;
|
||||||
|
use Component\Subscription\Entity\Subscription;
|
||||||
use Doctrine\Bundle\FixturesBundle\Fixture;
|
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||||
use Doctrine\Persistence\ObjectManager;
|
use Doctrine\Persistence\ObjectManager;
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ use App\Util\Nickname;
|
|||||||
use Component\Avatar\Avatar;
|
use Component\Avatar\Avatar;
|
||||||
use Component\Language\Entity\ActorLanguage;
|
use Component\Language\Entity\ActorLanguage;
|
||||||
use Component\Language\Entity\Language;
|
use Component\Language\Entity\Language;
|
||||||
|
use Component\Subscription\Entity\Subscription;
|
||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
use Functional as F;
|
use Functional as F;
|
||||||
|
|
||||||
@ -242,26 +243,26 @@ class Actor extends Entity
|
|||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
// }}} Autocode
|
// }}} Autocode
|
||||||
|
|
||||||
public const PERSON = 1;
|
public const PERSON = 1;
|
||||||
public const GROUP = 2;
|
public const GROUP = 2;
|
||||||
public const ORGANIZATION = 3;
|
public const ORGANIZATION = 3;
|
||||||
public const BUSINESS = 4;
|
public const BUSINESS = 4;
|
||||||
public const BOT = 5;
|
public const BOT = 5;
|
||||||
|
|
||||||
public static function cacheKeys(int|self $actor_id, mixed $other = null): array
|
public static function cacheKeys(int|self $actor_id, mixed $other = null): array
|
||||||
{
|
{
|
||||||
$actor_id = \is_int($actor_id) ? $actor_id : $actor_id->getId();
|
$actor_id = \is_int($actor_id) ? $actor_id : $actor_id->getId();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => "actor-id-{$actor_id}",
|
'id' => "actor-id-{$actor_id}",
|
||||||
'nickname' => "actor-nickname-id-{$actor_id}",
|
'nickname' => "actor-nickname-id-{$actor_id}",
|
||||||
'fullname' => "actor-fullname-id-{$actor_id}",
|
'fullname' => "actor-fullname-id-{$actor_id}",
|
||||||
'tags' => \is_null($other) ? "actor-tags-{$actor_id}" : "actor-tags-{$actor_id}-by-{$other}", // $other is $context_id
|
'tags' => \is_null($other) ? "actor-tags-{$actor_id}" : "actor-tags-{$actor_id}-by-{$other}", // $other is $context_id
|
||||||
'circles' => "actor-circles-{$actor_id}",
|
'circles' => "actor-circles-{$actor_id}",
|
||||||
'subscriber' => "subscriber-{$actor_id}",
|
'subscriber' => "subscriber-{$actor_id}",
|
||||||
'subscribed' => "subscribed-{$actor_id}",
|
'subscribed' => "subscribed-{$actor_id}",
|
||||||
'relative-nickname' => "actor-{$actor_id}-relative-nickname-{$other}", // $other is $nickname
|
'relative-nickname' => "actor-{$actor_id}-relative-nickname-{$other}", // $other is $nickname
|
||||||
'can-admin' => "actor-{$actor_id}-can-admin-{$other}", // $other is an actor id
|
'can-admin' => "actor-{$actor_id}-can-admin-{$other}", // $other is an actor id
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,17 +287,17 @@ class Actor extends Entity
|
|||||||
|
|
||||||
public static function getById(int $id): ?self
|
public static function getById(int $id): ?self
|
||||||
{
|
{
|
||||||
return Cache::get(self::cacheKeys($id)['id'], fn () => DB::find('actor', ['id' => $id]));
|
return Cache::get(self::cacheKeys($id)['id'], fn() => DB::find('actor', ['id' => $id]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getNicknameById(int $id): string
|
public static function getNicknameById(int $id): string
|
||||||
{
|
{
|
||||||
return Cache::get(self::cacheKeys($id)['nickname'], fn () => self::getById($id)->getNickname());
|
return Cache::get(self::cacheKeys($id)['nickname'], fn() => self::getById($id)->getNickname());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getFullnameById(int $id): ?string
|
public static function getFullnameById(int $id): ?string
|
||||||
{
|
{
|
||||||
return Cache::get(self::cacheKeys($id)['fullname'], fn () => self::getById($id)->getFullname());
|
return Cache::get(self::cacheKeys($id)['fullname'], fn() => self::getById($id)->getFullname());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -324,8 +325,8 @@ class Actor extends Entity
|
|||||||
* - If null = All tags attributed to self by other actors (excludes self tags)
|
* - If null = All tags attributed to self by other actors (excludes self tags)
|
||||||
* - If self = Same as getSelfTags
|
* - If self = Same as getSelfTags
|
||||||
* - otherwise = Tags that $context attributed to $this
|
* - otherwise = Tags that $context attributed to $this
|
||||||
* @param null|int $offset Offset from latest
|
* @param null|int $offset Offset from latest
|
||||||
* @param null|int $limit Max number to get
|
* @param null|int $limit Max number to get
|
||||||
*
|
*
|
||||||
* @return ActorTag[] resulting lists
|
* @return ActorTag[] resulting lists
|
||||||
*/
|
*/
|
||||||
@ -334,7 +335,7 @@ class Actor extends Entity
|
|||||||
if (\is_null($context)) {
|
if (\is_null($context)) {
|
||||||
return Cache::getList(
|
return Cache::getList(
|
||||||
self::cacheKeys($this->getId())['tags'],
|
self::cacheKeys($this->getId())['tags'],
|
||||||
fn () => DB::dql(
|
fn() => DB::dql(
|
||||||
<<< 'EOQ'
|
<<< 'EOQ'
|
||||||
SELECT tag
|
SELECT tag
|
||||||
FROM actor_tag tag
|
FROM actor_tag tag
|
||||||
@ -349,7 +350,7 @@ class Actor extends Entity
|
|||||||
$context_id = \is_int($context) ? $context : $context->getId();
|
$context_id = \is_int($context) ? $context : $context->getId();
|
||||||
return Cache::getList(
|
return Cache::getList(
|
||||||
self::cacheKeys($this->getId(), $context_id)['tags'],
|
self::cacheKeys($this->getId(), $context_id)['tags'],
|
||||||
fn () => DB::dql(
|
fn() => DB::dql(
|
||||||
<<< 'EOQ'
|
<<< 'EOQ'
|
||||||
SELECT tag
|
SELECT tag
|
||||||
FROM actor_tag tag
|
FROM actor_tag tag
|
||||||
@ -367,7 +368,7 @@ class Actor extends Entity
|
|||||||
{
|
{
|
||||||
return Cache::getList(
|
return Cache::getList(
|
||||||
self::cacheKeys($this->getId())['circles'],
|
self::cacheKeys($this->getId())['circles'],
|
||||||
fn () => DB::findBy('actor_circle', ['tagger' => $this->getId()]),
|
fn() => DB::findBy('actor_circle', ['tagger' => $this->getId()]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,10 +376,7 @@ class Actor extends Entity
|
|||||||
{
|
{
|
||||||
return Cache::get(
|
return Cache::get(
|
||||||
self::cacheKeys($this->getId())[$which],
|
self::cacheKeys($this->getId())[$which],
|
||||||
fn () => DB::dql(
|
fn() => DB::count(Subscription::class, [$column => $this->getId()]) - ($this->getIsLocal() ? 1 : 0)
|
||||||
"select count(s) from subscription s where s.{$column} = :{$column}", // Not injecting the parameter value
|
|
||||||
[$column => $this->getId()],
|
|
||||||
)[0][1] - ($this->getIsLocal() ? 1 : 0), // Remove self subscription if local
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,11 +385,31 @@ class Actor extends Entity
|
|||||||
return $this->getSubCount(which: 'subscriber', column: 'subscribed_id');
|
return $this->getSubCount(which: 'subscriber', column: 'subscribed_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSubscribedCount()
|
public function getSubscribedCount(): int
|
||||||
{
|
{
|
||||||
return $this->getSubCount(which: 'subscribed', column: 'subscriber_id');
|
return $this->getSubCount(which: 'subscribed', column: 'subscriber_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getSubscriptions(): array
|
||||||
|
{
|
||||||
|
return DB::dql(<<<EOF
|
||||||
|
SELECT a FROM actor AS a
|
||||||
|
INNER JOIN subscription AS s
|
||||||
|
WITH a.id = s.subscribed_id
|
||||||
|
WHERE s.subscriber_id = :self AND a.id != :self
|
||||||
|
EOF, ['self' => $this->getId()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSubscribers(): array
|
||||||
|
{
|
||||||
|
return DB::dql(<<<EOF
|
||||||
|
SELECT a FROM actor AS a
|
||||||
|
INNER JOIN subscription AS s
|
||||||
|
WITH a.id = s.subscriber_id
|
||||||
|
WHERE s.subscribed_id = :self AND a.id != :self
|
||||||
|
EOF, ['self' => $this->getId()]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve an ambiguous nickname reference, checking in following order:
|
* Resolve an ambiguous nickname reference, checking in following order:
|
||||||
* - Actors that $sender subscribes to
|
* - Actors that $sender subscribes to
|
||||||
|
@ -34,9 +34,9 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace App\Routes;
|
namespace App\Routes;
|
||||||
|
|
||||||
use App\Controller as C;
|
|
||||||
use App\Core\Router\RouteLoader;
|
use App\Core\Router\RouteLoader;
|
||||||
use App\Util\Nickname;
|
use App\Util\Nickname;
|
||||||
|
use Component\Subscription\Controller as C;
|
||||||
|
|
||||||
abstract class Subscribers
|
abstract class Subscribers
|
||||||
{
|
{
|
||||||
|
@ -34,9 +34,9 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace App\Routes;
|
namespace App\Routes;
|
||||||
|
|
||||||
use App\Controller as C;
|
|
||||||
use App\Core\Router\RouteLoader;
|
use App\Core\Router\RouteLoader;
|
||||||
use App\Util\Nickname;
|
use App\Util\Nickname;
|
||||||
|
use Component\Subscription\Controller as C;
|
||||||
|
|
||||||
abstract class Subscriptions
|
abstract class Subscriptions
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user