@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 PhabricatorAuditTransaction
4 extends PhabricatorModularTransaction {
5
6 const TYPE_COMMIT = 'audit:commit';
7
8 const MAILTAG_ACTION_CONCERN = 'audit-action-concern';
9 const MAILTAG_ACTION_ACCEPT = 'audit-action-accept';
10 const MAILTAG_ACTION_RESIGN = 'audit-action-resign';
11 const MAILTAG_ACTION_CLOSE = 'audit-action-close';
12 const MAILTAG_ADD_AUDITORS = 'audit-add-auditors';
13 const MAILTAG_ADD_CCS = 'audit-add-ccs';
14 const MAILTAG_COMMENT = 'audit-comment';
15 const MAILTAG_COMMIT = 'audit-commit';
16 const MAILTAG_PROJECTS = 'audit-projects';
17 const MAILTAG_OTHER = 'audit-other';
18
19 public function getApplicationName() {
20 return 'audit';
21 }
22
23 public function getBaseTransactionClass() {
24 return DiffusionCommitTransactionType::class;
25 }
26
27 public function getApplicationTransactionType() {
28 return PhabricatorRepositoryCommitPHIDType::TYPECONST;
29 }
30
31 public function getApplicationTransactionCommentObject() {
32 return new PhabricatorAuditTransactionComment();
33 }
34
35 public function getRemarkupBlocks() {
36 $blocks = parent::getRemarkupBlocks();
37
38 switch ($this->getTransactionType()) {
39 case self::TYPE_COMMIT:
40 $data = $this->getNewValue();
41 $blocks[] = $data['description'];
42 break;
43 }
44
45 return $blocks;
46 }
47
48 public function getActionStrength() {
49 $type = $this->getTransactionType();
50
51 switch ($type) {
52 case self::TYPE_COMMIT:
53 return 300;
54 }
55
56 return parent::getActionStrength();
57 }
58
59 public function getRequiredHandlePHIDs() {
60 $phids = parent::getRequiredHandlePHIDs();
61
62 $type = $this->getTransactionType();
63
64 switch ($type) {
65 case self::TYPE_COMMIT:
66 $phids[] = $this->getObjectPHID();
67 $data = $this->getNewValue();
68 if ($data['authorPHID']) {
69 $phids[] = $data['authorPHID'];
70 }
71 if ($data['committerPHID']) {
72 $phids[] = $data['committerPHID'];
73 }
74 break;
75 case PhabricatorAuditActionConstants::ADD_CCS:
76 case PhabricatorAuditActionConstants::ADD_AUDITORS:
77 $old = $this->getOldValue();
78 $new = $this->getNewValue();
79
80 if (!is_array($old)) {
81 $old = array();
82 }
83 if (!is_array($new)) {
84 $new = array();
85 }
86
87 foreach (array_keys($old + $new) as $phid) {
88 $phids[] = $phid;
89 }
90 break;
91 }
92
93 return $phids;
94 }
95
96 public function getActionName() {
97
98 switch ($this->getTransactionType()) {
99 case PhabricatorAuditActionConstants::ACTION:
100 switch ($this->getNewValue()) {
101 case PhabricatorAuditActionConstants::CONCERN:
102 return pht('Raised Concern');
103 case PhabricatorAuditActionConstants::ACCEPT:
104 return pht('Accepted');
105 case PhabricatorAuditActionConstants::RESIGN:
106 return pht('Resigned');
107 case PhabricatorAuditActionConstants::CLOSE:
108 return pht('Closed');
109 }
110 break;
111 case PhabricatorAuditActionConstants::ADD_AUDITORS:
112 return pht('Added Auditors');
113 case self::TYPE_COMMIT:
114 return pht('Committed');
115 }
116
117 return parent::getActionName();
118 }
119
120 public function getColor() {
121
122 $type = $this->getTransactionType();
123
124 switch ($type) {
125 case PhabricatorAuditActionConstants::ACTION:
126 switch ($this->getNewValue()) {
127 case PhabricatorAuditActionConstants::CONCERN:
128 return 'red';
129 case PhabricatorAuditActionConstants::ACCEPT:
130 return 'green';
131 case PhabricatorAuditActionConstants::RESIGN:
132 return 'black';
133 case PhabricatorAuditActionConstants::CLOSE:
134 return 'indigo';
135 }
136 }
137
138 return parent::getColor();
139 }
140
141 public function getIcon() {
142
143 $type = $this->getTransactionType();
144
145 switch ($type) {
146 case PhabricatorAuditActionConstants::ACTION:
147 switch ($this->getNewValue()) {
148 case PhabricatorAuditActionConstants::CONCERN:
149 return 'fa-exclamation-circle';
150 case PhabricatorAuditActionConstants::ACCEPT:
151 case PhabricatorAuditActionConstants::CLOSE:
152 return 'fa-check';
153 case PhabricatorAuditActionConstants::RESIGN:
154 return 'fa-plane';
155 }
156 }
157
158 return parent::getIcon();
159 }
160
161 public function getTitle() {
162 $old = $this->getOldValue();
163 $new = $this->getNewValue();
164
165 $author_handle = $this->renderHandleLink($this->getAuthorPHID());
166
167 $type = $this->getTransactionType();
168
169 switch ($type) {
170 case PhabricatorAuditActionConstants::ADD_CCS:
171 case PhabricatorAuditActionConstants::ADD_AUDITORS:
172 if (!is_array($old)) {
173 $old = array();
174 }
175 if (!is_array($new)) {
176 $new = array();
177 }
178 $add = array_keys(array_diff_key($new, $old));
179 $rem = array_keys(array_diff_key($old, $new));
180 break;
181 }
182
183 switch ($type) {
184 case self::TYPE_COMMIT:
185 $author = null;
186 if ($new['authorPHID']) {
187 $author = $this->renderHandleLink($new['authorPHID']);
188 } else {
189 $author = $new['authorName'];
190 }
191
192 $committer = null;
193 if ($new['committerPHID']) {
194 $committer = $this->renderHandleLink($new['committerPHID']);
195 } else if ($new['committerName']) {
196 $committer = $new['committerName'];
197 }
198
199 $commit = $this->renderHandleLink($this->getObjectPHID());
200
201 if (!$committer) {
202 $committer = $author;
203 $author = null;
204 }
205
206 if ($author) {
207 $title = pht(
208 '%s committed %s (authored by %s).',
209 $committer,
210 $commit,
211 $author);
212 } else {
213 $title = pht(
214 '%s committed %s.',
215 $committer,
216 $commit);
217 }
218 return $title;
219
220 case PhabricatorAuditActionConstants::INLINE:
221 return pht(
222 '%s added inline comments.',
223 $author_handle);
224
225 case PhabricatorAuditActionConstants::ADD_CCS:
226 if ($add && $rem) {
227 return pht(
228 '%s edited subscribers; added: %s, removed: %s.',
229 $author_handle,
230 $this->renderHandleList($add),
231 $this->renderHandleList($rem));
232 } else if ($add) {
233 return pht(
234 '%s added subscribers: %s.',
235 $author_handle,
236 $this->renderHandleList($add));
237 } else if ($rem) {
238 return pht(
239 '%s removed subscribers: %s.',
240 $author_handle,
241 $this->renderHandleList($rem));
242 } else {
243 return pht(
244 '%s added subscribers...',
245 $author_handle);
246 }
247
248 case PhabricatorAuditActionConstants::ADD_AUDITORS:
249 if ($add && $rem) {
250 return pht(
251 '%s edited auditors; added: %s, removed: %s.',
252 $author_handle,
253 $this->renderHandleList($add),
254 $this->renderHandleList($rem));
255 } else if ($add) {
256 return pht(
257 '%s added auditors: %s.',
258 $author_handle,
259 $this->renderHandleList($add));
260 } else if ($rem) {
261 return pht(
262 '%s removed auditors: %s.',
263 $author_handle,
264 $this->renderHandleList($rem));
265 } else {
266 return pht(
267 '%s added auditors...',
268 $author_handle);
269 }
270
271 case PhabricatorAuditActionConstants::ACTION:
272 switch ($new) {
273 case PhabricatorAuditActionConstants::ACCEPT:
274 return pht(
275 '%s accepted this commit.',
276 $author_handle);
277 case PhabricatorAuditActionConstants::CONCERN:
278 return pht(
279 '%s raised a concern with this commit.',
280 $author_handle);
281 case PhabricatorAuditActionConstants::RESIGN:
282 return pht(
283 '%s resigned from this audit.',
284 $author_handle);
285 case PhabricatorAuditActionConstants::CLOSE:
286 return pht(
287 '%s closed this audit.',
288 $author_handle);
289 }
290
291 }
292
293 return parent::getTitle();
294 }
295
296 public function getTitleForFeed() {
297 $old = $this->getOldValue();
298 $new = $this->getNewValue();
299
300 $author_handle = $this->renderHandleLink($this->getAuthorPHID());
301 $object_handle = $this->renderHandleLink($this->getObjectPHID());
302
303 $type = $this->getTransactionType();
304
305 switch ($type) {
306 case PhabricatorAuditActionConstants::ADD_CCS:
307 case PhabricatorAuditActionConstants::ADD_AUDITORS:
308 if (!is_array($old)) {
309 $old = array();
310 }
311 if (!is_array($new)) {
312 $new = array();
313 }
314 $add = array_keys(array_diff_key($new, $old));
315 $rem = array_keys(array_diff_key($old, $new));
316 break;
317 }
318
319 switch ($type) {
320 case self::TYPE_COMMIT:
321 $author = null;
322 if ($new['authorPHID']) {
323 $author = $this->renderHandleLink($new['authorPHID']);
324 } else {
325 $author = $new['authorName'];
326 }
327
328 $committer = null;
329 if ($new['committerPHID']) {
330 $committer = $this->renderHandleLink($new['committerPHID']);
331 } else if ($new['committerName']) {
332 $committer = $new['committerName'];
333 }
334
335 if (!$committer) {
336 $committer = $author;
337 $author = null;
338 }
339
340 // Show both Author and Committer only if they are different.
341 $show_both = $author && $committer;
342 if ($show_both) {
343 if ($new['authorPHID']) {
344 $show_both = $new['authorPHID'] !== $new['committerPHID'];
345 } else if (phutil_nonempty_string($new['authorName'])) {
346 $show_both = $new['authorName'] !== $new['committerName'];
347 }
348 }
349
350 if ($show_both) {
351 $title = pht(
352 '%s committed %s (authored by %s).',
353 $committer,
354 $object_handle,
355 $author);
356 } else {
357 $title = pht(
358 '%s committed %s.',
359 $committer,
360 $object_handle);
361 }
362 return $title;
363
364 case PhabricatorAuditActionConstants::INLINE:
365 return pht(
366 '%s added inline comments to %s.',
367 $author_handle,
368 $object_handle);
369
370 case PhabricatorAuditActionConstants::ADD_AUDITORS:
371 if ($add && $rem) {
372 return pht(
373 '%s edited auditors for %s; added: %s, removed: %s.',
374 $author_handle,
375 $object_handle,
376 $this->renderHandleList($add),
377 $this->renderHandleList($rem));
378 } else if ($add) {
379 return pht(
380 '%s added auditors to %s: %s.',
381 $author_handle,
382 $object_handle,
383 $this->renderHandleList($add));
384 } else if ($rem) {
385 return pht(
386 '%s removed auditors from %s: %s.',
387 $author_handle,
388 $object_handle,
389 $this->renderHandleList($rem));
390 } else {
391 return pht(
392 '%s added auditors to %s...',
393 $author_handle,
394 $object_handle);
395 }
396
397 case PhabricatorAuditActionConstants::ACTION:
398 switch ($new) {
399 case PhabricatorAuditActionConstants::ACCEPT:
400 return pht(
401 '%s accepted %s.',
402 $author_handle,
403 $object_handle);
404 case PhabricatorAuditActionConstants::CONCERN:
405 return pht(
406 '%s raised a concern with %s.',
407 $author_handle,
408 $object_handle);
409 case PhabricatorAuditActionConstants::RESIGN:
410 return pht(
411 '%s resigned from auditing %s.',
412 $author_handle,
413 $object_handle);
414 case PhabricatorAuditActionConstants::CLOSE:
415 return pht(
416 '%s closed the audit of %s.',
417 $author_handle,
418 $object_handle);
419 }
420
421 }
422
423 return parent::getTitleForFeed();
424 }
425
426 public function getBodyForFeed(PhabricatorFeedStory $story) {
427 switch ($this->getTransactionType()) {
428 case self::TYPE_COMMIT:
429 // At the moment commits have the very same title,
430 // and the very same body in web feeds.
431 // Maybe better to just show one of them.
432 // https://we.phorge.it/T15489
433 // $data = $this->getNewValue();
434 // return $story->renderSummary($data['summary']);
435 return null;
436 }
437 return parent::getBodyForFeed($story);
438 }
439
440 public function isInlineCommentTransaction() {
441 switch ($this->getTransactionType()) {
442 case PhabricatorAuditActionConstants::INLINE:
443 return true;
444 }
445
446 return parent::isInlineCommentTransaction();
447 }
448
449 public function getBodyForMail() {
450 switch ($this->getTransactionType()) {
451 case self::TYPE_COMMIT:
452 $data = $this->getNewValue();
453 return $data['description'];
454 }
455
456 return parent::getBodyForMail();
457 }
458
459 public function getMailTags() {
460 $tags = array();
461 switch ($this->getTransactionType()) {
462 case DiffusionCommitAcceptTransaction::TRANSACTIONTYPE:
463 $tags[] = self::MAILTAG_ACTION_ACCEPT;
464 break;
465 case DiffusionCommitConcernTransaction::TRANSACTIONTYPE:
466 $tags[] = self::MAILTAG_ACTION_CONCERN;
467 break;
468 case DiffusionCommitResignTransaction::TRANSACTIONTYPE:
469 $tags[] = self::MAILTAG_ACTION_RESIGN;
470 break;
471 case DiffusionCommitAuditorsTransaction::TRANSACTIONTYPE:
472 case PhabricatorAuditActionConstants::ADD_AUDITORS:
473 $tags[] = self::MAILTAG_ADD_AUDITORS;
474 break;
475 case PhabricatorAuditActionConstants::ACTION:
476 switch ($this->getNewValue()) {
477 case PhabricatorAuditActionConstants::CONCERN:
478 $tags[] = self::MAILTAG_ACTION_CONCERN;
479 break;
480 case PhabricatorAuditActionConstants::ACCEPT:
481 $tags[] = self::MAILTAG_ACTION_ACCEPT;
482 break;
483 case PhabricatorAuditActionConstants::RESIGN:
484 $tags[] = self::MAILTAG_ACTION_RESIGN;
485 break;
486 case PhabricatorAuditActionConstants::CLOSE:
487 $tags[] = self::MAILTAG_ACTION_CLOSE;
488 break;
489 }
490 break;
491 case PhabricatorAuditActionConstants::ADD_CCS:
492 $tags[] = self::MAILTAG_ADD_CCS;
493 break;
494 case PhabricatorAuditActionConstants::INLINE:
495 case PhabricatorTransactions::TYPE_COMMENT:
496 $tags[] = self::MAILTAG_COMMENT;
497 break;
498 case self::TYPE_COMMIT:
499 $tags[] = self::MAILTAG_COMMIT;
500 break;
501 case PhabricatorTransactions::TYPE_EDGE:
502 switch ($this->getMetadataValue('edge:type')) {
503 case PhabricatorProjectObjectHasProjectEdgeType::EDGECONST:
504 $tags[] = self::MAILTAG_PROJECTS;
505 break;
506 case PhabricatorObjectHasSubscriberEdgeType::EDGECONST:
507 $tags[] = self::MAILTAG_ADD_CCS;
508 break;
509 default:
510 $tags[] = self::MAILTAG_OTHER;
511 break;
512 }
513 break;
514 default:
515 $tags[] = self::MAILTAG_OTHER;
516 break;
517 }
518 return $tags;
519 }
520
521 public function shouldDisplayGroupWith(array $group) {
522 // Make the "This commit now requires audit." state message stand alone.
523 $type_state = DiffusionCommitStateTransaction::TRANSACTIONTYPE;
524
525 if ($this->getTransactionType() == $type_state) {
526 return false;
527 }
528
529 foreach ($group as $xaction) {
530 if ($xaction->getTransactionType() == $type_state) {
531 return false;
532 }
533 }
534
535 return parent::shouldDisplayGroupWith($group);
536 }
537
538}