1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-20 20:40:56 +01:00

Implement "Download ZIP" controller for Phragment

Summary: Depends on D7727.  This adds support for downloading a fragment and all it's children as a ZIP file.  Fragments that have children automatically become directories in the ZIP file.

Test Plan: Downloaded a fragment as a ZIP and was able to extract the contents successfully.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley

CC: Korvin, epriestley, aran

Maniphest Tasks: T4205

Differential Revision: https://secure.phabricator.com/D7728
This commit is contained in:
James Rhodes 2013-12-07 13:25:22 +11:00
parent f7f5a5dd34
commit ccd4ae5638
4 changed files with 120 additions and 0 deletions

View file

@ -2187,6 +2187,7 @@ phutil_register_library_map(array(
'PhragmentPHIDTypeFragmentVersion' => 'applications/phragment/phid/PhragmentPHIDTypeFragmentVersion.php',
'PhragmentPatchUtil' => 'applications/phragment/util/PhragmentPatchUtil.php',
'PhragmentUpdateController' => 'applications/phragment/controller/PhragmentUpdateController.php',
'PhragmentZIPController' => 'applications/phragment/controller/PhragmentZIPController.php',
'PhrequentController' => 'applications/phrequent/controller/PhrequentController.php',
'PhrequentDAO' => 'applications/phrequent/storage/PhrequentDAO.php',
'PhrequentListController' => 'applications/phrequent/controller/PhrequentListController.php',
@ -4785,6 +4786,7 @@ phutil_register_library_map(array(
'PhragmentPHIDTypeFragmentVersion' => 'PhabricatorPHIDType',
'PhragmentPatchUtil' => 'Phobject',
'PhragmentUpdateController' => 'PhragmentController',
'PhragmentZIPController' => 'PhragmentController',
'PhrequentController' => 'PhabricatorController',
'PhrequentDAO' => 'PhabricatorLiskDAO',
'PhrequentListController' =>

View file

@ -38,6 +38,7 @@ final class PhabricatorApplicationPhragment extends PhabricatorApplication {
'create/(?P<dblob>.*)' => 'PhragmentCreateController',
'update/(?P<dblob>.*)' => 'PhragmentUpdateController',
'history/(?P<dblob>.*)' => 'PhragmentHistoryController',
'zip/(?P<dblob>.*)' => 'PhragmentZIPController',
),
);
}

View file

@ -90,6 +90,12 @@ abstract class PhragmentController extends PhabricatorController {
->setHref($file_uri)
->setDisabled($file === null)
->setIcon('download'));
$actions->addAction(
id(new PhabricatorActionView())
->setName(pht('Download Contents as ZIP'))
->setHref($this->getApplicationURI("zip/".$fragment->getPath()))
->setDisabled(false) // TODO: Policy
->setIcon('zip'));
$actions->addAction(
id(new PhabricatorActionView())
->setName(pht('Update Fragment'))

View file

@ -0,0 +1,111 @@
<?php
final class PhragmentZIPController extends PhragmentController {
private $dblob;
public function willProcessRequest(array $data) {
$this->dblob = idx($data, "dblob", "");
}
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
$parents = $this->loadParentFragments($this->dblob);
if ($parents === null) {
return new Aphront404Response();
}
$fragment = idx($parents, count($parents) - 1, null);
$temp = new TempFile();
$zip = null;
try {
$zip = new ZipArchive();
} catch (Exception $e) {
$dialog = new AphrontDialogView();
$dialog->setUser($viewer);
$inst = pht(
'This system does not have the ZIP PHP extension installed. This '.
'is required to download ZIPs from Phragment.');
$dialog->setTitle(pht('ZIP Extension Not Installed'));
$dialog->appendParagraph($inst);
$dialog->addCancelButton('/phragment/browse/'.$this->dblob);
return id(new AphrontDialogResponse())->setDialog($dialog);
}
if (!$zip->open((string)$temp, ZipArchive::CREATE)) {
throw new Exception("Unable to create ZIP archive!");
}
$mappings = $this->getFragmentMappings($fragment, $fragment->getPath());
$phids = array();
foreach ($mappings as $path => $file_phid) {
$phids[] = $file_phid;
}
$files = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs($phids)
->execute();
$files = mpull($files, null, 'getPHID');
foreach ($mappings as $path => $file_phid) {
if (!isset($files[$file_phid])) {
unset($mappings[$path]);
}
$mappings[$path] = $files[$file_phid];
}
foreach ($mappings as $path => $file) {
$zip->addFromString($path, $file->loadFileData());
}
$zip->close();
$zip_name = $fragment->getName();
if (substr($zip_name, -4) !== '.zip') {
$zip_name .= '.zip';
}
$data = Filesystem::readFile((string)$temp);
$file = PhabricatorFile::buildFromFileDataOrHash(
$data,
array(
'name' => $zip_name,
'ttl' => time() + 60 * 60 * 24,
));
return id(new AphrontRedirectResponse())
->setURI($file->getBestURI());
}
/**
* Returns a list of mappings like array('some/path.txt' => 'file PHID');
*/
private function getFragmentMappings(PhragmentFragment $current, $base_path) {
$children = id(new PhragmentFragmentQuery())
->setViewer($this->getRequest()->getUser())
->needLatestVersion(true)
->withLeadingPath($current->getPath().'/')
->withDepths(array($current->getDepth() + 1))
->execute();
if (count($children) === 0) {
$path = substr($current->getPath(), strlen($base_path) + 1);
return array($path => $current->getLatestVersion()->getFilePHID());
} else {
$mappings = array();
foreach ($children as $child) {
$child_mappings = $this->getFragmentMappings($child, $base_path);
foreach ($child_mappings as $key => $value) {
$mappings[$key] = $value;
}
}
return $mappings;
}
}
}