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

Badges v0.1

Summary:
Basic plumbing for Badges application.

- You can make Badges.
- You can look at a list of them.
- They can be edited.
- They can be assigned to people.
- You can revoke them from people.
- You can subscribe to them.

Test Plan: Make Badges with various options. Give them to people. Take them away from people.

Reviewers: lpriestley, epriestley

Reviewed By: epriestley

Subscribers: tycho.tatitscheff, johnny-bit, epriestley, Korvin

Maniphest Tasks: T6526

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

+2317 -8
+5 -5
resources/celerity/map.php
··· 7 7 */ 8 8 return array( 9 9 'names' => array( 10 - 'core.pkg.css' => 'b5cc2f39', 10 + 'core.pkg.css' => 'f79ebe46', 11 11 'core.pkg.js' => 'a590b451', 12 12 'darkconsole.pkg.js' => 'e7393ebb', 13 13 'differential.pkg.css' => '9451634c', ··· 142 142 'rsrc/css/phui/phui-info-view.css' => '5b16bac6', 143 143 'rsrc/css/phui/phui-list.css' => '125599df', 144 144 'rsrc/css/phui/phui-object-box.css' => '407eaf5a', 145 - 'rsrc/css/phui/phui-object-item-list-view.css' => 'fc19bfc1', 145 + 'rsrc/css/phui/phui-object-item-list-view.css' => 'a1b990b7', 146 146 'rsrc/css/phui/phui-pager.css' => 'bea33d23', 147 147 'rsrc/css/phui/phui-pinboard-view.css' => '2495140e', 148 - 'rsrc/css/phui/phui-property-list-view.css' => '1baf23eb', 148 + 'rsrc/css/phui/phui-property-list-view.css' => 'aeb09581', 149 149 'rsrc/css/phui/phui-remarkup-preview.css' => '867f85b3', 150 150 'rsrc/css/phui/phui-spacing.css' => '042804d6', 151 151 'rsrc/css/phui/phui-status.css' => '888cedb8', ··· 797 797 'phui-inline-comment-view-css' => '9fadd6b8', 798 798 'phui-list-view-css' => '125599df', 799 799 'phui-object-box-css' => '407eaf5a', 800 - 'phui-object-item-list-view-css' => 'fc19bfc1', 800 + 'phui-object-item-list-view-css' => 'a1b990b7', 801 801 'phui-pager-css' => 'bea33d23', 802 802 'phui-pinboard-view-css' => '2495140e', 803 - 'phui-property-list-view-css' => '1baf23eb', 803 + 'phui-property-list-view-css' => 'aeb09581', 804 804 'phui-remarkup-preview-css' => '867f85b3', 805 805 'phui-spacing-css' => '042804d6', 806 806 'phui-status-list-view-css' => '888cedb8',
+54
resources/sql/autopatches/20150712.badges.1.sql
··· 1 + CREATE TABLE {$NAMESPACE}_badges.badges_badge ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + phid VARBINARY(64) NOT NULL, 4 + name VARCHAR(255) NOT NULL COLLATE {$COLLATE_TEXT}, 5 + flavor VARCHAR(255) NOT NULL COLLATE {$COLLATE_TEXT}, 6 + description LONGTEXT NOT NULL, 7 + icon VARCHAR(255) NOT NULL, 8 + quality VARCHAR(255) NOT NULL, 9 + status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT}, 10 + dateCreated INT UNSIGNED NOT NULL, 11 + dateModified INT UNSIGNED NOT NULL, 12 + viewPolicy VARBINARY(64) NOT NULL, 13 + editPolicy VARBINARY(64) NOT NULL, 14 + creatorPHID varbinary(64) NOT NULL, 15 + UNIQUE KEY `key_phid` (phid), 16 + KEY `key_creator` (creatorPHID, dateModified) 17 + ) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; 18 + 19 + CREATE TABLE {$NAMESPACE}_badges.badges_transaction ( 20 + id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, 21 + phid VARBINARY(64) NOT NULL, 22 + authorPHID VARBINARY(64) NOT NULL, 23 + objectPHID VARBINARY(64) NOT NULL, 24 + viewPolicy VARBINARY(64) NOT NULL, 25 + editPolicy VARBINARY(64) NOT NULL, 26 + commentPHID VARBINARY(64), 27 + commentVersion INT UNSIGNED NOT NULL, 28 + transactionType VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT}, 29 + oldValue LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, 30 + newValue LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, 31 + contentSource LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, 32 + metadata LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, 33 + dateCreated INT UNSIGNED NOT NULL, 34 + dateModified INT UNSIGNED NOT NULL, 35 + UNIQUE KEY `key_phid` (phid), 36 + KEY `key_object` (objectPHID) 37 + ) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; 38 + 39 + CREATE TABLE {$NAMESPACE}_badges.edge ( 40 + src VARBINARY(64) NOT NULL, 41 + type INT UNSIGNED NOT NULL, 42 + dst VARBINARY(64) NOT NULL, 43 + dateCreated INT UNSIGNED NOT NULL, 44 + seq INT UNSIGNED NOT NULL, 45 + dataID INT UNSIGNED, 46 + PRIMARY KEY (src, type, dst), 47 + KEY `src` (src, type, dateCreated, seq), 48 + UNIQUE KEY `key_dst` (dst, type, src) 49 + ) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; 50 + 51 + CREATE TABLE {$NAMESPACE}_badges.edgedata ( 52 + id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, 53 + data LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT} 54 + ) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
+55
src/__phutil_library_map__.php
··· 1617 1617 'PhabricatorAuthValidateController' => 'applications/auth/controller/PhabricatorAuthValidateController.php', 1618 1618 'PhabricatorAuthenticationConfigOptions' => 'applications/config/option/PhabricatorAuthenticationConfigOptions.php', 1619 1619 'PhabricatorAutoEventListener' => 'infrastructure/events/PhabricatorAutoEventListener.php', 1620 + 'PhabricatorBadgeHasRecipientEdgeType' => 'applications/badges/edge/PhabricatorBadgeHasRecipientEdgeType.php', 1621 + 'PhabricatorBadgesApplication' => 'applications/badges/application/PhabricatorBadgesApplication.php', 1622 + 'PhabricatorBadgesBadge' => 'applications/badges/storage/PhabricatorBadgesBadge.php', 1623 + 'PhabricatorBadgesController' => 'applications/badges/controller/PhabricatorBadgesController.php', 1624 + 'PhabricatorBadgesCreateCapability' => 'applications/badges/capability/PhabricatorBadgesCreateCapability.php', 1625 + 'PhabricatorBadgesDAO' => 'applications/badges/storage/PhabricatorBadgesDAO.php', 1626 + 'PhabricatorBadgesDefaultEditCapability' => 'applications/badges/capability/PhabricatorBadgesDefaultEditCapability.php', 1627 + 'PhabricatorBadgesDefaultViewCapability' => 'applications/badges/capability/PhabricatorBadgesDefaultViewCapability.php', 1628 + 'PhabricatorBadgesEditController' => 'applications/badges/controller/PhabricatorBadgesEditController.php', 1629 + 'PhabricatorBadgesEditIconController' => 'applications/badges/controller/PhabricatorBadgesEditIconController.php', 1630 + 'PhabricatorBadgesEditRecipientsController' => 'applications/badges/controller/PhabricatorBadgesEditRecipientsController.php', 1631 + 'PhabricatorBadgesEditor' => 'applications/badges/editor/PhabricatorBadgesEditor.php', 1632 + 'PhabricatorBadgesIcon' => 'applications/badges/icon/PhabricatorBadgesIcon.php', 1633 + 'PhabricatorBadgesListController' => 'applications/badges/controller/PhabricatorBadgesListController.php', 1634 + 'PhabricatorBadgesPHIDType' => 'applications/badges/phid/PhabricatorBadgesPHIDType.php', 1635 + 'PhabricatorBadgesQuery' => 'applications/badges/query/PhabricatorBadgesQuery.php', 1636 + 'PhabricatorBadgesRecipientsListView' => 'applications/badges/view/PhabricatorBadgesRecipientsListView.php', 1637 + 'PhabricatorBadgesRemoveRecipientsController' => 'applications/badges/controller/PhabricatorBadgesRemoveRecipientsController.php', 1638 + 'PhabricatorBadgesSchemaSpec' => 'applications/badges/storage/PhabricatorBadgesSchemaSpec.php', 1639 + 'PhabricatorBadgesSearchEngine' => 'applications/badges/query/PhabricatorBadgesSearchEngine.php', 1640 + 'PhabricatorBadgesTransaction' => 'applications/badges/storage/PhabricatorBadgesTransaction.php', 1641 + 'PhabricatorBadgesTransactionQuery' => 'applications/badges/query/PhabricatorBadgesTransactionQuery.php', 1642 + 'PhabricatorBadgesViewController' => 'applications/badges/controller/PhabricatorBadgesViewController.php', 1620 1643 'PhabricatorBarePageUIExample' => 'applications/uiexample/examples/PhabricatorBarePageUIExample.php', 1621 1644 'PhabricatorBarePageView' => 'view/page/PhabricatorBarePageView.php', 1622 1645 'PhabricatorBaseURISetupCheck' => 'applications/config/check/PhabricatorBaseURISetupCheck.php', ··· 2561 2584 'PhabricatorQueryOrderTestCase' => 'infrastructure/query/order/__tests__/PhabricatorQueryOrderTestCase.php', 2562 2585 'PhabricatorQueryOrderVector' => 'infrastructure/query/order/PhabricatorQueryOrderVector.php', 2563 2586 'PhabricatorRecaptchaConfigOptions' => 'applications/config/option/PhabricatorRecaptchaConfigOptions.php', 2587 + 'PhabricatorRecipientHasBadgeEdgeType' => 'applications/badges/edge/PhabricatorRecipientHasBadgeEdgeType.php', 2564 2588 'PhabricatorRedirectController' => 'applications/base/controller/PhabricatorRedirectController.php', 2565 2589 'PhabricatorRefreshCSRFController' => 'applications/auth/controller/PhabricatorRefreshCSRFController.php', 2566 2590 'PhabricatorRegistrationProfile' => 'applications/people/storage/PhabricatorRegistrationProfile.php', ··· 5339 5363 'PhabricatorAuthValidateController' => 'PhabricatorAuthController', 5340 5364 'PhabricatorAuthenticationConfigOptions' => 'PhabricatorApplicationConfigOptions', 5341 5365 'PhabricatorAutoEventListener' => 'PhabricatorEventListener', 5366 + 'PhabricatorBadgeHasRecipientEdgeType' => 'PhabricatorEdgeType', 5367 + 'PhabricatorBadgesApplication' => 'PhabricatorApplication', 5368 + 'PhabricatorBadgesBadge' => array( 5369 + 'PhabricatorBadgesDAO', 5370 + 'PhabricatorPolicyInterface', 5371 + 'PhabricatorApplicationTransactionInterface', 5372 + 'PhabricatorSubscribableInterface', 5373 + 'PhabricatorFlaggableInterface', 5374 + 'PhabricatorDestructibleInterface', 5375 + ), 5376 + 'PhabricatorBadgesController' => 'PhabricatorController', 5377 + 'PhabricatorBadgesCreateCapability' => 'PhabricatorPolicyCapability', 5378 + 'PhabricatorBadgesDAO' => 'PhabricatorLiskDAO', 5379 + 'PhabricatorBadgesDefaultEditCapability' => 'PhabricatorPolicyCapability', 5380 + 'PhabricatorBadgesDefaultViewCapability' => 'PhabricatorPolicyCapability', 5381 + 'PhabricatorBadgesEditController' => 'PhabricatorBadgesController', 5382 + 'PhabricatorBadgesEditIconController' => 'PhabricatorBadgesController', 5383 + 'PhabricatorBadgesEditRecipientsController' => 'PhabricatorBadgesController', 5384 + 'PhabricatorBadgesEditor' => 'PhabricatorApplicationTransactionEditor', 5385 + 'PhabricatorBadgesIcon' => 'Phobject', 5386 + 'PhabricatorBadgesListController' => 'PhabricatorBadgesController', 5387 + 'PhabricatorBadgesPHIDType' => 'PhabricatorPHIDType', 5388 + 'PhabricatorBadgesQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 5389 + 'PhabricatorBadgesRecipientsListView' => 'AphrontTagView', 5390 + 'PhabricatorBadgesRemoveRecipientsController' => 'PhabricatorBadgesController', 5391 + 'PhabricatorBadgesSchemaSpec' => 'PhabricatorConfigSchemaSpec', 5392 + 'PhabricatorBadgesSearchEngine' => 'PhabricatorApplicationSearchEngine', 5393 + 'PhabricatorBadgesTransaction' => 'PhabricatorApplicationTransaction', 5394 + 'PhabricatorBadgesTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 5395 + 'PhabricatorBadgesViewController' => 'PhabricatorBadgesController', 5342 5396 'PhabricatorBarePageUIExample' => 'PhabricatorUIExample', 5343 5397 'PhabricatorBarePageView' => 'AphrontPageView', 5344 5398 'PhabricatorBaseURISetupCheck' => 'PhabricatorSetupCheck', ··· 6448 6502 'Iterator', 6449 6503 ), 6450 6504 'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions', 6505 + 'PhabricatorRecipientHasBadgeEdgeType' => 'PhabricatorEdgeType', 6451 6506 'PhabricatorRedirectController' => 'PhabricatorController', 6452 6507 'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController', 6453 6508 'PhabricatorRegistrationProfile' => 'Phobject',
+79
src/applications/badges/application/PhabricatorBadgesApplication.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesApplication extends PhabricatorApplication { 4 + 5 + public function getName() { 6 + return pht('Badges'); 7 + } 8 + 9 + public function getBaseURI() { 10 + return '/badges/'; 11 + } 12 + 13 + public function getShortDescription() { 14 + return pht('Achievements and Notority'); 15 + } 16 + 17 + public function getFontIcon() { 18 + return 'fa-trophy'; 19 + } 20 + 21 + public function getFlavorText() { 22 + return pht('Build self esteem through gamification.'); 23 + } 24 + 25 + public function getApplicationGroup() { 26 + return self::GROUP_UTILITIES; 27 + } 28 + 29 + public function canUninstall() { 30 + return true; 31 + } 32 + 33 + public function isPrototype() { 34 + return true; 35 + } 36 + 37 + public function getRoutes() { 38 + return array( 39 + '/badges/' => array( 40 + '(?:query/(?P<queryKey>[^/]+)/)?' 41 + => 'PhabricatorBadgesListController', 42 + 'create/' 43 + => 'PhabricatorBadgesEditController', 44 + 'edit/(?:(?P<id>\d+)/)?' 45 + => 'PhabricatorBadgesEditController', 46 + 'view/(?:(?P<id>\d+)/)?' 47 + => 'PhabricatorBadgesViewController', 48 + 'icon/(?P<id>[1-9]\d*)/' 49 + => 'PhabricatorBadgesEditIconController', 50 + 'icon/' 51 + => 'PhabricatorBadgesEditIconController', 52 + 'recipients/(?P<id>[1-9]\d*)/' 53 + => 'PhabricatorBadgesEditRecipientsController', 54 + 'recipients/(?P<id>[1-9]\d*)/remove/' 55 + => 'PhabricatorBadgesRemoveRecipientsController', 56 + 57 + ), 58 + ); 59 + } 60 + 61 + protected function getCustomCapabilities() { 62 + return array( 63 + PhabricatorBadgesCreateCapability::CAPABILITY => array( 64 + 'default' => PhabricatorPolicies::POLICY_ADMIN, 65 + 'caption' => pht('Default create policy for badges.'), 66 + ), 67 + PhabricatorBadgesDefaultEditCapability::CAPABILITY => array( 68 + 'default' => PhabricatorPolicies::POLICY_ADMIN, 69 + 'caption' => pht('Default edit policy for badges.'), 70 + 'template' => PhabricatorBadgesPHIDType::TYPECONST, 71 + ), 72 + PhabricatorBadgesDefaultViewCapability::CAPABILITY => array( 73 + 'caption' => pht('Default view policy for badges.'), 74 + 'template' => PhabricatorBadgesPHIDType::TYPECONST, 75 + ), 76 + ); 77 + } 78 + 79 + }
+16
src/applications/badges/capability/PhabricatorBadgesCreateCapability.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesCreateCapability 4 + extends PhabricatorPolicyCapability { 5 + 6 + const CAPABILITY = 'badges.default.create'; 7 + 8 + public function getCapabilityName() { 9 + return pht('Can Create Badges'); 10 + } 11 + 12 + public function describeCapabilityRejection() { 13 + return pht('You do not have permission to create badges.'); 14 + } 15 + 16 + }
+12
src/applications/badges/capability/PhabricatorBadgesDefaultEditCapability.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesDefaultEditCapability 4 + extends PhabricatorPolicyCapability { 5 + 6 + const CAPABILITY = 'badges.default.edit'; 7 + 8 + public function getCapabilityName() { 9 + return pht('Default Edit Badges'); 10 + } 11 + 12 + }
+16
src/applications/badges/capability/PhabricatorBadgesDefaultViewCapability.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesDefaultViewCapability extends 4 + PhabricatorPolicyCapability { 5 + 6 + const CAPABILITY = 'badges.default.view'; 7 + 8 + public function getCapabilityName() { 9 + return pht('Default View Policy'); 10 + } 11 + 12 + public function shouldAllowPublicPolicySetting() { 13 + return true; 14 + } 15 + 16 + }
+3
src/applications/badges/controller/PhabricatorBadgesController.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorBadgesController extends PhabricatorController {}
+222
src/applications/badges/controller/PhabricatorBadgesEditController.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesEditController 4 + extends PhabricatorBadgesController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $request->getViewer(); 8 + $id = $request->getURIData('id'); 9 + 10 + if ($id) { 11 + $badge = id(new PhabricatorBadgesQuery()) 12 + ->setViewer($viewer) 13 + ->withIDs(array($id)) 14 + ->requireCapabilities( 15 + array( 16 + PhabricatorPolicyCapability::CAN_VIEW, 17 + PhabricatorPolicyCapability::CAN_EDIT, 18 + )) 19 + ->executeOne(); 20 + if (!$badge) { 21 + return new Aphront404Response(); 22 + } 23 + $is_new = false; 24 + } else { 25 + $badge = PhabricatorBadgesBadge::initializeNewBadge($viewer); 26 + $is_new = true; 27 + } 28 + 29 + if ($is_new) { 30 + $title = pht('Create Badge'); 31 + $button_text = pht('Create Badge'); 32 + $cancel_uri = $this->getApplicationURI(); 33 + } else { 34 + $title = pht( 35 + 'Edit %s', 36 + $badge->getName()); 37 + $button_text = pht('Save Changes'); 38 + $cancel_uri = $this->getApplicationURI('view/'.$id.'/'); 39 + } 40 + 41 + $e_name = true; 42 + $v_name = $badge->getName(); 43 + 44 + $v_icon = $badge->getIcon(); 45 + 46 + $v_flav = $badge->getFlavor(); 47 + $v_desc = $badge->getDescription(); 48 + $v_qual = $badge->getQuality(); 49 + $v_stat = $badge->getStatus(); 50 + 51 + $v_edit = $badge->getEditPolicy(); 52 + $v_view = $badge->getViewPolicy(); 53 + 54 + $validation_exception = null; 55 + if ($request->isFormPost()) { 56 + $v_name = $request->getStr('name'); 57 + $v_flav = $request->getStr('flavor'); 58 + $v_desc = $request->getStr('description'); 59 + $v_icon = $request->getStr('icon'); 60 + $v_stat = $request->getStr('status'); 61 + $v_qual = $request->getStr('quality'); 62 + 63 + $v_view = $request->getStr('viewPolicy'); 64 + $v_edit = $request->getStr('editPolicy'); 65 + 66 + $type_name = PhabricatorBadgesTransaction::TYPE_NAME; 67 + $type_flav = PhabricatorBadgesTransaction::TYPE_FLAVOR; 68 + $type_desc = PhabricatorBadgesTransaction::TYPE_DESCRIPTION; 69 + $type_icon = PhabricatorBadgesTransaction::TYPE_ICON; 70 + $type_qual = PhabricatorBadgesTransaction::TYPE_QUALITY; 71 + $type_stat = PhabricatorBadgesTransaction::TYPE_STATUS; 72 + 73 + $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY; 74 + $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; 75 + 76 + $xactions = array(); 77 + 78 + $xactions[] = id(new PhabricatorBadgesTransaction()) 79 + ->setTransactionType($type_name) 80 + ->setNewValue($v_name); 81 + 82 + $xactions[] = id(new PhabricatorBadgesTransaction()) 83 + ->setTransactionType($type_flav) 84 + ->setNewValue($v_flav); 85 + 86 + $xactions[] = id(new PhabricatorBadgesTransaction()) 87 + ->setTransactionType($type_desc) 88 + ->setNewValue($v_desc); 89 + 90 + $xactions[] = id(new PhabricatorBadgesTransaction()) 91 + ->setTransactionType($type_icon) 92 + ->setNewValue($v_icon); 93 + 94 + $xactions[] = id(new PhabricatorBadgesTransaction()) 95 + ->setTransactionType($type_qual) 96 + ->setNewValue($v_qual); 97 + 98 + $xactions[] = id(new PhabricatorBadgesTransaction()) 99 + ->setTransactionType($type_stat) 100 + ->setNewValue($v_stat); 101 + 102 + $xactions[] = id(new PhabricatorBadgesTransaction()) 103 + ->setTransactionType($type_view) 104 + ->setNewValue($v_view); 105 + 106 + $xactions[] = id(new PhabricatorBadgesTransaction()) 107 + ->setTransactionType($type_edit) 108 + ->setNewValue($v_edit); 109 + 110 + $editor = id(new PhabricatorBadgesEditor()) 111 + ->setActor($viewer) 112 + ->setContentSourceFromRequest($request) 113 + ->setContinueOnNoEffect(true); 114 + 115 + try { 116 + $editor->applyTransactions($badge, $xactions); 117 + $return_uri = $this->getApplicationURI('view/'.$badge->getID().'/'); 118 + return id(new AphrontRedirectResponse())->setURI($return_uri); 119 + 120 + } catch (PhabricatorApplicationTransactionValidationException $ex) { 121 + $validation_exception = $ex; 122 + 123 + $e_name = $ex->getShortMessage($type_name); 124 + } 125 + } 126 + 127 + if ($is_new) { 128 + $icon_uri = $this->getApplicationURI('icon/'); 129 + } else { 130 + $icon_uri = $this->getApplicationURI('icon/'.$badge->getID().'/'); 131 + } 132 + $icon_display = PhabricatorBadgesIcon::renderIconForChooser($v_icon); 133 + 134 + $policies = id(new PhabricatorPolicyQuery()) 135 + ->setViewer($viewer) 136 + ->setObject($badge) 137 + ->execute(); 138 + 139 + $form = id(new AphrontFormView()) 140 + ->setUser($viewer) 141 + ->appendChild( 142 + id(new AphrontFormTextControl()) 143 + ->setName('name') 144 + ->setLabel(pht('Name')) 145 + ->setValue($v_name) 146 + ->setError($e_name)) 147 + ->appendChild( 148 + id(new AphrontFormTextControl()) 149 + ->setName('flavor') 150 + ->setLabel(pht('Flavor Text')) 151 + ->setValue($v_flav)) 152 + ->appendChild( 153 + id(new AphrontFormChooseButtonControl()) 154 + ->setLabel(pht('Icon')) 155 + ->setName('icon') 156 + ->setDisplayValue($icon_display) 157 + ->setButtonText(pht('Choose Icon...')) 158 + ->setChooseURI($icon_uri) 159 + ->setValue($v_icon)) 160 + ->appendChild( 161 + id(new AphrontFormSelectControl()) 162 + ->setName('quality') 163 + ->setLabel(pht('Quality')) 164 + ->setValue($v_qual) 165 + ->setOptions($badge->getQualityNameMap())) 166 + ->appendChild( 167 + id(new AphrontFormSelectControl()) 168 + ->setLabel(pht('Status')) 169 + ->setName('status') 170 + ->setValue($v_stat) 171 + ->setOptions($badge->getStatusNameMap())) 172 + ->appendChild( 173 + id(new PhabricatorRemarkupControl()) 174 + ->setUser($viewer) 175 + ->setName('description') 176 + ->setLabel(pht('Description')) 177 + ->setValue($v_desc)) 178 + ->appendChild( 179 + id(new AphrontFormPolicyControl()) 180 + ->setName('viewPolicy') 181 + ->setPolicyObject($badge) 182 + ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) 183 + ->setValue($v_view) 184 + ->setPolicies($policies)) 185 + ->appendChild( 186 + id(new AphrontFormPolicyControl()) 187 + ->setName('editPolicy') 188 + ->setPolicyObject($badge) 189 + ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) 190 + ->setValue($v_edit) 191 + ->setPolicies($policies)) 192 + ->appendChild( 193 + id(new AphrontFormSubmitControl()) 194 + ->setValue($button_text) 195 + ->addCancelButton($cancel_uri)); 196 + 197 + $crumbs = $this->buildApplicationCrumbs(); 198 + if ($is_new) { 199 + $crumbs->addTextCrumb(pht('Create Badge')); 200 + } else { 201 + $crumbs->addTextCrumb( 202 + $badge->getName(), 203 + '/badges/view/'.$badge->getID().'/'); 204 + $crumbs->addTextCrumb(pht('Edit')); 205 + } 206 + 207 + $box = id(new PHUIObjectBoxView()) 208 + ->setValidationException($validation_exception) 209 + ->setHeaderText($title) 210 + ->appendChild($form); 211 + 212 + return $this->buildApplicationPage( 213 + array( 214 + $crumbs, 215 + $box, 216 + ), 217 + array( 218 + 'title' => $title, 219 + )); 220 + } 221 + 222 + }
+101
src/applications/badges/controller/PhabricatorBadgesEditIconController.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesEditIconController 4 + extends PhabricatorBadgesController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $request->getViewer(); 8 + $id = $request->getURIData('id'); 9 + 10 + if ($id) { 11 + $badge = id(new PhabricatorBadgesQuery()) 12 + ->setViewer($viewer) 13 + ->withIDs(array($id)) 14 + ->requireCapabilities( 15 + array( 16 + PhabricatorPolicyCapability::CAN_VIEW, 17 + PhabricatorPolicyCapability::CAN_EDIT, 18 + )) 19 + ->executeOne(); 20 + if (!$badge) { 21 + return new Aphront404Response(); 22 + } 23 + $cancel_uri = 24 + $this->getApplicationURI('view/'.$badge->getID().'/'); 25 + $badge_icon = $badge->getIcon(); 26 + } else { 27 + $this->requireApplicationCapability( 28 + PhabricatorBadgesCreateCapability::CAPABILITY); 29 + 30 + $cancel_uri = '/badges/'; 31 + $badge_icon = $request->getStr('value'); 32 + } 33 + 34 + require_celerity_resource('project-icon-css'); 35 + Javelin::initBehavior('phabricator-tooltips'); 36 + 37 + $badge_icons = PhabricatorBadgesIcon::getIconMap(); 38 + 39 + if ($request->isFormPost()) { 40 + $v_icon = $request->getStr('icon'); 41 + 42 + return id(new AphrontAjaxResponse())->setContent( 43 + array( 44 + 'value' => $v_icon, 45 + 'display' => PhabricatorBadgesIcon::renderIconForChooser($v_icon), 46 + )); 47 + } 48 + 49 + $ii = 0; 50 + $buttons = array(); 51 + foreach ($badge_icons as $icon => $label) { 52 + $view = id(new PHUIIconView()) 53 + ->setIconFont($icon); 54 + 55 + $aural = javelin_tag( 56 + 'span', 57 + array( 58 + 'aural' => true, 59 + ), 60 + pht('Choose "%s" Icon', $label)); 61 + 62 + if ($icon == $badge_icon) { 63 + $class_extra = ' selected'; 64 + } else { 65 + $class_extra = null; 66 + } 67 + 68 + $buttons[] = javelin_tag( 69 + 'button', 70 + array( 71 + 'class' => 'icon-button'.$class_extra, 72 + 'name' => 'icon', 73 + 'value' => $icon, 74 + 'type' => 'submit', 75 + 'sigil' => 'has-tooltip', 76 + 'meta' => array( 77 + 'tip' => $label, 78 + ), 79 + ), 80 + array( 81 + $aural, 82 + $view, 83 + )); 84 + if ((++$ii % 4) == 0) { 85 + $buttons[] = phutil_tag('br'); 86 + } 87 + } 88 + 89 + $buttons = phutil_tag( 90 + 'div', 91 + array( 92 + 'class' => 'icon-grid', 93 + ), 94 + $buttons); 95 + 96 + return $this->newDialog() 97 + ->setTitle(pht('Choose Badge Icon')) 98 + ->appendChild($buttons) 99 + ->addCancelButton($cancel_uri); 100 + } 101 + }
+120
src/applications/badges/controller/PhabricatorBadgesEditRecipientsController.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesEditRecipientsController 4 + extends PhabricatorBadgesController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $request->getViewer(); 8 + $id = $request->getURIData('id'); 9 + 10 + $badge = id(new PhabricatorBadgesQuery()) 11 + ->setViewer($viewer) 12 + ->withIDs(array($id)) 13 + ->needRecipients(true) 14 + ->requireCapabilities( 15 + array( 16 + PhabricatorPolicyCapability::CAN_EDIT, 17 + PhabricatorPolicyCapability::CAN_VIEW, 18 + )) 19 + ->executeOne(); 20 + if (!$badge) { 21 + return new Aphront404Response(); 22 + } 23 + 24 + $recipient_phids = $badge->getRecipientPHIDs(); 25 + 26 + if ($request->isFormPost()) { 27 + $recipient_spec = array(); 28 + 29 + $remove = $request->getStr('remove'); 30 + if ($remove) { 31 + $recipient_spec['-'] = array_fuse(array($remove)); 32 + } 33 + 34 + $add_recipients = $request->getArr('phids'); 35 + if ($add_recipients) { 36 + $recipient_spec['+'] = array_fuse($add_recipients); 37 + } 38 + 39 + $type_recipient = PhabricatorBadgeHasRecipientEdgeType::EDGECONST; 40 + 41 + $xactions = array(); 42 + 43 + $xactions[] = id(new PhabricatorBadgesTransaction()) 44 + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 45 + ->setMetadataValue('edge:type', $type_recipient) 46 + ->setNewValue($recipient_spec); 47 + 48 + $editor = id(new PhabricatorBadgesEditor($badge)) 49 + ->setActor($viewer) 50 + ->setContentSourceFromRequest($request) 51 + ->setContinueOnNoEffect(true) 52 + ->setContinueOnMissingFields(true) 53 + ->applyTransactions($badge, $xactions); 54 + 55 + return id(new AphrontRedirectResponse()) 56 + ->setURI($request->getRequestURI()); 57 + } 58 + 59 + $recipient_phids = array_reverse($recipient_phids); 60 + $handles = $this->loadViewerHandles($recipient_phids); 61 + 62 + $state = array(); 63 + foreach ($handles as $handle) { 64 + $state[] = array( 65 + 'phid' => $handle->getPHID(), 66 + 'name' => $handle->getFullName(), 67 + ); 68 + } 69 + 70 + $can_edit = PhabricatorPolicyFilter::hasCapability( 71 + $viewer, 72 + $badge, 73 + PhabricatorPolicyCapability::CAN_EDIT); 74 + 75 + $form_box = null; 76 + $title = pht('Add Recipient'); 77 + if ($can_edit) { 78 + $header_name = pht('Edit Recipients'); 79 + $view_uri = $this->getApplicationURI('view/'.$badge->getID().'/'); 80 + 81 + $form = new AphrontFormView(); 82 + $form 83 + ->setUser($viewer) 84 + ->appendControl( 85 + id(new AphrontFormTokenizerControl()) 86 + ->setName('phids') 87 + ->setLabel(pht('Add Recipients')) 88 + ->setDatasource(new PhabricatorPeopleDatasource())) 89 + ->appendChild( 90 + id(new AphrontFormSubmitControl()) 91 + ->addCancelButton($view_uri) 92 + ->setValue(pht('Add Recipients'))); 93 + $form_box = id(new PHUIObjectBoxView()) 94 + ->setHeaderText($title) 95 + ->setForm($form); 96 + } 97 + 98 + $recipient_list = id(new PhabricatorBadgesRecipientsListView()) 99 + ->setBadge($badge) 100 + ->setHandles($handles) 101 + ->setUser($viewer); 102 + 103 + $badge_url = $this->getApplicationURI('view/'.$id.'/'); 104 + 105 + $crumbs = $this->buildApplicationCrumbs(); 106 + $crumbs->addTextCrumb($badge->getName(), $badge_url); 107 + $crumbs->addTextCrumb(pht('Recipients')); 108 + 109 + return $this->buildApplicationPage( 110 + array( 111 + $crumbs, 112 + $form_box, 113 + $recipient_list, 114 + ), 115 + array( 116 + 'title' => $title, 117 + )); 118 + } 119 + 120 + }
+52
src/applications/badges/controller/PhabricatorBadgesListController.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesListController 4 + extends PhabricatorBadgesController { 5 + 6 + public function shouldAllowPublic() { 7 + return true; 8 + } 9 + 10 + public function handleRequest(AphrontRequest $request) { 11 + $query_key = $request->getURIData('queryKey'); 12 + $controller = id(new PhabricatorApplicationSearchController()) 13 + ->setQueryKey($query_key) 14 + ->setSearchEngine(new PhabricatorBadgesSearchEngine()) 15 + ->setNavigation($this->buildSideNavView()); 16 + 17 + return $this->delegateToController($controller); 18 + } 19 + 20 + public function buildSideNavView() { 21 + $user = $this->getRequest()->getUser(); 22 + 23 + $nav = new AphrontSideNavFilterView(); 24 + $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); 25 + 26 + id(new PhabricatorBadgesSearchEngine()) 27 + ->setViewer($user) 28 + ->addNavigationItems($nav->getMenu()); 29 + 30 + $nav->selectFilter(null); 31 + 32 + return $nav; 33 + } 34 + 35 + protected function buildApplicationCrumbs() { 36 + $crumbs = parent::buildApplicationCrumbs(); 37 + 38 + $can_create = $this->hasApplicationCapability( 39 + PhabricatorBadgesCreateCapability::CAPABILITY); 40 + 41 + $crumbs->addAction( 42 + id(new PHUIListItemView()) 43 + ->setName(pht('Create Badge')) 44 + ->setHref($this->getApplicationURI('create/')) 45 + ->setIcon('fa-plus-square') 46 + ->setDisabled(!$can_create) 47 + ->setWorkflow(!$can_create)); 48 + 49 + return $crumbs; 50 + } 51 + 52 + }
+77
src/applications/badges/controller/PhabricatorBadgesRemoveRecipientsController.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesRemoveRecipientsController 4 + extends PhabricatorBadgesController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $request->getViewer(); 8 + $id = $request->getURIData('id'); 9 + 10 + $badge = id(new PhabricatorBadgesQuery()) 11 + ->setViewer($viewer) 12 + ->withIDs(array($id)) 13 + ->needRecipients(true) 14 + ->requireCapabilities( 15 + array( 16 + PhabricatorPolicyCapability::CAN_VIEW, 17 + PhabricatorPolicyCapability::CAN_EDIT, 18 + )) 19 + ->executeOne(); 20 + if (!$badge) { 21 + return new Aphront404Response(); 22 + } 23 + 24 + $recipient_phids = $badge->getRecipientPHIDs(); 25 + $remove_phid = $request->getStr('phid'); 26 + 27 + if (!in_array($remove_phid, $recipient_phids)) { 28 + return new Aphront404Response(); 29 + } 30 + 31 + $recipients_uri = 32 + $this->getApplicationURI('recipients/'.$badge->getID().'/'); 33 + 34 + if ($request->isFormPost()) { 35 + $recipient_spec = array(); 36 + $recipient_spec['-'] = array($remove_phid => $remove_phid); 37 + 38 + $type_recipient = PhabricatorBadgeHasRecipientEdgeType::EDGECONST; 39 + 40 + $xactions = array(); 41 + 42 + $xactions[] = id(new PhabricatorBadgesTransaction()) 43 + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 44 + ->setMetadataValue('edge:type', $type_recipient) 45 + ->setNewValue($recipient_spec); 46 + 47 + $editor = id(new PhabricatorBadgesEditor($badge)) 48 + ->setActor($viewer) 49 + ->setContentSourceFromRequest($request) 50 + ->setContinueOnNoEffect(true) 51 + ->setContinueOnMissingFields(true) 52 + ->applyTransactions($badge, $xactions); 53 + 54 + return id(new AphrontRedirectResponse()) 55 + ->setURI($recipients_uri); 56 + } 57 + 58 + $handle = id(new PhabricatorHandleQuery()) 59 + ->setViewer($viewer) 60 + ->withPHIDs(array($remove_phid)) 61 + ->executeOne(); 62 + 63 + $dialog = id(new AphrontDialogView()) 64 + ->setUser($viewer) 65 + ->setTitle(pht('Really Revoke Badge?')) 66 + ->appendParagraph( 67 + pht( 68 + 'Really revoke the badge "%s" from %s?', 69 + phutil_tag('strong', array(), $badge->getName()), 70 + phutil_tag('strong', array(), $handle->getName()))) 71 + ->addCancelButton($recipients_uri) 72 + ->addSubmitButton(pht('Revoke Badge')); 73 + 74 + return $dialog; 75 + } 76 + 77 + }
+157
src/applications/badges/controller/PhabricatorBadgesViewController.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesViewController 4 + extends PhabricatorBadgesController { 5 + 6 + public function shouldAllowPublic() { 7 + return true; 8 + } 9 + 10 + public function handleRequest(AphrontRequest $request) { 11 + $viewer = $request->getViewer(); 12 + $id = $request->getURIData('id'); 13 + 14 + $badge = id(new PhabricatorBadgesQuery()) 15 + ->setViewer($viewer) 16 + ->withIDs(array($id)) 17 + ->needRecipients(true) 18 + ->executeOne(); 19 + if (!$badge) { 20 + return new Aphront404Response(); 21 + } 22 + 23 + $crumbs = $this->buildApplicationCrumbs(); 24 + $crumbs->addTextCrumb($badge->getName()); 25 + $title = $badge->getName(); 26 + 27 + if ($badge->isClosed()) { 28 + $status_icon = 'fa-ban'; 29 + $status_color = 'dark'; 30 + } else { 31 + $status_icon = 'fa-check'; 32 + $status_color = 'bluegrey'; 33 + } 34 + $status_name = idx( 35 + PhabricatorBadgesBadge::getStatusNameMap(), 36 + $badge->getStatus()); 37 + 38 + $header = id(new PHUIHeaderView()) 39 + ->setHeader($badge->getName()) 40 + ->setUser($viewer) 41 + ->setPolicyObject($badge) 42 + ->setStatus($status_icon, $status_color, $status_name); 43 + 44 + $properties = $this->buildPropertyListView($badge); 45 + $actions = $this->buildActionListView($badge); 46 + $properties->setActionList($actions); 47 + 48 + $box = id(new PHUIObjectBoxView()) 49 + ->setHeader($header) 50 + ->addPropertyList($properties); 51 + 52 + $timeline = $this->buildTransactionTimeline( 53 + $badge, 54 + new PhabricatorBadgesTransactionQuery()); 55 + $timeline 56 + ->setShouldTerminate(true); 57 + 58 + $recipient_phids = $badge->getRecipientPHIDs(); 59 + $recipient_phids = array_reverse($recipient_phids); 60 + $handles = $this->loadViewerHandles($recipient_phids); 61 + 62 + $recipient_list = id(new PhabricatorBadgesRecipientsListView()) 63 + ->setBadge($badge) 64 + ->setHandles($handles) 65 + ->setUser($viewer); 66 + 67 + return $this->buildApplicationPage( 68 + array( 69 + $crumbs, 70 + $box, 71 + $recipient_list, 72 + $timeline, 73 + ), 74 + array( 75 + 'title' => $title, 76 + 'pageObjects' => array($badge->getPHID()), 77 + )); 78 + } 79 + 80 + private function buildPropertyListView(PhabricatorBadgesBadge $badge) { 81 + $viewer = $this->getViewer(); 82 + 83 + $view = id(new PHUIPropertyListView()) 84 + ->setUser($viewer) 85 + ->setObject($badge); 86 + 87 + $quality = idx($badge->getQualityNameMap(), $badge->getQuality()); 88 + $icon = idx($badge->getIconNameMap(), $badge->getIcon()); 89 + 90 + $view->addProperty( 91 + pht('Quality'), 92 + $quality); 93 + 94 + $view->addProperty( 95 + pht('Icon'), 96 + $icon); 97 + 98 + $view->addProperty( 99 + pht('Flavor'), 100 + $badge->getFlavor()); 101 + 102 + $view->invokeWillRenderEvent(); 103 + 104 + $description = $badge->getDescription(); 105 + if (strlen($description)) { 106 + $description = PhabricatorMarkupEngine::renderOneObject( 107 + id(new PhabricatorMarkupOneOff())->setContent($description), 108 + 'default', 109 + $viewer); 110 + 111 + $view->addSectionHeader(pht('Description')); 112 + $view->addTextContent($description); 113 + } 114 + 115 + $badge = id(new PHUIBadgeView()) 116 + ->setIcon($badge->getIcon()) 117 + ->setHeader($badge->getName()) 118 + ->setSubhead($badge->getFlavor()) 119 + ->setQuality($badge->getQuality()); 120 + 121 + $view->addTextContent($badge); 122 + 123 + return $view; 124 + } 125 + 126 + private function buildActionListView(PhabricatorBadgesBadge $badge) { 127 + $viewer = $this->getViewer(); 128 + $id = $badge->getID(); 129 + 130 + $can_edit = PhabricatorPolicyFilter::hasCapability( 131 + $viewer, 132 + $badge, 133 + PhabricatorPolicyCapability::CAN_EDIT); 134 + 135 + $view = id(new PhabricatorActionListView()) 136 + ->setUser($viewer) 137 + ->setObject($badge); 138 + 139 + $view->addAction( 140 + id(new PhabricatorActionView()) 141 + ->setName(pht('Edit Badge')) 142 + ->setIcon('fa-pencil') 143 + ->setDisabled(!$can_edit) 144 + ->setWorkflow(!$can_edit) 145 + ->setHref($this->getApplicationURI("/edit/{$id}/"))); 146 + 147 + $view->addAction( 148 + id(new PhabricatorActionView()) 149 + ->setName('Manage Recipients') 150 + ->setIcon('fa-users') 151 + ->setDisabled(!$can_edit) 152 + ->setHref($this->getApplicationURI("/recipients/{$id}/"))); 153 + 154 + return $view; 155 + } 156 + 157 + }
+103
src/applications/badges/edge/PhabricatorBadgeHasRecipientEdgeType.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgeHasRecipientEdgeType 4 + extends PhabricatorEdgeType { 5 + 6 + const EDGECONST = 59; 7 + 8 + public function getInverseEdgeConstant() { 9 + return PhabricatorRecipientHasBadgeEdgeType::EDGECONST; 10 + } 11 + 12 + public function shouldWriteInverseTransactions() { 13 + return true; 14 + } 15 + 16 + public function getTransactionAddString( 17 + $actor, 18 + $add_count, 19 + $add_edges) { 20 + 21 + return pht( 22 + '%s awarded %s recipients(s): %s.', 23 + $actor, 24 + $add_count, 25 + $add_edges); 26 + } 27 + 28 + public function getTransactionRemoveString( 29 + $actor, 30 + $rem_count, 31 + $rem_edges) { 32 + 33 + return pht( 34 + '%s revoked %s recipients(s): %s.', 35 + $actor, 36 + $rem_count, 37 + $rem_edges); 38 + } 39 + 40 + public function getTransactionEditString( 41 + $actor, 42 + $total_count, 43 + $add_count, 44 + $add_edges, 45 + $rem_count, 46 + $rem_edges) { 47 + 48 + return pht( 49 + '%s edited recipient(s), awarded %s: %s; revoked %s: %s.', 50 + $actor, 51 + $add_count, 52 + $add_edges, 53 + $rem_count, 54 + $rem_edges); 55 + } 56 + 57 + public function getFeedAddString( 58 + $actor, 59 + $object, 60 + $add_count, 61 + $add_edges) { 62 + 63 + return pht( 64 + '%s awarded %s recipient(s) for %s: %s.', 65 + $actor, 66 + $add_count, 67 + $object, 68 + $add_edges); 69 + } 70 + 71 + public function getFeedRemoveString( 72 + $actor, 73 + $object, 74 + $rem_count, 75 + $rem_edges) { 76 + 77 + return pht( 78 + '%s revoked %s recipient(s) for %s: %s.', 79 + $actor, 80 + $rem_count, 81 + $object, 82 + $rem_edges); 83 + } 84 + 85 + public function getFeedEditString( 86 + $actor, 87 + $object, 88 + $total_count, 89 + $add_count, 90 + $add_edges, 91 + $rem_count, 92 + $rem_edges) { 93 + 94 + return pht( 95 + '%s edited recipient(s) for %s, awarded %s: %s; revoked %s: %s.', 96 + $actor, 97 + $object, 98 + $add_count, 99 + $add_edges, 100 + $rem_count, 101 + $rem_edges); 102 + } 103 + }
+103
src/applications/badges/edge/PhabricatorRecipientHasBadgeEdgeType.php
··· 1 + <?php 2 + 3 + final class PhabricatorRecipientHasBadgeEdgeType 4 + extends PhabricatorEdgeType { 5 + 6 + const EDGECONST = 58; 7 + 8 + public function getInverseEdgeConstant() { 9 + return PhabricatorBadgeHasRecipientEdgeType::EDGECONST; 10 + } 11 + 12 + public function shouldWriteInverseTransactions() { 13 + return true; 14 + } 15 + 16 + public function getTransactionAddString( 17 + $actor, 18 + $add_count, 19 + $add_edges) { 20 + 21 + return pht( 22 + '%s added %s badge(s): %s.', 23 + $actor, 24 + $add_count, 25 + $add_edges); 26 + } 27 + 28 + public function getTransactionRemoveString( 29 + $actor, 30 + $rem_count, 31 + $rem_edges) { 32 + 33 + return pht( 34 + '%s revoked %s badge(s): %s.', 35 + $actor, 36 + $rem_count, 37 + $rem_edges); 38 + } 39 + 40 + public function getTransactionEditString( 41 + $actor, 42 + $total_count, 43 + $add_count, 44 + $add_edges, 45 + $rem_count, 46 + $rem_edges) { 47 + 48 + return pht( 49 + '%s edited badge(s), added %s: %s; revoked %s: %s.', 50 + $actor, 51 + $add_count, 52 + $add_edges, 53 + $rem_count, 54 + $rem_edges); 55 + } 56 + 57 + public function getFeedAddString( 58 + $actor, 59 + $object, 60 + $add_count, 61 + $add_edges) { 62 + 63 + return pht( 64 + '%s added %s badge(s) for %s: %s.', 65 + $actor, 66 + $add_count, 67 + $object, 68 + $add_edges); 69 + } 70 + 71 + public function getFeedRemoveString( 72 + $actor, 73 + $object, 74 + $rem_count, 75 + $rem_edges) { 76 + 77 + return pht( 78 + '%s revoked %s badge(s) for %s: %s.', 79 + $actor, 80 + $rem_count, 81 + $object, 82 + $rem_edges); 83 + } 84 + 85 + public function getFeedEditString( 86 + $actor, 87 + $object, 88 + $total_count, 89 + $add_count, 90 + $add_edges, 91 + $rem_count, 92 + $rem_edges) { 93 + 94 + return pht( 95 + '%s edited badge(s) for %s, added %s: %s; revoked %s: %s.', 96 + $actor, 97 + $object, 98 + $add_count, 99 + $add_edges, 100 + $rem_count, 101 + $rem_edges); 102 + } 103 + }
+194
src/applications/badges/editor/PhabricatorBadgesEditor.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesEditor 4 + extends PhabricatorApplicationTransactionEditor { 5 + 6 + public function getEditorApplicationClass() { 7 + return 'PhabricatorBadgesApplication'; 8 + } 9 + 10 + public function getEditorObjectsDescription() { 11 + return pht('Badges'); 12 + } 13 + 14 + public function getTransactionTypes() { 15 + $types = parent::getTransactionTypes(); 16 + 17 + $types[] = PhabricatorBadgesTransaction::TYPE_NAME; 18 + $types[] = PhabricatorBadgesTransaction::TYPE_FLAVOR; 19 + $types[] = PhabricatorBadgesTransaction::TYPE_DESCRIPTION; 20 + $types[] = PhabricatorBadgesTransaction::TYPE_ICON; 21 + $types[] = PhabricatorBadgesTransaction::TYPE_STATUS; 22 + $types[] = PhabricatorBadgesTransaction::TYPE_QUALITY; 23 + 24 + $types[] = PhabricatorTransactions::TYPE_EDGE; 25 + $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; 26 + $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; 27 + 28 + return $types; 29 + } 30 + 31 + protected function getCustomTransactionOldValue( 32 + PhabricatorLiskDAO $object, 33 + PhabricatorApplicationTransaction $xaction) { 34 + switch ($xaction->getTransactionType()) { 35 + case PhabricatorBadgesTransaction::TYPE_NAME: 36 + return $object->getName(); 37 + case PhabricatorBadgesTransaction::TYPE_FLAVOR: 38 + return $object->getFlavor(); 39 + case PhabricatorBadgesTransaction::TYPE_DESCRIPTION: 40 + return $object->getDescription(); 41 + case PhabricatorBadgesTransaction::TYPE_ICON: 42 + return $object->getIcon(); 43 + case PhabricatorBadgesTransaction::TYPE_QUALITY: 44 + return $object->getQuality(); 45 + case PhabricatorBadgesTransaction::TYPE_STATUS: 46 + return $object->getStatus(); 47 + } 48 + 49 + return parent::getCustomTransactionOldValue($object, $xaction); 50 + } 51 + 52 + protected function getCustomTransactionNewValue( 53 + PhabricatorLiskDAO $object, 54 + PhabricatorApplicationTransaction $xaction) { 55 + 56 + switch ($xaction->getTransactionType()) { 57 + case PhabricatorBadgesTransaction::TYPE_NAME: 58 + case PhabricatorBadgesTransaction::TYPE_FLAVOR: 59 + case PhabricatorBadgesTransaction::TYPE_DESCRIPTION: 60 + case PhabricatorBadgesTransaction::TYPE_ICON: 61 + case PhabricatorBadgesTransaction::TYPE_STATUS: 62 + case PhabricatorBadgesTransaction::TYPE_QUALITY: 63 + return $xaction->getNewValue(); 64 + } 65 + 66 + return parent::getCustomTransactionNewValue($object, $xaction); 67 + } 68 + 69 + protected function applyCustomInternalTransaction( 70 + PhabricatorLiskDAO $object, 71 + PhabricatorApplicationTransaction $xaction) { 72 + 73 + $type = $xaction->getTransactionType(); 74 + switch ($type) { 75 + case PhabricatorBadgesTransaction::TYPE_NAME: 76 + $object->setName($xaction->getNewValue()); 77 + return; 78 + case PhabricatorBadgesTransaction::TYPE_FLAVOR: 79 + $object->setFlavor($xaction->getNewValue()); 80 + return; 81 + case PhabricatorBadgesTransaction::TYPE_DESCRIPTION: 82 + $object->setDescription($xaction->getNewValue()); 83 + return; 84 + case PhabricatorBadgesTransaction::TYPE_ICON: 85 + $object->setIcon($xaction->getNewValue()); 86 + return; 87 + case PhabricatorBadgesTransaction::TYPE_QUALITY: 88 + $object->setQuality($xaction->getNewValue()); 89 + return; 90 + case PhabricatorBadgesTransaction::TYPE_STATUS: 91 + $object->setStatus($xaction->getNewValue()); 92 + return; 93 + } 94 + 95 + return parent::applyCustomInternalTransaction($object, $xaction); 96 + } 97 + 98 + protected function applyCustomExternalTransaction( 99 + PhabricatorLiskDAO $object, 100 + PhabricatorApplicationTransaction $xaction) { 101 + 102 + $type = $xaction->getTransactionType(); 103 + switch ($type) { 104 + case PhabricatorBadgesTransaction::TYPE_NAME: 105 + case PhabricatorBadgesTransaction::TYPE_FLAVOR: 106 + case PhabricatorBadgesTransaction::TYPE_DESCRIPTION: 107 + case PhabricatorBadgesTransaction::TYPE_ICON: 108 + case PhabricatorBadgesTransaction::TYPE_STATUS: 109 + case PhabricatorBadgesTransaction::TYPE_QUALITY: 110 + return; 111 + } 112 + 113 + return parent::applyCustomExternalTransaction($object, $xaction); 114 + } 115 + 116 + protected function validateTransaction( 117 + PhabricatorLiskDAO $object, 118 + $type, 119 + array $xactions) { 120 + 121 + $errors = parent::validateTransaction($object, $type, $xactions); 122 + 123 + switch ($type) { 124 + case PhabricatorBadgesTransaction::TYPE_NAME: 125 + $missing = $this->validateIsEmptyTextField( 126 + $object->getName(), 127 + $xactions); 128 + 129 + if ($missing) { 130 + $error = new PhabricatorApplicationTransactionValidationError( 131 + $type, 132 + pht('Required'), 133 + pht('Badge name is required.'), 134 + nonempty(last($xactions), null)); 135 + 136 + $error->setIsMissingFieldError(true); 137 + $errors[] = $error; 138 + } 139 + break; 140 + } 141 + 142 + return $errors; 143 + } 144 + 145 + protected function shouldPublishFeedStory( 146 + PhabricatorLiskDAO $object, 147 + array $xactions) { 148 + return true; 149 + } 150 + 151 + protected function buildReplyHandler(PhabricatorLiskDAO $object) { 152 + return id(new PhabricatorMacroReplyHandler()) 153 + ->setMailReceiver($object); 154 + } 155 + 156 + protected function buildMailTemplate(PhabricatorLiskDAO $object) { 157 + $name = $object->getName(); 158 + $id = $object->getID(); 159 + $name = pht('Badge %d', $id); 160 + return id(new PhabricatorMetaMTAMail()) 161 + ->setSubject($name) 162 + ->addHeader('Thread-Topic', $name); 163 + } 164 + 165 + protected function getMailTo(PhabricatorLiskDAO $object) { 166 + return array( 167 + $this->requireActor()->getPHID(), 168 + ); 169 + } 170 + 171 + protected function buildMailBody( 172 + PhabricatorLiskDAO $object, 173 + array $xactions) { 174 + 175 + $description = $object->getDescription(); 176 + $body = parent::buildMailBody($object, $xactions); 177 + 178 + if (strlen($description)) { 179 + $body->addTextSection( 180 + pht('BADGE DESCRIPTION'), 181 + $object->getDescription()); 182 + } 183 + 184 + $body->addLinkSection( 185 + pht('BADGE DETAIL'), 186 + PhabricatorEnv::getProductionURI('/badge/view/'.$object->getID().'/')); 187 + return $body; 188 + } 189 + 190 + protected function getMailSubjectPrefix() { 191 + return pht('[Badge]'); 192 + } 193 + 194 + }
+53
src/applications/badges/icon/PhabricatorBadgesIcon.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesIcon extends Phobject { 4 + 5 + public static function getIconMap() { 6 + return 7 + array( 8 + 'fa-star' => pht('Superstar'), 9 + 'fa-user' => pht('Average Person'), 10 + 'fa-bug' => pht('Ladybug'), 11 + 'fa-users' => pht('Triplets'), 12 + 13 + 'fa-book' => pht('Nominomicon'), 14 + 'fa-rocket' => pht('Escape Route'), 15 + 'fa-life-ring' => pht('Foam Circle'), 16 + 'fa-birthday-cake' => pht('Cake Day'), 17 + 18 + 'fa-camera-retro' => pht('Leica Enthusiast'), 19 + 'fa-beer' => pht('Liquid Lunch'), 20 + 'fa-gift' => pht('Free Stuff'), 21 + 'fa-eye' => pht('Eye See You'), 22 + 23 + 'fa-heart' => pht('Love is Love'), 24 + 'fa-trophy' => pht('Winner at Things'), 25 + 'fa-umbrella' => pht('Rain Defender'), 26 + 'fa-graduation-cap' => pht('In Debt'), 27 + 28 + ); 29 + } 30 + 31 + public static function getLabel($key) { 32 + $map = self::getIconMap(); 33 + return $map[$key]; 34 + } 35 + 36 + public static function getAPIName($key) { 37 + return substr($key, 3); 38 + } 39 + 40 + public static function renderIconForChooser($icon) { 41 + $badge_icons = self::getIconMap(); 42 + 43 + return phutil_tag( 44 + 'span', 45 + array(), 46 + array( 47 + id(new PHUIIconView())->setIconFont($icon), 48 + ' ', 49 + idx($badge_icons, $icon, pht('Unknown Icon')), 50 + )); 51 + } 52 + 53 + }
+47
src/applications/badges/phid/PhabricatorBadgesPHIDType.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesPHIDType extends PhabricatorPHIDType { 4 + 5 + const TYPECONST = 'BDGE'; 6 + 7 + public function getTypeName() { 8 + return pht('Badge'); 9 + } 10 + 11 + public function newObject() { 12 + return new PhabricatorBadgesBadge(); 13 + } 14 + 15 + public function getPHIDTypeApplicationClass() { 16 + return 'PhabricatorBadgesApplication'; 17 + } 18 + 19 + protected function buildQueryForObjects( 20 + PhabricatorObjectQuery $query, 21 + array $phids) { 22 + 23 + return id(new PhabricatorBadgesQuery()) 24 + ->withPHIDs($phids); 25 + } 26 + 27 + public function loadHandles( 28 + PhabricatorHandleQuery $query, 29 + array $handles, 30 + array $objects) { 31 + 32 + foreach ($handles as $phid => $handle) { 33 + $badge = $objects[$phid]; 34 + 35 + $id = $badge->getID(); 36 + $name = $badge->getName(); 37 + 38 + if ($badge->isClosed()) { 39 + $handle->setStatus(PhabricatorObjectHandle::STATUS_CLOSED); 40 + } 41 + 42 + $handle->setName($name); 43 + $handle->setURI("/badges/view/{$id}/"); 44 + } 45 + } 46 + 47 + }
+113
src/applications/badges/query/PhabricatorBadgesQuery.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesQuery 4 + extends PhabricatorCursorPagedPolicyAwareQuery { 5 + 6 + private $ids; 7 + private $phids; 8 + private $qualities; 9 + private $statuses; 10 + private $recipientPHIDs; 11 + 12 + private $needRecipients; 13 + 14 + public function withIDs(array $ids) { 15 + $this->ids = $ids; 16 + return $this; 17 + } 18 + 19 + public function withPHIDs(array $phids) { 20 + $this->phids = $phids; 21 + return $this; 22 + } 23 + 24 + public function withQualities(array $qualities) { 25 + $this->qualities = $qualities; 26 + return $this; 27 + } 28 + 29 + public function withStatuses(array $statuses) { 30 + $this->statuses = $statuses; 31 + return $this; 32 + } 33 + 34 + public function withRecipientPHIDs(array $recipient_phids) { 35 + $this->recipientPHIDs = $recipient_phids; 36 + return $this; 37 + } 38 + 39 + public function needRecipients($need_recipients) { 40 + $this->needRecipients = $need_recipients; 41 + return $this; 42 + } 43 + 44 + protected function loadPage() { 45 + return $this->loadStandardPage($this->newResultObject()); 46 + } 47 + 48 + public function newResultObject() { 49 + return new PhabricatorBadgesBadge(); 50 + } 51 + 52 + protected function didFilterPage(array $badges) { 53 + 54 + if ($this->needRecipients) { 55 + $edge_query = id(new PhabricatorEdgeQuery()) 56 + ->withSourcePHIDs(mpull($badges, 'getPHID')) 57 + ->withEdgeTypes( 58 + array( 59 + PhabricatorBadgeHasRecipientEdgeType::EDGECONST, 60 + )); 61 + $edge_query->execute(); 62 + 63 + foreach ($badges as $badge) { 64 + $phids = $edge_query->getDestinationPHIDs( 65 + array( 66 + $badge->getPHID(), 67 + )); 68 + $badge->attachRecipientPHIDs($phids); 69 + } 70 + } 71 + 72 + return $badges; 73 + } 74 + 75 + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { 76 + $where = parent::buildWhereClauseParts($conn); 77 + 78 + if ($this->ids !== null) { 79 + $where[] = qsprintf( 80 + $conn, 81 + 'id IN (%Ld)', 82 + $this->ids); 83 + } 84 + 85 + if ($this->phids !== null) { 86 + $where[] = qsprintf( 87 + $conn, 88 + 'phid IN (%Ls)', 89 + $this->phids); 90 + } 91 + 92 + if ($this->qualities !== null) { 93 + $where[] = qsprintf( 94 + $conn, 95 + 'quality IN (%Ls)', 96 + $this->qualities); 97 + } 98 + 99 + if ($this->statuses !== null) { 100 + $where[] = qsprintf( 101 + $conn, 102 + 'status IN (%Ls)', 103 + $this->statuses); 104 + } 105 + 106 + return $where; 107 + } 108 + 109 + public function getQueryApplicationClass() { 110 + return 'PhabricatorBadgesApplication'; 111 + } 112 + 113 + }
+143
src/applications/badges/query/PhabricatorBadgesSearchEngine.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesSearchEngine 4 + extends PhabricatorApplicationSearchEngine { 5 + 6 + public function getResultTypeDescription() { 7 + return pht('Badge'); 8 + } 9 + 10 + public function getApplicationClassName() { 11 + return 'PhabricatorBadgesApplication'; 12 + } 13 + 14 + public function newQuery() { 15 + return new PhabricatorBadgesQuery(); 16 + } 17 + 18 + public function buildSavedQueryFromRequest(AphrontRequest $request) { 19 + $saved = new PhabricatorSavedQuery(); 20 + 21 + $saved->setParameter( 22 + 'statuses', 23 + $this->readListFromRequest($request, 'statuses')); 24 + 25 + $saved->setParameter( 26 + 'qualities', 27 + $this->readListFromRequest($request, 'qualities')); 28 + 29 + return $saved; 30 + } 31 + 32 + protected function buildCustomSearchFields() { 33 + return array( 34 + id(new PhabricatorSearchCheckboxesField()) 35 + ->setKey('qualities') 36 + ->setLabel(pht('Quality')) 37 + ->setOptions( 38 + id(new PhabricatorBadgesBadge()) 39 + ->getQualityNameMap()), 40 + id(new PhabricatorSearchCheckboxesField()) 41 + ->setKey('statuses') 42 + ->setLabel(pht('Status')) 43 + ->setOptions( 44 + id(new PhabricatorBadgesBadge()) 45 + ->getStatusNameMap()), 46 + ); 47 + } 48 + 49 + protected function buildQueryFromParameters(array $map) { 50 + $query = $this->newQuery(); 51 + 52 + if ($map['statuses']) { 53 + $query->withStatuses($map['statuses']); 54 + } 55 + 56 + if ($map['qualities']) { 57 + $query->withQualities($map['qualities']); 58 + } 59 + 60 + return $query; 61 + } 62 + 63 + protected function getURI($path) { 64 + return '/badges/'.$path; 65 + } 66 + 67 + protected function getBuiltinQueryNames() { 68 + $names = array(); 69 + 70 + $names['open'] = pht('Active Badges'); 71 + $names['all'] = pht('All Badges'); 72 + 73 + return $names; 74 + } 75 + 76 + public function buildSavedQueryFromBuiltin($query_key) { 77 + $query = $this->newSavedQuery(); 78 + $query->setQueryKey($query_key); 79 + 80 + switch ($query_key) { 81 + case 'all': 82 + return $query; 83 + case 'open': 84 + return $query->setParameter( 85 + 'statuses', 86 + array( 87 + PhabricatorBadgesBadge::STATUS_OPEN, 88 + )); 89 + } 90 + 91 + return parent::buildSavedQueryFromBuiltin($query_key); 92 + } 93 + 94 + protected function getRequiredHandlePHIDsForResultList( 95 + array $badges, 96 + PhabricatorSavedQuery $query) { 97 + 98 + $phids = array(); 99 + 100 + return $phids; 101 + } 102 + 103 + protected function renderResultList( 104 + array $badges, 105 + PhabricatorSavedQuery $query, 106 + array $handles) { 107 + assert_instances_of($badges, 'PhabricatorBadgesBadge'); 108 + 109 + $viewer = $this->requireViewer(); 110 + 111 + $list = id(new PHUIObjectItemListView()); 112 + foreach ($badges as $badge) { 113 + 114 + $quality = idx($badge->getQualityNameMap(), $badge->getQuality()); 115 + $mini_badge = id(new PHUIBadgeMiniView()) 116 + ->setHeader($badge->getName()) 117 + ->setIcon($badge->getIcon()) 118 + ->setQuality($badge->getQuality()); 119 + 120 + $item = id(new PHUIObjectItemView()) 121 + ->setHeader($badge->getName()) 122 + ->setBadge($mini_badge) 123 + ->setHref('/badges/view/'.$badge->getID().'/') 124 + ->addAttribute($quality) 125 + ->addAttribute($badge->getFlavor()); 126 + 127 + if ($badge->isClosed()) { 128 + $item->setDisabled(true); 129 + $item->addIcon('fa-ban', pht('Archived')); 130 + } 131 + 132 + $list->addItem($item); 133 + } 134 + 135 + $result = new PhabricatorApplicationSearchResultView(); 136 + $result->setObjectList($list); 137 + $result->setNoDataString(pht('No badges found.')); 138 + 139 + return $result; 140 + 141 + } 142 + 143 + }
+10
src/applications/badges/query/PhabricatorBadgesTransactionQuery.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesTransactionQuery 4 + extends PhabricatorApplicationTransactionQuery { 5 + 6 + public function getTemplateApplicationTransaction() { 7 + return new PhabricatorBadgesTransaction(); 8 + } 9 + 10 + }
+197
src/applications/badges/storage/PhabricatorBadgesBadge.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesBadge extends PhabricatorBadgesDAO 4 + implements 5 + PhabricatorPolicyInterface, 6 + PhabricatorApplicationTransactionInterface, 7 + PhabricatorSubscribableInterface, 8 + PhabricatorFlaggableInterface, 9 + PhabricatorDestructibleInterface { 10 + 11 + protected $name; 12 + protected $flavor; 13 + protected $description; 14 + protected $icon; 15 + protected $quality; 16 + protected $viewPolicy; 17 + protected $editPolicy; 18 + protected $status; 19 + protected $creatorPHID; 20 + 21 + private $recipientPHIDs = self::ATTACHABLE; 22 + 23 + const STATUS_OPEN = 'open'; 24 + const STATUS_CLOSED = 'closed'; 25 + 26 + const DEFAULT_ICON = 'fa-star'; 27 + const DEFAULT_QUALITY = 'green'; 28 + 29 + const POOR = 'grey'; 30 + const COMMON = 'white'; 31 + const UNCOMMON = 'green'; 32 + const RARE = 'blue'; 33 + const EPIC = 'indigo'; 34 + const LEGENDARY = 'orange'; 35 + const HEIRLOOM = 'yellow'; 36 + 37 + public static function getStatusNameMap() { 38 + return array( 39 + self::STATUS_OPEN => pht('Active'), 40 + self::STATUS_CLOSED => pht('Archived'), 41 + ); 42 + } 43 + 44 + public static function getQualityNameMap() { 45 + return array( 46 + self::POOR => pht('Poor'), 47 + self::COMMON => pht('Common'), 48 + self::UNCOMMON => pht('Uncommon'), 49 + self::RARE => pht('Rare'), 50 + self::EPIC => pht('Epic'), 51 + self::LEGENDARY => pht('Legendary'), 52 + self::HEIRLOOM => pht('Heirloom'), 53 + ); 54 + } 55 + 56 + public static function getIconNameMap() { 57 + return PhabricatorBadgesIcon::getIconMap(); 58 + } 59 + 60 + public static function initializeNewBadge(PhabricatorUser $actor) { 61 + $app = id(new PhabricatorApplicationQuery()) 62 + ->setViewer($actor) 63 + ->withClasses(array('PhabricatorBadgesApplication')) 64 + ->executeOne(); 65 + 66 + $view_policy = 67 + $app->getPolicy(PhabricatorBadgesDefaultViewCapability::CAPABILITY); 68 + 69 + $edit_policy = 70 + $app->getPolicy(PhabricatorBadgesDefaultEditCapability::CAPABILITY); 71 + 72 + return id(new PhabricatorBadgesBadge()) 73 + ->setIcon(self::DEFAULT_ICON) 74 + ->setQuality(self::DEFAULT_QUALITY) 75 + ->setCreatorPHID($actor->getPHID()) 76 + ->setViewPolicy($view_policy) 77 + ->setEditPolicy($edit_policy) 78 + ->setStatus(self::STATUS_OPEN); 79 + } 80 + 81 + protected function getConfiguration() { 82 + return array( 83 + self::CONFIG_AUX_PHID => true, 84 + self::CONFIG_COLUMN_SCHEMA => array( 85 + 'name' => 'text255', 86 + 'flavor' => 'text255', 87 + 'description' => 'text', 88 + 'icon' => 'text255', 89 + 'quality' => 'text255', 90 + 'status' => 'text32', 91 + ), 92 + self::CONFIG_KEY_SCHEMA => array( 93 + 'key_creator' => array( 94 + 'columns' => array('creatorPHID', 'dateModified'), 95 + ), 96 + ), 97 + ) + parent::getConfiguration(); 98 + } 99 + 100 + public function generatePHID() { 101 + return 102 + PhabricatorPHID::generateNewPHID(PhabricatorBadgesPHIDType::TYPECONST); 103 + } 104 + 105 + public function isClosed() { 106 + return ($this->getStatus() == self::STATUS_CLOSED); 107 + } 108 + 109 + public function attachRecipientPHIDs(array $phids) { 110 + $this->recipientPHIDs = $phids; 111 + return $this; 112 + } 113 + 114 + public function getRecipientPHIDs() { 115 + return $this->assertAttached($this->recipientPHIDs); 116 + } 117 + 118 + 119 + /* -( PhabricatorPolicyInterface )----------------------------------------- */ 120 + 121 + 122 + public function getCapabilities() { 123 + return array( 124 + PhabricatorPolicyCapability::CAN_VIEW, 125 + PhabricatorPolicyCapability::CAN_EDIT, 126 + ); 127 + } 128 + 129 + public function getPolicy($capability) { 130 + switch ($capability) { 131 + case PhabricatorPolicyCapability::CAN_VIEW: 132 + return $this->getViewPolicy(); 133 + case PhabricatorPolicyCapability::CAN_EDIT: 134 + return $this->getEditPolicy(); 135 + } 136 + } 137 + 138 + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 139 + return false; 140 + } 141 + 142 + public function describeAutomaticCapability($capability) { 143 + return null; 144 + } 145 + 146 + 147 + /* -( PhabricatorApplicationTransactionInterface )------------------------- */ 148 + 149 + 150 + public function getApplicationTransactionEditor() { 151 + return new PhabricatorBadgesEditor(); 152 + } 153 + 154 + public function getApplicationTransactionObject() { 155 + return $this; 156 + } 157 + 158 + public function getApplicationTransactionTemplate() { 159 + return new PhabricatorBadgesTransaction(); 160 + } 161 + 162 + public function willRenderTimeline( 163 + PhabricatorApplicationTransactionView $timeline, 164 + AphrontRequest $request) { 165 + 166 + return $timeline; 167 + } 168 + 169 + 170 + /* -( PhabricatorSubscribableInterface )----------------------------------- */ 171 + 172 + 173 + public function isAutomaticallySubscribed($phid) { 174 + return ($this->creatorPHID == $phid); 175 + } 176 + 177 + public function shouldShowSubscribersProperty() { 178 + return true; 179 + } 180 + 181 + public function shouldAllowSubscription($phid) { 182 + return true; 183 + } 184 + 185 + 186 + /* -( PhabricatorDestructibleInterface )----------------------------------- */ 187 + 188 + 189 + public function destroyObjectPermanently( 190 + PhabricatorDestructionEngine $engine) { 191 + 192 + $this->openTransaction(); 193 + $this->delete(); 194 + $this->saveTransaction(); 195 + } 196 + 197 + }
+9
src/applications/badges/storage/PhabricatorBadgesDAO.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorBadgesDAO extends PhabricatorLiskDAO { 4 + 5 + public function getApplicationName() { 6 + return 'badges'; 7 + } 8 + 9 + }
+10
src/applications/badges/storage/PhabricatorBadgesSchemaSpec.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesSchemaSpec 4 + extends PhabricatorConfigSchemaSpec { 5 + 6 + public function buildSchemata() { 7 + $this->buildEdgeSchemata(new PhabricatorBadgesBadge()); 8 + } 9 + 10 + }
+195
src/applications/badges/storage/PhabricatorBadgesTransaction.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesTransaction 4 + extends PhabricatorApplicationTransaction { 5 + 6 + const TYPE_NAME = 'badges:name'; 7 + const TYPE_DESCRIPTION = 'badges:description'; 8 + const TYPE_QUALITY = 'badges:quality'; 9 + const TYPE_ICON = 'badges:icon'; 10 + const TYPE_STATUS = 'badges:status'; 11 + const TYPE_FLAVOR = 'badges:flavor'; 12 + 13 + public function getApplicationName() { 14 + return 'badges'; 15 + } 16 + 17 + public function getApplicationTransactionType() { 18 + return PhabricatorBadgesPHIDType::TYPECONST; 19 + } 20 + 21 + public function getApplicationTransactionCommentObject() { 22 + return null; 23 + } 24 + 25 + public function getTitle() { 26 + $author_phid = $this->getAuthorPHID(); 27 + $object_phid = $this->getObjectPHID(); 28 + 29 + $old = $this->getOldValue(); 30 + $new = $this->getNewValue(); 31 + 32 + $type = $this->getTransactionType(); 33 + switch ($type) { 34 + case self::TYPE_NAME: 35 + if ($old === null) { 36 + return pht( 37 + '%s created this badge.', 38 + $this->renderHandleLink($author_phid)); 39 + } else { 40 + return pht( 41 + '%s renamed this badge from "%s" to "%s".', 42 + $this->renderHandleLink($author_phid), 43 + $old, 44 + $new); 45 + } 46 + break; 47 + case self::TYPE_FLAVOR: 48 + if ($old === null) { 49 + return pht( 50 + '%s set the flavor text for this badge.', 51 + $this->renderHandleLink($author_phid)); 52 + } else { 53 + return pht( 54 + '%s updated the flavor text for this badge.', 55 + $this->renderHandleLink($author_phid)); 56 + } 57 + break; 58 + case self::TYPE_DESCRIPTION: 59 + if ($old === null) { 60 + return pht( 61 + '%s set the description for this badge.', 62 + $this->renderHandleLink($author_phid)); 63 + } else { 64 + return pht( 65 + '%s updated the description for this badge.', 66 + $this->renderHandleLink($author_phid)); 67 + } 68 + break; 69 + case self::TYPE_ICON: 70 + if ($old === null) { 71 + return pht( 72 + '%s set the icon for this badge as "%s".', 73 + $this->renderHandleLink($author_phid), 74 + $new); 75 + } else { 76 + $icon_map = PhabricatorBadgesBadge::getIconNameMap(); 77 + $icon_new = idx($icon_map, $new, $new); 78 + $icon_old = idx($icon_map, $old, $old); 79 + return pht( 80 + '%s updated the icon for this badge from "%s" to "%s".', 81 + $this->renderHandleLink($author_phid), 82 + $icon_old, 83 + $icon_new); 84 + } 85 + break; 86 + case self::TYPE_QUALITY: 87 + if ($old === null) { 88 + return pht( 89 + '%s set the quality for this badge as "%s".', 90 + $this->renderHandleLink($author_phid), 91 + $new); 92 + } else { 93 + $qual_map = PhabricatorBadgesBadge::getQualityNameMap(); 94 + $qual_new = idx($qual_map, $new, $new); 95 + $qual_old = idx($qual_map, $old, $old); 96 + return pht( 97 + '%s updated the quality for this badge from "%s" to "%s".', 98 + $this->renderHandleLink($author_phid), 99 + $qual_old, 100 + $qual_new); 101 + } 102 + break; 103 + } 104 + 105 + return parent::getTitle(); 106 + } 107 + 108 + public function getTitleForFeed() { 109 + $author_phid = $this->getAuthorPHID(); 110 + $object_phid = $this->getObjectPHID(); 111 + 112 + $old = $this->getOldValue(); 113 + $new = $this->getNewValue(); 114 + 115 + $type = $this->getTransactionType(); 116 + switch ($type) { 117 + case self::TYPE_NAME: 118 + if ($old === null) { 119 + return pht( 120 + '%s created %s.', 121 + $this->renderHandleLink($author_phid), 122 + $this->renderHandleLink($object_phid)); 123 + 124 + } else { 125 + return pht( 126 + '%s renamed %s.', 127 + $this->renderHandleLink($author_phid), 128 + $this->renderHandleLink($object_phid)); 129 + } 130 + break; 131 + case self::TYPE_FLAVOR: 132 + return pht( 133 + '%s updated the flavor text for %s.', 134 + $this->renderHandleLink($author_phid), 135 + $this->renderHandleLink($object_phid)); 136 + case self::TYPE_ICON: 137 + return pht( 138 + '%s updated the icon for %s.', 139 + $this->renderHandleLink($author_phid), 140 + $this->renderHandleLink($object_phid)); 141 + case self::TYPE_QUALITY: 142 + return pht( 143 + '%s updated the quality level for %s.', 144 + $this->renderHandleLink($author_phid), 145 + $this->renderHandleLink($object_phid)); 146 + case self::TYPE_DESCRIPTION: 147 + return pht( 148 + '%s updated the description for %s.', 149 + $this->renderHandleLink($author_phid), 150 + $this->renderHandleLink($object_phid)); 151 + case self::TYPE_STATUS: 152 + switch ($new) { 153 + case PhabricatorBadgesBadge::STATUS_OPEN: 154 + return pht( 155 + '%s activated %s.', 156 + $this->renderHandleLink($author_phid), 157 + $this->renderHandleLink($object_phid)); 158 + case PhabricatorBadgesBadge::STATUS_CLOSED: 159 + return pht( 160 + '%s archived %s.', 161 + $this->renderHandleLink($author_phid), 162 + $this->renderHandleLink($object_phid)); 163 + } 164 + break; 165 + } 166 + 167 + return parent::getTitleForFeed(); 168 + } 169 + 170 + 171 + public function shouldHide() { 172 + $old = $this->getOldValue(); 173 + switch ($this->getTransactionType()) { 174 + case self::TYPE_DESCRIPTION: 175 + return ($old === null); 176 + } 177 + return parent::shouldHide(); 178 + } 179 + 180 + public function hasChangeDetails() { 181 + switch ($this->getTransactionType()) { 182 + case self::TYPE_DESCRIPTION: 183 + return ($this->getOldValue() !== null); 184 + } 185 + 186 + return parent::hasChangeDetails(); 187 + } 188 + 189 + public function renderChangeDetails(PhabricatorUser $viewer) { 190 + return $this->renderTextCorpusChangeDetails( 191 + $viewer, 192 + $this->getOldValue(), 193 + $this->getNewValue()); 194 + } 195 + }
+61
src/applications/badges/view/PhabricatorBadgesRecipientsListView.php
··· 1 + <?php 2 + 3 + final class PhabricatorBadgesRecipientsListView extends AphrontTagView { 4 + 5 + private $badge; 6 + private $handles; 7 + 8 + public function setBadge(PhabricatorBadgesBadge $badge) { 9 + $this->badge = $badge; 10 + return $this; 11 + } 12 + 13 + public function setHandles(array $handles) { 14 + $this->handles = $handles; 15 + return $this; 16 + } 17 + 18 + protected function getTagContent() { 19 + 20 + $viewer = $this->user; 21 + 22 + $badge = $this->badge; 23 + $handles = $this->handles; 24 + 25 + $can_edit = PhabricatorPolicyFilter::hasCapability( 26 + $viewer, 27 + $badge, 28 + PhabricatorPolicyCapability::CAN_EDIT); 29 + 30 + $list = id(new PHUIObjectItemListView()) 31 + ->setNoDataString(pht('This badge does not have any recipients.')); 32 + 33 + foreach ($handles as $handle) { 34 + $remove_uri = '/badges/recipients/'. 35 + $badge->getID().'/remove/?phid='.$handle->getPHID(); 36 + 37 + $item = id(new PHUIObjectItemView()) 38 + ->setHeader($handle->getFullName()) 39 + ->setHref($handle->getURI()) 40 + ->setImageURI($handle->getImageURI()); 41 + 42 + if ($can_edit) { 43 + $item->addAction( 44 + id(new PHUIListItemView()) 45 + ->setIcon('fa-times') 46 + ->setName(pht('Remove')) 47 + ->setHref($remove_uri) 48 + ->setWorkflow(true)); 49 + } 50 + 51 + $list->addItem($item); 52 + } 53 + 54 + $box = id(new PHUIObjectBoxView()) 55 + ->setHeaderText(pht('Recipients')) 56 + ->setObjectList($list); 57 + 58 + return $box; 59 + } 60 + 61 + }
+1 -1
src/applications/tokens/application/PhabricatorTokensApplication.php
··· 11 11 } 12 12 13 13 public function getFontIcon() { 14 - return 'fa-trophy'; 14 + return 'fa-thumbs-up'; 15 15 } 16 16 17 17 public function getTitleGlyph() {
+2 -2
src/applications/uiexample/examples/PHUIBadgeExample.php
··· 89 89 $badges2[] = id(new PHUIBadgeView()) 90 90 ->setIcon('fa-users') 91 91 ->setHeader(pht('Security Team')) 92 - ->setSubhead(pht('<sripts>alert(1);</script>')) 92 + ->setSubhead(pht('<script>alert(1);</script>')) 93 93 ->setQuality(PHUIBadgeView::EPIC) 94 94 ->setSource('Projects (automatic)') 95 95 ->addByline(pht('Dec 31, 1969')) ··· 152 152 $flex2->addItems($badges2); 153 153 154 154 $box2 = id(new PHUIObjectBoxView()) 155 - ->setHeaderText(pht('Acheivements')) 155 + ->setHeaderText(pht('Achievements')) 156 156 ->appendChild($flex2); 157 157 158 158 $flex3 = new PHUIBadgeBoxView();
+74
src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php
··· 1182 1182 '%s Task', 1183 1183 '%s Tasks', 1184 1184 ), 1185 + '%s added %s badge(s) for %s: %s.' => array( 1186 + array( 1187 + '%s added a badge for %s: %3$s.', 1188 + '%s added badges for %s: %3$s.', 1189 + ), 1190 + ), 1191 + '%s added %s badge(s): %s.' => array( 1192 + array( 1193 + '%s added a badge: %3$s.', 1194 + '%s added badges: %3$s.', 1195 + ), 1196 + ), 1197 + '%s awarded %s recipient(s) for %s: %s.' => array( 1198 + array( 1199 + '%s awarded %3$s to %4$s.', 1200 + '%s awarded %3$s to multiple recipients: %4$s.', 1201 + ), 1202 + ), 1203 + '%s awarded %s recipients(s): %s.' => array( 1204 + array( 1205 + '%s awarded a recipient: %3$s.', 1206 + '%s awarded multiple recipients: %3$s.', 1207 + ), 1208 + ), 1209 + '%s edited badge(s) for %s, added %s: %s; revoked %s: %s.' => array( 1210 + array( 1211 + '%s edited badges for %s, added %s: %s; revoked %s: %s.', 1212 + '%s edited badges for %s, added %s: %s; revoked %s: %s.', 1213 + ), 1214 + ), 1215 + '%s edited badge(s), added %s: %s; revoked %s: %s.' => array( 1216 + array( 1217 + '%s edited badges, added %s: %s; revoked %s: %s.', 1218 + '%s edited badges, added %s: %s; revoked %s: %s.', 1219 + ), 1220 + ), 1221 + '%s edited recipient(s) for %s, awarded %s: %s; revoked %s: %s.' => array( 1222 + array( 1223 + '%s edited recipients for %s, awarded %s: %s; revoked %s: %s.', 1224 + '%s edited recipients for %s, awarded %s: %s; revoked %s: %s.', 1225 + ), 1226 + ), 1227 + '%s edited recipient(s), awarded %s: %s; revoked %s: %s.' => array( 1228 + array( 1229 + '%s edited recipients, awarded %s: %s; revoked %s: %s.', 1230 + '%s edited recipients, awarded %s: %s; revoked %s: %s.', 1231 + ), 1232 + ), 1233 + '%s revoked %s badge(s) for %s: %s.' => array( 1234 + array( 1235 + '%s revoked a badge for %3$s: %4$s.', 1236 + '%s revoked multiple badges for %3$s: %4$s.', 1237 + ), 1238 + ), 1239 + '%s revoked %s badge(s): %s.' => array( 1240 + array( 1241 + '%s revoked a badge: %3$s.', 1242 + '%s revoked multiple badges: %3$s.', 1243 + ), 1244 + ), 1245 + '%s revoked %s recipient(s) for %s: %s.' => array( 1246 + array( 1247 + '%s revoked %3$s from %4$s.', 1248 + '%s revoked multiple recipients for %3$s: %4$s.', 1249 + ), 1250 + ), 1251 + 1252 + '%s revoked %s recipients(s): %s.' => array( 1253 + array( 1254 + '%s revoked a recipient: %3$s.', 1255 + '%s revoked multiple recipients: %3$s.', 1256 + ), 1257 + ), 1258 + 1185 1259 ); 1186 1260 } 1187 1261
+1
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
··· 106 106 'db.almanac' => array(), 107 107 'db.multimeter' => array(), 108 108 'db.spaces' => array(), 109 + 'db.badges' => array(), 109 110 '0000.legacy.sql' => array( 110 111 'legacy' => 0, 111 112 ),
+15
src/view/phui/PHUIObjectItemView.php
··· 23 23 private $fontIcon; 24 24 private $imageIcon; 25 25 private $titleText; 26 + private $badge; 26 27 27 28 const AGE_FRESH = 'fresh'; 28 29 const AGE_STALE = 'stale'; ··· 96 97 97 98 public function setSubHead($subhead) { 98 99 $this->subhead = $subhead; 100 + return $this; 101 + } 102 + 103 + public function setBadge(PHUIBadgeMiniView $badge) { 104 + $this->badge = $badge; 99 105 return $this; 100 106 } 101 107 ··· 586 592 'class' => 'phui-object-item-col0', 587 593 ), 588 594 $status); 595 + } 596 + 597 + if ($this->badge) { 598 + $column0 = phutil_tag( 599 + 'div', 600 + array( 601 + 'class' => 'phui-object-item-col0 phui-object-item-badge', 602 + ), 603 + $this->badge); 589 604 } 590 605 591 606 $column1 = phutil_tag(
+11
webroot/rsrc/css/phui/phui-object-item-list-view.css
··· 617 617 border: none; 618 618 } 619 619 620 + /* - Badges ---------------------------------------------------------------- */ 621 + 622 + .phui-object-item-col0.phui-object-item-badge { 623 + width: 28px; 624 + } 625 + 626 + .phui-object-item-col0.phui-object-item-badge .phui-icon-view { 627 + left: 0; 628 + } 629 + 630 + 620 631 /* - Dashboards ------------------------------------------------------------ */ 621 632 622 633 .phui-object-box .phui-object-item-list-view .phui-object-item-frame {
+6
webroot/rsrc/css/phui/phui-property-list-view.css
··· 98 98 border-width: 1px 0 0; 99 99 } 100 100 101 + .phui-property-list-container + .phui-property-list-text-content { 102 + border-color: {$thinblueborder}; 103 + border-style: solid; 104 + border-width: 1px 0 0; 105 + } 106 + 101 107 .phui-property-list-section-noninitial .phui-property-list-section-header { 102 108 border-top: none; 103 109 }