@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 PhabricatorProjectWatchController
4 extends PhabricatorProjectController {
5
6 public function handleRequest(AphrontRequest $request) {
7 $viewer = $request->getViewer();
8 $id = $request->getURIData('id');
9 $action = $request->getURIData('action');
10
11 $project = id(new PhabricatorProjectQuery())
12 ->setViewer($viewer)
13 ->withIDs(array($id))
14 ->needMembers(true)
15 ->needWatchers(true)
16 ->executeOne();
17 if (!$project) {
18 return new Aphront404Response();
19 }
20
21 $via = $request->getStr('via');
22 if ($via == 'profile') {
23 $done_uri = "/project/profile/{$id}/";
24 } else {
25 $done_uri = "/project/members/{$id}/";
26 }
27
28 $is_watcher = $project->isUserWatcher($viewer->getPHID());
29 $is_ancestor = $project->isUserAncestorWatcher($viewer->getPHID());
30 if ($is_ancestor && !$is_watcher) {
31 $ancestor_phid = $project->getWatchedAncestorPHID($viewer->getPHID());
32 $handles = $viewer->loadHandles(array($ancestor_phid));
33 $ancestor_handle = $handles[$ancestor_phid];
34
35 return $this->newDialog()
36 ->setTitle(pht('Watching Ancestor'))
37 ->appendParagraph(
38 pht(
39 'You are already watching %s, an ancestor of this project, and '.
40 'are thus watching all of its subprojects.',
41 $ancestor_handle->renderTag()->render()))
42 ->addCancelbutton($done_uri);
43 }
44
45 if ($request->isDialogFormPost()) {
46 $edge_action = null;
47 switch ($action) {
48 case 'watch':
49 $edge_action = '+';
50 break;
51 case 'unwatch':
52 $edge_action = '-';
53 break;
54 }
55
56 $type_watcher = PhabricatorObjectHasWatcherEdgeType::EDGECONST;
57 $member_spec = array(
58 $edge_action => array($viewer->getPHID() => $viewer->getPHID()),
59 );
60
61 $xactions = array();
62 $xactions[] = id(new PhabricatorProjectTransaction())
63 ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
64 ->setMetadataValue('edge:type', $type_watcher)
65 ->setNewValue($member_spec);
66
67 $editor = id(new PhabricatorProjectTransactionEditor())
68 ->setActor($viewer)
69 ->setContentSourceFromRequest($request)
70 ->setContinueOnNoEffect(true)
71 ->setContinueOnMissingFields(true)
72 ->applyTransactions($project, $xactions);
73
74 return id(new AphrontRedirectResponse())->setURI($done_uri);
75 }
76
77 $dialog = null;
78 switch ($action) {
79 case 'watch':
80 $title = pht('Watch Project?');
81 $body = array();
82 $body[] = pht(
83 'Watching a project will let you monitor it closely. You will '.
84 'receive email and notifications about changes to every object '.
85 'tagged with projects you watch.');
86 $body[] = pht(
87 'Watching a project also watches all subprojects and milestones of '.
88 'that project.');
89 $submit = pht('Watch Project');
90 break;
91 case 'unwatch':
92 $title = pht('Unwatch Project?');
93 $body = pht(
94 'You will no longer receive email or notifications about every '.
95 'object associated with this project.');
96 $submit = pht('Unwatch Project');
97 break;
98 default:
99 return new Aphront404Response();
100 }
101
102 $dialog = $this->newDialog()
103 ->setTitle($title)
104 ->addHiddenInput('via', $via)
105 ->addCancelButton($done_uri)
106 ->addSubmitButton($submit);
107
108 foreach ((array)$body as $paragraph) {
109 $dialog->appendParagraph($paragraph);
110 }
111
112 return $dialog;
113 }
114
115}