28 private JobQueueGroup $jobQueueGroup;
29 private bool $isMessageGroupSubscriptionEnabled;
30 private UserIdentityLookup $userIdentityLookup;
31 private array $queuedMessages = [];
32 private LoggerInterface $logger;
34 public const STATE_ADDED =
'added';
35 public const CONSTRUCTOR_OPTIONS = [
'TranslateEnableMessageGroupSubscription' ];
37 public const NOT_ENABLED =
'mgs-not-enabled';
38 public const UNNAMED_USER_UNSUPPORTED =
'mgs-unnamed-user-unsupported';
39 public const DYNAMIC_GROUP_UNSUPPORTED =
'mgs-dynamic-group-unsupported';
41 public function __construct(
43 JobQueueGroup $jobQueueGroup,
44 UserIdentityLookup $userIdentityLookup,
45 LoggerInterface $logger,
46 ServiceOptions $options
48 $this->groupSubscriptionStore = $groupSubscriptionStore;
49 $this->jobQueueGroup = $jobQueueGroup;
50 $this->userIdentityLookup = $userIdentityLookup;
51 $this->logger = $logger;
52 $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
53 $this->isMessageGroupSubscriptionEnabled = $options->get(
'TranslateEnableMessageGroupSubscription' );
56 public function isEnabled():
bool {
57 return $this->isMessageGroupSubscriptionEnabled;
60 public function subscribeToGroup(
MessageGroup $group, User $user ): StatusValue {
61 $status = $this->canUserSubscribeToGroup( $group, $user );
62 if ( !$status->isOK() ) {
66 $this->groupSubscriptionStore->addSubscription( $group->
getId(), $user->getId() );
67 return StatusValue::newGood();
70 public function isUserSubscribedTo(
MessageGroup $group, UserIdentity $user ):
bool {
71 return $this->groupSubscriptionStore->getSubscriptions( [ $group->
getId() ], $user->getId() )->count() !== 0;
74 public function unsubscribeFromGroup(
MessageGroup $group, UserIdentity $user ):
void {
75 $this->groupSubscriptionStore->removeSubscriptions( $group->
getId(), $user->getId() );
81 $result = $this->groupSubscriptionStore->getSubscriptions(
null, $user->getId() );
82 foreach ( $result as $row ) {
83 $subscriptions[] = $row->tmgs_group;
85 return $subscriptions;
100 foreach ( $groupIds as $groupId ) {
101 $this->queuedMessages[ $groupId ][ $state ][] = $messageTitle->getPrefixedDBkey();
105 public function queueNotificationJob(): void {
106 if ( !$this->isEnabled() || $this->queuedMessages === [] ) {
110 $this->jobQueueGroup->push( MessageGroupSubscriptionNotificationJob::newJob( $this->queuedMessages ) );
111 $this->logger->debug(
112 'Queued job with changes for {countGroups} groups',
113 [
'countGroups' => count( $this->queuedMessages ) ]
116 $this->queuedMessages = [];
119 public function sendNotifications( array $changesToProcess ): void {
120 if ( !$this->isEnabled() || $changesToProcess === [] ) {
124 $groupIds = array_keys( $changesToProcess );
125 $allGroupSubscribers = $this->getSubscriberIdsForGroups( $groupIds );
128 if ( !$allGroupSubscribers ) {
129 $this->logger->info(
'No subscribers for groups.' );
133 $groups = MessageGroups::getGroupsById( $groupIds );
134 foreach ( $changesToProcess as $groupId => $state ) {
135 $group = $groups[ $groupId ] ??
null;
137 $this->logger->debug(
138 'Group not found {groupId}.',
139 [
'groupId' => $groupId ]
144 $groupSubscribers = $allGroupSubscribers[ $groupId ] ?? [];
145 if ( $groupSubscribers === [] ) {
147 'No subscribers found for {groupId} group.',
148 [
'groupId' => $groupId ]
154 'type' =>
'translate-mgs-message-added',
156 'groupId' => $groupId,
163 'Event created for {groupId} with {subscriberCount} subscribers.',
165 'groupId' => $groupId,
166 'subscriberCount' => count( $groupSubscribers )
172 public function handleMessageIndexUpdate( MessageHandle $handle, array $old, array $new ): void {
173 $addedGroups = array_diff( $new, $old );
174 if ( $addedGroups ) {
175 $this->queueMessage( $handle->getTitle(), self::STATE_ADDED, $addedGroups );
184 $groupSubscriberIds = $this->getSubscriberIdsForGroups( [ $groupId ] );
185 $groupSubscriberIds = $groupSubscriberIds[ $groupId ] ?? [];
186 if ( $groupSubscriberIds === [] ) {
187 return new EmptyIterator();
190 return $this->userIdentityLookup->newSelectQueryBuilder()
191 ->whereUserIds( $groupSubscriberIds )
192 ->caller( __METHOD__ )
193 ->fetchUserIdentities();
202 private function getSubscriberIdsForGroups( array $groupIds ): array {
203 $dbGroupSubscriptions = $this->groupSubscriptionStore->getSubscriptions( $groupIds, null );
204 $groupSubscriptions = [];
206 foreach ( $dbGroupSubscriptions as $row ) {
207 $groupSubscriptions[ $row->tmgs_group ][] = (int)$row->tmgs_user_id;
210 return $groupSubscriptions;
213 public function canUserSubscribeToGroup(
MessageGroup $group, User $user ): StatusValue {
214 if ( !$this->isEnabled() ) {
215 return StatusValue::newFatal( self::NOT_ENABLED );
218 if ( MessageGroups::isDynamic( $group ) ) {
219 return StatusValue::newFatal( self::DYNAMIC_GROUP_UNSUPPORTED );
222 if ( !$user->isNamed() ) {
223 return StatusValue::newFatal( self::UNNAMED_USER_UNSUPPORTED );
226 return StatusValue::newGood();