public function render()
 {
     $viewer = $this->getViewer();
     if (!$viewer->isLoggedIn()) {
         return null;
     }
     $instructions_id = 'phabricator-global-drag-and-drop-upload-instructions';
     require_celerity_resource('global-drag-and-drop-css');
     $hint_text = $this->getHintText();
     if (!strlen($hint_text)) {
         $hint_text = "⇪ " . pht('Drop Files to Upload');
     }
     // Use the configured default view policy. Drag and drop uploads use
     // a more restrictive view policy if we don't specify a policy explicitly,
     // as the more restrictive policy is correct for most drop targets (like
     // Pholio uploads and Remarkup text areas).
     $view_policy = $this->getViewPolicy();
     if ($view_policy === null) {
         $view_policy = PhabricatorFile::initializeNewFile()->getViewPolicy();
     }
     $submit_uri = $this->getSubmitURI();
     $done_uri = '/file/query/authored/';
     Javelin::initBehavior('global-drag-and-drop', array('ifSupported' => $this->showIfSupportedID, 'instructions' => $instructions_id, 'uploadURI' => '/file/dropupload/', 'submitURI' => $submit_uri, 'browseURI' => $done_uri, 'viewPolicy' => $view_policy, 'chunkThreshold' => PhabricatorFileStorageEngine::getChunkThreshold()));
     return phutil_tag('div', array('id' => $instructions_id, 'class' => 'phabricator-global-upload-instructions', 'style' => 'display: none;'), $hint_text);
 }
 protected final function executeQuery()
 {
     $future = $this->newQueryFuture();
     $drequest = $this->getRequest();
     $name = basename($drequest->getPath());
     $ttl = PhabricatorTime::getNow() + phutil_units('48 hours in seconds');
     try {
         $threshold = PhabricatorFileStorageEngine::getChunkThreshold();
         $future->setReadBufferSize($threshold);
         $source = id(new PhabricatorExecFutureFileUploadSource())->setName($name)->setTTL($ttl)->setViewPolicy(PhabricatorPolicies::POLICY_NOONE)->setExecFuture($future);
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         $file = $source->uploadFile();
         unset($unguarded);
     } catch (CommandException $ex) {
         if (!$future->getWasKilledByTimeout()) {
             throw $ex;
         }
         $this->didHitTimeLimit = true;
         $file = null;
     }
     $byte_limit = $this->getByteLimit();
     if ($byte_limit && $file->getByteSize() > $byte_limit) {
         $this->didHitByteLimit = true;
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         id(new PhabricatorDestructionEngine())->destroyObject($file);
         unset($unguarded);
         $file = null;
     }
     return $file;
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $viewer = $request->getUser();
     $hash = $request->getValue('contentHash');
     $name = $request->getValue('name');
     $view_policy = $request->getValue('viewPolicy');
     $length = $request->getValue('contentLength');
     $properties = array('name' => $name, 'authorPHID' => $viewer->getPHID(), 'viewPolicy' => $view_policy, 'isExplicitUpload' => true);
     $ttl = $request->getValue('deleteAfterEpoch');
     if ($ttl) {
         $properties['ttl'] = $ttl;
     }
     $file = null;
     if ($hash) {
         $file = PhabricatorFile::newFileFromContentHash($hash, $properties);
     }
     if ($hash && !$file) {
         $chunked_hash = PhabricatorChunkedFileStorageEngine::getChunkedHash($viewer, $hash);
         $file = id(new PhabricatorFileQuery())->setViewer($viewer)->withContentHashes(array($chunked_hash))->executeOne();
     }
     if (strlen($name) && !$hash && !$file) {
         if ($length > PhabricatorFileStorageEngine::getChunkThreshold()) {
             // If we don't have a hash, but this file is large enough to store in
             // chunks and thus may be resumable, try to find a partially uploaded
             // file by the same author with the same name and same length. This
             // allows us to resume uploads in Javascript where we can't efficiently
             // compute file hashes.
             $file = id(new PhabricatorFileQuery())->setViewer($viewer)->withAuthorPHIDs(array($viewer->getPHID()))->withNames(array($name))->withLengthBetween($length, $length)->withIsPartial(true)->setLimit(1)->executeOne();
         }
     }
     if ($file) {
         return array('upload' => (bool) $file->getIsPartial(), 'filePHID' => $file->getPHID());
     }
     // If there are any non-chunk engines which this file can fit into,
     // just tell the client to upload the file.
     $engines = PhabricatorFileStorageEngine::loadStorageEngines($length);
     if ($engines) {
         return array('upload' => true, 'filePHID' => null);
     }
     // Otherwise, this is a large file and we want to perform a chunked
     // upload if we have a chunk engine available.
     $chunk_engines = PhabricatorFileStorageEngine::loadWritableChunkEngines();
     if ($chunk_engines) {
         $chunk_properties = $properties;
         if ($hash) {
             $chunk_properties += array('chunkedHash' => $chunked_hash);
         }
         $chunk_engine = head($chunk_engines);
         $file = $chunk_engine->allocateChunks($length, $chunk_properties);
         return array('upload' => true, 'filePHID' => $file->getPHID());
     }
     // None of the storage engines can accept this file.
     if (PhabricatorFileStorageEngine::loadWritableEngines()) {
         $error = pht('Unable to upload file: this file is too large for any ' . 'configured storage engine.');
     } else {
         $error = pht('Unable to upload file: the server is not configured with any ' . 'writable storage engines.');
     }
     return array('upload' => false, 'filePHID' => null, 'error' => $error);
 }
 public function execute(PhutilArgumentParser $args)
 {
     $iterator = $this->buildIterator($args);
     if (!$iterator) {
         throw new PhutilArgumentUsageException(pht('Either specify a list of files to encode, or use --all to ' . 'encode all files.'));
     }
     $force = (bool) $args->getArg('force');
     $format_list = PhabricatorFileStorageFormat::getAllFormats();
     $format_list = array_keys($format_list);
     $format_list = implode(', ', $format_list);
     $format_key = $args->getArg('as');
     if (!strlen($format_key)) {
         throw new PhutilArgumentUsageException(pht('Use --as <format> to select a target encoding format. Available ' . 'formats are: %s.', $format_list));
     }
     $format = PhabricatorFileStorageFormat::getFormat($format_key);
     if (!$format) {
         throw new PhutilArgumentUsageException(pht('Storage format "%s" is not valid. Available formats are: %s.', $format_key, $format_list));
     }
     $key_name = $args->getArg('key');
     if (strlen($key_name)) {
         $format->selectMasterKey($key_name);
     }
     $engines = PhabricatorFileStorageEngine::loadAllEngines();
     $failed = array();
     foreach ($iterator as $file) {
         $monogram = $file->getMonogram();
         $engine_key = $file->getStorageEngine();
         $engine = idx($engines, $engine_key);
         if (!$engine) {
             echo tsprintf("%s\n", pht('%s: Uses unknown storage engine "%s".', $monogram, $engine_key));
             $failed[] = $file;
             continue;
         }
         if ($engine->isChunkEngine()) {
             echo tsprintf("%s\n", pht('%s: Stored as chunks, no data to encode directly.', $monogram));
             continue;
         }
         if ($file->getStorageFormat() == $format_key && !$force) {
             echo tsprintf("%s\n", pht('%s: Already encoded in target format.', $monogram));
             continue;
         }
         echo tsprintf("%s\n", pht('%s: Changing encoding from "%s" to "%s".', $monogram, $file->getStorageFormat(), $format_key));
         try {
             $file->migrateToStorageFormat($format);
             echo tsprintf("%s\n", pht('Done.'));
         } catch (Exception $ex) {
             echo tsprintf("%B\n", pht('Failed! %s', (string) $ex));
             $failed[] = $file;
         }
     }
     if ($failed) {
         $monograms = mpull($failed, 'getMonogram');
         echo tsprintf("%s\n", pht('Failures: %s.', implode(', ', $monograms)));
         return 1;
     }
     return 0;
 }
 public function execute(PhutilArgumentParser $args)
 {
     $iterator = $this->buildIterator($args);
     if (!$iterator) {
         throw new PhutilArgumentUsageException(pht('Either specify a list of files to cycle, or use --all to cycle ' . 'all files.'));
     }
     $format_map = PhabricatorFileStorageFormat::getAllFormats();
     $engines = PhabricatorFileStorageEngine::loadAllEngines();
     $key_name = $args->getArg('key');
     $failed = array();
     foreach ($iterator as $file) {
         $monogram = $file->getMonogram();
         $engine_key = $file->getStorageEngine();
         $engine = idx($engines, $engine_key);
         if (!$engine) {
             echo tsprintf("%s\n", pht('%s: Uses unknown storage engine "%s".', $monogram, $engine_key));
             $failed[] = $file;
             continue;
         }
         if ($engine->isChunkEngine()) {
             echo tsprintf("%s\n", pht('%s: Stored as chunks, declining to cycle directly.', $monogram));
             continue;
         }
         $format_key = $file->getStorageFormat();
         if (empty($format_map[$format_key])) {
             echo tsprintf("%s\n", pht('%s: Uses unknown storage format "%s".', $monogram, $format_key));
             $failed[] = $file;
             continue;
         }
         $format = clone $format_map[$format_key];
         $format->setFile($file);
         if (!$format->canCycleMasterKey()) {
             echo tsprintf("%s\n", pht('%s: Storage format ("%s") does not support key cycling.', $monogram, $format->getStorageFormatName()));
             continue;
         }
         echo tsprintf("%s\n", pht('%s: Cycling master key.', $monogram));
         try {
             if ($key_name) {
                 $format->selectMasterKey($key_name);
             }
             $file->cycleMasterStorageKey($format);
             echo tsprintf("%s\n", pht('Done.'));
         } catch (Exception $ex) {
             echo tsprintf("%B\n", pht('Failed! %s', (string) $ex));
             $failed[] = $file;
         }
     }
     if ($failed) {
         $monograms = mpull($failed, 'getMonogram');
         echo tsprintf("%s\n", pht('Failures: %s.', implode(', ', $monograms)));
         return 1;
     }
     return 0;
 }
 /**
  * @phutil-external-symbol class PhabricatorStartup
  */
 protected function executeChecks()
 {
     $engines = PhabricatorFileStorageEngine::loadWritableChunkEngines();
     $chunk_engine_active = (bool) $engines;
     $this->checkS3();
     if (!$chunk_engine_active) {
         $doc_href = PhabricatorEnv::getDocLink('Configuring File Storage');
         $message = pht('Large file storage has not been configured, which will limit ' . 'the maximum size of file uploads. See %s for ' . 'instructions on configuring uploads and storage.', phutil_tag('a', array('href' => $doc_href, 'target' => '_blank'), pht('Configuring File Storage')));
         $this->newIssue('large-files')->setShortName(pht('Large Files'))->setName(pht('Large File Storage Not Configured'))->setMessage($message);
     }
     $post_max_size = ini_get('post_max_size');
     if ($post_max_size && (int) $post_max_size > 0) {
         $post_max_bytes = phutil_parse_bytes($post_max_size);
         $post_max_need = 32 * 1024 * 1024;
         if ($post_max_need > $post_max_bytes) {
             $summary = pht('Set %s in your PHP configuration to at least 32MB ' . 'to support large file uploads.', phutil_tag('tt', array(), 'post_max_size'));
             $message = pht('Adjust %s in your PHP configuration to at least 32MB. When ' . 'set to smaller value, large file uploads may not work properly.', phutil_tag('tt', array(), 'post_max_size'));
             $this->newIssue('php.post_max_size')->setName(pht('PHP post_max_size Not Configured'))->setSummary($summary)->setMessage($message)->setGroup(self::GROUP_PHP)->addPHPConfig('post_max_size');
         }
     }
     // This is somewhat arbitrary, but make sure we have enough headroom to
     // upload a default file at the chunk threshold (8MB), which may be
     // base64 encoded, then JSON encoded in the request, and may need to be
     // held in memory in the raw and as a query string.
     $need_bytes = 64 * 1024 * 1024;
     $memory_limit = PhabricatorStartup::getOldMemoryLimit();
     if ($memory_limit && (int) $memory_limit > 0) {
         $memory_limit_bytes = phutil_parse_bytes($memory_limit);
         $memory_usage_bytes = memory_get_usage();
         $available_bytes = $memory_limit_bytes - $memory_usage_bytes;
         if ($need_bytes > $available_bytes) {
             $summary = pht('Your PHP memory limit is configured in a way that may prevent ' . 'you from uploading large files or handling large requests.');
             $message = pht('When you upload a file via drag-and-drop or the API, chunks must ' . 'be buffered into memory before being written to permanent ' . 'storage. Phabricator needs memory available to store these ' . 'chunks while they are uploaded, but PHP is currently configured ' . 'to severly limit the available memory.' . "\n\n" . 'PHP processes currently have very little free memory available ' . '(%s). To work well, processes should have at least %s.' . "\n\n" . '(Note that the application itself must also fit in available ' . 'memory, so not all of the memory under the memory limit is ' . 'available for running workloads.)' . "\n\n" . "The easiest way to resolve this issue is to set %s to %s in your " . "PHP configuration, to disable the memory limit. There is " . "usually little or no value to using this option to limit " . "Phabricator process memory." . "\n\n" . "You can also increase the limit or ignore this issue and accept " . "that you may encounter problems uploading large files and " . "processing large requests.", phutil_format_bytes($available_bytes), phutil_format_bytes($need_bytes), phutil_tag('tt', array(), 'memory_limit'), phutil_tag('tt', array(), '-1'));
             $this->newIssue('php.memory_limit.upload')->setName(pht('Memory Limit Restricts File Uploads'))->setSummary($summary)->setMessage($message)->setGroup(self::GROUP_PHP)->addPHPConfig('memory_limit')->addPHPConfigOriginalValue('memory_limit', $memory_limit);
         }
     }
     $local_path = PhabricatorEnv::getEnvConfig('storage.local-disk.path');
     if (!$local_path) {
         return;
     }
     if (!Filesystem::pathExists($local_path) || !is_readable($local_path) || !is_writable($local_path)) {
         $message = pht('Configured location for storing uploaded files on disk ("%s") does ' . 'not exist, or is not readable or writable. Verify the directory ' . 'exists and is readable and writable by the webserver.', $local_path);
         $this->newIssue('config.storage.local-disk.path')->setShortName(pht('Local Disk Storage'))->setName(pht('Local Disk Storage Not Readable/Writable'))->setMessage($message)->addPhabricatorConfig('storage.local-disk.path');
     }
 }
 public function buildConfigurationPagePanel()
 {
     $viewer = $this->getViewer();
     $application = $this->getApplication();
     $engines = PhabricatorFileStorageEngine::loadAllEngines();
     $writable_engines = PhabricatorFileStorageEngine::loadWritableEngines();
     $chunk_engines = PhabricatorFileStorageEngine::loadWritableChunkEngines();
     $yes = pht('Yes');
     $no = pht('No');
     $rows = array();
     $rowc = array();
     foreach ($engines as $key => $engine) {
         $limited = $no;
         $limit = null;
         if ($engine->hasFilesizeLimit()) {
             $limited = $yes;
             $limit = phutil_format_bytes($engine->getFilesizeLimit());
         }
         if ($engine->canWriteFiles()) {
             $writable = $yes;
         } else {
             $writable = $no;
         }
         if ($engine->isTestEngine()) {
             $test = $yes;
         } else {
             $test = $no;
         }
         if (isset($writable_engines[$key]) || isset($chunk_engines[$key])) {
             $rowc[] = 'highlighted';
         } else {
             $rowc[] = null;
         }
         $rows[] = array($key, get_class($engine), $test, $writable, $limited, $limit);
     }
     $table = id(new AphrontTableView($rows))->setNoDataString(pht('No storage engines available.'))->setHeaders(array(pht('Key'), pht('Class'), pht('Unit Test'), pht('Writable'), pht('Has Limit'), pht('Limit')))->setRowClasses($rowc)->setColumnClasses(array('', 'wide', '', '', '', 'n'));
     $box = id(new PHUIObjectBoxView())->setHeaderText(pht('Storage Engines'))->setTable($table);
     return $box;
 }
 public function execute(PhutilArgumentParser $args)
 {
     $target_key = $args->getArg('engine');
     if (!$target_key) {
         throw new PhutilArgumentUsageException(pht('Specify an engine to migrate to with `%s`. ' . 'Use `%s` to get a list of engines.', '--engine', 'files engines'));
     }
     $target_engine = PhabricatorFile::buildEngine($target_key);
     $iterator = $this->buildIterator($args);
     if (!$iterator) {
         throw new PhutilArgumentUsageException(pht('Either specify a list of files to migrate, or use `%s` ' . 'to migrate all files.', '--all'));
     }
     $is_dry_run = $args->getArg('dry-run');
     $min_size = (int) $args->getArg('min-size');
     $max_size = (int) $args->getArg('max-size');
     $is_copy = $args->getArg('copy');
     $failed = array();
     $engines = PhabricatorFileStorageEngine::loadAllEngines();
     $total_bytes = 0;
     $total_files = 0;
     foreach ($iterator as $file) {
         $monogram = $file->getMonogram();
         $engine_key = $file->getStorageEngine();
         $engine = idx($engines, $engine_key);
         if (!$engine) {
             echo tsprintf("%s\n", pht('%s: Uses unknown storage engine "%s".', $monogram, $engine_key));
             $failed[] = $file;
             continue;
         }
         if ($engine->isChunkEngine()) {
             echo tsprintf("%s\n", pht('%s: Stored as chunks, no data to migrate directly.', $monogram));
             continue;
         }
         if ($engine_key === $target_key) {
             echo tsprintf("%s\n", pht('%s: Already stored in engine "%s".', $monogram, $target_key));
             continue;
         }
         $byte_size = $file->getByteSize();
         if ($min_size && $byte_size < $min_size) {
             echo tsprintf("%s\n", pht('%s: File size (%s) is smaller than minimum size (%s).', $monogram, phutil_format_bytes($byte_size), phutil_format_bytes($min_size)));
             continue;
         }
         if ($max_size && $byte_size > $max_size) {
             echo tsprintf("%s\n", pht('%s: File size (%s) is larger than maximum size (%s).', $monogram, phutil_format_bytes($byte_size), phutil_format_bytes($max_size)));
             continue;
         }
         if ($is_dry_run) {
             echo tsprintf("%s\n", pht('%s: (%s) Would migrate from "%s" to "%s" (dry run)...', $monogram, phutil_format_bytes($byte_size), $engine_key, $target_key));
         } else {
             echo tsprintf("%s\n", pht('%s: (%s) Migrating from "%s" to "%s"...', $monogram, phutil_format_bytes($byte_size), $engine_key, $target_key));
         }
         try {
             if ($is_dry_run) {
                 // Do nothing, this is a dry run.
             } else {
                 $file->migrateToEngine($target_engine, $is_copy);
             }
             $total_files += 1;
             $total_bytes += $byte_size;
             echo tsprintf("%s\n", pht('Done.'));
         } catch (Exception $ex) {
             echo tsprintf("%s\n", pht('Failed! %s', (string) $ex));
             $failed[] = $file;
             throw $ex;
         }
     }
     echo tsprintf("%s\n", pht('Total Migrated Files: %s', new PhutilNumber($total_files)));
     echo tsprintf("%s\n", pht('Total Migrated Bytes: %s', phutil_format_bytes($total_bytes)));
     if ($is_dry_run) {
         echo tsprintf("%s\n", pht('This was a dry run, so no real migrations were performed.'));
     }
     if ($failed) {
         $monograms = mpull($failed, 'getMonogram');
         echo tsprintf("%s\n", pht('Failures: %s.', implode(', ', $monograms)));
         return 1;
     }
     return 0;
 }
 private function browseFile()
 {
     $viewer = $this->getViewer();
     $request = $this->getRequest();
     $drequest = $this->getDiffusionRequest();
     $repository = $drequest->getRepository();
     $before = $request->getStr('before');
     if ($before) {
         return $this->buildBeforeResponse($before);
     }
     $path = $drequest->getPath();
     $preferences = $viewer->loadPreferences();
     $show_blame = $request->getBool('blame', $preferences->getPreference(PhabricatorUserPreferences::PREFERENCE_DIFFUSION_BLAME, false));
     $show_color = $request->getBool('color', $preferences->getPreference(PhabricatorUserPreferences::PREFERENCE_DIFFUSION_COLOR, true));
     $view = $request->getStr('view');
     if ($request->isFormPost() && $view != 'raw' && $viewer->isLoggedIn()) {
         $preferences->setPreference(PhabricatorUserPreferences::PREFERENCE_DIFFUSION_BLAME, $show_blame);
         $preferences->setPreference(PhabricatorUserPreferences::PREFERENCE_DIFFUSION_COLOR, $show_color);
         $preferences->save();
         $uri = $request->getRequestURI()->alter('blame', null)->alter('color', null);
         return id(new AphrontRedirectResponse())->setURI($uri);
     }
     // We need the blame information if blame is on and we're building plain
     // text, or blame is on and this is an Ajax request. If blame is on and
     // this is a colorized request, we don't show blame at first (we ajax it
     // in afterward) so we don't need to query for it.
     $needs_blame = $show_blame && !$show_color || $show_blame && $request->isAjax();
     $params = array('commit' => $drequest->getCommit(), 'path' => $drequest->getPath());
     $byte_limit = null;
     if ($view !== 'raw') {
         $byte_limit = PhabricatorFileStorageEngine::getChunkThreshold();
         $time_limit = 10;
         $params += array('timeout' => $time_limit, 'byteLimit' => $byte_limit);
     }
     $response = $this->callConduitWithDiffusionRequest('diffusion.filecontentquery', $params);
     $hit_byte_limit = $response['tooHuge'];
     $hit_time_limit = $response['tooSlow'];
     $file_phid = $response['filePHID'];
     if ($hit_byte_limit) {
         $corpus = $this->buildErrorCorpus(pht('This file is larger than %s byte(s), and too large to display ' . 'in the web UI.', phutil_format_bytes($byte_limit)));
     } else {
         if ($hit_time_limit) {
             $corpus = $this->buildErrorCorpus(pht('This file took too long to load from the repository (more than ' . '%s second(s)).', new PhutilNumber($time_limit)));
         } else {
             $file = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs(array($file_phid))->executeOne();
             if (!$file) {
                 throw new Exception(pht('Failed to load content file!'));
             }
             if ($view === 'raw') {
                 return $file->getRedirectResponse();
             }
             $data = $file->loadFileData();
             if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) {
                 $file_uri = $file->getBestURI();
                 if ($file->isViewableImage()) {
                     $corpus = $this->buildImageCorpus($file_uri);
                 } else {
                     $corpus = $this->buildBinaryCorpus($file_uri, $data);
                 }
             } else {
                 $this->loadLintMessages();
                 $this->coverage = $drequest->loadCoverage();
                 // Build the content of the file.
                 $corpus = $this->buildCorpus($show_blame, $show_color, $data, $needs_blame, $drequest, $path, $data);
             }
         }
     }
     if ($request->isAjax()) {
         return id(new AphrontAjaxResponse())->setContent($corpus);
     }
     require_celerity_resource('diffusion-source-css');
     // Render the page.
     $view = $this->buildActionView($drequest);
     $action_list = $this->enrichActionView($view, $drequest, $show_blame, $show_color);
     $properties = $this->buildPropertyView($drequest, $action_list);
     $object_box = id(new PHUIObjectBoxView())->setHeader($this->buildHeaderView($drequest))->addPropertyList($properties);
     $content = array();
     $content[] = $object_box;
     $follow = $request->getStr('follow');
     if ($follow) {
         $notice = new PHUIInfoView();
         $notice->setSeverity(PHUIInfoView::SEVERITY_WARNING);
         $notice->setTitle(pht('Unable to Continue'));
         switch ($follow) {
             case 'first':
                 $notice->appendChild(pht('Unable to continue tracing the history of this file because ' . 'this commit is the first commit in the repository.'));
                 break;
             case 'created':
                 $notice->appendChild(pht('Unable to continue tracing the history of this file because ' . 'this commit created the file.'));
                 break;
         }
         $content[] = $notice;
     }
     $renamed = $request->getStr('renamed');
     if ($renamed) {
         $notice = new PHUIInfoView();
         $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
         $notice->setTitle(pht('File Renamed'));
         $notice->appendChild(pht('File history passes through a rename from "%s" to "%s".', $drequest->getPath(), $renamed));
         $content[] = $notice;
     }
     $content[] = $corpus;
     $content[] = $this->buildOpenRevisions();
     $crumbs = $this->buildCrumbs(array('branch' => true, 'path' => true, 'view' => 'browse'));
     $basename = basename($this->getDiffusionRequest()->getPath());
     return $this->newPage()->setTitle(array($basename, $repository->getDisplayName()))->setCrumbs($crumbs)->appendChild($content);
 }
