@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 PhabricatorPeopleProfilePictureController
4 extends PhabricatorPeopleProfileController {
5
6 public function handleRequest(AphrontRequest $request) {
7 $viewer = $this->getViewer();
8 $id = $request->getURIData('id');
9
10 $user = id(new PhabricatorPeopleQuery())
11 ->setViewer($viewer)
12 ->withIDs(array($id))
13 ->needProfileImage(true)
14 ->requireCapabilities(
15 array(
16 PhabricatorPolicyCapability::CAN_VIEW,
17 PhabricatorPolicyCapability::CAN_EDIT,
18 ))
19 ->executeOne();
20 if (!$user) {
21 return new Aphront404Response();
22 }
23
24 $this->setUser($user);
25 $name = $user->getUserName();
26
27 $done_uri = '/p/'.$name.'/';
28
29 $supported_formats = PhabricatorFile::getTransformableImageFormats();
30 if ($supported_formats) {
31 $supported_formats_message = pht('Supported image formats: %s.',
32 implode(', ', $supported_formats));
33 } else {
34 $supported_formats_message = pht('Server supports no image formats.');
35 }
36 $e_file = true;
37 $errors = array();
38
39 // Get the image file transform.
40 $xform = PhabricatorFileTransform::getTransformByKey(
41 PhabricatorFileThumbnailTransform::TRANSFORM_PROFILE);
42
43 // Have an hard-limit to save our resources.
44 $max_image_dimensions = $xform->getMaxTransformDimensions();
45 $max_image_dimensions_message = pht('Maximum image dimensions: %s pixels.',
46 implode(mb_chr(215), $max_image_dimensions));
47
48 if ($request->isFormPost()) {
49 $phid = $request->getStr('phid');
50 $is_default = false;
51 if ($phid == PhabricatorPHIDConstants::PHID_VOID) {
52 $phid = null;
53 $is_default = true;
54 } else if ($phid) {
55 $file = id(new PhabricatorFileQuery())
56 ->setViewer($viewer)
57 ->withPHIDs(array($phid))
58 ->executeOne();
59 } else {
60 if ($request->getFileExists('picture')) {
61 $file = PhabricatorFile::newFromPHPUpload(
62 $_FILES['picture'],
63 array(
64 'authorPHID' => $viewer->getPHID(),
65 'canCDN' => true,
66 ));
67 } else {
68 $e_file = pht('Required');
69 $errors[] = pht(
70 'You must choose a file when uploading a new profile picture.');
71 }
72 }
73
74 if (!$errors && !$is_default) {
75 if (!$file->isTransformableImage()) {
76 $e_file = pht('Not Supported');
77 $errors[] = $supported_formats_message;
78 } else {
79 $xformed = $xform->getOrExecuteTransformExplicit($file);
80 }
81 }
82
83 if (!$errors) {
84 if ($is_default) {
85 $user->setProfileImagePHID(null);
86 } else {
87 $user->setProfileImagePHID($xformed->getPHID());
88 $xformed->attachToObject($user->getPHID());
89 }
90 $user->save();
91 return id(new AphrontRedirectResponse())->setURI($done_uri);
92 }
93 }
94
95 $title = pht('Edit Profile Picture');
96
97 $form = id(new PHUIFormLayoutView())
98 ->setUser($viewer);
99
100 $default_image = $user->getDefaultProfileImagePHID();
101 if ($default_image) {
102 $default_image = id(new PhabricatorFileQuery())
103 ->setViewer($viewer)
104 ->withPHIDs(array($default_image))
105 ->executeOne();
106 }
107
108 if (!$default_image) {
109 $default_image = PhabricatorFile::loadBuiltin($viewer, 'profile.png');
110 }
111
112 $images = array();
113
114 $current = $user->getProfileImagePHID();
115 $has_current = false;
116 if ($current) {
117 $files = id(new PhabricatorFileQuery())
118 ->setViewer($viewer)
119 ->withPHIDs(array($current))
120 ->execute();
121 if ($files) {
122 $file = head($files);
123 if ($file->isTransformableImage()) {
124 $has_current = true;
125 $images[$current] = array(
126 'uri' => $file->getBestURI(),
127 'tip' => pht('Current Picture'),
128 );
129 }
130 }
131 }
132
133 $builtins = array(
134 'user1.png',
135 'user2.png',
136 'user3.png',
137 'user4.png',
138 'user5.png',
139 'user6.png',
140 'user7.png',
141 'user8.png',
142 'user9.png',
143 );
144 foreach ($builtins as $builtin) {
145 $file = PhabricatorFile::loadBuiltin($viewer, $builtin);
146 $images[$file->getPHID()] = array(
147 'uri' => $file->getBestURI(),
148 'tip' => pht('Builtin Image'),
149 );
150 }
151
152 // Try to add external account images for any associated external accounts.
153 $accounts = id(new PhabricatorExternalAccountQuery())
154 ->setViewer($viewer)
155 ->withUserPHIDs(array($user->getPHID()))
156 ->needImages(true)
157 ->requireCapabilities(
158 array(
159 PhabricatorPolicyCapability::CAN_VIEW,
160 PhabricatorPolicyCapability::CAN_EDIT,
161 ))
162 ->execute();
163
164 foreach ($accounts as $account) {
165 $file = $account->getProfileImageFile();
166 if ($account->getProfileImagePHID() != $file->getPHID()) {
167 // This is a default image, just skip it.
168 continue;
169 }
170
171 $config = $account->getProviderConfig();
172 $provider = $config->getProvider();
173
174 $tip = pht('Picture From %s', $provider->getProviderName());
175
176 if ($file->isTransformableImage()) {
177 $images[$file->getPHID()] = array(
178 'uri' => $file->getBestURI(),
179 'tip' => $tip,
180 );
181 }
182 }
183
184 $images[PhabricatorPHIDConstants::PHID_VOID] = array(
185 'uri' => $default_image->getBestURI(),
186 'tip' => pht('Default Picture'),
187 );
188
189 require_celerity_resource('people-profile-css');
190 Javelin::initBehavior('phabricator-tooltips', array());
191
192 $buttons = array();
193 foreach ($images as $phid => $spec) {
194 $button = javelin_tag(
195 'button',
196 array(
197 'class' => 'button-grey profile-image-button',
198 'sigil' => 'has-tooltip',
199 'meta' => array(
200 'tip' => $spec['tip'],
201 'size' => 300,
202 ),
203 ),
204 phutil_tag(
205 'img',
206 array(
207 'height' => 50,
208 'width' => 50,
209 'src' => $spec['uri'],
210 )));
211
212 $button = array(
213 phutil_tag(
214 'input',
215 array(
216 'type' => 'hidden',
217 'name' => 'phid',
218 'value' => $phid,
219 )),
220 $button,
221 );
222
223 $button = phabricator_form(
224 $viewer,
225 array(
226 'class' => 'profile-image-form',
227 'method' => 'POST',
228 ),
229 $button);
230
231 $buttons[] = $button;
232 }
233
234 if ($has_current) {
235 $form->appendChild(
236 id(new AphrontFormMarkupControl())
237 ->setLabel(pht('Current Picture'))
238 ->setValue(array_shift($buttons)));
239 }
240
241 $form->appendChild(
242 id(new AphrontFormMarkupControl())
243 ->setLabel(pht('Use Picture'))
244 ->setValue($buttons));
245
246 $form_box = id(new PHUIObjectBoxView())
247 ->setHeaderText($title)
248 ->setFormErrors($errors)
249 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
250 ->setForm($form);
251
252 $upload_form = id(new AphrontFormView())
253 ->setUser($viewer)
254 ->setEncType('multipart/form-data')
255 ->appendChild(
256 id(new AphrontFormFileControl())
257 ->setName('picture')
258 ->setLabel(pht('Upload Picture'))
259 ->setError($e_file)
260 ->setCaption($supported_formats_message.' '.
261 $max_image_dimensions_message))
262 ->appendChild(
263 id(new AphrontFormSubmitControl())
264 ->addCancelButton($done_uri)
265 ->setValue(pht('Upload Picture')));
266
267 $upload_box = id(new PHUIObjectBoxView())
268 ->setHeaderText(pht('Upload New Picture'))
269 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
270 ->setForm($upload_form);
271
272 $crumbs = $this->buildApplicationCrumbs();
273 $crumbs->addTextCrumb(pht('Edit Profile Picture'));
274 $crumbs->setBorder(true);
275
276 $nav = $this->newNavigation(
277 $user,
278 PhabricatorPeopleProfileMenuEngine::ITEM_MANAGE);
279
280 $header = $this->buildProfileHeader();
281
282 $view = id(new PHUITwoColumnView())
283 ->setHeader($header)
284 ->addClass('project-view-home')
285 ->addClass('project-view-people-home')
286 ->setFooter(array(
287 $form_box,
288 $upload_box,
289 ));
290
291 return $this->newPage()
292 ->setTitle($title)
293 ->setCrumbs($crumbs)
294 ->setNavigation($nav)
295 ->appendChild($view);
296 }
297}