From e33caa99e5cafe286825bc82aaeceec0517a0805 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 31 Mar 2024 13:14:23 -0400 Subject: [PATCH] add 2024 Universal Code of Conduct Coordinating Committee elections --- .../framework/EventFactory.php | 28 ++++- .../framework/models/DateWrapper.php | 12 +- .../framework/rules/AccountAgeRule.php | 103 ++++++++++++++++++ 3 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 tool-labs/accounteligibility/framework/rules/AccountAgeRule.php diff --git a/tool-labs/accounteligibility/framework/EventFactory.php b/tool-labs/accounteligibility/framework/EventFactory.php index db04bc9..39e0e46 100644 --- a/tool-labs/accounteligibility/framework/EventFactory.php +++ b/tool-labs/accounteligibility/framework/EventFactory.php @@ -14,7 +14,7 @@ class EventFactory */ public function getDefaultEventID() { - return 71; + return 74; } /** @@ -22,6 +22,32 @@ public function getDefaultEventID() */ public function getEvents() { + ########## + ## 2024: Universal Code of Conduct Coordinating Committee elections + ########## + // voters + yield (new Event(74, 2024, 'Universal Code of Conduct Coordinating Committee elections (voters)', 'https://meta.wikimedia.org/wiki/Universal_Code_of_Conduct/Coordinating_Committee/Election/2024/Voter_eligibility_criteria')) + ->addRule(new NotBlockedRule(1), Workflow::HARD_FAIL) // not blocked on more than one wiki + ->addRule(new NotBotRule(), Workflow::HARD_FAIL) + ->addRule(new EditCountRule(300, null, '<20240317', EditCountRule::ACCUMULATE)) // 300 edits before 17 March 2024 + ->addRule(new EditCountRule(20, '20230317', '<20240317', EditCountRule::ACCUMULATE)) // 20 edits between 17 March 2023 and 17 March 2024 + ->withExtraRequirements(['Your account must not be a bot.']) + ->withExceptions([ + 'See the official voting rules for specific exceptions including developers, translators, staff, contractors, community organizers, and tool/script contributors.' + ]); + + // candidates + yield (new Event(73, 2024, 'Universal Code of Conduct Coordinating Committee elections (candidates)', 'https://meta.wikimedia.org/wiki/Universal_Code_of_Conduct/Coordinating_Committee/Election/2024#Call_for_Candidates')) + ->addRule(new NotBlockedRule(), Workflow::HARD_FAIL) // not blocked on any wiki + ->addRule(new NotBotRule(), Workflow::HARD_FAIL) + ->addRule(new AccountAgeRule(365, '<20240317')) // registered at least 365 days before 17 March 2024 + ->addRule(new EditCountRule(500, null, '<20240317', EditCountRule::ACCUMULATE)) // 500 edits before 17 March 2024 + ->withExtraRequirements(['Your account must not be a bot.']) + ->withAction('be a candidate') + ->withExtraRequirements([ + 'You must meet the other candidate eligibility requirements.' + ]); + ########## ## 2024: Vote to ratify the charter for the Universal Code of Conduct Coordinating Committee ########## diff --git a/tool-labs/accounteligibility/framework/models/DateWrapper.php b/tool-labs/accounteligibility/framework/models/DateWrapper.php index fa4ab63..21fba12 100644 --- a/tool-labs/accounteligibility/framework/models/DateWrapper.php +++ b/tool-labs/accounteligibility/framework/models/DateWrapper.php @@ -8,6 +8,12 @@ class DateWrapper ########## ## Accessors ########## + /** + * The date in PHP format. + * @var DateTime + */ + public $date; + /** * The date in MediaWiki's database format. * @var int @@ -34,9 +40,9 @@ class DateWrapper */ public function __construct($date) { - $date = $this->getDate($date); - $this->mediawiki = intval($date->format("YmdHis")); - $this->readable = $date->format("d F Y"); + $this->date = $this->getDate($date); + $this->mediawiki = intval($this->date->format("YmdHis")); + $this->readable = $this->date->format("d F Y"); } diff --git a/tool-labs/accounteligibility/framework/rules/AccountAgeRule.php b/tool-labs/accounteligibility/framework/rules/AccountAgeRule.php new file mode 100644 index 0000000..a7cd753 --- /dev/null +++ b/tool-labs/accounteligibility/framework/rules/AccountAgeRule.php @@ -0,0 +1,103 @@ +minDaysOld = $minDaysOld; + $this->maxDate = $maxDate ? new DateWrapper($maxDate) : null; + } + + /** + * Collect information from a wiki and return whether the rule has been met. + * @param Toolserver $db The database wrapper. + * @param Wiki $wiki The current wiki. + * @param LocalUser $user The local user account. + * @return ResultInfo|null The eligibility check result, or null if the rule doesn't apply to this wiki. + */ + public function accumulate($db, $wiki, $user) + { + // get result + $daysOld = $this->getAccountAge($db, $user); + $isOldEnough = is_null($daysOld) || $daysOld >= $this->minDaysOld; + $result = $isOldEnough ? Result::PASS : Result::ACCUMULATING; + + // get message + $message = + ($isOldEnough ? "was" : "was not") + . " registered at least {$this->minDaysOld} days " + . ($this->maxDate + ? "before {$this->maxDate->readable} " + : "ago " + ) + . (is_null($daysOld) + ? " (registered before 2005)" + : ( + " (registered {$daysOld} days " + . ($this->maxDate ? "before" : "ago") + . ")" + ) + ) + . ($isOldEnough + ? "." + : "..." + ); + + // build result + return new ResultInfo($result, $message); + } + + + ########## + ## Private methods + ########## + /** + * Get the local account age in days. + * @param Toolserver $db The database wrapper. + * @param LocalUser $user The local user account. + * @return int|null Returns the number of days between the user's registration and the max (or current) date, or null if the user was registered before registration dates started being tracked in 2005. + */ + private function getAccountAge($db, $user) + { + $registered = $user->registered; + if (!$user->registered) + $registered = $db->getRegistrationDate($user->id, $user->actorID, "d F Y", true)[0]; + + if (!$registered) + return null; // before 2005 + + $start = DateTime::createFromFormat('YmdHis', $registered); + $end = $this->maxDate + ? $this->maxDate->date + : new DateTime(); + + return $start->diff($end)->days; + } +}