Exemplo n.º 10
0
 protected function renderInput()
 {
     $file_id = $this->getID();
     Javelin::initBehavior('phui-file-upload', array('fileInputID' => $file_id, 'inputName' => $this->getName(), 'uploadURI' => '/file/dropupload/', 'chunkThreshold' => PhabricatorFileStorageEngine::getChunkThreshold()));
     return phutil_tag('input', array('type' => 'file', 'multiple' => $this->getAllowMultiple() ? 'multiple' : null, 'name' => $this->getName() . '.raw', 'id' => $file_id, 'disabled' => $this->getDisabled() ? 'disabled' : null));
 }
 protected function renderInput()
 {
     $id = $this->getID();
     if (!$id) {
         $id = celerity_generate_unique_node_id();
         $this->setID($id);
     }
     $viewer = $this->getUser();
     if (!$viewer) {
         throw new PhutilInvalidStateException('setUser');
     }
     // We need to have this if previews render images, since Ajax can not
     // currently ship JS or CSS.
     require_celerity_resource('lightbox-attachment-css');
     Javelin::initBehavior('aphront-drag-and-drop-textarea', array('target' => $id, 'activatedClass' => 'aphront-textarea-drag-and-drop', 'uri' => '/file/dropupload/', 'chunkThreshold' => PhabricatorFileStorageEngine::getChunkThreshold()));
     Javelin::initBehavior('phabricator-remarkup-assist', array('pht' => array('bold text' => pht('bold text'), 'italic text' => pht('italic text'), 'monospaced text' => pht('monospaced text'), 'List Item' => pht('List Item'), 'Quoted Text' => pht('Quoted Text'), 'data' => pht('data'), 'name' => pht('name'), 'URL' => pht('URL'))));
     Javelin::initBehavior('phabricator-tooltips', array());
     $actions = array('fa-bold' => array('tip' => pht('Bold')), 'fa-italic' => array('tip' => pht('Italics')), 'fa-text-width' => array('tip' => pht('Monospaced')), 'fa-link' => array('tip' => pht('Link')), array('spacer' => true), 'fa-list-ul' => array('tip' => pht('Bulleted List')), 'fa-list-ol' => array('tip' => pht('Numbered List')), 'fa-code' => array('tip' => pht('Code Block')), 'fa-quote-right' => array('tip' => pht('Quote')), 'fa-table' => array('tip' => pht('Table')), 'fa-cloud-upload' => array('tip' => pht('Upload File')));
     $can_use_macros = !$this->disableMacro && function_exists('imagettftext');
     if ($can_use_macros) {
         $can_use_macros = PhabricatorApplication::isClassInstalledForViewer('PhabricatorMacroApplication', $viewer);
     }
     if ($can_use_macros) {
         $actions[] = array('spacer' => true);
         $actions['fa-meh-o'] = array('tip' => pht('Meme'));
     }
     $actions['fa-life-bouy'] = array('tip' => pht('Help'), 'align' => 'right', 'href' => PhrictionDocument::getSlugURI('usage/formatting_reference'));
     if (!$this->disableFullScreen) {
         $actions[] = array('spacer' => true, 'align' => 'right');
         $actions['fa-arrows-alt'] = array('tip' => pht('Fullscreen Mode'), 'align' => 'right');
     }
     $buttons = array();
     foreach ($actions as $action => $spec) {
         $classes = array();
         if (idx($spec, 'align') == 'right') {
             $classes[] = 'remarkup-assist-right';
         }
         if (idx($spec, 'spacer')) {
             $classes[] = 'remarkup-assist-separator';
             $buttons[] = phutil_tag('span', array('class' => implode(' ', $classes)), '');
             continue;
         } else {
             $classes[] = 'remarkup-assist-button';
         }
         $href = idx($spec, 'href', '#');
         if ($href == '#') {
             $meta = array('action' => $action);
             $mustcapture = true;
             $target = null;
         } else {
             $meta = array();
             $mustcapture = null;
             $target = '_blank';
         }
         $content = null;
         $tip = idx($spec, 'tip');
         if ($tip) {
             $meta['tip'] = $tip;
             $content = javelin_tag('span', array('aural' => true), $tip);
         }
         $buttons[] = javelin_tag('a', array('class' => implode(' ', $classes), 'href' => $href, 'sigil' => 'remarkup-assist has-tooltip', 'meta' => $meta, 'mustcapture' => $mustcapture, 'target' => $target, 'tabindex' => -1), phutil_tag('div', array('class' => 'remarkup-assist phui-icon-view phui-font-fa bluegrey ' . $action), $content));
     }
     $buttons = phutil_tag('div', array('class' => 'remarkup-assist-bar'), $buttons);
     $monospaced_textareas = null;
     $monospaced_textareas_class = null;
     $monospaced_textareas = $viewer->loadPreferences()->getPreference(PhabricatorUserPreferences::PREFERENCE_MONOSPACED_TEXTAREAS);
     if ($monospaced_textareas == 'enabled') {
         $monospaced_textareas_class = 'PhabricatorMonospaced';
     }
     $this->setCustomClass('remarkup-assist-textarea ' . $monospaced_textareas_class);
     return javelin_tag('div', array('sigil' => 'remarkup-assist-control'), array($buttons, parent::renderInput()));
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $request->getUser();
     $response = $this->loadProject();
     if ($response) {
         return $response;
     }
     $project = $this->getProject();
     $this->readRequestState();
     $board_uri = $this->getApplicationURI('board/' . $project->getID() . '/');
     $search_engine = id(new ManiphestTaskSearchEngine())->setViewer($viewer)->setBaseURI($board_uri)->setIsBoardView(true);
     if ($request->isFormPost() && !$request->getBool('initialize')) {
         $saved = $search_engine->buildSavedQueryFromRequest($request);
         $search_engine->saveQuery($saved);
         $filter_form = id(new AphrontFormView())->setUser($viewer);
         $search_engine->buildSearchForm($filter_form, $saved);
         if ($search_engine->getErrors()) {
             return $this->newDialog()->setWidth(AphrontDialogView::WIDTH_FULL)->setTitle(pht('Advanced Filter'))->appendChild($filter_form->buildLayoutView())->setErrors($search_engine->getErrors())->setSubmitURI($board_uri)->addSubmitButton(pht('Apply Filter'))->addCancelButton($board_uri);
         }
         return id(new AphrontRedirectResponse())->setURI($this->getURIWithState($search_engine->getQueryResultsPageURI($saved->getQueryKey())));
     }
     $query_key = $request->getURIData('queryKey');
     if (!$query_key) {
         $query_key = 'open';
     }
     $this->queryKey = $query_key;
     $custom_query = null;
     if ($search_engine->isBuiltinQuery($query_key)) {
         $saved = $search_engine->buildSavedQueryFromBuiltin($query_key);
     } else {
         $saved = id(new PhabricatorSavedQueryQuery())->setViewer($viewer)->withQueryKeys(array($query_key))->executeOne();
         if (!$saved) {
             return new Aphront404Response();
         }
         $custom_query = $saved;
     }
     if ($request->getURIData('filter')) {
         $filter_form = id(new AphrontFormView())->setUser($viewer);
         $search_engine->buildSearchForm($filter_form, $saved);
         return $this->newDialog()->setWidth(AphrontDialogView::WIDTH_FULL)->setTitle(pht('Advanced Filter'))->appendChild($filter_form->buildLayoutView())->setSubmitURI($board_uri)->addSubmitButton(pht('Apply Filter'))->addCancelButton($board_uri);
     }
     $task_query = $search_engine->buildQueryFromSavedQuery($saved);
     $select_phids = array($project->getPHID());
     if ($project->getHasSubprojects() || $project->getHasMilestones()) {
         $descendants = id(new PhabricatorProjectQuery())->setViewer($viewer)->withAncestorProjectPHIDs($select_phids)->execute();
         foreach ($descendants as $descendant) {
             $select_phids[] = $descendant->getPHID();
         }
     }
     $tasks = $task_query->withEdgeLogicPHIDs(PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, PhabricatorQueryConstraint::OPERATOR_ANCESTOR, array($select_phids))->setOrder(ManiphestTaskQuery::ORDER_PRIORITY)->setViewer($viewer)->execute();
     $tasks = mpull($tasks, null, 'getPHID');
     $board_phid = $project->getPHID();
     $layout_engine = id(new PhabricatorBoardLayoutEngine())->setViewer($viewer)->setBoardPHIDs(array($board_phid))->setObjectPHIDs(array_keys($tasks))->setFetchAllBoards(true)->executeLayout();
     $columns = $layout_engine->getColumns($board_phid);
     if (!$columns || !$project->getHasWorkboard()) {
         $has_normal_columns = false;
         foreach ($columns as $column) {
             if (!$column->getProxyPHID()) {
                 $has_normal_columns = true;
                 break;
             }
         }
         $can_edit = PhabricatorPolicyFilter::hasCapability($viewer, $project, PhabricatorPolicyCapability::CAN_EDIT);
         if (!$has_normal_columns) {
             if (!$can_edit) {
                 $content = $this->buildNoAccessContent($project);
             } else {
                 $content = $this->buildInitializeContent($project);
             }
         } else {
             if (!$can_edit) {
                 $content = $this->buildDisabledContent($project);
             } else {
                 $content = $this->buildEnableContent($project);
             }
         }
         if ($content instanceof AphrontResponse) {
             return $content;
         }
         $nav = $this->getProfileMenu();
         $nav->selectFilter(PhabricatorProject::PANEL_WORKBOARD);
         $crumbs = $this->buildApplicationCrumbs();
         $crumbs->addTextCrumb(pht('Workboard'));
         return $this->newPage()->setTitle(array($project->getDisplayName(), pht('Workboard')))->setNavigation($nav)->setCrumbs($crumbs)->appendChild($content);
     }
     $task_can_edit_map = id(new PhabricatorPolicyFilter())->setViewer($viewer)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT))->apply($tasks);
     // If this is a batch edit, select the editable tasks in the chosen column
     // and ship the user into the batch editor.
     $batch_edit = $request->getStr('batch');
     if ($batch_edit) {
         if ($batch_edit !== self::BATCH_EDIT_ALL) {
             $column_id_map = mpull($columns, null, 'getID');
             $batch_column = idx($column_id_map, $batch_edit);
             if (!$batch_column) {
                 return new Aphront404Response();
             }
             $batch_task_phids = $layout_engine->getColumnObjectPHIDs($board_phid, $batch_column->getPHID());
             foreach ($batch_task_phids as $key => $batch_task_phid) {
                 if (empty($task_can_edit_map[$batch_task_phid])) {
                     unset($batch_task_phids[$key]);
                 }
             }
             $batch_tasks = array_select_keys($tasks, $batch_task_phids);
         } else {
             $batch_tasks = $task_can_edit_map;
         }
         if (!$batch_tasks) {
             $cancel_uri = $this->getURIWithState($board_uri);
             return $this->newDialog()->setTitle(pht('No Editable Tasks'))->appendParagraph(pht('The selected column contains no visible tasks which you ' . 'have permission to edit.'))->addCancelButton($board_uri);
         }
         $batch_ids = mpull($batch_tasks, 'getID');
         $batch_ids = implode(',', $batch_ids);
         $batch_uri = new PhutilURI('/maniphest/batch/');
         $batch_uri->setQueryParam('board', $this->id);
         $batch_uri->setQueryParam('batch', $batch_ids);
         return id(new AphrontRedirectResponse())->setURI($batch_uri);
     }
     $board_id = celerity_generate_unique_node_id();
     $board = id(new PHUIWorkboardView())->setUser($viewer)->setID($board_id)->addSigil('jx-workboard')->setMetadata(array('boardPHID' => $project->getPHID()));
     $visible_columns = array();
     $column_phids = array();
     $visible_phids = array();
     foreach ($columns as $column) {
         if (!$this->showHidden) {
             if ($column->isHidden()) {
                 continue;
             }
         }
         $proxy = $column->getProxy();
         if ($proxy && !$proxy->isMilestone()) {
             // TODO: For now, don't show subproject columns because we can't
             // handle tasks with multiple positions yet.
             continue;
         }
         $task_phids = $layout_engine->getColumnObjectPHIDs($board_phid, $column->getPHID());
         $column_tasks = array_select_keys($tasks, $task_phids);
         // If we aren't using "natural" order, reorder the column by the original
         // query order.
         if ($this->sortKey != PhabricatorProjectColumn::ORDER_NATURAL) {
             $column_tasks = array_select_keys($column_tasks, array_keys($tasks));
         }
         $column_phid = $column->getPHID();
         $visible_columns[$column_phid] = $column;
         $column_phids[$column_phid] = $column_tasks;
         foreach ($column_tasks as $phid => $task) {
             $visible_phids[$phid] = $phid;
         }
     }
     $rendering_engine = id(new PhabricatorBoardRenderingEngine())->setViewer($viewer)->setObjects(array_select_keys($tasks, $visible_phids))->setEditMap($task_can_edit_map)->setExcludedProjectPHIDs($select_phids);
     $templates = array();
     $column_maps = array();
     $all_tasks = array();
     foreach ($visible_columns as $column_phid => $column) {
         $column_tasks = $column_phids[$column_phid];
         $panel = id(new PHUIWorkpanelView())->setHeader($column->getDisplayName())->setSubHeader($column->getDisplayType())->addSigil('workpanel');
         $proxy = $column->getProxy();
         if ($proxy) {
             $proxy_id = $proxy->getID();
             $href = $this->getApplicationURI("view/{$proxy_id}/");
             $panel->setHref($href);
         }
         $header_icon = $column->getHeaderIcon();
         if ($header_icon) {
             $panel->setHeaderIcon($header_icon);
         }
         $display_class = $column->getDisplayClass();
         if ($display_class) {
             $panel->addClass($display_class);
         }
         if ($column->isHidden()) {
             $panel->addClass('project-panel-hidden');
         }
         $column_menu = $this->buildColumnMenu($project, $column);
         $panel->addHeaderAction($column_menu);
         $count_tag = id(new PHUITagView())->setType(PHUITagView::TYPE_SHADE)->setShade(PHUITagView::COLOR_BLUE)->addSigil('column-points')->setName(javelin_tag('span', array('sigil' => 'column-points-content'), pht('-')))->setStyle('display: none');
         $panel->setHeaderTag($count_tag);
         $cards = id(new PHUIObjectItemListView())->setUser($viewer)->setFlush(true)->setAllowEmptyList(true)->addSigil('project-column')->setItemClass('phui-workcard')->setMetadata(array('columnPHID' => $column->getPHID(), 'pointLimit' => $column->getPointLimit()));
         foreach ($column_tasks as $task) {
             $object_phid = $task->getPHID();
             $card = $rendering_engine->renderCard($object_phid);
             $templates[$object_phid] = hsprintf('%s', $card->getItem());
             $column_maps[$column_phid][] = $object_phid;
             $all_tasks[$object_phid] = $task;
         }
         $panel->setCards($cards);
         $board->addPanel($panel);
     }
     $behavior_config = array('moveURI' => $this->getApplicationURI('move/' . $project->getID() . '/'), 'createURI' => $this->getCreateURI(), 'uploadURI' => '/file/dropupload/', 'coverURI' => $this->getApplicationURI('cover/'), 'chunkThreshold' => PhabricatorFileStorageEngine::getChunkThreshold(), 'pointsEnabled' => ManiphestTaskPoints::getIsEnabled(), 'boardPHID' => $project->getPHID(), 'order' => $this->sortKey, 'templateMap' => $templates, 'columnMaps' => $column_maps, 'orderMaps' => mpull($all_tasks, 'getWorkboardOrderVectors'), 'propertyMaps' => mpull($all_tasks, 'getWorkboardProperties'), 'boardID' => $board_id, 'projectPHID' => $project->getPHID());
     $this->initBehavior('project-boards', $behavior_config);
     $sort_menu = $this->buildSortMenu($viewer, $this->sortKey);
     $filter_menu = $this->buildFilterMenu($viewer, $custom_query, $search_engine, $query_key);
     $manage_menu = $this->buildManageMenu($project, $this->showHidden);
     $header_link = phutil_tag('a', array('href' => $this->getApplicationURI('profile/' . $project->getID() . '/')), $project->getName());
     $board_box = id(new PHUIBoxView())->appendChild($board)->addClass('project-board-wrapper');
     $nav = $this->getProfileMenu();
     $divider = id(new PHUIListItemView())->setType(PHUIListItemView::TYPE_DIVIDER);
     $fullscreen = $this->buildFullscreenMenu();
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('Workboard'));
     $crumbs->setBorder(true);
     $crumbs->addAction($sort_menu);
     $crumbs->addAction($filter_menu);
     $crumbs->addAction($divider);
     $crumbs->addAction($manage_menu);
     $crumbs->addAction($fullscreen);
     return $this->newPage()->setTitle(array($project->getDisplayName(), pht('Workboard')))->setPageObjectPHIDs(array($project->getPHID()))->setShowFooter(false)->setNavigation($nav)->setCrumbs($crumbs)->addQuicksandConfig(array('boardConfig' => $behavior_config))->appendChild(array($board_box));
 }
 private function browseFile()
 {
     $viewer = $this->getViewer();
     $request = $this->getRequest();
     $drequest = $this->getDiffusionRequest();
     $repository = $drequest->getRepository();
     $before = $request->getStr('before');
     if ($before) {
         return $this->buildBeforeResponse($before);
     }
     $path = $drequest->getPath();
     $blame_key = PhabricatorDiffusionBlameSetting::SETTINGKEY;
     $color_key = PhabricatorDiffusionColorSetting::SETTINGKEY;
     $show_blame = $request->getBool('blame', $viewer->getUserSetting($blame_key));
     $show_color = $request->getBool('color', $viewer->getUserSetting($color_key));
     $view = $request->getStr('view');
     if ($request->isFormPost() && $view != 'raw' && $viewer->isLoggedIn()) {
         $preferences = PhabricatorUserPreferences::loadUserPreferences($viewer);
         $editor = id(new PhabricatorUserPreferencesEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true)->setContinueOnMissingFields(true);
         $xactions = array();
         $xactions[] = $preferences->newTransaction($blame_key, $show_blame);
         $xactions[] = $preferences->newTransaction($color_key, $show_color);
         $editor->applyTransactions($preferences, $xactions);
         $uri = $request->getRequestURI()->alter('blame', null)->alter('color', null);
         return id(new AphrontRedirectResponse())->setURI($uri);
     }
     // We need the blame information if blame is on and we're building plain
     // text, or blame is on and this is an Ajax request. If blame is on and
     // this is a colorized request, we don't show blame at first (we ajax it
     // in afterward) so we don't need to query for it.
     $needs_blame = $show_blame && !$show_color || $show_blame && $request->isAjax();
     $params = array('commit' => $drequest->getCommit(), 'path' => $drequest->getPath());
     $byte_limit = null;
     if ($view !== 'raw') {
         $byte_limit = PhabricatorFileStorageEngine::getChunkThreshold();
         $time_limit = 10;
         $params += array('timeout' => $time_limit, 'byteLimit' => $byte_limit);
     }
     $response = $this->callConduitWithDiffusionRequest('diffusion.filecontentquery', $params);
     $hit_byte_limit = $response['tooHuge'];
     $hit_time_limit = $response['tooSlow'];
     $file_phid = $response['filePHID'];
     if ($hit_byte_limit) {
         $corpus = $this->buildErrorCorpus(pht('This file is larger than %s byte(s), and too large to display ' . 'in the web UI.', phutil_format_bytes($byte_limit)));
     } else {
         if ($hit_time_limit) {
             $corpus = $this->buildErrorCorpus(pht('This file took too long to load from the repository (more than ' . '%s second(s)).', new PhutilNumber($time_limit)));
         } else {
             $file = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs(array($file_phid))->executeOne();
             if (!$file) {
                 throw new Exception(pht('Failed to load content file!'));
             }
             if ($view === 'raw') {
                 return $file->getRedirectResponse();
             }
             $data = $file->loadFileData();
             $ref = $this->getGitLFSRef($repository, $data);
             if ($ref) {
                 if ($view == 'git-lfs') {
                     $file = $this->loadGitLFSFile($ref);
                     // Rename the file locally so we generate a better vanity URI for
                     // it. In storage, it just has a name like "lfs-13f9a94c0923...",
                     // since we don't get any hints about possible human-readable names
                     // at upload time.
                     $basename = basename($drequest->getPath());
                     $file->makeEphemeral();
                     $file->setName($basename);
                     return $file->getRedirectResponse();
                 } else {
                     $corpus = $this->buildGitLFSCorpus($ref);
                 }
             } else {
                 if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) {
                     $file_uri = $file->getBestURI();
                     if ($file->isViewableImage()) {
                         $corpus = $this->buildImageCorpus($file_uri);
                     } else {
                         $corpus = $this->buildBinaryCorpus($file_uri, $data);
                     }
                 } else {
                     $this->loadLintMessages();
                     $this->coverage = $drequest->loadCoverage();
                     // Build the content of the file.
                     $corpus = $this->buildCorpus($show_blame, $show_color, $data, $needs_blame, $drequest, $path, $data);
                 }
             }
         }
     }
     if ($request->isAjax()) {
         return id(new AphrontAjaxResponse())->setContent($corpus);
     }
     require_celerity_resource('diffusion-source-css');
     // Render the page.
     $view = $this->buildCurtain($drequest);
     $curtain = $this->enrichCurtain($view, $drequest, $show_blame, $show_color);
     $properties = $this->buildPropertyView($drequest);
     $header = $this->buildHeaderView($drequest);
     $header->setHeaderIcon('fa-file-code-o');
     $content = array();
     $follow = $request->getStr('follow');
     if ($follow) {
         $notice = new PHUIInfoView();
         $notice->setSeverity(PHUIInfoView::SEVERITY_WARNING);
         $notice->setTitle(pht('Unable to Continue'));
         switch ($follow) {
             case 'first':
                 $notice->appendChild(pht('Unable to continue tracing the history of this file because ' . 'this commit is the first commit in the repository.'));
                 break;
             case 'created':
                 $notice->appendChild(pht('Unable to continue tracing the history of this file because ' . 'this commit created the file.'));
                 break;
         }
         $content[] = $notice;
     }
     $renamed = $request->getStr('renamed');
     if ($renamed) {
         $notice = new PHUIInfoView();
         $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
         $notice->setTitle(pht('File Renamed'));
         $notice->appendChild(pht('File history passes through a rename from "%s" to "%s".', $drequest->getPath(), $renamed));
         $content[] = $notice;
     }
     $content[] = $corpus;
     $content[] = $this->buildOpenRevisions();
     $crumbs = $this->buildCrumbs(array('branch' => true, 'path' => true, 'view' => 'browse'));
     $crumbs->setBorder(true);
     $basename = basename($this->getDiffusionRequest()->getPath());
     $view = id(new PHUITwoColumnView())->setHeader($header)->setCurtain($curtain)->setMainColumn(array($content));
     if ($properties) {
         $view->addPropertySection(pht('Details'), $properties);
     }
     $title = array($basename, $repository->getDisplayName());
     return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->appendChild(array($view));
 }
 /**
  * Find a storage engine which is suitable for storing chunks.
  *
  * This engine must be a writable engine, have a filesize limit larger than
  * the chunk limit, and must not be a chunk engine itself.
  */
 private function getWritableEngine()
 {
     // NOTE: We can't just load writable engines or we'll loop forever.
     $engines = parent::loadAllEngines();
     foreach ($engines as $engine) {
         if ($engine->isChunkEngine()) {
             continue;
         }
         if ($engine->isTestEngine()) {
             continue;
         }
         if (!$engine->canWriteFiles()) {
             continue;
         }
         if ($engine->hasFilesizeLimit()) {
             if ($engine->getFilesizeLimit() < $this->getChunkSize()) {
                 continue;
             }
         }
         return true;
     }
     return false;
 }
 private function getChunkEngine()
 {
     $chunk_engines = PhabricatorFileStorageEngine::loadWritableChunkEngines();
     if (!$chunk_engines) {
         throw new Exception(pht('Unable to upload file: this server is not configured with any ' . 'storage engine which can store large files.'));
     }
     return head($chunk_engines);
 }
