...
 
Commits (33)
image: minds/php:latest
services:
- docker:dind
image: minds/php:7.3
stages:
- build
......@@ -16,7 +13,7 @@ stages:
build:
stage: build
script:
- apk update && apk add --no-cache git
- apk add --no-cache git
- sh tools/setup.sh production
artifacts:
name: '$CI_COMMIT_REF_SLUG'
......@@ -26,19 +23,21 @@ build:
test:
stage: test
image: minds/php-tests:latest
image: minds/php:7.3
script:
- bin/phpspec run
- php -n -c Spec/php-test.ini bin/phpspec run
lint:
stage: test
image: minds/php-tests:latest
image: minds/php:7.3
script:
- bin/php-cs-fixer fix --allow-risky=yes --verbose --dry-run
prepare:fpm:
stage: prepare
image: minds/ci:latest
services:
- docker:dind
script:
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- |
......@@ -53,6 +52,8 @@ prepare:fpm:
prepare:runners:
stage: prepare
image: minds/ci:latest
services:
- docker:dind
script:
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- |
......@@ -136,6 +137,8 @@ qa:manual:
staging:fpm:
stage: deploy:staging
image: minds/ci:latest
services:
- docker:dind
script:
- IMAGE_LABEL="staging"
- $(aws ecr get-login --no-include-email --region us-east-1)
......@@ -162,6 +165,8 @@ staging:fpm:
canary:fpm:
stage: deploy:canary
image: minds/ci:latest
services:
- docker:dind
script:
- IMAGE_LABEL="canary"
- $(aws ecr get-login --no-include-email --region us-east-1)
......@@ -190,6 +195,8 @@ canary:fpm:
production:fpm:
stage: deploy:production
image: minds/ci:latest
services:
- docker:dind
script:
- IMAGE_LABEL="production"
- $(aws ecr get-login --no-include-email --region us-east-1)
......@@ -218,6 +225,8 @@ production:fpm:
production:runners:
stage: deploy:production
image: minds/ci:latest
services:
- docker:dind
script:
- IMAGE_LABEL="production"
- $(aws ecr get-login --no-include-email --region us-east-1)
......
......@@ -40,12 +40,14 @@ class CustomerSync extends Cli\Controller implements Interfaces\CliControllerInt
$guid = $data[29];
try {
$insert = new Core\Data\Cassandra\Prepared\Custom();
$insert->query("INSERT INTO user_index_to_guid (key, column1, value) VALUES (?, ?, ?)",
[
$insert->query(
"INSERT INTO user_index_to_guid (key, column1, value) VALUES (?, ?, ?)",
[
"$guid:payments",
"customer_id",
$id
]);
]
);
$this->db->request($insert);
$this->out("$guid with customer id $id done");
} catch (\Exception $e) {
......
......@@ -56,18 +56,21 @@ class SubscriptionSync extends Cli\Controller implements Interfaces\CliControlle
$amount = ($result->quantity * $result->plan->amount) / 100;
$insert = new Core\Data\Cassandra\Prepared\Custom();
$insert->query("INSERT INTO plans (user_guid, plan, entity_guid, amount) VALUES (?, ?, ?, ?)",
[
$insert->query(
"INSERT INTO plans (user_guid, plan, entity_guid, amount) VALUES (?, ?, ?, ?)",
[
$plan['user_guid'],
$plan['plan'],
$plan['entity_guid'],
(int) $amount
]);
]
);
$this->db->request($insert);
if ($plan['plan'] == 'exclusive') {
$query = new Core\Data\Cassandra\Prepared\Custom();
$query->query("INSERT INTO wire
$query->query(
"INSERT INTO wire
(receiver_guid, sender_guid, method, timestamp, entity_guid, wire_guid, amount, recurring, status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
[
......@@ -80,7 +83,8 @@ class SubscriptionSync extends Cli\Controller implements Interfaces\CliControlle
new \Cassandra\Decimal($amount),
true,
'success'
]);
]
);
$this->db->request($query);
}
......
......@@ -36,8 +36,12 @@ class report implements Interfaces\Api
/** @var Core\Reports\Repository $repository */
$repository = Di::_()->get('Reports\Repository');
$done = $repository->create($pages[0], Core\Session::getLoggedinUser(),
$reason, $reason_note);
$done = $repository->create(
$pages[0],
Core\Session::getLoggedinUser(),
$reason,
$reason_note
);
return Factory::response([
'done' => $done
......
......@@ -85,7 +85,7 @@ class media implements Interfaces\Api, Interfaces\ApiIgnorePam
Security\ACL::$ignore = $ignore;
}
/* No break */
/* no break */
default:
$entity->fullExport = true;
$response['entity'] = $entity->export();
......
......@@ -299,28 +299,6 @@ class merchant implements Interfaces\Api
$response['uploaded'] = true;
}
break;
case "charge":
$sale = (new Payments\Sale)
->setId($pages[1]);
try {
Payments\Factory::build('braintree', ['gateway'=>'merchants'])->chargeSale($sale);
} catch (\Exception $e) {
var_dump($e);
exit;
}
exit;
break;
case "void":
$sale = (new Payments\Sale)
->setId($pages[1]);
Payments\Factory::build('braintree', ['gateway'=>'merchants'])->voidSale($sale);
break;
case "refund":
$sale = (new Payments\Sale)
->setId($pages[1]);
Payments\Factory::build('braintree', ['gateway'=>'merchants'])->refundSale($sale);
break;
}
return Factory::response($response);
......
......@@ -9,6 +9,7 @@ namespace Minds\Controllers\api\v1\minds;
use Minds;
use Minds\Core;
use Minds\Core\Rewards\Contributions\ContributionValues;
use Minds\Interfaces;
use Minds\Api\Factory;
......@@ -44,6 +45,7 @@ class config implements Interfaces\Api, Interfaces\ApiIgnorePam
'pro' => Minds\Core\Di\Di::_()->get('Config')->get('pro')['handler'] ?? null,
],
'upgrades' => Minds\Core\Di\Di::_()->get('Config')->get('upgrades'),
'contribution_values' => ContributionValues::export(),
];
return Factory::response($minds);
......
......@@ -379,7 +379,7 @@ class newsfeed implements Interfaces\Api
->setTitle($embeded->title)
->setBlurb($embeded->description)
->export()
)
)
->setMessage($message);
}
$save->setEntity($activity)
......@@ -417,7 +417,7 @@ class newsfeed implements Interfaces\Api
->setTitle($embeded->title)
->setBlurb($embeded->description)
->export()
)
)
->setMessage($message);
}
$save->setEntity($activity)
......
<?php
/**
* Minds Payments API:: braintree
*
* @version 1
* @author Mark Harding
*/
namespace Minds\Controllers\api\v1\payments;
use Minds\Core;
use Minds\Helpers;
use Minds\Interfaces;
use Minds\Api\Factory;
use Minds\Core\Payments;
class braintree implements Interfaces\Api
{
/**
* Returns merchant information
* @param array $pages
*
* API:: /v1/merchant/:slug
*/
public function get($pages)
{
$response = [];
switch ($pages[0]) {
case "token":
$gateway = isset($pages[1]) ? $pages[1] : 'default';
$response['token'] = Payments\Factory::build('braintree', ['gateway'=>$gateway])->getToken();
break;
}
return Factory::response($response);
}
public function post($pages)
{
$response = [];
switch ($pages[0]) {
case "charge":
$amount = $_POST['amount'];
$fee = $amount * 0.05 + 0.30; //5% + $.30
if (!isset($_POST['merchant'])) {
$merchant = Core\Session::getLoggedInUser();
}
$sale = (new Payments\Sale())
->setAmount($amount)
->setMerchant($merchant)
->setFee($fee)
->setCustomerId(Core\Session::getLoggedInUser()->guid)
->setNonce($_POST['nonce']);
try {
$result = Payments\Factory::build('braintree', ['gateway'=>'merchants'])->setSale($sale);
} catch (\Exception $e) {
$response['status'] = "error";
$response['message'] = $e->getMessage();
}
break;
case "charge-master":
$amount = $_POST['amount'];
$sale = (new Payments\Sale())
->setAmount($amount)
->setCustomerId(Core\Session::getLoggedInUser()->guid)
->setSettle(true)
->setFee(0)
->setNonce($_POST['nonce']);
try {
$result = Payments\Factory::build('braintree', ['gateway'=>'merchants'])->setSale($sale);
} catch (\Exception $e) {
$response['status'] = "error";
$response['message'] = $e->getMessage();
}
break;
}
return Factory::response($response);
}
public function put($pages)
{
return Factory::response([]);
}
public function delete($pages)
{
return Factory::response([]);
}
}
......@@ -97,9 +97,6 @@ class subscriptions implements Interfaces\Api
}
$stripe = Core\Di\Di::_()->get('StripePayments');
$stripe->cancelSubscription($subscription);
} else {
$braintree = Payments\Factory::build("Braintree", ['gateway'=>'default']);
$braintree->cancelSubscription($subscription);
}
}
......
<?php
/**
* Minds Webhook: Braintree
*
* @version 1
* @author Mark Harding
*/
namespace Minds\Controllers\api\v1\webhooks;
use Minds\Core;
use Minds\Entities;
use Minds\Interfaces;
use Minds\Api\Factory;
use Minds\Helpers;
use Minds\Core\Payments;
use Braintree_WebhookNotification;
class braintree implements Interfaces\Api, Interfaces\ApiIgnorePam
{
/**
* NOT AVAILABLE
*/
public function get($pages)
{
return Factory::response(['status'=>'error', 'message'=>'GET is not supported for this endpoint']);
}
/**
*/
public function post($pages)
{
error_log("[webhooks]:: hit first entrace point");
/*$gateway = isset($pages[0]) ? $pages[0] : 'default';
$bt = Payments\Factory::build('braintree', ['gateway'=>$gateway]);
$hooks = new Payments\Hooks();
$hooks->loadDefaults();
$webhooks = new Payments\Braintree\Webhooks($hooks, $bt);
$webhooks->setSignature($_POST['bt_signature'])
->setPayload($_POST['bt_payload'])
->run();*/
}
public function put($pages)
{
}
public function delete($pages)
{
}
}
......@@ -48,24 +48,9 @@ class stripe implements Interfaces\Api, Interfaces\ApiIgnorePam
$hooks->run();
// Do something with $event_json
http_response_code(200); // PHP 5.4 or greater
exit;
/*$gateway = isset($pages[0]) ? $pages[0] : 'default';
$bt = Payments\Factory::build('braintree', ['gateway'=>$gateway]);
$hooks = new Payments\Hooks();
$hooks->loadDefaults();
$webhooks = new Payments\Braintree\Webhooks($hooks, $bt);
$webhooks->setSignature($_POST['bt_signature'])
->setPayload($_POST['bt_payload'])
->run();*/
return Factory::response([]);
}
......
......@@ -48,8 +48,10 @@ class peer implements Interfaces\Api
case 'inbox':
default:
$review->setType(Core\Session::getLoggedinUser()->guid);
$boosts = $review->getReviewQueue(isset($_GET['limit']) ? $_GET['limit'] : 12,
isset($_GET['offset']) ? $_GET['offset'] : "");
$boosts = $review->getReviewQueue(
isset($_GET['limit']) ? $_GET['limit'] : 12,
isset($_GET['offset']) ? $_GET['offset'] : ""
);
$response['boosts'] = Factory::exportable($boosts['data']);
......
......@@ -65,7 +65,11 @@ class scheduled implements Interfaces\Api
return Factory::response([
'status' => 'success',
'count' => $manager->getScheduledCount(['container_guid' => $container_guid, 'type' => $type])
'count' => $manager->getScheduledCount([
'container_guid' => $container_guid,
'type' => $type,
'owner_guid' => $currentUser->guid,
])
]);
default:
return Factory::response([
......@@ -148,6 +152,7 @@ class scheduled implements Interfaces\Api
'single_owner_threshold' => 0,
'pinned_guids' => $type === 'activity' ? array_reverse($container->getPinnedPosts()) : null,
'time_created_upper' => false,
'owner_guid' => $currentUser->guid,
];
if (isset($_GET['nsfw'])) {
......
......@@ -30,7 +30,7 @@ class channel implements Interfaces\Api
{
$currentUser = Session::getLoggedinUser();
$channel = new User($pages[0]);
$channel = new User(strtolower($pages[0]));
$channel->fullExport = true; //get counts
$channel->exportCounts = true;
......
......@@ -34,7 +34,7 @@ class settings implements Interfaces\Api
]);
}
$user = new User($pages[0]);
$user = new User(strtolower($pages[0]));
}
/** @var Manager $manager */
......@@ -66,7 +66,7 @@ class settings implements Interfaces\Api
]);
}
$user = new User($pages[0]);
$user = new User(strtolower($pages[0]));
}
/** @var Manager $manager */
......
......@@ -53,7 +53,7 @@ class assets implements Interfaces\Api
]);
}
$user = new User($pages[1]);
$user = new User(strtolower($pages[1]));
}
// Check uploaded file
......
......@@ -34,7 +34,7 @@ class domain implements Interfaces\Api
]);
}
$user = new User($pages[0]);
$user = new User(strtolower($pages[0]));
}
/** @var ProDomain $proDomain */
......
......@@ -10,7 +10,7 @@ namespace Minds\Controllers\fs\v1;
use Minds\Core;
use Minds\Entities;
use Minds\Interfaces;
use Minds\Api\Factory;
use Minds\Helpers\File;
class avatars implements Interfaces\FS
{
......@@ -59,10 +59,8 @@ class avatars implements Interfaces\FS
$contents = file_get_contents($filepath);
}
if ($filepath) {
$finfo = finfo_open(FILEINFO_MIME);
$mimetype = finfo_file($finfo, $filepath);
finfo_close($finfo);
if (!empty($contents)) {
$mimetype = File::getMime($contents);
} else {
$mimetype = 'image/jpeg';
}
......
......@@ -10,7 +10,7 @@ namespace Minds\Controllers\fs\v1;
use Minds\Core;
use Minds\Entities;
use Minds\Interfaces;
use Minds\Api\Factory;
use Minds\Helpers\File;
class banners implements Interfaces\FS
{
......@@ -56,6 +56,7 @@ class banners implements Interfaces\FS
$f->owner_guid = $entity->owner_guid ?: $entity->getOwnerObj()->guid;
$f->setFilename("group/{$entity->getGuid()}.jpg");
$f->open('read');
// no break
case "object":
break;
}
......@@ -101,9 +102,7 @@ class banners implements Interfaces\FS
}
}
$finfo = finfo_open(FILEINFO_MIME);
$mimetype = finfo_buffer($finfo, $content);
finfo_close($finfo);
$mimetype = File::getMime($content);
header('Content-Type: '.$mimetype);
header('Expires: ' . date('r', time() + 864000));
......
......@@ -10,7 +10,7 @@ namespace Minds\Controllers\fs\v1;
use Minds\Core;
use Minds\Entities;
use Minds\Interfaces;
use Minds\Api\Factory;
use Minds\Helpers\File;
class paywall implements Interfaces\FS
{
......@@ -31,9 +31,7 @@ class paywall implements Interfaces\FS
$contents = file_get_contents(Core\Di\Di::_()->get('Config')->get('path') . 'engine/Assets/photos/andromeda-galaxy.jpg');
}
$finfo = finfo_open(FILEINFO_MIME);
$mimetype = finfo_file($finfo, $filepath);
finfo_close($finfo);
$mimetype = File::getMime($contents);
header('Content-Type: '.$mimetype);
header('Expires: ' . date('r', time() + 864000));
header("Pragma: public");
......
......@@ -11,6 +11,7 @@ use Minds\Core\Di\Di;
use Minds\Core\Features\Manager as FeaturesManager;
use Minds\Entities;
use Minds\Interfaces;
use Minds\Helpers\File;
class thumbnail extends Core\page implements Interfaces\page
{
......@@ -69,8 +70,7 @@ class thumbnail extends Core\page implements Interfaces\page
}
try {
$finfo = new \finfo(FILEINFO_MIME);
$contentType = $finfo->buffer($contents) ?: 'image/jpeg';
$contentType = File::getMime($contents);
} catch (\Exception $e) {
error_log($e);
$contentType = 'image/jpeg';
......
<?php
/**
* Engagement Dashboard
*/
namespace Minds\Core\Analytics\Dashboards;
use Minds\Entities\User;
use Minds\Traits\MagicAttributes;
/**
* @method EngagementDashboard setTimespanId(string $timespanId)
* @method EngagementDashboard setFilterIds(array $filtersIds)
* @method EngagementDashboard setUser(User $user)
*/
class EngagementDashboard implements DashboardInterface
{
use MagicAttributes;
/** @var string */
private $timespanId = '30d';
/** @var string[] */
private $filterIds = [ 'platform::browser' ];
/** @var string */
private $metricId = 'votes_up';
/** @var Timespans\TimespansCollection */
private $timespansCollection;
/** @var Metrics\MetricsCollection */
private $metricsCollection;
/** @var Filters\FiltersCollection */
private $filtersCollection;
/** @var User */
private $user;
public function __construct(
$timespansCollection = null,
$metricsCollection = null,
$filtersCollection = null
) {
$this->timespansCollection = $timespansCollection ?? new Timespans\TimespansCollection();
$this->metricsCollection = $metricsCollection ?? new Metrics\MetricsCollection();
$this->filtersCollection = $filtersCollection ?? new Filters\FiltersCollection();
}
/**
* Build the dashboard
* @return self
*/
public function build(): self
{
$this->timespansCollection
->setSelectedId($this->timespanId)
->addTimespans(
new Timespans\TodayTimespan(),
new Timespans\_30dTimespan(),
new Timespans\_1yTimespan(),
new Timespans\MtdTimespan(),
new Timespans\YtdTimespan()
);
$this->filtersCollection
->setSelectedIds($this->filterIds)
->setUser($this->user)
->addFilters(
new Filters\ChannelFilter()
);
$this->metricsCollection
->setTimespansCollection($this->timespansCollection)
->setFiltersCollection($this->filtersCollection)
->setSelectedId($this->metricId)
->setUser($this->user)
->addMetrics(
new Metrics\Engagement\VotesUpMetric(),
new Metrics\Engagement\CommentsMetric(),
new Metrics\Engagement\RemindsMetric(),
new Metrics\Engagement\SubscribersMetric()
)
->build();
return $this;
}
/**
* Export
* @param array $extras
* @return array
*/
public function export(array $extras = []): array
{
$this->build();
return [
'category' => 'engagement',
'label' => 'Engagement',
'description' => '',
'timespan' => $this->timespansCollection->getSelected()->getId(),
'timespans' => $this->timespansCollection->export(),
'metric' => $this->metricsCollection->getSelected()->getId(),
'metrics' => $this->metricsCollection->export(),
'filter' => $this->filtersCollection->getSelectedIds(),
'filters' => $this->filtersCollection->export(),
];
}
}
......@@ -4,9 +4,11 @@ namespace Minds\Core\Analytics\Dashboards;
class Manager
{
const DASHBOARDS = [
'summary' => SummaryDashboard::class,
'traffic' => TrafficDashboard::class,
'trending' => TrendingDashboard::class,
'earnings' => EarningsDashboard::class,
'engagement' => EngagementDashboard::class,
];
/**
......
......@@ -39,7 +39,7 @@ class ActiveUsersMetric extends AbstractMetric
$timespan = $this->timespansCollection->getSelected();
$filters = $this->filtersCollection->getSelected();
$comparisonTsMs = strtotime("-{$timespan->getComparisonInterval()} days", $timespan->getFromTsMs() / 1000) * 1000;
$comparisonTsMs = strtotime("midnight -{$timespan->getComparisonInterval()} days", $timespan->getFromTsMs() / 1000) * 1000;
$currentTsMs = $timespan->getFromTsMs();
// Field name to use for the aggregation
......@@ -76,10 +76,14 @@ class ActiveUsersMetric extends AbstractMetric
],
];
$must[]['exists'] = [
'field' => 'active::total',
];
$must[]['range'] = [
'@timestamp' => [
'gte' => $tsMs,
'lte' => strtotime("midnight +{$timespan->getComparisonInterval()} days", $tsMs / 1000) * 1000,
'lt' => strtotime("midnight tomorrow +{$timespan->getComparisonInterval()} days", $tsMs / 1000) * 1000,
],
];
......@@ -145,6 +149,10 @@ class ActiveUsersMetric extends AbstractMetric
'entity_urn' => 'urn:metric:global'
];
$must[]['exists'] = [
'field' => 'active::total',
];
// Specify the resolution to avoid duplicates
$must[] = [
'term' => [
......
......@@ -54,7 +54,7 @@ abstract class AbstractEarningsMetric extends AbstractMetric
$must[]['range'] = [
'@timestamp' => [
'gte' => $tsMs,
'lte' => strtotime("midnight +{$timespan->getComparisonInterval()} days", $tsMs / 1000) * 1000,
'lt' => strtotime("midnight tomorrow +{$timespan->getComparisonInterval()} days", $tsMs / 1000) * 1000,
],
];
......@@ -66,6 +66,12 @@ abstract class AbstractEarningsMetric extends AbstractMetric
];
}
$must[] = [
'exists' => [
'field' => $this->aggField,
],
];
$query = [
'index' => 'minds-entitycentric-*',
'size' => 0,
......@@ -127,6 +133,12 @@ abstract class AbstractEarningsMetric extends AbstractMetric
];
}
$must[] = [
'exists' => [
'field' => $this->aggField,
],
];
// Do the query
$query = [
'index' => 'minds-entitycentric-*',
......
......@@ -14,7 +14,7 @@ class ReferralsEarningsMetric extends AbstractEarningsMetric
protected $id = 'earnings_referrals';
/** @var string */
protected $label = 'Referrals USD';
protected $label = 'Referrals';
/** @var string */
protected $description = "Total earnings for your active referrals. You earn $0.10 for every active referral. A referral must log in at least 3 of 7 days after registration to be credited.";
......
......@@ -14,7 +14,7 @@ class SalesEarningsMetric extends AbstractEarningsMetric
protected $id = 'earnings_sales';
/** @var string */
protected $label = 'Sales USD';
protected $label = 'Sales';
/** @var string */
protected $description = "Total earnings for the sales you have referred. You earn a 25% commission when your referrals purchase Plus, Pro or Minds Tokens.";
......
......@@ -14,7 +14,7 @@ class ViewsEarningsMetric extends AbstractEarningsMetric
protected $id = 'earnings_views';
/** @var string */
protected $label = 'Pageviews USD';
protected $label = 'Pageviews';
/** @var string */
protected $description = "Total earnings for the pageviews on your channel's assets. You earn $1 for every 1,000 pageviews.";
......
<?php
namespace Minds\Core\Analytics\Dashboards\Metrics\Engagement;
use Minds\Core\Di\Di;
use Minds\Core\Session;
use Minds\Core\Data\ElasticSearch;
use Minds\Core\Analytics\Dashboards\Metrics\AbstractMetric;
use Minds\Core\Analytics\Dashboards\Metrics\MetricSummary;
use Minds\Core\Analytics\Dashboards\Metrics\Visualisations;
abstract class AbstractEngagementMetric extends AbstractMetric
{
/** @var Elasticsearch\Client */
private $es;
/** @var string */
protected $id = '';
/** @var string */
protected $label = '';
/** @var string */
protected $description = '';
/** @var array */
protected $permissions = [ 'user', 'admin' ];
/** @var string */
protected $unit = 'number';
/** @var string */
protected $aggField = '';
public function __construct($es = null)
{
$this->es = $es ?? Di::_()->get('Database\ElasticSearch');
}
/**
* Build the metrics
* @return self
*/
public function buildSummary(): self
{
$timespan = $this->timespansCollection->getSelected();
$filters = $this->filtersCollection->getSelected();
$comparisonTsMs = strtotime("midnight -{$timespan->getComparisonInterval()} days", $timespan->getFromTsMs() / 1000) * 1000;
$currentTsMs = $timespan->getFromTsMs();
$values = [];
foreach ([ 'value' => $currentTsMs, 'comparison' => $comparisonTsMs ] as $key => $tsMs) {
$must = [];
$maxTs = strtotime("midnight tomorrow +{$timespan->getComparisonInterval()} days", $tsMs / 1000);
$must[]['range'] = [
'@timestamp' => [
'gte' => $tsMs,
'lt' => $maxTs * 1000,
],
];
if ($userGuid = $this->getUserGuid()) {
$must[] = [
'term' => [
'owner_guid' => $userGuid,
],
];
}
$must[] = [
'exists' => [
'field' => $this->aggField,
],
];
$indexes = implode(',', [
'minds-entitycentric-' . date('m-Y', $tsMs / 1000),
'minds-entitycentric-' . date('m-Y', $maxTs),
]);
$query = [
'index' => 'minds-entitycentric-*',
'size' => 0,
'body' => [
'query' => [
'bool' => [
'must' => $must,
],
],
'aggs' => [
'1' => [
'sum' => [
'field' => $this->aggField,
],
],
],
],
];
// Query elasticsearch
$prepared = new ElasticSearch\Prepared\Search();
$prepared->query($query);
$response = $this->es->request($prepared);
$values[$key] = $response['aggregations']['1']['value'];
}
$this->summary = new MetricSummary();
$this->summary
->setValue($values['value'])
->setComparisonValue($values['comparison'])
->setComparisonInterval($timespan->getComparisonInterval())
->setComparisonPositivity(true);
return $this;
}
/**
* Build a visualisation for the metric
* @return self
*/
public function buildVisualisation(): self
{
$timespan = $this->timespansCollection->getSelected();
$filters = $this->filtersCollection->getSelected();
$must = [];
// Range must be from previous period
$must[]['range'] = [
'@timestamp' => [
'gte' => $timespan->getFromTsMs(),
],
];
if ($userGuid = $this->getUserGuid()) {
$must[] = [
'term' => [
'owner_guid' => $userGuid,
],
];
}
$must[] = [
'exists' => [
'field' => $this->aggField,
],
];
// Do the query
$query = [
'index' => 'minds-entitycentric-*',
'size' => 0,
'body' => [
'query' => [
'bool' => [
'must' => $must,
],
],
'aggs' => [
'1' => [
'date_histogram' => [
'field' => '@timestamp',
'interval' => $timespan->getInterval(),
'min_doc_count' => 0,
'extended_bounds' => [
'min' => $timespan->getFromTsMs(),
'max' => time() * 1000,
],
],
'aggs' => [
'2' => [
'sum' => [
'field' => $this->aggField,
],
],
],
],
],
],
];
// Query elasticsearch
$prepared = new ElasticSearch\Prepared\Search();
$prepared->query($query);
$response = $this->es->request($prepared);
$buckets = [];
foreach ($response['aggregations']['1']['buckets'] as $bucket) {
$date = date(Visualisations\ChartVisualisation::DATE_FORMAT, $bucket['key'] / 1000);
$buckets[] = [
'key' => $bucket['key'],
'date' => date('c', $bucket['key'] / 1000),
'value' => $bucket['2']['value']
];
}
$this->visualisation = (new Visualisations\ChartVisualisation())
->setXLabel('Date')
->setYLabel('Count')
->setBuckets($buckets);
return $this;
}
}
<?php
namespace Minds\Core\Analytics\Dashboards\Metrics\Engagement;
use Minds\Core\Di\Di;
use Minds\Core\Session;
use Minds\Core\Data\ElasticSearch;
use Minds\Core\Analytics\Dashboards\Metrics\AbstractMetric;
use Minds\Core\Analytics\Dashboards\Metrics\MetricSummary;
use Minds\Core\Analytics\Dashboards\Metrics\Visualisations;
class CommentsMetric extends AbstractEngagementMetric
{
/** @var string */
protected $id = 'comments';
/** @var string */
protected $label = 'Comments';
/** @var string */
protected $description = "Number of comments you have received on your content";
/** @var array */
protected $permissions = [ 'user', 'admin' ];
/** @var string */
protected $aggField = 'comment::total';
}
<?php
namespace Minds\Core\Analytics\Dashboards\Metrics\Engagement;
use Minds\Core\Di\Di;
use Minds\Core\Session;
use Minds\Core\Data\ElasticSearch;
use Minds\Core\Analytics\Dashboards\Metrics\AbstractMetric;
use Minds\Core\Analytics\Dashboards\Metrics\MetricSummary;
use Minds\Core\Analytics\Dashboards\Metrics\Visualisations;
class RemindsMetric extends AbstractEngagementMetric
{
/** @var string */
protected $id = 'reminds';
/** @var string */
protected $label = 'Reminds';
/** @var string */
protected $description = "Number of reminds you have received on your content";
/** @var array */
protected $permissions = [ 'user', 'admin' ];
/** @var string */
protected $aggField = 'remind::total';
}
<?php
namespace Minds\Core\Analytics\Dashboards\Metrics\Engagement;
use Minds\Core\Di\Di;
use Minds\Core\Session;
use Minds\Core\Data\ElasticSearch;
use Minds\Core\Analytics\Dashboards\Metrics\AbstractMetric;
use Minds\Core\Analytics\Dashboards\Metrics\MetricSummary;
use Minds\Core\Analytics\Dashboards\Metrics\Visualisations;
class SubscribersMetric extends AbstractEngagementMetric
{
/** @var string */
protected $id = 'subscribers';
/** @var string */
protected $label = 'Subscribers';
/** @var string */
protected $description = "Number of subscribers your channel has gained";
/** @var array */
protected $permissions = [ 'user', 'admin' ];
/** @var string */
protected $aggField = 'subscribe::total';
}
<?php
namespace Minds\Core\Analytics\Dashboards\Metrics\Engagement;
use Minds\Core\Di\Di;
use Minds\Core\Session;
use Minds\Core\Data\ElasticSearch;
use Minds\Core\Analytics\Dashboards\Metrics\AbstractMetric;
use Minds\Core\Analytics\Dashboards\Metrics\MetricSummary;
use Minds\Core\Analytics\Dashboards\Metrics\Visualisations;
class VotesUpMetric extends AbstractEngagementMetric
{
/** @var string */
protected $id = 'votes_up';
/** @var string */
protected $label = 'Votes up';
/** @var string */
protected $description = "Number of votes up you have received on your content";
/** @var array */
protected $permissions = [ 'user', 'admin' ];
/** @var string */
protected $aggField = 'vote:up::total';
}
......@@ -54,7 +54,7 @@ class SignupsMetric extends AbstractMetric
$must[]['range'] = [
'@timestamp' => [
'gte' => $tsMs,
'lte' => strtotime("midnight +{$timespan->getComparisonInterval()} days", $tsMs / 1000) * 1000,
'lt' => strtotime("midnight tomorrow +{$timespan->getComparisonInterval()} days", $tsMs / 1000) * 1000,
],
];
......
......@@ -151,7 +151,7 @@ class ViewsTableMetric extends AbstractMetric
->setColumns([
[
'id' => 'entity',
'label' => '',
'label' => 'Content',
'order' => 0,
],
[
......
<?php
/**
* Summary Dashboard
*/
namespace Minds\Core\Analytics\Dashboards;
use Minds\Entities\User;
use Minds\Traits\MagicAttributes;
/**
* @method TrafficDashboard setTimespanId(string $timespanId)
* @method TrafficDashboard setFilterIds(array $filtersIds)
* @method TrafficDashboard setUser(User $user)
*/
class SummaryDashboard implements DashboardInterface
{
use MagicAttributes;
/** @var string */
private $timespanId = '30d';
/** @var string[] */
private $filterIds = [ 'platform::browser' ];
/** @var string */
private $metricId = 'active_users';
/** @var Timespans\TimespansCollection */
private $timespansCollection;
/** @var Metrics\MetricsCollection */
private $metricsCollection;
/** @var Filters\FiltersCollection */
private $filtersCollection;
/** @var User */
private $user;
public function __construct(
$timespansCollection = null,
$metricsCollection = null,
$filtersCollection = null
) {
$this->timespansCollection = $timespansCollection ?? new Timespans\TimespansCollection();
$this->metricsCollection = $metricsCollection ?? new Metrics\MetricsCollection();
$this->filtersCollection = $filtersCollection ?? new Filters\FiltersCollection();
}
/**
* Build the dashboard
* @return self
*/
public function build(): self
{
$this->timespansCollection
->setSelectedId($this->timespanId)
->addTimespans(
new Timespans\TodayTimespan(),
new Timespans\_30dTimespan(),
new Timespans\_1yTimespan(),
new Timespans\MtdTimespan(),
new Timespans\YtdTimespan()
);
$this->filtersCollection
->setSelectedIds($this->filterIds)
->setUser($this->user)
->addFilters(
// new Filters\PlatformFilter(),
new Filters\ViewTypeFilter(),
new Filters\ChannelFilter()
);
$this->metricsCollection
->setTimespansCollection($this->timespansCollection)
->setFiltersCollection($this->filtersCollection)
->setSelectedId($this->metricId)
->setUser($this->user)
->addMetrics(
new Metrics\ActiveUsersMetric()
)
->build();
return $this;
}
/**
* Export
* @param array $extras
* @return array
*/
public function export(array $extras = []): array
{
$this->build();
return [
'category' => 'summary',
'label' => 'Summary',
'description' => null,
'timespan' => $this->timespansCollection->getSelected()->getId(),
'timespans' => $this->timespansCollection->export(),
'metric' => $this->metricsCollection->getSelected()->getId(),
'metrics' => $this->metricsCollection->export(),
'filter' => $this->filtersCollection->getSelectedIds(),
'filters' => $this->filtersCollection->export(),
];
}
}
......@@ -16,7 +16,7 @@ class MtdTimespan extends AbstractTimespan
protected $fromTsMs;
/** @var int */
protected $comparisonInterval = 28;
protected $comparisonInterval = 30;
public function __construct()
{
......
......@@ -16,7 +16,7 @@ class _30dTimespan extends AbstractTimespan
protected $fromTsMs;
/** @var int */
protected $comparisonInterval = 28;
protected $comparisonInterval = 30;
public function __construct()
{
......
<?php
namespace Minds\Core\Analytics\EntityCentric;
use Minds\Core\Data\ElasticSearch;
use Minds\Core\Di\Di;
use DateTime;
use Exception;
class EngagementSynchroniser
{
/** @var array */
private $records = [];
/** @var ElasticSearch\Client */
private $es;
public function __construct($es = null)
{
$this->es = $es ?? Di::_()->get('Database\ElasticSearch');
}
/**
* @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);
$i = 0;
foreach ($this->getEntitiesMetrics() as $buckets) {
$urn = null;
$ownerGuid = null;
if (!$buckets['type']['buckets'][0]['key'] && $buckets['metrics']['buckets'][0]['key'] === 'subscribe') {
$urn = "urn:user:{$buckets['key']}";
$ownerGuid = (string) $buckets['key'];
} elseif (!$buckets['type']['buckets'][0]['key']) {
echo "\nEngagement: skipping as no type";
continue;
} else {
$urn = "urn:{$buckets['type']['buckets'][0]['key']}:{$buckets['key']}";
$ownerGuid = (string) $buckets['owner']['buckets'][0]['key'];
if ($buckets['type']['buckets'][0]['key'] === 'object') {
$urn = "urn:{$buckets['subtype']['buckets'][0]['key']}:{$buckets['key']}";
}
}
$record = new EntityCentricRecord();
$record->setEntityUrn($urn)
->setOwnerGuid($ownerGuid)
->setTimestamp($this->from)
->setResolution('day');
foreach ($buckets['metrics']['buckets'] as $metrics) {
$record->incrementSum($metrics['key'] . '::total', (int) $metrics['doc_count']);
}
$this->records[] = $record;
++$i;
error_log("Engagement: $i");
}
foreach ($this->records as $record) {
yield $record;
}
}
private function getEntitiesMetrics()
{
$opts = array_merge([
'fields' => [],
'from' => time(),
], []);
$must = [];
// $must[] = [
// 'term' => [
// 'action.keyword' => 'subscribe',
// ],
//];
$must[] = [
'range' => [
'@timestamp' => [
'gte' => $this->from * 1000,
'lt' => strtotime('+1 day', $this->from) * 1000,
],
],
];
$partition = 0;
$partitions = 50;
$partitionSize = 5000; // Allows for 250,000 entities
$index = 'minds-metrics-' . date('m-Y', $this->from);
while (++$partition < $partitions) {
// Do the query
$query = [
'index' => $index,
'size' => 0,
'body' => [
'query' => [
'bool' => [
'must' => $must,
],
],
'aggs' => [
'1' => [
'terms' => [
'field' => 'entity_guid.keyword',
'min_doc_count' => 1,
'size' => $partitionSize,
'include' => [
'partition' => $partition,
'num_partitions' => $partitions,
],
],
'aggs' => [
'metrics' => [
'terms' => [
'field' => 'action.keyword',
'min_doc_count' => 1,
],
],
'owner' => [
'terms' => [
'field' => 'entity_owner_guid.keyword',
'min_doc_count' => 1,
],
],
'type' => [
'terms' => [
'field' => 'entity_type.keyword',
],
],
'subtype' => [
'terms' => [
'field' => 'entity_subtype.keyword',
]
],
],
],
],
],
];
// Query elasticsearch
$prepared = new ElasticSearch\Prepared\Search();
$prepared->query($query);
$response = $this->es->request($prepared);
foreach ($response['aggregations']['1']['buckets'] as $bucket) {
yield $bucket;
}
}
}
}
......@@ -13,6 +13,7 @@ class Manager
{
/** @var array */
const SYNCHRONISERS = [
EngagementSynchroniser::class,
PartnerEarningsSynchroniser::class,
SignupsSynchroniser::class,
ActiveUsersSynchroniser::class,
......
......@@ -74,11 +74,11 @@ class TokenSaleEvent implements BlockchainEventInterface
$purchase = $this->manager->getPurchase($transaction->getData()['phone_number_hash'], $transaction->getTx());
if (!$purchase) {
echo "purchase not found";
error_log("purchase not found");
return; //purchase not found
}
var_dump($log);
error_log(print_r($log, true));
//is the requested amount below what has already been recorded
if ($transaction->getAmount() > $purchase->getUnissuedAmount()) {
return; //requested more than can issue
......
......@@ -96,7 +96,6 @@ class WithdrawEvent implements BlockchainEventInterface
try {
$this->manager->complete($request, $transaction);
} catch (\Exception $e) {
var_dump($e);
error_log(print_r($e, true));
}
}
......
......@@ -85,11 +85,13 @@ class Pending
public function delete($type, $tx_id)
{
$query = new Core\Data\Cassandra\Prepared\Custom();
$query->query("DELETE FROM blockchain_pending WHERE type = ? AND tx_id = ?",
$query->query(
"DELETE FROM blockchain_pending WHERE type = ? AND tx_id = ?",
[
(string) $type,
(string) $tx_id
]);
]
);
try {
return (bool) $this->db->request($query);
......
......@@ -46,14 +46,16 @@ class Sums
$query = new Custom();
if ($this->user) {
$query->query("SELECT
$query->query(
"SELECT
SUM(amount) as balance
FROM blockchain_transactions_mainnet_by_address
WHERE user_guid = ?
AND wallet_address = 'offchain'",
[
new Varint((int) $this->user->guid)
]);
]
);
$query->setOpts([
'consistency' => \Cassandra::CONSISTENCY_ALL
]);
......
......@@ -49,14 +49,16 @@ class TestnetSums
throw new \Exception('User is not set');
}
$query->query("SELECT
$query->query(
"SELECT
SUM(amount) as balance
FROM blockchain_transactions_by_address
WHERE user_guid = ?
AND wallet_address = 'offchain'",
[
new Varint((int) $this->user->guid)
]);
]
);
$query->setOpts([
'consistency' => \Cassandra::CONSISTENCY_ALL
]);
......
......@@ -47,7 +47,8 @@ class Navigation
->setVisibility(0); //only show for loggedin
$link = new Item();
NavigationManager::add($link
NavigationManager::add(
$link
->setPriority(4)
->setIcon('subject')
->setName('Blogs')
......
......@@ -244,8 +244,10 @@ class Iterator implements \Iterator
foreach ($boosts as $boost) {
$owner_guids[] = $boost->owner_guid;
}
$blocked = array_flip(Core\Security\ACL\Block::_()->isBlocked($owner_guids,
Core\Session::getLoggedInUserGuid()));
$blocked = array_flip(Core\Security\ACL\Block::_()->isBlocked(
$owner_guids,
Core\Session::getLoggedInUserGuid()
));
foreach ($boosts as $i => $boost) {
if (isset($blocked[$boost->owner_guid])) {
......
......@@ -97,10 +97,12 @@ class Repository
return $this;
}
foreach ($this->categories as $category) {
$query->query("INSERT INTO categories
$query->query(
"INSERT INTO categories
(type, category, filter, guid)
VALUES (?, ?, ?, ?)",
[ $this->type, $category, $this->filter, (string) $guid ]);
[ $this->type, $category, $this->filter, (string) $guid ]
);
try {
$result = $this->db->request($query);
} catch (\Exception $e) {
......@@ -116,9 +118,11 @@ class Repository
return $this;
}
foreach ($this->categories as $category) {
$query->query("DELETE FROM categories
$query->query(
"DELETE FROM categories
WHERE type = ? AND category = ? AND filter = ? AND guid = ?",
[ $this->type, $category, $this->filter, (string) $guid ]);
[ $this->type, $category, $this->filter, (string) $guid ]
);
try {
$result = $this->db->request($query);
} catch (\Exception $e) {
......
<?php
/**
* @author: eiennohi.
*/
namespace Minds\Core\Channels\Delegates;
use Minds\Core\Analytics\Metrics\Event;
use Minds\Entities\User;
class MetricsDelegate
{
public function onDelete(User $user)
{
$event = new Event();
$event->setType('action')
->setAction('delete')
->setProduct('platform')
->setUserGuid((string) $user->guid)
->setUserPhoneNumberHash($user->getPhoneNumberHash())
->push();
}
}
......@@ -5,6 +5,7 @@
namespace Minds\Core\Channels;
use Minds\Core\Channels\Delegates\MetricsDelegate;
use Minds\Core\Di\Di;
use Minds\Core\Queue\Interfaces\QueueClient;
use Minds\Entities\User;
......@@ -30,6 +31,9 @@ class Manager
/** @var Delegates\Artifacts\Factory */
protected $artifactsDelegatesFactory;
/** @var MetricsDelegate */
protected $metricsDelegate;
/** @var Delegates\Logout */
protected $logoutDelegate;
......@@ -44,10 +48,12 @@ class Manager
*/
public function __construct(
$artifactsDelegatesFactory = null,
$metricsDelegate = null,
$logoutDelegate = null,
$queueClient = null
) {
$this->artifactsDelegatesFactory = $artifactsDelegatesFactory ?: new Delegates\Artifacts\Factory();
$this->metricsDelegate = $metricsDelegate ?: new MetricsDelegate();
$this->logoutDelegate = $logoutDelegate ?: new Delegates\Logout();
$this->queueClient = $queueClient ?: Di::_()->get('Queue');
}
......@@ -139,6 +145,7 @@ class Manager
}
}
$this->metricsDelegate->onDelete($this->user);
$this->logoutDelegate->logout($this->user);
return true;
......
......@@ -9,6 +9,7 @@ use Minds\Entities\RepositoryEntity;
use Minds\Entities\User;
use Minds\Helpers\Flags;
use Minds\Helpers\Unknown;
use Minds\Helpers\Export;
use Minds\Core\Di\Di;
/**
......@@ -406,6 +407,8 @@ class Comment extends RepositoryEntity
//$output['parent_guid'] = (string) $this->entityGuid;
$output = Export::sanitize($output);
return $output;
}
}
......@@ -161,13 +161,15 @@ class Call
array_push(self::$keys, $key);
$options = array_merge(
[
[
'multi' => false,
'offset' => "",
'finish' => "",
'limit' => 500,
'reversed' => true
], $options);
],
$options
);
$query = new Cassandra\Prepared\Custom();
......
......@@ -41,13 +41,13 @@ class Client implements Interfaces\ClientInterface
try {
$statement = $this->session->prepare($cql['string']);
$future = $this->session->executeAsync(
$statement,
@new Driver\ExecutionOptions(array_merge(
[
$statement,
@new Driver\ExecutionOptions(array_merge(
[
'arguments' => $cql['values']
],
$request->getOpts()
))
$request->getOpts()
))
);
if ($silent) {
return $future;
......
......@@ -75,14 +75,16 @@ class DataProvider extends Provider
$sslmode = isset($config['sslmode']) ? $config['sslmode'] : 'disable';
$username = isset($config['username']) ? $config['username'] : 'php';
// This is a generic data object using the postgres driver to connect to cockroachdb.
return new PDO("pgsql:host=$host;port=$port;dbname=$name;sslmode=$sslmode",
return new PDO(
"pgsql:host=$host;port=$port;dbname=$name;sslmode=$sslmode",
$username,
null,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => true,
PDO::ATTR_PERSISTENT => isset($config['persistent']) ? $config['persistent'] : false,
]);
]
);
}, ['useFactory'=>true]);
/**
* Locks
......
......@@ -11,13 +11,15 @@ class Client
public function __construct($dbh = null)
{
$this->dbh = $dbh ?: new PDO('pgsql:host=cockroachdb;port=26257;dbname=minds;sslmode=disable',
$this->dbh = $dbh ?: new PDO(
'pgsql:host=cockroachdb;port=26257;dbname=minds;sslmode=disable',
'maxroach',
null,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => true,
]);
]
);
}
/**
......
......@@ -72,8 +72,10 @@ class EndFacebookSupport
foreach ($this->getUsers() as $user) {
if (!$user instanceof \Minds\Entities\User || !$user->guid || $user->disabled_emails || $user->enabled != "yes") {
$skipped++;
echo "\r [emails]: $queued queued | $skipped skipped | " . date('d-m-Y',
$user->time_created) . " | $user->guid ";
echo "\r [emails]: $queued queued | $skipped skipped | " . date(
'd-m-Y',
$user->time_created
) . " | $user->guid ";
continue;
}
$queued++;
......@@ -95,8 +97,10 @@ class EndFacebookSupport
if (!$this->dryRun) {
$this->mailer->queue($message);
}
echo "\r [emails]: $queued queued | $skipped skipped | " . date('d-m-Y',
$user->time_created) . " | $user->guid ";
echo "\r [emails]: $queued queued | $skipped skipped | " . date(
'd-m-Y',
$user->time_created
) . " | $user->guid ";
}
echo "[emails]: Completed ($queued queued | $skipped skipped) \n";
}
......
......@@ -59,8 +59,10 @@ class GlobalTips extends EmailCampaign
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]
))
->setSubject($subject)
->setHtml($this->template);
......
......@@ -70,8 +70,10 @@ class InactiveUsers extends EmailCampaign
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]
))
->setSubject($this->subject)
->setHtml($this->template);
......
......@@ -65,8 +65,10 @@ class Invoice
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1('invoice' . time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1('invoice' . time())]
))
->setSubject($subject)
->setHtml($this->template);
......
......@@ -76,8 +76,10 @@ class MissedSinceLogin extends EmailCampaign
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]
))
->setSubject($this->subject)
->setHtml($this->template);
......
......@@ -73,8 +73,10 @@ class News extends EmailCampaign
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]
))
->setSubject($this->subject)
->setHtml($this->template);
......
......@@ -70,8 +70,10 @@ class Promotion extends EmailCampaign
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]
))
->setSubject($this->subject)
->setHtml($this->template);
......
......@@ -62,8 +62,10 @@ class GoneCold extends EmailCampaign
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign.$this->topic.time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign.$this->topic.time())]
))
->setSubject($subject)
->setHtml($this->template);
......
......@@ -62,8 +62,10 @@ class WelcomeComplete extends EmailCampaign
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign.$this->topic.time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign.$this->topic.time())]
))
->setSubject($subject)
->setHtml($this->template);
......
......@@ -62,8 +62,10 @@ class WelcomeIncomplete extends EmailCampaign
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign.$this->topic.time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign.$this->topic.time())]
))
->setSubject($subject)
->setHtml($this->template);
......
......@@ -60,8 +60,10 @@ class WhenBoost extends EmailCampaign
$subject = 'Your boost is complete';
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign.$this->topic.time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign.$this->topic.time())]
))
->setSubject($subject)
->setHtml($this->template);
......
......@@ -49,8 +49,10 @@ class WhenNotifications extends EmailCampaign
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign.$this->topic.time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign.$this->topic.time())]
))
->setSubject($subject)
->setHtml($this->template);
......
......@@ -75,8 +75,10 @@ class WhenWire extends EmailCampaign
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]
))
->setSubject($this->subject)
->setHtml($this->template);
......
......@@ -118,8 +118,10 @@ class WirePayment
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->template . time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->template . time())]
))
->setSubject($subject)
->setHtml($this->template);
......
......@@ -75,8 +75,10 @@ class WirePromotions extends EmailCampaign
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]
))
->setSubject($this->subject)
->setHtml($this->template);
......
......@@ -58,8 +58,10 @@ class WithActivity extends EmailCampaign
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]
))
->setSubject($subject)
->setHtml($this->template);
......
......@@ -72,8 +72,10 @@ class WithBlogs extends EmailCampaign
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]
))
->setSubject($subject)
->setHtml($this->template);
......
......@@ -50,8 +50,10 @@ class WithChannelTips extends EmailCampaign
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]
))
->setSubject($subject)
->setHtml($this->template);
......
......@@ -39,8 +39,10 @@ class WithImprovementTips extends EmailCampaign
$message = new Message();
$message->setTo($this->user)
->setMessageId(implode('-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]))
->setMessageId(implode(
'-',
[$this->user->guid, sha1($this->user->getEmail()), sha1($this->campaign . $this->topic . time())]
))
->setSubject($subject)
->setHtml($this->template);
......
......@@ -3,6 +3,12 @@ namespace Minds\Core\Email;
use Minds\Traits\MagicAttributes;
/**
* Class EmailSubscription
* @package Minds\Core\Email
*
* @method string getUserGuid()
*/
class EmailSubscription
{
use MagicAttributes;
......
......@@ -38,10 +38,14 @@ class Manager
$result = $this->repository->getList($options);
if (!$result || count($result['data'] === 0)) {
if (!$result || count($result['data']) === 0) {
return [];
}
/*$guids = [];
foreach($result['data'] as $subscription) {
$guids[] = $subscription->getUserGuid();
}*/
$guids = array_map(function ($item) {
return $item->getUserGuid();
}, $result['data']);
......
......@@ -79,8 +79,8 @@ class Manager
public function save(
$entity,
User $moderator,
int $time = null)
{
int $time = null
) {
if (!$time) {
$time = time();
}
......@@ -92,8 +92,8 @@ class Manager
private function saveEntity(
$entity,
User $moderator,
int $time = null)
{
int $time = null
) {
$entity->setModeratorGuid($moderator->getGUID());
$entity->setTimeModerated($time);
......
......@@ -28,6 +28,7 @@ class Repository
$opts = array_merge([
'container_guid' => null,
'type' => null,
'owner_guid' => null,
], $opts);
if (!$opts['type']) {
......@@ -64,6 +65,16 @@ class Repository
]
];
if ($opts['owner_guid']) {
$ownerGuids = Text::buildArray($opts['owner_guid']);
$query['body']['query']['bool']['must'][] = [
'terms' => [
'owner_guid' => $ownerGuids,
],
];
}
$prepared = new Prepared\Count();
$prepared->query($query);
......
......@@ -34,7 +34,8 @@ class Entities
* @param ACL $acl
*/
public function __construct(
$entitiesBuilder = null, $acl = null
$entitiesBuilder = null,
$acl = null
) {
$this->entitiesBuilder = $entitiesBuilder ?: Di::_()->get('EntitiesBuilder');
$this->acl = $acl ?: ACL::_();
......
......@@ -42,7 +42,6 @@ class Notifications
$cql = null,
$notifications = null,
$notificationBatches = null
) {
$this->relDB = $relDb ?: Di::_()->get('Database\Cassandra\Relationships');
$this->indexDb = $indexDb ?: Di::_()->get('Database\Cassandra\Indexes');
......
......@@ -27,7 +27,10 @@ class CurlWrapper
curl_setopt($this->handle, CURLOPT_BUFFERSIZE, 128);
curl_setopt($this->handle, CURLOPT_NOPROGRESS, false);
curl_setopt($this->handle, CURLOPT_PROGRESSFUNCTION, function (
$downloadSize, $downloaded, $uploadSize, $uploaded
$downloadSize,
$downloaded,
$uploadSize,
$uploaded
) use ($limitKb) {
error_log($downloaded);
if ($downloaded) {
......
......@@ -20,7 +20,7 @@ class Image implements AssetsInterface
public function upload(array $media, array $data)
{
$filename = "/image/{$this->entity->batch_guid}/{$this->entity->guid}/master.jpg";
$filename = "image/{$this->entity->batch_guid}/{$this->entity->guid}/master.jpg";
// @note: legacy file handling
$file = new \ElggFile();
......
......@@ -128,8 +128,12 @@ class Resize
$params = $this->getResizeParameters();
// First crop the image
$this->image->cropImage($params['selectionwidth'], $params['selectionheight'], $params['xoffset'],
$params['yoffset']);
$this->image->cropImage(
$params['selectionwidth'],
$params['selectionheight'],
$params['xoffset'],
$params['yoffset']
);
// If selected with / height differ from selection width/height, then we need to resize
if ($params['selectionwidth'] !== $params['newwidth'] || $params['selectionheight'] !== $params['newheight']) {
......
......@@ -9,6 +9,7 @@
namespace Minds\Core\Media\Proxy;
use Minds\Core\Di\Di;
use Minds\Helpers\File;
use Minds\Core\Http\Curl\Client;
use Minds\Traits\MagicAttributes;
......@@ -99,8 +100,7 @@ class Download
throw new \Exception('Invalid image');
}
$finfo = new \finfo(FILEINFO_MIME);
$mime = $finfo->buffer($content);
$mime = File::getMime($content);
if (!$mime) {
throw new \Exception('Cannot read image MIME');
......
......@@ -34,21 +34,26 @@ class SEO
$type = ucfirst($slugs[0]);
switch ($slugs[1]) {
case 'top':
return $this->getInfo("Top $type",
return $this->getInfo(
"Top $type",
"$type from channels I'm subscribed to",
Core\Di\Di::_()->get('Config')->site_url . implode('/', $slugs));
Core\Di\Di::_()->get('Config')->site_url . implode('/', $slugs)
);
break;
case 'network':
return $this->getInfo("$type from your Network",
return $this->getInfo(
"$type from your Network",
"$type from channels you're subscribed to",
Core\Di\Di::_()->get('Config')->site_url . implode('/', $slugs));
Core\Di\Di::_()->get('Config')->site_url . implode('/', $slugs)
);
break;
case 'my':
return $this->getInfo(
"Your $type",
"List of your $type",
Core\Di\Di::_()->get('Config')->site_url . implode('/', $slugs));
Core\Di\Di::_()->get('Config')->site_url . implode('/', $slugs)
);
break;
}
}
......
......@@ -54,6 +54,7 @@ class FFMpeg implements ServiceInterface
'ffmpeg.binaries' => '/usr/bin/ffmpeg',
'ffprobe.binaries' => '/usr/bin/ffprobe',
'ffmpeg.threads' => $this->config->get('transcoder')['threads'],
'timeout' => 0,
]);
$this->ffprobe = $ffprobe ?: FFProbeClient::create([
'ffprobe.binaries' => '/usr/bin/ffprobe',
......@@ -237,8 +238,10 @@ class FFMpeg implements ServiceInterface
}
$video->filters()
->resize(new \FFMpeg\Coordinate\Dimension($opts['width'], $opts['height']),
$rotated ? ResizeFilter::RESIZEMODE_FIT : ResizeFilter::RESIZEMODE_SCALE_WIDTH)
->resize(
new \FFMpeg\Coordinate\Dimension($opts['width'], $opts['height']),
$rotated ? ResizeFilter::RESIZEMODE_FIT : ResizeFilter::RESIZEMODE_SCALE_WIDTH
)
->synchronize();
$formatMap = [
......@@ -251,19 +254,25 @@ class FFMpeg implements ServiceInterface
$pfx = ($rotated ? $opts['width'] : $opts['height']).'.'.$format;
$path = $sourcePath.'-'.$pfx;
try {
echo "\nTranscoding: $path ($this->key)";
echo "\nTranscoding: $path ($this->key)\n";
$formatMap[$format]->on('progress', function ($a, $b, $pct) {
echo "\r$pct% transcoded";
// also emit out to cassandra so frontend can keep track
});
$formatMap[$format]
->setKiloBitRate($opts['bitrate'])
->setAudioChannels(2)
// ->setAudioChannels(2)
->setAudioKiloBitrate($opts['audio_bitrate']);
$video->save($formatMap[$format], $path);
//now upload to s3
$this->uploadTranscodedFile($path, $pfx);
//cleanup tmp file
@unlink($path);
} catch (\Exception $e) {
echo " failed {$e->getMessage()}";
//cleanup tmp file
@unlink($path);
}
}
}
......
......@@ -116,7 +116,10 @@ class Ads
$dateRange = $payouts->getPayoutDateRange();
$list = $dateRange ? $this->getList(
$dateRange['start'], $dateRange['end'], $offset, $count
$dateRange['start'],
$dateRange['end'],
$offset,
$count
) : [];
return [
......
......@@ -101,14 +101,16 @@ class Repository
public function add(EarningsDeposit $deposit): bool
{
$prepared = new Prepared();
$prepared->query("INSERT INTO partner_earnings_ledger (user_guid, timestamp, item, amount_cents, amount_tokens) VALUES (?,?,?,?,?)",
$prepared->query(
"INSERT INTO partner_earnings_ledger (user_guid, timestamp, item, amount_cents, amount_tokens) VALUES (?,?,?,?,?)",
[
new Bigint($deposit->getUserGuid()),
new Timestamp($deposit->getTimestamp()),
$deposit->getItem(),
$deposit->getAmountCents() ? (int) $deposit->getAmountCents() : null,
$deposit->getAmountTokens() ? new Bigint($deposit->getAmountTokens()) : null,
]);
]
);
return (bool) $this->db->request($prepared);
}
......
......@@ -63,70 +63,80 @@ class Manager
->setTitle('Admin')
->setPath('admin/analytics')
->setVisibility(-1)
->addSubItem((new Item())
->addSubItem(
(new Item())
->setPriority(1)
->setIcon('trending_up')
->setName('Boost')
->setTitle('Boost (Admin)')
->setPath('admin/boosts')
)
->addSubItem((new Item())
->addSubItem(
(new Item())
->setPriority(2)
->setIcon('insert_chart')
->setName('Analytics')
->setTitle('Analytics')
->setPath('admin/analytics')
)
->addSubItem((new Item())
->addSubItem(
(new Item())
->setPriority(3)
->setIcon('create')
->setName('Pages')
->setTitle('Pages')
->setPath('admin/pages')
)
->addSubItem((new Item())
->addSubItem(
(new Item())
->setPriority(4)
->setIcon('flag')
->setName('Reports')
->setTitle('Reports')
->setPath('admin/reports')
)
->addSubItem((new Item())
->addSubItem(
(new Item())
->setPriority(5)
->setIcon('attach_money')
->setName('Monetization review')
->setTitle('Monetization review')
->setPath('admin/monetization')
)
->addSubItem((new Item())
->addSubItem(
(new Item())
->setPriority(6)
->setIcon('queue')
->setName('Program applications')
->setTitle('Program applications')
->setPath('admin/programs')
)
->addSubItem((new Item())
->addSubItem(
(new Item())
->setPriority(7)
->setIcon('branding_watermark')
->setName('Payouts queue')
->setTitle('Payouts queue')
->setPath('admin/payouts')
)
->addSubItem((new Item())
->addSubItem(
(new Item())
->setPriority(8)
->setIcon('star')
->setName('Featured')
->setTitle('Featured')
->setPath('admin/featured')
)
->addSubItem((new Item())
->addSubItem(
(new Item())
->setPriority(9)
->setIcon('whatshot')
->setName('Hashtags')
->setTitle('Hashtags')
->setPath('admin/tagcloud')
)
->addSubItem((new Item())
->addSubItem(
(new Item())
->setPriority(10)
->setIcon('verified_user')
->setName('Verfiy')
......
......@@ -157,6 +157,7 @@ class Push implements Interfaces\NotificationExtensionInterface
if (!empty($entity->custom_data)) {
return $entity->custom_data[0]['src'];
}
// no break
default:
return null;
......
This diff is collapsed.
<?php
/**
* Braintree webhooks
*/
namespace Minds\Core\Payments\Braintree;
use Minds\Core;
use Minds\Core\Guid;
use Minds\Core\Payments;
use Minds\Entities;
use Minds\Helpers\Wallet as WalletHelper;
use Minds\Core\Di\Di;
use Minds\Core\Blockchain\Transactions\Transaction;
use Braintree_ClientToken;
use Braintree_Configuration;
use Braintree_MerchantAccount;
use Braintree_Transaction;
use Braintree_TransactionSearch;
use Braintree_Customer;
use Braintree_CustomerSearch;
use Braintree_PaymentMethod;
use Braintree_Subscription;
use Braintree_Test_MerchantAccount;
use Braintree_WebhookNotification;
use Minds\Core\Payments\Subscriptions\Subscription;
class Webhooks
{
protected $payload;
protected $signature;
protected $notification;
protected $aliases = [
Braintree_WebhookNotification::SUB_MERCHANT_ACCOUNT_APPROVED => 'subMerchantApproved',
Braintree_WebhookNotification::SUB_MERCHANT_ACCOUNT_DECLINED => 'subMerchantDeclined',
'subscription_charged_successfully' => 'subscriptionCharged',
'subscription_went_active' => 'subscriptionActive',
Braintree_WebhookNotification::SUBSCRIPTION_EXPIRED => 'subscriptionExpired',
Braintree_WebhookNotification::SUBSCRIPTION_WENT_PAST_DUE => 'subscriptionOverdue',
Braintree_WebhookNotification::SUBSCRIPTION_CANCELED => 'subscriptionCanceled',
'check' => 'check'
];
protected $hooks;
public function __construct($hooks = null, $braintree = null)
{
$this->hooks = $hooks ?: new Payments\Hooks();
$this->braintree = $braintree;
}
/**
* Set the request payload
* @param string $payload
* @return $this
*/
public function setPayload($payload)
{
$this->payload = $payload;
return $this;
}
/**
* Set the request signature
* @param string $signature
* @return $this
*/
public function setSignature($signature)
{
$this->signature = $signature;
return $this;
}
/**
* Run the notification hook
* @return $this
*/
public function run()
{
$this->buildNotification();
$this->routeAlias();
return $this;
}
protected function buildNotification()
{
$this->notification = Braintree_WebhookNotification::parse($this->signature, $this->payload);
}
protected function routeAlias()
{
if (method_exists($this, $this->aliases[$this->notification->kind])) {
$method = $this->aliases[$this->notification->kind];
$this->$method();
}
}
/**
* @return void
*/
protected function subMerchantApproved()
{
$message = "Congrats, you are now a Minds Merchant";
Core\Events\Dispatcher::trigger('notification', 'elgg/hook/activity', [
'to'=>[$notification->merchantAccount->id],
'from' => 100000000000000519,
'notification_view' => 'custom_message',
'params' => ['message'=>$message],
'message'=>$message
]);
}
/**
* @return void
*/
protected function subMerchantDeclined()
{
$reason = $notification->message;
$message = "Sorry, we could not approve your Merchant Account: $reason";
Core\Events\Dispatcher::trigger('notification', 'elgg/hook/activity', [
'to'=>[$notification->merchantAccount->id],
'from' => 100000000000000519,
'notification_view' => 'custom_message',
'params' => ['message'=>$message],
'message'=>$message
]);
}
/**
* @return void
*/
protected function subscriptionCharged()
{
$subscription = (new Subscription())
->setId($this->notification->subscription->id)
->setBalance($this->notification->subscription->balance)
->setPrice($this->notification->subscription->price);
$db = new Core\Data\Call('user_index_to_guid');
//find the customer
$user_guids = $db->getRow("subscription:" . $subscription->getId());
$user = Entities\Factory::build($user_guids[0]);
//WalletHelper::createTransaction($user->guid, ($subscription->getPrice() * 1000) * 1.1, null, "Purchase (Recurring)");
//$this->hooks->onCharged($subscription);
$transaction = new Transaction();
$transaction
->setUserGuid($user->guid)
->setWalletAddress('offchain')
->setTimestamp(time())
->setTx('cc:bt-' . Guid::build())
->setAmount(($subscription->getPrice()) * 1.1 * 10 ** 18)
->setContract('offchain:points')
->setCompleted(true);
Di::_()->get('Blockchain\Transactions\Repository')
->add($transaction);
}
/**
* @return void
*/
protected function subscriptionActive()
{
$subscription = (new Subscription())
->setId($this->notification->subscription->id)
->setBalance($this->notification->subscription->balance)
->setPrice($this->notification->subscription->price);
$this->hooks->onActive($subscription);
}
/**
* @return void
*/
protected function subscriptionExpired()
{
$subscription = (new Subscription())
->setId($this->notification->subscription->id);
$this->hooks->onExpired($subscription);
}
/**
* @return void
*/
protected function subscriprionOverdue()
{
$subscription = (new Subscription())
->setId($this->notification->subscription->id);
$this->hooks->onOverdue($subscription);
}
/**
* @return void
*/
protected function subscriptionCanceled()
{
$subscription = (new Subscription())
->setId($this->notification->subscription->id);
$this->hooks->onCanceled($subscription);
}
/**
* @return void
*/
protected function check()
{
error_log("[webook]:: check is OK!");
}
}
<?php
/**
* Payments Factory
*/
namespace Minds\Core\Payments;
use Minds\Core\Di\Di;
/**
* A factory providing handlers boosting items
*/
class Factory
{
/**
* Build the handler
* @param string $handler
* @param array $options (optional)
* @return BoostHandlerInterface
*/
public static function build($handler, $opts = [])
{
switch (ucfirst($handler)) {
case "Braintree":
return Di::_()->get('BraintreePayments')->setConfig($opts);
default:
throw new \Exception("Service not found");
}
......
......@@ -9,12 +9,6 @@ use Minds\Core;
use Minds\Core\Data;
use Minds\Core\Di\Provider;
use Braintree_ClientToken;
use Braintree_Configuration;
use Braintree_Transaction;
use Braintree_TransactionSearch;
use Braintree_MerchantAccount;
class PaymentsProvider extends Provider
{
public function register()
......@@ -27,33 +21,15 @@ class PaymentsProvider extends Provider
return new Repository();
}, [ 'useFactory' => true ]);
//
$this->di->bind('Payments\Points', function ($di) {
return new Points\Manager();
});
//
$this->di->bind('BraintreePayments', function ($di) {
$config = $di->get('Config');
$braintree = new Braintree\Braintree(new Braintree_Configuration(), $di->get('Config'));
/*$braintree->setConfig([
'environment' => $config->payments['braintree']['default']['environment'] ?: 'sandbox',
'merchant_id' => $config->payments['braintree']['default']['merchant_id'],
'master_merchant_id' => $config->payments['braintree']['default']['master_merchant_id'],
'public_key' => $config->payments['braintree']['default']['public_key'],
'private_key' => $config->payments['braintree']['default']['private_key']
]);*/
return $braintree;
}, ['useFactory'=>true]);
$this->di->bind('StripePayments', function ($di) {
$config = $di->get('Config');
return new Stripe\Stripe($di->get('Config'));
}, ['useFactory'=>true]);
// Stripe
$this->di->bind('Stripe\Connect\Manager', function ($di) {
return new Stripe\Connect\Manager();
}, ['useFactory'=>true]);
......
......@@ -65,13 +65,15 @@ class PaywallReview
public function add()
{
$query = new Core\Data\Cassandra\Prepared\Custom();
$query->query("INSERT INTO entities_by_time
$query->query(
"INSERT INTO entities_by_time
(key, column1, value)
VALUES ('paywall:review', ?, ?)",
[
[
(string) $this->entity_guid,
(string) $this->entity_guid
]);
]
);
try {
$result = $this->db->request($query);
} catch (\Exception $e) {
......@@ -84,7 +86,8 @@ class PaywallReview
public function remove()
{
$query = new Core\Data\Cassandra\Prepared\Custom();
$query->query("DELETE FROM entities_by_time
$query->query(
"DELETE FROM entities_by_time
WHERE key = 'paywall:review' AND column1 = ?",
[
(string) $this->entity_guid
......
......@@ -205,17 +205,19 @@ class Repository
public function add($plan)
{
$query = new Core\Data\Cassandra\Prepared\Custom();
$query->query("INSERT INTO plans
$query->query(
"INSERT INTO plans
(entity_guid, plan, user_guid, status, subscription_id, expires)
VALUES (?, ?, ?, ?, ?, ?)",
[
[
(string) $plan->getEntityGuid(),
(string) $plan->getName(),
(string) $plan->getUserGuid(),
(string) $plan->getStatus(),
(string) $plan->getSubscriptionId(),
(int) $plan->getExpires(),
]);
]
);
try {
$result = $this->db->request($query);
} catch (\Exception $e) {
......
......@@ -22,8 +22,8 @@ class Manager
public function __construct(
$lookup = null,
$customersManager = null,
$paymentMethodInstance = null)
{
$paymentMethodInstance = null
) {
$this->lookup = $lookup ?: Di::_()->get('Database\Cassandra\Lookup');
$this->customersManager = $customersManager ?? new CustomersManager;
$this->paymentMethodInstance = $paymentMethodInstance ?? new PaymentMethodInstance();
......
<?php
/**
* Braintree webhooks
*/
namespace Minds\Core\Payments\Stripe;
......
......@@ -185,7 +185,8 @@ class Repository
public function add($subscription)
{
$query = new Custom();
$query->query("INSERT INTO subscriptions (
$query->query(
"INSERT INTO subscriptions (
subscription_id,
plan_id,
payment_method,
......@@ -197,7 +198,7 @@ class Repository
last_billing,
next_billing
) VALUES (?,?,?,?,?,?,?,?,?,?)",
[
[
$subscription->getId(),
$subscription->getPlanId(),
$subscription->getPaymentMethod(),
......@@ -208,7 +209,8 @@ class Repository
$subscription->getStatus(),
new Timestamp($subscription->getLastBilling()),
new Timestamp($subscription->getNextBilling())
]);
]
);
$result = $this->cql->request($query);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.