Correct Aphlict websocket URI construction after PHP8 compatibility changes
[phabricator.git] / src / applications / people / storage / PhabricatorExternalAccount.php
blobc8c22e40e2c6794b81bdd9e3777510066f4f14a5
1 <?php
3 final class PhabricatorExternalAccount
4 extends PhabricatorUserDAO
5 implements
6 PhabricatorPolicyInterface,
7 PhabricatorDestructibleInterface {
9 protected $userPHID;
10 protected $accountSecret;
11 protected $displayName;
12 protected $username;
13 protected $realName;
14 protected $email;
15 protected $emailVerified = 0;
16 protected $accountURI;
17 protected $profileImagePHID;
18 protected $properties = array();
19 protected $providerConfigPHID;
21 // TODO: Remove these (see T13493). These columns are obsolete and have
22 // no readers and only trivial writers.
23 protected $accountType;
24 protected $accountDomain;
25 protected $accountID;
27 private $profileImageFile = self::ATTACHABLE;
28 private $providerConfig = self::ATTACHABLE;
29 private $accountIdentifiers = self::ATTACHABLE;
31 public function getProfileImageFile() {
32 return $this->assertAttached($this->profileImageFile);
35 public function attachProfileImageFile(PhabricatorFile $file) {
36 $this->profileImageFile = $file;
37 return $this;
40 public function generatePHID() {
41 return PhabricatorPHID::generateNewPHID(
42 PhabricatorPeopleExternalPHIDType::TYPECONST);
45 protected function getConfiguration() {
46 return array(
47 self::CONFIG_AUX_PHID => true,
48 self::CONFIG_SERIALIZATION => array(
49 'properties' => self::SERIALIZATION_JSON,
51 self::CONFIG_COLUMN_SCHEMA => array(
52 'userPHID' => 'phid?',
53 'accountType' => 'text16',
54 'accountDomain' => 'text64',
55 'accountSecret' => 'text?',
56 'accountID' => 'text64',
57 'displayName' => 'text255?',
58 'username' => 'text255?',
59 'realName' => 'text255?',
60 'email' => 'text255?',
61 'emailVerified' => 'bool',
62 'profileImagePHID' => 'phid?',
63 'accountURI' => 'text255?',
65 self::CONFIG_KEY_SCHEMA => array(
66 'key_user' => array(
67 'columns' => array('userPHID'),
69 'key_provider' => array(
70 'columns' => array('providerConfigPHID', 'userPHID'),
73 ) + parent::getConfiguration();
76 public function save() {
77 if (!$this->getAccountSecret()) {
78 $this->setAccountSecret(Filesystem::readRandomCharacters(32));
81 $this->openTransaction();
83 $result = parent::save();
85 $account_phid = $this->getPHID();
86 $config_phid = $this->getProviderConfigPHID();
88 if ($this->accountIdentifiers !== self::ATTACHABLE) {
89 foreach ($this->getAccountIdentifiers() as $identifier) {
90 $identifier
91 ->setExternalAccountPHID($account_phid)
92 ->setProviderConfigPHID($config_phid)
93 ->save();
97 $this->saveTransaction();
99 return $result;
102 public function unlinkAccount() {
104 // When unlinking an account, we disassociate it from the user and
105 // remove all the identifying information. We retain the PHID, the
106 // object itself, and the "ExternalAccountIdentifier" objects in the
107 // external table.
109 // TODO: This unlinks (but does not destroy) any profile image.
111 return $this
112 ->setUserPHID(null)
113 ->setDisplayName(null)
114 ->setUsername(null)
115 ->setRealName(null)
116 ->setEmail(null)
117 ->setEmailVerified(0)
118 ->setProfileImagePHID(null)
119 ->setAccountURI(null)
120 ->setProperties(array())
121 ->save();
124 public function setProperty($key, $value) {
125 $this->properties[$key] = $value;
126 return $this;
129 public function getProperty($key, $default = null) {
130 return idx($this->properties, $key, $default);
133 public function isUsableForLogin() {
134 $config = $this->getProviderConfig();
135 if (!$config->getIsEnabled()) {
136 return false;
139 $provider = $config->getProvider();
140 if (!$provider->shouldAllowLogin()) {
141 return false;
144 return true;
147 public function attachProviderConfig(PhabricatorAuthProviderConfig $config) {
148 $this->providerConfig = $config;
149 return $this;
152 public function getProviderConfig() {
153 return $this->assertAttached($this->providerConfig);
156 public function getAccountIdentifiers() {
157 $raw = $this->assertAttached($this->accountIdentifiers);
158 return array_values($raw);
161 public function attachAccountIdentifiers(array $identifiers) {
162 assert_instances_of($identifiers, 'PhabricatorExternalAccountIdentifier');
163 $this->accountIdentifiers = mpull($identifiers, null, 'getIdentifierRaw');
164 return $this;
167 public function appendIdentifier(
168 PhabricatorExternalAccountIdentifier $identifier) {
170 $this->assertAttached($this->accountIdentifiers);
172 $map = $this->accountIdentifiers;
173 $raw = $identifier->getIdentifierRaw();
175 $old = idx($map, $raw);
176 $new = $identifier;
178 if ($old === null) {
179 $result = $new;
180 } else {
181 // Here, we already know about an identifier and have rediscovered it.
183 // We could copy properties from the new version of the identifier here,
184 // or merge them in some other way (for example, update a "last seen
185 // from the provider" timestamp), but no such properties currently exist.
186 $result = $old;
189 $this->accountIdentifiers[$raw] = $result;
191 return $this;
195 /* -( PhabricatorPolicyInterface )----------------------------------------- */
198 public function getCapabilities() {
199 return array(
200 PhabricatorPolicyCapability::CAN_VIEW,
201 PhabricatorPolicyCapability::CAN_EDIT,
205 public function getPolicy($capability) {
206 switch ($capability) {
207 case PhabricatorPolicyCapability::CAN_VIEW:
208 return PhabricatorPolicies::getMostOpenPolicy();
209 case PhabricatorPolicyCapability::CAN_EDIT:
210 return PhabricatorPolicies::POLICY_NOONE;
214 public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
215 return ($viewer->getPHID() == $this->getUserPHID());
218 public function describeAutomaticCapability($capability) {
219 switch ($capability) {
220 case PhabricatorPolicyCapability::CAN_VIEW:
221 return null;
222 case PhabricatorPolicyCapability::CAN_EDIT:
223 return pht(
224 'External accounts can only be edited by the account owner.');
229 /* -( PhabricatorDestructibleInterface )----------------------------------- */
232 public function destroyObjectPermanently(
233 PhabricatorDestructionEngine $engine) {
235 $viewer = $engine->getViewer();
237 $identifiers = id(new PhabricatorExternalAccountIdentifierQuery())
238 ->setViewer($viewer)
239 ->withExternalAccountPHIDs(array($this->getPHID()))
240 ->newIterator();
241 foreach ($identifiers as $identifier) {
242 $engine->destroyObject($identifier);
245 // TODO: This may leave a profile image behind.
247 $this->delete();