From 420235f9c4e1a25d6afb1e6eed2896307be8d09e Mon Sep 17 00:00:00 2001 From: Ricky Elrod Date: Fri, 8 Jul 2011 00:17:00 -0400 Subject: [PATCH] Drag-drop file upload. Summary: - have files be uploaded by drag+drop instead of browse. - Files are named by their uploaded filename, the user isn't given a chance to enter a file name. Is this bad? - Store author PHID now with files - Allow an ?author= to limit the /files/ list by author. - If one file is uploaded, the user is taken to its info page. - If several are uploaded, they are taken to a list of their files. Test Plan: - Quickly tested everything and it still worked, I'd recommend some people try this out before it gets committed though. It's a rather huge revision. Reviewers: epriestley, Ttech CC: Differential Revision: 612 --- .../sql/patches/055.add_author_to_files.sql | 3 ++ ...atorOAuthDefaultRegistrationController.php | 3 +- .../upload/ConduitAPI_file_upload_Method.php | 4 +- .../PhabricatorFileDropUploadController.php | 2 + .../list/PhabricatorFileListController.php | 27 ++++++++++-- .../files/controller/list/__init__.php | 2 + .../PhabricatorFileMacroEditController.php | 2 + .../PhabricatorFileUploadController.php | 42 ++++++++++--------- .../files/controller/upload/__init__.php | 5 +-- .../view/PhabricatorFileViewController.php | 17 +++++++- .../files/controller/view/__init__.php | 1 + .../files/storage/file/PhabricatorFile.php | 6 +++ .../ManiphestTransactionSaveController.php | 6 ++- ...icatorMetaMTASendGridReceiveController.php | 7 +++- .../PhabricatorPasteCreateController.php | 1 + ...PhabricatorPeopleProfileEditController.php | 6 ++- .../PhabricatorUserSettingsController.php | 6 ++- ...habricatorProjectProfileEditController.php | 6 ++- 18 files changed, 112 insertions(+), 34 deletions(-) create mode 100644 resources/sql/patches/055.add_author_to_files.sql diff --git a/resources/sql/patches/055.add_author_to_files.sql b/resources/sql/patches/055.add_author_to_files.sql new file mode 100644 index 0000000000..f6947fbf80 --- /dev/null +++ b/resources/sql/patches/055.add_author_to_files.sql @@ -0,0 +1,3 @@ +ALTER TABLE phabricator_file.file + ADD COLUMN authorPHID VARCHAR(64) BINARY, + ADD KEY (authorPHID); \ No newline at end of file diff --git a/src/applications/auth/controller/oauthregistration/default/PhabricatorOAuthDefaultRegistrationController.php b/src/applications/auth/controller/oauthregistration/default/PhabricatorOAuthDefaultRegistrationController.php index a748c3e274..aeea60db19 100644 --- a/src/applications/auth/controller/oauthregistration/default/PhabricatorOAuthDefaultRegistrationController.php +++ b/src/applications/auth/controller/oauthregistration/default/PhabricatorOAuthDefaultRegistrationController.php @@ -76,7 +76,8 @@ class PhabricatorOAuthDefaultRegistrationController $file = PhabricatorFile::newFromFileData( $image, array( - 'name' => $provider->getProviderKey().'-profile.jpg' + 'name' => $provider->getProviderKey().'-profile.jpg', + 'authorPHID' => $user->getPHID(), )); $user->setProfileImagePHID($file->getPHID()); } diff --git a/src/applications/conduit/method/file/upload/ConduitAPI_file_upload_Method.php b/src/applications/conduit/method/file/upload/ConduitAPI_file_upload_Method.php index 4dd4897277..b0189008da 100644 --- a/src/applications/conduit/method/file/upload/ConduitAPI_file_upload_Method.php +++ b/src/applications/conduit/method/file/upload/ConduitAPI_file_upload_Method.php @@ -45,11 +45,13 @@ class ConduitAPI_file_upload_Method extends ConduitAPIMethod { $data = $request->getValue('data_base64'); $name = $request->getValue('name'); $data = base64_decode($data, $strict = true); + $user = $request->getUser(); $file = PhabricatorFile::newFromFileData( $data, array( - 'name' => $name + 'name' => $name, + 'authorPHID' => $user->getPHID(), )); return $file->getPHID(); } diff --git a/src/applications/files/controller/dropupload/PhabricatorFileDropUploadController.php b/src/applications/files/controller/dropupload/PhabricatorFileDropUploadController.php index d50fbd181a..2f676ebff3 100644 --- a/src/applications/files/controller/dropupload/PhabricatorFileDropUploadController.php +++ b/src/applications/files/controller/dropupload/PhabricatorFileDropUploadController.php @@ -20,6 +20,7 @@ class PhabricatorFileDropUploadController extends PhabricatorFileController { public function processRequest() { $request = $this->getRequest(); + $user = $request->getUser(); $data = file_get_contents('php://input'); $name = $request->getStr('name'); @@ -28,6 +29,7 @@ class PhabricatorFileDropUploadController extends PhabricatorFileController { $data, array( 'name' => $request->getStr('name'), + 'authorPHID' => $user->getPHID(), )); $view = new AphrontAttachedFileView(); diff --git a/src/applications/files/controller/list/PhabricatorFileListController.php b/src/applications/files/controller/list/PhabricatorFileListController.php index 92a3035f5a..f78af9fd2c 100644 --- a/src/applications/files/controller/list/PhabricatorFileListController.php +++ b/src/applications/files/controller/list/PhabricatorFileListController.php @@ -22,13 +22,32 @@ class PhabricatorFileListController extends PhabricatorFileController { $request = $this->getRequest(); + $author_username = $request->getStr('author'); + if ($author_username) { + $author = id(new PhabricatorUser())->loadOneWhere( + 'userName = %s', + $author_username); + + if (!$author) { + return id(new Aphront404Response()); + } + } + $pager = new AphrontPagerView(); $pager->setOffset($request->getInt('page')); - $files = id(new PhabricatorFile())->loadAllWhere( - '1 = 1 ORDER BY id DESC LIMIT %d, %d', - $pager->getOffset(), - $pager->getPageSize() + 1); + if ($author) { + $files = id(new PhabricatorFile())->loadAllWhere( + 'authorPHID = %s ORDER BY id DESC LIMIT %d, %d', + $author->getPHID(), + $pager->getOffset(), + $pager->getPageSize() + 1); + } else { + $files = id(new PhabricatorFile())->loadAllWhere( + '1 = 1 ORDER BY id DESC LIMIT %d, %d', + $pager->getOffset(), + $pager->getPageSize() + 1); + } $files = $pager->sliceResults($files); $pager->setURI($request->getRequestURI(), 'page'); diff --git a/src/applications/files/controller/list/__init__.php b/src/applications/files/controller/list/__init__.php index 3bdf0dba19..d858fc288e 100644 --- a/src/applications/files/controller/list/__init__.php +++ b/src/applications/files/controller/list/__init__.php @@ -6,8 +6,10 @@ +phutil_require_module('phabricator', 'aphront/response/404'); phutil_require_module('phabricator', 'applications/files/controller/base'); phutil_require_module('phabricator', 'applications/files/storage/file'); +phutil_require_module('phabricator', 'applications/people/storage/user'); phutil_require_module('phabricator', 'view/control/pager'); phutil_require_module('phabricator', 'view/control/table'); phutil_require_module('phabricator', 'view/layout/panel'); diff --git a/src/applications/files/controller/macroedit/PhabricatorFileMacroEditController.php b/src/applications/files/controller/macroedit/PhabricatorFileMacroEditController.php index 1b086d0112..cb0c576417 100644 --- a/src/applications/files/controller/macroedit/PhabricatorFileMacroEditController.php +++ b/src/applications/files/controller/macroedit/PhabricatorFileMacroEditController.php @@ -39,6 +39,7 @@ class PhabricatorFileMacroEditController extends PhabricatorFileController { $e_name = true; $request = $this->getRequest(); + $user = $request->getUser(); if ($request->isFormPost()) { $macro->setName($request->getStr('name')); @@ -60,6 +61,7 @@ class PhabricatorFileMacroEditController extends PhabricatorFileController { idx($_FILES, 'file'), array( 'name' => $request->getStr('name'), + 'authorPHID' => $user->getPHID(), )); $macro->setFilePHID($file->getPHID()); diff --git a/src/applications/files/controller/upload/PhabricatorFileUploadController.php b/src/applications/files/controller/upload/PhabricatorFileUploadController.php index 9d4b9e2be2..5bb5f2c333 100644 --- a/src/applications/files/controller/upload/PhabricatorFileUploadController.php +++ b/src/applications/files/controller/upload/PhabricatorFileUploadController.php @@ -21,43 +21,47 @@ class PhabricatorFileUploadController extends PhabricatorFileController { public function processRequest() { $request = $this->getRequest(); - if ($request->isFormPost()) { - $file = PhabricatorFile::newFromPHPUpload( - idx($_FILES, 'file'), - array( - 'name' => $request->getStr('name'), - )); + $user = $request->getUser(); - return id(new AphrontRedirectResponse()) - ->setURI('/file/info/'.phutil_escape_uri($file->getPHID()).'/'); + if ($request->isFormPost()) { + $files = $request->getArr('file'); + + if (count($files) > 1) { + return id(new AphrontRedirectResponse()) + ->setURI('/file/?author='.phutil_escape_uri($user->getUserName())); + } else { + return id(new AphrontRedirectResponse()) + ->setURI('/file/info/'.end($files).'/'); + } } + $panel_id = celerity_generate_unique_node_id(); + $form = new AphrontFormView(); $form->setAction('/file/upload/'); $form->setUser($request->getUser()); $form ->setEncType('multipart/form-data') + ->appendChild( - id(new AphrontFormFileControl()) - ->setLabel('File') - ->setName('file') - ->setError(true)) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel('Name') - ->setName('name') - ->setCaption('Optional file display name.')) + id(new AphrontFormDragAndDropUploadControl()) + ->setLabel('Files') + ->setName('file') + ->setError(true) + ->setDragAndDropTarget($panel_id) + ->setActivatedClass('aphront-panel-view-drag-and-drop')) + ->appendChild( id(new AphrontFormSubmitControl()) - ->setValue('Upload') - ->addCancelButton('/file/')); + ->setValue('Done here!')); $panel = new AphrontPanelView(); $panel->setHeader('Upload File'); $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_FORM); + $panel->setID($panel_id); return $this->buildStandardPageResponse( array($panel), diff --git a/src/applications/files/controller/upload/__init__.php b/src/applications/files/controller/upload/__init__.php index 1df8898806..8867ecb9c3 100644 --- a/src/applications/files/controller/upload/__init__.php +++ b/src/applications/files/controller/upload/__init__.php @@ -8,11 +8,10 @@ phutil_require_module('phabricator', 'aphront/response/redirect'); phutil_require_module('phabricator', 'applications/files/controller/base'); -phutil_require_module('phabricator', 'applications/files/storage/file'); +phutil_require_module('phabricator', 'infrastructure/celerity/api'); phutil_require_module('phabricator', 'view/form/base'); -phutil_require_module('phabricator', 'view/form/control/file'); +phutil_require_module('phabricator', 'view/form/control/draganddropupload'); phutil_require_module('phabricator', 'view/form/control/submit'); -phutil_require_module('phabricator', 'view/form/control/text'); phutil_require_module('phabricator', 'view/layout/panel'); phutil_require_module('phutil', 'markup'); diff --git a/src/applications/files/controller/view/PhabricatorFileViewController.php b/src/applications/files/controller/view/PhabricatorFileViewController.php index b13acb5b19..a4e035e2c3 100644 --- a/src/applications/files/controller/view/PhabricatorFileViewController.php +++ b/src/applications/files/controller/view/PhabricatorFileViewController.php @@ -71,6 +71,20 @@ class PhabricatorFileViewController extends PhabricatorFileController { break; } + $author_child = null; + if ($file->getAuthorPHID()) { + $author = id(new PhabricatorUser())->loadOneWhere( + 'phid = %s', + $file->getAuthorPHID()); + + if ($author) { + $author_child = id(new AphrontFormStaticControl()) + ->setLabel('Author') + ->setName('author') + ->setValue($author->getUserName()); + } + } + $form = new AphrontFormView(); if ($file->isViewableInBrowser()) { @@ -80,7 +94,7 @@ class PhabricatorFileViewController extends PhabricatorFileController { $form->setAction('/file/download/'.$file->getPHID().'/'); $button_name = 'Download File'; } - $form->setUser($this->getRequest()->getUser()); + $form->setUser($user); $form ->appendChild( id(new AphrontFormStaticControl()) @@ -92,6 +106,7 @@ class PhabricatorFileViewController extends PhabricatorFileController { ->setLabel('PHID') ->setName('phid') ->setValue($file->getPHID())) + ->appendChild($author_child) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel('Created') diff --git a/src/applications/files/controller/view/__init__.php b/src/applications/files/controller/view/__init__.php index 36cba91615..f6dbd0e152 100644 --- a/src/applications/files/controller/view/__init__.php +++ b/src/applications/files/controller/view/__init__.php @@ -13,6 +13,7 @@ phutil_require_module('phabricator', 'applications/files/controller/base'); phutil_require_module('phabricator', 'applications/files/storage/file'); phutil_require_module('phabricator', 'applications/files/storage/transformed'); phutil_require_module('phabricator', 'applications/files/uri'); +phutil_require_module('phabricator', 'applications/people/storage/user'); phutil_require_module('phabricator', 'view/control/table'); phutil_require_module('phabricator', 'view/form/base'); phutil_require_module('phabricator', 'view/form/control/static'); diff --git a/src/applications/files/storage/file/PhabricatorFile.php b/src/applications/files/storage/file/PhabricatorFile.php index 0c70be9320..57c702d24e 100644 --- a/src/applications/files/storage/file/PhabricatorFile.php +++ b/src/applications/files/storage/file/PhabricatorFile.php @@ -29,6 +29,7 @@ class PhabricatorFile extends PhabricatorFileDAO { protected $name; protected $mimeType; protected $byteSize; + protected $authorPHID; protected $storageEngine; protected $storageFormat; @@ -88,9 +89,14 @@ class PhabricatorFile extends PhabricatorFileDAO { $file_name = idx($params, 'name'); $file_name = self::normalizeFileName($file_name); + // If for whatever reason, authorPHID isn't passed as a param + // (always the case with newFromFileDownload()), store a '' + $authorPHID = idx($params, 'authorPHID'); + $file = new PhabricatorFile(); $file->setName($file_name); $file->setByteSize(strlen($data)); + $file->setAuthorPHID($authorPHID); $blob = new PhabricatorFileStorageBlob(); $blob->setData($data); diff --git a/src/applications/maniphest/controller/transactionsave/ManiphestTransactionSaveController.php b/src/applications/maniphest/controller/transactionsave/ManiphestTransactionSaveController.php index 99e95f6088..49bbc6a065 100644 --- a/src/applications/maniphest/controller/transactionsave/ManiphestTransactionSaveController.php +++ b/src/applications/maniphest/controller/transactionsave/ManiphestTransactionSaveController.php @@ -53,7 +53,11 @@ class ManiphestTransactionSaveController extends ManiphestController { if (!empty($_FILES['file'])) { $err = idx($_FILES['file'], 'error'); if ($err != UPLOAD_ERR_NO_FILE) { - $file = PhabricatorFile::newFromPHPUpload($_FILES['file']); + $file = PhabricatorFile::newFromPHPUpload( + $_FILES['file'], + array( + 'authorPHID' => $user->getPHID(), + )); $files[] = $file; } } diff --git a/src/applications/metamta/controller/sendgridreceive/PhabricatorMetaMTASendGridReceiveController.php b/src/applications/metamta/controller/sendgridreceive/PhabricatorMetaMTASendGridReceiveController.php index 281eef3559..be18f7c2d9 100644 --- a/src/applications/metamta/controller/sendgridreceive/PhabricatorMetaMTASendGridReceiveController.php +++ b/src/applications/metamta/controller/sendgridreceive/PhabricatorMetaMTASendGridReceiveController.php @@ -26,6 +26,7 @@ class PhabricatorMetaMTASendGridReceiveController public function processRequest() { $request = $this->getRequest(); + $user = $request->getUser(); $raw_headers = $request->getStr('headers'); $raw_headers = explode("\n", rtrim($raw_headers)); @@ -51,7 +52,11 @@ class PhabricatorMetaMTASendGridReceiveController $file_phids = array(); foreach ($_FILES as $file_raw) { try { - $file = PhabricatorFile::newFromPHPUpload($file_raw); + $file = PhabricatorFile::newFromPHPUpload( + $file_raw, + array( + 'authorPHID' => $user->getPHID(), + )); $file_phids[] = $file->getPHID(); } catch (Exception $ex) { phlog($ex); diff --git a/src/applications/paste/controller/create/PhabricatorPasteCreateController.php b/src/applications/paste/controller/create/PhabricatorPasteCreateController.php index e56b400e05..5fb13d950c 100644 --- a/src/applications/paste/controller/create/PhabricatorPasteCreateController.php +++ b/src/applications/paste/controller/create/PhabricatorPasteCreateController.php @@ -59,6 +59,7 @@ class PhabricatorPasteCreateController extends PhabricatorPasteController { array( 'name' => $title, 'mime-type' => 'text/plain; charset=utf-8', + 'authorPHID' => $user->getPHID(), )); $paste->setFilePHID($paste_file->getPHID()); $paste->setAuthorPHID($user->getPHID()); diff --git a/src/applications/people/controller/profileedit/PhabricatorPeopleProfileEditController.php b/src/applications/people/controller/profileedit/PhabricatorPeopleProfileEditController.php index 48e3db955e..8ec1e222a3 100644 --- a/src/applications/people/controller/profileedit/PhabricatorPeopleProfileEditController.php +++ b/src/applications/people/controller/profileedit/PhabricatorPeopleProfileEditController.php @@ -40,7 +40,11 @@ class PhabricatorPeopleProfileEditController if (!empty($_FILES['image'])) { $err = idx($_FILES['image'], 'error'); if ($err != UPLOAD_ERR_NO_FILE) { - $file = PhabricatorFile::newFromPHPUpload($_FILES['image']); + $file = PhabricatorFile::newFromPHPUpload( + $_FILES['image'], + array( + 'authorPHID' => $user->getPHID(), + )); $okay = $file->isTransformableImage(); if ($okay) { $xformer = new PhabricatorImageTransformer(); diff --git a/src/applications/people/controller/settings/PhabricatorUserSettingsController.php b/src/applications/people/controller/settings/PhabricatorUserSettingsController.php index dfe1f877c4..024ed82630 100644 --- a/src/applications/people/controller/settings/PhabricatorUserSettingsController.php +++ b/src/applications/people/controller/settings/PhabricatorUserSettingsController.php @@ -117,7 +117,11 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController { if (!empty($_FILES['profile'])) { $err = idx($_FILES['profile'], 'error'); if ($err != UPLOAD_ERR_NO_FILE) { - $file = PhabricatorFile::newFromPHPUpload($_FILES['profile']); + $file = PhabricatorFile::newFromPHPUpload( + $_FILES['profile'], + array( + 'authorPHID' => $user->getPHID(), + )); $okay = $file->isTransformableImage(); if ($okay) { $xformer = new PhabricatorImageTransformer(); diff --git a/src/applications/project/controller/profileedit/PhabricatorProjectProfileEditController.php b/src/applications/project/controller/profileedit/PhabricatorProjectProfileEditController.php index cef8edb283..55b0c1c218 100644 --- a/src/applications/project/controller/profileedit/PhabricatorProjectProfileEditController.php +++ b/src/applications/project/controller/profileedit/PhabricatorProjectProfileEditController.php @@ -57,7 +57,11 @@ class PhabricatorProjectProfileEditController if (!empty($_FILES['image'])) { $err = idx($_FILES['image'], 'error'); if ($err != UPLOAD_ERR_NO_FILE) { - $file = PhabricatorFile::newFromPHPUpload($_FILES['image']); + $file = PhabricatorFile::newFromPHPUpload( + $_FILES['image'], + array( + 'authorPHID' => $user->getPHID(), + )); $okay = $file->isTransformableImage(); if ($okay) { $xformer = new PhabricatorImageTransformer();