Changeset View
Changeset View
Standalone View
Standalone View
src/applications/auth/storage/PhabricatorAuthContactNumber.php
| <?php | <?php | ||||
| final class PhabricatorAuthContactNumber | final class PhabricatorAuthContactNumber | ||||
| extends PhabricatorAuthDAO | extends PhabricatorAuthDAO | ||||
| implements | implements | ||||
| PhabricatorApplicationTransactionInterface, | PhabricatorApplicationTransactionInterface, | ||||
| PhabricatorPolicyInterface, | PhabricatorPolicyInterface, | ||||
| PhabricatorDestructibleInterface { | PhabricatorDestructibleInterface { | ||||
| protected $objectPHID; | protected $objectPHID; | ||||
| protected $contactNumber; | protected $contactNumber; | ||||
| protected $uniqueKey; | protected $uniqueKey; | ||||
| protected $status; | protected $status; | ||||
| protected $isPrimary; | |||||
| protected $properties = array(); | protected $properties = array(); | ||||
| const STATUS_ACTIVE = 'active'; | const STATUS_ACTIVE = 'active'; | ||||
| const STATUS_DISABLED = 'disabled'; | const STATUS_DISABLED = 'disabled'; | ||||
| protected function getConfiguration() { | protected function getConfiguration() { | ||||
| return array( | return array( | ||||
| self::CONFIG_SERIALIZATION => array( | self::CONFIG_SERIALIZATION => array( | ||||
| 'properties' => self::SERIALIZATION_JSON, | 'properties' => self::SERIALIZATION_JSON, | ||||
| ), | ), | ||||
| self::CONFIG_AUX_PHID => true, | self::CONFIG_AUX_PHID => true, | ||||
| self::CONFIG_COLUMN_SCHEMA => array( | self::CONFIG_COLUMN_SCHEMA => array( | ||||
| 'contactNumber' => 'text255', | 'contactNumber' => 'text255', | ||||
| 'status' => 'text32', | 'status' => 'text32', | ||||
| 'uniqueKey' => 'bytes12?', | 'uniqueKey' => 'bytes12?', | ||||
| 'isPrimary' => 'bool', | |||||
| ), | ), | ||||
| self::CONFIG_KEY_SCHEMA => array( | self::CONFIG_KEY_SCHEMA => array( | ||||
| 'key_object' => array( | 'key_object' => array( | ||||
| 'columns' => array('objectPHID'), | 'columns' => array('objectPHID'), | ||||
| ), | ), | ||||
| 'key_unique' => array( | 'key_unique' => array( | ||||
| 'columns' => array('uniqueKey'), | 'columns' => array('uniqueKey'), | ||||
| 'unique' => true, | 'unique' => true, | ||||
| ), | ), | ||||
| ), | ), | ||||
| ) + parent::getConfiguration(); | ) + parent::getConfiguration(); | ||||
| } | } | ||||
| public static function initializeNewContactNumber($object) { | public static function initializeNewContactNumber($object) { | ||||
| return id(new self()) | return id(new self()) | ||||
| ->setStatus(self::STATUS_ACTIVE) | ->setStatus(self::STATUS_ACTIVE) | ||||
| ->setObjectPHID($object->getPHID()); | ->setObjectPHID($object->getPHID()) | ||||
| ->setIsPrimary(0); | |||||
| } | } | ||||
| public function getPHIDType() { | public function getPHIDType() { | ||||
| return PhabricatorAuthContactNumberPHIDType::TYPECONST; | return PhabricatorAuthContactNumberPHIDType::TYPECONST; | ||||
| } | } | ||||
| public function getURI() { | public function getURI() { | ||||
| return urisprintf('/auth/contact/%s/', $this->getID()); | return urisprintf('/auth/contact/%s/', $this->getID()); | ||||
| Show All 13 Lines | final class PhabricatorAuthContactNumber | ||||
| public function newIconView() { | public function newIconView() { | ||||
| if ($this->isDisabled()) { | if ($this->isDisabled()) { | ||||
| return id(new PHUIIconView()) | return id(new PHUIIconView()) | ||||
| ->setIcon('fa-ban', 'grey') | ->setIcon('fa-ban', 'grey') | ||||
| ->setTooltip(pht('Disabled')); | ->setTooltip(pht('Disabled')); | ||||
| } | } | ||||
| if ($this->getIsPrimary()) { | |||||
| return id(new PHUIIconView()) | return id(new PHUIIconView()) | ||||
| ->setIcon('fa-mobile', 'green') | ->setIcon('fa-certificate', 'blue') | ||||
| ->setTooltip(pht('Primary Number')); | |||||
| } | |||||
| return id(new PHUIIconView()) | |||||
| ->setIcon('fa-hashtag', 'bluegrey') | |||||
| ->setTooltip(pht('Active Phone Number')); | ->setTooltip(pht('Active Phone Number')); | ||||
| } | } | ||||
| public function newUniqueKey() { | public function newUniqueKey() { | ||||
| $parts = array( | $parts = array( | ||||
| // This is future-proofing for a world where we have multiple types | // This is future-proofing for a world where we have multiple types | ||||
| // of contact numbers, so we might be able to avoid re-hashing | // of contact numbers, so we might be able to avoid re-hashing | ||||
| // everything. | // everything. | ||||
| Show All 10 Lines | public function save() { | ||||
| // We require that active contact numbers be unique, but it's okay to | // We require that active contact numbers be unique, but it's okay to | ||||
| // disable a number and then reuse it somewhere else. | // disable a number and then reuse it somewhere else. | ||||
| if ($this->isDisabled()) { | if ($this->isDisabled()) { | ||||
| $this->uniqueKey = null; | $this->uniqueKey = null; | ||||
| } else { | } else { | ||||
| $this->uniqueKey = $this->newUniqueKey(); | $this->uniqueKey = $this->newUniqueKey(); | ||||
| } | } | ||||
| return parent::save(); | parent::save(); | ||||
| return $this->updatePrimaryContactNumber(); | |||||
| } | |||||
| private function updatePrimaryContactNumber() { | |||||
| // Update the "isPrimary" column so that at most one number is primary for | |||||
| // each user, and no disabled number is primary. | |||||
| $conn = $this->establishConnection('w'); | |||||
| $this_id = (int)$this->getID(); | |||||
| if ($this->getIsPrimary() && !$this->isDisabled()) { | |||||
| // If we're trying to make this number primary and it's active, great: | |||||
| // make this number the primary number. | |||||
| $primary_id = $this_id; | |||||
| } else { | |||||
| // If we aren't trying to make this number primary or it is disabled, | |||||
| // pick another number to make primary if we can. A number must be active | |||||
| // to become primary. | |||||
| // If there are multiple active numbers, pick the oldest one currently | |||||
| // marked primary (usually, this should mean that we just keep the | |||||
| // current primary number as primary). | |||||
| // If none are marked primary, just pick the oldest one. | |||||
| $primary_row = queryfx_one( | |||||
| $conn, | |||||
| 'SELECT id FROM %R | |||||
| WHERE objectPHID = %s AND status = %s | |||||
| ORDER BY isPrimary DESC, id ASC | |||||
| LIMIT 1', | |||||
| $this, | |||||
| $this->getObjectPHID(), | |||||
| self::STATUS_ACTIVE); | |||||
| if ($primary_row) { | |||||
| $primary_id = (int)$primary_row['id']; | |||||
| } else { | |||||
| $primary_id = -1; | |||||
| } | |||||
| } | |||||
| // Set the chosen number to primary, and all other numbers to nonprimary. | |||||
| queryfx( | |||||
| $conn, | |||||
| 'UPDATE %R SET isPrimary = IF(id = %d, 1, 0) | |||||
| WHERE objectPHID = %s', | |||||
| $this, | |||||
| $primary_id, | |||||
| $this->getObjectPHID()); | |||||
| $this->setIsPrimary((int)($primary_id === $this_id)); | |||||
| return $this; | |||||
| } | } | ||||
| public static function getStatusNameMap() { | public static function getStatusNameMap() { | ||||
| return ipull(self::getStatusPropertyMap(), 'name'); | return ipull(self::getStatusPropertyMap(), 'name'); | ||||
| } | } | ||||
| private static function getStatusPropertyMap() { | private static function getStatusPropertyMap() { | ||||
| return array( | return array( | ||||
| self::STATUS_ACTIVE => array( | self::STATUS_ACTIVE => array( | ||||
| 'name' => pht('Active'), | 'name' => pht('Active'), | ||||
| ), | ), | ||||
| self::STATUS_DISABLED => array( | self::STATUS_DISABLED => array( | ||||
| 'name' => pht('Disabled'), | 'name' => pht('Disabled'), | ||||
| ), | ), | ||||
| ); | ); | ||||
| } | } | ||||
| public function getSortVector() { | |||||
| // Sort the primary number first, then active numbers, then disabled | |||||
| // numbers. In each group, sort from oldest to newest. | |||||
| return id(new PhutilSortVector()) | |||||
| ->addInt($this->getIsPrimary() ? 0 : 1) | |||||
| ->addInt($this->isDisabled() ? 1 : 0) | |||||
| ->addInt($this->getID()); | |||||
| } | |||||
| /* -( PhabricatorPolicyInterface )----------------------------------------- */ | /* -( PhabricatorPolicyInterface )----------------------------------------- */ | ||||
| public function getCapabilities() { | public function getCapabilities() { | ||||
| return array( | return array( | ||||
| PhabricatorPolicyCapability::CAN_VIEW, | PhabricatorPolicyCapability::CAN_VIEW, | ||||
| PhabricatorPolicyCapability::CAN_EDIT, | PhabricatorPolicyCapability::CAN_EDIT, | ||||
| Show All 34 Lines | |||||