Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/files/controller/PhabricatorFileViewController.php
12242 views
1
<?php
2
3
final class PhabricatorFileViewController extends PhabricatorFileController {
4
5
public function shouldAllowPublic() {
6
return true;
7
}
8
9
public function handleRequest(AphrontRequest $request) {
10
$viewer = $request->getViewer();
11
$id = $request->getURIData('id');
12
$phid = $request->getURIData('phid');
13
14
if ($phid) {
15
$file = id(new PhabricatorFileQuery())
16
->setViewer($viewer)
17
->withPHIDs(array($phid))
18
->withIsDeleted(false)
19
->executeOne();
20
21
if (!$file) {
22
return new Aphront404Response();
23
}
24
return id(new AphrontRedirectResponse())->setURI($file->getInfoURI());
25
}
26
27
$file = id(new PhabricatorFileQuery())
28
->setViewer($viewer)
29
->withIDs(array($id))
30
->withIsDeleted(false)
31
->executeOne();
32
if (!$file) {
33
return new Aphront404Response();
34
}
35
36
$phid = $file->getPHID();
37
38
$header = id(new PHUIHeaderView())
39
->setUser($viewer)
40
->setPolicyObject($file)
41
->setHeader($file->getName())
42
->setHeaderIcon('fa-file-o');
43
44
$ttl = $file->getTTL();
45
if ($ttl !== null) {
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);
51
}
52
53
$partial = $file->getIsPartial();
54
if ($partial) {
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);
60
}
61
62
$curtain = $this->buildCurtainView($file);
63
$timeline = $this->buildTransactionView($file);
64
$crumbs = $this->buildApplicationCrumbs();
65
$crumbs->addTextCrumb(
66
$file->getMonogram(),
67
$file->getInfoURI());
68
$crumbs->setBorder(true);
69
70
$object_box = id(new PHUIObjectBoxView())
71
->setHeaderText(pht('File Metadata'))
72
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
73
74
$this->buildPropertyViews($object_box, $file);
75
$title = $file->getName();
76
77
$file_content = $this->newFileContent($file);
78
79
$view = id(new PHUITwoColumnView())
80
->setHeader($header)
81
->setCurtain($curtain)
82
->setMainColumn(
83
array(
84
$file_content,
85
$object_box,
86
$timeline,
87
));
88
89
return $this->newPage()
90
->setTitle($title)
91
->setCrumbs($crumbs)
92
->setPageObjectPHIDs(array($file->getPHID()))
93
->appendChild($view);
94
}
95
96
private function buildTransactionView(PhabricatorFile $file) {
97
$viewer = $this->getViewer();
98
99
$timeline = $this->buildTransactionTimeline(
100
$file,
101
new PhabricatorFileTransactionQuery());
102
103
$comment_view = id(new PhabricatorFileEditEngine())
104
->setViewer($viewer)
105
->buildEditEngineCommentView($file);
106
107
$monogram = $file->getMonogram();
108
109
$timeline->setQuoteRef($monogram);
110
$comment_view->setTransactionTimeline($timeline);
111
112
return array(
113
$timeline,
114
$comment_view,
115
);
116
}
117
118
private function buildCurtainView(PhabricatorFile $file) {
119
$viewer = $this->getViewer();
120
121
$id = $file->getID();
122
123
$can_edit = PhabricatorPolicyFilter::hasCapability(
124
$viewer,
125
$file,
126
PhabricatorPolicyCapability::CAN_EDIT);
127
128
$curtain = $this->newCurtainView($file);
129
130
$can_download = !$file->getIsPartial();
131
132
if ($file->isViewableInBrowser()) {
133
$curtain->addAction(
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));
140
} else {
141
$curtain->addAction(
142
id(new PhabricatorActionView())
143
->setUser($viewer)
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));
150
}
151
152
$curtain->addAction(
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));
159
160
$curtain->addAction(
161
id(new PhabricatorActionView())
162
->setName(pht('Delete File'))
163
->setIcon('fa-times')
164
->setHref($this->getApplicationURI("/delete/{$id}/"))
165
->setWorkflow(true)
166
->setDisabled(!$can_edit));
167
168
$curtain->addAction(
169
id(new PhabricatorActionView())
170
->setName(pht('View Transforms'))
171
->setIcon('fa-crop')
172
->setHref($this->getApplicationURI("/transforms/{$id}/")));
173
174
$phids = array();
175
176
$viewer_phid = $viewer->getPHID();
177
$author_phid = $file->getAuthorPHID();
178
if ($author_phid) {
179
$phids[] = $author_phid;
180
}
181
182
$handles = $viewer->loadHandles($phids);
183
184
if ($author_phid) {
185
$author_refs = id(new PHUICurtainObjectRefListView())
186
->setViewer($viewer);
187
188
$author_ref = $author_refs->newObjectRefView()
189
->setHandle($handles[$author_phid])
190
->setEpoch($file->getDateCreated())
191
->setHighlighted($author_phid === $viewer_phid);
192
193
$curtain->newPanel()
194
->setHeaderText(pht('Authored By'))
195
->appendChild($author_refs);
196
}
197
198
$curtain->newPanel()
199
->setHeaderText(pht('Size'))
200
->appendChild(phutil_format_bytes($file->getByteSize()));
201
202
$width = $file->getImageWidth();
203
$height = $file->getImageHeight();
204
205
if ($width || $height) {
206
$curtain->newPanel()
207
->setHeaderText(pht('Dimensions'))
208
->appendChild(
209
pht(
210
"%spx \xC3\x97 %spx",
211
new PhutilNumber($width),
212
new PhutilNumber($height)));
213
}
214
215
return $curtain;
216
}
217
218
private function buildPropertyViews(
219
PHUIObjectBoxView $box,
220
PhabricatorFile $file) {
221
$request = $this->getRequest();
222
$viewer = $request->getUser();
223
224
$tab_group = id(new PHUITabGroupView());
225
$box->addTabGroup($tab_group);
226
227
$finfo = new PHUIPropertyListView();
228
229
$tab_group->addTab(
230
id(new PHUITabView())
231
->setName(pht('Details'))
232
->setKey('details')
233
->appendChild($finfo));
234
235
$finfo->addProperty(
236
pht('Mime Type'),
237
$file->getMimeType());
238
239
$ttl = $file->getTtl();
240
if ($ttl) {
241
$delta = $ttl - PhabricatorTime::getNow();
242
243
$finfo->addProperty(
244
pht('Expires'),
245
pht(
246
'%s (%s)',
247
phabricator_datetime($ttl, $viewer),
248
phutil_format_relative_time_detailed($delta)));
249
}
250
251
$is_image = $file->isViewableImage();
252
if ($is_image) {
253
$image_string = pht('Yes');
254
$cache_string = $file->getCanCDN() ? pht('Yes') : pht('No');
255
} else {
256
$image_string = pht('No');
257
$cache_string = pht('Not Applicable');
258
}
259
260
$types = array();
261
if ($file->isViewableImage()) {
262
$types[] = pht('Image');
263
}
264
265
if ($file->isVideo()) {
266
$types[] = pht('Video');
267
}
268
269
if ($file->isAudio()) {
270
$types[] = pht('Audio');
271
}
272
273
if ($file->getCanCDN()) {
274
$types[] = pht('Can CDN');
275
}
276
277
$builtin = $file->getBuiltinName();
278
if ($builtin !== null) {
279
$types[] = pht('Builtin ("%s")', $builtin);
280
}
281
282
if ($file->getIsProfileImage()) {
283
$types[] = pht('Profile');
284
}
285
286
if ($types) {
287
$types = implode(', ', $types);
288
$finfo->addProperty(pht('Attributes'), $types);
289
}
290
291
$finfo->addProperty(
292
pht('Storage Engine'),
293
$file->getStorageEngine());
294
295
$engine = $this->loadStorageEngine($file);
296
if ($engine && $engine->isChunkEngine()) {
297
$format_name = pht('Chunks');
298
} else {
299
$format_key = $file->getStorageFormat();
300
$format = PhabricatorFileStorageFormat::getFormat($format_key);
301
if ($format) {
302
$format_name = $format->getStorageFormatName();
303
} else {
304
$format_name = pht('Unknown ("%s")', $format_key);
305
}
306
}
307
$finfo->addProperty(pht('Storage Format'), $format_name);
308
309
$finfo->addProperty(
310
pht('Storage Handle'),
311
$file->getStorageHandle());
312
313
$custom_alt = $file->getCustomAltText();
314
if ($custom_alt !== null && strlen($custom_alt)) {
315
$finfo->addProperty(pht('Custom Alt Text'), $custom_alt);
316
}
317
318
$default_alt = $file->getDefaultAltText();
319
if ($default_alt !== null && strlen($default_alt)) {
320
$finfo->addProperty(pht('Default Alt Text'), $default_alt);
321
}
322
323
$attachments_table = $this->newAttachmentsView($file);
324
325
$tab_group->addTab(
326
id(new PHUITabView())
327
->setName(pht('Attached'))
328
->setKey('attached')
329
->appendChild($attachments_table));
330
331
$engine = $this->loadStorageEngine($file);
332
if ($engine) {
333
if ($engine->isChunkEngine()) {
334
$chunkinfo = new PHUIPropertyListView();
335
336
$tab_group->addTab(
337
id(new PHUITabView())
338
->setName(pht('Chunks'))
339
->setKey('chunks')
340
->appendChild($chunkinfo));
341
342
$chunks = id(new PhabricatorFileChunkQuery())
343
->setViewer($viewer)
344
->withChunkHandles(array($file->getStorageHandle()))
345
->execute();
346
$chunks = msort($chunks, 'getByteStart');
347
348
$rows = array();
349
$completed = array();
350
foreach ($chunks as $chunk) {
351
$is_complete = $chunk->getDataFilePHID();
352
353
$rows[] = array(
354
$chunk->getByteStart(),
355
$chunk->getByteEnd(),
356
($is_complete ? pht('Yes') : pht('No')),
357
);
358
359
if ($is_complete) {
360
$completed[] = $chunk;
361
}
362
}
363
364
$table = id(new AphrontTableView($rows))
365
->setHeaders(
366
array(
367
pht('Offset'),
368
pht('End'),
369
pht('Complete'),
370
))
371
->setColumnClasses(
372
array(
373
'',
374
'',
375
'wide',
376
));
377
378
$chunkinfo->addProperty(
379
pht('Total Chunks'),
380
count($chunks));
381
382
$chunkinfo->addProperty(
383
pht('Completed Chunks'),
384
count($completed));
385
386
$chunkinfo->addRawContent($table);
387
}
388
}
389
390
}
391
392
private function loadStorageEngine(PhabricatorFile $file) {
393
$engine = null;
394
395
try {
396
$engine = $file->instantiateStorageEngine();
397
} catch (Exception $ex) {
398
// Don't bother raising this anywhere for now.
399
}
400
401
return $engine;
402
}
403
404
private function newFileContent(PhabricatorFile $file) {
405
$request = $this->getRequest();
406
407
$ref = id(new PhabricatorDocumentRef())
408
->setFile($file);
409
410
$engine = id(new PhabricatorFileDocumentRenderingEngine())
411
->setRequest($request);
412
413
return $engine->newDocumentView($ref);
414
}
415
416
private function newAttachmentsView(PhabricatorFile $file) {
417
$viewer = $this->getViewer();
418
419
$attachments = id(new PhabricatorFileAttachmentQuery())
420
->setViewer($viewer)
421
->withFilePHIDs(array($file->getPHID()))
422
->execute();
423
424
$handles = $viewer->loadHandles(mpull($attachments, 'getObjectPHID'));
425
426
$rows = array();
427
428
$mode_map = PhabricatorFileAttachment::getModeNameMap();
429
$mode_attach = PhabricatorFileAttachment::MODE_ATTACH;
430
431
foreach ($attachments as $attachment) {
432
$object_phid = $attachment->getObjectPHID();
433
$handle = $handles[$object_phid];
434
435
$attachment_mode = $attachment->getAttachmentMode();
436
437
$mode_name = idx($mode_map, $attachment_mode);
438
if ($mode_name === null) {
439
$mode_name = pht('Unknown ("%s")', $attachment_mode);
440
}
441
442
$detach_uri = urisprintf(
443
'/file/ui/detach/%s/%s/',
444
$object_phid,
445
$file->getPHID());
446
447
$is_disabled = !$attachment->canDetach();
448
449
$detach_button = id(new PHUIButtonView())
450
->setHref($detach_uri)
451
->setTag('a')
452
->setWorkflow(true)
453
->setDisabled($is_disabled)
454
->setColor(PHUIButtonView::GREY)
455
->setSize(PHUIButtonView::SMALL)
456
->setText(pht('Detach File'));
457
458
javelin_tag(
459
'a',
460
array(
461
'href' => $detach_uri,
462
'sigil' => 'workflow',
463
'disabled' => true,
464
'class' => 'small button button-grey disabled',
465
),
466
pht('Detach File'));
467
468
$rows[] = array(
469
$handle->renderLink(),
470
$mode_name,
471
$detach_button,
472
);
473
}
474
475
$table = id(new AphrontTableView($rows))
476
->setHeaders(
477
array(
478
pht('Attached To'),
479
pht('Mode'),
480
null,
481
))
482
->setColumnClasses(
483
array(
484
'pri wide',
485
null,
486
null,
487
));
488
489
return $table;
490
}
491
492
493
}
494
495