Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • omadrid/engine
  • javanick/engine
  • minds/engine
  • joe59/engine
  • eiennohi/engine
  • edgebal/engine
  • msantang78/engine
  • maruthi-adithya/engine
  • duyquoc/engine
  • benhayward.ben/engine
  • rlperez/engine
  • priestd09/engine
  • dknunn/engine
  • ascenderking/engine
  • catastrop/engine
  • jim-toth/engine
  • project_connection/engine
  • manishoo/engine
  • murbo98/engine
  • namesty/engine
  • Moikapy/engine
  • bedriguler/engine
  • CodingNagger/engine
  • jun784/engine
  • alexgleason/engine
  • gigasim97/engine
  • auxchar/engine
  • pestixaba/engine
  • m994/engine
  • webprodev/minds_engine
  • fabiolalombardim/engine
  • zackwy/engine
  • linleyj7/engine
  • fiatjaf/minds-engine
  • ppitestsblishaokai/engine
  • VARUN-KUSH/engine
  • brainr386/engine
  • th2tran/engine
38 results
Show changes
Commits on Source (2)
Showing
with 769 additions and 25 deletions
......@@ -34,4 +34,42 @@ class Moderation extends Cli\Controller implements Interfaces\CliControllerInter
$manager->run($this->getOpt('jury') ?? 'initial');
}
public function summon()
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
/** @var Core\Reports\Repository $reportsRepository */
$reportsRepository = Di::_()->get('Reports\Repository');
/** @var Core\Reports\Summons\Manager $summonsManager */
$summonsManager = Di::_()->get('Moderation\Summons\Manager');
$userId = $this->getOpt('user');
$reportUrn = $this->getOpt('report');
if (!$userId || !$reportUrn) {
$this->out('Usage: cli.php moderation summon --user=<username_or_guid> --report=<report_urn>');
exit(1);
}
$user = new Entities\User($userId, false);
if (!$user || !$user->guid) {
$this->out('Error: Invalid user');
exit(1);
}
$report = $reportsRepository->get($reportUrn);
if (!$report) {
$this->out('Error: Invalid report');
exit(1);
}
$appeal = new Core\Reports\Appeals\Appeal();
$appeal->setReport($report);
$summonsManager->summon($appeal, [ $user->guid ]);
}
}
<?php
/**
* summon
*
* @author edgebal
*/
namespace Minds\Controllers\api\v2\moderation;
use Minds\Api\Factory;
use Minds\Core\Di\Di;
use Minds\Core\Reports\Repository as ReportsRepository;
use Minds\Core\Reports\Summons\Manager;
use Minds\Core\Reports\Summons\Summon as SummonEntity;
use Minds\Core\Session;
use Minds\Interfaces;
class summon implements Interfaces\Api
{
/**
* Equivalent to HTTP GET method
* @param array $pages
* @return mixed|null
*/
public function get($pages)
{
return Factory::response([]);
}
/**
* Equivalent to HTTP POST method
* @param array $pages
* @return mixed|null
* @throws \Exception
*/
public function post($pages)
{
$reportUrn = $_POST['report_urn'] ?? null;
$juryType = $_POST['jury_type'] ?? null;
$userGuid = Session::getLoggedInUserGuid();
$status = $_POST['status'] ?? null;
/** @var Manager $summonsManager */
$summonsManager = Di::_()->get('Moderation\Summons\Manager');
/** @var ReportsRepository $reportsRepository */
$reportsRepository = Di::_()->get('Reports\Repository');
$summon = new SummonEntity();
try {
$summon
->setReportUrn($reportUrn)
->setJuryType($juryType)
->setJurorGuid((string) $userGuid)
->setStatus($status);
} catch (\Exception $e) {
return Factory::response([
'status' => 'error',
'message' => $e->getMessage(),
]);
}
if (!$summonsManager->isSummoned($summon)) {
return Factory::response([
'status' => 'error',
'message' => 'You\'re not summoned',
]);
}
$summonsManager->respond($summon);
$response = [
'summon' => $summon->getStatus(),
'expires_in' => $summon->getTtl(),
];
if ($summon->isAccepted()) {
$response['report'] = $reportsRepository->get($summon->getReportUrn());
}
return Factory::response($response);
}
/**
* Equivalent to HTTP PUT method
* @param array $pages
* @return mixed|null
*/
public function put($pages)
{
return Factory::response([]);
}
/**
* Equivalent to HTTP DELETE method
* @param array $pages
* @return mixed|null
*/
public function delete($pages)
{
return Factory::response([]);
}
}
<?php
/**
* ReportsAppealSummon
*
* @author edgebal
*/
namespace Minds\Core\Queue\Runners;
use Minds\Core\Di\Di;
use Minds\Core\Queue\Message;
use Minds\Core\Queue\Client;
use Minds\Core\Queue\Interfaces\QueueClient;
use Minds\Core\Queue\Interfaces\QueueRunner;
use Minds\Core\Reports\Summons\Manager;
class ReportsAppealSummon implements QueueRunner
{
/**
* Run the queue
* @return void
* @throws \Exception
*/
public function run()
{
/** @var QueueClient $client */
$client = Client::build();
$client
->setQueue(static::class)
->receive(function (Message $data) {
$params = $data->getData();
$appeal = $params['appeal'] ?? null;
$cohort = $params['cohort'] ?? null;
if (!$appeal) {
echo 'Invalid empty appeal' . PHP_EOL;
return;
}
/** @var Manager $manager */
$manager = Di::_()->get('Moderation\Summons\Manager');
$manager->summon($appeal, $cohort);
});
}
}
......@@ -4,25 +4,27 @@
*/
namespace Minds\Core\Reports\Appeals;
use Minds\Core\Reports\Report;
use Minds\Traits\MagicAttributes;
/**
* @method Report getOwnerGuid(): long
* @method Report getReport(): Report
* @method Report getTimestamp: int
* @method Report getNote(): int
* @method int|string getOwnerGuid()
* @method Report getReport()
* @method Appeal setReport(Report $report)
* @method int getTimestamp
* @method string getNote()
*/
class Appeal
{
use MagicAttributes;
/** @var long $timestamp -< in ms*/
/** @var int $timestamp -< in ms*/
private $timestamp;
/** @var Report $report */
private $report;
/** @var int $note */
/** @var string $note */
private $note;
/**
......
<?php
/**
* SummonDelegate
*
* @author edgebal
*/
namespace Minds\Core\Reports\Appeals\Delegates;
use Minds\Core\Queue\Client;
use Minds\Core\Queue\Interfaces\QueueClient;
use Minds\Core\Queue\Runners\ReportsAppealSummon;
use Minds\Core\Reports\Appeals\Appeal;
class SummonDelegate
{
/** @var QueueClient */
protected $queue;
public function __construct(
$queue = null
)
{
$this->queue = $queue ?: Client::build();
}
public function onAppeal(Appeal $appeal)
{
$this->queue
->setQueue(ReportsAppealSummon::class)
->send([
'appeal' => $appeal,
'cohort' => null, // TODO: It can be an array of user guids. For development purposes only.
]);
}
}
......@@ -20,26 +20,32 @@ class Manager
/** @var Repository $repository */
private $repository;
/** @var NotificationDelegate $notificationDelegate */
private $notificationDelegate;
/** @var EntitiesResolver $entitiesResolver */
private $entitiesResolver;
/** @var Delegates\NotificationDelegate $notificationDelegate */
private $notificationDelegate;
/** @var Delegates\SummonDelegate $summonDelegate */
private $summonDelegate;
public function __construct(
$repository = null,
$entitiesResolver = null,
$notificationDelegate = null
$notificationDelegate = null,
$summonDelegate = null
)
{
$this->repository = $repository ?: new Repository;
$this->entitiesResolver = $entitiesResolver ?: new EntitiesResolver;
$this->notificationDelegate = $notificationDelegate ?: new Delegates\NotificationDelegate;
$this->summonDelegate = $summonDelegate ?: new Delegates\SummonDelegate();
}
/**
* @param array $opts
* @return Response
* @throws \Exception
*/
public function getList($opts = [])
{
......@@ -77,6 +83,7 @@ class Manager
$added = $this->repository->add($appeal);
$this->summonDelegate->onAppeal($appeal);
$this->notificationDelegate->onAction($appeal);
return $added;
......
......@@ -41,5 +41,9 @@ class Provider extends DiProvider
$this->di->bind('Moderation\Strikes\Manager', function ($di) {
return new Strikes\Manager;
}, [ 'useFactory'=> true ]);
$this->di->bind('Moderation\Summons\Manager', function ($di) {
return new Summons\Manager();
}, [ 'useFactory'=> true ]);
}
}
......@@ -4,23 +4,24 @@
*/
namespace Minds\Core\Reports;
use Minds\Core\Reports\UserReport;
use Minds\Core\Reports\Jury\Decision;
use Minds\Core\Reports\UserReports\UserReport;
use Minds\Entities\Entity;
use Minds\Traits\MagicAttributes;
/**
* Class Report
* @method Report getEntityGuid(): long
* @method Report getEntityUrn(): string
* @method Report getReports(): []
* @method Report getEntity(): Entity
* @method Report isAppeal(): boolean
* @method Report getInitialJuryDecisions: []
* @method Report getAppealJuryDecisions: []
* @method Report getAppealTimestamp: int
* @method Report getReasonCode(): int
* @method Report getSubReasonCode(): int
* @method int getEntityGuid()
* @method string getEntityUrn()
* @method UserReport[] getReports()
* @method Entity getEntity()
* @method boolean isAppeal()
* @method Decision[] getInitialJuryDecisions()
* @method Decision[] getAppealJuryDecisions()
* @method int getAppealTimestamp()
* @method int getReasonCode()
* @method int getSubReasonCode()
* @method Report setState(string $string)
* @method Report getState(): string
* @method Report setTimestamp(int $timestamp)
* @method Report setReasonCode(int $value)
* @method Report setSubReasonCode(int $value)
......
......@@ -138,7 +138,8 @@ class Repository
/**
* Return a single report
* @param string $urn
* @return ReportEntity
* @return Report
* @throws \Exception
*/
public function get($urn)
{
......
<?php
/**
* Cohort
*
* @author edgebal
*/
namespace Minds\Core\Reports\Summons;
use Minds\Core\Data\ElasticSearch\Client as ElasticsearchClient;
use Minds\Core\Data\ElasticSearch\Prepared\Search;
use Minds\Core\Di\Di;
use Minds\Helpers\Text;
class Cohort
{
/** @var ElasticsearchClient */
protected $elasticsearch;
/** @var string */
protected $index;
/**
* Repository constructor.
* @param ElasticsearchClient $elasticsearch
* @param string $index
*/
public function __construct(
$elasticsearch = null,
$index = null
)
{
$this->elasticsearch = $elasticsearch ?: Di::_()->get('Database\ElasticSearch');
$this->index = $index ?: 'minds-metrics-*';
}
/**
* @param array $opts
* @return \Generator
* @yields string
*/
public function getList(array $opts = [])
{
$opts = array_merge([
'for' => null,
'active_threshold' => 0,
'platform' => null,
'validated' => false,
'limit' => 10,
'offset' => 0,
], $opts);
$now = (int) (microtime(true) * 1000);
$fromTimestamp = $now - ($opts['active_threshold'] * 1000);
$body = [
'_source' => [
'user_guid',
],
'query' => [
'bool' => [
'must' => [
[
'range' => [
'@timestamp' => [
'gte' => $fromTimestamp,
],
],
],
[
'term' => [
'type' => 'action',
],
],
],
],
],
'aggs' => [
'entities' => [
'terms' => [
'field' => 'user_guid.keyword',
'size' => $opts['limit'],
],
],
],
'size' => 0,
];
if ($opts['platform']) {
$body['query']['bool']['must'][] = [
'terms' => [
'platform' => Text::buildArray($opts['platform']),
],
];
}
if ($opts['for']) {
if (!isset($body['query']['bool']['must_not'])) {
$body['query']['bool']['must_not'] = [];
}
$body['query']['bool']['must_not'][] = [
'term' => [
'user_guid' => (string) $opts['for'],
],
];
$body['query']['bool']['must_not'][] = [
'terms' => [
'user_guid' => [
'index' => 'minds-graph',
'type' => 'subscriptions',
'id' => (string) $opts['for'],
'path' => 'guids',
],
],
];
}
if ($opts['validated']) {
$body['query']['bool']['must'][] = [
'exists' => [
'field' => 'user_phone_number_hash',
],
];
if (!isset($body['query']['bool']['must_not'])) {
$body['query']['bool']['must_not'] = [];
}
$body['query']['bool']['must_not'][] = [
'term' => [
'user_phone_number_hash' => '',
],
];
}
$query = [
'index' => $this->index,
'type' => 'action',
'body' => $body,
'size' => $opts['limit'],
'from' => $opts['offset'],
];
$prepared = new Search();
$prepared->query($query);
$result = $this->elasticsearch->request($prepared);
foreach ($result['aggregations']['entities']['buckets'] as $bucket) {
yield $bucket['key'];
}
}
}
<?php
/**
* SocketDelegate
*
* @author edgebal
*/
namespace Minds\Core\Reports\Summons\Delegates;
use Minds\Core\Reports\Summons\Summon;
use Minds\Core\Sockets\Events as SocketEvents;
class SocketDelegate
{
/** @var SocketEvents */
protected $socketEvents;
/**
* SocketDelegate constructor.
* @param SocketEvents $socketEvents
*/
public function __construct(
$socketEvents = null
)
{
$this->socketEvents = $socketEvents ?: new SocketEvents();
}
/**
* @param Summon $summon
* @throws \Exception
*/
public function onSummon(Summon $summon)
{
$this->socketEvents
->setUser($summon->getJurorGuid())
->emit('moderation_summon', json_encode($summon));
}
}
<?php
/**
* Manager
*
* @author edgebal
*/
namespace Minds\Core\Reports\Summons;
use Minds\Core\Reports\Appeals\Appeal;
use Minds\Core\Reports\Summons\Delegates;
class Manager
{
/** @var Cohort $cohort */
protected $cohort;
/** @vat Repository $repository */
protected $repository;
/** @var Delegates\SocketDelegate $socketDelegate */
protected $socketDelegate;
/**
* Manager constructor.
* @param Cohort $cohort
* @param Repository $repository
* @param Delegates\SocketDelegate $socketDelegate
*/
public function __construct(
$cohort = null,
$repository = null,
$socketDelegate = null
)
{
$this->cohort = $cohort ?: new Cohort();
$this->repository = $repository ?: new Repository();
$this->socketDelegate = $socketDelegate ?: new Delegates\SocketDelegate();
}
/**
* @param Appeal $appeal
* @param array $cohort
* @throws \Exception
*/
public function summon(Appeal $appeal, $cohort = null)
{
$cohort = $cohort ?: $this->cohort->getList([
'active_threshold' => 5 * 60,
'platform' => 'browser',
'for' => $appeal->getOwnerGuid(),
'validated' => true,
'limit' => 12,
]);
foreach ($cohort as $juror) {
$summon = new Summon();
$summon
->setReportUrn($appeal->getReport()->getUrn())
->setJuryType('appeal_jury')
->setJurorGuid($juror)
->setTtl(120)
->setStatus('awaiting');
$this->repository->add($summon);
$this->socketDelegate->onSummon($summon);
}
}
/**
* @param Summon $summon
* @return bool
*/
public function isSummoned(Summon $summon)
{
return $this->repository->exists($summon);
}
/**
* @param Summon $summon
* @return Summon
*/
public function respond(Summon $summon)
{
$summon
->setTtl(10 * 60);
$this->repository->add($summon);
return $summon;
}
}
<?php
/**
* Repository
*
* @author edgebal
*/
namespace Minds\Core\Reports\Summons;
use Cassandra\Bigint;
use Minds\Core\Data\Cassandra\Client as CassandraClient;
use Minds\Core\Data\Cassandra\Prepared\Custom;
use Minds\Core\Di\Di;
class Repository
{
/** @var CassandraClient */
protected $db;
/**
* Repository constructor.
* @param CassandraClient $db
*/
public function __construct(
$db = null
)
{
$this->db = $db ?: Di::_()->get('Database\Cassandra\Cql');
}
/**
* @param array $opts
* @throws \NotImplementedException
*/
public function getList(array $opts = [])
{
throw new \NotImplementedException();
}
/**
* @param Summon $summon
* @return bool
*/
public function add(Summon $summon)
{
$expires = time() + ((int) $summon->getTtl());
$cql = "INSERT INTO moderation_summons (report_urn, jury_type, juror_guid, status, expires) VALUES (?, ?, ?, ?, ?) USING TTL ?";
$values = [
$summon->getReportUrn(),
$summon->getJuryType(),
new Bigint($summon->getJurorGuid()),
$summon->getStatus(),
$expires,
(int) $summon->getTtl(),
];
$prepared = new Custom();
$prepared->query($cql, $values);
try {
return (bool) $this->db->request($prepared, true);
} catch (\Exception $e) {
error_log($e);
return false;
}
}
/**
* @param Summon $summon
* @return bool
*/
public function exists(Summon $summon)
{
$cql = "SELECT COUNT(*) as total FROM moderation_summons WHERE report_urn = ? AND jury_type = ? AND juror_guid = ?";
$values = [
$summon->getReportUrn(),
$summon->getJuryType(),
new Bigint($summon->getJurorGuid()),
];
$prepared = new Custom();
$prepared->query($cql, $values);
try {
$response = $this->db->request($prepared);
return $response[0]['total'] > 0;
} catch (\Exception $e) {
error_log($e);
return false;
}
}
/**
* @param Summon $summon
* @throws \NotImplementedException
*/
public function delete(Summon $summon)
{
throw new \NotImplementedException();
}
}
<?php
/**
* Summon
*
* @author edgebal
*/
namespace Minds\Core\Reports\Summons;
use Minds\Traits\MagicAttributes;
/**
* Class Summon
* @package Minds\Core\Reports\Summons
* @method string getReportUrn()
* @method Summon setReportUrn(string $reportUrn)
* @method string getJuryType()
* @method Summon setJuryType(string $juryType)
* @method int|string getJurorGuid()
* @method Summon setJurorGuid(int|string $jurorGuid)
* @method string getStatus()
* @method int getTtl()
* @method Summon setTtl(int $ttl)
*/
class Summon implements \JsonSerializable
{
use MagicAttributes;
/** @var string */
protected $reportUrn;
/** @var string */
protected $juryType;
/** @var int|string */
protected $jurorGuid;
/** @var $status */
protected $status;
/** @var int */
protected $ttl;
/**
* @param string $status
* @return $this
* @throws \Exception
*/
public function setStatus($status)
{
if (!in_array($status, ['awaiting', 'accepted', 'declined'])) {
throw new \Exception('Invalid status');
}
$this->status = $status;
return $this;
}
/**
* @return bool
*/
public function isAwaiting()
{
return $this->status === 'awaiting';
}
/**
* @return bool
*/
public function isAccepted()
{
return $this->status === 'accepted';
}
/**
* @return bool
*/
public function isDeclined()
{
return $this->status === 'declined';
}
/**
* @return array
*/
public function export()
{
return [
'report_urn' => $this->reportUrn,
'jury_type' => $this->juryType,
'juror_guid' => (string) $this->jurorGuid,
'status' => $this->status,
'ttl' => $this->ttl,
];
}
/**
* Specify data which should be serialized to JSON
* @link https://php.net/manual/en/jsonserializable.jsonserialize.php
* @return mixed data which can be serialized by <b>json_encode</b>,
* which is a value of any type other than a resource.
* @since 5.4.0
*/
public function jsonSerialize()
{
return $this->export();
}
}
......@@ -18,17 +18,20 @@ class ManagerSpec extends ObjectBehavior
private $repository;
private $entitiesResolver;
private $notificationDelegate;
private $summonDelegate;
function let(
Repository $repository,
EntitiesResolver $entitiesResolver,
Delegates\NotificationDelegate $notificationDelegate
Delegates\NotificationDelegate $notificationDelegate,
Delegates\SummonDelegate $summonDelegate
)
{
$this->beConstructedWith($repository, $entitiesResolver, $notificationDelegate);
$this->beConstructedWith($repository, $entitiesResolver, $notificationDelegate, $summonDelegate);
$this->repository = $repository;
$this->entitiesResolver = $entitiesResolver;
$this->notificationDelegate = $notificationDelegate;
$this->summonDelegate = $summonDelegate;
}
function it_is_initializable()
......@@ -84,6 +87,10 @@ class ManagerSpec extends ObjectBehavior
$this->notificationDelegate->onAction($appeal)
->shouldBeCalled();
$this->summonDelegate
->onAppeal(Argument::type(Appeal::class))
->shouldBeCalled();
$appeal->getReport()
->willReturn($report);
......