Skip to content
......@@ -38,7 +38,7 @@ class BoostCampaigns extends Cli\Controller implements Interfaces\CliControllerI
$iterator = (new Core\Boost\Campaigns\Iterator())
->setOffset($offset)
->setState(Core\Boost\Campaigns\Campaign::CREATED_STATUS)
->setState(Core\Boost\Campaigns\Campaign::STATUS_CREATED)
->setOwnerGuid($ownerGuid)
->setType($type);
......
......@@ -8,6 +8,7 @@
namespace Minds\Controllers\api\v2\blockchain;
use Minds\Core\Blockchain\Purchase\Manager;
use Minds\Core\Blockchain\Purchase\Sums;
use Minds\Core\Di\Di;
use Minds\Core\Session;
use Minds\Core\Util\BigNumber;
......@@ -26,7 +27,9 @@ class purchase implements Interfaces\Api
{
$response = [];
/** @var Sums $sums */
$sums = Di::_()->get('Blockchain\Purchase\Sums');
/** @var Manager $manager */
$manager = Di::_()->get('Blockchain\Purchase\Manager');
$response['cap'] = $manager->getAutoIssueCap();
......
......@@ -10,11 +10,9 @@
namespace Minds\Controllers\api\v2\boost;
use Exception;
use Minds\Api\Exportable;
use Minds\Common\Urn;
use Minds\Core\Boost\Campaigns\Campaign;
use Minds\Core\Boost\Campaigns\Manager;
use Minds\Core\Boost\Campaigns\Repository;
use Minds\Core\Di\Di;
use Minds\Core\Session;
use Minds\Interfaces;
......@@ -61,7 +59,7 @@ class campaigns implements Interfaces\Api
return $campaign->getOwnerGuid() == Session::getLoggedinUserGuid();
});
return Factory::response([
Factory::response([
'campaigns' => $response,
'load-next' => $response->getPagingToken(),
]);
......@@ -113,11 +111,11 @@ class campaigns implements Interfaces\Api
$campaign = $manager->update($campaign, $_POST['payment'] ?? null);
}
return Factory::response([
Factory::response([
'campaign' => $campaign,
]);
} catch (\Exception $e) {
return Factory::response([
Factory::response([
'status' => 'error',
'message' => $e->getMessage(),
]);
......@@ -127,27 +125,26 @@ class campaigns implements Interfaces\Api
/**
* Equivalent to HTTP PUT method
* @param array $pages
* @return mixed|null
*/
public function put($pages)
{
return Factory::response([]);
Factory::response([]);
}
/**
* Equivalent to HTTP DELETE method
* @param array $pages
* @return mixed|null
*/
public function delete($pages)
{
$urn = $pages[0] ?? null;
if (!$urn[0]) {
return Factory::response([
Factory::response([
'status' => 'error',
'message' => 'Missing URN',
]);
return;
}
$campaign = new Campaign();
......@@ -162,11 +159,11 @@ class campaigns implements Interfaces\Api
try {
$campaign = $manager->cancel($campaign);
return Factory::response([
Factory::response([
'campaign' => $campaign,
]);
} catch (\Exception $e) {
return Factory::response([
Factory::response([
'status' => 'error',
'message' => $e->getMessage(),
]);
......
......@@ -5,8 +5,6 @@
namespace Minds\Core\Blockchain\Purchase;
use Minds\Core\Queue;
use Minds\Core\Events\Dispatcher;
use Minds\Core\Di\Di;
use Minds\Entities\User;
use Minds\Core\Blockchain\Transactions\Transaction;
......
......@@ -65,27 +65,27 @@ class Campaign implements JsonSerializable
use MagicAttributes;
/** @var string */
const PENDING_STATUS = 'pending';
const STATUS_PENDING = 'pending';
/** @var string */
const CREATED_STATUS = 'created';
const STATUS_CREATED = 'created';
/** @var string */
const APPROVED_STATUS = 'approved';
const STATUS_APPROVED = 'approved';
/** @var string */
const REJECTED_STATUS = 'rejected';
const STATUS_REJECTED = 'rejected';
/** @var string */
const REVOKED_STATUS = 'revoked';
const STATUS_REVOKED = 'revoked';
/** @var string */
const COMPLETED_STATUS = 'completed';
const STATUS_COMPLETED = 'completed';
/** @var int */
const SAFE_RATING = 1;
const RATING_SAFE = 1;
/** @var int */
const OPEN_RATING = 2;
const RATING_OPEN = 2;
/** @var string */
protected $urn;
......@@ -195,18 +195,18 @@ class Campaign implements JsonSerializable
public function getDeliveryStatus()
{
if ($this->completedTimestamp) {
return static::COMPLETED_STATUS;
return static::STATUS_COMPLETED;
} elseif ($this->rejectedTimestamp) {
return static::REJECTED_STATUS;
return static::STATUS_REJECTED;
} elseif ($this->revokedTimestamp) {
return static::REVOKED_STATUS;
return static::STATUS_REVOKED;
} elseif ($this->reviewedTimestamp) {
return static::APPROVED_STATUS;
return static::STATUS_APPROVED;
} elseif ($this->createdTimestamp) {
return static::CREATED_STATUS;
return static::STATUS_CREATED;
}
return static::PENDING_STATUS;
return static::STATUS_PENDING;
}
/**
......@@ -216,7 +216,7 @@ class Campaign implements JsonSerializable
public function setNsfw($value)
{
$this->nsfw = $value;
$this->setRating(count($this->getNsfw()) > 0 ? static::OPEN_RATING : static::SAFE_RATING); // 2 = open; 1 = safe
$this->setRating(count($this->getNsfw()) > 0 ? static::RATING_OPEN : static::RATING_SAFE); // 2 = open; 1 = safe
return $this;
}
......@@ -238,7 +238,7 @@ class Campaign implements JsonSerializable
*/
public function isDelivering()
{
return $this->getDeliveryStatus() === static::APPROVED_STATUS;
return $this->getDeliveryStatus() === static::STATUS_APPROVED;
}
/**
......@@ -247,7 +247,7 @@ class Campaign implements JsonSerializable
*/
public function shouldBeStarted($now)
{
$isCreated = $this->getDeliveryStatus() === static::CREATED_STATUS;
$isCreated = $this->getDeliveryStatus() === static::STATUS_CREATED;
$started = $now >= $this->getStart() && $now < $this->getEnd();
return $isCreated && $started;
......@@ -266,6 +266,26 @@ class Campaign implements JsonSerializable
return $isDelivering && ($ended || $fulfilled);
}
/**
* @return bool
*/
public function hasStarted(): bool
{
return !in_array($this->getDeliveryStatus(), [static::STATUS_PENDING, static::STATUS_CREATED], true);
}
/**
* @return bool
*/
public function hasFinished(): bool
{
return in_array($this->getDeliveryStatus(), [
static::STATUS_COMPLETED,
static::STATUS_REJECTED,
static::STATUS_REVOKED,
], true);
}
/**
* @return array
*/
......
......@@ -18,28 +18,13 @@ class NormalizeDatesDelegate
*/
public function onCreate(Campaign $campaign)
{
$start = intval($campaign->getStart() / 1000);
$end = intval($campaign->getEnd() / 1000);
$start = $this->normaliseStartTime($campaign->getStart());
$end = $this->normaliseEndTime($campaign->getEnd());
$this->validateStartTime($start);
$this->validateEndTime($end);
$this->validateStartAgainstEnd($start, $end);
if ($start <= 0 || $end <= 0) {
throw new CampaignException('Campaign should have a start and end date');
}
$today = strtotime(date('Y-m-d') . ' 00:00:00') * 1000;
$start = strtotime(date('Y-m-d', $start) . ' 00:00:00') * 1000;
$end = strtotime(date('Y-m-d', $end) . ' 23:59:59') * 1000;
if ($start < $today) {
throw new CampaignException('Campaign start should not be in the past');
} elseif ($start >= $end) {
throw new CampaignException('Campaign end before starting');
}
$campaign
->setStart($start)
->setEnd($end);
return $campaign;
return $campaign->setStart($start)->setEnd($end);
}
/**
......@@ -52,21 +37,64 @@ class NormalizeDatesDelegate
{
// TODO: Ensure date updates from ref are valid against original campaign budget, etc.
// Only allow changing start date if the campaign hasn't yet started
if ($campaign->getDeliveryStatus() === Campaign::CREATED_STATUS) {
$campaign->setStart($campaignRef->getStart());
$start = $this->normaliseStartTime($campaignRef->getStart());
$end = $this->normaliseEndTime($campaignRef->getEnd());
$this->validateStartTime($start);
$this->validateEndTime($end);
$this->validateStartAgainstEnd($start, $end);
if (!$campaign->hasStarted()) {
$campaign->setStart($start);
}
if (!$campaign->hasFinished() && $campaign->getEnd() < $end) {
$campaign->setEnd($end);
}
return $campaign;
}
private function normaliseStartTime(int $startTime): int
{
return strtotime(date('Y-m-d', $startTime / 1000) . ' 00:00:00') * 1000;
}
private function normaliseEndTime(int $endTime): int
{
return strtotime(date('Y-m-d', $endTime / 1000) . ' 23:59:59') * 1000;
}
private function validateStartTime(int $startTime): void
{
if ($startTime <= 0) {
throw new CampaignException('Campaign should have a start date');
}
$today = strtotime(date('Y-m-d') . ' 00:00:00') * 1000;
if ($startTime < $today) {
throw new CampaignException('Campaign start should not be in the past');
}
}
private function validateEndTime(int $endTime): void
{
if ($endTime <= 0) {
throw new CampaignException('Campaign should have an end date');
}
}
// Only allow extending the campaign if it hasn't hasn't finished
if (
!in_array($campaign->getDeliveryStatus(), [
Campaign::COMPLETED_STATUS, Campaign::REJECTED_STATUS, Campaign::REVOKED_STATUS,
], true)
&& $campaign->getEnd() <= $campaignRef->getEnd()
) {
$campaign->setEnd($campaignRef->getEnd());
private function validateStartAgainstEnd(int $start, int $end): void
{
if ($start >= $end) {
throw new CampaignException('Campaign end before starting');
}
return $this->onCreate($campaign);
$startPlusOneMonth = strtotime('+1 month', $start / 1000) * 1000;
if ($startPlusOneMonth < $end) {
throw new CampaignException('Campaign must not be longer than 1 month');
}
}
}
......@@ -105,9 +105,9 @@ class PaymentsDelegate
// NOTE: Do not spec test. Individually test the other methods.
$isFinished = in_array($campaign->getDeliveryStatus(), [
Campaign::REJECTED_STATUS,
Campaign::REVOKED_STATUS,
Campaign::COMPLETED_STATUS
Campaign::STATUS_REJECTED,
Campaign::STATUS_REVOKED,
Campaign::STATUS_COMPLETED
], true);
if ($isFinished) {
......
......@@ -268,7 +268,7 @@ class Manager
// Check state
if (!in_array($campaign->getDeliveryStatus(), [Campaign::PENDING_STATUS, Campaign::CREATED_STATUS, Campaign::APPROVED_STATUS], true)) {
if (!in_array($campaign->getDeliveryStatus(), [Campaign::STATUS_PENDING, Campaign::STATUS_CREATED, Campaign::STATUS_APPROVED], true)) {
throw new CampaignException('Campaign should be in [pending], [created], [approved] state in order to edit it');
}
......@@ -358,7 +358,7 @@ class Manager
// Check state
if ($campaign->getDeliveryStatus() !== Campaign::CREATED_STATUS) {
if ($campaign->getDeliveryStatus() !== Campaign::STATUS_CREATED) {
throw new CampaignException('Campaign should be in [created] state in order to start it');
}
......@@ -400,7 +400,7 @@ class Manager
// Check state
if (!in_array($campaign->getDeliveryStatus(), [Campaign::CREATED_STATUS, Campaign::APPROVED_STATUS], true)) {
if (!in_array($campaign->getDeliveryStatus(), [Campaign::STATUS_CREATED, Campaign::STATUS_APPROVED], true)) {
throw new CampaignException('Campaign should be in [created] or [approved] state in order to cancel it');
}
......@@ -450,7 +450,7 @@ class Manager
// Check state
if ($campaign->getDeliveryStatus() !== Campaign::CREATED_STATUS) {
if ($campaign->getDeliveryStatus() !== Campaign::STATUS_CREATED) {
throw new CampaignException('Campaign should be in [created] state in order to reject it');
}
......@@ -494,7 +494,7 @@ class Manager
// Check state
if ($campaign->getDeliveryStatus() !== Campaign::APPROVED_STATUS) {
if ($campaign->getDeliveryStatus() !== Campaign::STATUS_APPROVED) {
throw new CampaignException('Campaign should be in [approved] state in order to complete it');
}
......
<?php
namespace Minds\Core;
use League\OAuth2\Server\ResourceServer;
use Minds\Core;
use Minds\Core\Di\Di;
use Minds\Common\Cookie;
......@@ -13,6 +14,7 @@ use Sentry;
*/
class Session extends base
{
/** @var User $user */
private static $user;
private $session_name = 'minds';
......@@ -39,7 +41,7 @@ class Session extends base
/**
* Create a JWT token for our web socket integration
* @param User $user
* @param Core\Sessions\Session $session
* @return null
*/
public static function generateJWTCookie($session)
......@@ -63,12 +65,14 @@ class Session extends base
/**
* Construct the user via the OAuth middleware
* @param $server
* @param $request
* @param $response
* @return void
*/
public static function withRouterRequest(&$request, &$response)
{
try {
/** @var ResourceServer $server */
$server = Di::_()->get('OAuth\Server\Resource');
$request = $server->validateAuthenticatedRequest($request);
$user_guid = $request->getAttribute('oauth_user_id');
......@@ -80,7 +84,7 @@ class Session extends base
/**
* Construct the user manually by guid
* @param $user
* @param $user_guid
* @return void
*/
public static function setUserByGuid($user_guid)
......@@ -91,7 +95,7 @@ class Session extends base
/**
* Construct the user manually
* @param $user
* @param User $user
* @return void
*/
public static function setUser($user)
......
......@@ -6,6 +6,19 @@ namespace Minds\Core\Sessions;
use Minds\Traits\MagicAttributes;
/**
* Class Session
* @package Minds\Core\Sessions
*
* @method int getId()
* @method Session setId(string $id)
* @method string getToken()
* @method Session setToken(string $token)
* @method int getUserGuid()
* @method Session setUserGuid(int $userGuid)
* @method int getExpires()
* @method Session setExpires(int $expires)
*/
class Session
{
use MagicAttributes;
......
......@@ -68,35 +68,35 @@ class CampaignSpec extends ObjectBehavior
{
$this
->getDeliveryStatus()
->shouldReturn(Campaign::PENDING_STATUS);
->shouldReturn(Campaign::STATUS_PENDING);
$this
->setCreatedTimestamp(1564537097)
->getDeliveryStatus()
->shouldReturn(Campaign::CREATED_STATUS);
->shouldReturn(Campaign::STATUS_CREATED);
$this
->setReviewedTimestamp(1564537097)
->getDeliveryStatus()
->shouldReturn(Campaign::APPROVED_STATUS);
->shouldReturn(Campaign::STATUS_APPROVED);
$this
->setReviewedTimestamp(null)
->setRevokedTimestamp(1564537097)
->getDeliveryStatus()
->shouldReturn(Campaign::REVOKED_STATUS);
->shouldReturn(Campaign::STATUS_REVOKED);
$this
->setRevokedTimestamp(null)
->setRejectedTimestamp(1564537097)
->getDeliveryStatus()
->shouldReturn(Campaign::REJECTED_STATUS);
->shouldReturn(Campaign::STATUS_REJECTED);
$this
->setRejectedTimestamp(null)
->setCompletedTimestamp(1564537097)
->getDeliveryStatus()
->shouldReturn(Campaign::COMPLETED_STATUS);
->shouldReturn(Campaign::STATUS_COMPLETED);
}
public function it_should_set_nsfw_along_with_rating()
......@@ -109,7 +109,7 @@ class CampaignSpec extends ObjectBehavior
->shouldReturn([]);
$this->getRating()
->shouldReturn(Campaign::SAFE_RATING);
->shouldReturn(Campaign::RATING_SAFE);
$this
->setNsfw([1, 3]);
......@@ -119,7 +119,7 @@ class CampaignSpec extends ObjectBehavior
->shouldReturn([1, 3]);
$this->getRating()
->shouldReturn(Campaign::OPEN_RATING);
->shouldReturn(Campaign::RATING_OPEN);
}
public function it_should_calculate_cpm()
......
......@@ -2,9 +2,10 @@
namespace Spec\Minds\Core\Boost\Campaigns\Delegates;
use Minds\Core\Boost\Campaigns\Campaign;
use Minds\Core\Boost\Campaigns\CampaignException;
use Minds\Core\Boost\Campaigns\Delegates\NormalizeDatesDelegate;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class NormalizeDatesDelegateSpec extends ObjectBehavior
{
......@@ -12,4 +13,96 @@ class NormalizeDatesDelegateSpec extends ObjectBehavior
{
$this->shouldHaveType(NormalizeDatesDelegate::class);
}
public function it_should_reject_start_date_in_past_on_create(Campaign $campaign)
{
$campaign->getStart()->willReturn(strtotime('-1 day') * 1000);
$campaign->getEnd()->willReturn(strtotime('+3 days') * 1000);
$this->shouldThrow(CampaignException::class)->during('onCreate', [$campaign]);
}
public function it_should_reject_end_date_before_start_date_on_create(Campaign $campaign)
{
$campaign->getStart()->willReturn(strtotime('+2 days') * 1000);
$campaign->getEnd()->willReturn(strtotime('+1 days') * 1000);
$this->shouldThrow(CampaignException::class)->during('onCreate', [$campaign]);
}
public function it_should_adjust_start_and_end_to_first_and_last_timestamps_of_days_on_create(Campaign $campaign)
{
$campaign->getStart()->willReturn(strtotime('today 12:01:31') * 1000);
$campaign->getEnd()->willReturn(strtotime('+1 days 17:32:05') * 1000);
$campaign->setStart(strtotime('today 00:00:00') * 1000)->shouldBeCalled()->willReturn($campaign);
$campaign->setEnd(strtotime('+1 days 23:59:59') * 1000)->shouldBeCalled()->willReturn($campaign);
$this->onCreate($campaign);
}
public function it_should_accept_valid_days_on_create(Campaign $campaign)
{
$campaign->getStart()->willReturn(strtotime('+2 days') * 1000);
$campaign->getEnd()->willReturn(strtotime('+5 days') * 1000);
$campaign->setStart(strtotime('+2 days 00:00:00') * 1000)->shouldBeCalled()->willReturn($campaign);
$campaign->setEnd(strtotime('+5 days 23:59:59') * 1000)->shouldBeCalled()->willReturn($campaign);
$this->onCreate($campaign);
}
public function it_should_reject_campaign_longer_than_one_month(Campaign $campaign)
{
$campaign->getStart()->willReturn(strtotime('+2 days') * 1000);
$campaign->getEnd()->willReturn(strtotime('+34 days') * 1000);
$this->shouldThrow(CampaignException::class)->during('onCreate', [$campaign]);
}
public function it_should_validate_dates_are_valid_against_campaign_budget_on_update()
{
// TODO: Not Implemented yet
}
public function it_should_not_change_start_date_if_campaign_has_started_on_update(Campaign $campaign, Campaign $campaignRef)
{
$campaign->hasStarted()->shouldBeCalled()->willReturn(true);
$campaign->hasFinished()->shouldBeCalled()->willReturn(true);
$campaignRef->getStart()->willReturn(strtotime('+2 days') * 1000);
$campaignRef->getEnd()->willReturn(strtotime('+5 days') * 1000);
$campaign->getStart()->willReturn(strtotime('+2 days') * 1000);
$campaign->getEnd()->willReturn(strtotime('+5 days') * 1000);
$this->onUpdate($campaign, $campaignRef);
}
public function it_should_change_start_date_if_campaign_has_not_started_on_update(Campaign $campaign, Campaign $campaignRef)
{
$campaign->hasStarted()->shouldBeCalled()->willReturn(false);
$campaign->hasFinished()->shouldBeCalled()->willReturn(false);
$campaignRef->getStart()->willReturn(strtotime('+2 days') * 1000);
$campaignRef->getEnd()->willReturn(strtotime('+5 days') * 1000);
$campaign->getStart()->willReturn(strtotime('+2 days') * 1000);
$campaign->getEnd()->willReturn(strtotime('+5 days') * 1000);
$campaign->setStart(strtotime('+2 days 00:00:00') * 1000)->shouldBeCalled()->willReturn($campaign);
$campaign->setEnd(strtotime('+5 days 23:59:59') * 1000)->shouldBeCalled();
$this->onUpdate($campaign, $campaignRef);
}
public function it_should_only_change_end_date_if_campaign_hasnt_finished_on_update(Campaign $campaign, Campaign $campaignRef)
{
$campaign->hasStarted()->shouldBeCalled()->willReturn(true);
$campaign->hasFinished()->shouldBeCalled()->willReturn(false);
$campaignRef->getStart()->willReturn(strtotime('+2 days') * 1000);
$campaignRef->getEnd()->willReturn(strtotime('+7 days') * 1000);
$campaign->getStart()->willReturn(strtotime('+2 days') * 1000);
$campaign->getEnd()->willReturn(strtotime('+5 days') * 1000);
$campaign->setEnd(strtotime('+7 days 23:59:59') * 1000)->shouldBeCalled();
$this->onUpdate($campaign, $campaignRef);
}
}
......@@ -4,7 +4,7 @@ chmod = 0777
chown= nobody:nogroup
[supervisord]
logfile = /dev/stdout
logfile = /dev/null
logfile_maxbytes = 0
loglevel = debug
pidfile = /tmp/supervisord.pid
......@@ -19,4 +19,4 @@ serverurl = unix:///tmp/supervisor.sock
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[include]
files = /etc/supervisor/conf.d/*.conf
\ No newline at end of file
files = /etc/supervisor/conf.d/*.conf