...
 
Commits (14)
......@@ -13,22 +13,16 @@ stages:
- deploy:canary
- deploy:production
cache:
paths:
- vendor
- bin
policy: pull
build:
stage: build
script:
- apk update && apk add --no-cache git
- sh tools/setup.sh production
cache:
artifacts:
name: '$CI_COMMIT_REF_SLUG'
paths:
- vendor
- bin
policy: push
test:
stage: test
......
......@@ -25,13 +25,22 @@ class plus implements Interfaces\Api
*/
public function get($pages)
{
$response = [];
$user = Core\Session::getLoggedInUser();
if (!$user) {
return Factory::response([
'status' => 'error',
'message' => 'Invalid user'
]);
}
$plus = new Core\Plus\Subscription();
$plus->setUser(Core\Session::getLoggedInUser());
$response['active'] = $plus->isActive();
$plus->setUser($user);
return Factory::response($response);
return Factory::response([
'active' => $plus->isActive(),
'can_be_cancelled' => $plus->canBeCancelled()
]);
}
public function post($pages)
......
......@@ -26,78 +26,37 @@ class subscribe implements Interfaces\Api
*/
public function get($pages)
{
$manager = new Subscriptions\Manager();
$response = [];
switch ($pages[0]) {
case 'subscriptions':
$db = new \Minds\Core\Data\Call('friends');
$subscribers= $db->getRow($pages[1], ['limit'=>get_input('limit', 12), 'offset'=>get_input('offset', '')]);
if (!$subscribers) {
return Factory::response([]);
}
$users = [];
foreach ($subscribers as $guid => $subscriber) {
if ($guid == get_input('offset')) {
continue;
}
if (is_numeric($subscriber)) {
//this is a local, old style subscription
$users[] = new \Minds\Entities\User($guid);
continue;
}
$users[] = new \Minds\Entities\User(json_decode($subscriber, true));
}
$users = array_values(array_filter($users, function ($user) {
return ($user->enabled != 'no' && $user->banned != 'yes');
}));
$response['users'] = factory::exportable($users);
$response['load-next'] = (string) end($users)->guid;
$response['load-previous'] = (string) key($users)->guid;
break;
case 'subscribers':
if ($pages[1] == "100000000000000519") {
break;
}
$db = new \Minds\Core\Data\Call('friendsof');
$subscribers= $db->getRow($pages[1], ['limit'=>get_input('limit', 12), 'offset'=>get_input('offset', '')]);
if (!$subscribers) {
return Factory::response([]);
}
$users = [];
if (get_input('offset') && key($subscribers) != get_input('offset')) {
$response['load-previous'] = (string) get_input('offset');
} else {
foreach ($subscribers as $guid => $subscriber) {
if ($guid == get_input('offset')) {
unset($subscribers[$guid]);
continue;
}
if (is_numeric($subscriber)) {
//this is a local, old style subscription
$users[] = new \Minds\Entities\User($guid);
continue;
}
//var_dump(print_r($users,true));die();
$users[] = new \Minds\Entities\User(json_decode($subscriber, true));
}
$users = array_values(array_filter($users, function ($user) {
return ($user->enabled != 'no' && $user->banned != 'yes')
&& $user->guid && $user->username;
}));
$response['users'] = factory::exportable($users);
$response['load-next'] = (string) end($users)->guid;
$response['load-previous'] = (string) key($users)->guid;
}
break;
$guid = $pages[1] ?? Core\Session::getLoggedInUser()->guid;
$type = $pages[0] ?? "subscribers";
$limit = $_GET['limit'] ?? 12;
$offset = $_GET['offset'] ?? "";
$opts = [
'guid'=>$guid,
'type'=>$type,
'limit'=>$limit,
'offset'=>$offset,
];
$users = $manager->getList($opts);
if (!$users) {
return Factory::response([
'status' => 'error',
'message' => 'Unable to find '.$type,
]);
}
$pagingToken = (string) $users->getPagingToken();
$users = array_filter(Factory::exportable($users->toArray()), function ($user) {
return ($user->enabled != 'no' && $user->banned != 'yes');
});
$response['users'] = $users;
$response['load-next'] = $pagingToken;
return Factory::response($response);
}
......
......@@ -37,4 +37,15 @@ class Custom implements Interfaces\PreparedInterface
{
return $this->opts;
}
/**
* Gets the template of the custom query
* e.g. "SELECT * FROM friendsof WHERE column1 = ?"
*
* @return string the template.
*/
public function getTemplate(): string
{
return $this->template;
}
}
You've received a gift of 1 Minds token! You can spend this token to earn 1,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'] ?>) |
| |
......@@ -13,6 +13,7 @@ class Subscription
{
private $stripe;
private $repo;
/** @var User */
protected $user;
/** @var Manager $subscriptionsManager */
protected $subscriptionsManager;
......@@ -44,13 +45,15 @@ class Subscription
*/
public function isActive()
{
$subscription = $this->getSubscription();
if (!$subscription) {
return false;
}
return $this->user->isPlus();
}
return $subscription->getStatus() == 'active';
/**
* @return bool
*/
public function canBeCancelled()
{
return ((int) $this->user->plus_expires) > time();
}
/**
......
......@@ -1510,3 +1510,18 @@ CREATE MATERIALIZED VIEW minds.pro_by_domain AS
WHERE user_guid IS NOT NULL AND domain IS NOT NULL
PRIMARY KEY (domain, user_guid)
WITH CLUSTERING ORDER BY (user_guid ASC);
CREATE TABLE minds.subscription_requests (
publisher_guid bigint,
subscriber_guid bigint,
timestamp timestamp,
declined boolean,
PRIMARY KEY (publisher_guid, subscriber_guid)
);
CREATE TABLE minds.notification_batches (
user_guid varint,
batch_id text,
primary key (user_guid, batch_id)
);
......@@ -171,7 +171,7 @@ class EntityMapping implements MappingInterface
$fullText .= ' ' . $map['message'];
}
$htRe = '/(^|\s||)#(\w*[a-zA-Z_]+\w*)/';
$htRe = '/(^|\s||)#(\w*[a-zA-Z0-9_]+\w*)/';
$matches = [];
preg_match_all($htRe, $fullText, $matches);
......
......@@ -61,6 +61,32 @@ class Manager
$this->checkRateLimitDelegate = $checkRateLimitDelegate ?: new CheckRateLimit();
}
/**
* Gets a subscription or subscribers list from the repository.
*
* @param array $opts -
* guid - required!
* type - either 'subscribers' or 'subscriptions'.
* limit - limit.
* offset - offset.
* @return Response response objet
*/
public function getList($opts)
{
if (!$opts['guid']) {
return [];
}
$opts = array_merge([
'limit' => 12,
'offset' => '',
'guid' => '',
'type' => 'subscribers',
], $opts);
return $this->repository->getList($opts);
}
public function setSubscriber($user)
{
$this->subscriber = $user;
......
......@@ -5,9 +5,9 @@ namespace Minds\Core\Subscriptions;
use Cassandra;
use Minds\Common\Repository\Response;
use Minds\Core\Data\Cassandra\Client;
use Minds\Core\Data\Cassandra\Prepared\Custom;
use Minds\Core\Di\Di;
use Minds\Core\Util\UUIDGenerator;
use Minds\Core\Data\Cassandra\Prepared;
use Minds\Entities\User;
class Repository
{
......@@ -20,17 +20,67 @@ class Repository
}
/**
* @param array $opts
* @return Response
* Gets a subscription or subscribers list from cassandra.
*
* @param array $opts -
* guid - required!
* type - either 'subscribers' or 'subscriptions'.
* limit - limit.
* offset - offset.
* @return Response response object.
*/
public function getList(array $opts = [])
public function getList(array $opts = []): Response
{
$opts = array_merge([
'limit' => 10,
'offset' => 0,
'uuid' => '',
'recursive' => false,
'limit' => 12,
'offset' => '',
'guid' => null,
'type' => null,
], $opts);
if (!$opts['guid']) {
throw new \Exception('GUID is required');
}
$response = new Response;
if ($opts['type'] === 'subscribers') {
$statement = "SELECT * FROM friendsof";
} else {
$statement = "SELECT * FROM friends";
}
$where = ["key = ?"];
$values = [$opts['guid']];
$statement .= " WHERE " . implode(' AND ', $where);
$cqlOpts = [];
if ($opts['limit']) {
$cqlOpts['page_size'] = (int) $opts['limit'];
}
if ($opts['offset']) {
$cqlOpts['paging_state_token'] = base64_decode($opts['offset'], true);
}
$query = new Prepared\Custom();
$query->query($statement, $values);
$query->setOpts($cqlOpts);
try {
$rows = $this->client->request($query);
foreach ($rows as $row) {
$user = new User($row['column1']);
$response[] = $user;
}
$response->setPagingToken(base64_encode($rows->pagingStateToken()));
$response->setLastPage($rows->isLastPage());
} catch (\Exception $e) {
// do nothing.
}
return $response;
}
/**
......
......@@ -431,7 +431,7 @@ class Group extends NormalizedEntity
{
$guids = $this->getOwnerGuids();
return $guids
? guids[0]
? $guids[0]
: $this->getOwnerObj()->guid;
}
......
......@@ -902,11 +902,11 @@ class User extends \ElggUser
/**
* Is the user a plus user.
*
* @return int
* @return bool
*/
public function isPlus()
{
return (bool) ((int) $this->plus_expires > time());
return $this->isPro() || ((int) $this->plus_expires > time());
}
/**
......
......@@ -75,8 +75,8 @@ class EmailRewards
$validator = $_GET['validator'];
//$key = '.md';
//return;
if ($validator == sha1($campaign . 'gift-30-09-19.mdl' . $topic . $user->guid . Config::_()->get('emails_secret'))) {
$tokens = 2 * (10 ** 18);
if ($validator == sha1($campaign . 'gift-30-10-19.mdl' . $topic . $user->guid . Config::_()->get('emails_secret'))) {
$tokens = 1 * (10 ** 18);
$campaign = $validator; //hack
} else {
return;
......
......@@ -22,41 +22,35 @@ class SubscriptionSpec extends ObjectBehavior
public function it_should_return_if_a_subscription_is_active(
Stripe $stripe,
Repository $repo,
Subscription $subscription
User $user
) {
$this->beConstructedWith($stripe, null, $repo);
$repo->getList(Argument::any())->willReturn([
$subscription
]);
$subscription->getStatus()->willReturn('active');
$user = new User();
$user->guid = 123;
$user->isPlus()
->shouldBeCalled()
->willReturn(true);
$this->setUser($user);
$this->isActive()->shouldBe(true);
$this
->setUser($user)
->isActive()
->shouldBe(true);
}
public function it_should_return_false_if_a_subscription_is_active(
Stripe $stripe,
Repository $repo,
Subscription $subscription
User $user
) {
$this->beConstructedWith($stripe, null, $repo);
$repo->getList(Argument::any())->willReturn([
$subscription
]);
$subscription->getStatus()->willReturn('cancelled');
$user = new User();
$user->guid = 123;
$user->isPlus()
->shouldBeCalled()
->willReturn(false);
$this->setUser($user);
$this->isActive()->shouldBe(false);
$this
->setUser($user)
->isActive()
->shouldBe(false);
}
public function is_should_create_a_new_subscription(
......
......@@ -7,6 +7,8 @@ use Minds\Core\Subscriptions\Subscription;
use Minds\Core\Data\Cassandra\Client;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Spec\Minds\Mocks\Cassandra\Rows;
use Minds\Common\Repository\Response;
class RepositorySpec extends ObjectBehavior
{
......@@ -62,4 +64,40 @@ class RepositorySpec extends ObjectBehavior
$newSubscription->isActive()
->shouldBe(false);
}
public function it_should_get_subscribers()
{
$this->client->request(Argument::that(function ($prepared) {
var_dump($prepared->getTemplate());
return $prepared->getTemplate() === "SELECT * FROM friendsof WHERE key = ?";
}))
->shouldBeCalled()
->willReturn(new Rows([
[ 'guid' => 1 ],
[ 'guid' => 2 ],
], 'paging-token'));
$this->getList([
'guid' => '1234567891',
'type' => 'subscribers',
])->shouldImplement(Response::class);
}
public function it_should_get_subscriptions()
{
$this->client->request(Argument::that(function ($prepared) {
return $prepared->getTemplate() === "SELECT * FROM friends WHERE key = ?";
}))
->shouldBeCalled()
->willReturn(new Rows([
[ 'guid' => 1 ],
[ 'guid' => 2 ],
], 'paging-token'));
$this->getList([
'guid' => '1234567891',
'type' => 'subscriptions',
])->shouldImplement(Response::class);
}
}