diff --git a/src/applications/audit/editor/PhabricatorAuditEditor.php b/src/applications/audit/editor/PhabricatorAuditEditor.php --- a/src/applications/audit/editor/PhabricatorAuditEditor.php +++ b/src/applications/audit/editor/PhabricatorAuditEditor.php @@ -366,7 +366,7 @@ return $reply_handler; } - protected function getMailSubjectPrefix() { + protected function getMailSubjectPrefix(PhabricatorLiskDAO $object) { return PhabricatorEnv::getEnvConfig('metamta.diffusion.subject-prefix'); } diff --git a/src/applications/conpherence/editor/ConpherenceEditor.php b/src/applications/conpherence/editor/ConpherenceEditor.php --- a/src/applications/conpherence/editor/ConpherenceEditor.php +++ b/src/applications/conpherence/editor/ConpherenceEditor.php @@ -412,7 +412,7 @@ return $body; } - protected function getMailSubjectPrefix() { + protected function getMailSubjectPrefix(PhabricatorLiskDAO $object) { return PhabricatorEnv::getEnvConfig('metamta.conpherence.subject-prefix'); } diff --git a/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php b/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php --- a/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php +++ b/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php @@ -244,7 +244,11 @@ 'metamta.differential.subject-prefix', 'string', '[Differential]') - ->setDescription(pht('Subject prefix for Differential mail.')), + ->setSummary(pht('Subject prefix template for Differential mail.')) + ->setDescription(pht('Available keys: id, title, repository, branch')) + ->addExample( + '[${repository}/${branch}] [Differential]', + pht('Use repository and branch')), $this->newOption( 'metamta.differential.attach-patches', 'bool', diff --git a/src/applications/differential/editor/DifferentialTransactionEditor.php b/src/applications/differential/editor/DifferentialTransactionEditor.php --- a/src/applications/differential/editor/DifferentialTransactionEditor.php +++ b/src/applications/differential/editor/DifferentialTransactionEditor.php @@ -1095,8 +1095,24 @@ return $action; } - protected function getMailSubjectPrefix() { - return PhabricatorEnv::getEnvConfig('metamta.differential.subject-prefix'); + protected function getMailSubjectPrefix(PhabricatorLiskDAO $object) { + $branch = nonempty($object->getActiveDiff()->getBranch(), '-'); + $repo_name = null; + + if ($object->getRepository()) { + $repo_name = $object->getRepository()->getName(); + } + + if ($repo_name === null) { + $repo_name = basename($object->getActiveDiff()->getSourcePath()); + } + + return $this->mergeVariables( + PhabricatorEnv::getEnvConfig('metamta.differential.subject-prefix'), + array( + 'branch' => $branch, + 'repository' => $repo_name, + )); } protected function getMailThreadID(PhabricatorLiskDAO $object) { @@ -1124,6 +1140,42 @@ ->addHeader('Thread-Topic', $thread_topic); } + /** + * Convert a user-provided string with variables in it, like: + * + * ${project}/${branch} + * + * ...into a string with variables merged into it safely: + * + * myproject/mybranch + * + * Maybe move to libphutil? + * @param string User-provided pattern string containing `${variables}`. + * @param dict List of available replacement variables. + * @return string String with variables replaced safely into it. + * + */ + protected function mergeVariables($pattern, array $variables) { + $regexp = '/\\$\\{(?P[a-z\\.]+)\\}/'; + + $matches = null; + preg_match_all($regexp, $pattern, $matches); + + $argv = array(); + foreach ($matches['name'] as $name) { + if (!array_key_exists($name, $variables)) { + throw new Exception(pht("No such variable '%s'!", $name)); + } + $argv[] = $variables[$name]; + } + + $pattern = str_replace('%', '%%', $pattern); + $pattern = preg_replace($regexp, '%s', $pattern); + + return vsprintf($pattern, $argv); + } + + protected function buildMailBody( PhabricatorLiskDAO $object, array $xactions) { diff --git a/src/applications/files/editor/PhabricatorFileEditor.php b/src/applications/files/editor/PhabricatorFileEditor.php --- a/src/applications/files/editor/PhabricatorFileEditor.php +++ b/src/applications/files/editor/PhabricatorFileEditor.php @@ -54,7 +54,7 @@ return true; } - protected function getMailSubjectPrefix() { + protected function getMailSubjectPrefix(PhabricatorLiskDAO $object) { return PhabricatorEnv::getEnvConfig('metamta.files.subject-prefix'); } diff --git a/src/applications/legalpad/editor/LegalpadDocumentEditor.php b/src/applications/legalpad/editor/LegalpadDocumentEditor.php --- a/src/applications/legalpad/editor/LegalpadDocumentEditor.php +++ b/src/applications/legalpad/editor/LegalpadDocumentEditor.php @@ -201,7 +201,7 @@ return $body; } - protected function getMailSubjectPrefix() { + protected function getMailSubjectPrefix(PhabricatorLiskDAO $object) { return PhabricatorEnv::getEnvConfig('metamta.legalpad.subject-prefix'); } diff --git a/src/applications/macro/editor/PhabricatorMacroEditor.php b/src/applications/macro/editor/PhabricatorMacroEditor.php --- a/src/applications/macro/editor/PhabricatorMacroEditor.php +++ b/src/applications/macro/editor/PhabricatorMacroEditor.php @@ -160,7 +160,7 @@ return $body; } - protected function getMailSubjectPrefix() { + protected function getMailSubjectPrefix(PhabricatorLiskDAO $object) { return PhabricatorEnv::getEnvConfig('metamta.macro.subject-prefix'); } diff --git a/src/applications/maniphest/conduit/ManiphestConduitAPIMethod.php b/src/applications/maniphest/conduit/ManiphestConduitAPIMethod.php --- a/src/applications/maniphest/conduit/ManiphestConduitAPIMethod.php +++ b/src/applications/maniphest/conduit/ManiphestConduitAPIMethod.php @@ -32,6 +32,8 @@ 'title' => $is_new ? 'required string' : 'optional string', 'description' => 'optional string', 'ownerPHID' => 'optional phid', + 'viewPolicy' => 'optional phid or policy string', + 'editPolicy' => 'optional phid or policy string', 'ccPHIDs' => 'optional list', 'priority' => 'optional int', 'projectPHIDs' => 'optional list', @@ -114,6 +116,20 @@ $transactions = array(); + $view_policy = $request->getValue('viewPolicy'); + if ($view_policy !== null) { + $transactions[] = id(new ManiphestTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) + ->setNewValue($view_policy); + } + + $edit_policy = $request->getValue('editPolicy'); + if ($edit_policy !== null) { + $transactions[] = id(new ManiphestTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) + ->setNewValue($edit_policy); + } + $project_phids = $request->getValue('projectPHIDs'); if ($project_phids !== null) { $this->validatePHIDList( diff --git a/src/applications/maniphest/editor/ManiphestTransactionEditor.php b/src/applications/maniphest/editor/ManiphestTransactionEditor.php --- a/src/applications/maniphest/editor/ManiphestTransactionEditor.php +++ b/src/applications/maniphest/editor/ManiphestTransactionEditor.php @@ -403,7 +403,7 @@ return $xactions; } - protected function getMailSubjectPrefix() { + protected function getMailSubjectPrefix(PhabricatorLiskDAO $object) { return PhabricatorEnv::getEnvConfig('metamta.maniphest.subject-prefix'); } @@ -438,19 +438,23 @@ public function getMailTagsMap() { return array( - MetaMTANotificationType::TYPE_MANIPHEST_STATUS => + ManiphestTransaction::MAILTAG_STATUS => pht("A task's status changes."), - MetaMTANotificationType::TYPE_MANIPHEST_OWNER => + ManiphestTransaction::MAILTAG_OWNER => pht("A task's owner changes."), - MetaMTANotificationType::TYPE_MANIPHEST_PRIORITY => + ManiphestTransaction::MAILTAG_PRIORITY => pht("A task's priority changes."), - MetaMTANotificationType::TYPE_MANIPHEST_CC => - pht("A task's CCs change."), - MetaMTANotificationType::TYPE_MANIPHEST_PROJECTS => + ManiphestTransaction::MAILTAG_CC => + pht("A task's subscribers change."), + ManiphestTransaction::MAILTAG_PROJECTS => pht("A task's associated projects change."), - MetaMTANotificationType::TYPE_MANIPHEST_COMMENT => + ManiphestTransaction::MAILTAG_UNBLOCK => + pht('One of the tasks a task is blocked by changes status.'), + ManiphestTransaction::MAILTAG_COLUMN => + pht('A task is moved between columns on a workboard.'), + ManiphestTransaction::MAILTAG_COMMENT => pht('Someone comments on a task.'), - MetaMTANotificationType::TYPE_MANIPHEST_OTHER => + ManiphestTransaction::MAILTAG_OTHER => pht('Other task activity not listed above occurs.'), ); } diff --git a/src/applications/maniphest/storage/ManiphestTransaction.php b/src/applications/maniphest/storage/ManiphestTransaction.php --- a/src/applications/maniphest/storage/ManiphestTransaction.php +++ b/src/applications/maniphest/storage/ManiphestTransaction.php @@ -20,6 +20,18 @@ // so any transactions render correctly. const TYPE_ATTACH = 'attach'; + + const MAILTAG_STATUS = 'maniphest-status'; + const MAILTAG_OWNER = 'maniphest-owner'; + const MAILTAG_PRIORITY = 'maniphest-priority'; + const MAILTAG_CC = 'maniphest-cc'; + const MAILTAG_PROJECTS = 'maniphest-projects'; + const MAILTAG_COMMENT = 'maniphest-comment'; + const MAILTAG_COLUMN = 'maniphest-column'; + const MAILTAG_UNBLOCK = 'maniphest-unblock'; + const MAILTAG_OTHER = 'maniphest-other'; + + public function getApplicationName() { return 'maniphest'; } @@ -828,32 +840,38 @@ $tags = array(); switch ($this->getTransactionType()) { case self::TYPE_STATUS: - $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_STATUS; + $tags[] = self::MAILTAG_STATUS; break; case self::TYPE_OWNER: - $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_OWNER; + $tags[] = self::MAILTAG_OWNER; break; case self::TYPE_CCS: - $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_CC; + $tags[] = self::MAILTAG_CC; break; case PhabricatorTransactions::TYPE_EDGE: switch ($this->getMetadataValue('edge:type')) { case PhabricatorProjectObjectHasProjectEdgeType::EDGECONST: - $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_PROJECTS; + $tags[] = self::MAILTAG_PROJECTS; break; default: - $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_OTHER; + $tags[] = self::MAILTAG_OTHER; break; } break; case self::TYPE_PRIORITY: - $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_PRIORITY; + $tags[] = self::MAILTAG_PRIORITY; + break; + case self::TYPE_UNBLOCK: + $tags[] = self::MAILTAG_UNBLOCK; + break; + case self::TYPE_PROJECT_COLUMN: + $tags[] = self::MAILTAG_COLUMN; break; case PhabricatorTransactions::TYPE_COMMENT: - $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_COMMENT; + $tags[] = self::MAILTAG_COMMENT; break; default: - $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_OTHER; + $tags[] = self::MAILTAG_OTHER; break; } return $tags; diff --git a/src/applications/metamta/constants/MetaMTANotificationType.php b/src/applications/metamta/constants/MetaMTANotificationType.php --- a/src/applications/metamta/constants/MetaMTANotificationType.php +++ b/src/applications/metamta/constants/MetaMTANotificationType.php @@ -11,14 +11,6 @@ const TYPE_DIFFERENTIAL_REVIEW_REQUEST = 'differential-review-request'; const TYPE_DIFFERENTIAL_OTHER = 'differential-other'; - const TYPE_MANIPHEST_STATUS = 'maniphest-status'; - const TYPE_MANIPHEST_OWNER = 'maniphest-owner'; - const TYPE_MANIPHEST_PRIORITY = 'maniphest-priority'; - const TYPE_MANIPHEST_CC = 'maniphest-cc'; - const TYPE_MANIPHEST_PROJECTS = 'maniphest-projects'; - const TYPE_MANIPHEST_COMMENT = 'maniphest-comment'; - const TYPE_MANIPHEST_OTHER = 'maniphest-other'; - const TYPE_PHOLIO_STATUS = 'pholio-status'; const TYPE_PHOLIO_COMMENT = 'pholio-comment'; const TYPE_PHOLIO_UPDATED = 'pholio-updated'; diff --git a/src/applications/paste/editor/PhabricatorPasteEditor.php b/src/applications/paste/editor/PhabricatorPasteEditor.php --- a/src/applications/paste/editor/PhabricatorPasteEditor.php +++ b/src/applications/paste/editor/PhabricatorPasteEditor.php @@ -136,7 +136,7 @@ return true; } - protected function getMailSubjectPrefix() { + protected function getMailSubjectPrefix(PhabricatorLiskDAO $object) { return PhabricatorEnv::getEnvConfig('metamta.paste.subject-prefix'); } diff --git a/src/applications/pholio/editor/PholioMockEditor.php b/src/applications/pholio/editor/PholioMockEditor.php --- a/src/applications/pholio/editor/PholioMockEditor.php +++ b/src/applications/pholio/editor/PholioMockEditor.php @@ -416,7 +416,7 @@ return $body; } - protected function getMailSubjectPrefix() { + protected function getMailSubjectPrefix(PhabricatorLiskDAO $object) { return PhabricatorEnv::getEnvConfig('metamta.pholio.subject-prefix'); } diff --git a/src/applications/phriction/editor/PhrictionDocumentEditor.php b/src/applications/phriction/editor/PhrictionDocumentEditor.php --- a/src/applications/phriction/editor/PhrictionDocumentEditor.php +++ b/src/applications/phriction/editor/PhrictionDocumentEditor.php @@ -350,7 +350,7 @@ $body = implode("\n\n", $body); - $subject_prefix = $this->getMailSubjectPrefix(); + $subject_prefix = $this->getMailSubjectPrefix(null); $mail = new PhabricatorMetaMTAMail(); $mail->setSubject($name) @@ -368,7 +368,7 @@ /* --( For less copy-pasting when switching to ApplicationTransactions )--- */ - protected function getMailSubjectPrefix() { + protected function getMailSubjectPrefix(PhabricatorLiskDAO $object) { return PhabricatorEnv::getEnvConfig('metamta.phriction.subject-prefix'); } diff --git a/src/applications/ponder/editor/PonderEditor.php b/src/applications/ponder/editor/PonderEditor.php --- a/src/applications/ponder/editor/PonderEditor.php +++ b/src/applications/ponder/editor/PonderEditor.php @@ -31,7 +31,7 @@ ); } - protected function getMailSubjectPrefix() { + protected function getMailSubjectPrefix(PhabricatorLiskDAO $object) { return '[Ponder]'; } diff --git a/src/applications/releeph/editor/ReleephRequestTransactionalEditor.php b/src/applications/releeph/editor/ReleephRequestTransactionalEditor.php --- a/src/applications/releeph/editor/ReleephRequestTransactionalEditor.php +++ b/src/applications/releeph/editor/ReleephRequestTransactionalEditor.php @@ -196,7 +196,7 @@ ->setMailReceiver($object); } - protected function getMailSubjectPrefix() { + protected function getMailSubjectPrefix(PhabricatorLiskDAO $object) { return '[Releeph]'; } diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -1858,7 +1858,7 @@ $template ->setFrom($this->getActingAsPHID()) - ->setSubjectPrefix($this->getMailSubjectPrefix()) + ->setSubjectPrefix($this->getMailSubjectPrefix($object)) ->setVarySubjectPrefix('['.$action.']') ->setThreadID($this->getMailThreadID($object), $this->getIsNewObject()) ->setRelatedPHID($object->getPHID()) @@ -1931,7 +1931,7 @@ /** * @task mail */ - protected function getMailSubjectPrefix() { + protected function getMailSubjectPrefix(PhabricatorLiskDAO $object) { throw new Exception('Capability not supported.'); } diff --git a/src/infrastructure/daemon/bot/handler/PhabricatorBotMacroHandler.php b/src/infrastructure/daemon/bot/handler/PhabricatorBotMacroHandler.php --- a/src/infrastructure/daemon/bot/handler/PhabricatorBotMacroHandler.php +++ b/src/infrastructure/daemon/bot/handler/PhabricatorBotMacroHandler.php @@ -31,7 +31,7 @@ foreach ($macros as $macro_name => $macro) { $regexp[] = preg_quote($macro_name, '/'); } - $regexp = '/('.implode('|', $regexp).')/'; + $regexp = '/^('.implode('|', $regexp).')\z/'; $this->macros = $macros; $this->regexp = $regexp; @@ -49,7 +49,7 @@ $message_body = $message->getBody(); $matches = null; - if (!preg_match($this->regexp, $message_body, $matches)) { + if (!preg_match($this->regexp, trim($message_body), $matches)) { return; }