L:ock editing to task assignee

Is it possible to allow the user the task is assigned to edit access without editing the editable by policy each time?

This would severely cut down on administration time.

I can see “task author” and “subscribers” in the form Custom Policy options, but not “assignee”.
image

I’m guessing it would be relatively easy for you to to write a custom Policy Rule by copying one of those.

I attempted to copy the ManiphestTaskAuthorPolicyRule, however I received the following error:

The code:

ManiphestTaskAssigneePolicyRule
<?php

final class ManiphestTaskAssigneePolicyRule
  extends PhabricatorPolicyRule {

  public function getObjectPolicyKey() {
    return 'maniphest.assignee';
  }

  public function getObjectPolicyName() {
    return pht('Task Assignee');
  }

  public function getPolicyExplanation() {
    return pht('The assignee of this task can take this action.');
  }

  public function getRuleDescription() {
    return pht('task assignee');
  }

  public function canApplyToObject(PhabricatorPolicyInterface $object) {
    return ($object instanceof ManiphestTask);
  }

  public function applyRule(
    PhabricatorUser $viewer,
    $value,
    PhabricatorPolicyInterface $object) {

    $viewer_phid = $viewer->getPHID();
    if (!$viewer_phid) {
      return false;
    }

    return ($object->getAssigneePHID() == $viewer_phid);
  }

  public function getValueControlType() {
    return self::CONTROL_TYPE_NONE;
  }

}
ManiphestTaskAuthorPolicyRule
<?php

final class ManiphestTaskAuthorPolicyRule
  extends PhabricatorPolicyRule {

  public function getObjectPolicyKey() {
    return 'maniphest.author';
  }

  public function getObjectPolicyName() {
    return pht('Task Author');
  }

  public function getPolicyExplanation() {
    return pht('The author of this task can take this action.');
  }

  public function getRuleDescription() {
    return pht('task author');
  }

  public function canApplyToObject(PhabricatorPolicyInterface $object) {
    return ($object instanceof ManiphestTask);
  }

  public function applyRule(
    PhabricatorUser $viewer,
    $value,
    PhabricatorPolicyInterface $object) {

    $viewer_phid = $viewer->getPHID();
    if (!$viewer_phid) {
      return false;
    }

    return ($object->getAuthorPHID() == $viewer_phid);
  }

  public function getValueControlType() {
    return self::CONTROL_TYPE_NONE;
  }

}

The exception says it found an maniphest.author, which is the existing code, not your new class.
Are you trying to edit the policy directly in the DB?
You should have a full stack trace in the error log, and maybe if you enable DarkConsole under Developer options (globally and in your profile).

