Page MenuHomePhabricator

D10035.id.diff
No OneTemporary

D10035.id.diff

diff --git a/resources/sql/autopatches/20150420.imagemacro.1.sql b/resources/sql/autopatches/20150420.imagemacro.1.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20150420.imagemacro.1.sql
@@ -0,0 +1,8 @@
+CREATE TABLE {$NAMESPACE}_file.file_imagemacrousage (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ macroPHID VARBINARY(64) NOT NULL,
+ authorPHID VARBINARY(64) NOT NULL,
+ count INT UNSIGNED NOT NULL,
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
diff --git a/resources/sql/autopatches/20150420.imagemacro.2.backfill.php b/resources/sql/autopatches/20150420.imagemacro.2.backfill.php
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20150420.imagemacro.2.backfill.php
@@ -0,0 +1,38 @@
+<?php
+
+$engine = PhabricatorMarkupEngine::getEngine('extract');
+$engine->setConfig('viewer', PhabricatorUser::getOmnipotentUser());
+PhabricatorEnv::setRequestBaseURI('/'); // Doesn't matter during backfill
+
+$macro_usage_table = new PhabricatorFileImageMacroUsage();
+$macro_usage_key = PhabricatorImageMacroRemarkupRule::KEY_MACRO_USAGE;
+
+$xaction_classes = id(new PhutilSymbolLoader())
+ ->setAncestorClass('PhabricatorApplicationTransaction')
+ ->loadObjects();
+
+foreach ($xaction_classes as $xaction_class) {
+ /*if (get_class($xaction_class) != "DifferentialTransaction") {
+ continue;
+ }*/
+ $objs = $xaction_class->loadAll();
+ // foreach (new LiskMigrationIterator($xaction_class) as $xaction) {
+ foreach ($objs as $obj) {
+ // $obj = $xaction_class->load($xaction->getID());
+ try {
+ $blocks = $obj->getRemarkupBlocks();
+ } catch (Exception $e) {
+ continue;
+ }
+ // $authorPHID = $xaction->getAuthorPHID();
+ $authorPHID = '';
+
+ foreach ($blocks as $block) {
+ $engine->markupText($block);
+ $macro_usage = $engine->getTextMetadata($macro_usage_key, array());
+ //$macro_usage_table->updateUsage($authorPHID, $macro_usage);
+ print($authorPHID . "\n");
+ print_r($macro_usage);
+ }
+ }
+}
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1832,6 +1832,7 @@
'PhabricatorFileFilePHIDType' => 'applications/files/phid/PhabricatorFileFilePHIDType.php',
'PhabricatorFileHasObjectEdgeType' => 'applications/files/edge/PhabricatorFileHasObjectEdgeType.php',
'PhabricatorFileImageMacro' => 'applications/macro/storage/PhabricatorFileImageMacro.php',
+ 'PhabricatorFileImageMacroUsage' => 'applications/macro/storage/PhabricatorFileImageMacroUsage.php',
'PhabricatorFileInfoController' => 'applications/files/controller/PhabricatorFileInfoController.php',
'PhabricatorFileLinkListView' => 'view/layout/PhabricatorFileLinkListView.php',
'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php',
@@ -5194,6 +5195,7 @@
'PhabricatorFlaggableInterface',
'PhabricatorPolicyInterface',
),
+ 'PhabricatorFileImageMacroUsage' => 'PhabricatorFileDAO',
'PhabricatorFileInfoController' => 'PhabricatorFileController',
'PhabricatorFileLinkListView' => 'AphrontView',
'PhabricatorFileLinkView' => 'AphrontView',
diff --git a/src/applications/macro/markup/PhabricatorImageMacroRemarkupRule.php b/src/applications/macro/markup/PhabricatorImageMacroRemarkupRule.php
--- a/src/applications/macro/markup/PhabricatorImageMacroRemarkupRule.php
+++ b/src/applications/macro/markup/PhabricatorImageMacroRemarkupRule.php
@@ -5,6 +5,7 @@
private $macros;
const KEY_RULE_MACRO = 'rule.macro';
+ const KEY_MACRO_USAGE = 'rule.macro_usage';
public function apply($text) {
return preg_replace_callback(
@@ -151,6 +152,17 @@
$engine->overwriteStoredText($spec['token'], $result);
}
+ $macro_usage_key = self::KEY_MACRO_USAGE;
+ $macro_usage = $engine->getTextMetadata($macro_usage_key, array());
+ foreach ($metadata as $spec) {
+ if (isset($macro_usage[$spec['phid']])) {
+ $macro_usage[$spec['phid']]++;
+ } else {
+ $macro_usage[$spec['phid']] = 1;
+ }
+ }
+ $engine->setTextMetadata($macro_usage_key, $macro_usage);
+
$engine->setTextMetadata($metadata_key, array());
}
diff --git a/src/applications/macro/markup/PhabricatorMemeRemarkupRule.php b/src/applications/macro/markup/PhabricatorMemeRemarkupRule.php
--- a/src/applications/macro/markup/PhabricatorMemeRemarkupRule.php
+++ b/src/applications/macro/markup/PhabricatorMemeRemarkupRule.php
@@ -59,7 +59,26 @@
));
}
- return $this->getEngine()->storeText($img);
+ $engine = $this->getEngine();
+
+ $macro_usage_key = PhabricatorImageMacroRemarkupRule::KEY_MACRO_USAGE;
+ $macro_usage = $engine->getTextMetadata($macro_usage_key, array());
+ $viewer = $engine->getConfig('viewer');
+ $macro = id(new PhabricatorMacroQuery())
+ ->setViewer($viewer)
+ ->withNames(array($options['src']))
+ ->needFiles(false)
+ ->executeOne();
+ if ($macro) {
+ if (isset($macro_usage[$macro->getPHID()])) {
+ $macro_usage[$macro->getPHID()]++;
+ } else {
+ $macro_usage[$macro->getPHID()] = 1;
+ }
+ $engine->setTextMetadata($macro_usage_key, $macro_usage);
+ }
+
+ return $engine->storeText($img);
}
}
diff --git a/src/applications/macro/query/PhabricatorMacroQuery.php b/src/applications/macro/query/PhabricatorMacroQuery.php
--- a/src/applications/macro/query/PhabricatorMacroQuery.php
+++ b/src/applications/macro/query/PhabricatorMacroQuery.php
@@ -3,9 +3,11 @@
final class PhabricatorMacroQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
+ private $byPopularity;
private $ids;
private $phids;
private $authors;
+ private $abusers;
private $names;
private $nameLike;
private $namePrefix;
@@ -41,6 +43,11 @@
return $options;
}
+ public function withPopularitySort($use_popularity_sort) {
+ $this->byPopularity = $use_popularity_sort;
+ return $this;
+ }
+
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
@@ -56,6 +63,11 @@
return $this;
}
+ public function withAbuserPHIDs(array $abusers) {
+ $this->abusers = $abusers;
+ return $this;
+ }
+
public function withNameLike($name) {
$this->nameLike = $name;
return $this;
@@ -100,15 +112,77 @@
$macro_table = new PhabricatorFileImageMacro();
$conn = $macro_table->establishConnection('r');
- $rows = queryfx_all(
+ if ($this->byPopularity) {
+ $rows = queryfx_all(
+ $conn,
+ 'SELECT m.*, SUM(n.count) as popularity FROM %T m %Q %Q %Q %Q %Q %Q',
+ $macro_table->getTableName(),
+ $this->buildJoinClause($conn),
+ $this->buildWhereClause($conn),
+ $this->buildGroupClause($conn),
+ $this->buildHavingClause($conn),
+ $this->buildOrderClause($conn),
+ $this->buildLimitClause($conn));
+ } else {
+ $rows = queryfx_all(
+ $conn,
+ 'SELECT m.* FROM %T m %Q %Q %Q',
+ $macro_table->getTableName(),
+ $this->buildWhereClause($conn),
+ $this->buildOrderClause($conn),
+ $this->buildLimitClause($conn));
+ }
+
+ $macros = $macro_table->loadAllFromArray($rows);
+ if ($this->byPopularity) {
+ $macros_by_id = mpull($macros, null, 'getId');
+
+ $macro_usage_table = new PhabricatorFileImageMacroUsage();
+ $author_popularity_rows = queryfx_all(
+ $conn,
+ 'SELECT macroPHID, authorPHID, SUM(count) as authorUses FROM %T
+ GROUP BY macroPHID, authorPHID
+ ORDER BY macroPHID, authorUses',
+ $macro_usage_table->getTableName());
+ $by_macro = ipull($author_popularity_rows, null, 'macroPHID');
+
+ foreach ($rows as $row) {
+ $macro_id = $row['id'];
+ $macro_phid = $row['phid'];
+ $author_phid = isset($by_macro[$macro_phid]) ?
+ $by_macro[$macro_phid]['authorPHID'] : null;
+ $author_uses = isset($by_macro[$macro_phid]) ?
+ $by_macro[$macro_phid]['authorUses'] : null;
+ $macros_by_id[$macro_id]->setPopularity(
+ $row['popularity'] != null ? $row['popularity'] : 0,
+ $author_phid,
+ $author_uses);
+ }
+ }
+ return $macros;
+ }
+
+
+ protected function buildHavingClause(AphrontDatabaseConnection $conn) {
+ $where = $this->buildPagingClause($conn);
+ if ($where != null) {
+ return 'HAVING '.$where;
+ }
+ return '';
+ }
+
+ protected function buildJoinClause(AphrontDatabaseConnection $conn) {
+ assert($this->byPopularity);
+ $macro_usage_table = new PhabricatorFileImageMacroUsage();
+
+ $joins = array();
+ $joins[] = qsprintf(
$conn,
- 'SELECT m.* FROM %T m %Q %Q %Q',
- $macro_table->getTableName(),
- $this->buildWhereClause($conn),
- $this->buildOrderClause($conn),
- $this->buildLimitClause($conn));
+ 'LEFT JOIN %T n ON m.phid = n.macroPHID',
+ $macro_usage_table->getTableName());
+
+ return implode(' ', $joins);
- return $macro_table->loadAllFromArray($rows);
}
protected function buildWhereClause(AphrontDatabaseConnection $conn) {
@@ -135,6 +209,13 @@
$this->authors);
}
+ if ($this->abusers && $this->byPopularity) {
+ $where[] = qsprintf(
+ $conn,
+ 'n.authorPHID IN (%Ls)',
+ $this->abusers);
+ }
+
if ($this->nameLike) {
$where[] = qsprintf(
$conn,
@@ -210,11 +291,22 @@
}
}
- $where[] = $this->buildPagingClause($conn);
+ if (!$this->byPopularity) {
+ $where[] = $this->buildPagingClause($conn);
+ }
return $this->formatWhereClause($where);
}
+ protected function buildGroupClause(AphrontDatabaseConnection $conn) {
+ $group = array();
+ $group[] = qsprintf(
+ $conn,
+ 'GROUP BY m.phid');
+
+ return implode(' ', $group);
+ }
+
protected function didFilterPage(array $macros) {
if ($this->needFiles) {
$file_phids = mpull($macros, 'getFilePHID');
@@ -242,6 +334,53 @@
return 'm';
}
+ protected function getPagingColumn() {
+ $popularity_order = 'popularity '.
+ ($this->getBeforeID() ? 'ASC' : 'DESC').', m.id';
+ return $this->byPopularity ? $popularity_order : 'm.id';
+ }
+
+ protected function getPagingValue($macro) {
+ if ($this->byPopularity) {
+ $popularity = $macro->getPopularity();
+ return (string)$popularity['popularity'].','.(string)$macro->getId();
+ }
+ return PhabricatorCursorPagedPolicyAwareQuery::getPagingValue($macro);
+ }
+
+ protected function buildPagingClause(
+ AphrontDatabaseConnection $conn_r) {
+
+ if ($this->byPopularity) {
+ if ($this->getBeforeID()) {
+ $strs = explode(',', $this->getBeforeID());
+ $beforePopularity = (int)$strs[0];
+ $beforeId = (int)$strs[1];
+
+ return qsprintf(
+ $conn_r,
+ 'popularity > %d OR (popularity = %d AND m.id > %d)',
+ $beforePopularity,
+ $beforePopularity,
+ $beforeId);
+ } else if ($this->getAfterID()) {
+ $strs = explode(',', $this->getAfterID());
+ $afterPopularity = (int)$strs[0];
+ $afterId = (int)$strs[1];
+
+ return qsprintf(
+ $conn_r,
+ 'popularity < %d OR (popularity = %d AND m.id < %d)',
+ $afterPopularity,
+ $afterPopularity,
+ $afterId);
+ }
+
+ return null;
+ }
+ return PhabricatorCursorPagedPolicyAwareQuery::buildPagingClause($conn_r);
+ }
+
public function getQueryApplicationClass() {
return 'PhabricatorMacroApplication';
}
diff --git a/src/applications/macro/query/PhabricatorMacroSearchEngine.php b/src/applications/macro/query/PhabricatorMacroSearchEngine.php
--- a/src/applications/macro/query/PhabricatorMacroSearchEngine.php
+++ b/src/applications/macro/query/PhabricatorMacroSearchEngine.php
@@ -17,6 +17,12 @@
'authorPHIDs',
$this->readUsersFromRequest($request, 'authors'));
+ $abuser_phids = $this->readUsersFromRequest($request, 'abusers');
+ $saved->setParameter(
+ 'abuserPHIDs',
+ $abuser_phids);
+ $saved->setParameter('popularitySort', !empty($abuser_phids));
+
$saved->setParameter('status', $request->getStr('status'));
$saved->setParameter('names', $request->getStrList('names'));
$saved->setParameter('nameLike', $request->getStr('nameLike'));
@@ -34,7 +40,9 @@
->needFiles(true)
->withIDs($saved->getParameter('ids', array()))
->withPHIDs($saved->getParameter('phids', array()))
- ->withAuthorPHIDs($saved->getParameter('authorPHIDs', array()));
+ ->withAuthorPHIDs($saved->getParameter('authorPHIDs', array()))
+ ->withAbuserPHIDs($saved->getParameter('abuserPHIDs', array()))
+ ->withPopularitySort($saved->getParameter('popularitySort', false));
$this->setQueryOrder($query, $saved);
@@ -79,6 +87,7 @@
PhabricatorSavedQuery $saved) {
$author_phids = $saved->getParameter('authorPHIDs', array());
+ $abuser_phids = $saved->getParameter('abuserPHIDs', array());
$status = $saved->getParameter('status');
$names = implode(', ', $saved->getParameter('names', array()));
$like = $saved->getParameter('nameLike');
@@ -97,6 +106,12 @@
->setName('authors')
->setLabel(pht('Authors'))
->setValue($author_phids))
+ ->appendControl(
+ id(new AphrontFormTokenizerControl())
+ ->setDatasource(new PhabricatorPeopleDatasource())
+ ->setName('abusers')
+ ->setLabel(pht('Abused By'))
+ ->setValue($abuser_phids))
->appendChild(
id(new AphrontFormTextControl())
->setName('nameLike')
@@ -135,11 +150,13 @@
protected function getBuiltinQueryNames() {
$names = array(
'active' => pht('Active'),
- 'all' => pht('All'),
+ 'recent' => pht('Recent'),
+ 'popular' => pht('Popular'),
);
if ($this->requireViewer()->isLoggedIn()) {
$names['authored'] = pht('Authored');
+ $names['favorites'] = pht('Favorites');
}
return $names;
@@ -152,7 +169,7 @@
switch ($query_key) {
case 'active':
return $query;
- case 'all':
+ case 'recent':
return $query->setParameter(
'status',
PhabricatorMacroQuery::STATUS_ANY);
@@ -160,6 +177,25 @@
return $query->setParameter(
'authorPHIDs',
array($this->requireViewer()->getPHID()));
+ case 'popular':
+ return $query
+ ->setParameter(
+ 'status',
+ PhabricatorMacroQuery::STATUS_ANY)
+ ->setParameter(
+ 'popularitySort',
+ true);
+ case 'favorites':
+ return $query
+ ->setParameter(
+ 'status',
+ PhabricatorMacroQuery::STATUS_ANY)
+ ->setParameter(
+ 'popularitySort',
+ true)
+ ->setParameter(
+ 'abuserPHIDs',
+ array($this->requireViewer()->getPHID()));
}
return parent::buildSavedQueryFromBuiltin($query_key);
@@ -168,7 +204,9 @@
protected function getRequiredHandlePHIDsForResultList(
array $macros,
PhabricatorSavedQuery $query) {
- return mpull($macros, 'getAuthorPHID');
+ return array_merge(
+ mpull($macros, 'getAuthorPHID'),
+ ipull(mpull($macros, 'getPopularity'), 'top_abuser'));
}
protected function renderResultList(
@@ -212,6 +250,30 @@
pht('Created by %s', $author_handle->renderLink()));
}
+ $popularity = $macro->getPopularity();
+ if ($popularity != null) {
+ $popularizer_phid = $popularity['top_abuser'];
+
+ $item->appendChild(
+ phutil_tag(
+ 'div',
+ array(),
+ pht('Popularity %d', $popularity['popularity'])));
+
+ $message = $popularity['popularity'] == 0 ?
+ pht('Wow. This macro must suck.') :
+ pht('Abused most by %s (%d time%s)',
+ $handles[$popularizer_phid]->renderLink(),
+ $popularity['top_abuser_count'],
+ $popularity['top_abuser_count'] != 1 ? 's' : '');
+ $item->appendChild(
+ phutil_tag(
+ 'div',
+ array(),
+ $message));
+ }
+
+
$item->setURI($this->getApplicationURI('/view/'.$macro->getID().'/'));
$item->setDisabled($macro->getisDisabled());
$item->setHeader($macro->getName());
diff --git a/src/applications/macro/storage/PhabricatorFileImageMacro.php b/src/applications/macro/storage/PhabricatorFileImageMacro.php
--- a/src/applications/macro/storage/PhabricatorFileImageMacro.php
+++ b/src/applications/macro/storage/PhabricatorFileImageMacro.php
@@ -17,6 +17,9 @@
private $file = self::ATTACHABLE;
private $audio = self::ATTACHABLE;
+ private $popularity = null;
+ private $topAbuser = null;
+ private $topAbuserCount = null;
const AUDIO_BEHAVIOR_NONE = 'audio:none';
const AUDIO_BEHAVIOR_ONCE = 'audio:once';
@@ -79,6 +82,23 @@
return parent::save();
}
+ public function setPopularity($popularity, $top_abuser, $top_abuser_count) {
+ $this->popularity = $popularity;
+ $this->topAbuser = $top_abuser;
+ $this->topAbuserCount = $top_abuser_count;
+ }
+
+ public function getPopularity() {
+ if (is_null($this->popularity)) {
+ return null;
+ } else {
+ return array(
+ 'popularity' => $this->popularity,
+ 'top_abuser' => $this->topAbuser,
+ 'top_abuser_count' => $this->topAbuserCount);
+ }
+ }
+
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
diff --git a/src/applications/macro/storage/PhabricatorFileImageMacroUsage.php b/src/applications/macro/storage/PhabricatorFileImageMacroUsage.php
new file mode 100644
--- /dev/null
+++ b/src/applications/macro/storage/PhabricatorFileImageMacroUsage.php
@@ -0,0 +1,51 @@
+<?php
+final class PhabricatorFileImageMacroUsage extends PhabricatorFileDAO {
+
+ /********************************/
+ /* Update our macro usage table */
+ /********************************/
+
+ private $macroPHID;
+ private $authorPHID;
+ private $count;
+
+ protected function getConfiguration() {
+ return array(
+ self::CONFIG_COLUMN_SCHEMA => array(
+ 'macroPHID' => 'phid?',
+ 'authorPHID' => 'phid?',
+ 'count' => 'uint32',
+ ),
+ self::CONFIG_KEY_SCHEMA => array(
+ ),
+ ) + parent::getConfiguration();
+ }
+
+ public function updateUsage($author_phid, $macros) {
+ if (empty($macros)) {
+ return;
+ }
+
+ $conn = $this->establishConnection('w');
+
+ // Append to our wonderful macrousage table
+ $values = array();
+ foreach ($macros as $macro_phid => $count) {
+ $values[] = qsprintf(
+ $conn,
+ '(%s, %s, %d)',
+ $macro_phid,
+ $author_phid,
+ $count);
+ }
+ $values_clause = implode(',', $values);
+
+ queryfx(
+ $conn,
+ 'INSERT INTO %T
+ (macroPHID, authorPHID, count)
+ VALUES %Q',
+ $this->getTableName(),
+ $values_clause);
+ }
+}
diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
--- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
+++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
@@ -1265,6 +1265,18 @@
$blocks,
$engine);
+ $macro_usage_table = new PhabricatorFileImageMacroUsage();
+ $macro_usage_key = PhabricatorImageMacroRemarkupRule::KEY_MACRO_USAGE;
+ $authorPHID = $this->getActor()->getPHID();
+
+ foreach ($blocks as $key => $xaction_blocks) {
+ foreach ($xaction_blocks as $block) {
+ $engine->markupText($block);
+ $macro_usage = $engine->getTextMetadata($macro_usage_key, array());
+ $macro_usage_table->updateUsage($authorPHID, $macro_usage);
+ }
+ }
+
$mentioned_phids = array();
if ($this->shouldEnableMentions($object, $xactions)) {
foreach ($blocks as $key => $xaction_blocks) {

File Metadata

Mime Type
text/plain
Expires
Mon, Mar 17, 3:46 AM (1 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7346549
Default Alt Text
D10035.id.diff (19 KB)

Event Timeline