mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +01:00
Store width and height metadata of image files
Summary: Also provide a way to update old files metadata. Test Plan: Create a revision which includes a image file. Check whether the widht, height metadata exists. Run `scripts/files/manage_files.php metadata --all` to update previously uploaded files. Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T2101 Differential Revision: https://secure.phabricator.com/D4347
This commit is contained in:
parent
ae0773b789
commit
712e22208c
7 changed files with 212 additions and 0 deletions
5
resources/sql/patches/20130103.filemetadata.sql
Normal file
5
resources/sql/patches/20130103.filemetadata.sql
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_file.file
|
||||||
|
ADD metadata LONGTEXT COLLATE utf8_bin NOT NULL;
|
||||||
|
|
||||||
|
UPDATE {$NAMESPACE}_file.file
|
||||||
|
SET metadata = '{}' WHERE metadata = '';
|
|
@ -18,6 +18,7 @@ $workflows = array(
|
||||||
new PhabricatorFilesManagementEnginesWorkflow(),
|
new PhabricatorFilesManagementEnginesWorkflow(),
|
||||||
new PhabricatorFilesManagementMigrateWorkflow(),
|
new PhabricatorFilesManagementMigrateWorkflow(),
|
||||||
new PhutilHelpArgumentWorkflow(),
|
new PhutilHelpArgumentWorkflow(),
|
||||||
|
new PhabricatorFilesManagementMetadataWorkflow(),
|
||||||
);
|
);
|
||||||
|
|
||||||
$args->parseWorkflows($workflows);
|
$args->parseWorkflows($workflows);
|
||||||
|
|
|
@ -830,6 +830,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorFileUploadController' => 'applications/files/controller/PhabricatorFileUploadController.php',
|
'PhabricatorFileUploadController' => 'applications/files/controller/PhabricatorFileUploadController.php',
|
||||||
'PhabricatorFileUploadException' => 'applications/files/exception/PhabricatorFileUploadException.php',
|
'PhabricatorFileUploadException' => 'applications/files/exception/PhabricatorFileUploadException.php',
|
||||||
'PhabricatorFilesManagementEnginesWorkflow' => 'applications/files/management/PhabricatorFilesManagementEnginesWorkflow.php',
|
'PhabricatorFilesManagementEnginesWorkflow' => 'applications/files/management/PhabricatorFilesManagementEnginesWorkflow.php',
|
||||||
|
'PhabricatorFilesManagementMetadataWorkflow' => 'applications/files/management/PhabricatorFilesManagementMetadataWorkflow.php',
|
||||||
'PhabricatorFilesManagementMigrateWorkflow' => 'applications/files/management/PhabricatorFilesManagementMigrateWorkflow.php',
|
'PhabricatorFilesManagementMigrateWorkflow' => 'applications/files/management/PhabricatorFilesManagementMigrateWorkflow.php',
|
||||||
'PhabricatorFilesManagementWorkflow' => 'applications/files/management/PhabricatorFilesManagementWorkflow.php',
|
'PhabricatorFilesManagementWorkflow' => 'applications/files/management/PhabricatorFilesManagementWorkflow.php',
|
||||||
'PhabricatorFlag' => 'applications/flag/storage/PhabricatorFlag.php',
|
'PhabricatorFlag' => 'applications/flag/storage/PhabricatorFlag.php',
|
||||||
|
@ -2177,6 +2178,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorFileUploadController' => 'PhabricatorFileController',
|
'PhabricatorFileUploadController' => 'PhabricatorFileController',
|
||||||
'PhabricatorFileUploadException' => 'Exception',
|
'PhabricatorFileUploadException' => 'Exception',
|
||||||
'PhabricatorFilesManagementEnginesWorkflow' => 'PhabricatorFilesManagementWorkflow',
|
'PhabricatorFilesManagementEnginesWorkflow' => 'PhabricatorFilesManagementWorkflow',
|
||||||
|
'PhabricatorFilesManagementMetadataWorkflow' => 'PhabricatorFilesManagementWorkflow',
|
||||||
'PhabricatorFilesManagementMigrateWorkflow' => 'PhabricatorFilesManagementWorkflow',
|
'PhabricatorFilesManagementMigrateWorkflow' => 'PhabricatorFilesManagementWorkflow',
|
||||||
'PhabricatorFilesManagementWorkflow' => 'PhutilArgumentWorkflow',
|
'PhabricatorFilesManagementWorkflow' => 'PhutilArgumentWorkflow',
|
||||||
'PhabricatorFlag' => 'PhabricatorFlagDAO',
|
'PhabricatorFlag' => 'PhabricatorFlagDAO',
|
||||||
|
|
|
@ -125,6 +125,17 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
|
||||||
pht('Handle'),
|
pht('Handle'),
|
||||||
phutil_escape_html($file->getStorageHandle()));
|
phutil_escape_html($file->getStorageHandle()));
|
||||||
|
|
||||||
|
$metadata = $file->getMetadata();
|
||||||
|
if (!empty($metadata)) {
|
||||||
|
$view->addSectionHeader(pht('Metadata'));
|
||||||
|
|
||||||
|
foreach ($metadata as $key => $value) {
|
||||||
|
$view->addProperty(
|
||||||
|
PhabricatorFile::getMetadataName($key),
|
||||||
|
phutil_escape_html($value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($file->isViewableInBrowser()) {
|
if ($file->isViewableInBrowser()) {
|
||||||
|
|
||||||
// TODO: Clean this up after Pholio (dark backgrounds, standardization,
|
// TODO: Clean this up after Pholio (dark backgrounds, standardization,
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorFilesManagementMetadataWorkflow
|
||||||
|
extends PhabricatorFilesManagementWorkflow {
|
||||||
|
|
||||||
|
public function didConstruct() {
|
||||||
|
$this
|
||||||
|
->setName('metadata')
|
||||||
|
->setSynopsis('Update metadata of old files.')
|
||||||
|
->setArguments(
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'name' => 'all',
|
||||||
|
'help' => 'Update all files.',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'names',
|
||||||
|
'wildcard' => true,
|
||||||
|
'help' => 'Update the given files.',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'dry-run',
|
||||||
|
'help' => 'Show what would be updated.',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
$console = PhutilConsole::getConsole();
|
||||||
|
|
||||||
|
if ($args->getArg('all')) {
|
||||||
|
if ($args->getArg('names')) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
"Specify either a list of files or `--all`, but not both.");
|
||||||
|
}
|
||||||
|
$iterator = new LiskMigrationIterator(new PhabricatorFile());
|
||||||
|
} else if ($args->getArg('names')) {
|
||||||
|
$iterator = array();
|
||||||
|
|
||||||
|
foreach ($args->getArg('names') as $name) {
|
||||||
|
$name = trim($name);
|
||||||
|
|
||||||
|
$id = preg_replace('/^F/i', '', $name);
|
||||||
|
if (ctype_digit($id)) {
|
||||||
|
$file = id(new PhabricatorFile())->loadOneWhere(
|
||||||
|
'id = %d',
|
||||||
|
$id);
|
||||||
|
if (!$file) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
"No file exists with id '{$name}'.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$file = id(new PhabricatorFile())->loadOneWhere(
|
||||||
|
'phid = %d',
|
||||||
|
$name);
|
||||||
|
if (!$file) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
"No file exists with PHID '{$name}'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$iterator[] = $file;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
"Either specify a list of files to update, or use `--all` ".
|
||||||
|
"to update all files.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$is_dry_run = $args->getArg('dry-run');
|
||||||
|
|
||||||
|
$failed = array();
|
||||||
|
|
||||||
|
foreach ($iterator as $file) {
|
||||||
|
$fid = 'F'.$file->getID();
|
||||||
|
|
||||||
|
if (!$file->isViewableImage()) {
|
||||||
|
$console->writeOut(
|
||||||
|
"%s: Not an image file.\n",
|
||||||
|
$fid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$metadata = $file->getMetadata();
|
||||||
|
$image_width = idx($metadata, PhabricatorFile::METADATA_IMAGE_WIDTH);
|
||||||
|
$image_height = idx($metadata, PhabricatorFile::METADATA_IMAGE_HEIGHT);
|
||||||
|
if ($image_width && $image_height) {
|
||||||
|
$console->writeOut(
|
||||||
|
"%s: Already updated\n",
|
||||||
|
$fid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($is_dry_run) {
|
||||||
|
$console->writeOut(
|
||||||
|
"%s: Would update file (dry run)\n",
|
||||||
|
$fid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$console->writeOut(
|
||||||
|
"%s: Updating metadata... ",
|
||||||
|
$fid);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$file->updateDimensions();
|
||||||
|
$console->writeOut("done.\n");
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$console->writeOut("failed!\n");
|
||||||
|
$console->writeErr("%s\n", (string)$ex);
|
||||||
|
$failed[] = $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($failed) {
|
||||||
|
$console->writeOut("**Failures!**\n");
|
||||||
|
$ids = array();
|
||||||
|
foreach ($failed as $file) {
|
||||||
|
$ids[] = 'F'.$file->getID();
|
||||||
|
}
|
||||||
|
$console->writeOut("%s\n", implode(', ', $ids));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
$console->writeOut("**Success!**\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,9 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
||||||
|
|
||||||
const STORAGE_FORMAT_RAW = 'raw';
|
const STORAGE_FORMAT_RAW = 'raw';
|
||||||
|
|
||||||
|
const METADATA_IMAGE_WIDTH = 'width';
|
||||||
|
const METADATA_IMAGE_HEIGHT = 'height';
|
||||||
|
|
||||||
protected $phid;
|
protected $phid;
|
||||||
protected $name;
|
protected $name;
|
||||||
protected $mimeType;
|
protected $mimeType;
|
||||||
|
@ -12,6 +15,7 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
||||||
protected $authorPHID;
|
protected $authorPHID;
|
||||||
protected $secretKey;
|
protected $secretKey;
|
||||||
protected $contentHash;
|
protected $contentHash;
|
||||||
|
protected $metadata = array();
|
||||||
|
|
||||||
protected $storageEngine;
|
protected $storageEngine;
|
||||||
protected $storageFormat;
|
protected $storageFormat;
|
||||||
|
@ -20,6 +24,9 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
||||||
public function getConfiguration() {
|
public function getConfiguration() {
|
||||||
return array(
|
return array(
|
||||||
self::CONFIG_AUX_PHID => true,
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
self::CONFIG_SERIALIZATION => array(
|
||||||
|
'metadata' => self::SERIALIZATION_JSON,
|
||||||
|
),
|
||||||
) + parent::getConfiguration();
|
) + parent::getConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,6 +203,12 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
||||||
$file->setMimeType(Filesystem::getMimeType($tmp));
|
$file->setMimeType(Filesystem::getMimeType($tmp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$file->updateDimensions(false);
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
$file->save();
|
$file->save();
|
||||||
|
|
||||||
return $file;
|
return $file;
|
||||||
|
@ -485,6 +498,51 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
||||||
return Filesystem::readRandomCharacters(20);
|
return Filesystem::readRandomCharacters(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateDimensions($save = true) {
|
||||||
|
if (!$this->isViewableImage()) {
|
||||||
|
throw new Exception(
|
||||||
|
"This file is not a viewable image.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists("imagecreatefromstring")) {
|
||||||
|
throw new Exception(
|
||||||
|
"Cannot retrieve image information.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->loadFileData();
|
||||||
|
|
||||||
|
$img = imagecreatefromstring($data);
|
||||||
|
if ($img === false) {
|
||||||
|
throw new Exception(
|
||||||
|
"Error when decoding image.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->metadata[self::METADATA_IMAGE_WIDTH] = imagesx($img);
|
||||||
|
$this->metadata[self::METADATA_IMAGE_HEIGHT] = imagesy($img);
|
||||||
|
|
||||||
|
if ($save) {
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getMetadataName($metadata) {
|
||||||
|
switch ($metadata) {
|
||||||
|
case self::METADATA_IMAGE_WIDTH:
|
||||||
|
$name = pht('Width');
|
||||||
|
break;
|
||||||
|
case self::METADATA_IMAGE_HEIGHT:
|
||||||
|
$name = pht('Height');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$name = ucfirst($metadata);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorPolicyInterface Implementation )-------------------------- */
|
/* -( PhabricatorPolicyInterface Implementation )-------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -1081,6 +1081,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
||||||
'name' =>
|
'name' =>
|
||||||
$this->getPatchPath('20130102.metamtareceivedmailmessageidhash.sql'),
|
$this->getPatchPath('20130102.metamtareceivedmailmessageidhash.sql'),
|
||||||
),
|
),
|
||||||
|
'20130103.filemetadata.sql' => array(
|
||||||
|
'type' => 'sql',
|
||||||
|
'name' => $this->getPatchPath('20130103.filemetadata.sql'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue