Skip to content
Commits on Source (25)
<?php
namespace Minds\Controllers\Cli;
use Minds\Core\Minds;
use Minds\Cli;
use Minds\Core\Feeds\Suggested\Manager;
use Minds\Interfaces;
class Suggested extends Cli\Controller implements Interfaces\CliControllerInterface
{
/** @var Manager */
private $manager;
public function __construct()
{
$minds = new Minds();
$minds->start();
$this->manager = new Manager();
}
public function help($command = null)
{
$this->out('Syntax usage: cli trending <type>');
}
public function exec()
{
$this->out('Syntax usage: cli trending <type>');
}
public function sync_all()
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
$this->out('Collecting trending items');
$this->manager->setFrom($this->getOpt('from') ?: strtotime('-12 hours') * 1000);
$this->manager->setTo($this->getOpt('to') ?: time() * 1000);
$this->manager->run('all');
$this->out('Completed syncing all');
}
public function sync_newsfeed()
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
$this->out('Syncing newsfeed');
$this->manager->setFrom($this->getOpt('from') ?: strtotime('-12 hours') * 1000);
$this->manager->setTo($this->getOpt('to') ?: time() * 1000);
$this->manager->run('newsfeed');
$this->out('Completed syncing newsfeed');
}
public function sync_images()
{
$this->out('Syncing images');
$this->manager->setFrom($this->getOpt('from') ?: strtotime('-12 hours') * 1000);
$this->manager->setTo($this->getOpt('to') ?: time() * 1000);
$this->manager->run('images');
$this->out('Completed syncing images');
}
public function sync_videos()
{
$this->out('Syncing videos');
$this->manager->setFrom($this->getOpt('from') ?: strtotime('-12 hours') * 1000);
$this->manager->setTo($this->getOpt('to') ?: time() * 1000);
$this->manager->run('videos');
$this->out('Completed syncing videos');
}
public function sync_groups()
{
$this->out('Syncing groups');
$this->manager->setFrom($this->getOpt('from') ?: strtotime('-12 hours') * 1000);
$this->manager->setTo($this->getOpt('to') ?: time() * 1000);
$this->manager->run('groups');
$this->out('Completed syncing groups');
}
public function sync_blogs()
{
$this->out('Syncing blogs');
$this->manager->setFrom($this->getOpt('from') ?: strtotime('-12 hours') * 1000);
$this->manager->setTo($this->getOpt('to') ?: time() * 1000);
$this->manager->run('blogs');
$this->out('Completed syncing blogs');
}
}
......@@ -178,32 +178,8 @@ class fetch implements Interfaces\Api
private function getSuggestedPosts($opts = [])
{
$opts = array_merge([
'offset' => 0,
'limit' => 12,
'rating' => 1,
], $opts);
/** @var Core\Feeds\Suggested\Manager $repo */
$repo = Di::_()->get('Feeds\Suggested\Manager');
$opts = [
'user_guid' => Core\Session::getLoggedInUserGuid(),
'rating' => $opts['rating'],
'limit' => $opts['limit'],
'offset' => $opts['offset'],
'type' => 'newsfeed',
'all' => true,
];
$result = $repo->getFeed($opts);
// Remove all unlisted content if it appears
$result = array_values(array_filter($result, function($entity) {
return $entity->getAccessId() != 0;
}));
return $result;
// @deprecated
return [];
}
}
......@@ -99,7 +99,14 @@ class comments implements Interfaces\Api
switch ($pages[0]) {
case "update":
$comment = $manager->getByLuid($pages[1]);
if (!$comment || !$comment->canEdit()) {
$canEdit = $comment->canEdit();
if ($canEdit && $comment->getOwnerGuid() != Core\Session::getLoggedInUserGuid()) {
$canEdit = false;
}
if (!$comment || !$canEdit) {
$response = array('status' => 'error', 'message' => 'This comment can not be edited');
break;
}
......
......@@ -394,6 +394,7 @@ class newsfeed implements Interfaces\Api
'mature' => $embeded instanceof Flaggable ? $embeded->getFlag('mature') : false,
'width' => $embeded->width,
'height' => $embeded->height,
'gif' => (bool) $embeded->gif ?? false,
]])
->setMature($embeded instanceof Flaggable ? $embeded->getFlag('mature') : false)
->setFromEntity($embeded)
......@@ -410,6 +411,7 @@ class newsfeed implements Interfaces\Api
'mature' => $embeded instanceof Flaggable ? $embeded->getFlag('mature') : false,
'width' => $embeded->width,
'height' => $embeded->height,
'gif' => (bool) $embeded->gif ?? false,
]])
->setMature($embeded instanceof Flaggable ? $embeded->getFlag('mature') : false)
->setFromEntity($embeded)
......@@ -606,6 +608,7 @@ class newsfeed implements Interfaces\Api
'mature' => $attachment instanceof Flaggable ? $attachment->getFlag('mature') : false,
'width' => $attachment->width,
'height' => $attachment->height,
'gif' => (bool) $attachment->gif ?? false,
]])
->setFromEntity($attachment)
->setTitle($attachment->message);
......
......@@ -47,7 +47,6 @@ class notifications implements Interfaces\Api
if (!isset($pages[0])) {
$pages = ['list'];
}
return [];
$repository = Di::_()->get('Notification\Manager');
$repository->setUser(Core\Session::getLoggedInUser());
......
......@@ -99,7 +99,6 @@ class register implements Interfaces\Api, Interfaces\ApiIgnorePam
'guid' => $guid,
'user' => $user->export()
];
} catch (\Exception $e) {
$response = array('status'=>'error', 'message'=>$e->getMessage());
}
......
......@@ -92,7 +92,14 @@ class comments implements Interfaces\Api
switch ($pages[0]) {
case "update":
$comment = $manager->getByLuid($pages[1]);
if (!$comment || !$comment->canEdit()) {
$canEdit = $comment->canEdit();
if ($canEdit && $comment->getOwnerGuid() != Core\Session::getLoggedInUserGuid()) {
$canEdit = false;
}
if (!$comment || !$canEdit) {
$response = array('status' => 'error', 'message' => 'This comment can not be edited');
break;
}
......
......@@ -68,9 +68,6 @@ class suggested implements Interfaces\Api
$hashtag = $_GET['hashtag'];
}
/** @var Core\Feeds\Suggested\Manager $repo */
$repo = Di::_()->get('Feeds\Suggested\Manager');
$opts = [
'user_guid' => Core\Session::getLoggedInUserGuid(),
'rating' => $rating,
......@@ -84,17 +81,19 @@ class suggested implements Interfaces\Api
$opts['hashtag'] = $hashtag;
}
$result = $repo->getFeed($opts);
// @deprecated
$result = [];
// Remove all unlisted content if it appears
$result = array_values(array_filter($result, function($entity) {
return $entity->getAccessId() != 0;
}));
// @deprecated
// // Remove all unlisted content if it appears
// $result = array_values(array_filter($result, function($entity) {
// return $entity->getAccessId() != 0;
// }));
return Factory::response([
'status' => 'success',
'entities' => Factory::exportable($result),
'load-next' => $limit + $offset,
'load-next' => '',
]);
}
......
......@@ -76,7 +76,7 @@ class DataProvider extends Provider
$username,
null,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => true,
PDO::ATTR_PERSISTENT => isset($config['persistent']) ? $config['persistent'] : false,
]);
......
......@@ -46,6 +46,7 @@ class Register
$manager = Di::_()->get('Referrals\Manager');
$manager->add($referral);
}
});
......
<?php
namespace Minds\Core\Feeds\Suggested;
use Minds\Core;
use Minds\Core\Di\Di;
use Minds\Entities\Entity;
use Minds\Core\EntitiesBuilder;
class Manager
{
/** @var Repository */
protected $feedsRepository;
/** @var Core\EntitiesBuilder */
protected $entitiesBuilder;
/** @var \Minds\Core\Hashtags\Entity\Repository */
private $entityHashtagsRepository;
/** @var array */
private $maps;
/** @var Core\Trending\EntityValidator */
private $validator;
private $from;
private $to;
public function __construct(
$repo = null,
$entityHashtagsRepository = null,
$validator = null,
$maps = null,
$entitiesBuilder = null
) {
$this->feedsRepository = $repo ?: Di::_()->get('Feeds\Suggested\Repository');
$this->entityHashtagsRepository = $entityHashtagsRepository ?: Di::_()->get('Hashtags\Entity\Repository');
$this->validator = $validator ?: new Core\Trending\EntityValidator();
$this->maps = $maps ?: Core\Trending\Maps::$maps;
$this->entitiesBuilder = $entitiesBuilder ?: new EntitiesBuilder;
$this->from = strtotime('-12 hours') * 1000;
$this->to = time() * 1000;
}
/**
* @param array $opts
* @return Entity[]
* @throws \Exception
*/
public function getFeed(array $opts = [])
{
$opts = array_merge([
'user_guid' => null,
'offset' => 0,
'limit' => 12,
'rating' => 1,
'type' => null,
'all' => false,
], $opts);
$guids = [];
foreach ($this->feedsRepository->getFeed($opts) as $item) {
$guids[] = $item['guid'];
}
$entities = [];
if (count($guids) > 0) {
$entities = $this->entitiesBuilder->get(['guids' => $guids]);
}
return $entities;
}
public function run(string $type)
{
//\Minds\Core\Security\ACL::$ignore = true;
$scores = [];
$maps = null;
switch ($type) {
case 'all':
$maps = $this->maps;
break;
case 'channels':
$maps = ['user' => $this->maps['channels']];
break;
case 'newsfeed':
$maps = ['newsfeed' => $this->maps['newsfeed']];
break;
case 'images':
$maps = ['image' => $this->maps['images']];
break;
case 'videos':
$maps = ['video' => $this->maps['videos']];
break;
case 'groups':
$maps = ['group' => $this->maps['groups']];
break;
case 'blogs':
$maps = ['blog' => $this->maps['blogs']];
break;
case 'default':
throw new \Exception("Invalid type. Valid values are: 'newsfeed', 'images', 'videos', 'groups' and 'blogs'");
break;
}
foreach ($maps as $key => $map) {
if (!isset($scores[$key])) {
$scores[$key] = [];
}
$ratings = [];
foreach ($map['aggregates'] as $aggregate) {
$class = is_string($aggregate) ? new $aggregate : $aggregate;
$class->setLimit(10000);
$class->setType($map['type']);
$class->setSubtype($map['subtype']);
$class->setFrom($this->from);
$class->setTo($this->to);
foreach ($class->get() as $guid => $score) {
if ($score < 2) {
continue;
}
echo "\n$guid ($score)";
//collect the entity
$entity = $this->entitiesBuilder->single($guid);
if (!$entity->guid) {
continue;
}
$tags = $entity->getTags();
if ($entity->container_guid != 0 && $entity->container_guid != $entity->owner_guid && $key == 'newsfeed') {
echo " skipping because group post";
continue; // skip groups
}
$this->saveTags($entity->guid, $tags);
$ratings[$entity->guid] = $entity->getRating();
//validate this entity is ok
if (!$this->validator->isValid($entity)) {
echo "\n[$entity->getRating()] $key: $guid ($score) invalid";
continue;
}
//is this an activity entity?
//if so, let add it the guids for this key
if ($entity->custom_type == 'batch' && $entity->entity_guid) {
if (!isset($scores['image'][$entity->entity_guid])) {
$scores['image'][$entity->entity_guid] = 0;
}
$scores['image'][$entity->entity_guid] += $score;
$ratings[$entity->entity_guid] = $ratings[$guid];
$this->saveTags($entity->entity_guid, $tags);
} elseif ($entity->custom_type == 'video' && $entity->entity_guid) {
if (!isset($scores['video'][$entity->entity_guid])) {
$scores['video'][$entity->entity_guid] = 0;
}
$scores['video'][$entity->entity_guid] += $score;
$ratings[$entity->entity_guid] = $ratings[$guid];
$this->saveTags($entity->entity_guid, $tags);
} elseif (strpos($entity->perma_url, '/blog') !== false && $entity->entity_guid) {
if (!isset($scores['blog'][$entity->entity_guid])) {
$scores['blog'][$entity->entity_guid] = 0;
}
$scores['blog'][$entity->entity_guid] += $score;
$ratings[$entity->entity_guid] = $ratings[$guid];
$this->saveTags($entity->entity_guid, $tags);
echo "\n\tblog here $entity->entity_guid";
}
if (!isset($scores[$key][$guid])) {
$scores[$key][$guid] = 0;
}
$scores[$key][$guid] += $score;
}
}
//arsort($scores[$key]);
$sync = time();
foreach ($scores as $_key => $_scores) {
foreach ($_scores as $guid => $score) {
if (! (int) $score || !$guid) {
continue;
}
if (!isset($ratings[$guid])) {
$ratings[$guid] = 2;
}
$this->feedsRepository->add([
'entity_guid' => $guid,
'score' => (int) $score,
'type' => $_key,
'rating' => $ratings[$guid],
'lastSynced' => $sync,
]);
echo "\n[{$ratings[$guid]}] $_key: $guid ($score)";
}
}
}
//\Minds\Core\Security\ACL::$ignore = false;
}
private function saveTags($guid, $tags)
{
if (!$tags) {
echo " no tags";
return;
}
$hashtagEntities = [];
foreach ($tags as $tag) {
if (strpos($tag, '#', 0) === 0) {
$tag = substr($tag, 1);
}
echo "\n\t#$tag";
$hashtagEntity = new Core\Hashtags\HashtagEntity();
$hashtagEntity->setGuid($guid);
$hashtagEntity->setHashtag(strtolower($tag));
$hashtagEntities[] = $hashtagEntity;
}
//if ($key == 'newsfeed' && count($hashtagEntities) >= 5) {
// continue;
//}
foreach ($hashtagEntities as $hashtagEntity) {
$this->entityHashtagsRepository->add([$hashtagEntity]);
}
echo "\nSaved tags to repo";
}
}
<?php
namespace Minds\Core\Feeds\Suggested;
use Minds\Core\Di\Di;
class Repository
{
/** @var \PDO */
protected $db;
public function __construct($db = null)
{
$this->db = $db ?: Di::_()->get('Database\PDO');
}
/**
* @param array $opts
* @return array
* @throws \Exception
*/
public function getFeed(array $opts = [])
{
$opts = array_merge([
'user_guid' => null,
'offset' => 0,
'limit' => 12,
'rating' => 1,
'hashtag' => null,
'type' => null,
'all' => false, // if true, it ignores user selected hashtags
], $opts);
if (!$opts['user_guid']) {
throw new \Exception('user_guid must be provided');
}
if (!$opts['type']) {
throw new \Exception('type must be provided');
}
if ($opts['hashtag']) {
$query = "SELECT DISTINCT suggested.guid as guid,
lastSynced, score
FROM suggested
JOIN entity_hashtags
ON suggested.guid = entity_hashtags.guid
WHERE entity_hashtags.hashtag = ?
AND type = ?
AND rating <= ?
ORDER BY lastSynced DESC, score DESC
LIMIT ? OFFSET ?";
$opts = [
$opts['hashtag'],
$opts['type'],
$opts['rating'],
$opts['limit'],
$opts['offset']
];
} else {
// ignore user selected hashtags if all is true
if ($opts['all']) {
$query = "SELECT DISTINCT suggested.guid as guid,
lastSynced, score
FROM suggested
WHERE type = ?
AND rating <= ?
ORDER BY lastSynced DESC, score DESC
LIMIT ? OFFSET ?";
$opts = [
$opts['type'],
$opts['rating'],
$opts['limit'],
$opts['offset']
];
} else {
$query = "SELECT DISTINCT suggested.guid as guid,
lastSynced, score
FROM user_hashtags
INNER JOIN entity_hashtags
ON user_hashtags.hashtag = entity_hashtags.hashtag
INNER JOIN suggested
ON entity_hashtags.guid = suggested.guid
WHERE user_hashtags.guid = ?
AND type = ?
AND rating <= ?
ORDER BY lastSynced DESC, score DESC
LIMIT ? OFFSET ?";
$opts = [
$opts['user_guid'],
$opts['type'],
$opts['rating'],
//date('c', strtotime('-48 minutes') / $opts['user_hashtag_count']),
//strtotime('-48 hours'),
$opts['limit'],
$opts['offset']
];
}
}
$statement = $this->db->prepare($query);
$statement->execute($opts);
return $statement->fetchAll(\PDO::FETCH_ASSOC);
}
public function add(array $opts = [])
{
$opts = array_merge([
'entity_guid' => null,
'score' => null,
'type' => null,
'rating' => null,
'lastSynced' => time(),
], $opts);
if (!$opts['entity_guid']) {
throw new \Exception('entity_guid must be provided');
}
if (!$opts['score']) {
throw new \Exception('score must be provided');
}
if (!$opts['type']) {
throw new \Exception('type must be provided');
}
if (!$opts['rating']) {
throw new \Exception('rating must be provided');
}
$query = "UPSERT INTO suggested (guid, rating, type, score, lastSynced) VALUES (?, ?, ?, ?, ?)";
$values = [
$opts['entity_guid'],
$opts['rating'],
$opts['type'],
$opts['score'],
date('c', $opts['lastSynced']),
];
$statement = $this->db->prepare($query);
return $statement->execute($values);
//if ($rating > 1) {
// $template .= " USING TTL 1200";
//}
}
public function removeAll($type)
{
if (!$type) {
throw new \Exception('type must be provided');
}
if ($type === 'all') {
$statement = $this->db->prepare("TRUNCATE suggested");
return $statement->execute();
}
$selectQuery = "SELECT suggested.guid AS guid
FROM suggested
JOIN entity_hashtags
ON suggested.guid = entity_hashtags.guid
WHERE suggested.type = ?";
$params = [
$type
];
$statement = $this->db->prepare($selectQuery);
$statement->execute($params);
$guids = $statement->fetchAll(\PDO::FETCH_ASSOC);
$guids = array_map(function ($item) {
return $item['guid'];
}, $guids);
$variables = implode(',', array_fill(0, count($guids), '?'));
$deleteQuery = "DELETE FROM suggested WHERE guid IN ({$variables})";
$statement = $this->db->prepare($deleteQuery);
return $statement->execute($guids);
}
}
......@@ -8,14 +8,6 @@ class FeedsProvider extends Provider
{
public function register()
{
$this->di->bind('Feeds\Suggested\Repository', function ($di) {
return new Suggested\Repository();
});
$this->di->bind('Feeds\Suggested\Manager', function ($di) {
return new Suggested\Manager();
});
$this->di->bind('Feeds\Top\Manager', function ($di) {
return new Top\Manager();
});
......
<?php
namespace Minds\Core\Feeds\Suggested;
use Minds\Core;
use Minds\Core\Di\Di;
use Minds\Entities\Entity;
use Minds\Core\EntitiesBuilder;
class Manager
{
/** @var Repository */
protected $feedsRepository;
/** @var Core\EntitiesBuilder */
protected $entitiesBuilder;
/** @var \Minds\Core\Hashtags\Entity\Repository */
private $entityHashtagsRepository;
/** @var array */
private $maps;
/** @var Core\Trending\EntityValidator */
private $validator;
private $from;
private $to;
public function __construct(
$repo = null,
$entityHashtagsRepository = null,
$validator = null,
$maps = null,
$entitiesBuilder = null
) {
$this->feedsRepository = $repo ?: Di::_()->get('Feeds\Suggested\Repository');
$this->entityHashtagsRepository = $entityHashtagsRepository ?: Di::_()->get('Hashtags\Entity\Repository');
$this->validator = $validator ?: new Core\Trending\EntityValidator();
$this->maps = $maps ?: Core\Trending\Maps::$maps;
$this->entitiesBuilder = $entitiesBuilder ?: new EntitiesBuilder;
$this->from = strtotime('-12 hours') * 1000;
$this->to = time() * 1000;
}
public function setFrom($from)
{
$this->from = $from;
return $this;
}
/**
* @param array $opts
* @return Entity[]
* @throws \Exception
*/
public function getFeed(array $opts = [])
{
$opts = array_merge([
'user_guid' => null,
'offset' => 0,
'limit' => 12,
'rating' => 1,
'type' => null,
'all' => false,
], $opts);
$guids = [];
foreach ($this->feedsRepository->getFeed($opts) as $item) {
$guids[] = $item['guid'];
}
$entities = [];
if (count($guids) > 0) {
$entities = $this->entitiesBuilder->get(['guids' => $guids]);
}
return $entities;
}
public function run(string $type)
{
//\Minds\Core\Security\ACL::$ignore = true;
$scores = [];
$maps = null;
switch ($type) {
case 'all':
$maps = $this->maps;
break;
case 'channels':
$maps = ['user' => $this->maps['channels']];
break;
case 'newsfeed':
$maps = ['newsfeed' => $this->maps['newsfeed']];
break;
case 'images':
$maps = ['image' => $this->maps['images']];
break;
case 'videos':
$maps = ['video' => $this->maps['videos']];
break;
case 'groups':
$maps = ['group' => $this->maps['groups']];
break;
case 'blogs':
$maps = ['blog' => $this->maps['blogs']];
break;
case 'default':
throw new \Exception("Invalid type. Valid values are: 'newsfeed', 'images', 'videos', 'groups' and 'blogs'");
break;
}
foreach ($maps as $key => $map) {
if (!isset($scores[$key])) {
$scores[$key] = [];
}
$ratings = [];
$ownersCounts = [];
foreach ($map['aggregates'] as $aggregate) {
$class = is_string($aggregate) ? new $aggregate : $aggregate;
$class->setLimit(10000);
$class->setType($map['type']);
$class->setSubtype($map['subtype']);
$class->setFrom($this->from);
$class->setTo($this->to);
foreach ($class->get() as $guid => $score) {
if ($score < 2) {
// continue;
}
echo "\n$guid ($score)";
//collect the entity
$entity = $this->entitiesBuilder->single($guid);
if (!$entity->guid) {
continue;
}
if (isset($ownersCounts[$entity->owner_guid]) && $entity->type != 'user') {
continue;
}
$ownersCounts[$entity->owner_guid] = 1;
$tags = $entity->getTags();
if ($entity->container_guid != 0 && $entity->container_guid != $entity->owner_guid) {
echo " skipping because group post";
continue; // skip groups
}
$this->saveTags($entity->guid, $tags);
$ratings[$entity->guid] = $entity->getRating();
//validate this entity is ok
if (!$this->validator->isValid($entity)) {
echo "\n[$entity->getRating()] $key: $guid ($score) invalid";
$this->feedsRepository->remove($key, $guid);
continue;
}
//is this an activity entity?
//if so, let add it the guids for this key
if ($entity->custom_type == 'batch' && $entity->entity_guid) {
if (!isset($scores['image'][$entity->entity_guid])) {
$scores['image'][$entity->entity_guid] = 0;
}
//$scores['image'][$entity->entity_guid] += $score;
//$ratings[$entity->entity_guid] = $ratings[$guid];
$this->saveTags($entity->entity_guid, $tags);
} elseif ($entity->custom_type == 'video' && $entity->entity_guid) {
if (!isset($scores['video'][$entity->entity_guid])) {
$scores['video'][$entity->entity_guid] = 0;
}
//$scores['video'][$entity->entity_guid] += $score;
//$ratings[$entity->entity_guid] = $ratings[$guid];
$this->saveTags($entity->entity_guid, $tags);
} elseif (strpos($entity->perma_url, '/blog') !== false && $entity->entity_guid) {
if (!isset($scores['blog'][$entity->entity_guid])) {
$scores['blog'][$entity->entity_guid] = 0;
}
//$scores['blog'][$entity->entity_guid] += $score;
//$ratings[$entity->entity_guid] = $ratings[$guid];
$this->saveTags($entity->entity_guid, $tags);
echo "\n\tblog here $entity->entity_guid";
}
if (!isset($scores[$key][$guid])) {
$scores[$key][$guid] = 0;
}
$scores[$key][$guid] += $score;
}
}
//arsort($scores[$key]);
$sync = time();
foreach ($scores as $_key => $_scores) {
foreach ($_scores as $guid => $score) {
if (! (int) $score || !$guid) {
echo "\n[{$ratings[$guid]}] $_key: $guid ($score) FAILED";
continue;
}
if (!isset($ratings[$guid])) {
$ratings[$guid] = 2;
}
$this->feedsRepository->add([
'entity_guid' => $guid,
'score' => (int) $score,
'type' => $_key,
'rating' => $ratings[$guid],
'lastSynced' => $sync,
]);
echo "\n[{$ratings[$guid]}] $_key: $guid ($score)";
}
}
}
//\Minds\Core\Security\ACL::$ignore = false;
}
private function saveTags($guid, $tags)
{
if (!$tags) {
echo " no tags";
return;
}
$hashtagEntities = [];
foreach ($tags as $tag) {
if (strpos($tag, '#', 0) === 0) {
$tag = substr($tag, 1);
}
echo "\n\t#$tag";
$hashtagEntity = new Core\Hashtags\HashtagEntity();
$hashtagEntity->setGuid($guid);
$hashtagEntity->setHashtag(strtolower($tag));
$hashtagEntities[] = $hashtagEntity;
}
//if ($key == 'newsfeed' && count($hashtagEntities) >= 5) {
// continue;
//}
foreach ($hashtagEntities as $hashtagEntity) {
$this->entityHashtagsRepository->add([$hashtagEntity]);
}
echo "\nSaved tags to repo";
}
}
<?php
namespace Minds\Core\Feeds\Suggested;
use Minds\Core\Di\Di;
class Repository
{
/** @var \PDO */
protected $db;
public function __construct($db = null)
{
$this->db = $db ?: Di::_()->get('Database\PDO');
}
/**
* @param array $opts
* @return array
* @throws \Exception
*/
public function getFeed(array $opts = [])
{
$opts = array_merge([
'user_guid' => null,
'offset' => 0,
'limit' => 12,
'rating' => 1,
'hashtag' => null,
'type' => null,
'all' => false, // if true, it ignores user selected hashtags
], $opts);
if (!$opts['user_guid']) {
throw new \Exception('user_guid must be provided');
}
if (!$opts['type']) {
throw new \Exception('type must be provided');
}
if ($opts['hashtag']) {
$opts['hashtag'] = strtolower($opts['hashtag']);
$query = "SELECT DISTINCT suggested.guid as guid,
lastSynced, score
FROM suggested
JOIN entity_hashtags
ON suggested.guid = entity_hashtags.guid
WHERE entity_hashtags.hashtag = ?
AND type = ?
AND rating <= ?
ORDER BY lastSynced DESC, score DESC
LIMIT ? OFFSET ?";
$opts = [
$opts['hashtag'],
$opts['type'],
$opts['rating'],
$opts['limit'],
$opts['offset']
];
} else {
// ignore user selected hashtags if all is true
if ($opts['all']) {
$query = "SELECT DISTINCT suggested.guid as guid,
lastSynced, score
FROM suggested
WHERE type = ?
AND rating <= ?
ORDER BY lastSynced DESC, score DESC
LIMIT ? OFFSET ?";
$opts = [
$opts['type'],
$opts['rating'],
$opts['limit'],
$opts['offset']
];
} else {
$query = "SELECT DISTINCT suggested.guid as guid,
lastSynced, score
FROM user_hashtags
INNER JOIN entity_hashtags
ON user_hashtags.hashtag = entity_hashtags.hashtag
INNER JOIN suggested
ON entity_hashtags.guid = suggested.guid
WHERE user_hashtags.guid = ?
AND type = ?
AND rating <= ?
ORDER BY lastSynced DESC, score DESC
LIMIT ? OFFSET ?";
$opts = [
$opts['user_guid'],
$opts['type'],
$opts['rating'],
//date('c', strtotime('-48 minutes') / $opts['user_hashtag_count']),
//strtotime('-48 hours'),
$opts['limit'],
$opts['offset']
];
}
}
$statement = $this->db->prepare($query);
$statement->execute($opts);
return $statement->fetchAll(\PDO::FETCH_ASSOC);
}
public function add(array $opts = [])
{
$opts = array_merge([
'entity_guid' => null,
'score' => null,
'type' => null,
'rating' => null,
'lastSynced' => time(),
], $opts);
if (!$opts['entity_guid']) {
throw new \Exception('entity_guid must be provided');
}
if (!$opts['score']) {
throw new \Exception('score must be provided');
}
if (!$opts['type']) {
throw new \Exception('type must be provided');
}
if (!$opts['rating']) {
throw new \Exception('rating must be provided');
}
$query = "UPSERT INTO suggested (guid, rating, type, score, lastSynced) VALUES (?, ?, ?, ?, ?)";
$values = [
$opts['entity_guid'],
$opts['rating'],
$opts['type'],
$opts['score'],
date('c', $opts['lastSynced']),
];
$statement = $this->db->prepare($query);
return $statement->execute($values);
//if ($rating > 1) {
// $template .= " USING TTL 1200";
//}
}
public function removeAll($type)
{
if (!$type) {
throw new \Exception('type must be provided');
}
if ($type === 'all') {
$statement = $this->db->prepare("TRUNCATE suggested");
return $statement->execute();
}
$selectQuery = "SELECT suggested.guid AS guid
FROM suggested
JOIN entity_hashtags
ON suggested.guid = entity_hashtags.guid
WHERE suggested.type = ?";
$params = [
$type
];
$statement = $this->db->prepare($selectQuery);
$statement->execute($params);
$guids = $statement->fetchAll(\PDO::FETCH_ASSOC);
$guids = array_map(function ($item) {
return $item['guid'];
}, $guids);
$variables = implode(',', array_fill(0, count($guids), '?'));
$deleteQuery = "DELETE FROM suggested WHERE guid IN ({$variables})";
$statement = $this->db->prepare($deleteQuery);
return $statement->execute($guids);
}
public function remove($key, $guid)
{
$statement = $this->db->prepare("DELETE FROM suggested WHERE guid = ?");
return $statement->execute([ $guid ]);
}
}
......@@ -101,7 +101,8 @@ class Entities
];
$activity = new Activity();
$activity->setEphemeral(true);
$activity->setEphemeral(true)
->setHideImpressions(true);
if ($entity instanceof Blog) {
// New entities
......
<?php
namespace Minds\Core\Hashtags\Entity;
use Minds\Core\Di\Di;
use Minds\Core\Hashtags\HashtagEntity;
class Repository
{
/** @var \PDO */
protected $db;
public function __construct($db = null)
{
$this->db = $db ?: Di::_()->get('Database\PDO');
}
/**
* Return all hashtags
*/
public function getAll($opts = [])
{
$opts = array_merge([
'entity_guid' => null
], $opts);
if (!$opts['entity_guid']) {
throw new \Exception('entity_guid must be provided');
}
$query = "SELECT * FROM entity_hashtags WHERE guid=?";
$params = [$opts['entity_guid']];
$statement = $this->db->prepare($query);
$statement->execute($params);
return $statement->fetchAll(\PDO::FETCH_ASSOC);
}
/**
* @param HashtagEntity[] $hashtags
* @return bool
*/
public function add($hashtags)
{
$query = "UPSERT INTO entity_hashtags (guid, hashtag) VALUES (?, ?)";
foreach ($hashtags as $hashtag) {
try {
$statement = $this->db->prepare($query);
if (!$hashtag->getHashtag()) {
continue;
}
return $statement->execute([$hashtag->getGuid(), $hashtag->getHashtag()]);
} catch (\Exception $e) {
error_log($e->getMessage());
}
}
return false;
}
}
......@@ -32,5 +32,4 @@ class HashtagEntity
'hashtag' => $this->getHashtag(),
];
}
}
......@@ -17,14 +17,6 @@ class HashtagsProvider extends Provider
return new User\Manager();
});
$this->di->bind('Hashtags\Entity\Repository', function ($di) {
return new Entity\Repository();
});
$this->di->bind('Hashtags\Suggested\Repository', function ($di) {
return new Suggested\Repository();
});
$this->di->bind('Hashtags\Trending\Repository', function ($di) {
return new Trending\Repository();
});
......
<?php
namespace Minds\Core\Hashtags\Suggested;
use Minds\Core\Di\Di;
class Repository
{
/** @var \PDO $db */
protected $db;
public function __construct(\PDO $db = null)
{
$this->db = $db ?: Di::_()->get('Database\PDO');
}
/**
* @param array $opts
* @return array
* @throws \Exception
*/
public function getAll(array $opts = [])
{
$opts = array_merge([
'user_guid' => null,
'limit' => null
], $opts);
if (!$opts['user_guid']) {
throw new \Exception('user_guid must be provided');
}
$query = "SELECT DISTINCT
CASE WHEN user_hashtags.hashtag IS NOT NULL THEN user_hashtags.hashtag ELSE entity_hashtags.hashtag END as value,
CASE WHEN user_hashtags.guid IS NOT NULL THEN true ELSE false END as selected
FROM suggested
JOIN entity_hashtags
ON suggested.guid = entity_hashtags.guid
FULL OUTER JOIN user_hashtags
ON (entity_hashtags.hashtag = user_hashtags.hashtag OR user_hashtags.hashtag = null)
WHERE suggested.lastSynced > ? OR suggested.lastsynced IS NULL AND user_hashtags.guid = ?
ORDER BY selected DESC, suggested.score DESC";
$params = [
date('c', strtotime('24 hours ago')),
$opts['user_guid'],
];
if ($opts['limit']) {
$query .= " LIMIT ?";
$params[] = $opts['limit'];
}
$statement = $this->db->prepare($query);
$statement->execute($params);
return $statement->fetchAll(\PDO::FETCH_ASSOC);
}
}