diff --git a/src/applications/badges/controller/PhabricatorBadgesAwardController.php b/src/applications/badges/controller/PhabricatorBadgesAwardController.php index 3fa474018e..e934e4f2a1 100644 --- a/src/applications/badges/controller/PhabricatorBadgesAwardController.php +++ b/src/applications/badges/controller/PhabricatorBadgesAwardController.php @@ -1,78 +1,78 @@ getViewer(); $id = $request->getURIData('id'); $user = id(new PhabricatorPeopleQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->executeOne(); if (!$user) { return new Aphront404Response(); } $view_uri = '/people/badges/'.$user->getID().'/'; if ($request->isFormPost()) { $badge_phids = $request->getArr('badgePHIDs'); $badges = id(new PhabricatorBadgesQuery()) ->setViewer($viewer) ->withPHIDs($badge_phids) ->needRecipients(true) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_EDIT, PhabricatorPolicyCapability::CAN_VIEW, )) ->execute(); if (!$badges) { return new Aphront404Response(); } $award_phids = array($user->getPHID()); foreach ($badges as $badge) { $xactions = array(); $xactions[] = id(new PhabricatorBadgesTransaction()) ->setTransactionType( PhabricatorBadgesBadgeAwardTransaction::TRANSACTIONTYPE) ->setNewValue($award_phids); $editor = id(new PhabricatorBadgesEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->setContinueOnMissingFields(true) ->applyTransactions($badge, $xactions); } return id(new AphrontRedirectResponse()) ->setURI($view_uri); } $form = id(new AphrontFormView()) ->setUser($viewer) ->appendControl( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Badge')) ->setName('badgePHIDs') ->setDatasource( id(new PhabricatorBadgesDatasource()) ->setParameters( array( 'recipientPHID' => $user->getPHID(), )))); $dialog = $this->newDialog() - ->setTitle(pht('Grant Badge')) + ->setTitle(pht('Award Badge')) ->appendForm($form) ->addCancelButton($view_uri) ->addSubmitButton(pht('Award')); return $dialog; } } diff --git a/src/applications/badges/controller/PhabricatorBadgesRemoveRecipientsController.php b/src/applications/badges/controller/PhabricatorBadgesRemoveRecipientsController.php index b26a2c2159..e6638b745c 100644 --- a/src/applications/badges/controller/PhabricatorBadgesRemoveRecipientsController.php +++ b/src/applications/badges/controller/PhabricatorBadgesRemoveRecipientsController.php @@ -1,71 +1,71 @@ getViewer(); $id = $request->getURIData('id'); $badge = id(new PhabricatorBadgesQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->needRecipients(true) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$badge) { return new Aphront404Response(); } $awards = $badge->getAwards(); $recipient_phids = mpull($awards, 'getRecipientPHID'); $remove_phid = $request->getStr('phid'); if (!in_array($remove_phid, $recipient_phids)) { return new Aphront404Response(); } - $view_uri = $this->getApplicationURI('view/'.$badge->getID().'/'); + $view_uri = $this->getApplicationURI('recipients/'.$badge->getID().'/'); if ($request->isFormPost()) { $xactions = array(); $xactions[] = id(new PhabricatorBadgesTransaction()) ->setTransactionType( PhabricatorBadgesBadgeRevokeTransaction::TRANSACTIONTYPE) ->setNewValue(array($remove_phid)); $editor = id(new PhabricatorBadgesEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->setContinueOnMissingFields(true) ->applyTransactions($badge, $xactions); return id(new AphrontRedirectResponse()) ->setURI($view_uri); } $handle = id(new PhabricatorHandleQuery()) ->setViewer($viewer) ->withPHIDs(array($remove_phid)) ->executeOne(); $dialog = id(new AphrontDialogView()) ->setUser($viewer) ->setTitle(pht('Really Revoke Badge?')) ->appendParagraph( pht( 'Really revoke the badge "%s" from %s?', phutil_tag('strong', array(), $badge->getName()), phutil_tag('strong', array(), $handle->getName()))) ->addCancelButton($view_uri) ->addSubmitButton(pht('Revoke Badge')); return $dialog; } } diff --git a/src/applications/badges/controller/PhabricatorBadgesViewController.php b/src/applications/badges/controller/PhabricatorBadgesViewController.php index 3c434ff1d5..a5390ea5f4 100644 --- a/src/applications/badges/controller/PhabricatorBadgesViewController.php +++ b/src/applications/badges/controller/PhabricatorBadgesViewController.php @@ -1,133 +1,124 @@ getViewer(); $id = $request->getURIData('id'); $badge = id(new PhabricatorBadgesQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->executeOne(); if (!$badge) { return new Aphront404Response(); } $this->setBadge($badge); $crumbs = $this->buildApplicationCrumbs(); $title = $badge->getName(); $header = $this->buildHeaderView(); $curtain = $this->buildCurtain($badge); $details = $this->buildDetailsView($badge); $timeline = $this->buildTransactionTimeline( $badge, new PhabricatorBadgesTransactionQuery()); $comment_view = id(new PhabricatorBadgesEditEngine()) ->setViewer($viewer) ->buildEditEngineCommentView($badge); $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setCurtain($curtain) ->setMainColumn(array( $timeline, $comment_view, )) ->addPropertySection(pht('Description'), $details); $navigation = $this->buildSideNavView('view'); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setPageObjectPHIDs(array($badge->getPHID())) ->setNavigation($navigation) ->appendChild($view); } private function buildDetailsView( PhabricatorBadgesBadge $badge) { $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView()) ->setUser($viewer); $description = $badge->getDescription(); if (strlen($description)) { $view->addTextContent( new PHUIRemarkupView($viewer, $description)); } $badge = id(new PHUIBadgeView()) ->setIcon($badge->getIcon()) ->setHeader($badge->getName()) ->setSubhead($badge->getFlavor()) ->setQuality($badge->getQuality()); $view->addTextContent($badge); return $view; } private function buildCurtain(PhabricatorBadgesBadge $badge) { $viewer = $this->getViewer(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $badge, PhabricatorPolicyCapability::CAN_EDIT); $id = $badge->getID(); $edit_uri = $this->getApplicationURI("/edit/{$id}/"); $archive_uri = $this->getApplicationURI("/archive/{$id}/"); - $award_uri = $this->getApplicationURI("/recipients/{$id}/add/"); $curtain = $this->newCurtainView($badge); $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Edit Badge')) ->setIcon('fa-pencil') ->setDisabled(!$can_edit) ->setHref($edit_uri)); if ($badge->isArchived()) { $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Activate Badge')) ->setIcon('fa-check') ->setDisabled(!$can_edit) ->setWorkflow($can_edit) ->setHref($archive_uri)); } else { $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Archive Badge')) ->setIcon('fa-ban') ->setDisabled(!$can_edit) ->setWorkflow($can_edit) ->setHref($archive_uri)); } - $curtain->addAction( - id(new PhabricatorActionView()) - ->setName('Add Recipients') - ->setIcon('fa-users') - ->setDisabled(!$can_edit) - ->setWorkflow(true) - ->setHref($award_uri)); - return $curtain; } } diff --git a/src/applications/badges/editor/PhabricatorBadgesEditEngine.php b/src/applications/badges/editor/PhabricatorBadgesEditEngine.php index 597cf470f6..596e70cd13 100644 --- a/src/applications/badges/editor/PhabricatorBadgesEditEngine.php +++ b/src/applications/badges/editor/PhabricatorBadgesEditEngine.php @@ -1,130 +1,130 @@ getViewer()); } protected function newObjectQuery() { return new PhabricatorBadgesQuery(); } protected function getObjectCreateTitleText($object) { return pht('Create New Badge'); } protected function getObjectEditTitleText($object) { return pht('Edit Badge: %s', $object->getName()); } protected function getObjectEditShortText($object) { return $object->getName(); } protected function getObjectCreateShortText() { return pht('Create Badge'); } protected function getObjectName() { return pht('Badge'); } protected function getObjectCreateCancelURI($object) { return $this->getApplication()->getApplicationURI('/'); } protected function getEditorURI() { return $this->getApplication()->getApplicationURI('edit/'); } protected function getCommentViewHeaderText($object) { return pht('Render Honors'); } protected function getCommentViewButtonText($object) { return pht('Salute'); } protected function getObjectViewURI($object) { return $object->getViewURI(); } protected function getCreateNewObjectPolicy() { return $this->getApplication()->getPolicy( PhabricatorBadgesCreateCapability::CAPABILITY); } protected function buildCustomEditFields($object) { return array( id(new PhabricatorTextEditField()) ->setKey('name') ->setLabel(pht('Name')) ->setDescription(pht('Badge name.')) ->setConduitTypeDescription(pht('New badge name.')) ->setTransactionType( PhabricatorBadgesBadgeNameTransaction::TRANSACTIONTYPE) ->setValue($object->getName()) ->setIsRequired(true), id(new PhabricatorTextEditField()) ->setKey('flavor') - ->setLabel(pht('Flavor text')) + ->setLabel(pht('Flavor Text')) ->setDescription(pht('Short description of the badge.')) ->setConduitTypeDescription(pht('New badge flavor.')) ->setValue($object->getFlavor()) ->setTransactionType( PhabricatorBadgesBadgeFlavorTransaction::TRANSACTIONTYPE), id(new PhabricatorIconSetEditField()) ->setKey('icon') ->setLabel(pht('Icon')) ->setIconSet(new PhabricatorBadgesIconSet()) ->setTransactionType( PhabricatorBadgesBadgeIconTransaction::TRANSACTIONTYPE) ->setConduitDescription(pht('Change the badge icon.')) ->setConduitTypeDescription(pht('New badge icon.')) ->setValue($object->getIcon()), id(new PhabricatorSelectEditField()) ->setKey('quality') ->setLabel(pht('Quality')) ->setDescription(pht('Color and rarity of the badge.')) ->setConduitTypeDescription(pht('New badge quality.')) ->setValue($object->getQuality()) ->setTransactionType( PhabricatorBadgesBadgeQualityTransaction::TRANSACTIONTYPE) ->setOptions(PhabricatorBadgesQuality::getDropdownQualityMap()), id(new PhabricatorRemarkupEditField()) ->setKey('description') ->setLabel(pht('Description')) ->setDescription(pht('Badge long description.')) ->setConduitTypeDescription(pht('New badge description.')) ->setTransactionType( PhabricatorBadgesBadgeDescriptionTransaction::TRANSACTIONTYPE) ->setValue($object->getDescription()), ); } } diff --git a/src/applications/badges/editor/PhabricatorBadgesEditor.php b/src/applications/badges/editor/PhabricatorBadgesEditor.php index 65b2ca6cdf..48057f66e6 100644 --- a/src/applications/badges/editor/PhabricatorBadgesEditor.php +++ b/src/applications/badges/editor/PhabricatorBadgesEditor.php @@ -1,102 +1,126 @@ pht('Someone changes the badge\'s details.'), PhabricatorBadgesTransaction::MAILTAG_COMMENT => pht('Someone comments on a badge.'), PhabricatorBadgesTransaction::MAILTAG_OTHER => pht('Other badge activity not listed above occurs.'), ); } protected function shouldPublishFeedStory( PhabricatorLiskDAO $object, array $xactions) { return true; } + protected function expandTransactions( + PhabricatorLiskDAO $object, + array $xactions) { + + $actor = $this->getActor(); + $actor_phid = $actor->getPHID(); + + $results = parent::expandTransactions($object, $xactions); + + // Automatically subscribe the author when they create a badge. + if ($this->getIsNewObject()) { + if ($actor_phid) { + $results[] = id(new PhabricatorBadgesTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS) + ->setNewValue( + array( + '+' => array($actor_phid => $actor_phid), + )); + } + } + + return $results; + } + protected function buildReplyHandler(PhabricatorLiskDAO $object) { return id(new PhabricatorBadgesReplyHandler()) ->setMailReceiver($object); } protected function buildMailTemplate(PhabricatorLiskDAO $object) { $name = $object->getName(); $id = $object->getID(); $name = pht('Badge %d', $id); return id(new PhabricatorMetaMTAMail()) ->setSubject($name) ->addHeader('Thread-Topic', $name); } protected function getMailTo(PhabricatorLiskDAO $object) { return array( $object->getCreatorPHID(), $this->requireActor()->getPHID(), ); } protected function buildMailBody( PhabricatorLiskDAO $object, array $xactions) { $description = $object->getDescription(); $body = parent::buildMailBody($object, $xactions); if (strlen($description)) { $body->addRemarkupSection( pht('BADGE DESCRIPTION'), $object->getDescription()); } $body->addLinkSection( pht('BADGE DETAIL'), PhabricatorEnv::getProductionURI('/badges/view/'.$object->getID().'/')); return $body; } protected function getMailSubjectPrefix() { return pht('[Badge]'); } } diff --git a/src/applications/badges/query/PhabricatorBadgesSearchEngine.php b/src/applications/badges/query/PhabricatorBadgesSearchEngine.php index b57eae5910..4db0cdd979 100644 --- a/src/applications/badges/query/PhabricatorBadgesSearchEngine.php +++ b/src/applications/badges/query/PhabricatorBadgesSearchEngine.php @@ -1,156 +1,156 @@ setLabel(pht('Name Contains')) ->setKey('name') ->setDescription(pht('Search for badges by name substring.')), id(new PhabricatorSearchCheckboxesField()) ->setKey('qualities') ->setLabel(pht('Quality')) ->setOptions(PhabricatorBadgesQuality::getDropdownQualityMap()), id(new PhabricatorSearchCheckboxesField()) ->setKey('statuses') ->setLabel(pht('Status')) ->setOptions( id(new PhabricatorBadgesBadge()) ->getStatusNameMap()), ); } protected function buildQueryFromParameters(array $map) { $query = $this->newQuery(); if ($map['statuses']) { $query->withStatuses($map['statuses']); } if ($map['qualities']) { $query->withQualities($map['qualities']); } if ($map['name'] !== null) { $query->withNameNgrams($map['name']); } return $query; } protected function getURI($path) { return '/badges/'.$path; } protected function getBuiltinQueryNames() { $names = array(); $names['open'] = pht('Active Badges'); $names['all'] = pht('All Badges'); return $names; } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { case 'all': return $query; case 'open': return $query->setParameter( 'statuses', array( PhabricatorBadgesBadge::STATUS_ACTIVE, )); } return parent::buildSavedQueryFromBuiltin($query_key); } protected function getRequiredHandlePHIDsForResultList( array $badges, PhabricatorSavedQuery $query) { $phids = array(); return $phids; } protected function renderResultList( array $badges, PhabricatorSavedQuery $query, array $handles) { assert_instances_of($badges, 'PhabricatorBadgesBadge'); $viewer = $this->requireViewer(); $list = id(new PHUIObjectItemListView()); foreach ($badges as $badge) { $quality_name = PhabricatorBadgesQuality::getQualityName( $badge->getQuality()); $mini_badge = id(new PHUIBadgeMiniView()) ->setHeader($badge->getName()) ->setIcon($badge->getIcon()) ->setQuality($badge->getQuality()); $item = id(new PHUIObjectItemView()) ->setHeader($badge->getName()) ->setBadge($mini_badge) ->setHref('/badges/view/'.$badge->getID().'/') ->addAttribute($quality_name) ->addAttribute($badge->getFlavor()); if ($badge->isArchived()) { $item->setDisabled(true); $item->addIcon('fa-ban', pht('Archived')); } $list->addItem($item); } $result = new PhabricatorApplicationSearchResultView(); $result->setObjectList($list); $result->setNoDataString(pht('No badges found.')); return $result; } protected function getNewUserBody() { $create_button = id(new PHUIButtonView()) ->setTag('a') ->setText(pht('Create a Badge')) ->setHref('/badges/create/') ->setColor(PHUIButtonView::GREEN); $icon = $this->getApplication()->getIcon(); $app_name = $this->getApplication()->getName(); $view = id(new PHUIBigInfoView()) ->setIcon($icon) ->setTitle(pht('Welcome to %s', $app_name)) ->setDescription( pht('Badges let you award and distinguish special users '. - 'throughout your instance.')) + 'throughout your install.')) ->addAction($create_button); return $view; } } diff --git a/src/applications/badges/storage/PhabricatorBadgesBadge.php b/src/applications/badges/storage/PhabricatorBadgesBadge.php index 4cdc4edf61..cf02f705ce 100644 --- a/src/applications/badges/storage/PhabricatorBadgesBadge.php +++ b/src/applications/badges/storage/PhabricatorBadgesBadge.php @@ -1,226 +1,226 @@ pht('Active'), self::STATUS_ARCHIVED => pht('Archived'), ); } public static function initializeNewBadge(PhabricatorUser $actor) { $app = id(new PhabricatorApplicationQuery()) ->setViewer($actor) ->withClasses(array('PhabricatorBadgesApplication')) ->executeOne(); $view_policy = PhabricatorPolicies::getMostOpenPolicy(); $edit_policy = $app->getPolicy(PhabricatorBadgesDefaultEditCapability::CAPABILITY); return id(new PhabricatorBadgesBadge()) ->setIcon(self::DEFAULT_ICON) ->setQuality(PhabricatorBadgesQuality::DEFAULT_QUALITY) ->setCreatorPHID($actor->getPHID()) ->setEditPolicy($edit_policy) ->setFlavor('') ->setDescription('') ->setStatus(self::STATUS_ACTIVE); } protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_COLUMN_SCHEMA => array( 'name' => 'sort255', 'flavor' => 'text255', 'description' => 'text', 'icon' => 'text255', 'quality' => 'uint32', 'status' => 'text32', 'mailKey' => 'bytes20', ), self::CONFIG_KEY_SCHEMA => array( 'key_creator' => array( 'columns' => array('creatorPHID', 'dateModified'), ), ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID(PhabricatorBadgesPHIDType::TYPECONST); } public function isArchived() { return ($this->getStatus() == self::STATUS_ARCHIVED); } public function attachAwards(array $awards) { $this->awards = $awards; return $this; } public function getAwards() { return $this->assertAttached($this->awards); } public function getViewURI() { return '/badges/view/'.$this->getID().'/'; } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return PhabricatorPolicies::getMostOpenPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { return new PhabricatorBadgesEditor(); } public function getApplicationTransactionObject() { return $this; } public function getApplicationTransactionTemplate() { return new PhabricatorBadgesTransaction(); } public function willRenderTimeline( PhabricatorApplicationTransactionView $timeline, AphrontRequest $request) { return $timeline; } /* -( PhabricatorSubscribableInterface )----------------------------------- */ public function isAutomaticallySubscribed($phid) { - return ($this->creatorPHID == $phid); + return false; } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $awards = id(new PhabricatorBadgesAwardQuery()) ->setViewer($engine->getViewer()) ->withBadgePHIDs(array($this->getPHID())) ->execute(); foreach ($awards as $award) { $engine->destroyObject($award); } $this->openTransaction(); $this->delete(); $this->saveTransaction(); } /* -( PhabricatorConduitResultInterface )---------------------------------- */ public function getFieldSpecificationsForConduit() { return array( id(new PhabricatorConduitSearchFieldSpecification()) ->setKey('name') ->setType('string') ->setDescription(pht('The name of the badge.')), id(new PhabricatorConduitSearchFieldSpecification()) ->setKey('creatorPHID') ->setType('phid') ->setDescription(pht('User PHID of the creator.')), id(new PhabricatorConduitSearchFieldSpecification()) ->setKey('status') ->setType('string') ->setDescription(pht('Active or archived status of the badge.')), ); } public function getFieldValuesForConduit() { return array( 'name' => $this->getName(), 'creatorPHID' => $this->getCreatorPHID(), 'status' => $this->getStatus(), ); } public function getConduitSearchAttachments() { return array(); } /* -( PhabricatorNgramInterface )------------------------------------------ */ public function newNgrams() { return array( id(new PhabricatorBadgesBadgeNameNgrams()) ->setValue($this->getName()), ); } } diff --git a/src/applications/badges/xaction/PhabricatorBadgesBadgeAwardTransaction.php b/src/applications/badges/xaction/PhabricatorBadgesBadgeAwardTransaction.php index 5f339fa368..5ecacdd441 100644 --- a/src/applications/badges/xaction/PhabricatorBadgesBadgeAwardTransaction.php +++ b/src/applications/badges/xaction/PhabricatorBadgesBadgeAwardTransaction.php @@ -1,62 +1,90 @@ getAwards(), 'getRecipientPHID'); } public function applyExternalEffects($object, $value) { $awards = $object->getAwards(); $awards = mpull($awards, null, 'getRecipientPHID'); foreach ($value as $phid) { $award = idx($awards, $phid); if (!$award) { $award = PhabricatorBadgesAward::initializeNewBadgesAward( $this->getActor(), $object, $phid); $award->save(); $awards[] = $award; } } $object->attachAwards($awards); return; } public function getTitle() { $new = $this->getNewValue(); if (!is_array($new)) { $new = array(); } $handles = $this->renderHandleList($new); return pht( '%s awarded this badge to %s recipient(s): %s.', $this->renderAuthor(), new PhutilNumber(count($new)), $handles); } public function getTitleForFeed() { $new = $this->getNewValue(); if (!is_array($new)) { $new = array(); } $handles = $this->renderHandleList($new); return pht( '%s awarded %s to %s recipient(s): %s.', $this->renderAuthor(), $this->renderObject(), new PhutilNumber(count($new)), $handles); } public function getIcon() { return 'fa-user-plus'; } + public function validateTransactions($object, array $xactions) { + $errors = array(); + + foreach ($xactions as $xaction) { + $user_phids = $xaction->getNewValue(); + if (!$user_phids) { + $errors[] = $this->newRequiredError( + pht('Recipient is required.')); + continue; + } + + foreach ($user_phids as $user_phid) { + $user = id(new PhabricatorPeopleQuery()) + ->setViewer($this->getActor()) + ->withPHIDs(array($user_phid)) + ->executeOne(); + if (!$user) { + $errors[] = $this->newInvalidError( + pht( + 'Recipient PHID "%s" is not a valid user PHID.', + $user_phid)); + } + } + } + + return $errors; + } + } diff --git a/src/applications/badges/xaction/PhabricatorBadgesBadgeFlavorTransaction.php b/src/applications/badges/xaction/PhabricatorBadgesBadgeFlavorTransaction.php index 069ec09603..2635aab1a6 100644 --- a/src/applications/badges/xaction/PhabricatorBadgesBadgeFlavorTransaction.php +++ b/src/applications/badges/xaction/PhabricatorBadgesBadgeFlavorTransaction.php @@ -1,33 +1,50 @@ getFlavor(); } public function applyInternalEffects($object, $value) { $object->setFlavor($value); } public function getTitle() { return pht( '%s updated the flavor from %s to %s.', $this->renderAuthor(), $this->renderOldValue(), $this->renderNewValue()); } public function getTitleForFeed() { return pht( '%s updated %s flavor text from %s to %s.', $this->renderAuthor(), $this->renderObject(), $this->renderOldValue(), $this->renderNewValue()); } + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $max_length = $object->getColumnMaximumByteLength('flavor'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newRequiredError( + pht('The flavor text can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + } diff --git a/src/applications/badges/xaction/PhabricatorBadgesBadgeNameTransaction.php b/src/applications/badges/xaction/PhabricatorBadgesBadgeNameTransaction.php index 4565c95fb7..1df7d89a70 100644 --- a/src/applications/badges/xaction/PhabricatorBadgesBadgeNameTransaction.php +++ b/src/applications/badges/xaction/PhabricatorBadgesBadgeNameTransaction.php @@ -1,44 +1,55 @@ getName(); } public function applyInternalEffects($object, $value) { $object->setName($value); } public function getTitle() { return pht( '%s renamed this badge from %s to %s.', $this->renderAuthor(), $this->renderOldValue(), $this->renderNewValue()); } public function getTitleForFeed() { return pht( '%s renamed %s badge %s to %s.', $this->renderAuthor(), $this->renderObject(), $this->renderOldValue(), $this->renderNewValue()); } public function validateTransactions($object, array $xactions) { $errors = array(); if ($this->isEmptyTextTransaction($object->getName(), $xactions)) { $errors[] = $this->newRequiredError( pht('Badges must have a name.')); } + $max_length = $object->getColumnMaximumByteLength('name'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newRequiredError( + pht('The name can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + return $errors; } } diff --git a/src/applications/badges/xaction/PhabricatorBadgesBadgeRevokeTransaction.php b/src/applications/badges/xaction/PhabricatorBadgesBadgeRevokeTransaction.php index 704a518371..a3fa58a060 100644 --- a/src/applications/badges/xaction/PhabricatorBadgesBadgeRevokeTransaction.php +++ b/src/applications/badges/xaction/PhabricatorBadgesBadgeRevokeTransaction.php @@ -1,54 +1,83 @@ getAwards(); $awards = mpull($awards, null, 'getRecipientPHID'); foreach ($value as $phid) { $awards[$phid]->delete(); } $object->attachAwards($awards); return; } public function getTitle() { $new = $this->getNewValue(); if (!is_array($new)) { $new = array(); } $handles = $this->renderHandleList($new); return pht( '%s revoked this badge from %s recipient(s): %s.', $this->renderAuthor(), new PhutilNumber(count($new)), $handles); } public function getTitleForFeed() { $new = $this->getNewValue(); if (!is_array($new)) { $new = array(); } $handles = $this->renderHandleList($new); return pht( '%s revoked %s from %s recipient(s): %s.', $this->renderAuthor(), $this->renderObject(), new PhutilNumber(count($new)), $handles); } public function getIcon() { return 'fa-user-times'; } + public function validateTransactions($object, array $xactions) { + $errors = array(); + + foreach ($xactions as $xaction) { + $award_phids = $xaction->getNewValue(); + if (!$award_phids) { + $errors[] = $this->newRequiredError( + pht('Recipient is required.')); + continue; + } + + foreach ($award_phids as $award_phid) { + $award = id(new PhabricatorBadgesAwardQuery()) + ->setViewer($this->getActor()) + ->withRecipientPHIDs(array($award_phid)) + ->withBadgePHIDs(array($object->getPHID())) + ->executeOne(); + if (!$award) { + $errors[] = $this->newInvalidError( + pht( + 'Recipient PHID "%s" has not been awarded.', + $award_phid)); + } + } + } + + return $errors; + } + }