Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/auth/storage/PhabricatorAuthContactNumber.php
12256 views
1
<?php
2
3
4
final class PhabricatorAuthContactNumber
5
extends PhabricatorAuthDAO
6
implements
7
PhabricatorApplicationTransactionInterface,
8
PhabricatorPolicyInterface,
9
PhabricatorDestructibleInterface,
10
PhabricatorEditEngineMFAInterface {
11
12
protected $objectPHID;
13
protected $contactNumber;
14
protected $uniqueKey;
15
protected $status;
16
protected $isPrimary;
17
protected $properties = array();
18
19
const STATUS_ACTIVE = 'active';
20
const STATUS_DISABLED = 'disabled';
21
22
protected function getConfiguration() {
23
return array(
24
self::CONFIG_SERIALIZATION => array(
25
'properties' => self::SERIALIZATION_JSON,
26
),
27
self::CONFIG_AUX_PHID => true,
28
self::CONFIG_COLUMN_SCHEMA => array(
29
'contactNumber' => 'text255',
30
'status' => 'text32',
31
'uniqueKey' => 'bytes12?',
32
'isPrimary' => 'bool',
33
),
34
self::CONFIG_KEY_SCHEMA => array(
35
'key_object' => array(
36
'columns' => array('objectPHID'),
37
),
38
'key_unique' => array(
39
'columns' => array('uniqueKey'),
40
'unique' => true,
41
),
42
),
43
) + parent::getConfiguration();
44
}
45
46
public static function initializeNewContactNumber($object) {
47
return id(new self())
48
->setStatus(self::STATUS_ACTIVE)
49
->setObjectPHID($object->getPHID())
50
->setIsPrimary(0);
51
}
52
53
public function getPHIDType() {
54
return PhabricatorAuthContactNumberPHIDType::TYPECONST;
55
}
56
57
public function getURI() {
58
return urisprintf('/auth/contact/%s/', $this->getID());
59
}
60
61
public function getObjectName() {
62
return pht('Contact Number %d', $this->getID());
63
}
64
65
public function getDisplayName() {
66
return $this->getContactNumber();
67
}
68
69
public function isDisabled() {
70
return ($this->getStatus() === self::STATUS_DISABLED);
71
}
72
73
public function newIconView() {
74
if ($this->isDisabled()) {
75
return id(new PHUIIconView())
76
->setIcon('fa-ban', 'grey')
77
->setTooltip(pht('Disabled'));
78
}
79
80
if ($this->getIsPrimary()) {
81
return id(new PHUIIconView())
82
->setIcon('fa-certificate', 'blue')
83
->setTooltip(pht('Primary Number'));
84
}
85
86
return id(new PHUIIconView())
87
->setIcon('fa-hashtag', 'bluegrey')
88
->setTooltip(pht('Active Phone Number'));
89
}
90
91
public function newUniqueKey() {
92
$parts = array(
93
// This is future-proofing for a world where we have multiple types
94
// of contact numbers, so we might be able to avoid re-hashing
95
// everything.
96
'phone',
97
$this->getContactNumber(),
98
);
99
100
$parts = implode("\0", $parts);
101
102
return PhabricatorHash::digestForIndex($parts);
103
}
104
105
public function save() {
106
// We require that active contact numbers be unique, but it's okay to
107
// disable a number and then reuse it somewhere else.
108
if ($this->isDisabled()) {
109
$this->uniqueKey = null;
110
} else {
111
$this->uniqueKey = $this->newUniqueKey();
112
}
113
114
parent::save();
115
116
return $this->updatePrimaryContactNumber();
117
}
118
119
private function updatePrimaryContactNumber() {
120
// Update the "isPrimary" column so that at most one number is primary for
121
// each user, and no disabled number is primary.
122
123
$conn = $this->establishConnection('w');
124
$this_id = (int)$this->getID();
125
126
if ($this->getIsPrimary() && !$this->isDisabled()) {
127
// If we're trying to make this number primary and it's active, great:
128
// make this number the primary number.
129
$primary_id = $this_id;
130
} else {
131
// If we aren't trying to make this number primary or it is disabled,
132
// pick another number to make primary if we can. A number must be active
133
// to become primary.
134
135
// If there are multiple active numbers, pick the oldest one currently
136
// marked primary (usually, this should mean that we just keep the
137
// current primary number as primary).
138
139
// If none are marked primary, just pick the oldest one.
140
$primary_row = queryfx_one(
141
$conn,
142
'SELECT id FROM %R
143
WHERE objectPHID = %s AND status = %s
144
ORDER BY isPrimary DESC, id ASC
145
LIMIT 1',
146
$this,
147
$this->getObjectPHID(),
148
self::STATUS_ACTIVE);
149
if ($primary_row) {
150
$primary_id = (int)$primary_row['id'];
151
} else {
152
$primary_id = -1;
153
}
154
}
155
156
// Set the chosen number to primary, and all other numbers to nonprimary.
157
158
queryfx(
159
$conn,
160
'UPDATE %R SET isPrimary = IF(id = %d, 1, 0)
161
WHERE objectPHID = %s',
162
$this,
163
$primary_id,
164
$this->getObjectPHID());
165
166
$this->setIsPrimary((int)($primary_id === $this_id));
167
168
return $this;
169
}
170
171
public static function getStatusNameMap() {
172
return ipull(self::getStatusPropertyMap(), 'name');
173
}
174
175
private static function getStatusPropertyMap() {
176
return array(
177
self::STATUS_ACTIVE => array(
178
'name' => pht('Active'),
179
),
180
self::STATUS_DISABLED => array(
181
'name' => pht('Disabled'),
182
),
183
);
184
}
185
186
public function getSortVector() {
187
// Sort the primary number first, then active numbers, then disabled
188
// numbers. In each group, sort from oldest to newest.
189
return id(new PhutilSortVector())
190
->addInt($this->getIsPrimary() ? 0 : 1)
191
->addInt($this->isDisabled() ? 1 : 0)
192
->addInt($this->getID());
193
}
194
195
196
/* -( PhabricatorPolicyInterface )----------------------------------------- */
197
198
199
public function getCapabilities() {
200
return array(
201
PhabricatorPolicyCapability::CAN_VIEW,
202
PhabricatorPolicyCapability::CAN_EDIT,
203
);
204
}
205
206
public function getPolicy($capability) {
207
return $this->getObjectPHID();
208
}
209
210
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
211
return false;
212
}
213
214
215
/* -( PhabricatorDestructibleInterface )----------------------------------- */
216
217
218
public function destroyObjectPermanently(
219
PhabricatorDestructionEngine $engine) {
220
$this->delete();
221
}
222
223
224
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
225
226
227
public function getApplicationTransactionEditor() {
228
return new PhabricatorAuthContactNumberEditor();
229
}
230
231
public function getApplicationTransactionTemplate() {
232
return new PhabricatorAuthContactNumberTransaction();
233
}
234
235
236
/* -( PhabricatorEditEngineMFAInterface )---------------------------------- */
237
238
239
public function newEditEngineMFAEngine() {
240
return new PhabricatorAuthContactNumberMFAEngine();
241
}
242
243
}
244
245