Exemplo n.º 16
0
 /**
  * Destroy stored file data if there are no remaining files which reference
  * it.
  */
 public function deleteFileDataIfUnused(PhabricatorFileStorageEngine $engine, $engine_identifier, $handle)
 {
     // Check to see if any files are using storage.
     $usage = id(new PhabricatorFile())->loadAllWhere('storageEngine = %s AND storageHandle = %s LIMIT 1', $engine_identifier, $handle);
     // If there are no files using the storage, destroy the actual storage.
     if (!$usage) {
         try {
             $engine->deleteFile($handle);
         } catch (Exception $ex) {
             // In the worst case, we're leaving some data stranded in a storage
             // engine, which is not a big deal.
             phlog($ex);
         }
     }
 }
 protected function renderInput()
 {
     $id = $this->getID();
     if (!$id) {
         $id = celerity_generate_unique_node_id();
         $this->setID($id);
     }
     $viewer = $this->getUser();
     if (!$viewer) {
         throw new PhutilInvalidStateException('setUser');
     }
     // We need to have this if previews render images, since Ajax can not
     // currently ship JS or CSS.
     require_celerity_resource('lightbox-attachment-css');
     if (!$this->getDisabled()) {
         Javelin::initBehavior('aphront-drag-and-drop-textarea', array('target' => $id, 'activatedClass' => 'aphront-textarea-drag-and-drop', 'uri' => '/file/dropupload/', 'chunkThreshold' => PhabricatorFileStorageEngine::getChunkThreshold()));
     }
     $root_id = celerity_generate_unique_node_id();
     $user_datasource = new PhabricatorPeopleDatasource();
     $proj_datasource = id(new PhabricatorProjectDatasource())->setParameters(array('autocomplete' => 1));
     Javelin::initBehavior('phabricator-remarkup-assist', array('pht' => array('bold text' => pht('bold text'), 'italic text' => pht('italic text'), 'monospaced text' => pht('monospaced text'), 'List Item' => pht('List Item'), 'Quoted Text' => pht('Quoted Text'), 'data' => pht('data'), 'name' => pht('name'), 'URL' => pht('URL')), 'disabled' => $this->getDisabled(), 'rootID' => $root_id, 'autocompleteMap' => (object) array(64 => array('datasourceURI' => $user_datasource->getDatasourceURI(), 'headerIcon' => 'fa-user', 'headerText' => pht('Find User:'******'hintText' => $user_datasource->getPlaceholderText()), 35 => array('datasourceURI' => $proj_datasource->getDatasourceURI(), 'headerIcon' => 'fa-briefcase', 'headerText' => pht('Find Project:'), 'hintText' => $proj_datasource->getPlaceholderText()))));
     Javelin::initBehavior('phabricator-tooltips', array());
     $actions = array('fa-bold' => array('tip' => pht('Bold'), 'nodevice' => true), 'fa-italic' => array('tip' => pht('Italics'), 'nodevice' => true), 'fa-text-width' => array('tip' => pht('Monospaced'), 'nodevice' => true), 'fa-link' => array('tip' => pht('Link'), 'nodevice' => true), array('spacer' => true, 'nodevice' => true), 'fa-list-ul' => array('tip' => pht('Bulleted List'), 'nodevice' => true), 'fa-list-ol' => array('tip' => pht('Numbered List'), 'nodevice' => true), 'fa-code' => array('tip' => pht('Code Block'), 'nodevice' => true), 'fa-quote-right' => array('tip' => pht('Quote'), 'nodevice' => true), 'fa-table' => array('tip' => pht('Table'), 'nodevice' => true), 'fa-cloud-upload' => array('tip' => pht('Upload File')));
     $can_use_macros = !$this->disableMacro && function_exists('imagettftext');
     if ($can_use_macros) {
         $can_use_macros = PhabricatorApplication::isClassInstalledForViewer('PhabricatorMacroApplication', $viewer);
     }
     if ($can_use_macros) {
         $actions[] = array('spacer' => true);
         $actions['fa-meh-o'] = array('tip' => pht('Meme'));
     }
     $actions['fa-eye'] = array('tip' => pht('Preview'), 'align' => 'right');
     $actions[] = array('spacer' => true, 'align' => 'right');
     $actions['fa-life-bouy'] = array('tip' => pht('Help'), 'align' => 'right', 'href' => PhabricatorEnv::getDoclink('Remarkup Reference'));
     if (!$this->disableFullScreen) {
         $actions[] = array('spacer' => true, 'align' => 'right');
         $actions['fa-arrows-alt'] = array('tip' => pht('Fullscreen Mode'), 'align' => 'right');
     }
     $buttons = array();
     foreach ($actions as $action => $spec) {
         $classes = array();
         if (idx($spec, 'align') == 'right') {
             $classes[] = 'remarkup-assist-right';
         }
         if (idx($spec, 'nodevice')) {
             $classes[] = 'remarkup-assist-nodevice';
         }
         if (idx($spec, 'spacer')) {
             $classes[] = 'remarkup-assist-separator';
             $buttons[] = phutil_tag('span', array('class' => implode(' ', $classes)), '');
             continue;
         } else {
             $classes[] = 'remarkup-assist-button';
         }
         $href = idx($spec, 'href', '#');
         if ($href == '#') {
             $meta = array('action' => $action);
             $mustcapture = true;
             $target = null;
         } else {
             $meta = array();
             $mustcapture = null;
             $target = '_blank';
         }
         $content = null;
         $tip = idx($spec, 'tip');
         if ($tip) {
             $meta['tip'] = $tip;
             $content = javelin_tag('span', array('aural' => true), $tip);
         }
         $sigils = array();
         $sigils[] = 'remarkup-assist';
         if (!$this->getDisabled()) {
             $sigils[] = 'has-tooltip';
         }
         $buttons[] = javelin_tag('a', array('class' => implode(' ', $classes), 'href' => $href, 'sigil' => implode(' ', $sigils), 'meta' => $meta, 'mustcapture' => $mustcapture, 'target' => $target, 'tabindex' => -1), phutil_tag('div', array('class' => 'remarkup-assist phui-icon-view phui-font-fa bluegrey ' . $action), $content));
     }
     $buttons = phutil_tag('div', array('class' => 'remarkup-assist-bar'), $buttons);
     $use_monospaced = $viewer->compareUserSetting(PhabricatorMonospacedTextareasSetting::SETTINGKEY, PhabricatorMonospacedTextareasSetting::VALUE_TEXT_MONOSPACED);
     if ($use_monospaced) {
         $monospaced_textareas_class = 'PhabricatorMonospaced';
     } else {
         $monospaced_textareas_class = null;
     }
     $this->setCustomClass('remarkup-assist-textarea ' . $monospaced_textareas_class);
     return javelin_tag('div', array('sigil' => 'remarkup-assist-control', 'class' => $this->getDisabled() ? 'disabled-control' : null, 'id' => $root_id), array($buttons, parent::renderInput()));
 }
 public function testLoadAllEngines()
 {
     PhabricatorFileStorageEngine::loadAllEngines();
     $this->assertTrue(true);
 }