3 final class PhabricatorFileViewController
extends PhabricatorFileController
{
5 public function shouldAllowPublic() {
9 public function handleRequest(AphrontRequest
$request) {
10 $viewer = $request->getViewer();
11 $id = $request->getURIData('id');
12 $phid = $request->getURIData('phid');
15 $file = id(new PhabricatorFileQuery())
17 ->withPHIDs(array($phid))
18 ->withIsDeleted(false)
22 return new Aphront404Response();
24 return id(new AphrontRedirectResponse())->setURI($file->getInfoURI());
27 $file = id(new PhabricatorFileQuery())
30 ->withIsDeleted(false)
33 return new Aphront404Response();
36 $phid = $file->getPHID();
38 $header = id(new PHUIHeaderView())
40 ->setPolicyObject($file)
41 ->setHeader($file->getName())
42 ->setHeaderIcon('fa-file-o');
44 $ttl = $file->getTTL();
46 $ttl_tag = id(new PHUITagView())
47 ->setType(PHUITagView
::TYPE_SHADE
)
48 ->setColor(PHUITagView
::COLOR_YELLOW
)
49 ->setName(pht('Temporary'));
50 $header->addTag($ttl_tag);
53 $partial = $file->getIsPartial();
55 $partial_tag = id(new PHUITagView())
56 ->setType(PHUITagView
::TYPE_SHADE
)
57 ->setColor(PHUITagView
::COLOR_ORANGE
)
58 ->setName(pht('Partial Upload'));
59 $header->addTag($partial_tag);
62 $curtain = $this->buildCurtainView($file);
63 $timeline = $this->buildTransactionView($file);
64 $crumbs = $this->buildApplicationCrumbs();
65 $crumbs->addTextCrumb(
68 $crumbs->setBorder(true);
70 $object_box = id(new PHUIObjectBoxView())
71 ->setHeaderText(pht('File Metadata'))
72 ->setBackground(PHUIObjectBoxView
::BLUE_PROPERTY
);
74 $this->buildPropertyViews($object_box, $file);
75 $title = $file->getName();
77 $file_content = $this->newFileContent($file);
79 $view = id(new PHUITwoColumnView())
81 ->setCurtain($curtain)
89 return $this->newPage()
92 ->setPageObjectPHIDs(array($file->getPHID()))
96 private function buildTransactionView(PhabricatorFile
$file) {
97 $viewer = $this->getViewer();
99 $timeline = $this->buildTransactionTimeline(
101 new PhabricatorFileTransactionQuery());
103 $comment_view = id(new PhabricatorFileEditEngine())
105 ->buildEditEngineCommentView($file);
107 $monogram = $file->getMonogram();
109 $timeline->setQuoteRef($monogram);
110 $comment_view->setTransactionTimeline($timeline);
118 private function buildCurtainView(PhabricatorFile
$file) {
119 $viewer = $this->getViewer();
121 $id = $file->getID();
123 $can_edit = PhabricatorPolicyFilter
::hasCapability(
126 PhabricatorPolicyCapability
::CAN_EDIT
);
128 $curtain = $this->newCurtainView($file);
130 $can_download = !$file->getIsPartial();
132 if ($file->isViewableInBrowser()) {
134 id(new PhabricatorActionView())
135 ->setName(pht('View File'))
136 ->setIcon('fa-file-o')
137 ->setHref($file->getViewURI())
138 ->setDisabled(!$can_download)
139 ->setWorkflow(!$can_download));
142 id(new PhabricatorActionView())
144 ->setDownload($can_download)
145 ->setName(pht('Download File'))
146 ->setIcon('fa-download')
147 ->setHref($file->getDownloadURI())
148 ->setDisabled(!$can_download)
149 ->setWorkflow(!$can_download));
153 id(new PhabricatorActionView())
154 ->setName(pht('Edit File'))
155 ->setIcon('fa-pencil')
156 ->setHref($this->getApplicationURI("/edit/{$id}/"))
157 ->setWorkflow(!$can_edit)
158 ->setDisabled(!$can_edit));
161 id(new PhabricatorActionView())
162 ->setName(pht('Delete File'))
163 ->setIcon('fa-times')
164 ->setHref($this->getApplicationURI("/delete/{$id}/"))
166 ->setDisabled(!$can_edit));
169 id(new PhabricatorActionView())
170 ->setName(pht('View Transforms'))
172 ->setHref($this->getApplicationURI("/transforms/{$id}/")));
176 $viewer_phid = $viewer->getPHID();
177 $author_phid = $file->getAuthorPHID();
179 $phids[] = $author_phid;
182 $handles = $viewer->loadHandles($phids);
185 $author_refs = id(new PHUICurtainObjectRefListView())
186 ->setViewer($viewer);
188 $author_ref = $author_refs->newObjectRefView()
189 ->setHandle($handles[$author_phid])
190 ->setEpoch($file->getDateCreated())
191 ->setHighlighted($author_phid === $viewer_phid);
194 ->setHeaderText(pht('Authored By'))
195 ->appendChild($author_refs);
199 ->setHeaderText(pht('Size'))
200 ->appendChild(phutil_format_bytes($file->getByteSize()));
202 $width = $file->getImageWidth();
203 $height = $file->getImageHeight();
205 if ($width ||
$height) {
207 ->setHeaderText(pht('Dimensions'))
210 "%spx \xC3\x97 %spx",
211 new PhutilNumber($width),
212 new PhutilNumber($height)));
218 private function buildPropertyViews(
219 PHUIObjectBoxView
$box,
220 PhabricatorFile
$file) {
221 $request = $this->getRequest();
222 $viewer = $request->getUser();
224 $tab_group = id(new PHUITabGroupView());
225 $box->addTabGroup($tab_group);
227 $finfo = new PHUIPropertyListView();
230 id(new PHUITabView())
231 ->setName(pht('Details'))
233 ->appendChild($finfo));
237 $file->getMimeType());
239 $ttl = $file->getTtl();
241 $delta = $ttl - PhabricatorTime
::getNow();
247 phabricator_datetime($ttl, $viewer),
248 phutil_format_relative_time_detailed($delta)));
251 $is_image = $file->isViewableImage();
253 $image_string = pht('Yes');
254 $cache_string = $file->getCanCDN() ?
pht('Yes') : pht('No');
256 $image_string = pht('No');
257 $cache_string = pht('Not Applicable');
261 if ($file->isViewableImage()) {
262 $types[] = pht('Image');
265 if ($file->isVideo()) {
266 $types[] = pht('Video');
269 if ($file->isAudio()) {
270 $types[] = pht('Audio');
273 if ($file->getCanCDN()) {
274 $types[] = pht('Can CDN');
277 $builtin = $file->getBuiltinName();
278 if ($builtin !== null) {
279 $types[] = pht('Builtin ("%s")', $builtin);
282 if ($file->getIsProfileImage()) {
283 $types[] = pht('Profile');
287 $types = implode(', ', $types);
288 $finfo->addProperty(pht('Attributes'), $types);
292 pht('Storage Engine'),
293 $file->getStorageEngine());
295 $engine = $this->loadStorageEngine($file);
296 if ($engine && $engine->isChunkEngine()) {
297 $format_name = pht('Chunks');
299 $format_key = $file->getStorageFormat();
300 $format = PhabricatorFileStorageFormat
::getFormat($format_key);
302 $format_name = $format->getStorageFormatName();
304 $format_name = pht('Unknown ("%s")', $format_key);
307 $finfo->addProperty(pht('Storage Format'), $format_name);
310 pht('Storage Handle'),
311 $file->getStorageHandle());
313 $custom_alt = $file->getCustomAltText();
314 if (strlen($custom_alt)) {
315 $finfo->addProperty(pht('Custom Alt Text'), $custom_alt);
318 $default_alt = $file->getDefaultAltText();
319 if (strlen($default_alt)) {
320 $finfo->addProperty(pht('Default Alt Text'), $default_alt);
323 $phids = $file->getObjectPHIDs();
325 $attached = new PHUIPropertyListView();
328 id(new PHUITabView())
329 ->setName(pht('Attached'))
331 ->appendChild($attached));
333 $attached->addProperty(
335 $viewer->renderHandleList($phids));
338 $engine = $this->loadStorageEngine($file);
340 if ($engine->isChunkEngine()) {
341 $chunkinfo = new PHUIPropertyListView();
344 id(new PHUITabView())
345 ->setName(pht('Chunks'))
347 ->appendChild($chunkinfo));
349 $chunks = id(new PhabricatorFileChunkQuery())
351 ->withChunkHandles(array($file->getStorageHandle()))
353 $chunks = msort($chunks, 'getByteStart');
356 $completed = array();
357 foreach ($chunks as $chunk) {
358 $is_complete = $chunk->getDataFilePHID();
361 $chunk->getByteStart(),
362 $chunk->getByteEnd(),
363 ($is_complete ?
pht('Yes') : pht('No')),
367 $completed[] = $chunk;
371 $table = id(new AphrontTableView($rows))
385 $chunkinfo->addProperty(
389 $chunkinfo->addProperty(
390 pht('Completed Chunks'),
393 $chunkinfo->addRawContent($table);
399 private function loadStorageEngine(PhabricatorFile
$file) {
403 $engine = $file->instantiateStorageEngine();
404 } catch (Exception
$ex) {
405 // Don't bother raising this anywhere for now.
411 private function newFileContent(PhabricatorFile
$file) {
412 $request = $this->getRequest();
414 $ref = id(new PhabricatorDocumentRef())
417 $engine = id(new PhabricatorFileDocumentRenderingEngine())
418 ->setRequest($request);
420 return $engine->newDocumentView($ref);