Path: blob/master/src/applications/auth/storage/PhabricatorAuthContactNumber.php
12256 views
<?php123final class PhabricatorAuthContactNumber4extends PhabricatorAuthDAO5implements6PhabricatorApplicationTransactionInterface,7PhabricatorPolicyInterface,8PhabricatorDestructibleInterface,9PhabricatorEditEngineMFAInterface {1011protected $objectPHID;12protected $contactNumber;13protected $uniqueKey;14protected $status;15protected $isPrimary;16protected $properties = array();1718const STATUS_ACTIVE = 'active';19const STATUS_DISABLED = 'disabled';2021protected function getConfiguration() {22return array(23self::CONFIG_SERIALIZATION => array(24'properties' => self::SERIALIZATION_JSON,25),26self::CONFIG_AUX_PHID => true,27self::CONFIG_COLUMN_SCHEMA => array(28'contactNumber' => 'text255',29'status' => 'text32',30'uniqueKey' => 'bytes12?',31'isPrimary' => 'bool',32),33self::CONFIG_KEY_SCHEMA => array(34'key_object' => array(35'columns' => array('objectPHID'),36),37'key_unique' => array(38'columns' => array('uniqueKey'),39'unique' => true,40),41),42) + parent::getConfiguration();43}4445public static function initializeNewContactNumber($object) {46return id(new self())47->setStatus(self::STATUS_ACTIVE)48->setObjectPHID($object->getPHID())49->setIsPrimary(0);50}5152public function getPHIDType() {53return PhabricatorAuthContactNumberPHIDType::TYPECONST;54}5556public function getURI() {57return urisprintf('/auth/contact/%s/', $this->getID());58}5960public function getObjectName() {61return pht('Contact Number %d', $this->getID());62}6364public function getDisplayName() {65return $this->getContactNumber();66}6768public function isDisabled() {69return ($this->getStatus() === self::STATUS_DISABLED);70}7172public function newIconView() {73if ($this->isDisabled()) {74return id(new PHUIIconView())75->setIcon('fa-ban', 'grey')76->setTooltip(pht('Disabled'));77}7879if ($this->getIsPrimary()) {80return id(new PHUIIconView())81->setIcon('fa-certificate', 'blue')82->setTooltip(pht('Primary Number'));83}8485return id(new PHUIIconView())86->setIcon('fa-hashtag', 'bluegrey')87->setTooltip(pht('Active Phone Number'));88}8990public function newUniqueKey() {91$parts = array(92// This is future-proofing for a world where we have multiple types93// of contact numbers, so we might be able to avoid re-hashing94// everything.95'phone',96$this->getContactNumber(),97);9899$parts = implode("\0", $parts);100101return PhabricatorHash::digestForIndex($parts);102}103104public function save() {105// We require that active contact numbers be unique, but it's okay to106// disable a number and then reuse it somewhere else.107if ($this->isDisabled()) {108$this->uniqueKey = null;109} else {110$this->uniqueKey = $this->newUniqueKey();111}112113parent::save();114115return $this->updatePrimaryContactNumber();116}117118private function updatePrimaryContactNumber() {119// Update the "isPrimary" column so that at most one number is primary for120// each user, and no disabled number is primary.121122$conn = $this->establishConnection('w');123$this_id = (int)$this->getID();124125if ($this->getIsPrimary() && !$this->isDisabled()) {126// If we're trying to make this number primary and it's active, great:127// make this number the primary number.128$primary_id = $this_id;129} else {130// If we aren't trying to make this number primary or it is disabled,131// pick another number to make primary if we can. A number must be active132// to become primary.133134// If there are multiple active numbers, pick the oldest one currently135// marked primary (usually, this should mean that we just keep the136// current primary number as primary).137138// If none are marked primary, just pick the oldest one.139$primary_row = queryfx_one(140$conn,141'SELECT id FROM %R142WHERE objectPHID = %s AND status = %s143ORDER BY isPrimary DESC, id ASC144LIMIT 1',145$this,146$this->getObjectPHID(),147self::STATUS_ACTIVE);148if ($primary_row) {149$primary_id = (int)$primary_row['id'];150} else {151$primary_id = -1;152}153}154155// Set the chosen number to primary, and all other numbers to nonprimary.156157queryfx(158$conn,159'UPDATE %R SET isPrimary = IF(id = %d, 1, 0)160WHERE objectPHID = %s',161$this,162$primary_id,163$this->getObjectPHID());164165$this->setIsPrimary((int)($primary_id === $this_id));166167return $this;168}169170public static function getStatusNameMap() {171return ipull(self::getStatusPropertyMap(), 'name');172}173174private static function getStatusPropertyMap() {175return array(176self::STATUS_ACTIVE => array(177'name' => pht('Active'),178),179self::STATUS_DISABLED => array(180'name' => pht('Disabled'),181),182);183}184185public function getSortVector() {186// Sort the primary number first, then active numbers, then disabled187// numbers. In each group, sort from oldest to newest.188return id(new PhutilSortVector())189->addInt($this->getIsPrimary() ? 0 : 1)190->addInt($this->isDisabled() ? 1 : 0)191->addInt($this->getID());192}193194195/* -( PhabricatorPolicyInterface )----------------------------------------- */196197198public function getCapabilities() {199return array(200PhabricatorPolicyCapability::CAN_VIEW,201PhabricatorPolicyCapability::CAN_EDIT,202);203}204205public function getPolicy($capability) {206return $this->getObjectPHID();207}208209public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {210return false;211}212213214/* -( PhabricatorDestructibleInterface )----------------------------------- */215216217public function destroyObjectPermanently(218PhabricatorDestructionEngine $engine) {219$this->delete();220}221222223/* -( PhabricatorApplicationTransactionInterface )------------------------- */224225226public function getApplicationTransactionEditor() {227return new PhabricatorAuthContactNumberEditor();228}229230public function getApplicationTransactionTemplate() {231return new PhabricatorAuthContactNumberTransaction();232}233234235/* -( PhabricatorEditEngineMFAInterface )---------------------------------- */236237238public function newEditEngineMFAEngine() {239return new PhabricatorAuthContactNumberMFAEngine();240}241242}243244245