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

Provide default view and edit policies in Calendar, plus "Event Host" and "Event Invitees"

Summary:
Fixes T9224. This adds:

- A "Default Edit Policy" and "Default View Policy" to Calendar, similar to other applications.
- "Event Host" and "Event Invitees" objects policies.

These policies often end up being redundant (the host can always view/edit, the invitees can always view), but they can be more clear than setting "No One", and "Editable By: Event Invitees" is a legitimately useful policy.

Test Plan:
- Created and edited events.
- Fiddled with defaults.
- Tried to remove myself as the event host for an "Editable By: Host" event, got an error ("you wouldn't be able to edit").
- Tried to remove myself as host/invitee for an "Editable By: Invitees" event, got an error.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9224

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

+226 -2
+8
src/__phutil_library_map__.php
··· 2026 2026 'PhabricatorCalendarEventCancelTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventCancelTransaction.php', 2027 2027 'PhabricatorCalendarEventDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventDateTransaction.php', 2028 2028 'PhabricatorCalendarEventDeclineTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventDeclineTransaction.php', 2029 + 'PhabricatorCalendarEventDefaultEditCapability' => 'applications/calendar/capability/PhabricatorCalendarEventDefaultEditCapability.php', 2030 + 'PhabricatorCalendarEventDefaultViewCapability' => 'applications/calendar/capability/PhabricatorCalendarEventDefaultViewCapability.php', 2029 2031 'PhabricatorCalendarEventDescriptionTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventDescriptionTransaction.php', 2030 2032 'PhabricatorCalendarEventDragController' => 'applications/calendar/controller/PhabricatorCalendarEventDragController.php', 2031 2033 'PhabricatorCalendarEventEditConduitAPIMethod' => 'applications/calendar/conduit/PhabricatorCalendarEventEditConduitAPIMethod.php', ··· 2036 2038 'PhabricatorCalendarEventEndDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventEndDateTransaction.php', 2037 2039 'PhabricatorCalendarEventFrequencyTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventFrequencyTransaction.php', 2038 2040 'PhabricatorCalendarEventFulltextEngine' => 'applications/calendar/search/PhabricatorCalendarEventFulltextEngine.php', 2041 + 'PhabricatorCalendarEventHostPolicyRule' => 'applications/calendar/policyrule/PhabricatorCalendarEventHostPolicyRule.php', 2039 2042 'PhabricatorCalendarEventHostTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventHostTransaction.php', 2040 2043 'PhabricatorCalendarEventIconTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventIconTransaction.php', 2041 2044 'PhabricatorCalendarEventInviteTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventInviteTransaction.php', 2042 2045 'PhabricatorCalendarEventInvitee' => 'applications/calendar/storage/PhabricatorCalendarEventInvitee.php', 2043 2046 'PhabricatorCalendarEventInviteeQuery' => 'applications/calendar/query/PhabricatorCalendarEventInviteeQuery.php', 2047 + 'PhabricatorCalendarEventInviteesPolicyRule' => 'applications/calendar/policyrule/PhabricatorCalendarEventInviteesPolicyRule.php', 2044 2048 'PhabricatorCalendarEventJoinController' => 'applications/calendar/controller/PhabricatorCalendarEventJoinController.php', 2045 2049 'PhabricatorCalendarEventListController' => 'applications/calendar/controller/PhabricatorCalendarEventListController.php', 2046 2050 'PhabricatorCalendarEventMailReceiver' => 'applications/calendar/mail/PhabricatorCalendarEventMailReceiver.php', ··· 6654 6658 'PhabricatorCalendarEventCancelTransaction' => 'PhabricatorCalendarEventTransactionType', 6655 6659 'PhabricatorCalendarEventDateTransaction' => 'PhabricatorCalendarEventTransactionType', 6656 6660 'PhabricatorCalendarEventDeclineTransaction' => 'PhabricatorCalendarEventReplyTransaction', 6661 + 'PhabricatorCalendarEventDefaultEditCapability' => 'PhabricatorPolicyCapability', 6662 + 'PhabricatorCalendarEventDefaultViewCapability' => 'PhabricatorPolicyCapability', 6657 6663 'PhabricatorCalendarEventDescriptionTransaction' => 'PhabricatorCalendarEventTransactionType', 6658 6664 'PhabricatorCalendarEventDragController' => 'PhabricatorCalendarController', 6659 6665 'PhabricatorCalendarEventEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', ··· 6664 6670 'PhabricatorCalendarEventEndDateTransaction' => 'PhabricatorCalendarEventDateTransaction', 6665 6671 'PhabricatorCalendarEventFrequencyTransaction' => 'PhabricatorCalendarEventTransactionType', 6666 6672 'PhabricatorCalendarEventFulltextEngine' => 'PhabricatorFulltextEngine', 6673 + 'PhabricatorCalendarEventHostPolicyRule' => 'PhabricatorPolicyRule', 6667 6674 'PhabricatorCalendarEventHostTransaction' => 'PhabricatorCalendarEventTransactionType', 6668 6675 'PhabricatorCalendarEventIconTransaction' => 'PhabricatorCalendarEventTransactionType', 6669 6676 'PhabricatorCalendarEventInviteTransaction' => 'PhabricatorCalendarEventTransactionType', ··· 6672 6679 'PhabricatorPolicyInterface', 6673 6680 ), 6674 6681 'PhabricatorCalendarEventInviteeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 6682 + 'PhabricatorCalendarEventInviteesPolicyRule' => 'PhabricatorPolicyRule', 6675 6683 'PhabricatorCalendarEventJoinController' => 'PhabricatorCalendarController', 6676 6684 'PhabricatorCalendarEventListController' => 'PhabricatorCalendarController', 6677 6685 'PhabricatorCalendarEventMailReceiver' => 'PhabricatorObjectMailReceiver',
+15
src/applications/calendar/application/PhabricatorCalendarApplication.php
··· 83 83 ); 84 84 } 85 85 86 + protected function getCustomCapabilities() { 87 + return array( 88 + PhabricatorCalendarEventDefaultViewCapability::CAPABILITY => array( 89 + 'caption' => pht('Default view policy for newly created events.'), 90 + 'template' => PhabricatorCalendarEventPHIDType::TYPECONST, 91 + 'capability' => PhabricatorPolicyCapability::CAN_VIEW, 92 + ), 93 + PhabricatorCalendarEventDefaultEditCapability::CAPABILITY => array( 94 + 'caption' => pht('Default edit policy for newly created events.'), 95 + 'template' => PhabricatorCalendarEventPHIDType::TYPECONST, 96 + 'capability' => PhabricatorPolicyCapability::CAN_EDIT, 97 + ), 98 + ); 99 + } 100 + 86 101 }
+12
src/applications/calendar/capability/PhabricatorCalendarEventDefaultEditCapability.php
··· 1 + <?php 2 + 3 + final class PhabricatorCalendarEventDefaultEditCapability 4 + extends PhabricatorPolicyCapability { 5 + 6 + const CAPABILITY = 'calendar.event.default.edit'; 7 + 8 + public function getCapabilityName() { 9 + return pht('Default Edit Policy'); 10 + } 11 + 12 + }
+16
src/applications/calendar/capability/PhabricatorCalendarEventDefaultViewCapability.php
··· 1 + <?php 2 + 3 + final class PhabricatorCalendarEventDefaultViewCapability 4 + extends PhabricatorPolicyCapability { 5 + 6 + const CAPABILITY = 'calendar.event.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 + }
+23
src/applications/calendar/editor/PhabricatorCalendarEventEditor.php
··· 65 65 return $types; 66 66 } 67 67 68 + protected function adjustObjectForPolicyChecks( 69 + PhabricatorLiskDAO $object, 70 + array $xactions) { 71 + 72 + $copy = parent::adjustObjectForPolicyChecks($object, $xactions); 73 + foreach ($xactions as $xaction) { 74 + switch ($xaction->getTransactionType()) { 75 + case PhabricatorCalendarEventHostTransaction::TRANSACTIONTYPE: 76 + $copy->setHostPHID($xaction->getNewValue()); 77 + break; 78 + case PhabricatorCalendarEventInviteTransaction::TRANSACTIONTYPE: 79 + PhabricatorPolicyRule::passTransactionHintToRule( 80 + $copy, 81 + new PhabricatorCalendarEventInviteesPolicyRule(), 82 + array_fuse($xaction->getNewValue())); 83 + break; 84 + } 85 + } 86 + 87 + return $copy; 88 + } 89 + 90 + 68 91 protected function applyFinalEffects( 69 92 PhabricatorLiskDAO $object, 70 93 array $xactions) {
+43
src/applications/calendar/policyrule/PhabricatorCalendarEventHostPolicyRule.php
··· 1 + <?php 2 + 3 + final class PhabricatorCalendarEventHostPolicyRule 4 + extends PhabricatorPolicyRule { 5 + 6 + public function getObjectPolicyKey() { 7 + return 'calendar.event.host'; 8 + } 9 + 10 + public function getObjectPolicyName() { 11 + return pht('Event Host'); 12 + } 13 + 14 + public function getPolicyExplanation() { 15 + return pht('The host of this event can take this action.'); 16 + } 17 + 18 + public function getRuleDescription() { 19 + return pht('event host'); 20 + } 21 + 22 + public function canApplyToObject(PhabricatorPolicyInterface $object) { 23 + return ($object instanceof PhabricatorCalendarEvent); 24 + } 25 + 26 + public function applyRule( 27 + PhabricatorUser $viewer, 28 + $value, 29 + PhabricatorPolicyInterface $object) { 30 + 31 + $viewer_phid = $viewer->getPHID(); 32 + if (!$viewer_phid) { 33 + return false; 34 + } 35 + 36 + return ($object->getHostPHID() == $viewer_phid); 37 + } 38 + 39 + public function getValueControlType() { 40 + return self::CONTROL_TYPE_NONE; 41 + } 42 + 43 + }
+104
src/applications/calendar/policyrule/PhabricatorCalendarEventInviteesPolicyRule.php
··· 1 + <?php 2 + 3 + final class PhabricatorCalendarEventInviteesPolicyRule 4 + extends PhabricatorPolicyRule { 5 + 6 + private $invited = array(); 7 + private $sourcePHIDs = array(); 8 + 9 + public function getObjectPolicyKey() { 10 + return 'calendar.event.invitees'; 11 + } 12 + 13 + public function getObjectPolicyName() { 14 + return pht('Event Invitees'); 15 + } 16 + 17 + public function getPolicyExplanation() { 18 + return pht('Users invited to this event can take this action.'); 19 + } 20 + 21 + public function getRuleDescription() { 22 + return pht('event invitees'); 23 + } 24 + 25 + public function canApplyToObject(PhabricatorPolicyInterface $object) { 26 + return ($object instanceof PhabricatorCalendarEvent); 27 + } 28 + 29 + public function willApplyRules( 30 + PhabricatorUser $viewer, 31 + array $values, 32 + array $objects) { 33 + 34 + $viewer_phid = $viewer->getPHID(); 35 + if (!$viewer_phid) { 36 + return; 37 + } 38 + 39 + if (empty($this->invited[$viewer_phid])) { 40 + $this->invited[$viewer_phid] = array(); 41 + } 42 + 43 + if (!isset($this->sourcePHIDs[$viewer_phid])) { 44 + $source_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( 45 + $viewer_phid, 46 + PhabricatorProjectMemberOfProjectEdgeType::EDGECONST); 47 + $source_phids[] = $viewer_phid; 48 + $this->sourcePHIDs[$viewer_phid] = $source_phids; 49 + } 50 + 51 + foreach ($objects as $key => $object) { 52 + $cache = $this->getTransactionHint($object); 53 + if ($cache === null) { 54 + // We don't have a hint for this object, so we'll deal with it below. 55 + continue; 56 + } 57 + 58 + // We have a hint, so use that as the source of truth. 59 + unset($objects[$key]); 60 + 61 + foreach ($this->sourcePHIDs[$viewer_phid] as $source_phid) { 62 + if (isset($cache[$source_phid])) { 63 + $this->invited[$viewer_phid][$object->getPHID()] = true; 64 + break; 65 + } 66 + } 67 + } 68 + 69 + $phids = mpull($objects, 'getPHID'); 70 + if (!$phids) { 71 + return; 72 + } 73 + 74 + $invited = id(new PhabricatorCalendarEventInvitee())->loadAllWhere( 75 + 'eventPHID IN (%Ls) 76 + AND inviteePHID IN (%Ls) 77 + AND status != %s', 78 + $phids, 79 + $this->sourcePHIDs[$viewer_phid], 80 + PhabricatorCalendarEventInvitee::STATUS_UNINVITED); 81 + $invited = mpull($invited, 'getEventPHID'); 82 + 83 + $this->invited[$viewer_phid] += array_fill_keys($invited, true); 84 + } 85 + 86 + public function applyRule( 87 + PhabricatorUser $viewer, 88 + $value, 89 + PhabricatorPolicyInterface $object) { 90 + 91 + $viewer_phid = $viewer->getPHID(); 92 + if (!$viewer_phid) { 93 + return false; 94 + } 95 + 96 + $invited = idx($this->invited, $viewer_phid); 97 + return isset($invited[$object->getPHID()]); 98 + } 99 + 100 + public function getValueControlType() { 101 + return self::CONTROL_TYPE_NONE; 102 + } 103 + 104 + }
+5 -2
src/applications/calendar/storage/PhabricatorCalendarEvent.php
··· 57 57 ->withClasses(array('PhabricatorCalendarApplication')) 58 58 ->executeOne(); 59 59 60 - $view_policy = PhabricatorPolicies::getMostOpenPolicy(); 60 + $view_default = PhabricatorCalendarEventDefaultViewCapability::CAPABILITY; 61 + $edit_default = PhabricatorCalendarEventDefaultEditCapability::CAPABILITY; 62 + $view_policy = $app->getPolicy($view_default); 63 + $edit_policy = $app->getPolicy($edit_default); 61 64 62 65 $start = new DateTime('@'.PhabricatorTime::getNow()); 63 66 $start->setTimeZone($actor->getTimeZone()); ··· 83 86 )) 84 87 ->setIcon($default_icon) 85 88 ->setViewPolicy($view_policy) 86 - ->setEditPolicy($actor->getPHID()) 89 + ->setEditPolicy($edit_policy) 87 90 ->setSpacePHID($actor->getDefaultSpacePHID()) 88 91 ->attachInvitees(array()) 89 92 ->setDateFrom($epoch_min)