Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/project/xaction/PhabricatorProjectSlugsTransaction.php b/src/applications/project/xaction/PhabricatorProjectSlugsTransaction.php
index d442c39a76..e1f22b3746 100644
--- a/src/applications/project/xaction/PhabricatorProjectSlugsTransaction.php
+++ b/src/applications/project/xaction/PhabricatorProjectSlugsTransaction.php
@@ -1,164 +1,174 @@
<?php
final class PhabricatorProjectSlugsTransaction
extends PhabricatorProjectTransactionType {
const TRANSACTIONTYPE = 'project:slugs';
public function generateOldValue($object) {
$slugs = $object->getSlugs();
$slugs = mpull($slugs, 'getSlug', 'getSlug');
unset($slugs[$object->getPrimarySlug()]);
return array_keys($slugs);
}
public function generateNewValue($object, $value) {
return $this->getEditor()->normalizeSlugs($value);
}
public function applyInternalEffects($object, $value) {
return;
}
public function applyExternalEffects($object, $value) {
$old = $this->getOldValue();
$new = $value;
$add = array_diff($new, $old);
$rem = array_diff($old, $new);
foreach ($add as $slug) {
$this->getEditor()->addSlug($object, $slug, true);
}
$this->getEditor()->removeSlugs($object, $rem);
}
public function getTitle() {
$old = $this->getOldValue();
$new = $this->getNewValue();
$add = array_diff($new, $old);
$rem = array_diff($old, $new);
+ $add = $this->renderHashtags($add);
+ $rem = $this->renderHashtags($rem);
+
if ($add && $rem) {
return pht(
'%s changed project hashtag(s), added %d: %s; removed %d: %s.',
$this->renderAuthor(),
count($add),
- $this->renderSlugList($add),
+ $this->renderValueList($add),
count($rem),
- $this->renderSlugList($rem));
+ $this->renderValueList($rem));
} else if ($add) {
return pht(
'%s added %d project hashtag(s): %s.',
$this->renderAuthor(),
count($add),
- $this->renderSlugList($add));
+ $this->renderValueList($add));
} else if ($rem) {
return pht(
'%s removed %d project hashtag(s): %s.',
$this->renderAuthor(),
count($rem),
- $this->renderSlugList($rem));
+ $this->renderValueList($rem));
}
}
public function getTitleForFeed() {
$old = $this->getOldValue();
$new = $this->getNewValue();
$add = array_diff($new, $old);
$rem = array_diff($old, $new);
+ $add = $this->renderHashtags($add);
+ $rem = $this->renderHashtags($rem);
+
if ($add && $rem) {
return pht(
'%s changed %s hashtag(s), added %d: %s; removed %d: %s.',
$this->renderAuthor(),
$this->renderObject(),
count($add),
- $this->renderSlugList($add),
+ $this->renderValueList($add),
count($rem),
- $this->renderSlugList($rem));
+ $this->renderValueList($rem));
} else if ($add) {
return pht(
'%s added %d %s hashtag(s): %s.',
$this->renderAuthor(),
count($add),
$this->renderObject(),
- $this->renderSlugList($add));
+ $this->renderValueList($add));
} else if ($rem) {
return pht(
'%s removed %d %s hashtag(s): %s.',
$this->renderAuthor(),
count($rem),
$this->renderObject(),
- $this->renderSlugList($rem));
+ $this->renderValueList($rem));
}
}
public function getIcon() {
return 'fa-tag';
}
public function validateTransactions($object, array $xactions) {
$errors = array();
if (!$xactions) {
return $errors;
}
$slug_xaction = last($xactions);
$new = $slug_xaction->getNewValue();
$invalid = array();
foreach ($new as $slug) {
if (!PhabricatorSlug::isValidProjectSlug($slug)) {
$invalid[] = $slug;
}
}
if ($invalid) {
$errors[] = $this->newInvalidError(
pht(
'Hashtags must contain at least one letter or number. %s '.
'project hashtag(s) are invalid: %s.',
phutil_count($invalid),
implode(', ', $invalid)));
return $errors;
}
$new = $this->getEditor()->normalizeSlugs($new);
if ($new) {
$slugs_used_already = id(new PhabricatorProjectSlug())
->loadAllWhere('slug IN (%Ls)', $new);
} else {
// The project doesn't have any extra slugs.
$slugs_used_already = array();
}
$slugs_used_already = mgroup($slugs_used_already, 'getProjectPHID');
foreach ($slugs_used_already as $project_phid => $used_slugs) {
if ($project_phid == $object->getPHID()) {
continue;
}
$used_slug_strs = mpull($used_slugs, 'getSlug');
$errors[] = $this->newInvalidError(
pht(
'%s project hashtag(s) are already used by other projects: %s.',
phutil_count($used_slug_strs),
implode(', ', $used_slug_strs)));
}
return $errors;
}
- private function renderSlugList($slugs) {
- return implode(', ', $slugs);
+ private function renderHashtags(array $tags) {
+ $result = array();
+ foreach ($tags as $tag) {
+ $result[] = '#'.$tag;
+ }
+ return $result;
}
}
diff --git a/src/applications/transactions/storage/PhabricatorModularTransactionType.php b/src/applications/transactions/storage/PhabricatorModularTransactionType.php
index 8a56e8e8ce..128b5c7c19 100644
--- a/src/applications/transactions/storage/PhabricatorModularTransactionType.php
+++ b/src/applications/transactions/storage/PhabricatorModularTransactionType.php
@@ -1,322 +1,335 @@
<?php
abstract class PhabricatorModularTransactionType
extends Phobject {
private $storage;
private $viewer;
private $editor;
final public function getTransactionTypeConstant() {
return $this->getPhobjectClassConstant('TRANSACTIONTYPE');
}
public function generateOldValue($object) {
throw new PhutilMethodNotImplementedException();
}
public function generateNewValue($object, $value) {
return $value;
}
public function validateTransactions($object, array $xactions) {
return array();
}
public function willApplyTransactions($object, array $xactions) {
return;
}
public function applyInternalEffects($object, $value) {
return;
}
public function applyExternalEffects($object, $value) {
return;
}
public function getTransactionHasEffect($object, $old, $new) {
return ($old !== $new);
}
public function extractFilePHIDs($object, $value) {
return array();
}
public function shouldHide() {
return false;
}
public function getIcon() {
return null;
}
public function getTitle() {
return null;
}
public function getTitleForFeed() {
return null;
}
public function getActionName() {
return null;
}
public function getActionStrength() {
return null;
}
public function getColor() {
return null;
}
public function hasChangeDetailView() {
return false;
}
public function newChangeDetailView() {
return null;
}
public function getMailDiffSectionHeader() {
return pht('EDIT DETAILS');
}
public function newRemarkupChanges() {
return array();
}
public function mergeTransactions(
$object,
PhabricatorApplicationTransaction $u,
PhabricatorApplicationTransaction $v) {
return null;
}
final public function setStorage(
PhabricatorApplicationTransaction $xaction) {
$this->storage = $xaction;
return $this;
}
private function getStorage() {
return $this->storage;
}
final public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
}
final protected function getViewer() {
return $this->viewer;
}
final public function getActor() {
return $this->getEditor()->getActor();
}
final public function getActingAsPHID() {
return $this->getEditor()->getActingAsPHID();
}
final public function setEditor(
PhabricatorApplicationTransactionEditor $editor) {
$this->editor = $editor;
return $this;
}
final protected function getEditor() {
if (!$this->editor) {
throw new PhutilInvalidStateException('setEditor');
}
return $this->editor;
}
final protected function getAuthorPHID() {
return $this->getStorage()->getAuthorPHID();
}
final protected function getObjectPHID() {
return $this->getStorage()->getObjectPHID();
}
final protected function getObject() {
return $this->getStorage()->getObject();
}
final protected function getOldValue() {
return $this->getStorage()->getOldValue();
}
final protected function getNewValue() {
return $this->getStorage()->getNewValue();
}
final protected function renderAuthor() {
$author_phid = $this->getAuthorPHID();
return $this->getStorage()->renderHandleLink($author_phid);
}
final protected function renderObject() {
$object_phid = $this->getObjectPHID();
return $this->getStorage()->renderHandleLink($object_phid);
}
final protected function renderHandle($phid) {
$viewer = $this->getViewer();
$display = $viewer->renderHandle($phid);
if ($this->isTextMode()) {
$display->setAsText(true);
}
return $display;
}
final protected function renderOldHandle() {
return $this->renderHandle($this->getOldValue());
}
final protected function renderNewHandle() {
return $this->renderHandle($this->getNewValue());
}
final protected function renderHandleList(array $phids) {
$viewer = $this->getViewer();
$display = $viewer->renderHandleList($phids)
->setAsInline(true);
if ($this->isTextMode()) {
$display->setAsText(true);
}
return $display;
}
final protected function renderValue($value) {
if ($this->isTextMode()) {
return sprintf('"%s"', $value);
}
return phutil_tag(
'span',
array(
'class' => 'phui-timeline-value',
),
$value);
}
+ final protected function renderValueList(array $values) {
+ $result = array();
+ foreach ($values as $value) {
+ $result[] = $this->renderValue($value);
+ }
+
+ if ($this->isTextMode()) {
+ return implode(', ', $result);
+ }
+
+ return phutil_implode_html(', ', $result);
+ }
+
final protected function renderOldValue() {
return $this->renderValue($this->getOldValue());
}
final protected function renderNewValue() {
return $this->renderValue($this->getNewValue());
}
final protected function renderDate($epoch) {
$viewer = $this->getViewer();
// We accept either epoch timestamps or dictionaries describing a
// PhutilCalendarDateTime.
if (is_array($epoch)) {
$datetime = PhutilCalendarAbsoluteDateTime::newFromDictionary($epoch)
->setViewerTimezone($viewer->getTimezoneIdentifier());
$all_day = $datetime->getIsAllDay();
$epoch = $datetime->getEpoch();
} else {
$all_day = false;
}
if ($all_day) {
$display = phabricator_date($epoch, $viewer);
} else if ($this->isRenderingTargetExternal()) {
// When rendering to text, we explicitly render the offset from UTC to
// provide context to the date: the mail may be generating with the
// server's settings, or the user may later refer back to it after
// changing timezones.
$display = phabricator_datetimezone($epoch, $viewer);
} else {
$display = phabricator_datetime($epoch, $viewer);
}
return $this->renderValue($display);
}
final protected function renderOldDate() {
return $this->renderDate($this->getOldValue());
}
final protected function renderNewDate() {
return $this->renderDate($this->getNewValue());
}
final protected function newError($title, $message, $xaction = null) {
return new PhabricatorApplicationTransactionValidationError(
$this->getTransactionTypeConstant(),
$title,
$message,
$xaction);
}
final protected function newRequiredError($message, $xaction = null) {
return $this->newError(pht('Required'), $message, $xaction)
->setIsMissingFieldError(true);
}
final protected function newInvalidError($message, $xaction = null) {
return $this->newError(pht('Invalid'), $message, $xaction);
}
final protected function isNewObject() {
return $this->getEditor()->getIsNewObject();
}
final protected function isEmptyTextTransaction($value, array $xactions) {
foreach ($xactions as $xaction) {
$value = $xaction->getNewValue();
}
return !strlen($value);
}
/**
* When rendering to external targets (Email/Asana/etc), we need to include
* more information that users can't obtain later.
*/
final protected function isRenderingTargetExternal() {
// Right now, this is our best proxy for this:
return $this->isTextMode();
// "TARGET_TEXT" means "EMail" and "TARGET_HTML" means "Web".
}
final protected function isTextMode() {
$target = $this->getStorage()->getRenderingTarget();
return ($target == PhabricatorApplicationTransaction::TARGET_TEXT);
}
final protected function newRemarkupChange() {
return id(new PhabricatorTransactionRemarkupChange())
->setTransaction($this->getStorage());
}
final protected function isCreateTransaction() {
return $this->getStorage()->getIsCreateTransaction();
}
final protected function getPHIDList(array $old, array $new) {
$editor = $this->getEditor();
return $editor->getPHIDList($old, $new);
}
public function getMetadataValue($key, $default = null) {
return $this->getStorage()->getMetadataValue($key, $default);
}
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Mar 14, 3:01 PM (1 d, 9 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
71976
Default Alt Text
(13 KB)

Event Timeline