2022-12-01 20:32:12 +01:00
|
|
|
<?php
|
|
|
|
|
2022-12-01 20:52:16 +01:00
|
|
|
namespace com\fwdekker\deathnotifier\tracking;
|
2022-12-01 20:32:12 +01:00
|
|
|
|
2022-12-01 23:46:05 +01:00
|
|
|
use com\fwdekker\deathnotifier\Action;
|
2022-12-01 22:24:20 +01:00
|
|
|
use com\fwdekker\deathnotifier\ActionException;
|
2022-12-01 23:46:05 +01:00
|
|
|
use com\fwdekker\deathnotifier\ActionMethod;
|
2022-12-02 23:05:25 +01:00
|
|
|
use com\fwdekker\deathnotifier\Config;
|
2022-12-01 22:24:20 +01:00
|
|
|
use com\fwdekker\deathnotifier\Database;
|
2022-12-01 23:46:05 +01:00
|
|
|
use com\fwdekker\deathnotifier\LoggerUtil;
|
2022-12-03 14:59:53 +01:00
|
|
|
use com\fwdekker\deathnotifier\mailer\Email;
|
2022-12-01 23:05:12 +01:00
|
|
|
use com\fwdekker\deathnotifier\mailer\MailManager;
|
2022-12-01 22:24:20 +01:00
|
|
|
use com\fwdekker\deathnotifier\mediawiki\MediaWiki;
|
|
|
|
use com\fwdekker\deathnotifier\mediawiki\MediaWikiException;
|
2022-12-01 23:46:05 +01:00
|
|
|
use com\fwdekker\deathnotifier\validator\IsEqualToRule;
|
|
|
|
use Monolog\Logger;
|
2022-12-01 22:24:20 +01:00
|
|
|
use PDO;
|
2022-12-01 20:32:12 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates all trackings that users have added.
|
|
|
|
*/
|
2022-12-01 23:46:05 +01:00
|
|
|
class UpdateTrackingsAction extends Action
|
2022-12-01 20:32:12 +01:00
|
|
|
{
|
2022-12-01 23:46:05 +01:00
|
|
|
/**
|
|
|
|
* @var Logger the logger to log with
|
|
|
|
*/
|
|
|
|
private Logger $logger;
|
2022-12-01 22:24:20 +01:00
|
|
|
/**
|
|
|
|
* @var PDO the database connection to interact with
|
|
|
|
*/
|
|
|
|
private readonly PDO $conn;
|
2022-12-01 20:32:12 +01:00
|
|
|
/**
|
|
|
|
* @var TrackingManager the manager through which trackings should be updated
|
|
|
|
*/
|
|
|
|
private readonly TrackingManager $tracking_manager;
|
2022-12-01 22:24:20 +01:00
|
|
|
/**
|
|
|
|
* @var MediaWiki the instance to connect to Wikipedia with
|
|
|
|
*/
|
|
|
|
private readonly MediaWiki $mediawiki;
|
|
|
|
/**
|
2022-12-01 23:05:12 +01:00
|
|
|
* @var MailManager the mailer to send emails with
|
2022-12-01 22:24:20 +01:00
|
|
|
*/
|
2022-12-01 23:05:12 +01:00
|
|
|
private readonly MailManager $mailer;
|
2022-12-01 20:32:12 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructs a new `UpdateTrackingsAction`.
|
|
|
|
*
|
2022-12-01 22:24:20 +01:00
|
|
|
* @param PDO $conn the database connection to interact with
|
2022-12-01 20:32:12 +01:00
|
|
|
* @param TrackingManager $tracking_manager the manager through which trackings should be updated
|
2022-12-01 22:24:20 +01:00
|
|
|
* @param MediaWiki $mediawiki the instance to connect to Wikipedia with
|
2022-12-01 23:05:12 +01:00
|
|
|
* @param MailManager $mailer the mailer to send emails with
|
2022-12-01 20:32:12 +01:00
|
|
|
*/
|
2022-12-02 23:05:25 +01:00
|
|
|
public function __construct(PDO $conn, TrackingManager $tracking_manager, MediaWiki $mediawiki, MailManager $mailer)
|
2022-12-01 20:32:12 +01:00
|
|
|
{
|
2022-12-01 23:46:05 +01:00
|
|
|
parent::__construct(
|
|
|
|
ActionMethod::CLI,
|
|
|
|
"update-trackings",
|
2022-12-02 23:05:25 +01:00
|
|
|
rule_lists: [
|
|
|
|
"password" => [new IsEqualToRule(Config::get()["admin"]["cli_secret"], "Incorrect password.")]
|
|
|
|
],
|
2022-12-01 23:46:05 +01:00
|
|
|
);
|
2022-12-01 20:32:12 +01:00
|
|
|
|
2022-12-01 23:46:05 +01:00
|
|
|
$this->logger = LoggerUtil::with_name($this::class);
|
2022-12-01 22:24:20 +01:00
|
|
|
$this->conn = $conn;
|
2022-12-01 20:32:12 +01:00
|
|
|
$this->tracking_manager = $tracking_manager;
|
2022-12-01 22:24:20 +01:00
|
|
|
$this->mediawiki = $mediawiki;
|
|
|
|
$this->mailer = $mailer;
|
2022-12-01 20:32:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates all trackings that users have added.
|
|
|
|
*
|
2022-12-03 14:59:53 +01:00
|
|
|
* @return null
|
2022-12-01 22:24:20 +01:00
|
|
|
* @throws ActionException if the Wikipedia API could not be reached
|
2022-12-01 20:32:12 +01:00
|
|
|
*/
|
|
|
|
public function handle(): mixed
|
|
|
|
{
|
2022-12-01 22:24:20 +01:00
|
|
|
$names = $this->tracking_manager->list_all_unique_person_names();
|
2022-12-01 23:46:05 +01:00
|
|
|
if (empty($names)) return null;
|
2022-12-01 22:24:20 +01:00
|
|
|
|
|
|
|
// Fetch changes
|
|
|
|
try {
|
|
|
|
$people_statuses = $this->mediawiki->query_person_info($names);
|
2022-12-01 23:46:05 +01:00
|
|
|
} catch (MediaWikiException $exception) {
|
|
|
|
$this->logger->error("Failed to query page info.", ["cause" => $exception, "pages" => $names]);
|
2022-12-01 22:24:20 +01:00
|
|
|
throw new ActionException("Could not reach Wikipedia. Maybe the website is down?");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Process changes
|
|
|
|
$actual_deletions = [];
|
|
|
|
$undeletions = [];
|
|
|
|
$status_changes = [];
|
|
|
|
Database::transaction(
|
|
|
|
$this->conn,
|
|
|
|
function () use (
|
|
|
|
$people_statuses,
|
|
|
|
&$actual_deletions,
|
|
|
|
&$undeletions,
|
|
|
|
&$status_changes
|
|
|
|
) {
|
|
|
|
$this->tracking_manager->rename_persons($people_statuses->redirects);
|
|
|
|
$actual_deletions = $this->tracking_manager->delete_persons($people_statuses->missing);
|
2022-12-02 23:05:25 +01:00
|
|
|
[$undeletions, $status_changes] = $this->tracking_manager->update_statuses($people_statuses->results);
|
2022-12-01 22:24:20 +01:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Send mails
|
|
|
|
// TODO: Restrict number of notifications to 1 per hour (excluding "oops we're not sure" message)
|
|
|
|
// TODO: Reuse `stmt`s for listing trackers and queueing emails to reduce overheads
|
|
|
|
foreach ($actual_deletions as $deletion)
|
|
|
|
foreach ($this->tracking_manager->list_trackers($deletion) as $user_email)
|
|
|
|
$this->mailer->queue_email(new NotifyArticleDeletedEmail($user_email, $deletion));
|
|
|
|
|
|
|
|
foreach ($undeletions as $undeletion)
|
|
|
|
foreach ($this->tracking_manager->list_trackers($undeletion) as $user_email)
|
|
|
|
$this->mailer->queue_email(new NotifyArticleUndeletedEmail($user_email, $undeletion));
|
|
|
|
|
|
|
|
foreach ($status_changes as $person_name => $person_status)
|
|
|
|
foreach ($this->tracking_manager->list_trackers($person_name) as $user_email)
|
|
|
|
$this->mailer->queue_email(new NotifyStatusChangedEmail($user_email, $person_name, $person_status));
|
2022-12-01 20:32:12 +01:00
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2022-12-03 14:59:53 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An email to inform a user that a tracked article has been deleted.
|
|
|
|
*/
|
|
|
|
class NotifyArticleDeletedEmail extends Email
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* A string identifying the type of email.
|
|
|
|
*/
|
|
|
|
public const TYPE = "notify-article-deleted";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string the name of the article that was deleted
|
|
|
|
*/
|
|
|
|
public string $name;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructs a new `NotifyArticleDeletedEmail`.
|
|
|
|
*
|
|
|
|
* @param string $recipient the intended recipient of the email
|
|
|
|
* @param string $name the name of the article that was deleted
|
|
|
|
*/
|
|
|
|
public function __construct(string $recipient, string $name)
|
|
|
|
{
|
|
|
|
parent::__construct($this::TYPE . "/" . $name, $recipient);
|
|
|
|
|
|
|
|
$this->name = $name;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function get_subject(): string
|
|
|
|
{
|
|
|
|
return "$this->name article has been deleted";
|
|
|
|
}
|
|
|
|
|
|
|
|
public function get_body(): string
|
|
|
|
{
|
|
|
|
$base_path = Config::get()["server"]["base_path"];
|
|
|
|
|
|
|
|
return
|
|
|
|
"The Wikipedia article about $this->name has been deleted. " .
|
|
|
|
"Death Notifier is now unable to send you a notification if $this->name dies. " .
|
|
|
|
"If the Wikipedia article is ever re-created, Death Notifier will automatically resume tracking this " .
|
|
|
|
"article, and you will receive another notification." .
|
|
|
|
"\n\n" .
|
|
|
|
"You are receiving this message because of the preferences in your Death Notifier account. " .
|
|
|
|
"To unsubscribe from these messages, go to the Death Notifier website, log in, and change your email " .
|
|
|
|
"preferences." .
|
|
|
|
"\n\n" .
|
|
|
|
$base_path;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An email to inform a user that a tracked article has been re-created.
|
|
|
|
*/
|
|
|
|
class NotifyArticleUndeletedEmail extends Email
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* A string identifying the type of email.
|
|
|
|
*/
|
|
|
|
public const TYPE = "notify-article-undeleted";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string the name of the article that was re-created
|
|
|
|
*/
|
|
|
|
public string $name;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructs a new `NotifyArticleUndeletedEmail`.
|
|
|
|
*
|
|
|
|
* @param string $recipient the intended recipient of the email
|
|
|
|
* @param string $name the name of the article that was re-created
|
|
|
|
*/
|
|
|
|
public function __construct(string $recipient, string $name)
|
|
|
|
{
|
|
|
|
parent::__construct($this::TYPE . "/" . $name, $recipient);
|
|
|
|
|
|
|
|
$this->name = $name;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function get_subject(): string
|
|
|
|
{
|
|
|
|
return "$this->name article has been re-created";
|
|
|
|
}
|
|
|
|
|
|
|
|
public function get_body(): string
|
|
|
|
{
|
|
|
|
$base_path = Config::get()["server"]["base_path"];
|
|
|
|
|
|
|
|
return
|
|
|
|
"The Wikipedia article about $this->name has been re-created. " .
|
|
|
|
"Death Notifier will once again track the article and notify you if $this->name dies." .
|
|
|
|
"\n\n" .
|
|
|
|
"You are receiving this message because of the preferences in your Death Notifier account. " .
|
|
|
|
"To unsubscribe from these messages, go to the Death Notifier website, log in, and change your email " .
|
|
|
|
"preferences." .
|
|
|
|
"\n\n" .
|
|
|
|
$base_path;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An email to inform a user a tracker person's status has changed.
|
|
|
|
*/
|
|
|
|
class NotifyStatusChangedEmail extends Email
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* A string identifying the type of email.
|
|
|
|
*/
|
|
|
|
public const TYPE = "notify-status-changed";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string the name of the person whose status has changed
|
|
|
|
*/
|
|
|
|
public string $name;
|
|
|
|
/**
|
|
|
|
* @var string the new status of the person
|
|
|
|
*/
|
|
|
|
public string $new_status;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructs a new `NotifyStatusChangedEmail`.
|
|
|
|
*
|
|
|
|
* @param string $recipient the intended recipient of the email
|
|
|
|
* @param string $name the name of the person who died
|
|
|
|
* @param string $new_status the new status of the person
|
|
|
|
*/
|
|
|
|
public function __construct(string $recipient, string $name, string $new_status)
|
|
|
|
{
|
|
|
|
parent::__construct($this::TYPE . "/" . $name, $recipient);
|
|
|
|
|
|
|
|
$this->name = $name;
|
|
|
|
$this->new_status = $new_status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function get_subject(): string
|
|
|
|
{
|
|
|
|
return "$this->name may be $this->new_status";
|
|
|
|
}
|
|
|
|
|
|
|
|
public function get_body(): string
|
|
|
|
{
|
|
|
|
$base_path = Config::get()["server"]["base_path"];
|
|
|
|
|
|
|
|
return
|
|
|
|
"Someone has edited Wikipedia to state that $this->name is $this->new_status. " .
|
|
|
|
"For more information, read their Wikipedia article at " .
|
|
|
|
"https://en.wikipedia.org/wiki/" . rawurlencode($this->name) .
|
|
|
|
"\n\n" .
|
|
|
|
"You are receiving this message because of the preferences in your Death Notifier account. " .
|
|
|
|
"To unsubscribe from these messages, go to the Death Notifier website, log in, and change your email " .
|
|
|
|
"preferences." .
|
|
|
|
"\n\n" .
|
|
|
|
$base_path;
|
|
|
|
}
|
|
|
|
}
|