Path: blob/master/src/applications/files/controller/PhabricatorFileViewController.php
12242 views
<?php12final class PhabricatorFileViewController extends PhabricatorFileController {34public function shouldAllowPublic() {5return true;6}78public function handleRequest(AphrontRequest $request) {9$viewer = $request->getViewer();10$id = $request->getURIData('id');11$phid = $request->getURIData('phid');1213if ($phid) {14$file = id(new PhabricatorFileQuery())15->setViewer($viewer)16->withPHIDs(array($phid))17->withIsDeleted(false)18->executeOne();1920if (!$file) {21return new Aphront404Response();22}23return id(new AphrontRedirectResponse())->setURI($file->getInfoURI());24}2526$file = id(new PhabricatorFileQuery())27->setViewer($viewer)28->withIDs(array($id))29->withIsDeleted(false)30->executeOne();31if (!$file) {32return new Aphront404Response();33}3435$phid = $file->getPHID();3637$header = id(new PHUIHeaderView())38->setUser($viewer)39->setPolicyObject($file)40->setHeader($file->getName())41->setHeaderIcon('fa-file-o');4243$ttl = $file->getTTL();44if ($ttl !== null) {45$ttl_tag = id(new PHUITagView())46->setType(PHUITagView::TYPE_SHADE)47->setColor(PHUITagView::COLOR_YELLOW)48->setName(pht('Temporary'));49$header->addTag($ttl_tag);50}5152$partial = $file->getIsPartial();53if ($partial) {54$partial_tag = id(new PHUITagView())55->setType(PHUITagView::TYPE_SHADE)56->setColor(PHUITagView::COLOR_ORANGE)57->setName(pht('Partial Upload'));58$header->addTag($partial_tag);59}6061$curtain = $this->buildCurtainView($file);62$timeline = $this->buildTransactionView($file);63$crumbs = $this->buildApplicationCrumbs();64$crumbs->addTextCrumb(65$file->getMonogram(),66$file->getInfoURI());67$crumbs->setBorder(true);6869$object_box = id(new PHUIObjectBoxView())70->setHeaderText(pht('File Metadata'))71->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);7273$this->buildPropertyViews($object_box, $file);74$title = $file->getName();7576$file_content = $this->newFileContent($file);7778$view = id(new PHUITwoColumnView())79->setHeader($header)80->setCurtain($curtain)81->setMainColumn(82array(83$file_content,84$object_box,85$timeline,86));8788return $this->newPage()89->setTitle($title)90->setCrumbs($crumbs)91->setPageObjectPHIDs(array($file->getPHID()))92->appendChild($view);93}9495private function buildTransactionView(PhabricatorFile $file) {96$viewer = $this->getViewer();9798$timeline = $this->buildTransactionTimeline(99$file,100new PhabricatorFileTransactionQuery());101102$comment_view = id(new PhabricatorFileEditEngine())103->setViewer($viewer)104->buildEditEngineCommentView($file);105106$monogram = $file->getMonogram();107108$timeline->setQuoteRef($monogram);109$comment_view->setTransactionTimeline($timeline);110111return array(112$timeline,113$comment_view,114);115}116117private function buildCurtainView(PhabricatorFile $file) {118$viewer = $this->getViewer();119120$id = $file->getID();121122$can_edit = PhabricatorPolicyFilter::hasCapability(123$viewer,124$file,125PhabricatorPolicyCapability::CAN_EDIT);126127$curtain = $this->newCurtainView($file);128129$can_download = !$file->getIsPartial();130131if ($file->isViewableInBrowser()) {132$curtain->addAction(133id(new PhabricatorActionView())134->setName(pht('View File'))135->setIcon('fa-file-o')136->setHref($file->getViewURI())137->setDisabled(!$can_download)138->setWorkflow(!$can_download));139} else {140$curtain->addAction(141id(new PhabricatorActionView())142->setUser($viewer)143->setDownload($can_download)144->setName(pht('Download File'))145->setIcon('fa-download')146->setHref($file->getDownloadURI())147->setDisabled(!$can_download)148->setWorkflow(!$can_download));149}150151$curtain->addAction(152id(new PhabricatorActionView())153->setName(pht('Edit File'))154->setIcon('fa-pencil')155->setHref($this->getApplicationURI("/edit/{$id}/"))156->setWorkflow(!$can_edit)157->setDisabled(!$can_edit));158159$curtain->addAction(160id(new PhabricatorActionView())161->setName(pht('Delete File'))162->setIcon('fa-times')163->setHref($this->getApplicationURI("/delete/{$id}/"))164->setWorkflow(true)165->setDisabled(!$can_edit));166167$curtain->addAction(168id(new PhabricatorActionView())169->setName(pht('View Transforms'))170->setIcon('fa-crop')171->setHref($this->getApplicationURI("/transforms/{$id}/")));172173$phids = array();174175$viewer_phid = $viewer->getPHID();176$author_phid = $file->getAuthorPHID();177if ($author_phid) {178$phids[] = $author_phid;179}180181$handles = $viewer->loadHandles($phids);182183if ($author_phid) {184$author_refs = id(new PHUICurtainObjectRefListView())185->setViewer($viewer);186187$author_ref = $author_refs->newObjectRefView()188->setHandle($handles[$author_phid])189->setEpoch($file->getDateCreated())190->setHighlighted($author_phid === $viewer_phid);191192$curtain->newPanel()193->setHeaderText(pht('Authored By'))194->appendChild($author_refs);195}196197$curtain->newPanel()198->setHeaderText(pht('Size'))199->appendChild(phutil_format_bytes($file->getByteSize()));200201$width = $file->getImageWidth();202$height = $file->getImageHeight();203204if ($width || $height) {205$curtain->newPanel()206->setHeaderText(pht('Dimensions'))207->appendChild(208pht(209"%spx \xC3\x97 %spx",210new PhutilNumber($width),211new PhutilNumber($height)));212}213214return $curtain;215}216217private function buildPropertyViews(218PHUIObjectBoxView $box,219PhabricatorFile $file) {220$request = $this->getRequest();221$viewer = $request->getUser();222223$tab_group = id(new PHUITabGroupView());224$box->addTabGroup($tab_group);225226$finfo = new PHUIPropertyListView();227228$tab_group->addTab(229id(new PHUITabView())230->setName(pht('Details'))231->setKey('details')232->appendChild($finfo));233234$finfo->addProperty(235pht('Mime Type'),236$file->getMimeType());237238$ttl = $file->getTtl();239if ($ttl) {240$delta = $ttl - PhabricatorTime::getNow();241242$finfo->addProperty(243pht('Expires'),244pht(245'%s (%s)',246phabricator_datetime($ttl, $viewer),247phutil_format_relative_time_detailed($delta)));248}249250$is_image = $file->isViewableImage();251if ($is_image) {252$image_string = pht('Yes');253$cache_string = $file->getCanCDN() ? pht('Yes') : pht('No');254} else {255$image_string = pht('No');256$cache_string = pht('Not Applicable');257}258259$types = array();260if ($file->isViewableImage()) {261$types[] = pht('Image');262}263264if ($file->isVideo()) {265$types[] = pht('Video');266}267268if ($file->isAudio()) {269$types[] = pht('Audio');270}271272if ($file->getCanCDN()) {273$types[] = pht('Can CDN');274}275276$builtin = $file->getBuiltinName();277if ($builtin !== null) {278$types[] = pht('Builtin ("%s")', $builtin);279}280281if ($file->getIsProfileImage()) {282$types[] = pht('Profile');283}284285if ($types) {286$types = implode(', ', $types);287$finfo->addProperty(pht('Attributes'), $types);288}289290$finfo->addProperty(291pht('Storage Engine'),292$file->getStorageEngine());293294$engine = $this->loadStorageEngine($file);295if ($engine && $engine->isChunkEngine()) {296$format_name = pht('Chunks');297} else {298$format_key = $file->getStorageFormat();299$format = PhabricatorFileStorageFormat::getFormat($format_key);300if ($format) {301$format_name = $format->getStorageFormatName();302} else {303$format_name = pht('Unknown ("%s")', $format_key);304}305}306$finfo->addProperty(pht('Storage Format'), $format_name);307308$finfo->addProperty(309pht('Storage Handle'),310$file->getStorageHandle());311312$custom_alt = $file->getCustomAltText();313if ($custom_alt !== null && strlen($custom_alt)) {314$finfo->addProperty(pht('Custom Alt Text'), $custom_alt);315}316317$default_alt = $file->getDefaultAltText();318if ($default_alt !== null && strlen($default_alt)) {319$finfo->addProperty(pht('Default Alt Text'), $default_alt);320}321322$attachments_table = $this->newAttachmentsView($file);323324$tab_group->addTab(325id(new PHUITabView())326->setName(pht('Attached'))327->setKey('attached')328->appendChild($attachments_table));329330$engine = $this->loadStorageEngine($file);331if ($engine) {332if ($engine->isChunkEngine()) {333$chunkinfo = new PHUIPropertyListView();334335$tab_group->addTab(336id(new PHUITabView())337->setName(pht('Chunks'))338->setKey('chunks')339->appendChild($chunkinfo));340341$chunks = id(new PhabricatorFileChunkQuery())342->setViewer($viewer)343->withChunkHandles(array($file->getStorageHandle()))344->execute();345$chunks = msort($chunks, 'getByteStart');346347$rows = array();348$completed = array();349foreach ($chunks as $chunk) {350$is_complete = $chunk->getDataFilePHID();351352$rows[] = array(353$chunk->getByteStart(),354$chunk->getByteEnd(),355($is_complete ? pht('Yes') : pht('No')),356);357358if ($is_complete) {359$completed[] = $chunk;360}361}362363$table = id(new AphrontTableView($rows))364->setHeaders(365array(366pht('Offset'),367pht('End'),368pht('Complete'),369))370->setColumnClasses(371array(372'',373'',374'wide',375));376377$chunkinfo->addProperty(378pht('Total Chunks'),379count($chunks));380381$chunkinfo->addProperty(382pht('Completed Chunks'),383count($completed));384385$chunkinfo->addRawContent($table);386}387}388389}390391private function loadStorageEngine(PhabricatorFile $file) {392$engine = null;393394try {395$engine = $file->instantiateStorageEngine();396} catch (Exception $ex) {397// Don't bother raising this anywhere for now.398}399400return $engine;401}402403private function newFileContent(PhabricatorFile $file) {404$request = $this->getRequest();405406$ref = id(new PhabricatorDocumentRef())407->setFile($file);408409$engine = id(new PhabricatorFileDocumentRenderingEngine())410->setRequest($request);411412return $engine->newDocumentView($ref);413}414415private function newAttachmentsView(PhabricatorFile $file) {416$viewer = $this->getViewer();417418$attachments = id(new PhabricatorFileAttachmentQuery())419->setViewer($viewer)420->withFilePHIDs(array($file->getPHID()))421->execute();422423$handles = $viewer->loadHandles(mpull($attachments, 'getObjectPHID'));424425$rows = array();426427$mode_map = PhabricatorFileAttachment::getModeNameMap();428$mode_attach = PhabricatorFileAttachment::MODE_ATTACH;429430foreach ($attachments as $attachment) {431$object_phid = $attachment->getObjectPHID();432$handle = $handles[$object_phid];433434$attachment_mode = $attachment->getAttachmentMode();435436$mode_name = idx($mode_map, $attachment_mode);437if ($mode_name === null) {438$mode_name = pht('Unknown ("%s")', $attachment_mode);439}440441$detach_uri = urisprintf(442'/file/ui/detach/%s/%s/',443$object_phid,444$file->getPHID());445446$is_disabled = !$attachment->canDetach();447448$detach_button = id(new PHUIButtonView())449->setHref($detach_uri)450->setTag('a')451->setWorkflow(true)452->setDisabled($is_disabled)453->setColor(PHUIButtonView::GREY)454->setSize(PHUIButtonView::SMALL)455->setText(pht('Detach File'));456457javelin_tag(458'a',459array(460'href' => $detach_uri,461'sigil' => 'workflow',462'disabled' => true,463'class' => 'small button button-grey disabled',464),465pht('Detach File'));466467$rows[] = array(468$handle->renderLink(),469$mode_name,470$detach_button,471);472}473474$table = id(new AphrontTableView($rows))475->setHeaders(476array(477pht('Attached To'),478pht('Mode'),479null,480))481->setColumnClasses(482array(483'pri wide',484null,485null,486));487488return $table;489}490491492}493494495