@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<?php
2
3final class PhabricatorCalendarEventCancelController
4 extends PhabricatorCalendarController {
5
6 public function handleRequest(AphrontRequest $request) {
7 $viewer = $request->getViewer();
8 $id = $request->getURIData('id');
9
10 // Just check CAN_VIEW first. Then we'll check if this is an import so
11 // we can raise a better error.
12 $event = id(new PhabricatorCalendarEventQuery())
13 ->setViewer($viewer)
14 ->withIDs(array($id))
15 ->executeOne();
16 if (!$event) {
17 return new Aphront404Response();
18 }
19
20 $response = $this->newImportedEventResponse($event);
21 if ($response) {
22 return $response;
23 }
24
25 // Now that we've done the import check, check for CAN_EDIT.
26 PhabricatorPolicyFilter::requireCapability(
27 $viewer,
28 $event,
29 PhabricatorPolicyCapability::CAN_EDIT);
30
31 $cancel_uri = $event->getURI();
32
33 $is_parent = $event->isParentEvent();
34 $is_child = $event->isChildEvent();
35
36 $is_cancelled = $event->getIsCancelled();
37 $is_recurring = $event->getIsRecurring();
38
39 $validation_exception = null;
40 if ($request->isFormPost()) {
41
42 $targets = array($event);
43 if ($is_recurring) {
44 $mode = $request->getStr('mode');
45 $is_future = ($mode == 'future');
46
47 // We need to fork the event if we're cancelling just the parent, or
48 // are cancelling a child and all future events.
49 $must_fork = ($is_child && $is_future) ||
50 ($is_parent && !$is_future);
51 if ($must_fork) {
52 $fork_target = $event->loadForkTarget($viewer);
53 if ($fork_target) {
54 $xactions = array();
55
56 $xaction = id(new PhabricatorCalendarEventTransaction())
57 ->setTransactionType(
58 PhabricatorCalendarEventForkTransaction::TRANSACTIONTYPE)
59 ->setNewValue(true);
60
61 $editor = id(new PhabricatorCalendarEventEditor())
62 ->setActor($viewer)
63 ->setContentSourceFromRequest($request)
64 ->setContinueOnNoEffect(true)
65 ->setContinueOnMissingFields(true);
66
67 $editor->applyTransactions($fork_target, array($xaction));
68 }
69 }
70
71 if ($is_future) {
72 $future = $event->loadFutureEvents($viewer);
73 foreach ($future as $future_event) {
74 $targets[] = $future_event;
75 }
76 }
77 }
78
79 foreach ($targets as $target) {
80 $xactions = array();
81
82 $xaction = id(new PhabricatorCalendarEventTransaction())
83 ->setTransactionType(
84 PhabricatorCalendarEventCancelTransaction::TRANSACTIONTYPE)
85 ->setNewValue(!$is_cancelled);
86
87 $editor = id(new PhabricatorCalendarEventEditor())
88 ->setActor($viewer)
89 ->setContentSourceFromRequest($request)
90 ->setContinueOnNoEffect(true)
91 ->setContinueOnMissingFields(true);
92
93 try {
94 $editor->applyTransactions($target, array($xaction));
95 } catch (PhabricatorApplicationTransactionValidationException $ex) {
96 $validation_exception = $ex;
97 break;
98 }
99
100 }
101
102 if (!$validation_exception) {
103 return id(new AphrontRedirectResponse())->setURI($cancel_uri);
104 }
105 }
106
107 if ($is_cancelled) {
108 $title = pht('Reinstate Event');
109 if ($is_recurring) {
110 $body = pht(
111 'This event is part of a series. Which events do you want to '.
112 'reinstate?');
113 $show_control = true;
114 } else {
115 $body = pht('Reinstate this event?');
116 $show_control = false;
117 }
118 $submit = pht('Reinstate Event');
119 } else {
120 $title = pht('Cancel Event');
121 if ($is_recurring) {
122 $body = pht(
123 'This event is part of a series. Which events do you want to '.
124 'cancel?');
125 $show_control = true;
126 } else {
127 $body = pht('Cancel this event?');
128 $show_control = false;
129 }
130 $submit = pht('Cancel Event');
131 }
132
133 $dialog = $this->newDialog()
134 ->setTitle($title)
135 ->setValidationException($validation_exception)
136 ->appendParagraph($body)
137 ->addCancelButton($cancel_uri, pht('Back'))
138 ->addSubmitButton($submit);
139
140 if ($show_control) {
141 $start_time = phutil_tag(
142 'strong',
143 array(),
144 phabricator_datetime($event->getStartDateTimeEpoch(), $viewer));
145
146 if ($is_cancelled) {
147 $this_name = pht('Reinstate Only This Event');
148 $this_caption = pht(
149 'Reinstate only the event which occurs on %s.',
150 $start_time);
151
152 $future_name = pht('Reinstate This And All Later Events');
153 $future_caption = pht(
154 'Reinstate this event and all events in the series which occur '.
155 'on or after %s.',
156 $start_time);
157 } else {
158 $this_name = pht('Cancel Only This Event');
159 $this_caption = pht(
160 'Cancel only the event which occurs on %s.',
161 $start_time);
162
163 $future_name = pht('Cancel This And All Later Events');
164 $future_caption = pht(
165 'Cancel this event and all events in the series which occur '.
166 'on or after %s.',
167 $start_time);
168 }
169
170
171 $form = id(new AphrontFormView())
172 ->setViewer($viewer)
173 ->appendControl(
174 id(new AphrontFormRadioButtonControl())
175 ->setName('mode')
176 ->setValue(PhabricatorCalendarEventEditEngine::MODE_THIS)
177 ->addButton(
178 PhabricatorCalendarEventEditEngine::MODE_THIS,
179 $this_name,
180 $this_caption)
181 ->addButton(
182 PhabricatorCalendarEventEditEngine::MODE_FUTURE,
183 $future_name,
184 $future_caption));
185
186 $dialog
187 ->setWidth(AphrontDialogView::WIDTH_FORM)
188 ->appendForm($form);
189 }
190
191 return $dialog;
192 }
193}