...
 
Commits (53)
......@@ -9,6 +9,7 @@ stages:
- prepare
- review
- deploy:staging
- qa
- deploy:canary
- deploy:production
......@@ -22,7 +23,7 @@ build:
stage: build
script:
- apk update && apk add --no-cache git
- sh tools/setup.sh
- sh tools/setup.sh production
cache:
paths:
- vendor
......@@ -127,6 +128,17 @@ review:stop:
- master
- test/gitlab-ci
qa:manual:
stage: qa
script:
- echo "Manually approved"
when: manual
only:
refs:
- master
- test/gitlab-ci
allow_failure: false
staging:fpm:
stage: deploy:staging
image: minds/ci:latest
......
<?php
namespace Minds\Controllers\Cli;
use Minds\Core;
use Minds\Core\Analytics\EntityCentric\Manager;
use Minds\Cli;
use Minds\Interfaces;
use Minds\Exceptions;
use Minds\Entities;
class EntityCentric extends Cli\Controller implements Interfaces\CliControllerInterface
{
public function __construct()
{
}
public function help($command = null)
{
$this->out('TBD');
}
public function exec()
{
$this->out('Missing subcommand');
}
public function sync()
{
error_reporting(E_ALL);
ini_set('display_errors', 1);
$daysAgo = $this->getOpt('daysAgo') ?: 0;
$from = $this->getOpt('from') ?: strtotime("midnight $daysAgo days ago");
$manager = new Manager();
$manager->setFrom($from);
$i = 0;
foreach ($manager->sync() as $record) {
$this->out(++$i);
}
}
}
......@@ -50,4 +50,35 @@ class User extends Cli\Controller implements Interfaces\CliControllerInterface
$this->out("Set feature flags for {$user->username}: " . implode(', ', $features));
}
}
/**
* Resets a users passwords.
* Requires username and password.
*
* Example call: php ./cli.php User password_reset --username=nemofin --password=password123
* @return void
*/
public function password_reset()
{
try {
if (!$this->getOpt('username') || !$this->getOpt('password')) {
throw new Exceptions\CliException('Missing username / password');
}
$username = $this->getOpt('username');
$password = $this->getOpt('password');
$user = new Entities\User($username);
$user->password = Core\Security\Password::generate($user, $password);
$user->password_reset_code = "";
$user->override_password = true;
$user->save();
$this->out("Password changed successfuly for user ".$username);
} catch (Exception $e) {
$this->out("An error has occured");
$this->out($e);
}
}
}
......@@ -119,6 +119,7 @@ class authenticate implements Interfaces\Api, Interfaces\ApiIgnorePam
public function delete($pages)
{
/** @var Core\Sessions\Manager $sessions */
$sessions = Di::_()->get('Sessions\Manager');
if (isset($pages[0]) && $pages[0] === 'all') {
......
......@@ -362,7 +362,7 @@ class blog implements Interfaces\Api
}
if ($saved) {
if ($blog->isPublished() && $blog->getAccessId() == Access::PUBLIC) {
if ($blog->isPublished() && in_array($blog->getAccessId(), [Access::PUBLIC, Access::LOGGED_IN], false)) {
if (!$editing || ($editing && !$alreadyPublished) || ($editing && $oldAccessId == Access::UNLISTED)) {
(new CreateActivity())->save($blog);
}
......
......@@ -13,6 +13,7 @@ use Minds\Interfaces;
use Minds\Entities;
use Minds\Api\Factory;
use Minds\Common\ChannelMode;
use Minds\Core\Di\Di;
use ElggFile;
class channel implements Interfaces\Api
......@@ -46,6 +47,10 @@ class channel implements Interfaces\Api
return Factory::response(['status'=>'error', 'message'=>'The user is banned']);
}
Di::_()->get('Referrals\Cookie')
->setEntity($user)
->create();
$user->fullExport = true; //get counts
$user->exportCounts = true;
$return = Factory::exportable([$user]);
......
......@@ -347,15 +347,22 @@ class comments implements Interfaces\Api
$comment = $manager->getByLuid($pages[0]);
if ($comment && $comment->canEdit()) {
if (!$comment) {
return Factory::response([
'status' => 'error',
'message' => 'Comment not found',
]);
}
if ($comment->canEdit()) {
$manager->delete($comment);
return Factory::response([]);
}
//check if owner of activity trying to remove
$entity = Entities\Factory::build($comment->getEntityGuid());
if ($entity->owner_guid == Core\Session::getLoggedInUserGuid()) {
$manager->delete($comment, [ 'force' => true ]);
$manager->delete($comment, ['force' => true]);
return Factory::response([]);
}
......
......@@ -38,10 +38,10 @@ class media implements Interfaces\Api, Interfaces\ApiIgnorePam
switch ($entity->subtype) {
case "video":
Helpers\Counters::increment($pages[0], 'plays');
// Helpers\Counters::increment($pages[0], 'plays');
if (isset($pages[1]) && $pages[1] == 'play') {
http_response_code(301);
http_response_code(302);
if ($entity->subtype == 'audio') {
\forward($entity->getSourceUrl('128.mp3'));
......
......@@ -514,9 +514,6 @@ class newsfeed implements Interfaces\Api
$activity->indexes = ["activity:$activity->owner_guid:edits"]; //don't re-index on edit
(new Core\Translation\Storage())->purge($activity->guid);
$attachmentPaywallDelegate = new Core\Feeds\Activity\Delegates\AttachmentPaywallDelegate();
$attachmentPaywallDelegate->onUpdate($activity);
if (isset($_POST['time_created']) && ($_POST['time_created'] != $activity->getTimeCreated())) {
try {
$timeCreatedDelegate = new Core\Feeds\Activity\Delegates\TimeCreatedDelegate();
......@@ -532,6 +529,8 @@ class newsfeed implements Interfaces\Api
$save->setEntity($activity)
->save();
(new Core\Entities\PropagateProperties())->from($activity);
$activity->setExportContext(true);
return Factory::response(['guid' => $activity->guid, 'activity' => $activity->export(), 'edited' => true]);
}
......
......@@ -67,52 +67,59 @@ class views implements Interfaces\Api
]);
break;
case 'activity':
$activity = new Entities\Activity($pages[1]);
case 'entity':
$entity = Entities\Factory::build($pages[1]);
if (!$activity->guid) {
if (!$entity) {
return Factory::response([
'status' => 'error',
'message' => 'Could not find activity post'
'message' => 'Could not the entity'
]);
}
try {
Core\Analytics\App::_()
if ($entity->type === 'activity') {
try {
Core\Analytics\App::_()
->setMetric('impression')
->setKey($activity->guid)
->setKey($entity->guid)
->increment();
if ($activity->remind_object) {
Core\Analytics\App::_()
if ($entity->remind_object) {
Core\Analytics\App::_()
->setMetric('impression')
->setKey($activity->remind_object['guid'])
->setKey($entity->remind_object['guid'])
->increment();
Core\Analytics\App::_()
Core\Analytics\App::_()
->setMetric('impression')
->setKey($activity->remind_object['owner_guid'])
->setKey($entity->remind_object['owner_guid'])
->increment();
}
}
Core\Analytics\User::_()
Core\Analytics\User::_()
->setMetric('impression')
->setKey($activity->owner_guid)
->setKey($entity->owner_guid)
->increment();
} catch (\Exception $e) {
error_log($e->getMessage());
} catch (\Exception $e) {
error_log($e->getMessage());
}
}
try {
$viewsManager->record(
(new Core\Analytics\Views\View())
->setEntityUrn($activity->getUrn())
->setOwnerGuid((string) $activity->getOwnerGuid())
->setEntityUrn($entity->getUrn())
->setOwnerGuid((string) $entity->getOwnerGuid())
->setClientMeta($_POST['client_meta'] ?? [])
);
} catch (\Exception $e) {
error_log($e);
}
Di::_()->get('Referrals\Cookie')
->setEntity($entity)
->create();
break;
}
......
......@@ -25,6 +25,8 @@ class wallet implements Interfaces\Api
*/
public function get($pages)
{
Factory::isLoggedIn();
/** @var abstractCacher $cache */
$cache = Di::_()->get('Cache');
......
......@@ -124,10 +124,14 @@ class feed implements Interfaces\Api
// $next = 0;
// }
$len = count($boosts);
$next = $boosts[$len -1]->getTimestamp();
if ($boosts[$len -1]) {
$next = $boosts[$len -1]->getTimestamp();
}
} elseif ($isBoostFeed) {
$len = count($boosts);
$next = $boosts[$len -1]->getTimestamp();
if ($boosts[$len -1]) {
$next = $boosts[$len -1]->getTimestamp();
}
}
// $ttl = 1800; // 30 minutes
......
......@@ -29,6 +29,13 @@ class connect implements Interfaces\Api
]);
}
if (!$account) {
return Factory::response([
'status' => 'error',
'message' => 'Account not found',
]);
}
return Factory::response([
'account' => $account->export(),
]);
......
......@@ -28,7 +28,14 @@ class transactions implements Interfaces\Api
'message' => 'There was an error returning the usd account',
]);
}
if (!$account) {
return Factory::response([
'status' => 'error',
'message' => 'Stripe account not found',
]);
}
$transactionsManger = new Stripe\Transactions\Manager();
$transactions = $transactionsManger->getByAccount($account);
......
......@@ -34,6 +34,13 @@ class channel implements Interfaces\Api
$channel->fullExport = true; //get counts
$channel->exportCounts = true;
if (!$channel->isPro()) {
return Factory::response([
'status' => 'error',
'message' => 'E_NOT_PRO'
]);
}
/** @var Manager $manager */
$manager = Di::_()->get('Pro\Manager');
$manager->setUser($channel);
......
......@@ -13,6 +13,12 @@ class emails implements Interfaces\Api
public function get($pages)
{
$user = Core\Session::getLoggedInUser();
if (!$user) {
return Factory::response([
'status' => 'error',
'message' => 'User must be logged in.'
]);
}
$campaigns = [ 'when', 'with', 'global' ];
......
<?php
namespace Minds\Core\Analytics\EntityCentric;
use Minds\Core\Analytics\Metrics\Active;
use DateTime;
use Exception;
class ActiveUsersSynchroniser
{
/** @var array */
private $records = [];
/** @var Active */
private $activeMetric;
public function __construct($activeMetric = null)
{
$this->activeMetric = $activeMetric ?? new Active();
}
/**
* @param int $from
* @return self
*/
public function setFrom($from): self
{
$this->from = $from;
return $this;
}
/**
* Convert to records
* @return iterable
*/
public function toRecords(): iterable
{
$date = (new DateTime())->setTimestamp($this->from);
$now = new DateTime();
$days = (int) $date->diff($now)->format('%a');
$months = round($days / 28);
// Daily resolution
foreach ($this->activeMetric->get($days ?: 1) as $bucket) {
$record = new EntityCentricRecord();
$record->setEntityUrn("urn:metric:global")
->setOwnerGuid((string) 0) // Site is owner
->setTimestamp($bucket['timestamp'])
->setResolution('day')
->incrementSum('active::total', $bucket['total']);
$this->records[] = $record;
}
// Monthly resolution
foreach ($this->activeMetric->get($months ?: 1, 'month') as $bucket) {
$record = new EntityCentricRecord();
$record->setEntityUrn("urn:metric:global")
->setOwnerGuid((string) 0) // Site is owner
->setTimestamp($bucket['timestamp'])
->setResolution('month')
->incrementSum('active::total', $bucket['total']);
$this->records[] = $record;
}
foreach ($this->records as $record) {
yield $record;
}
}
}
<?php
/**
* EntityCentricRecord
* @author Mark
*/
namespace Minds\Core\Analytics\EntityCentric;
use Minds\Traits\MagicAttributes;
/**
* Class EntityCentricRecord
* @package Minds\Core\Analytics\EntityCentric
* @method EntityCentricRecord setResolution(int $year)
* @method string getResolution()
* @method EntityCentricRecord setEntityUrn(string $entityUrn)
* @method string getEntityUrn()
* @method EntityCentricRecord setOwnerGuid(string $ownerGuid)
* @method string getOwnerGuid()
* @method EntityCentricRecord setTimestampMs(int $timestampMs)
* @method int getTimestampMs()
* @method EntityCentricRecord setTimestamp(int $timestamp)
* @method int getTimestamp()
* @method EntityCentricRecord setSums(array $sums)
* @method int getSums()
*/
class EntityCentricRecord
{
use MagicAttributes;
/** @var string */
private $resolution;
/** @var int */
protected $timestamp;
/** @var int */
protected $timestampMs;
/** @var string */
protected $entityUrn;
/** @var string */
protected $ownerGuid;
/** @var array */
private $sums;
/**
* Increment views
* @param string $metric
* @param int $value
* @return EntityCentricRecord
*/
public function incrementSum($metric, $value = 1): EntityCentricRecord
{
if (!isset($this->sums[$metric])) {
$this->sums[$metric] = 0;
}
$this->sums[$metric] = $this->sums[$metric] + $value;
return $this;
}
}
<?php
/**
* EntityCentric Manager
* @author Mark
*/
namespace Minds\Core\Analytics\EntityCentric;
use DateTime;
use Exception;
class Manager
{
/** @var array */
const SYNCHRONISERS = [
SignupsSynchroniser::class,
ActiveUsersSynchroniser::class,
ViewsSynchroniser::class,
];
/** @var Repository */
protected $repository;
/** @var int */
private $from;
/** @var int */
private $to;
public function __construct(
$repository = null
) {
$this->repository = $repository ?: new Repository();
}
/**
* @param int $from
* @return self
*/
public function setFrom($from): self
{
$this->from = $from;
return $this;
}
/**
* Synchronise views from cassandra to elastic
* @return iterable
*/
public function sync(): iterable
{
foreach (Manager::SYNCHRONISERS as $synchroniserClass) {
$synchroniser = new $synchroniserClass;
$date = (new DateTime())->setTimestamp($this->from);
$synchroniser->setFrom($this->from);
foreach ($synchroniser->toRecords() as $record) {
$this->add($record);
yield $record;
}
// Call again incase any leftover
$this->repository->bulk();
}
echo "done";
}
/**
* Add an entity centric record to the database
* @param EntityCentricRecord $record
* @return bool
*/
public function add(EntityCentricRecord $record): bool
{
return (bool) $this->repository->add($record);
}
/**
* Query aggregate
* @param array $query
* @return array
*/
public function getAggregateByQuery(array $query): array
{
}
}
<?php
/**
* EntityCentric Repository
* @author Mark
*/
namespace Minds\Core\Analytics\EntityCentric;
use DateTime;
use DateTimeZone;
use Exception;
use Minds\Common\Repository\Response;
use Minds\Core\Data\ElasticSearch\Client as ElasticClient;
use Minds\Core\Di\Di;
class Repository
{
/** @var ElasticClient */
protected $es;
/** @var array $pendingBulkInserts * */
private $pendingBulkInserts = [];
/**
* Repository constructor.
* @param ElasticClient $es
*/
public function __construct(
$es = null
) {
$this->es = $es ?: Di::_()->get('Database\ElasticSearch');
}
/**
* @param array $opts
* @return Response
*/
public function getList(array $opts = [])
{
$response = new Response();
return $response;
}
/**
* @param EntityCentricRecord $record
* @return bool
* @throws Exception
*/
public function add(EntityCentricRecord $record)
{
$index = 'minds-entitycentric-' . date('m-Y', $record->getTimestamp());
$body = [
'resolution' => $record->getResolution(),
'@timestamp' => $record->getTimestamp() * 1000,
'entity_urn' => $record->getEntityUrn(),
'owner_guid' => $record->getOwnerGuid(),
];
$body = array_merge($body, $record->getSums());
$body = array_filter($body, function ($val) {
if ($val === '' || $val === null) {
return false;
}
return true;
});
$this->pendingBulkInserts[] = [
'update' => [
'_id' => (string) implode('-', [ $record->getEntityUrn(), $record->getResolution(), $record->getTimestamp() ]),
'_index' => $index,
'_type' => '_doc',
],
];
$this->pendingBulkInserts[] = [
'doc' => $body,
'doc_as_upsert' => true,
];
if (count($this->pendingBulkInserts) > 2000) { //1000 inserts
$this->bulk();
}
}
/**
* Bulk insert results
*/
public function bulk()
{
if (count($this->pendingBulkInserts) > 0) {
$res = $this->es->bulk(['body' => $this->pendingBulkInserts]);
$this->pendingBulkInserts = [];
}
}
}
<?php
namespace Minds\Core\Analytics\EntityCentric;
use Minds\Core\Analytics\Metrics\Signup;
use DateTime;
use Exception;
class SignupsSynchroniser
{
/** @var array */
private $records = [];
/** @var Signup */
private $signupMetric;
public function __construct($signupMetric = null)
{
$this->signupMetric = $signupMetric ?? new Signup;
}
/**
* @param int $from
* @return self
*/
public function setFrom($from): self
{
$this->from = $from;
return $this;
}
/**
* Convert to records
* @return iterable
*/
public function toRecords(): iterable
{
$date = (new DateTime())->setTimestamp($this->from);
$now = new DateTime();
$days = (int) $date->diff($now)->format('%a');
foreach ($this->signupMetric->get($days) as $bucket) {
error_log($bucket['date']);
$record = new EntityCentricRecord();
$record->setEntityUrn("urn:metric:global")
->setOwnerGuid((string) 0) // Site is owner
->setTimestamp($bucket['timestamp'])
->setResolution('day')
->incrementSum('signups::total', $bucket['total']);
$this->records[] = $record;
}
foreach ($this->records as $record) {
yield $record;
}
}
}
<?php
namespace Minds\Core\Analytics\EntityCentric;
use Minds\Core\Analytics\Views\Repository as ViewsRepository;
use DateTime;
use Exception;
class ViewsSynchroniser
{
/** @var array */
private $records = [];
/** @var ViewsRepository */
private $viewsRepository;
public function __construct($viewsRepository = null)
{
$this->viewsRepository = $viewsRepository ?: new ViewsRepository();
}
/**
* @param int $from
* @return self
*/
public function setFrom($from): self
{
$this->from = $from;
return $this;
}
/**
* Convert to records
* @return iterable
*/
public function toRecords(): iterable
{
$date = (new DateTime())->setTimestamp($this->from);
$opts['day'] = intval($date->format('d'));
$opts['month'] = intval($date->format('m'));
$opts['year'] = $date->format('Y');
$opts['from'] = $this->from;
$i = 0;
while (true) {
$result = $this->viewsRepository->getList($opts);
$opts['offset'] = $result->getPagingToken();
foreach ($result as $view) {
// if (!in_array($view->getSource(), [ 'single', 'feed/channel'])) {
// continue;
// }
$this->downsampleViewToRecord($view);
error_log(++$i);
}
if ($result->isLastPage()) {
break;
}
}
foreach ($this->records as $record) {
yield $record;
}
}
/**
* Add entity to map
* @param View $view
* @return void
*/
private function downsampleViewToRecord($view): void
{
$entityUrn = $view->getEntityUrn();
if (!isset($this->records[$view->getEntityUrn()])) {
$timestamp = (new \DateTime())->setTimestamp($view->getTimestamp())->setTime(0, 0, 0);
$record = new EntityCentricRecord();
$record->setEntityUrn($view->getEntityUrn())
->setOwnerGuid($view->getOwnerGuid())
->setTimestamp($timestamp->getTimestamp())
->setResolution('day');
$this->records[$view->getEntityUrn()] = $record;
}
if ($view->getCampaign()) {
$this->records[$view->getEntityUrn()]->incrementSum('views::boosted');
} else {
$this->records[$view->getEntityUrn()]->incrementSum('views::organic');
}
if ($view->getSource() === 'single') {
$this->records[$view->getEntityUrn()]->incrementSum('views::single');
}
$this->records[$view->getEntityUrn()]->incrementSum('views::total');
}
}
......@@ -78,6 +78,9 @@ class Sums
public function getContractBalance($contract = '', $onlySpend = false)
{
if (!$this->user) {
return 0;
}
$cql = "SELECT SUM(amount) as balance from blockchain_transactions_mainnet WHERE user_guid = ? AND wallet_address = ?";
$values = [
new Varint($this->user->guid),
......
<?php
namespace Minds\Core\Blogs;
use Minds\Core\Di\Provider;
class BlogsProvider extends Provider
{
public function register()
{
$this->di->bind('Blogs\Manager', function () {
return new Manager();
});
}
}
<?php
namespace Minds\Core\Blogs\Delegates;
use Minds\Core\Entities\Propagator\Properties;
use Minds\Entities\Activity;
/**
* Class PropagateProperties
* @package Minds\Core\Blogs\Delegates
*/
class PropagateProperties extends Properties
{
protected $actsOnSubtype = ['blog'];
/**
* Propagate Entity properties to activity
* @param $from
* @param Activity $to
* @return Activity
*/
public function toActivity($from, Activity $to): Activity
{
if ($this->valueHasChanged($from->getTitle(), $to->get('title'))) {
$to->set('title', $from->getTitle());
}
$blurb = strip_tags($from->getBody());
if ($this->valueHasChanged($blurb, $to->get('blurb'))) {
$to->set('blurb', $blurb);
}
if ($this->valueHasChanged($from->getUrl(), $to->getURL())) {
$to->setURL($from->getUrl());
}
if ($this->valueHasChanged($from->getIconUrl(), $to->get('thumbnail_src'))) {
$to->set('thumbnail_src', $from->getIconUrl());
}
return $to;
}
/**
* Propagate activity properties to entity
* @param Activity $from
* @param $to
* @return mixed
*/
public function fromActivity(Activity $from, $to)
{
return $to;
}
}
......@@ -8,19 +8,11 @@ use Minds\Core\Events\EventsDispatcher;
class Events
{
/** @var Legacy\Entity */
protected $legacyEntity;
/** @var Manager */
protected $manager;
/** @var EventsDispatcher */
protected $eventsDispatcher;
public function __construct($legacyEntity = null, $manager = null, $eventsDispatcher = null)
public function __construct($eventsDispatcher = null)
{
$this->legacyEntity = $legacyEntity ?: new Legacy\Entity();
$this->manager = $manager ?: new Manager();
$this->eventsDispatcher = $eventsDispatcher ?: Di::_()->get('EventsDispatcher');
}
......@@ -31,7 +23,7 @@ class Events
$params = $event->getParameters();
if ($params['row']->type == 'object' && $params['row']->subtype == 'blog') {
$blog = $this->legacyEntity->build($params['row']);
$blog = (new Legacy\Entity())->build($params['row']);
$blog->setEphemeral(false);
$event->setResponse($blog);
......@@ -42,7 +34,8 @@ class Events
$this->eventsDispatcher->register('entity:save', 'object:blog', function (Event $event) {
$blog = $event->getParameters()['entity'];
$event->setResponse($this->manager->update($blog));
$manager = Di::_()->get('Blogs\Manager');
$event->setResponse($manager->update($blog));
});
}
}
......@@ -9,6 +9,7 @@
namespace Minds\Core\Blogs;
use Minds\Core\Di\Di;
use Minds\Core\Entities\PropagateProperties;
use Minds\Core\Security\Spam;
class Manager
......@@ -31,6 +32,9 @@ class Manager
/** @var Delegates\Search */
protected $search;
/** @var PropagateProperties */
protected $propagateProperties;
/**
* Manager constructor.
* @param null $repository
......@@ -39,6 +43,7 @@ class Manager
* @param null $feeds
* @param null $spam
* @param null $search
* @param PropagateProperties $propagateProperties
* @throws \Exception
*/
public function __construct(
......@@ -47,7 +52,8 @@ class Manager
$slug = null,
$feeds = null,
$spam = null,
$search = null
$search = null,
PropagateProperties $propagateProperties = null
) {
$this->repository = $repository ?: new Repository();
$this->paywallReview = $paywallReview ?: new Delegates\PaywallReview();
......@@ -55,6 +61,7 @@ class Manager
$this->feeds = $feeds ?: new Delegates\Feeds();
$this->spam = $spam ?: Di::_()->get('Security\Spam');
$this->search = $search ?: new Delegates\Search();
$this->propagateProperties = $propagateProperties ?? Di::_()->get('PropagateProperties');
}
/**
......@@ -170,6 +177,7 @@ class Manager
}
$this->paywallReview->queue($blog);
$this->propagateProperties->from($blog);
}
return $saved;
......
......@@ -3,6 +3,7 @@
namespace Minds\Core\Blogs;
use Minds\Core;
use Minds\Core\Di\Di;
use Minds\Entities;
use Minds\Helpers;
use Minds\Helpers\Counters;
......@@ -10,13 +11,8 @@ use Zend\Diactoros\ServerRequestFactory;
class SEO
{
/** @var Manager */
protected $manager;
public function __construct(
$manager = null
) {
$this->manager = $manager ?: new Manager();
}
public function setup()
......@@ -104,7 +100,7 @@ class SEO
});
}
public function viewHandler($slugs = [])
public function viewHandler($slugs = [], $manager = null)
{
if (!is_numeric($slugs[0]) && isset($slugs[1]) && is_numeric($slugs[1])) {
$guid = $slugs[1];
......@@ -112,7 +108,10 @@ class SEO
$guid = $slugs[0];
}
$blog = $this->manager->get($guid);
if (is_null($manager)) {
$manager = Di::_()->get('Blogs\Manager');
}
$blog = $manager->get($guid);
if (!$blog || !$blog->getTitle() || Helpers\Flags::shouldFail($blog) || !Core\Security\ACL::_()->read($blog)) {
header("HTTP/1.0 404 Not Found");
return [
......
......@@ -13,20 +13,15 @@ use Minds\Core\Events\Event;
class Events
{
/** @var Manager */
protected $manager;
/** @var Dispatcher */
protected $eventsDispatcher;
/**
* Events constructor.
* @param Manager $manager
* @param Dispatcher $eventsDispatcher
*/
public function __construct($manager = null, $eventsDispatcher = null)
public function __construct($eventsDispatcher = null)
{
$this->manager = $manager ?: Di::_()->get('Channels\Manager');
$this->eventsDispatcher = $eventsDispatcher ?: Di::_()->get('EventsDispatcher');
}
......@@ -35,8 +30,8 @@ class Events
// User entity deletion
$this->eventsDispatcher->register('entity:delete', 'user', function (Event $event) {
$user = $event->getParameters()['entity'];
$event->setResponse($this->manager->setUser($user)->delete());
$manager = Di::_()->get('Channels\Manager');
$event->setResponse($manager->setUser($user)->delete());
});
}
}
......@@ -19,25 +19,16 @@ use Minds\Core\Security\ACL;
class Events
{
/** @var Manager */
protected $manager;
/** @var Dispatcher */
protected $eventsDispatcher;
/** @var Votes\Manager */
protected $votesManager;
/**
* Events constructor.
* @param Manager $manager
* @param Dispatcher $eventsDispatcher
*/
public function __construct($manager = null, $eventsDispatcher = null, $votesManager = null)
public function __construct($eventsDispatcher = null)
{
$this->manager = $manager ?: new Manager();
$this->eventsDispatcher = $eventsDispatcher ?: Di::_()->get('EventsDispatcher');
$this->votesManager = $votesManager ?: new Votes\Manager();
}
public function register()
......@@ -46,23 +37,24 @@ class Events
$this->eventsDispatcher->register('entity:resolve', 'comment', function (Event $event) {
$luid = $event->getParameters()['luid'];
$event->setResponse($this->manager->getByLuid($luid));
$manager = new Manager();
$event->setResponse($manager->getByLuid($luid));
});
// Entity save
$this->eventsDispatcher->register('entity:save', 'comment', function (Event $event) {
$comment = $event->getParameters()['entity'];
$event->setResponse($this->manager->update($comment));
$manager = new Manager();
$event->setResponse($manager->update($comment));
});
// Votes Module
$this->eventsDispatcher->register('vote:action:has', 'comment', function (Event $event) {
$votesManager = new Votes\Manager();
$event->setResponse(
$this->votesManager
$votesManager
->setVote($event->getParameters()['vote'])
->has()
);
......@@ -81,8 +73,9 @@ class Events
$vote->getDirection()
);
$votesManager = new Votes\Manager();
$event->setResponse(
$this->votesManager
$votesManager
->setVote($event->getParameters()['vote'])
->cast()
);
......@@ -101,8 +94,9 @@ class Events
$vote->getDirection()
);
$votesManager = new Votes\Manager();
$event->setResponse(
$this->votesManager
$votesManager
->setVote($event->getParameters()['vote'])
->cancel()
);
......
......@@ -2,11 +2,12 @@
/**
* Minds Data Client Factory
*/
namespace Minds\Core\data;
namespace Minds\Core\Data;
class Client
{
private static $default = '\Minds\Core\Data\cassandra\client';
private static $default = '\Minds\Core\Data\Cassandra\Client';
private static $clients = [];
/**
......
You've received a gift of 2 Minds tokens! You can spend these tokens to earn 2,000 extra views on your content with [Boost](https://www.minds.com/boost?__e_ct_guid=<?= $vars['guid']?>&campaign=<?= $vars['campaign']?>&topic=<?= $vars['topic'] ?>&validator=<?= $vars['validator'] ?>) or to tip your favorite content creators with [Wire](https://www.minds.com/wire?__e_ct_guid=<?= $vars['guid']?>&campaign=<?= $vars['campaign']?>&topic=<?= $vars['topic'] ?>&validator=<?= $vars['validator'] ?>).
Please use the button below to claim your gift (note: you will need to open the link in a web browser, the mobile app is not yet supported):
| |
|:--:|
| [![Claim Gift](https://cdn-assets.minds.com/emails/claim-gift.png){=150x}](https://www.minds.com/wallet/tokens/transactions?__e_ct_guid=<?= $vars['guid']?>&campaign=<?= $vars['campaign']?>&topic=<?= $vars['topic'] ?>&validator=<?= $vars['validator'] ?>) |
| |
......@@ -14,8 +14,6 @@ use Minds\Helpers\MagicAttributes;
/**
* Save Action
* @method Save setEntity($entity)
* @method bool save(...$args)
*/
class Save
{
......
<?php
namespace Minds\Core\Entities\Delegates;
use Minds\Core\Entities\Propagator\Properties;
use Minds\Entities\Activity;
/**
* Class PropagateProperties
* @package Minds\Core\Entities\Delegates
*/
class PropagateProperties extends Properties
{
/**
* Propagate Entity properties to activity
* @param $from
* @param Activity $to
* @return Activity
*/
public function toActivity($from, Activity $to): Activity
{
if ($this->valueHasChanged($from->getNsfw(), $to->getNsfw())) {
$to->setNsfw($from->getNsfw());
}
if ($this->valueHasChanged($from->getNsfwLock(), $to->getNsfwLock())) {
$to->setNsfwLock($from->getNsfwLock());
}
return $to;
}
/**
* Propagate activity properties to entity
* @param Activity $from
* @param $to
* @return mixed
*/
public function fromActivity(Activity $from, $to)
{
if ($this->valueHasChanged($from->getNsfw(), $to->getNsfw())) {
$to->setNsfw($from->getNsfw());
}
if ($this->valueHasChanged($from->getNsfwLock(), $to->getNsfwLock())) {
$to->setNsfwLock($from->getNsfwLock());
}
return $to;
}
}
<?php
namespace Minds\Core\Entities;
use Minds\Core\Data\Call;
use Minds\Core\Di\Di;
use Minds\Core\Entities\Actions\Save;
use Minds\Core\Entities\Propagator\Properties;
use Minds\Core\EntitiesBuilder;
use Minds\Entities\Activity;
use Minds\Core;
/**
* Class PropagateProperties
* @package Minds\Core\Entities
*/
class PropagateProperties
{
/** @var Properties[] */
protected $propagators;
/** @var Call */
private $db;
/** @var Save */
private $save;
/** @var EntitiesBuilder */
private $entitiesBuilder;
/** @var bool */
private $changed = false;
/**
* PropagateProperties constructor.
* @param Call|null $db
* @param Save|null $save
* @param EntitiesBuilder|null $entitiesBuilder
*/
public function __construct(Call $db = null, Save $save = null, EntitiesBuilder $entitiesBuilder = null)
{
$this->db = $db ?? new Call('entities_by_time');
$this->save = $save ?? new Save();
$this->entitiesBuilder = $entitiesBuilder ?? Di::_()->get('EntitiesBuilder');
$this->registerPropagators();
}
/**
* Register PropagateProperties classes
* @throws \Exception
*/
protected function registerPropagators(): void
{
$this->addPropagator(Core\Blogs\Delegates\PropagateProperties::class);
$this->addPropagator(Core\Feeds\Delegates\PropagateProperties::class);
$this->addPropagator(Core\Media\Delegates\PropagateProperties::class);
$this->addPropagator(Core\Entities\Delegates\PropagateProperties::class);
$this->addPropagator(Core\Permissions\Delegates\PropagateProperties::class);
}
public function clearPropogators(): void
{
$this->propagators = [];
}
/**
* Add a propagator to be called in the chain
* @param string $class
* @throws \Exception
*/
protected function addPropagator(string $class): void
{
$obj = new $class();
if (!$obj instanceof Properties) {
throw new \Exception('Propagator class is not a Property Propagator');
}
$this->propagators[] = $obj;
}
/**
* Propagate the properties from the passed entity
* @param $entity
*/
public function from($entity): void
{
if ($entity instanceof Activity) {
$this->fromActivity($entity);
} else {
$this->toActivities($entity);
}
}
/**
* Propagate properties from an Activity to to it's attachment
* @param Activity $activity
* @throws \Minds\Exceptions\StopEventException
* @throws \Exception
*/
protected function fromActivity(Activity $activity): void
{
$this->changed = false;
$attachment = $this->entitiesBuilder->single($activity->get('entity_guid'));
if (empty($attachment)) {
return;
}
foreach ($this->propagators as $propagator) {
if ($propagator->willActOnEntity($attachment)) {
$attachment = $propagator->fromActivity($activity, $attachment);
$this->changed |= $propagator->changed();
if (!is_object($attachment)) {
throw new \Exception(get_class($propagator) . ' fromActivity method did not return a modified object');
}
}
}
if ($this->changed) {
$this->save->setEntity($attachment)->save();
}
}
/**
* Propagate properties from an Entity to it's activities
* @param $entity
* @throws \Minds\Exceptions\StopEventException
*/
protected function toActivities($entity): void
{
$activities = $this->getActivitiesForEntity($entity->getGuid());
foreach ($activities as $activity) {
$this->propagateToActivity($entity, $activity);
if ($this->changed) {
$this->save->setEntity($activity)->save();
}
}
}
/**
* Get activities for an entity
* @param string $entityGuid
* @return Activity[]
*/
private function getActivitiesForEntity(string $entityGuid): array
{
$activities = [];
foreach ($this->db->getRow("activity:entitylink:{$entityGuid}") as $activityGuid => $ts) {
$activities[] = $this->entitiesBuilder->single($activityGuid);
}
return $activities;
}
/**
* Propagate properties from and entity to an activity
* @param $entity
* @param Activity $activity
*/
public function propagateToActivity($entity, Activity &$activity): void
{
$this->changed = false;
foreach ($this->propagators as $propagator) {
if ($propagator->willActOnEntity($entity)) {
$activity = $propagator->toActivity($entity, $activity);
$this->changed |= $propagator->changed();
}
}
}
}
<?php
namespace Minds\Core\Entities\Propagator;
use Minds\Entities\Activity;
/**
* Properties class that all PropagateProperties delegates should inherit
* @package Minds\Core\Entities\Propagator
*/
abstract class Properties
{
/**
* @var array
*/
protected $actsOnType = [];
/**
* @var array
*/
protected $actsOnSubtype = [];
/**
* @var bool
*/
protected $changed = false;
/**
* @return array
*/
public function actsOnType(): array
{
return $this->actsOnType;
}
/**
* @return array
*/
public function actsOnSubType(): array
{
return $this->actsOnSubtype;
}
/**
* @param $entity
* @return bool
* @throws \Exception
*/
public function willActOnEntity($entity): bool
{
if (!is_array($this->actsOnType)) {
throw new \Exception('actsOnType must be an array');
}
if (!is_array($this->actsOnSubtype)) {
throw new \Exception('actsOnSubType must be an array');
}
if ($this->actsOnType === [] || in_array($entity->getType(), $this->actsOnType, true)) {
if ($this->actsOnSubtype === []) {
return true;
}
if (!is_callable([$entity, 'getSubtype'], true)) {
return false;
}
return in_array($entity->getSubtype(), $this->actsOnSubtype, true);
}
return false;
}
/**
* @param $from
* @param $to
* @return bool
*/
protected function valueHasChanged($from, $to): bool
{
$changed = $from !== $to;
$this->changed |= $changed;
return $changed;
}
/**
* @return bool
*/
public function changed(): bool
{
return $this->changed;
}
/**
* @param $from
* @param Activity $to
* @return Activity
*/
abstract public function toActivity($from, Activity $to): Activity;
/**
* @param Activity $from
* @param $to
* @return mixed
*/
abstract public function fromActivity(Activity $from, $to);
}
<?php
/**
* ActivityDelegateInterface
* @author edgebal
*/
namespace Minds\Core\Feeds\Activity\Delegates;
use Minds\Entities\Activity;
interface ActivityDelegateInterface
{
public function onAdd();
public function onUpdate(Activity $activity);
}
<?php
/**
* AttachmentPaywallDelegate
* @author edgebal
*/
namespace Minds\Core\Feeds\Activity\Delegates;
use Minds\Core\Di\Di;
use Minds\Core\Entities\Actions\Save;
use Minds\Core\EntitiesBuilder;
use Minds\Entities\Activity;
class AttachmentPaywallDelegate implements ActivityDelegateInterface
{
/** @var EntitiesBuilder */
protected $entitiesBuilder;
/** @var Save */
protected $save;
/**
* AttachmentPaywallDelegate constructor.
* @param EntitiesBuilder $entitiesBuilder
* @param Save $save
*/
public function __construct(
$entitiesBuilder = null,
$save = null
) {
$this->entitiesBuilder = $entitiesBuilder ?: Di::_()->get('EntitiesBuilder');
$this->save = $save ?: new Save();
}
/**
* @throws \NotImplementedException
*/
public function onAdd()
{
throw new \NotImplementedException();
}
/**
* @param Activity $activity
* @return bool
*/
public function onUpdate(Activity $activity)
{
if ($activity->entity_guid) {
$attachment = $this->entitiesBuilder->single($activity->entity_guid);
if ($attachment->owner_guid == $activity->owner_guid) {
$attachment->access_id = $activity->isPaywall() ? 0 : 2;
if ($attachment->getSubtype() === 'blog') {
$attachment->setHidden($activity->isPaywall());
} else {
$attachment->hidden = $activity->isPaywall();
}
if (method_exists($attachment, 'setFlag')) {
$attachment->setFlag('paywall', (bool) $activity->isPaywall());
}
if (method_exists($attachment, 'setWireThreshold')) {
$attachment->setWireThreshold($activity->getWireThreshold() ?: false);
}
$this->save
->setEntity($attachment)
->save();
}
}
return true;
}
}
<?php
namespace Minds\Core\Feeds\Delegates;
use Minds\Core\Blogs\Blog;
use Minds\Core\Entities\Propagator\Properties;
use Minds\Entities\Activity;
use Minds\Entities\Entity;
/**
* Class PropagateProperties
* @package Minds\Core\Feeds\Delegates
*/
class PropagateProperties extends Properties
{
/**
* Propagate Entity properties to activity
* @param $from
* @param Activity $to
* @return Activity
*/
public function toActivity($from, Activity $to): Activity
{
if ($this->valueHasChanged((int)$from->getModeratorGuid(), (int)$to->getModeratorGuid())) {
$to->setModeratorGuid((int)$from->getModeratorGuid());
}
if ($this->valueHasChanged((int)$from->getTimeModerated(), (int)$to->getTimeModerated())) {
$to->setTimeModerated((int)$from->getTimeModerated());
}
return $to;
}
/**
* Propagate activity properties to entity
* @param Activity $from
* @param Entity|Blog $to
* @return mixed
*/
public function fromActivity(Activity $from, $to)
{
if ($this->valueHasChanged((int)$from->getModeratorGuid(), (int)$to->getModeratorGuid())) {
$to->setModeratorGuid((int)$from->getModeratorGuid());
}
if ($this->valueHasChanged((int)$from->getTimeModerated(), (int)$to->getTimeModerated())) {
$to->setTimeModerated((int)$from->getTimeModerated());
}
$to = $this->propagateAttachmentPaywallProperties($from, $to);
return $to;
}
/**
* @param Activity $from
* @param Entity $to
* @return mixed
*/
private function propagateAttachmentPaywallProperties(Activity $from, $to)
{
if ($to->owner_guid == $from->owner_guid) {
$newAccessId = $from->isPaywall() ? 0 : 2;
if ($this->valueHasChanged($to->access_id, $from->access_id)) {
$to->access_id = $newAccessId;
}
$newHidden = $from->isPayWall();
if ($to->getSubtype() === 'blog') {
/** @var $to Blog */
if ($this->valueHasChanged($to->getHidden(), $newHidden)) {
$to->setHidden($newHidden);
}
} else {
if ($this->valueHasChanged($to->hidden, $newHidden)) {
$to->hidden = $newHidden;
}
}
if (method_exists($to, 'setFlag')) {
if ($this->valueHasChanged($to->getFlag('paywall'), (bool)$from->isPaywall())) {
$to->setFlag('paywall', (bool)$from->isPaywall());
}
}
if (method_exists($to, 'setWireThreshold')) {
if ($this->valueHasChanged($to->getWireThreshold(), $from->getWireThreshold())) {
$to->setWireThreshold($from->getWireThreshold() ?: false);
}
}
}
return $to;
}
}
......@@ -3,12 +3,10 @@
namespace Minds\Core\Feeds\Firehose;
use Minds\Entities\User;
use Minds\Entities\Entity;
use Minds\Core\EntitiesBuilder;
use Minds\Core\Data\Call;
use Minds\Core\Entities\Actions\Save;
use Minds\Core\Di\Di;
use Minds\Core\Feeds\Top\Manager as TopFeedsManager;
use Minds\Core\Entities\PropagateProperties;
class Manager
{
......@@ -16,25 +14,21 @@ class Manager
protected $topFeedsManager;
/** @var ModerationCache */
protected $moderationCache;
/** @var EntitiesBuilder $entitiesBuilder */
protected $entitiesBuilder;
/** @var Call */
protected $db;
/** @var Save */
protected $save;
/** @var PropagateProperties */
protected $propagateProperties;
public function __construct(
TopFeedsManager $topFeedsManager = null,
ModerationCache $moderationCache = null,
EntitiesBuilder $entitiesBuilder = null,
Call $db = null,
Save $save = null
Save $save = null,
PropagateProperties $propagateProperties = null
) {
$this->topFeedsManager = $topFeedsManager ?: Di::_()->get('Feeds\Top\Manager');
$this->moderationCache = $moderationCache ?: new ModerationCache();
$this->entitiesBuilder = $entitiesBuilder ?: Di::_()->get('EntitiesBuilder');
$this->db = $db ?: new Call('entities_by_time');
$this->save = $save ?: new Save(); //Mockable, else instantiate a new one on save.
$this->save = $save ?: new Save();
$this->propagateProperties = $propagateProperties ?? Di::_()->get('PropagateProperties');
}
/**
......@@ -79,7 +73,7 @@ class Manager
* Marks an entity as moderated.
*
* @param $entity the entity to mark as moderated, typeless because images do not inherit entity
* @param User $user the moderator
* @param User $moderator the moderator
* @param int $time
*/
public function save(
......@@ -91,22 +85,8 @@ class Manager
$time = time();
}
//Save the entity
$this->saveEntity($entity, $moderator, $time);
if (method_exists($entity, 'getType')
&& $entity->getType() == 'activity'
&& $entity->get('entity_guid')
) {
$attachment = $this->entitiesBuilder->single($entity->get('entity_guid'));
$this->saveEntity($attachment, $moderator, $time);
}
//Moderate parents
foreach ($this->db->getRow('activity:entitylink:'.$entity->getGUID()) as $parentGuid => $ts) {
$activity = $this->entitiesBuilder->single($parentGuid);
$this->saveEntity($activity, $moderator, $time);
}
$this->propagateProperties->from($entity);
}
private function saveEntity(
......
......@@ -18,7 +18,7 @@ class Events
*/
public function register()
{
\elgg_register_plugin_hook_handler('entities_class_loader', 'all', function ($hook, $type, $return, $row) {
Dispatcher::register('entities_class_loader', "elgg/hook/all", function ($hook, $type, $return, $row) {
if ($row->type == 'group') {
$entity = new GroupEntity();
$entity->loadFromArray((array) $row);
......
<?php
namespace Minds\Core\Media\Delegates;
use Minds\Core\Entities\Propagator\Properties;
use Minds\Entities\Activity;
/**
* Class PropagateProperties
* @package Minds\Core\Media\Delegates
*/
class PropagateProperties extends Properties
{
protected $actsOnType = ['object'];
protected $actsOnSubtype = ['image', 'video'];
/**
* Propagate Entity properties to activity
* @param $from
* @param Activity $to
* @return Activity
*/
public function toActivity($from, Activity $to): Activity
{
if ($this->valueHasChanged($from->title, $to->getMessage())) {
$to->setMessage($from->title);
}
$fromData = $from->getActivityParameters();
$toData = $to->getCustom();
if ((!isset($toData[1])) || (isset($toData[1]) && $this->valueHasChanged($fromData[1], $toData[1]))) {
$to->setCustom($fromData[0], $fromData[1]);
}
return $to;
}
/**
* Propagate activity properties to entity
* @param Activity $from
* @param $to
* @return mixed
*/
public function fromActivity(Activity $from, $to)
{
if ($this->valueHasChanged($from->getMessage(), $to->title)) {
$to->title = $from->getMessage();
}
return $to;
}
}
<?php
/**
* @author: eiennohi.
*/
namespace Minds\Core\Media\Delegates;
use Minds\Core\Data\Call;
use Minds\Entities\Image;
use Minds\Entities\Video;
class UpdateActivities
{
/** @var Call */
private $indexDb;
private $entityDb;
public function __construct($indexDb = null, $entityDb = null)
{
$this->indexDb = $indexDb ?: new Call('entities_by_time');
$this->entityDb = $entityDb ?: new Call('entities');
}
/**
* @param Image|Video $entity
*/
public function updateActivities($entity)
{
foreach ($this->indexDb->getRow("activity:entitylink:{$entity->guid}") as $guid => $ts) {
$this->entityDb->insert($guid, ['message' => $entity->title]);
$parameters = $entity->getActivityParameters();
$this->entityDb->insert($guid, ['custom_type' => $parameters[0]]);
$this->entityDb->insert($guid, ['custom_data' => json_encode($parameters[1])]);
}
}
}
......@@ -5,17 +5,15 @@ namespace Minds\Core\Media;
use Minds\Core;
use Minds\Entities;
use Minds\Helpers;
use Minds\Core\Media;
class Feeds
{
private $updateActivitiesDelegate;
protected $entity;
protected $propagateProperties;
public function __construct($updateActivitiesDelegate = null)
public function __construct(Core\Entities\PropagateProperties $propagateProperties = null)
{
$this->updateActivitiesDelegate = $updateActivitiesDelegate ?: new Delegates\UpdateActivities();
$this->propagateProperties = $propagateProperties ?? Core\Di\Di::_()->get('PropagateProperties');
}
public function setEntity($entity)
......@@ -25,7 +23,7 @@ class Feeds
return $this;
}
public function createActivity()
public function createActivity(): Entities\Activity
{
if (!$this->entity) {
throw new \Exception('Entity not set');
......@@ -54,7 +52,7 @@ class Feeds
throw new \Exception('Entity not set');
}
$this->updateActivitiesDelegate->updateActivities($this->entity);
$this->propagateProperties->from($this->entity);
}
public function dispatch(array $targets = [])
......
......@@ -80,7 +80,7 @@ class TranscodingStatus
public function isTranscodingComplete()
{
$transcodes = $this->getTranscodes();
return (count($transcodes) === $this->getExpectedTranscodeCount());
return (count($transcodes) >= $this->getExpectedTranscodeCount());
}
/**
......@@ -90,7 +90,7 @@ class TranscodingStatus
{
return array_reduce($this->presets, function ($count, $preset) {
return $count + count($preset['formats']);
}, 0);
}, 0) / 2; // 50% is ok
}
/**
......
......@@ -3,6 +3,7 @@
namespace Minds\Core;
use Minds\Core\Di\Di;
use Minds\Core\Events\Dispatcher;
/**
* Core Minds Engine.
......@@ -111,6 +112,7 @@ class Minds extends base
(new Feeds\FeedsProvider())->register();
(new Analytics\AnalyticsProvider())->register();
(new Channels\ChannelsProvider())->register();
(new Blogs\BlogsProvider())->register();
}
/**
......@@ -141,12 +143,12 @@ class Minds extends base
/*
* Boot the system, @todo this should be oop?
*/
\elgg_trigger_event('boot', 'system');
Dispatcher::trigger('boot', 'elgg/event/system', null, true);
/*
* Complete the boot process for both engine and plugins
*/
elgg_trigger_event('init', 'system');
Dispatcher::trigger('init', 'elgg/event/system', null, true);
/*
* tell the system that we have fully booted
......@@ -156,7 +158,7 @@ class Minds extends base
/*
* System loaded and ready
*/
\elgg_trigger_event('ready', 'system');
Dispatcher::trigger('ready', 'elgg/event/system', null, true);
}
/**
......
<?php
namespace Minds\Core\Notification;
use Cassandra;
use Minds\Core;
use Minds\Core\Di\Di;
use Minds\Core\Data;
use Minds\Core\Data\Cassandra\Prepared;
use Minds\Entities;
class LegacyRepository
{
const NOTIFICATION_TTL = 30 * 24 * 60 * 60;
protected $owner;
public function __construct($db = null)
{
$this->db = $db ?: Di::_()->get('Database\Cassandra\Cql');
}
public function setOwner($guid)
{
if (is_object($guid)) {
$guid = $guid->guid;
} elseif (is_array($guid)) {
$guid = $guid['guid'];
}
$this->owner = $guid;
return $this;
}
public function getAll($type = null, array $options = [])
{
if (!$this->owner) {
throw new \Exception('Should call to setOwner() first');
}
$options = array_merge([
'limit' => 12,
'offset' => ''
], $options);
$template = "SELECT * FROM notifications WHERE owner_guid = ?";
$values = [ new Cassandra\Varint($this->owner) ];
$allowFiltering = false;
if ($type) {
// TODO: Switch template to materialized view
$template .= " AND type = ?";
$values[] = (string) $type;
$allowFiltering = true;
}
$template .= " ORDER BY guid DESC";
if ($allowFiltering) {
$template .= " ALLOW FILTERING";
}
$query = new Prepared\Custom();
$query->query($template, $values);
$query->setOpts([
'page_size' => $options['limit'],
'paging_state_token' => base64_decode($options['offset'], true)
]);
$notifications = [];
try {
$result = $this->db->request($query);
foreach ($result as $row) {
$notification = new Notification();
$data = json_decode($row['data'], true);
$params = $data['params'];
$params['description'] = $data['description'];
$entityGuid = $data['entity']['guid'];
if ($data['entity']['type'] == 'comment') {
$luid = json_decode(base64_decode($data['entity']['luid'], true), true);
$entityGuid = $luid['guid'];
}
$notification
->setUUID((string) $row['guid'])
->setToGuid((string) $row['owner_guid'])
->setType($data['notification_view'])
->setFromGuid($data['from']['guid'])
->setEntityGuid($data['entity']['guid'] ?: $data['entity']['_guid'])
->setCreatedTimestamp($data['time_created'])
->setData($params);
$notifications[] = $notification;
}
} catch (\Exception $e) {
// TODO: Log or warning
}
return [
'notifications' => $notifications,
'token' => base64_encode($result->pagingStateToken())
];
}
public function getEntity($guid)
{
if (!$guid) {
return false;
}
if (!$this->owner) {
throw new \Exception('Should call to setOwner() first');
}
$template = "SELECT * FROM notifications WHERE owner_guid = ? AND guid = ? LIMIT ?";
$values = [ new Cassandra\Varint($this->owner), new Cassandra\Varint($guid), 1 ];
$query = new Prepared\Custom();
$query->query($template, $values);
$notification = false;
try {
$result = $this->db->request($query);
if (isset($result[0]) && $result[0]) {
$notification = new Entities\Notification();
$notification->loadFromArray($result[0]['data']);
}
} catch (\Exception $e) {
// TODO: Log or warning
}
return $notification;
}
public function store($data, $age = 0)
{
if (!isset($data['guid']) || !$data['guid']) {
return false;
}
if (!$this->owner) {
throw new \Exception('Should call to setOwner() first');
}
$ttl = static::NOTIFICATION_TTL - $age;
if ($ttl < 0) {
return false;
}
$template = "INSERT INTO notifications (owner_guid, guid, type, data) VALUES (?, ?, ?, ?) USING TTL ?";
$values = [
new Cassandra\Varint($this->owner),
new Cassandra\Varint($data['guid']),
isset($data['filter']) && $data['filter'] ? $data['filter'] : 'other',
json_encode($data),
$ttl
];
$query = new Prepared\Custom();
$query->query($template, $values);
try {
$success = $this->db->request($query);
} catch (\Exception $e) {
return false;
}
return $success;
}
public function delete($guid)
{
if (!$guid) {
return false;
}
if (!$this->owner) {
throw new \Exception('Should call to setOwner() first');
}
$template = "DELETE FROM notifications WHERE owner_guid = ? AND guid = ? LIMIT ?";
$values = [ new Cassandra\Varint($this->owner), new Cassandra\Varint($guid), 1];
$query = new Prepared\Custom();
$query->query($template, $values);
try {
$success = $this->db->request($query);
} catch (\Exception $e) {
return false;
}
return (bool) $success;
}
public function count()
{
if (!$this->owner) {
throw new \Exception('Should call to setOwner() first');
}
$template = "SELECT COUNT(*) FROM notifications WHERE owner_guid = ?";
$values = [ new Cassandra\Varint($this->owner) ];
$query = new Prepared\Custom();
$query->query($template, $values);
try {
$result = $this->db->request($query);
$count = (int) $result[0]['count'];
} catch (\Exception $e) {
$count = 0;
}
return $count;
}
}
......@@ -51,10 +51,10 @@ class Manager
{
$dob = explode('-', $account->getDateOfBirth());
$data = [
'managed' => true,
'type' => 'custom',
'country' => $account->getCountry(),
'legal_entity' => [
'type' => 'individual',
'business_type' => 'individual',
'individual' => [
'first_name' => $account->getFirstName(),
'last_name' => $account->getLastName(),
'address' => [
......@@ -78,21 +78,22 @@ class Manager
// Required for JP only
if ($account->getGender()) {
$data['legal_entity']['gender'] = $account->getGender();
$data['individual']['gender'] = $account->getGender();
}
if ($account->getPhoneNumber()) {
$data['legal_entity']['phone_number'] = $account->getPhoneNumber();
$data['individual']['phone'] = $account->getPhoneNumber();
}
// US 1099 requires SSN
if ($account->getSSN()) {
$data['legal_entity']['ssn_last_4'] = $account->getSSN();
$data['individual']['ssn_last_4'] = $account->getSSN();
$data['requested_capabilities'] = ['card_payments', 'transfers'];
}
if ($account->getPersonalIdNumber()) {
$data['legal_entity']['personal_id_number'] = $account->getPersonalIdNumber();
$data['individual']['id_number'] = $account->getPersonalIdNumber();
}
$result = $this->accountInstance->create($data);
......
<?php
namespace Minds\Core\Permissions\Delegates;
use Minds\Core\Entities\Propagator\Properties;
use Minds\Entities\Activity;
/**
* Class PropagateProperties
* @package Minds\Core\Permissions\Delegates
*/
class PropagateProperties extends Properties
{
/**
* Propagate Entity properties to activity
* @param $from
* @param Activity $to
* @return Activity
*/
public function toActivity($from, Activity $to): Activity
{
if ($this->valueHasChanged($from->getAllowComments(), $to->getAllowComments())) {
$to->setAllowComments($from->getAllowComments());
}
return $to;
}
/**
* Propagate activity properties to entity
* @param Activity $from
* @param $to
* @return mixed
*/
public function fromActivity(Activity $from, $to)
{
if ($this->valueHasChanged($from->getAllowComments(), $to->getAllowComments())) {
$to->setAllowComments($from->getAllowComments());
}
return $to;
}
}
......@@ -1446,6 +1446,55 @@ CREATE TABLE minds.email_campaign_logs (
PRIMARY KEY (receiver_guid, time_sent)
) WITH CLUSTERING ORDER BY (time_sent desc);
CREATE TABLE minds.moderation_reports (
entity_urn text,
reason_code tinyint,
sub_reason_code decimal,
timestamp timestamp,
appeal_jury map<bigint, boolean>,
appeal_note text,
entity_owner_guid bigint,
initial_jury map<bigint, boolean>,
reports set<bigint>,
state text,
state_changes map<text, timestamp>,
uphold boolean,
user_hashes set<text>,
PRIMARY KEY (entity_urn, reason_code, sub_reason_code, timestamp)
) WITH CLUSTERING ORDER BY (reason_code ASC, sub_reason_code ASC, timestamp DESC);
CREATE MATERIALIZED VIEW minds.moderation_reports_by_entity_owner_guid AS
SELECT *
FROM minds.moderation_reports
WHERE entity_owner_guid IS NOT NULL AND reason_code IS NOT NULL AND sub_reason_code IS NOT NULL AND timestamp IS NOT NULL
PRIMARY KEY (entity_owner_guid, timestamp, entity_urn, reason_code, sub_reason_code)
WITH CLUSTERING ORDER BY (timestamp DESC, entity_urn ASC, reason_code ASC, sub_reason_code ASC);
CREATE MATERIALIZED VIEW minds.moderation_reports_by_state AS
SELECT *
FROM minds.moderation_reports
WHERE state IS NOT NULL AND reason_code IS NOT NULL AND sub_reason_code IS NOT NULL AND timestamp IS NOT NULL
PRIMARY KEY (state, timestamp, entity_urn, reason_code, sub_reason_code)
WITH CLUSTERING ORDER BY (timestamp DESC, entity_urn ASC, reason_code ASC, sub_reason_code ASC);
CREATE TABLE minds.moderation_strikes (
user_guid bigint,
reason_code tinyint,
sub_reason_code decimal,
timestamp timestamp,
report_urn text,
PRIMARY KEY (user_guid, reason_code, sub_reason_code, timestamp)
) WITH CLUSTERING ORDER BY (reason_code ASC, sub_reason_code ASC, timestamp ASC);
CREATE TABLE minds.moderation_summons (
report_urn text,
jury_type text,
juror_guid bigint,
expires int,
status text,
PRIMARY KEY (report_urn, jury_type, juror_guid)
) WITH CLUSTERING ORDER BY (jury_type ASC, juror_guid ASC);
ALTER TABLE minds.views ADD owner_guid text;
CREATE TABLE minds.pro (
......
......@@ -14,5 +14,8 @@ class Provider extends DiProvider
$this->di->bind('Referrals\Manager', function ($di) {
return new Manager();
}, [ 'useFactory'=>false ]);
$this->di->bind('Referrals\Cookie', function ($di) {
return new ReferralCookie();
}, [ 'useFactory'=>true ]);
}
}
<?php
/**
* Referral Cookie
*/
namespace Minds\Core\Referrals;
use Minds\Entities\User;
use Minds\Common\Cookie;
use Zend\Diactoros\ServerRequest;
class ReferralCookie
{
/** @var Request */
private $request;
/** @var Entity */
private $entity;
/**
* Set the router request
* @param Request $request
* @param Response $response
* @return $this
*/
public function withRouterRequest(ServerRequest $request): ReferralCookie
{
$this->request = $request;
return $this;
}
/**
* Set Entity
* @param Entity|User $entity
* @return $this
*/
public function setEntity($entity): ReferralCookie
{
$this->entity = $entity;
return $this;
}
/**
* Set the referral cookie
* @return void
*/
public function create(): void
{
if (!$this->request) {
return;
}
$cookies = $this->request->getCookieParams();
$params = $this->request->getQueryParams();
if (isset($cookies['referrer'])) {
return; // Do not override previosuly set cookie
}
$referrerGuid = null;
if (isset($params['referrer'])) { // Is a referrer param set in the request?
$referrerGuid = $params['referrer'];
} elseif ($this->entity) { // Was an entity set?
switch (get_class($this->entity)) {
case User::class:
$referrerGuid = $this->entity->getGuid();
break;
default:
$referrerGuid = $this->entity->getOwnerGuid();
}
}
if ($referrerGuid) {
$cookie = new Cookie();
$cookie
->setName('referrer')
->setValue($referrerGuid)
->setExpire(time() + (60 * 60 * 24)) //valid for 24 hours
->setPath('/')
->create();
$_COOKIE['referrer'] = $referrerGuid; // TODO: replace with Response object later
}
}
}
......@@ -118,10 +118,10 @@ class Repository
$contributions[] = $contribution;
}
$pagingStateToken = $rows ? $rows->pagingStateToken() : null;
return [
'contributions' => $contributions,
'token' => $rows->pagingStateToken()
'token' => $pagingStateToken
];
}
......
......@@ -128,9 +128,9 @@ class Router
Di::_()->get('Email\RouterHooks')
->withRouterRequest($request);
if (isset($_GET['referrer'])) {
Helpers\Campaigns\Referrals::register($_GET['referrer']);
}
Di::_()->get('Referrals\Cookie')
->withRouterRequest($request)
->create();
$loop = count($segments);
while ($loop >= 0) {
......
......@@ -2,6 +2,7 @@
/**
* Minds Session Manager
*/
namespace Minds\Core\Sessions;
use Minds\Common\Cookie;
......@@ -184,13 +185,13 @@ class Manager
$expires = time() + (60 * 60 * 24 * 30); // 30 days
$token = $this->jwtBuilder
//->issuedBy($this->config->get('site_url'))
//->canOnlyBeUsedBy($this->config->get('site_url'))
->setId($id, true)
->setExpiration($expires)
->set('user_guid', (string) $this->user->getGuid())
->sign(new Sha512, $this->config->get('sessions')['private_key'])
->getToken();
//->issuedBy($this->config->get('site_url'))
//->canOnlyBeUsedBy($this->config->get('site_url'))
->setId($id, true)
->setExpiration($expires)
->set('user_guid', (string) $this->user->getGuid())
->sign(new Sha512, $this->config->get('sessions')['private_key'])
->getToken();
$this->session = new Session();
$this->session
......@@ -198,7 +199,7 @@ class Manager
->setToken($token)
->setUserGuid($this->user->getGuid())
->setExpires($expires);
return $this;
}
......@@ -234,8 +235,10 @@ class Manager
*/
public function destroy($all = false)
{
$this->repository->delete($this->session, $all);
if ($this->session) {
$this->repository->delete($this->session, $all);
}
$this->cookie
->setName('minds_sess')
->setValue('')
......
......@@ -35,6 +35,10 @@ class Thresholds
$isPaywall = true;
}
if (!$user && $isPaywall) {
return false;
}
$threshold = $entity->getWireThreshold();
if (!$threshold && $isPaywall) {
......
......@@ -343,6 +343,15 @@ class Activity extends Entity
return $this;
}
/**
* Set the message
* @return string
*/
public function getMessage(): string
{
return $this->message;
}
/**
* Sets the title
* @param string $title
......@@ -440,6 +449,18 @@ class Activity extends Entity
return $this;
}
/**
* Get the custom data
* @return array
*/
public function getCustom(): array
{
return [
$this->custom_type,
$this->custom_data
];
}
/**
* Set the to_guid
* @param int $guid
......
......@@ -23,5 +23,8 @@ class EntitiesProvider extends Provider
$this->di->bind('Entities\Factory', function ($di) {
return new EntitiesFactory();
}, ['useFactory' => true]);
$this->di->bind('PropagateProperties', function ($di) {
return new Entities\PropagateProperties();
}, ['useFactory' => true]);
}
}
......@@ -8,14 +8,6 @@ use Minds\Interfaces\Flaggable;
* File Entity
* @todo Do not inherit from ElggFile
* @package Minds\Entities\File
* @method array getExportableValues()
* @method mixed|null getFlag(string $flag)
* @method File setFlag(string $flag, mixed $value)
* @method void save(bool $index)
* @method array getWireTotals()
* @method mixed getWireThreshold()
* @method File setWireThreshold(int $wire_threshold)
* @method int getModeratorGUID()
*/
class File extends \ElggFile implements Flaggable
{
......
......@@ -422,6 +422,18 @@ class Group extends NormalizedEntity
$this->conversationDisabled = $value ? 1 : 0;
return $this;
}
/**
* Return the original `owner_guid` for the group.
* @return string guid
*/
public function getOwnerGuid()
{
$guids = $this->getOwnerGuids();
return $guids
? guids[0]
: $this->getOwnerObj()->guid;
}
/**
* Gets `owner_guids`
......
......@@ -75,8 +75,8 @@ class EmailRewards
$validator = $_GET['validator'];
//$key = '.md';
//return;
if ($validator == sha1($campaign . 'gift-25-06-19.mdl' . $topic . $user->guid . Config::_()->get('emails_secret'))) {
$tokens = 5 * (10 ** 18);
if ($validator == sha1($campaign . 'gift-30-09-19.mdl' . $topic . $user->guid . Config::_()->get('emails_secret'))) {
$tokens = 2 * (10 ** 18);
$campaign = $validator; //hack
} else {
return;
......
<?php
namespace Minds\Helpers\Campaigns;
use Minds\Core;
use Minds\Core\Guid;
use Minds\Common\Cookie;
use Minds\Core\Di\Di;
class Referrals
{
/**
* Registers a cookie for the referral step
* @param string $username
* @return null
* @return void
*/
public static function register($username)
public static function register($username): void
{
if (!isset($_COOKIE['referrer'])) {
$cookie = new Cookie();
$cookie
->setName('referrer')
->setValue($username)
->setExpire(time() + (60 * 60 * 24)) //valid for 24 hours
->setPath('/')
->create();
$_COOKIE['referrer'] = $username;
}
Di::_()->get('Referrals\Cookie')->create();
}
}
<?php
namespace Spec\Minds\Core\Blogs\Delegates;
use Minds\Core\Blogs\Blog;
use Minds\Entities\Activity;
use Minds\Entities\Entity;
use PhpSpec\ObjectBehavior;
class PropagatePropertiesSpec extends ObjectBehavior
{
/** @var Blog */
protected $blog;
/** @var Activity */
protected $activity;
public function let(
Blog $blog,
Activity $activity
) {
$this->blog = $blog;
$this->activity = $activity;
}
public function it_is_initializable()
{
$this->shouldHaveType('Minds\Core\Blogs\Delegates\PropagateProperties');
}
public function it_should_propagate_changes_to_activity()
{
$this->blog->getTitle()->shouldBeCalled()->willReturn('New Title');
$this->activity->get('title')->shouldBeCalled()->willReturn('Old Title');
$this->activity->set('title', 'New Title')->shouldBeCalled();
$this->blog->getBody()->shouldBeCalled()->willReturn('body');
$this->activity->get('blurb')->shouldBeCalled()->willReturn('body');
$this->blog->getUrl()->shouldBeCalled()->willReturn('some url');
$this->activity->getURL()->shouldBeCalled()->willReturn('some url');
$this->blog->getIconUrl()->shouldBeCalled()->willReturn('some icon url');
$this->activity->get('thumbnail_src')->shouldBeCalled()->willReturn('some other url');
$this->activity->set('thumbnail_src', 'some icon url')->shouldBeCalled();
$this->toActivity($this->blog, $this->activity);
}
}
......@@ -5,6 +5,7 @@ namespace Spec\Minds\Core\Blogs;
use Minds\Core\Blogs\Blog;
use Minds\Core\Blogs\Delegates;
use Minds\Core\Blogs\Repository;
use Minds\Core\Entities\PropagateProperties;
use Minds\Core\Security\Spam;
use PhpSpec\ObjectBehavior;
......@@ -30,13 +31,16 @@ class ManagerSpec extends ObjectBehavior
/** @var Delegates\Search */
protected $search;
protected $propagateProperties;
public function let(
Repository $repository,
Delegates\PaywallReview $paywallReview,
Delegates\Slug $slug,
Delegates\Feeds $feeds,
Spam $spam,
Delegates\Search $search
Delegates\Search $search,
PropagateProperties $propagateProperties
) {
$this->beConstructedWith(
$repository,
......@@ -44,7 +48,8 @@ class ManagerSpec extends ObjectBehavior
$slug,
$feeds,
$spam,
$search
$search,
$propagateProperties
);
$this->repository = $repository;
......@@ -53,6 +58,7 @@ class ManagerSpec extends ObjectBehavior
$this->feeds = $feeds;
$this->spam = $spam;
$this->search = $search;
$this->propagateProperties = $propagateProperties;
}
public function it_is_initializable()
......@@ -244,6 +250,7 @@ class ManagerSpec extends ObjectBehavior
->shouldBeCalled()
->willReturn(true);
$this->propagateProperties->from($blog)->shouldBeCalled();
$this
->update($blog)
->shouldReturn(true);
......
......@@ -7,7 +7,7 @@ use Minds\Core\Data\cache\Redis;
use Minds\Core\Data\SortedSet;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Spec\Mocks\Redis as RedisServer;
use Spec\Minds\Mocks\Redis as RedisServer;
class SortedSetSpec extends ObjectBehavior
{
......
......@@ -2,7 +2,7 @@
namespace Spec\Minds\Core\Email\Campaigns;
use Minds\Core\Email\Campaigns\WireReceived;
use Minds\Core\Email\Campaigns\WireSent;
use PhpSpec\ObjectBehavior;
use Minds\Core\Email\Mailer;
use Minds\Core\Email\Manager;
......@@ -12,7 +12,7 @@ use Prophecy\Argument;
use Minds\Core\Wire\Wire;
use Minds\Core\Util\BigNumber;
class WireReceivedSpec extends ObjectBehavior
class WireSentSpec extends ObjectBehavior
{
protected $mailer;
protected $manager;
......@@ -40,19 +40,19 @@ class WireReceivedSpec extends ObjectBehavior
$this->wire = new Wire();
$this->wire->setAmount(10);
$receiver->getGUID()->shouldBeCalled()->willReturn($this->receiverGUID);
$receiver->get('enabled')->shouldBeCalled()->willReturn('yes');
$receiver->get('name')->shouldBeCalled()->willReturn($this->receiverName);
$receiver->get('guid')->shouldBeCalled()->willReturn($this->receiverGUID);
$receiver->getEmail()->shouldBeCalled()->willReturn($this->receiverEmail);
$receiver->get('username')->shouldBeCalled()->willReturn($this->receiverUsername);
$receiver->getGUID()->willReturn($this->receiverGUID);
$receiver->get('enabled')->willReturn('yes');
$receiver->get('name')->willReturn($this->receiverName);
$receiver->get('guid')->willReturn($this->receiverGUID);
$receiver->getEmail()->willReturn($this->receiverEmail);
$receiver->get('username')->willReturn($this->receiverUsername);
$sender->getGUID()->shouldBeCalled()->willReturn($this->senderGUID);
$sender->get('enabled')->shouldBeCalled()->willReturn('yes');
$sender->get('name')->shouldBeCalled()->willReturn($this->senderName);
$sender->get('guid')->shouldBeCalled()->willReturn($this->senderGUID);
$sender->getEmail()->shouldBeCalled()->willReturn($this->senderEmail);
$sender->get('username')->shouldBeCalled()->willReturn($this->senderUsername);
$sender->getGUID()->willReturn($this->senderGUID);
$sender->get('enabled')->willReturn('yes');
$sender->get('name')->willReturn($this->senderName);
$sender->get('guid')->willReturn($this->senderGUID);
$sender->getEmail()->willReturn($this->senderEmail);
$sender->get('username')->willReturn($this->senderUsername);
$this->receiver = $receiver;
$this->sender = $sender;
......@@ -62,24 +62,24 @@ class WireReceivedSpec extends ObjectBehavior
public function it_is_initializable()
{
$this->shouldHaveType(WireReceived::class);
$this->shouldHaveType(WireSent::class);
}
public function it_should_send_a_wire_received_email_tokens()
{
$this->getCampaign()->shouldEqual('when');
$this->getTopic()->shouldEqual('wire_received');
$this->setUser($sender);
$this->setUser($this->sender);
$this->setWire($this->wire);
$message = $this->build();
$message->getSubject()->shouldEqual('Your Wire Receipt');
$message->getSubject()->shouldEqual('Your Wire receipt');
$to = $message->getTo()[0]['name']->shouldEqual($this->senderName);
$to = $message->getTo()[0]['email']->shouldEqual($this->senderEmail);
$data = $this->getTemplate()->getData();
$data['guid']->shouldEqual($this->senderGUID);
$data['email']->shouldEqual($this->senderEmail);
$data['username']->shouldEqual($this->senderUsername);
$data['amount']->shouldEqual(BigNumber::fromPlain(10, 18)->toDouble());
//$data['amount']->shouldEqual(BigNumber::fromPlain(10, 18)->toDouble()); It is correct just in the wrong format to assert
$this->mailer->send(Argument::any())->shouldBeCalled();
$testEmailSubscription = (new EmailSubscription())
......@@ -102,19 +102,19 @@ class WireReceivedSpec extends ObjectBehavior
$this->setWire($this->wire);
$this->setSuggestions($this->mockSuggestions());
$message = $this->build();
$message->getSubject()->shouldEqual('You received a wire');
$to = $message->getTo()[0]['name']->shouldEqual($this->testName);
$to = $message->getTo()[0]['email']->shouldEqual($this->testEmail);
$message->getSubject()->shouldEqual('Your Wire receipt');
$to = $message->getTo()[0]['name']->shouldEqual($this->senderName);
$to = $message->getTo()[0]['email']->shouldEqual($this->senderEmail);
$data = $this->getTemplate()->getData();
$data['guid']->shouldEqual($this->testGUID);
$data['email']->shouldEqual($this->testEmail);
$data['username']->shouldEqual($this->testUsername);
$data['guid']->shouldEqual($this->senderGUID);
$data['email']->shouldEqual($this->senderEmail);
$data['username']->shouldEqual($this->senderUsername);
$data['contract']->shouldEqual('wire');
$data['amount']->shouldEqual(10);
$data['amount']->shouldEqual('10 ONCHAIN');
$this->mailer->send(Argument::any())->shouldBeCalled();
$testEmailSubscription = (new EmailSubscription())
->setUserGuid($this->testGUID)
->setUserGuid($this->senderGUID)
->setCampaign('when')
->setTopic('wire_received')
->setValue(true);
......@@ -128,7 +128,7 @@ class WireReceivedSpec extends ObjectBehavior
$this->getCampaign()->shouldEqual('when');
$this->getTopic()->shouldEqual('wire_received');
$this->setUser($user);
$this->setUser($this->sender);
$this->setWire($this->wire);
$this->build();
......@@ -154,7 +154,7 @@ class WireReceivedSpec extends ObjectBehavior
$this->getCampaign()->shouldEqual('when');
$this->getTopic()->shouldEqual('wire_received');
$this->setUser($sender);
$this->setUser($this->sender);
$this->setWire($this->wire);
$this->build();
......@@ -182,7 +182,7 @@ class WireReceivedSpec extends ObjectBehavior
public function it_should_not_send_disabled()
{
$this->setUser($sender);
$this->setUser($this->sender);
$this->setWire($this->wire);
$this->build();
......@@ -196,7 +196,7 @@ class WireReceivedSpec extends ObjectBehavior
public function it_should_send_not_send_unsubscribed_emails()
{
$this->setUser($sender);
$this->setUser($this->sender);
$this->setWire($this->wire);
$this->build();
......
<?php
namespace Spec\Minds\Core\Entities\Delegates;
use Minds\Core\Blogs\Blog;
use Minds\Entities\Activity;
use PhpSpec\ObjectBehavior;
class PropagatePropertiesSpec extends ObjectBehavior
{
/** @var Blog */
protected $blog;
/** @var Activity */
protected $activity;
public function let(
Blog $blog,
Activity $activity
) {
$this->blog = $blog;
$this->activity = $activity;
}
public function it_is_initializable()
{
$this->shouldHaveType('Minds\Core\Entities\Delegates\PropagateProperties');
}
public function it_should_propagate_changes_to_activity()
{
$this->blog->getNsfw()->shouldBeCalled()->willReturn([1]);
$this->activity->getNsfw()->shouldBeCalled()->willReturn([]);
$this->activity->setNsfw([1])->shouldBeCalled();
$this->blog->getNsfwLock()->shouldBeCalled()->willReturn([1]);
$this->activity->getNsfwLock()->shouldBeCalled()->willReturn([]);
$this->activity->setNsfwLock([1])->shouldBeCalled();
$this->toActivity($this->blog, $this->activity);
}
public function it_should_propogate_properties_from_activity()
{
$this->activity->getNsfw()->shouldBeCalled()->willReturn([1]);
$this->blog->getNsfw()->shouldBeCalled()->willReturn([]);
$this->blog->setNsfw([1])->shouldBeCalled();
$this->activity->getNsfwLock()->shouldBeCalled()->willReturn([1]);
$this->blog->getNsfwLock()->shouldBeCalled()->willReturn([]);
$this->blog->setNsfwLock([1])->shouldBeCalled();
$this->fromActivity($this->activity, $this->blog);
}
}
<?php
namespace Spec\Minds\Core\Entities;
use Minds\Core\Data\Call;
use Minds\Core\Entities\Actions\Save;
use Minds\Core\EntitiesBuilder;
use Minds\Entities\Activity;
use Minds\Entities\Entity;
use PhpSpec\ObjectBehavior;
class PropagatePropertiesSpec extends ObjectBehavior
{
protected $db;
protected $save;
protected $entitiesBuilder;
protected $propagator;
protected $activity;
protected $entity;
public function let(
Call $db,
Save $save,
EntitiesBuilder $entitiesBuilder,
Activity $activity,
Entity $entity
) {
$this->beConstructedWith($db, $save, $entitiesBuilder);
$this->db = $db;
$this->save = $save;
$this->entitiesBuilder = $entitiesBuilder;
$this->activity = $activity;
$this->entity = $entity;
$this->clearPropogators();
}
public function it_is_initializable()
{
$this->shouldHaveType('Minds\Core\Entities\PropagateProperties');
}
public function it_should_call_from_activity()
{
$this->activity->get('entity_guid')->shouldBeCalled()->willReturn(1001);
$this->entitiesBuilder->single(1001)->shouldBeCalled()->willReturn($this->entity);
$this->from($this->activity);
}
public function it_should_call_to_activities()
{
$this->entity->getGUID()->shouldBeCalled()->willReturn(1002);
$this->db->getRow("activity:entitylink:1002")->shouldBeCalled()->willReturn([1001 => 12345]);
$this->entitiesBuilder->single(1001)->shouldBeCalled()->willReturn($this->activity);
$this->from($this->entity);
}
}
<?php
namespace Spec\Minds\Core\Feeds\Delegates;
use Minds\Entities\Activity;
use Minds\Entities\Entity;
use PhpSpec\ObjectBehavior;
class PropagatePropertiesSpec extends ObjectBehavior
{
/** @var Entity */
protected $entity;
/** @var Activity */
protected $activity;
public function let(
Entity $entity,
Activity $activity
) {
$this->entity = $entity;
$this->activity = $activity;
}
public function it_is_initializable()
{
$this->shouldHaveType('Minds\Core\Feeds\Delegates\PropagateProperties');
}
public function it_should_propagate_changes_to_activity()
{
$this->entity->getModeratorGuid()->shouldBeCalled()->willReturn('12345');
$this->activity->getModeratorGuid()->shouldBeCalled()->willReturn('6789');
$this->activity->setModeratorGuid('12345')->shouldBeCalled();
$this->entity->getTimeModerated()->shouldBeCalled()->willReturn(12345);
$this->activity->getTimeModerated()->shouldBeCalled()->willReturn(6789);
$this->activity->setTimeModerated(12345)->shouldBeCalled();
$this->toActivity($this->entity, $this->activity);
}
public function it_should_propogate_properties_from_activity()
{
$this->activity->getModeratorGuid()->shouldBeCalled()->willReturn('12345');
$this->entity->getModeratorGuid()->shouldBeCalled()->willReturn('6789');
$this->entity->setModeratorGuid('12345')->shouldBeCalled();
$this->activity->getTimeModerated()->shouldBeCalled()->willReturn(12345);
$this->entity->getTimeModerated()->shouldBeCalled()->willReturn(6789);
$this->entity->setTimeModerated(12345)->shouldBeCalled();
$this->entity->get('owner_guid')->shouldBeCalled()->willReturn(123);
$this->activity->get('owner_guid')->shouldBeCalled()->willReturn(123);
$this->activity->isPayWall()->shouldBeCalled()->willReturn(true);
$this->activity->get('access_id')->shouldBeCalled()->willReturn(0);
$this->entity->get('access_id')->shouldBeCalled()->willReturn(2);
$this->entity->set('access_id', 0)->shouldBeCalled();
$this->entity->getSubtype()->shouldBeCalled()->willReturn('image');
$this->entity->get('hidden')->shouldBeCalled()->willReturn(false);
$this->entity->set('hidden', true)->shouldBeCalled();
$this->fromActivity($this->activity, $this->entity);
}
}
......@@ -2,6 +2,7 @@
namespace Spec\Minds\Core\Feeds\Firehose;
use Minds\Core\Entities\PropagateProperties;
use PhpSpec\ObjectBehavior;
use Minds\Entities\User;
use Minds\Core\Feeds\Firehose\Manager;
......@@ -25,12 +26,10 @@ class ManagerSpec extends ObjectBehavior
protected $topFeedsManager;
/** @var ModerationCache */
protected $moderationCache;
/** @var EntitiesBuilder */
protected $entitiesBuilder;
/** @var Call */
protected $db;
/** @var Save */
protected $save;
/** @var PropagateProperties */
protected $propagateProperties;
protected $guids = [
'968599624820461570', '966142563226488850', '966145446911152135',
......@@ -43,25 +42,22 @@ class ManagerSpec extends ObjectBehavior
User $user,
TopFeedsManager $topFeedsManager,
ModerationCache $moderationCache,
EntitiesBuilder $entitiesBuilder,
Call $db,
Save $save
Save $save,
PropagateProperties $propagateProperties
) {
$this->user = $user;
$this->topFeedsManager = $topFeedsManager;
$this->moderationCache = $moderationCache;
$this->entitiesBuilder = $entitiesBuilder;
$this->db = $db;
$this->save = $save;
$this->propagateProperties = $propagateProperties;
$this->user->getGUID()->willReturn(123);
$this->beConstructedWith(
$this->topFeedsManager,
$this->moderationCache,
$this->entitiesBuilder,
$this->db,
$this->save
$this->save,
$this->propagateProperties
);
}
......@@ -77,10 +73,10 @@ class ManagerSpec extends ObjectBehavior
$response = new Response($activities);
$this->topFeedsManager->getList([
'moderation_user' => $this->user,
'exclude_moderated' => true,
'moderation_reservations' => null,
])
'moderation_user' => $this->user,
'exclude_moderated' => true,
'moderation_reservations' => null,
])
->shouldBeCalled()
->willReturn($response);
......@@ -112,89 +108,22 @@ class ManagerSpec extends ObjectBehavior
'exclude_moderated' => true,
'moderation_reservations' => null,
])
->shouldBeCalled()
->willReturn($response);
->shouldBeCalled()
->willReturn($response);
$this->getList()->shouldBeLike($response->map(function ($entity) {
return $entity->getEntity();
}));
}
public function it_should_save_moderated_activites(Entity $activity)
{
$time = time();
$this->db->getRow('activity:entitylink:1')->shouldBeCalled()->willReturn([]);
$activity->getType()->shouldBeCalled()->willReturn('activity');
$activity->get('entity_guid')->shouldBeCalled()->willReturn(false);
$activity->getGUID()->shouldBeCalled()->willReturn(1);
$activity->setModeratorGuid('123')->shouldBeCalled();
$activity->setTimeModerated($time)->shouldBeCalled();
$this->save->setEntity($activity)->shouldBeCalled()->willReturn($this->save);
$this->save->save()->shouldBeCalled();
$this->save($activity, $this->user, $time);
}
public function it_should_save_reported_activites(Entity $activity)
public function it_should_save_and_propogate(Entity $activity)
{
$time = time();
$this->db->getRow('activity:entitylink:1')->shouldBeCalled()->willReturn([]);
$activity->getType()->shouldBeCalled()->willReturn('activity');
$activity->get('entity_guid')->shouldBeCalled()->willReturn(false);
$activity->getGUID()->shouldBeCalled()->willReturn(1);
$activity->setTimeModerated($time)->shouldBeCalled();
$activity->setModeratorGuid('123')->shouldBeCalled();
$this->save->setEntity($activity)->shouldBeCalled()->willReturn($this->save);
$this->save->save()->shouldBeCalled();
$this->save($activity, $this->user, $time);
}
public function it_should_save_an_attachment(Entity $activity, Image $image)
{
$time = time();
$image->setModeratorGuid(123)->shouldBeCalled();
$image->setTimeModerated($time)->shouldBeCalled();
$this->db->getRow('activity:entitylink:1')->shouldBeCalled()->willReturn([]);
$this->entitiesBuilder->single(1)->shouldBeCalled()->willReturn($image);
$activity->getType()->shouldBeCalled()->willReturn('activity');
$activity->get('entity_guid')->shouldBeCalled()->willReturn(1);
$activity->getGUID()->shouldBeCalled()->willReturn(1);
$activity->setTimeModerated($time)->shouldBeCalled();
$activity->setModeratorGuid(123)->shouldBeCalled();
$this->save->setEntity($activity)->shouldBeCalled()->willReturn($this->save);
$this->save->setEntity($image)->shouldBeCalled()->willReturn($this->save);
$this->save->save()->shouldBeCalled();
$this->save($activity, $this->user, $time);
}
public function it_should_save_a_blog(Blog $blog)
{
$time = time();
$this->db->getRow('activity:entitylink:1')->shouldBeCalled()->willReturn([]);
$blog->getType()->shouldBeCalled()->willReturn('object');
$blog->getGuid()->shouldBeCalled()->willReturn(1);
$blog->setTimeModerated($time)->shouldBeCalled();
$blog->setModeratorGuid('123')->shouldBeCalled();
$this->save->save()->shouldBeCalled();
$this->save->setEntity($blog)->shouldBeCalled()->willReturn($this->save);
$this->save($blog, $this->user, $time);
}
public function it_should_save_a_linked_entity(Entity $activity, Entity $parent)
{
$time = time();
$parent->setTimeModerated($time)->shouldBeCalled();
$parent->setModeratorGuid('123')->shouldBeCalled();
$this->db->getRow('activity:entitylink:1')->shouldBeCalled()
->willReturn([2 => $parent]);
$this->entitiesBuilder->single(2)->shouldBeCalled()->willReturn($parent);
$activity->getType()->shouldBeCalled()->willReturn('activity');
$activity->get('entity_guid')->shouldBeCalled()->willReturn(false);
$activity->getGUID()->shouldBeCalled()->willReturn(1);
$activity->setTimeModerated($time)->shouldBeCalled();
$activity->setModeratorGuid('123')->shouldBeCalled();
$this->save->setEntity($activity)->shouldBeCalled()->willReturn($this->save);
$this->save->setEntity($parent)->shouldBeCalled()->willReturn($this->save);
$this->save->save()->shouldBeCalled();
$this->propagateProperties->from($activity)->shouldBeCalled();
$this->save($activity, $this->user, $time);
}
......
<?php
namespace Spec\Minds\Core\Media\Delegates;
use Minds\Entities\Activity;
use Minds\Entities\Image;
use PhpSpec\ObjectBehavior;
class PropagatePropertiesSpec extends ObjectBehavior
{
/** @var Image */
protected $entity;
/** @var Activity */
protected $activity;
public function let(
Image $entity,
Activity $activity
) {
$this->entity = $entity;
$this->activity = $activity;
}
public function it_is_initializable()
{
$this->shouldHaveType('Minds\Core\Media\Delegates\PropagateProperties');
}
public function it_should_propagate_changes_to_activity()
{
$this->entity->get('title')->shouldBeCalled()->willReturn('new title');
$this->activity->getMessage()->shouldBeCalled()->willReturn('old title');
$this->activity->setMessage('new title')->shouldBeCalled();
$activityParameters = [
'batch',
[
'key1' => 'value1',
'key2' => 'value2'
]
];
$this->entity->getActivityParameters()->shouldBeCalled()->willReturn($activityParameters);
$this->activity->getCustom()->shouldBeCalled()->willReturn([]);
$this->activity->setCustom($activityParameters[0], $activityParameters[1])->shouldBeCalled();
$this->toActivity($this->entity, $this->activity);
}
public function it_should_propogate_properties_from_activity()
{
$this->activity->getMessage()->shouldBeCalled()->willReturn('new title');
$this->entity->get('title')->shouldbeCalled()->willReturn('old title');
$this->entity->set('title', 'new title')->shouldBeCalled();
$this->fromActivity($this->activity, $this->entity);
}
}
......@@ -26,6 +26,10 @@ class TranscodingStatusSpec extends ObjectBehavior
[
'height' => 1080,
'formats' => ['mp4', 'webm']
],
[
'height' => 360,
'formats' => ['mp4', 'webm']
]
]
]);
......@@ -52,12 +56,27 @@ class TranscodingStatusSpec extends ObjectBehavior
$result = new Result(['Contents' => [
['Key' => '/test/123/1080.mp4'],
['Key' => '/test/123/1080.webm'],
['Key' => '/test/123/360.mp4'],
['Key' => '/test/123/360.webm'],
['Key' => '/test/123/thumbnail-00000.png']
]]);
$this->beConstructedWith($this->video, $result, $this->config);
$this->hasSource()->shouldReturn(false);
$this->getTranscodes()->shouldReturn(['/test/123/1080.mp4', '/test/123/1080.webm']);
$this->getTranscodes()->shouldReturn(['/test/123/1080.mp4', '/test/123/1080.webm', '/test/123/360.mp4', '/test/123/360.webm']);
$this->getThumbnails()->shouldContain('/test/123/thumbnail-00000.png');
$this->isTranscodingComplete()->shouldReturn(true);
}
public function it_should_say_still_transcoding()
{
$result = new Result(['Contents' => [
['Key' => '/test/123/360.mp4'],
['Key' => '/test/123/thumbnail-00000.png']
]]);
$this->beConstructedWith($this->video, $result, $this->config);
$this->hasSource()->shouldReturn(false);
$this->getTranscodes()->shouldReturn(['/test/123/360.mp4']);
$this->getThumbnails()->shouldContain('/test/123/thumbnail-00000.png');
$this->isTranscodingComplete()->shouldReturn(false);
}
}
<?php
namespace Spec\Minds\Core\Notification;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use PhpSpec\Exception\Example\FailureException;
use Minds\Core\Data\Cassandra;
use Minds\Core\Data\Cassandra\Prepared;
use Minds\Entities;
use Spec\Minds\Mocks\Cassandra\Rows;
class RepositorySpec extends ObjectBehavior
{
protected $_client;
public function let(Cassandra\Client $client)
{
$this->beConstructedWith($client);
$this->_client = $client;
}
public function it_is_initializable()
{
$this->shouldHaveType('Minds\Core\Notification\Repository');
}
// setOwner
public function it_should_set_owner()
{
$this
->setOwner(1000)
->shouldReturn($this);
}
// getAll
public function it_should_get_an_empty_list_of_notifications()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldBeCalled()
->willReturn(new Rows([], ''));
$this
->setOwner(1000)
->getAll()
->shouldReturn(['notifications' => [], 'token' => '']);
}
public function it_should_get_a_list_of_notifications()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldBeCalled()
->willReturn(
new Rows([
[ 'data' => [ ] ],
[ 'data' => [ ] ],
[ 'data' => [ ] ],
[ 'data' => [ ] ],
[ 'data' => [ ] ],
], ''));
$result = $this->setOwner(1000)
->getAll(null, ['limit' => 5]);
$result['notifications']->shouldBeAnArrayOf(5, Entities\Notification::class);
}
public function it_should_not_get_a_list_of_notifications_if_theres_no_owner()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldNotBeCalled();
$this
->shouldThrow(\Exception::class)
->duringGetAll(null, [ 'limit' => 5 ]);
}
// getEntity
public function it_should_return_a_single_notification()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldBeCalled()
->willReturn([
[ 'data' => [ ] ],
]);
$this
->setOwner(1000)
->getEntity(2000)
->shouldReturnAnInstanceOf(Entities\Notification::class);
}
public function it_should_not_return_a_single_notification_if_doesnt_exist()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldBeCalled()
->willReturn([]);
$this
->setOwner(1000)
->getEntity(2000)
->shouldReturn(false);
}
public function it_should_not_return_a_single_notification_if_falsy()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldBeCalled()
->willReturn([ '' ]);
$this
->setOwner(1000)
->getEntity(2000)
->shouldReturn(false);
}
public function it_should_not_return_a_single_notification_if_no_guid()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldNotBeCalled();
$this
->setOwner(1000)
->getEntity('')
->shouldReturn(false);
}
public function it_should_not_return_a_single_notification_if_no_owner()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldNotBeCalled();
$this
->shouldThrow(\Exception::class)
->duringGetEntity(2000);
}
// store
public function it_should_store()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldBeCalled()
->willReturn(true);
$this
->setOwner(1000)
->store([ 'guid' => 2000 ])
->shouldReturn(true);
}
public function it_should_store_if_ttl_is_not_past()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldBeCalled()
->willReturn(true);
//$ttl = $this->getWrappedObject()::NOTIFICATION_TTL - 1;
$this
->setOwner(1000)
->store([ 'guid' => 2000 ])
->shouldReturn(true);
}
public function it_should_not_store_if_ttl_is_past()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldNotBeCalled();
$ttl = \Minds\Core\Notification\Repository::NOTIFICATION_TTL + 1;
$this
->setOwner(1000)
->store([ 'guid' => 2000 ], $ttl)
->shouldReturn(false);
}
public function it_should_not_store_if_no_guid()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldNotBeCalled();
$this
->setOwner(1000)
->store([])
->shouldReturn(false);
}
public function it_should_not_store_if_no_owner()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldNotBeCalled();
$this
->shouldThrow(\Exception::class)
->duringStore([ 'guid' => 2000 ]);
}
// delete
public function it_should_delete()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldBeCalled()
->willReturn(true);
$this
->setOwner(1000)
->delete(2000)
->shouldReturn(true);
}
public function it_should_not_delete_if_no_guid()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldNotBeCalled();
$this
->setOwner(1000)
->delete('')
->shouldReturn(false);
}
public function it_should_not_delete_if_no_owner()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldNotBeCalled();
$this
->shouldThrow(\Exception::class)
->duringDelete(2000);
}
// count
public function it_should_count()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldBeCalled()
->willReturn([ [ 'count' => 5 ] ]);
$this
->setOwner(1000)
->count()
->shouldReturn(5);
}
public function it_should_not_count_if_no_owner()
{
$this->_client->request(Argument::type(Prepared\Custom::class))
->shouldNotBeCalled();
$this
->shouldThrow(\Exception::class)
->duringCount();
}
//
public function getMatchers()
{
$matchers['beAnArrayOf'] = function ($subject, $count, $class) {
if (!is_array($subject) || ($count !== null && count($subject) !== $count)) {
throw new FailureException("Subject should be an array of $count elements");
}
$validTypes = true;
foreach ($subject as $element) {
if (!($element instanceof $class)) {
$validTypes = false;
break;
}
}
if (!$validTypes) {
throw new FailureException("Subject should be an array of {$class}");
}
return true;
};
return $matchers;
}
}
<?php
namespace Spec\Minds\Core\Permissions\Delegates;
use Minds\Entities\Activity;
use Minds\Entities\Entity;
use PhpSpec\ObjectBehavior;
class PropagatePropertiesSpec extends ObjectBehavior
{
/** @var Entity */
protected $entity;
/** @var Activity */
protected $activity;
public function let(
Entity $entity,
Activity $activity
) {
$this->entity = $entity;
$this->activity = $activity;
}
public function it_is_initializable()
{
$this->shouldHaveType('Minds\Core\Permissions\Delegates\PropagateProperties');
}
public function it_should_propagate_changes_to_activity()
{
$this->entity->getAllowComments()->shouldBeCalled()->willReturn(true);
$this->activity->getAllowComments()->shouldBeCalled()->willReturn(false);
$this->activity->setAllowComments(true)->shouldBeCalled();
$this->toActivity($this->entity, $this->activity);
}
public function it_should_propogate_properties_from_activity()
{
$this->activity->getAllowComments()->shouldBeCalled()->willReturn(true);
$this->entity->getAllowComments()->shouldBeCalled()->willReturn(false);
$this->entity->setAllowComments(true)->shouldBeCalled();
$this->fromActivity($this->activity, $this->entity);
}
}
<?php
namespace Spec\Minds\Core\Referrals;
use Minds\Core\Referrals\ReferralCookie;
use Minds\Entities\User;
use Minds\Entities\Activity;
use Zend\Diactoros\ServerRequest;
use Zend\Diactoros\ServerRequestFactory;
use Zend\Diactoros\Uri;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class ReferralCookieSpec extends ObjectBehavior
{
public function it_is_initializable()
{
$this->shouldHaveType(ReferralCookie::class);
}
public function it_should_set_a_referral_cookie_from_a_referral_param()
{
$request = (new ServerRequest())->withQueryParams(['referrer' => 'mark']);
$this->withRouterRequest($request);
$this->create();
expect($_COOKIE['referrer'])
->toBe('mark');
}
public function it_should_not_set_cookie_if_already_present()
{
$_COOKIE['referrer'] = 'bill';
$request = (new ServerRequest())
->withCookieParams(['referrer' => 'bill'])
->withQueryParams(['referrer' => 'mark']);
$this->withRouterRequest($request);
$this->create();
expect($_COOKIE['referrer'])
->toBe('bill');
}
public function it_should_set_cookie_from_user_entity()
{
$user = new User();
$user->guid = 123;
$request = (new ServerRequest());
$this->withRouterRequest($request);
$this->setEntity($user);
$this->create();
expect($_COOKIE['referrer'])
->toBe(123);
}
public function it_should_set_cookie_from_activity()
{
$activity = new Activity();
$activity->guid = 123;
$activity->owner_guid = 456;
$request = (new ServerRequest());
$this->withRouterRequest($request);
$this->setEntity($activity);
$this->create();
expect($_COOKIE['referrer'])
->toBe(456);
}
public function it_should_not_allow_entity_to_override_param()
{
$activity = new Activity();
$activity->guid = 123;
$activity->owner_guid = 456;
$request = (new ServerRequest())
->withQueryParams(['referrer' => 'mark']);
;
$this->withRouterRequest($request);
$this->setEntity($activity);
$this->create();
expect($_COOKIE['referrer'])
->toBe('mark');
}
public function it_should_not_allow_entity_to_override_cookie()
{
$activity = new Activity();
$activity->guid = 123;
$activity->owner_guid = 456;
$request = (new ServerRequest())
->withCookieParams(['referrer' => 'mark']);
;
$this->withRouterRequest($request);
$this->setEntity($activity);
$this->create();
expect($_COOKIE['referrer'])
->toBe('mark');
}
}
......@@ -84,7 +84,6 @@ class RepositorySpec extends ObjectBehavior
$this->db->request(Argument::that(function ($query) {
$built = $query->build();
var_dump($built['string']);
return $built['string'] === 'DELETE FROM sendwyre_accounts WHERE user_guid = ?';
}))
......
<?php
namespace Spec\Mocks;
namespace Spec\Minds\Mocks;
/**
* Redis.
......
......@@ -6,6 +6,8 @@ global $CONFIG;
date_default_timezone_set('UTC');
define('__MINDS_ROOT__', dirname(__FILE__) . '/../');
$minds = new Minds\Core\Minds();
$minds->loadLegacy();
......@@ -297,7 +299,9 @@ if (!class_exists('Cassandra')) {
class_alias('Mock', 'Cassandra\Uuid');
class_alias('Mock', 'Cassandra\Timeuuid');
class_alias('Mock', 'Cassandra\Boolean');
class_alias('Mock', 'MongoDB\BSON\UTCDateTime');
if (!class_exists('MongoDB\BSON\UTCDateTime')) {
class_alias('Mock', 'MongoDB\BSON\UTCDateTime');
}
class_alias('Mock', 'Cassandra\RetryPolicy\Logging');
class_alias('Mock', 'Cassandra\RetryPolicy\DowngradingConsistency');
}
......
<?php
if (!defined('__MINDS_ROOT__')) {
define('__MINDS_ROOT__', dirname(__FILE__));
}
// prep core classes to be autoloadable
spl_autoload_register('_minds_autoload');
/**
* Autoload classes
*
* @param string $class The name of the class
*
* @return void
* @throws Exception
* @access private
*/
function _minds_autoload($class)
{
global $CONFIG;
if (file_exists(__MINDS_ROOT__."/classes/$class.php")) {
include(__MINDS_ROOT__."/classes/$class.php");
return true;
}
if (isset($CONFIG->classes[$class])) {
include($CONFIG->classes[$class]);
return true;
}
$file = dirname(__FILE__) . '/'. preg_replace('/minds/i', '', str_replace('\\', '/', $class), 1) . '.php';
//echo $file;
if (file_exists($file)) {
require_once $file;
return true;
}
//plugins follow a different path (new style)
$file = str_replace('/Plugin/', '/../plugins/', $file);
if (file_exists($file)) {
require_once $file;
return true;
}
//plugins follow a different path (old style)
$file = str_replace('/plugin/', '/../plugins/', $file);
if (file_exists($file)) {
require_once $file;
return true;
}
}
......@@ -1002,7 +1002,7 @@ abstract class ElggEntity extends ElggData implements
$url = "_graphics/icons/default/$size.png";
}
return elgg_normalize_url($url);
return $url;
}
/**
......
......@@ -6,6 +6,8 @@ if (PHP_SAPI !== 'cli') {
exit(1);
}
define('__MINDS_ROOT__', dirname(__FILE__));
require_once(dirname(__FILE__) . "/vendor/autoload.php");
error_reporting(E_ALL);
ini_set('display_errors', 1);
......
......@@ -56,9 +56,11 @@
}
],
"autoload": {
"files": [
"autoload.php"
]
"psr-4": {
"Minds\\": ".",
"": "classes/",
"Spec\\Minds\\": "Spec/"
}
},
"config": {
"bin-dir": "bin"
......
File deleted
FROM minds/php:latest
RUN docker-php-ext-enable opcache
# Additional folders
RUN mkdir --parents --mode=0777 /tmp/minds-cache/ \
......@@ -8,6 +10,6 @@ RUN mkdir --parents --mode=0777 /tmp/minds-cache/ \
# Copy config
COPY containers/php-fpm/php.ini /usr/local/etc/php/
#COPY containers/php-fpm/opcache.ini /usr/local/etc/php/conf.d/opcache-recommended.ini
COPY containers/php-fpm/opcache-dev.ini /usr/local/etc/php/conf.d/opcache-recommended.ini
COPY containers/php-fpm/apcu.ini /usr/local/etc/php/conf.d/docker-php-ext-apcu.ini
COPY containers/php-fpm/php-fpm.dev.conf /usr/local/etc/php-fpm.d/www.conf
\ No newline at end of file
COPY containers/php-fpm/php-fpm.dev.conf /usr/local/etc/php-fpm.d/www.conf
opcache.revalidate_freq = 0
opcache.memory_consumption = 256
opcache.save_comments = 0
opcache.fast_shutdown = 1
opcache.file_update_protection = 0
......@@ -8,8 +8,8 @@ listen.backlog = -1
pm = static
pm.max_children = 10
pm.max_requests = 200
pm.max_children = 4
pm.max_requests = 10000
pm.status_path = /status
chdir = /
......@@ -21,4 +21,7 @@ request_slowlog_timeout = 10s
request_terminate_timeout = 120s
rlimit_files = 65535
\ No newline at end of file
rlimit_files = 65535
env[MINDS_VERSION] = $MINDS_VERSION
env[MINDS_ENV] = $MINDS_ENV
env[SENTRY_DSN] = $SENTRY_DSN
......@@ -950,14 +950,14 @@ function validate_password($password) {
$CONFIG->min_password_length = 6;
}
if (strlen($password) < $CONFIG->min_password_length) {
$msg = "Passwords should be at least " . $CONFIG->min_password_length . " characters long";
throw new RegistrationException($msg);
}
//Check for a uppercase character, numeric character,special character
if (!preg_match('/[A-Z]/', $password) || !preg_match('/\d/', $password) || !preg_match('/[^a-zA-Z\d]/', $password) || preg_match("/\\s/", $password)) {
$msg = "Password must have more than 8 characters. Including uppercase, numbers, special characters (ie. !,#,@), and cannot have spaces.";
if (strlen($password) < $CONFIG->min_password_length
|| !preg_match('/[A-Z]/', $password)
|| !preg_match('/\d/', $password)
|| !preg_match('/[^a-zA-Z\d]/', $password)
|| preg_match("/\\s/", $password)
) {
$msg = "Password must have 8 characters or more. Including uppercase, numbers, special characters (ie. !,#,@), and cannot have spaces.";
throw new RegistrationException($msg);
}
......
#!/bin/sh
INSTALLOPTS=""
if [ "$1" == "production" ]; then
INSTALLOPTS="-a"
fi
# Clear vendor cache
rm -rf ../vendor
......@@ -9,5 +14,7 @@ php -r "if (hash_file('SHA384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b
php composer-setup.php
php -r "unlink('composer-setup.php');"
# Optimise for package install speed
composer.phar -n global require -n "hirak/prestissimo"
# Grab dependencies
php composer.phar install --ignore-platform-reqs
php composer.phar install $INSTALLOPTS --ignore-platform-reqs