Page MenuHomePhabricator

D7728.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2187,6 +2187,7 @@
'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 @@
'PhragmentPHIDTypeFragmentVersion' => 'PhabricatorPHIDType',
'PhragmentPatchUtil' => 'Phobject',
'PhragmentUpdateController' => 'PhragmentController',
+ 'PhragmentZIPController' => 'PhragmentController',
'PhrequentController' => 'PhabricatorController',
'PhrequentDAO' => 'PhabricatorLiskDAO',
'PhrequentListController' =>
diff --git a/src/applications/phragment/application/PhabricatorApplicationPhragment.php b/src/applications/phragment/application/PhabricatorApplicationPhragment.php
--- a/src/applications/phragment/application/PhabricatorApplicationPhragment.php
+++ b/src/applications/phragment/application/PhabricatorApplicationPhragment.php
@@ -38,6 +38,7 @@
'create/(?P<dblob>.*)' => 'PhragmentCreateController',
'update/(?P<dblob>.*)' => 'PhragmentUpdateController',
'history/(?P<dblob>.*)' => 'PhragmentHistoryController',
+ 'zip/(?P<dblob>.*)' => 'PhragmentZIPController',
),
);
}
diff --git a/src/applications/phragment/controller/PhragmentController.php b/src/applications/phragment/controller/PhragmentController.php
--- a/src/applications/phragment/controller/PhragmentController.php
+++ b/src/applications/phragment/controller/PhragmentController.php
@@ -92,6 +92,12 @@
->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'))
->setHref($this->getApplicationURI("update/".$fragment->getPath()))
->setDisabled(false) // TODO: Policy
diff --git a/src/applications/phragment/controller/PhragmentZIPController.php b/src/applications/phragment/controller/PhragmentZIPController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phragment/controller/PhragmentZIPController.php
@@ -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;
+ }
+ }
+
+}

File Metadata

Mime Type
text/x-diff
Storage Engine
amazon-s3
Storage Format
Raw Data
Storage Handle
phabricator/se/ov/k5fsmpy5lqtjlbya
Default Alt Text
D7728.diff (6 KB)

Event Timeline