Also, getAssigneePHID() method doesn’t exist - it may be called getOwnerPHID() (db field ownerPHID.

The error shown in DarkConsole is:

Click to view
Policy identifier is an object PHID ('obj.maniphest.author'), but no object handle was provided. A handle must be provided for object policies.
Stack trace:
PhabricatorPolicy::newFromPolicyAndHandle called at [/var/www/phabricator/phabricator/src/applications/transactions/storage/PhabricatorApplicationTransaction.php:444]
PhabricatorApplicationTransaction::renderPolicyName called at [/var/www/phabricator/phabricator/src/applications/transactions/storage/PhabricatorApplicationTransaction.php:933]
PhabricatorApplicationTransaction::getTitle called at [/var/www/phabricator/phabricator/src/applications/transactions/storage/PhabricatorModularTransaction.php:132]
PhabricatorModularTransaction::getTitle called at [/var/www/phabricator/phabricator/src/applications/maniphest/storage/ManiphestTransaction.php:136]
ManiphestTransaction::getTitle called at [/var/www/phabricator/phabricator/src/applications/transactions/view/PhabricatorApplicationTransactionView.php:431]
PhabricatorApplicationTransactionView::renderEvent called at [/var/www/phabricator/phabricator/src/applications/transactions/view/PhabricatorApplicationTransactionView.php:171]
PhabricatorApplicationTransactionView::buildEvents called at [/var/www/phabricator/phabricator/src/applications/transactions/view/PhabricatorApplicationTransactionView.php:219]
PhabricatorApplicationTransactionView::buildPHUITimelineView called at [/var/www/phabricator/phabricator/src/applications/transactions/view/PhabricatorApplicationTransactionView.php:198]
phutil_escape_html called at [/var/www/phabricator/phabricator/src/infrastructure/markup/render.php:135]
phutil_escape_html called at [/var/www/phabricator/phabricator/src/infrastructure/markup/render.php:97]
phutil_tag called at [/var/www/phabricator/phabricator/src/view/phui/PHUITwoColumnView.php:203]
PHUITwoColumnView::buildMainColumn called at [/var/www/phabricator/phabricator/src/view/phui/PHUITwoColumnView.php:121]
PHUITwoColumnView::getTagContent called at [/var/www/phabricator/phabricator/src/view/AphrontTagView.php:161]
AphrontTagView::render called at [/var/www/phabricator/phabricator/src/view/AphrontView.php:222]
AphrontView::producePhutilSafeHTML called at [/var/www/phabricator/phabricator/src/infrastructure/markup/render.php:111]
phutil_escape_html called at [/var/www/phabricator/phabricator/src/infrastructure/markup/render.php:167]
phutil_implode_html called at [/var/www/phabricator/phabricator/src/view/page/PhabricatorBarePageView.php:58]
PhabricatorBarePageView::willRenderPage called at [/var/www/phabricator/phabricator/src/view/page/PhabricatorStandardPageView.php:216]
PhabricatorStandardPageView::willRenderPage called at [/var/www/phabricator/phabricator/src/view/page/AphrontPageView.php:46]
AphrontPageView::render called at [/var/www/phabricator/phabricator/src/view/page/PhabricatorStandardPageView.php:904]
PhabricatorStandardPageView::produceAphrontResponse called at [/var/www/phabricator/phabricator/src/aphront/configuration/AphrontApplicationConfiguration.php:723]
AphrontApplicationConfiguration::produceResponse called at [/var/www/phabricator/phabricator/src/aphront/configuration/AphrontApplicationConfiguration.php:303]
phlog called at [/var/www/phabricator/phabricator/src/aphront/handler/PhabricatorDefaultRequestExceptionHandler.php:41]
PhabricatorDefaultRequestExceptionHandler::handleRequestThrowable called at [/var/www/phabricator/phabricator/src/aphront/configuration/AphrontApplicationConfiguration.php:752]
AphrontApplicationConfiguration::handleThrowable called at [/var/www/phabricator/phabricator/src/aphront/configuration/AphrontApplicationConfiguration.php:341]
AphrontApplicationConfiguration::processRequest called at [/var/www/phabricator/phabricator/src/aphront/configuration/AphrontApplicationConfiguration.php:211]
AphrontApplicationConfiguration::runHTTPRequest called at [/var/www/phabricator/phabricator/webroot/index.php:35]

My code:

Click to view
<?php

final class ManiphestTaskOwnerPolicyRule
  extends PhabricatorPolicyRule {

  public function getObjectPolicyKey() {
    return 'maniphest.owner';
  }

  public function getObjectPolicyName() {
    return pht('Task Assignee');
  }

  public function getPolicyExplanation() {
    return pht('The assignee of this task can take this action.');
  }

  public function getRuleDescription() {
    return pht('task assignee');
  }

  public function canApplyToObject(PhabricatorPolicyInterface $object) {
    return ($object instanceof ManiphestTask);
  }

  public function applyRule(
    PhabricatorUser $viewer,
    $value,
    PhabricatorPolicyInterface $object) {

    $viewer_phid = $viewer->getPHID();
    if (!$viewer_phid) {
      return false;
    }

    return ($object->getOwnerPHID() == $viewer_phid);
  }

  public function getValueControlType() {
    return self::CONTROL_TYPE_NONE;
  }

}

Also, getAssigneePHID() method doesn’t exist - it may be called getOwnerPHID() (db field ownerPHID .

Thanks for the heads up on this - I’ve made the edit.

No, I’m writing an extension file and putting it in src/extensions/

It looks like somehow one of the transaction object for the task got corrupted, and the UI is crashing because of that.
Can you just try with a new task, maybe it’s some transient thing. Otherwise, you might have to go in the DB and manually fix (or delete) the record.

This is strange, it appears to be overwriting the Task Author policy.

This is a screenshot with the extension enabled:

This is a screenshot with the extension disabled:

mmm.

This is the code that loads the rules:

     50     $rules = id(new PhutilClassMapQuery())
     51       ->setAncestorClass('PhabricatorPolicyRule')
     52       ->execute();
     53
     54     foreach ($rules as $key => $rule) {
     55       if (!$rule->canApplyToObject($object)) {
     56         unset($rules[$key]);
     57       }
     58     }
     59
     60     $rules = msort($rules, 'getRuleOrder');

(PhabricatorPolicyEditController.php.php). There’s no custom key function, so I’d guess the keys are class names, which would not expect to allow your class to override the existing one.

So, is this not possible?

It shouldn’t be doing that. Do you have any proxy/cache that might be munging the content being delivered or the classes loaded?

Not as far as I am aware.

¯_(ツ)_/¯

Works fine for me.

Screen Shot 2020-09-14 at 11.17.28 AM

Note that the method is getOwnerPHID(), not getAssigneePHID(), and that the rule as implemented locks tasks into a broken state when a task is unassigned.

1 Like

Hmm…

Are you using the exact code I provided above?

Edit: This seems to now be working, I’m not sure why it wasn’t earlier. Thanks for everyone’s help. The code above works jjust fine.