mirror of
https://we.phorge.it/source/phorge.git
synced 2025-02-17 01:08:41 +01:00
PhabricatorMemeEngine HA HA HA HA
Summary: Depends on D19198. Ref T13101. Ref T5258. Pull compositing logic out of the `Controller`. This is moving toward fixing memes in email. Test Plan: Used new and old memes. Used API memes. Maniphest Tasks: T13101, T5258 Differential Revision: https://secure.phabricator.com/D19200
This commit is contained in:
parent
a099a06265
commit
c7408f2797
5 changed files with 201 additions and 115 deletions
|
@ -3295,6 +3295,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMarkupInterface' => 'infrastructure/markup/PhabricatorMarkupInterface.php',
|
'PhabricatorMarkupInterface' => 'infrastructure/markup/PhabricatorMarkupInterface.php',
|
||||||
'PhabricatorMarkupOneOff' => 'infrastructure/markup/PhabricatorMarkupOneOff.php',
|
'PhabricatorMarkupOneOff' => 'infrastructure/markup/PhabricatorMarkupOneOff.php',
|
||||||
'PhabricatorMarkupPreviewController' => 'infrastructure/markup/PhabricatorMarkupPreviewController.php',
|
'PhabricatorMarkupPreviewController' => 'infrastructure/markup/PhabricatorMarkupPreviewController.php',
|
||||||
|
'PhabricatorMemeEngine' => 'applications/macro/engine/PhabricatorMemeEngine.php',
|
||||||
'PhabricatorMemeRemarkupRule' => 'applications/macro/markup/PhabricatorMemeRemarkupRule.php',
|
'PhabricatorMemeRemarkupRule' => 'applications/macro/markup/PhabricatorMemeRemarkupRule.php',
|
||||||
'PhabricatorMentionRemarkupRule' => 'applications/people/markup/PhabricatorMentionRemarkupRule.php',
|
'PhabricatorMentionRemarkupRule' => 'applications/people/markup/PhabricatorMentionRemarkupRule.php',
|
||||||
'PhabricatorMentionableInterface' => 'applications/transactions/interface/PhabricatorMentionableInterface.php',
|
'PhabricatorMentionableInterface' => 'applications/transactions/interface/PhabricatorMentionableInterface.php',
|
||||||
|
@ -8893,6 +8894,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMarkupInterface',
|
'PhabricatorMarkupInterface',
|
||||||
),
|
),
|
||||||
'PhabricatorMarkupPreviewController' => 'PhabricatorController',
|
'PhabricatorMarkupPreviewController' => 'PhabricatorController',
|
||||||
|
'PhabricatorMemeEngine' => 'Phobject',
|
||||||
'PhabricatorMemeRemarkupRule' => 'PhutilRemarkupRule',
|
'PhabricatorMemeRemarkupRule' => 'PhutilRemarkupRule',
|
||||||
'PhabricatorMentionRemarkupRule' => 'PhutilRemarkupRule',
|
'PhabricatorMentionRemarkupRule' => 'PhutilRemarkupRule',
|
||||||
'PhabricatorMercurialGraphStream' => 'PhabricatorRepositoryGraphStream',
|
'PhabricatorMercurialGraphStream' => 'PhabricatorRepositoryGraphStream',
|
||||||
|
|
|
@ -35,22 +35,15 @@ final class MacroCreateMemeConduitAPIMethod extends MacroConduitAPIMethod {
|
||||||
protected function execute(ConduitAPIRequest $request) {
|
protected function execute(ConduitAPIRequest $request) {
|
||||||
$user = $request->getUser();
|
$user = $request->getUser();
|
||||||
|
|
||||||
$macro_name = $request->getValue('macroName');
|
$file = id(new PhabricatorMemeEngine())
|
||||||
$upper_text = $request->getValue('upperText');
|
->setViewer($user)
|
||||||
$lower_text = $request->getValue('lowerText');
|
->setTemplate($request->getValue('macroName'))
|
||||||
|
->setAboveText($request->getValue('upperText'))
|
||||||
$uri = PhabricatorMacroMemeController::generateMacro(
|
->setBelowText($request->getValue('lowerText'))
|
||||||
$user,
|
->newAsset();
|
||||||
$macro_name,
|
|
||||||
$upper_text,
|
|
||||||
$lower_text);
|
|
||||||
|
|
||||||
if (!$uri) {
|
|
||||||
throw new ConduitException('ERR-NOT-FOUND');
|
|
||||||
}
|
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'uri' => $uri,
|
'uri' => $file->getViewURI(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,104 +13,18 @@ final class PhabricatorMacroMemeController
|
||||||
$lower_text = $request->getStr('lowertext');
|
$lower_text = $request->getStr('lowertext');
|
||||||
$viewer = $request->getViewer();
|
$viewer = $request->getViewer();
|
||||||
|
|
||||||
$uri = self::generateMacro(
|
$file = id(new PhabricatorMemeEngine())
|
||||||
$viewer,
|
->setViewer($viewer)
|
||||||
$macro_name,
|
->setTemplate($macro_name)
|
||||||
$upper_text,
|
->setAboveText($request->getStr('above'))
|
||||||
$lower_text);
|
->setBelowText($request->getStr('below'))
|
||||||
|
->newAsset();
|
||||||
|
|
||||||
$content = array(
|
$content = array(
|
||||||
'imageURI' => $uri,
|
'imageURI' => $file->getViewURI(),
|
||||||
);
|
);
|
||||||
|
|
||||||
return id(new AphrontAjaxResponse())->setContent($content);
|
return id(new AphrontAjaxResponse())->setContent($content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function generateMacro(
|
|
||||||
PhabricatorUser $viewer,
|
|
||||||
$macro_name,
|
|
||||||
$upper_text,
|
|
||||||
$lower_text) {
|
|
||||||
|
|
||||||
$macro = id(new PhabricatorMacroQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withNames(array($macro_name))
|
|
||||||
->needFiles(true)
|
|
||||||
->executeOne();
|
|
||||||
if (!$macro) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$file = $macro->getFile();
|
|
||||||
|
|
||||||
$upper_text = phutil_utf8_strtoupper($upper_text);
|
|
||||||
$lower_text = phutil_utf8_strtoupper($lower_text);
|
|
||||||
|
|
||||||
$hash = PhabricatorHash::digestForIndex(
|
|
||||||
phutil_json_encode(
|
|
||||||
array(
|
|
||||||
'kind' => 'meme',
|
|
||||||
'upper' => $upper_text,
|
|
||||||
'lower' => $lower_text,
|
|
||||||
)));
|
|
||||||
|
|
||||||
$xfile = self::loadTransformedFile($viewer, $file->getPHID(), $hash);
|
|
||||||
if ($xfile) {
|
|
||||||
return $xfile->getViewURI();
|
|
||||||
}
|
|
||||||
|
|
||||||
$transformer = new PhabricatorImageTransformer();
|
|
||||||
|
|
||||||
$new_file = $transformer->executeMemeTransform(
|
|
||||||
$file,
|
|
||||||
$upper_text,
|
|
||||||
$lower_text);
|
|
||||||
|
|
||||||
$xfile = id(new PhabricatorTransformedFile())
|
|
||||||
->setOriginalPHID($file->getPHID())
|
|
||||||
->setTransformedPHID($new_file->getPHID())
|
|
||||||
->setTransform($hash);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$caught = null;
|
|
||||||
|
|
||||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
|
||||||
try {
|
|
||||||
$xfile->save();
|
|
||||||
} catch (Exception $ex) {
|
|
||||||
$caught = $ex;
|
|
||||||
}
|
|
||||||
unset($unguarded);
|
|
||||||
|
|
||||||
if ($caught) {
|
|
||||||
throw $caught;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $new_file->getViewURI();
|
|
||||||
} catch (AphrontDuplicateKeyQueryException $ex) {
|
|
||||||
$xfile = self::loadTransformedFile($viewer, $file->getPHID(), $hash);
|
|
||||||
if (!$xfile) {
|
|
||||||
throw $ex;
|
|
||||||
}
|
|
||||||
return $xfile->getViewURI();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function loadTransformedFile(
|
|
||||||
PhabricatorUser $viewer,
|
|
||||||
$file_phid,
|
|
||||||
$hash) {
|
|
||||||
|
|
||||||
$xform = id(new PhabricatorTransformedFile())->loadOneWhere(
|
|
||||||
'originalPHID = %s AND transform = %s',
|
|
||||||
$file_phid,
|
|
||||||
$hash);
|
|
||||||
if (!$xform) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return id(new PhabricatorFileQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withPHIDs(array($xform->getTransformedPHID()))
|
|
||||||
->executeOne();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
163
src/applications/macro/engine/PhabricatorMemeEngine.php
Normal file
163
src/applications/macro/engine/PhabricatorMemeEngine.php
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorMemeEngine extends Phobject {
|
||||||
|
|
||||||
|
private $viewer;
|
||||||
|
private $template;
|
||||||
|
private $aboveText;
|
||||||
|
private $belowText;
|
||||||
|
|
||||||
|
private $templateFile;
|
||||||
|
|
||||||
|
public function setViewer(PhabricatorUser $viewer) {
|
||||||
|
$this->viewer = $viewer;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getViewer() {
|
||||||
|
return $this->viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTemplate($template) {
|
||||||
|
$this->template = $template;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTemplate() {
|
||||||
|
return $this->template;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAboveText($above_text) {
|
||||||
|
$this->aboveText = $above_text;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAboveText() {
|
||||||
|
return $this->aboveText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBelowText($below_text) {
|
||||||
|
$this->belowText = $below_text;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBelowText() {
|
||||||
|
return $this->belowText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGenerateURI() {
|
||||||
|
return id(new PhutilURI('/macro/meme/'))
|
||||||
|
->alter('macro', $this->getTemplate())
|
||||||
|
->alter('above', $this->getAboveText())
|
||||||
|
->alter('below', $this->getBelowText());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newAsset() {
|
||||||
|
$cache = $this->loadCachedFile();
|
||||||
|
if ($cache) {
|
||||||
|
return $cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
$template = $this->loadTemplateFile();
|
||||||
|
if (!$template) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Template "%s" is not a valid template.',
|
||||||
|
$template));
|
||||||
|
}
|
||||||
|
|
||||||
|
$hash = $this->newTransformHash();
|
||||||
|
|
||||||
|
$transformer = new PhabricatorImageTransformer();
|
||||||
|
$asset = $transformer->executeMemeTransform(
|
||||||
|
$template,
|
||||||
|
$this->getAboveText(),
|
||||||
|
$this->getBelowText());
|
||||||
|
|
||||||
|
$xfile = id(new PhabricatorTransformedFile())
|
||||||
|
->setOriginalPHID($template->getPHID())
|
||||||
|
->setTransformedPHID($asset->getPHID())
|
||||||
|
->setTransform($hash);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$caught = null;
|
||||||
|
|
||||||
|
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||||
|
try {
|
||||||
|
$xfile->save();
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$caught = $ex;
|
||||||
|
}
|
||||||
|
unset($unguarded);
|
||||||
|
|
||||||
|
if ($caught) {
|
||||||
|
throw $caught;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $asset;
|
||||||
|
} catch (AphrontDuplicateKeyQueryException $ex) {
|
||||||
|
$xfile = $this->loadCachedFile();
|
||||||
|
if (!$xfile) {
|
||||||
|
throw $ex;
|
||||||
|
}
|
||||||
|
return $xfile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newTransformHash() {
|
||||||
|
$properties = array(
|
||||||
|
'kind' => 'meme',
|
||||||
|
'above' => phutil_utf8_strtoupper($this->getAboveText()),
|
||||||
|
'below' => phutil_utf8_strtoupper($this->getBelowText()),
|
||||||
|
);
|
||||||
|
|
||||||
|
$properties = phutil_json_encode($properties);
|
||||||
|
|
||||||
|
return PhabricatorHash::digestForIndex($properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadCachedFile() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$template_file = $this->loadTemplateFile();
|
||||||
|
if (!$template_file) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hash = $this->newTransformHash();
|
||||||
|
|
||||||
|
$xform = id(new PhabricatorTransformedFile())->loadOneWhere(
|
||||||
|
'originalPHID = %s AND transform = %s',
|
||||||
|
$template_file->getPHID(),
|
||||||
|
$hash);
|
||||||
|
if (!$xform) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return id(new PhabricatorFileQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs(array($xform->getTransformedPHID()))
|
||||||
|
->executeOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadTemplateFile() {
|
||||||
|
if ($this->templateFile === null) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$template = $this->getTemplate();
|
||||||
|
|
||||||
|
$macro = id(new PhabricatorMacroQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withNames(array($template))
|
||||||
|
->needFiles(true)
|
||||||
|
->executeOne();
|
||||||
|
if (!$macro) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->templateFile = $macro->getFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->templateFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -29,10 +29,14 @@ final class PhabricatorMemeRemarkupRule extends PhutilRemarkupRule {
|
||||||
$parser = new PhutilSimpleOptions();
|
$parser = new PhutilSimpleOptions();
|
||||||
$options = $parser->parse($matches[1]) + $options;
|
$options = $parser->parse($matches[1]) + $options;
|
||||||
|
|
||||||
$uri = id(new PhutilURI('/macro/meme/'))
|
$engine = id(new PhabricatorMemeEngine())
|
||||||
->alter('macro', $options['src'])
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
->alter('uppertext', $options['above'])
|
->setTemplate($options['src'])
|
||||||
->alter('lowertext', $options['below']);
|
->setAboveText($options['above'])
|
||||||
|
->setBelowText($options['below']);
|
||||||
|
|
||||||
|
$asset = $engine->loadCachedFile();
|
||||||
|
$uri = $engine->getGenerateURI();
|
||||||
|
|
||||||
if ($this->getEngine()->isHTMLMailMode()) {
|
if ($this->getEngine()->isHTMLMailMode()) {
|
||||||
$uri = PhabricatorEnv::getProductionURI($uri);
|
$uri = PhabricatorEnv::getProductionURI($uri);
|
||||||
|
@ -50,10 +54,20 @@ final class PhabricatorMemeRemarkupRule extends PhutilRemarkupRule {
|
||||||
$options['above'],
|
$options['above'],
|
||||||
$options['below']);
|
$options['below']);
|
||||||
|
|
||||||
$img = id(new PHUIRemarkupImageView())
|
if ($asset) {
|
||||||
->setURI($uri)
|
$img = $this->newTag(
|
||||||
->addClass('phabricator-remarkup-macro')
|
'img',
|
||||||
->setAlt($alt_text);
|
array(
|
||||||
|
'src' => $asset->getViewURI(),
|
||||||
|
'class' => 'phabricator-remarkup-macro',
|
||||||
|
'alt' => $alt_text,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
$img = id(new PHUIRemarkupImageView())
|
||||||
|
->setURI($uri)
|
||||||
|
->addClass('phabricator-remarkup-macro')
|
||||||
|
->setAlt($alt_text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->getEngine()->storeText($img);
|
return $this->getEngine()->storeText($img);
|
||||||
|
|
Loading…
Add table
Reference in a new issue