@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at recaptime-dev/main 99 lines 3.6 kB view raw
1<?php 2 3/** 4 * Before a profile picture is destroyed, restore the builtin picture. 5 */ 6final class PeopleProfilePictureBeforeDestructionEngineExtension 7 extends PhabricatorBeforeDestructionEngineExtension { 8 9 const EXTENSIONKEY = 'people-profiles'; 10 11 public function getExtensionName(): string { 12 return pht('People Profile Pictures'); 13 } 14 15 public function canBeforeDestroyObject( 16 PhabricatorDestructionEngine $destruction_engine, 17 $object): bool { 18 return ($object instanceof PhabricatorFile) 19 && $object->getIsProfileImage(); 20 } 21 22 public function beforeDestroyObject( 23 PhabricatorDestructionEngine $destruction_engine, 24 $object): void { 25 // File that will be destroyed soon. 26 // The file PHID is always non-empty at this point. 27 $file_phid = $object->getPHID(); 28 29 // Note that a file that is used as profile images have 30 // the authorPHID = null, so it's not so obvious which 31 // is the affected user. 32 // https://we.phorge.it/T15407 33 34 // Note that we could find the affected users by running this 35 // very inefficient query that would lead to a full table scan: 36 // SELECT * FROM user WHERE profileImagePHID = $file_phid 37 // In the future it might make sense to add an index on 'profileImagePHID' 38 // if more frontend features will read that info, so we can also avoid the 39 // following lines of code. 40 // https://we.phorge.it/T16080 41 42 // We look at the file attachments to find the affected user efficiently. 43 // Note that file attachments are only available before destroying the file, 44 // and... fortunately we are inside a "Before Destruction" engine. 45 // This query is efficient thanks to the database index on 'filePHID' and 46 // the low cardinality of this result set. 47 $viewer = $destruction_engine->getViewer(); 48 $file_attachments_query = new PhabricatorFileAttachmentQuery(); 49 $file_attachments = 50 $file_attachments_query 51 ->setViewer($viewer) 52 ->withFilePHIDs(array($file_phid)) 53 ->withObjectPHIDType(PhabricatorPeopleUserPHIDType::TYPECONST) 54 ->withAttachmentModes(array(PhabricatorFileAttachment::MODE_ATTACH)) 55 ->execute(); 56 $attached_objects = mpull($file_attachments, 'getObject'); 57 58 // Be 100% sure to only operate on users, 59 // and that these are really using this picture. 60 $affected_users = array(); 61 foreach ($attached_objects as $attached_object) { 62 if (($attached_object instanceof PhabricatorUser) && 63 ($attached_object->getProfileImagePHID() == $file_phid)) { 64 $affected_users[] = $attached_object; 65 } 66 } 67 68 $user_table = new PhabricatorUser(); 69 70 if (!$affected_users) { 71 // The above fast speculation has found no users. 72 // It can happen when somebody manually used the "Detach File" button 73 // from the file (why people can generally do that? uhm). 74 // Only in this desperate case, we run this inefficient query. 75 $affected_users = $user_table 76 ->loadAllWhere( 77 'profileImagePHID = %s', 78 $file_phid); 79 } 80 81 // Avoid opening an empty transaction. 82 if (!$affected_users) { 83 return; 84 } 85 86 // Set the builtin profile image to each affected user. 87 // Premising that it's supposed to be just one user. 88 // Maybe in the future multiple users may use the same 89 // profile picture, so let's covers more corner cases, 90 // because we can. 91 $user_table->openTransaction(); 92 foreach ($affected_users as $affected_user) { 93 $affected_user->setProfileImagePHID(null); 94 $affected_user->save(); 95 } 96 $user_table->saveTransaction(); 97 } 98 99}