Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15360718
D20011.id47810.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
13 KB
Referenced Files
None
Subscribers
None
D20011.id47810.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Wed, Mar 12, 9:47 AM (1 w, 22 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7226284
Default Alt Text
D20011.id47810.diff (13 KB)
Attached To
Mode
D20011: Support designating a contact number as "primary"
Attached
Detach File
Event Timeline
Log In to Comment