Page MenuHomePhabricator

D20011.id.diff
No OneTemporary

D20011.id.diff

diff --git a/resources/sql/autopatches/20190121.contact.01.primary.sql b/resources/sql/autopatches/20190121.contact.01.primary.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20190121.contact.01.primary.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {$NAMESPACE}_auth.auth_contactnumber
+ ADD isPrimary BOOL NOT NULL;
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2207,6 +2207,8 @@
'PhabricatorAuthContactNumberEditor' => 'applications/auth/editor/PhabricatorAuthContactNumberEditor.php',
'PhabricatorAuthContactNumberNumberTransaction' => 'applications/auth/xaction/PhabricatorAuthContactNumberNumberTransaction.php',
'PhabricatorAuthContactNumberPHIDType' => 'applications/auth/phid/PhabricatorAuthContactNumberPHIDType.php',
+ 'PhabricatorAuthContactNumberPrimaryController' => 'applications/auth/controller/contact/PhabricatorAuthContactNumberPrimaryController.php',
+ 'PhabricatorAuthContactNumberPrimaryTransaction' => 'applications/auth/xaction/PhabricatorAuthContactNumberPrimaryTransaction.php',
'PhabricatorAuthContactNumberQuery' => 'applications/auth/query/PhabricatorAuthContactNumberQuery.php',
'PhabricatorAuthContactNumberStatusTransaction' => 'applications/auth/xaction/PhabricatorAuthContactNumberStatusTransaction.php',
'PhabricatorAuthContactNumberTransaction' => 'applications/auth/storage/PhabricatorAuthContactNumberTransaction.php',
@@ -7912,6 +7914,8 @@
'PhabricatorAuthContactNumberEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorAuthContactNumberNumberTransaction' => 'PhabricatorAuthContactNumberTransactionType',
'PhabricatorAuthContactNumberPHIDType' => 'PhabricatorPHIDType',
+ 'PhabricatorAuthContactNumberPrimaryController' => 'PhabricatorAuthContactNumberController',
+ 'PhabricatorAuthContactNumberPrimaryTransaction' => 'PhabricatorAuthContactNumberTransactionType',
'PhabricatorAuthContactNumberQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorAuthContactNumberStatusTransaction' => 'PhabricatorAuthContactNumberTransactionType',
'PhabricatorAuthContactNumberTransaction' => 'PhabricatorModularTransaction',
diff --git a/src/applications/auth/application/PhabricatorAuthApplication.php b/src/applications/auth/application/PhabricatorAuthApplication.php
--- a/src/applications/auth/application/PhabricatorAuthApplication.php
+++ b/src/applications/auth/application/PhabricatorAuthApplication.php
@@ -113,6 +113,8 @@
'PhabricatorAuthContactNumberViewController',
'(?P<action>disable|enable)/(?P<id>[1-9]\d*)/' =>
'PhabricatorAuthContactNumberDisableController',
+ 'primary/(?P<id>[1-9]\d*)/' =>
+ 'PhabricatorAuthContactNumberPrimaryController',
),
),
diff --git a/src/applications/auth/controller/contact/PhabricatorAuthContactNumberPrimaryController.php b/src/applications/auth/controller/contact/PhabricatorAuthContactNumberPrimaryController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/controller/contact/PhabricatorAuthContactNumberPrimaryController.php
@@ -0,0 +1,78 @@
+<?php
+
+final class PhabricatorAuthContactNumberPrimaryController
+ extends PhabricatorAuthContactNumberController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $request->getViewer();
+ $id = $request->getURIData('id');
+
+ $number = id(new PhabricatorAuthContactNumberQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$number) {
+ return new Aphront404Response();
+ }
+
+ $id = $number->getID();
+ $cancel_uri = $number->getURI();
+
+ if ($number->isDisabled()) {
+ return $this->newDialog()
+ ->setTitle(pht('Number Disabled'))
+ ->appendParagraph(
+ pht(
+ 'You can not make a disabled number your primary contact number.'))
+ ->addCancelButton($cancel_uri);
+ }
+
+ if ($number->getIsPrimary()) {
+ return $this->newDialog()
+ ->setTitle(pht('Number Already Primary'))
+ ->appendParagraph(
+ pht(
+ 'This contact number is already your primary contact number.'))
+ ->addCancelButton($cancel_uri);
+ }
+
+ if ($request->isFormPost()) {
+ $xactions = array();
+
+ $xactions[] = id(new PhabricatorAuthContactNumberTransaction())
+ ->setTransactionType(
+ PhabricatorAuthContactNumberPrimaryTransaction::TRANSACTIONTYPE)
+ ->setNewValue(true);
+
+ $editor = id(new PhabricatorAuthContactNumberEditor())
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true);
+
+ $editor->applyTransactions($number, $xactions);
+
+ return id(new AphrontRedirectResponse())->setURI($cancel_uri);
+ }
+
+ $number_display = phutil_tag(
+ 'strong',
+ array(),
+ $number->getDisplayName());
+
+ return $this->newDialog()
+ ->setTitle(pht('Set Primary Contact Number'))
+ ->appendParagraph(
+ pht(
+ 'Designate %s as your primary contact number?',
+ $number_display))
+ ->addSubmitButton(pht('Make Primary'))
+ ->addCancelButton($cancel_uri);
+ }
+
+}
diff --git a/src/applications/auth/controller/contact/PhabricatorAuthContactNumberViewController.php b/src/applications/auth/controller/contact/PhabricatorAuthContactNumberViewController.php
--- a/src/applications/auth/controller/contact/PhabricatorAuthContactNumberViewController.php
+++ b/src/applications/auth/controller/contact/PhabricatorAuthContactNumberViewController.php
@@ -56,6 +56,8 @@
if ($number->isDisabled()) {
$view->setStatus('fa-ban', 'red', pht('Disabled'));
+ } else if ($number->getIsPrimary()) {
+ $view->setStatus('fa-certificate', 'blue', pht('Primary'));
}
return $view;
@@ -96,17 +98,26 @@
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
-
if ($number->isDisabled()) {
$disable_uri = $this->getApplicationURI("contact/enable/{$id}/");
$disable_name = pht('Enable Contact Number');
$disable_icon = 'fa-check';
+ $can_primary = false;
} else {
$disable_uri = $this->getApplicationURI("contact/disable/{$id}/");
$disable_name = pht('Disable Contact Number');
$disable_icon = 'fa-ban';
+ $can_primary = !$number->getIsPrimary();
}
+ $curtain->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Make Primary Number'))
+ ->setIcon('fa-certificate')
+ ->setHref($this->getApplicationURI("contact/primary/{$id}/"))
+ ->setDisabled(!$can_primary)
+ ->setWorkflow(true));
+
$curtain->addAction(
id(new PhabricatorActionView())
->setName($disable_name)
diff --git a/src/applications/auth/storage/PhabricatorAuthContactNumber.php b/src/applications/auth/storage/PhabricatorAuthContactNumber.php
--- a/src/applications/auth/storage/PhabricatorAuthContactNumber.php
+++ b/src/applications/auth/storage/PhabricatorAuthContactNumber.php
@@ -12,6 +12,7 @@
protected $contactNumber;
protected $uniqueKey;
protected $status;
+ protected $isPrimary;
protected $properties = array();
const STATUS_ACTIVE = 'active';
@@ -27,6 +28,7 @@
'contactNumber' => 'text255',
'status' => 'text32',
'uniqueKey' => 'bytes12?',
+ 'isPrimary' => 'bool',
),
self::CONFIG_KEY_SCHEMA => array(
'key_object' => array(
@@ -43,7 +45,8 @@
public static function initializeNewContactNumber($object) {
return id(new self())
->setStatus(self::STATUS_ACTIVE)
- ->setObjectPHID($object->getPHID());
+ ->setObjectPHID($object->getPHID())
+ ->setIsPrimary(0);
}
public function getPHIDType() {
@@ -73,8 +76,14 @@
->setTooltip(pht('Disabled'));
}
+ if ($this->getIsPrimary()) {
+ return id(new PHUIIconView())
+ ->setIcon('fa-certificate', 'blue')
+ ->setTooltip(pht('Primary Number'));
+ }
+
return id(new PHUIIconView())
- ->setIcon('fa-mobile', 'green')
+ ->setIcon('fa-hashtag', 'bluegrey')
->setTooltip(pht('Active Phone Number'));
}
@@ -101,7 +110,61 @@
$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() {
@@ -119,6 +182,15 @@
);
}
+ 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 )----------------------------------------- */
diff --git a/src/applications/auth/xaction/PhabricatorAuthContactNumberPrimaryTransaction.php b/src/applications/auth/xaction/PhabricatorAuthContactNumberPrimaryTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/xaction/PhabricatorAuthContactNumberPrimaryTransaction.php
@@ -0,0 +1,49 @@
+<?php
+
+final class PhabricatorAuthContactNumberPrimaryTransaction
+ extends PhabricatorAuthContactNumberTransactionType {
+
+ const TRANSACTIONTYPE = 'primary';
+
+ public function generateOldValue($object) {
+ return (bool)$object->getIsPrimary();
+ }
+
+ public function applyInternalEffects($object, $value) {
+ $object->setIsPrimary((int)$value);
+ }
+
+ public function getTitle() {
+ return pht(
+ '%s made this the primary contact number.',
+ $this->renderAuthor());
+ }
+
+ public function validateTransactions($object, array $xactions) {
+ $errors = array();
+
+ foreach ($xactions as $xaction) {
+ $new_value = $xaction->getNewValue();
+
+ if (!$new_value) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'To choose a different primary contact number, make that '.
+ 'number primary (instead of trying to demote this one).'),
+ $xaction);
+ continue;
+ }
+
+ if ($object->isDisabled()) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'You can not make a disabled number a primary contact number.'),
+ $xaction);
+ continue;
+ }
+ }
+
+ return $errors;
+ }
+
+}
diff --git a/src/applications/settings/panel/PhabricatorContactNumbersSettingsPanel.php b/src/applications/settings/panel/PhabricatorContactNumbersSettingsPanel.php
--- a/src/applications/settings/panel/PhabricatorContactNumbersSettingsPanel.php
+++ b/src/applications/settings/panel/PhabricatorContactNumbersSettingsPanel.php
@@ -12,7 +12,7 @@
}
public function getPanelMenuIcon() {
- return 'fa-mobile';
+ return 'fa-hashtag';
}
public function getPanelGroupKey() {
@@ -31,9 +31,19 @@
->setViewer($viewer)
->withObjectPHIDs(array($user->getPHID()))
->execute();
+ $numbers = msortv($numbers, 'getSortVector');
$rows = array();
+ $row_classes = array();
foreach ($numbers as $number) {
+ if ($number->getIsPrimary()) {
+ $primary_display = pht('Primary');
+ $row_classes[] = 'highlighted';
+ } else {
+ $primary_display = null;
+ $row_classes[] = null;
+ }
+
$rows[] = array(
$number->newIconView(),
phutil_tag(
@@ -42,6 +52,7 @@
'href' => $number->getURI(),
),
$number->getDisplayName()),
+ $primary_display,
phabricator_datetime($number->getDateCreated(), $viewer),
);
}
@@ -49,16 +60,19 @@
$table = id(new AphrontTableView($rows))
->setNoDataString(
pht("You haven't added any contact numbers to your account."))
+ ->setRowClasses($row_classes)
->setHeaders(
array(
null,
pht('Number'),
+ pht('Status'),
pht('Created'),
))
->setColumnClasses(
array(
null,
'wide pri',
+ null,
'right',
));

File Metadata

Mime Type
text/plain
Expires
Mon, May 13, 1:27 AM (3 w, 4 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6273868
Default Alt Text
D20011.id.diff (13 KB)

Event Timeline