@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.

Do not CC users without permissions to view an object

Summary:
Ref T4411
I'm not quite sure if this is the right place for this as it will be difficult to provide proper user feedback of why we removed a particular subscriber.
Is the ApplicationTransactionEditor generally the right place to extract mentioned phids in comments?
On the other hand in some cases we cannot really give user feedback why a user was not subscribed (e.g.: commits & diffs)

Adding a diff to a repo where the user mentioned has no view permissions the subscriber is currently still added. Still would have to find where this is donet...

Any other places?

Unrelated: Is there any way to remove a subscriber from a commit/audit ?

Test Plan:
- Edited tasks with the mentioned user having view permissions to this specific task and without
- Raised concern with a commit and commented on the audit with the user having view permissions to the repo and without
- Added a commit to a repo with and without the mentioned user having permissions
- Mention a user in a task & commit comment with and without permissions
- Mentioning a user in a diff description & comments with and without permissions to the specific diff

Reviewers: chad, #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: chad, Korvin, epriestley

Maniphest Tasks: T4411

Differential Revision: https://secure.phabricator.com/D11049

authored by

Fabian Stelzer and committed by
epriestley
cd677161 86eb7c0e

+88 -24
+3 -3
resources/celerity/map.php
··· 7 7 */ 8 8 return array( 9 9 'names' => array( 10 - 'core.pkg.css' => 'f588bfc3', 10 + 'core.pkg.css' => 'd83f8c13', 11 11 'core.pkg.js' => '44aac665', 12 12 'darkconsole.pkg.js' => 'd326843f', 13 13 'differential.pkg.css' => '8af45893', ··· 104 104 'rsrc/css/application/tokens/tokens.css' => '3d0f239e', 105 105 'rsrc/css/application/uiexample/example.css' => '528b19de', 106 106 'rsrc/css/core/core.css' => 'ca42b69f', 107 - 'rsrc/css/core/remarkup.css' => 'a2d3f9c4', 107 + 'rsrc/css/core/remarkup.css' => '7604f12e', 108 108 'rsrc/css/core/syntax.css' => '56c1ba38', 109 109 'rsrc/css/core/z-index.css' => '44e1d311', 110 110 'rsrc/css/diviner/diviner-shared.css' => '38813222', ··· 725 725 'phabricator-phtize' => 'd254d646', 726 726 'phabricator-prefab' => 'bbae734c', 727 727 'phabricator-profile-css' => '28f433ef', 728 - 'phabricator-remarkup-css' => 'a2d3f9c4', 728 + 'phabricator-remarkup-css' => '7604f12e', 729 729 'phabricator-search-results-css' => 'f240504c', 730 730 'phabricator-shaped-request' => '7cbe244b', 731 731 'phabricator-side-menu-view-css' => '90eafc85',
+2 -1
src/applications/maniphest/controller/ManiphestTaskDescriptionPreviewController.php
··· 13 13 $output = PhabricatorMarkupEngine::renderOneObject( 14 14 $task, 15 15 ManiphestTask::MARKUP_FIELD_DESCRIPTION, 16 - $request->getUser()); 16 + $request->getUser(), 17 + $task); 17 18 18 19 $content = phutil_tag_div('phabricator-remarkup', $output); 19 20
+1
src/applications/maniphest/controller/ManiphestTaskDetailController.php
··· 124 124 125 125 $engine = new PhabricatorMarkupEngine(); 126 126 $engine->setViewer($user); 127 + $engine->setContextObject($task); 127 128 $engine->addObject($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION); 128 129 129 130 $timeline = $this->buildTransactionTimeline(
+1
src/applications/maniphest/controller/ManiphestTransactionPreviewController.php
··· 113 113 114 114 $engine = new PhabricatorMarkupEngine(); 115 115 $engine->setViewer($user); 116 + $engine->setContextObject($task); 116 117 if ($transaction->hasComment()) { 117 118 $engine->addObject( 118 119 $transaction->getComment(),
+2 -11
src/applications/maniphest/controller/ManiphestTransactionSaveController.php
··· 22 22 23 23 $action = $request->getStr('action'); 24 24 25 - // Compute new CCs added by @mentions. Several things can cause CCs to 26 - // be added as side effects: mentions, explicit CCs, users who aren't 27 - // CC'd interacting with the task, and ownership changes. We build up a 28 - // list of all the CCs and then construct a transaction for them at the 29 - // end if necessary. 30 - $added_ccs = PhabricatorMarkupEngine::extractPHIDsFromMentions( 31 - $user, 32 - array( 33 - $request->getStr('comments'), 34 - )); 25 + $added_ccs = array(); 35 26 36 27 $cc_transaction = new ManiphestTransaction(); 37 28 $cc_transaction ··· 67 58 case PhabricatorTransactions::TYPE_SUBSCRIBERS: 68 59 // Accumulate the new explicit CCs into the array that we'll add in 69 60 // the CC transaction later. 70 - $added_ccs = array_merge($added_ccs, $request->getArr('ccs')); 61 + $added_ccs = $request->getArr('ccs'); 71 62 72 63 // Throw away the primary transaction. 73 64 $transaction = null;
+32 -3
src/applications/people/markup/PhabricatorMentionRemarkupRule.php
··· 92 92 } 93 93 94 94 $engine->setTextMetadata($mentioned_key, $mentioned); 95 + $context_object = $engine->getConfig('contextObject'); 95 96 96 97 foreach ($metadata as $username => $tokens) { 97 98 $exists = isset($actual_users[$username]); 99 + $user_has_no_permission = false; 98 100 99 101 if ($exists) { 100 102 $user = $actual_users[$username]; 101 103 Javelin::initBehavior('phabricator-hovercards'); 102 104 105 + // Check if the user has view access to the object she was mentioned in 106 + if ($context_object 107 + && $context_object instanceof PhabricatorPolicyInterface) { 108 + if (!PhabricatorPolicyFilter::hasCapability( 109 + $user, 110 + $context_object, 111 + PhabricatorPolicyCapability::CAN_VIEW)) { 112 + // User mentioned has no permission to this object 113 + $user_has_no_permission = true; 114 + } 115 + } 116 + 103 117 $user_href = '/p/'.$user->getUserName().'/'; 104 118 105 119 if ($engine->isHTMLMailMode()) { 106 120 $user_href = PhabricatorEnv::getProductionURI($user_href); 121 + 122 + if ($user_has_no_permission) { 123 + $colors = ' 124 + border-color: #92969D; 125 + color: #92969D; 126 + background-color: #F7F7F7;'; 127 + } else { 128 + $colors = ' 129 + border-color: #f1f7ff; 130 + color: #19558d; 131 + background-color: #f1f7ff;'; 132 + } 133 + 107 134 $tag = phutil_tag( 108 135 'a', 109 136 array( 110 137 'href' => $user_href, 111 - 'style' => 'background-color: #f1f7ff; 112 - border-color: #f1f7ff; 138 + 'style' => $colors.' 113 139 border: 1px solid transparent; 114 140 border-radius: 3px; 115 - color: #19558d; 116 141 font-weight: bold; 117 142 padding: 0 4px;', 118 143 ), ··· 123 148 ->setPHID($user->getPHID()) 124 149 ->setName('@'.$user->getUserName()) 125 150 ->setHref($user_href); 151 + 152 + if ($user_has_no_permission) { 153 + $tag->addClass('phabricator-remarkup-mention-nopermission'); 154 + } 126 155 127 156 if (!$user->isUserActivated()) { 128 157 $tag->setDotColor(PHUITagView::COLOR_GREY);
+24 -5
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 1053 1053 $phids = array_diff($phids, $this->subscribers); 1054 1054 } 1055 1055 1056 - foreach ($phids as $key => $phid) { 1057 - if ($object->isAutomaticallySubscribed($phid)) { 1058 - unset($phids[$key]); 1056 + if ($phids) { 1057 + $users = id(new PhabricatorPeopleQuery()) 1058 + ->setViewer($this->getActor()) 1059 + ->withPHIDs($phids) 1060 + ->execute(); 1061 + $users = mpull($users, null, 'getPHID'); 1062 + 1063 + foreach ($phids as $key => $phid) { 1064 + // Do not subscribe mentioned users 1065 + // who do not have VIEW Permissions 1066 + if ($object instanceof PhabricatorPolicyInterface 1067 + && !PhabricatorPolicyFilter::hasCapability( 1068 + $users[$phid], 1069 + $object, 1070 + PhabricatorPolicyCapability::CAN_VIEW) 1071 + ) { 1072 + unset($phids[$key]); 1073 + } else { 1074 + if ($object->isAutomaticallySubscribed($phid)) { 1075 + unset($phids[$key]); 1076 + } 1077 + } 1059 1078 } 1079 + $phids = array_values($phids); 1060 1080 } 1061 - $phids = array_values($phids); 1062 - 1081 + // No else here to properly return null should we unset all subscriber 1063 1082 if (!$phids) { 1064 1083 return null; 1065 1084 }
+18 -1
src/infrastructure/markup/PhabricatorMarkupEngine.php
··· 41 41 42 42 private $objects = array(); 43 43 private $viewer; 44 + private $contextObject; 44 45 private $version = 14; 45 46 46 47 ··· 54 55 * @param PhabricatorMarkupInterface The object to render. 55 56 * @param string The field to render. 56 57 * @param PhabricatorUser User viewing the markup. 58 + * @param object A context object for policy checks 57 59 * @return string Marked up output. 58 60 * @task markup 59 61 */ 60 62 public static function renderOneObject( 61 63 PhabricatorMarkupInterface $object, 62 64 $field, 63 - PhabricatorUser $viewer) { 65 + PhabricatorUser $viewer, 66 + $context_object = null) { 64 67 return id(new PhabricatorMarkupEngine()) 65 68 ->setViewer($viewer) 69 + ->setContextObject($context_object) 66 70 ->addObject($object, $field) 67 71 ->process() 68 72 ->getOutput($object, $field); ··· 116 120 foreach ($objects as $key => $info) { 117 121 $engines[$key] = $info['object']->newMarkupEngine($info['field']); 118 122 $engines[$key]->setConfig('viewer', $this->viewer); 123 + $engines[$key]->setConfig('contextObject', $this->contextObject); 119 124 } 120 125 121 126 // Load or build the preprocessor caches. ··· 287 292 */ 288 293 public function setViewer(PhabricatorUser $viewer) { 289 294 $this->viewer = $viewer; 295 + return $this; 296 + } 297 + 298 + /** 299 + * Set the context object. Used to implement object permissions. 300 + * 301 + * @param The object in which context this remarkup is used. 302 + * @return this 303 + * @task markup 304 + */ 305 + public function setContextObject($object) { 306 + $this->contextObject = $object; 290 307 return $this; 291 308 } 292 309
+5
webroot/rsrc/css/core/remarkup.css
··· 208 208 background: #ffaaaa; 209 209 } 210 210 211 + .phabricator-remarkup-mention-nopermission .phui-tag-core { 212 + background: {$lightgreybackground}; 213 + color: {$lightgreytext}; 214 + } 215 + 211 216 .phabricator-remarkup .remarkup-note { 212 217 margin: 16px 0; 213 218 padding: 12px;