@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 PhortuneAccountEmailViewController
4 extends PhortuneAccountController {
5
6 protected function shouldRequireAccountEditCapability() {
7 return true;
8 }
9
10 protected function handleAccountRequest(AphrontRequest $request) {
11 $viewer = $this->getViewer();
12 $account = $this->getAccount();
13
14 $address = id(new PhortuneAccountEmailQuery())
15 ->setViewer($viewer)
16 ->withAccountPHIDs(array($account->getPHID()))
17 ->withIDs(array($request->getURIData('addressID')))
18 ->executeOne();
19 if (!$address) {
20 return new Aphront404Response();
21 }
22
23 $crumbs = $this->buildApplicationCrumbs()
24 ->addTextCrumb(pht('Email Addresses'), $account->getEmailAddressesURI())
25 ->addTextCrumb($address->getObjectName())
26 ->setBorder(true);
27
28 $header = id(new PHUIHeaderView())
29 ->setHeader(pht('Account Email: %s', $address->getAddress()));
30
31 $details = $this->newDetailsView($address);
32
33 $timeline = $this->buildTransactionTimeline(
34 $address,
35 new PhortuneAccountEmailTransactionQuery());
36 $timeline->setShouldTerminate(true);
37
38 $curtain = $this->buildCurtainView($address);
39
40 $view = id(new PHUITwoColumnView())
41 ->setHeader($header)
42 ->setCurtain($curtain)
43 ->setMainColumn(
44 array(
45 $details,
46 $timeline,
47 ));
48
49 return $this->newPage()
50 ->setTitle($address->getObjectName())
51 ->setCrumbs($crumbs)
52 ->appendChild($view);
53 }
54
55 private function buildCurtainView(PhortuneAccountEmail $address) {
56 $viewer = $this->getViewer();
57 $account = $address->getAccount();
58
59 $can_edit = PhabricatorPolicyFilter::hasCapability(
60 $viewer,
61 $address,
62 PhabricatorPolicyCapability::CAN_EDIT);
63
64 $edit_uri = $this->getApplicationURI(
65 urisprintf(
66 'account/%d/addresses/edit/%d/',
67 $account->getID(),
68 $address->getID()));
69
70 if ($can_edit) {
71 $external_uri = $address->getExternalURI();
72 } else {
73 $external_uri = null;
74 }
75
76 $curtain = $this->newCurtainView($account);
77
78 $curtain->addAction(
79 id(new PhabricatorActionView())
80 ->setName(pht('Edit Address'))
81 ->setIcon('fa-pencil')
82 ->setHref($edit_uri)
83 ->setDisabled(!$can_edit)
84 ->setWorkflow(!$can_edit));
85
86 switch ($address->getStatus()) {
87 case PhortuneAccountEmailStatus::STATUS_ACTIVE:
88 $disable_name = pht('Disable Address');
89 $disable_icon = 'fa-times';
90 $can_disable = true;
91 $disable_action = 'disable';
92 break;
93 case PhortuneAccountEmailStatus::STATUS_DISABLED:
94 $disable_name = pht('Enable Address');
95 $disable_icon = 'fa-check';
96 $can_disable = true;
97 $disable_action = 'enable';
98 break;
99 case PhortuneAccountEmailStatus::STATUS_UNSUBSCRIBED:
100 $disable_name = pht('Disable Address');
101 $disable_icon = 'fa-times';
102 $can_disable = false;
103 $disable_action = 'disable';
104 break;
105 }
106
107 $disable_uri = $this->getApplicationURI(
108 urisprintf(
109 'account/%d/addresses/%d/%s/',
110 $account->getID(),
111 $address->getID(),
112 $disable_action));
113
114 $curtain->addAction(
115 id(new PhabricatorActionView())
116 ->setName($disable_name)
117 ->setIcon($disable_icon)
118 ->setHref($disable_uri)
119 ->setDisabled(!$can_disable)
120 ->setWorkflow(true));
121
122 $rotate_uri = $this->getApplicationURI(
123 urisprintf(
124 'account/%d/addresses/%d/rotate/',
125 $account->getID(),
126 $address->getID()));
127
128 $curtain->addAction(
129 id(new PhabricatorActionView())
130 ->setName(pht('Rotate Access Key'))
131 ->setIcon('fa-refresh')
132 ->setHref($rotate_uri)
133 ->setDisabled(!$can_edit)
134 ->setWorkflow(true));
135
136 $curtain->addAction(
137 id(new PhabricatorActionView())
138 ->setName(pht('Show External View'))
139 ->setIcon('fa-eye')
140 ->setHref($external_uri)
141 ->setDisabled(!$can_edit)
142 ->setOpenInNewWindow(true));
143
144 return $curtain;
145 }
146
147 private function newDetailsView(PhortuneAccountEmail $address) {
148 $viewer = $this->getViewer();
149
150 $view = id(new PHUIPropertyListView())
151 ->setUser($viewer);
152
153 $access_key = $address->getAccessKey();
154
155 // This is not a meaningful security barrier: the full plaintext of the
156 // access key is visible on the page in the link target of the "Show
157 // External View" action. It's just here to make it clear "Rotate Access
158 // Key" actually does something.
159
160 $prefix_length = 4;
161 $visible_part = substr($access_key, 0, $prefix_length);
162 $masked_part = str_repeat(
163 "\xE2\x80\xA2",
164 strlen($access_key) - $prefix_length);
165 $access_display = $visible_part.$masked_part;
166 $access_display = phutil_tag('tt', array(), $access_display);
167
168 $view->addProperty(pht('Email Address'), $address->getAddress());
169 $view->addProperty(pht('Access Key'), $access_display);
170
171 return id(new PHUIObjectBoxView())
172 ->setHeaderText(pht('Email Address Details'))
173 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
174 ->addPropertyList($view);
175 }
176}