mediawiki-extensions-Echo/includes/api/Push/ApiEchoPushSubscriptionsCreate.php
Michael Holloway 3513c642dd Create push subscription manager group/right to clean up dead subs
Creates a new push-subscription-manager group and an associated
right, manage-all-push-subscriptions. The purpose of this is to
allow privileged accounts to purge expired subscriptions from the
database on behalf of other users. A user with this right will be
permitted to delete any subscription from the DB based on the token
alone. For all other users, deletion requests will be limited to
those associated with the requesting user's central ID.

This right will be granted to a bot account on Metawiki associated
with the Wikimedia push notifications service, and the push
notifications service account will make push subscription delete
requests to the API for subscriptions for which vendor APIs return bad
subscription responses.

Additionally, the providertoken parameter to ApiPushSubscriptionDelete
is updated to allow multiple providertoken values.

Bug: T259148
Change-Id: Ia6c17588ee94e6be74e5e3a75eb33e38f172fc93
2020-08-20 17:08:48 -04:00

138 lines
3.4 KiB
PHP

<?php
namespace EchoPush\Api;
use ApiBase;
use ApiMain;
use EchoPush\SubscriptionManager;
use EchoPush\Utils;
use EchoServices;
use OverflowException;
use Wikimedia\ParamValidator\ParamValidator;
class ApiEchoPushSubscriptionsCreate extends ApiBase {
/**
* Supported push notification providers:
* (1) fcm: Firebase Cloud Messaging
* (2) apns: Apple Push Notification Service
*/
private const PROVIDERS = [ 'fcm', 'apns' ];
/** @var ApiBase */
private $parent;
/** @var SubscriptionManager */
private $subscriptionManager;
/**
* Static entry point for initializing the module
* @param ApiBase $parent Parent module
* @param string $name Module name
* @return ApiEchoPushSubscriptionsCreate
*/
public static function factory( ApiBase $parent, string $name ):
ApiEchoPushSubscriptionsCreate {
$subscriptionManger = EchoServices::getInstance()->getPushSubscriptionManager();
$module = new self( $parent->getMain(), $name, $subscriptionManger );
$module->parent = $parent;
return $module;
}
/**
* @param ApiMain $mainModule
* @param string $moduleName
* @param SubscriptionManager $subscriptionManager
*/
public function __construct(
ApiMain $mainModule,
string $moduleName,
SubscriptionManager $subscriptionManager
) {
parent::__construct( $mainModule, $moduleName );
$this->subscriptionManager = $subscriptionManager;
}
/**
* Entry point for executing the module.
* @inheritDoc
*/
public function execute(): void {
$provider = $this->getParameter( 'provider' );
$token = $this->getParameter( 'providertoken' );
$topic = null;
// check if metadata is a JSON string correctly encoded
if ( $provider === 'apns' ) {
$topic = $this->getParameter( 'topic' );
if ( !$topic ) {
$this->dieWithError( 'apierror-echo-push-topic-required' );
}
}
$userId = Utils::getPushUserId( $this->getUser() );
try {
$success = $this->subscriptionManager->create( $provider, $token, $userId, $topic );
} catch ( OverflowException $e ) {
$maxSubscriptionsPerUser = $this->subscriptionManager->getMaxSubscriptionsPerUser();
$this->dieWithError( [ 'apierror-echo-push-too-many-subscriptions',
$maxSubscriptionsPerUser ] );
}
if ( !$success ) {
$this->dieWithError( 'apierror-echo-push-token-exists' );
}
}
/**
* Get the parent module.
* @return ApiBase
*/
public function getParent(): ApiBase {
return $this->parent;
}
/** @inheritDoc */
protected function getAllowedParams(): array {
return [
'provider' => [
ParamValidator::PARAM_TYPE => self::PROVIDERS,
ParamValidator::PARAM_REQUIRED => true,
],
'providertoken' => [
ParamValidator::PARAM_TYPE => 'string',
ParamValidator::PARAM_REQUIRED => true,
],
'topic' => [
ParamValidator::PARAM_TYPE => 'string',
ParamValidator::PARAM_REQUIRED => false,
],
];
}
/** @inheritDoc */
protected function getExamplesMessages(): array {
return [
"action=echopushsubscriptions&command=create&provider=fcm&providertoken=ABC123" =>
"apihelp-echopushsubscriptions+create-example"
];
}
// The parent module already enforces these but they make documentation nicer.
/** @inheritDoc */
public function isWriteMode(): bool {
return true;
}
/** @inheritDoc */
public function mustBePosted(): bool {
return true;
}
/** @inheritDoc */
public function isInternal(): bool {
// experimental!
return true;
}
}