Skip to content
Next
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Switch to GitLab Next
Sign in / Register
Toggle navigation
Minds Backend - Engine
Project
Project
Details
Activity
Releases
Cycle Analytics
Insights
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Locked Files
Issues
231
Issues
231
List
Boards
Labels
Service Desk
Milestones
Merge Requests
36
Merge Requests
36
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Security & Compliance
Security & Compliance
Dependency List
Packages
Packages
List
Container Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Minds
Minds Backend - Engine
Compare Revisions
168443b0250798b5bb32328e2265985f0d37d13b...cfaac31d377e9f97d3b0c53220bb0af923b1dcd0
Source
cfaac31d377e9f97d3b0c53220bb0af923b1dcd0
Select Git revision
...
Target
168443b0250798b5bb32328e2265985f0d37d13b
Select Git revision
Compare
Commits (2)
(wip): partner earnings
· 474516ab
Mark Harding
authored
4 hours ago
474516ab
(chore): various fixes and changes to dashboards
· cfaac31d
Mark Harding
authored
4 hours ago
cfaac31d
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
1005 additions
and
75 deletions
+1005
-75
Controllers/Cli/PartnerEarnings.php
Controllers/Cli/PartnerEarnings.php
+42
-0
Core/Analytics/Dashboards/EarningsDashboard.php
Core/Analytics/Dashboards/EarningsDashboard.php
+101
-0
Core/Analytics/Dashboards/Manager.php
Core/Analytics/Dashboards/Manager.php
+1
-0
Core/Analytics/Dashboards/Metrics/AbstractMetric.php
Core/Analytics/Dashboards/Metrics/AbstractMetric.php
+32
-0
Core/Analytics/Dashboards/Metrics/ActiveUsersMetric.php
Core/Analytics/Dashboards/Metrics/ActiveUsersMetric.php
+9
-0
Core/Analytics/Dashboards/Metrics/Earnings/AbstractEarningsMetric.php
...cs/Dashboards/Metrics/Earnings/AbstractEarningsMetric.php
+181
-0
Core/Analytics/Dashboards/Metrics/Earnings/ReferralsEarningsMetric.php
...s/Dashboards/Metrics/Earnings/ReferralsEarningsMetric.php
+27
-0
Core/Analytics/Dashboards/Metrics/Earnings/SalesEarningsMetric.php
...ytics/Dashboards/Metrics/Earnings/SalesEarningsMetric.php
+27
-0
Core/Analytics/Dashboards/Metrics/Earnings/TotalEarningsMetric.php
...ytics/Dashboards/Metrics/Earnings/TotalEarningsMetric.php
+27
-0
Core/Analytics/Dashboards/Metrics/Earnings/ViewsEarningsMetric.php
...ytics/Dashboards/Metrics/Earnings/ViewsEarningsMetric.php
+27
-0
Core/Analytics/Dashboards/Metrics/MetricsCollection.php
Core/Analytics/Dashboards/Metrics/MetricsCollection.php
+3
-0
Core/Analytics/Dashboards/Metrics/SignupsMetric.php
Core/Analytics/Dashboards/Metrics/SignupsMetric.php
+9
-0
Core/Analytics/Dashboards/Metrics/ViewsMetric.php
Core/Analytics/Dashboards/Metrics/ViewsMetric.php
+2
-36
Core/Analytics/Dashboards/Metrics/ViewsTableMetric.php
Core/Analytics/Dashboards/Metrics/ViewsTableMetric.php
+42
-35
Core/Analytics/Dashboards/TrafficDashboard.php
Core/Analytics/Dashboards/TrafficDashboard.php
+1
-1
Core/Analytics/Dashboards/TrendingDashboard.php
Core/Analytics/Dashboards/TrendingDashboard.php
+1
-1
Core/Analytics/EntityCentric/EntityCentricRecord.php
Core/Analytics/EntityCentric/EntityCentricRecord.php
+8
-0
Core/Analytics/EntityCentric/Manager.php
Core/Analytics/EntityCentric/Manager.php
+17
-2
Core/Analytics/EntityCentric/PartnerEarningsSynchroniser.php
Core/Analytics/EntityCentric/PartnerEarningsSynchroniser.php
+71
-0
Core/Analytics/EntityCentric/Sums.php
Core/Analytics/EntityCentric/Sums.php
+107
-0
Core/Monetization/Partners/EarningsDeposit.php
Core/Monetization/Partners/EarningsDeposit.php
+44
-0
Core/Monetization/Partners/Manager.php
Core/Monetization/Partners/Manager.php
+95
-0
Core/Monetization/Partners/Repository.php
Core/Monetization/Partners/Repository.php
+131
-0
No files found.
Controllers/Cli/PartnerEarnings.php
0 → 100644
View file @
cfaac31d
<?php
namespace
Minds\Controllers\Cli
;
use
Minds\Core
;
use
Minds\Core\Monetization\Partners\Manager
;
use
Minds\Cli
;
use
Minds\Interfaces
;
use
Minds\Exceptions
;
use
Minds\Entities
;
class
PartnerEarnings
extends
Cli\Controller
implements
Interfaces\CliControllerInterface
{
public
function
__construct
()
{
}
public
function
help
(
$command
=
null
)
{
$this
->
out
(
'TBD'
);
}
public
function
exec
()
{
$this
->
out
(
'Missing subcommand'
);
}
public
function
sync
()
{
error_reporting
(
E_ALL
);
ini_set
(
'display_errors'
,
1
);
$daysAgo
=
$this
->
getOpt
(
'daysAgo'
)
?:
0
;
$from
=
$this
->
getOpt
(
'from'
)
?:
strtotime
(
"midnight
$daysAgo
days ago"
);
$manager
=
new
Manager
();
$i
=
0
;
foreach
(
$manager
->
issueDeposits
([
'from'
=>
$from
])
as
$record
)
{
$this
->
out
(
++
$i
);
}
}
}
This diff is collapsed.
Click to expand it.
Core/Analytics/Dashboards/EarningsDashboard.php
0 → 100644
View file @
cfaac31d
<?php
/**
* Earnings Dashboard
*/
namespace
Minds\Core\Analytics\Dashboards
;
use
Minds\Traits\MagicAttributes
;
/**
* @method TrafficDashboard setTimespanId(string $timespanId)
* @method TrafficDashboard setFilterIds(array $filtersIds)
*/
class
EarningsDashboard
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 Visualisations\Chart\ChartSegmentsCollection */
private
$chartCollection
;
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
)
->
addFilters
(
new
Filters\ChannelFilter
()
);
$this
->
metricsCollection
->
setTimespansCollection
(
$this
->
timespansCollection
)
->
setFiltersCollection
(
$this
->
filtersCollection
)
->
setSelectedId
(
$this
->
metricId
)
->
addMetrics
(
new
Metrics\Earnings\TotalEarningsMetric
(),
new
Metrics\Earnings\ViewsEarningsMetric
(),
new
Metrics\Earnings\ReferralsEarningsMetric
(),
new
Metrics\Earnings\SalesEarningsMetric
()
)
->
build
();
return
$this
;
}
/**
* Export
* @param array $extras
* @return array
*/
public
function
export
(
array
$extras
=
[])
:
array
{
$this
->
build
();
return
[
'category'
=>
'earnings'
,
'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
(),
];
}
}
This diff is collapsed.
Click to expand it.
Core/Analytics/Dashboards/Manager.php
View file @
cfaac31d
...
...
@@ -6,6 +6,7 @@ class Manager
const
DASHBOARDS
=
[
'traffic'
=>
TrafficDashboard
::
class
,
'trending'
=>
TrendingDashboard
::
class
,
'earnings'
=>
EarningsDashboard
::
class
,
];
/**
...
...
This diff is collapsed.
Click to expand it.
Core/Analytics/Dashboards/Metrics/AbstractMetric.php
View file @
cfaac31d
...
...
@@ -3,6 +3,7 @@ namespace Minds\Core\Analytics\Dashboards\Metrics;
use
Minds\Core\Analytics\Dashboards\Timespans\TimespansCollection
;
use
Minds\Core\Di\Di
;
use
Minds\Core\Session
;
use
Minds\Traits\MagicAttributes
;
/**
...
...
@@ -43,6 +44,37 @@ abstract class AbstractMetric
/** @var FiltersCollection */
protected
$filtersCollection
;
/**
* Return the usd guid for metrics
* @return string
*/
protected
function
getUserGuid
()
:
?
string
{
$filters
=
$this
->
filtersCollection
->
getSelected
();
$channelFilter
=
$filters
[
'channel'
];
if
(
!
$channelFilter
)
{
if
(
!
Session
::
getLoggedInUserGuid
())
{
throw
new
\Exception
(
"You must be loggedin"
);
}
return
Session
::
getLoggedInUserGuid
();
}
if
(
$channelFilter
->
getSelectedOption
()
===
'all'
)
{
if
(
Session
::
isAdmin
())
{
return
""
;
}
$channelFilter
->
setSelectedOption
(
'self'
);
}
if
(
$channelFilter
->
getSelectedOption
()
===
'self'
)
{
return
Session
::
getLoggedInUserGuid
();
}
// TODO: check permissions first
return
$channelFilter
->
getSelectedOption
();
}
/**
* Export
* @param array $extras
...
...
This diff is collapsed.
Click to expand it.
Core/Analytics/Dashboards/Metrics/ActiveUsersMetric.php
View file @
cfaac31d
...
...
@@ -32,6 +32,10 @@ class ActiveUsersMetric extends AbstractMetric
*/
public
function
buildSummary
()
:
self
{
if
(
$this
->
getUserGuid
())
{
return
$this
;
}
$timespan
=
$this
->
timespansCollection
->
getSelected
();
$filters
=
$this
->
filtersCollection
->
getSelected
();
...
...
@@ -118,6 +122,11 @@ class ActiveUsersMetric extends AbstractMetric
*/
public
function
buildVisualisation
()
:
self
{
if
(
$this
->
getUserGuid
())
{
$this
->
visualisation
=
(
new
Visualisations\ChartVisualisation
());
return
$this
;
}
$timespan
=
$this
->
timespansCollection
->
getSelected
();
$xValues
=
[];
$yValues
=
[];
...
...
This diff is collapsed.
Click to expand it.
Core/Analytics/Dashboards/Metrics/Earnings/AbstractEarningsMetric.php
0 → 100644
View file @
cfaac31d
<?php
namespace
Minds\Core\Analytics\Dashboards\Metrics\Earnings
;
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
AbstractEarningsMetric
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
=
'usd'
;
/** @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
=
[];
$must
[][
'range'
]
=
[
'@timestamp'
=>
[
'gte'
=>
$tsMs
,
'lte'
=>
strtotime
(
"midnight +
{
$timespan
->
getComparisonInterval
()
}
days"
,
$tsMs
/
1000
)
*
1000
,
],
];
if
(
$userGuid
=
$this
->
getUserGuid
())
{
$must
[]
=
[
'term'
=>
[
'owner_guid'
=>
$userGuid
,
],
];
}
$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
,
],
];
}
// 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'
=>
1
,
],
'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
;
}
}
This diff is collapsed.
Click to expand it.
Core/Analytics/Dashboards/Metrics/Earnings/ReferralsEarningsMetric.php
0 → 100644
View file @
cfaac31d
<?php
namespace
Minds\Core\Analytics\Dashboards\Metrics\Earnings
;
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
ReferralsEarningsMetric
extends
AbstractEarningsMetric
{
/** @var string */
protected
$id
=
'earnings_referrals'
;
/** @var string */
protected
$label
=
'Referrals USD'
;
/** @var string */
protected
$description
=
'Referral earnings for PRO users'
;
/** @var array */
protected
$permissions
=
[
'user'
,
'admin'
];
/** @var string */
protected
$aggField
=
'usd_earnings::referrals'
;
}
This diff is collapsed.
Click to expand it.
Core/Analytics/Dashboards/Metrics/Earnings/SalesEarningsMetric.php
0 → 100644
View file @
cfaac31d
<?php
namespace
Minds\Core\Analytics\Dashboards\Metrics\Earnings
;
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
SalesEarningsMetric
extends
AbstractEarningsMetric
{
/** @var string */
protected
$id
=
'earnings_sales'
;
/** @var string */
protected
$label
=
'Sales USD'
;
/** @var string */
protected
$description
=
'Sales earnings for PRO users'
;
/** @var array */
protected
$permissions
=
[
'user'
,
'admin'
];
/** @var string */
protected
$aggField
=
'usd_earnings::sales'
;
}
This diff is collapsed.
Click to expand it.
Core/Analytics/Dashboards/Metrics/Earnings/TotalEarningsMetric.php
0 → 100644
View file @
cfaac31d
<?php
namespace
Minds\Core\Analytics\Dashboards\Metrics\Earnings
;
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
TotalEarningsMetric
extends
AbstractEarningsMetric
{
/** @var string */
protected
$id
=
'earnings_total'
;
/** @var string */
protected
$label
=
'Total Earnings'
;
/** @var string */
protected
$description
=
'Total earnings for PRO users'
;
/** @var array */
protected
$permissions
=
[
'user'
,
'admin'
];
/** @var string */
protected
$aggField
=
'usd_earnings::total'
;
}
This diff is collapsed.
Click to expand it.
Core/Analytics/Dashboards/Metrics/Earnings/ViewsEarningsMetric.php
0 → 100644
View file @
cfaac31d
<?php
namespace
Minds\Core\Analytics\Dashboards\Metrics\Earnings
;
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
ViewsEarningsMetric
extends
AbstractEarningsMetric
{
/** @var string */
protected
$id
=
'earnings_views'
;
/** @var string */
protected
$label
=
'Views USD'
;
/** @var string */
protected
$description
=
'Views earnings for PRO users'
;
/** @var array */
protected
$permissions
=
[
'user'
,
'admin'
];
/** @var string */
protected
$aggField
=
'usd_earnings::views'
;
}
This diff is collapsed.
Click to expand it.
Core/Analytics/Dashboards/Metrics/MetricsCollection.php
View file @
cfaac31d
...
...
@@ -70,6 +70,9 @@ class MetricsCollection implements DashboardCollectionInterface
*/
public
function
getSelected
()
:
AbstractMetric
{
if
(
!
isset
(
$this
->
metrics
[
$this
->
selectedId
]))
{
$this
->
selectedId
=
key
(
$this
->
metrics
);
}
return
$this
->
metrics
[
$this
->
selectedId
];
}
...
...
This diff is collapsed.
Click to expand it.
Core/Analytics/Dashboards/Metrics/SignupsMetric.php
View file @
cfaac31d
...
...
@@ -32,6 +32,10 @@ class SignupsMetric extends AbstractMetric
*/
public
function
buildSummary
()
:
self
{
if
(
$this
->
getUserGuid
())
{
return
$this
;
}
$timespan
=
$this
->
timespansCollection
->
getSelected
();
$comparisonTsMs
=
strtotime
(
"-
{
$timespan
->
getComparisonInterval
()
}
days"
,
$timespan
->
getFromTsMs
()
/
1000
)
*
1000
;
$currentTsMs
=
$timespan
->
getFromTsMs
();
...
...
@@ -95,6 +99,11 @@ class SignupsMetric extends AbstractMetric
*/
public
function
buildVisualisation
()
:
self
{
if
(
$this
->
getUserGuid
())
{
$this
->
visualisation
=
(
new
Visualisations\ChartVisualisation
());
return
$this
;
}
$timespan
=
$this
->
timespansCollection
->
getSelected
();
$xValues
=
[];
$yValues
=
[];
...
...
This diff is collapsed.
Click to expand it.
Core/Analytics/Dashboards/Metrics/ViewsMetric.php
View file @
cfaac31d
...
...
@@ -3,7 +3,7 @@ namespace Minds\Core\Analytics\Dashboards\Metrics;
use
Minds\Core\Di\Di
;
use
Minds\Core\Session
;
use
Minds\Core\Data\Elastic
s
earch
;
use
Minds\Core\Data\Elastic
S
earch
;
class
ViewsMetric
extends
AbstractMetric
{
...
...
@@ -48,14 +48,7 @@ class ViewsMetric extends AbstractMetric
$values
=
[];
foreach
([
'value'
=>
$currentTsMs
,
'comparison'
=>
$comparisonTsMs
]
as
$key
=>
$tsMs
)
{
$must
=
[];
// Specify the resolution to avoid duplicates
$must
[]
=
[
'term'
=>
[
'resolution'
=>
$timespan
->
getInterval
(),
],
];
$must
[][
'range'
]
=
[
'@timestamp'
=>
[
'gte'
=>
$tsMs
,
...
...
@@ -133,13 +126,6 @@ class ViewsMetric extends AbstractMetric
],
];
// Specify the resolution to avoid duplicates
$must
[]
=
[
'term'
=>
[
'resolution'
=>
$timespan
->
getInterval
(),
],
];
if
(
$userGuid
=
$this
->
getUserGuid
())
{
$must
[]
=
[
'term'
=>
[
...
...
@@ -203,24 +189,4 @@ class ViewsMetric extends AbstractMetric
return
$this
;
}
private
function
getUserGuid
()
:
?
string
{
$filters
=
$this
->
filtersCollection
->
getSelected
();
$channelFilter
=
$filters
[
'channel'
];
if
(
!
$channelFilter
)
{
return
""
;
}
if
(
$channelFilter
->
getSelectedOption
()
===
'self'
)
{
return
Session
::
getLoggedInUserGuid
();
}
if
(
$channelFilter
->
getSelectedOption
()
===
'all'
)
{
return
""
;
}
// TODO: check permissions first
return
$channelFilter
->
getSelectedOption
();
}
}
This diff is collapsed.
Click to expand it.
Core/Analytics/Dashboards/Metrics/ViewsTableMetric.php
View file @
cfaac31d
...
...
@@ -2,14 +2,18 @@
namespace
Minds\Core\Analytics\Dashboards\Metrics
;
use
Minds\Core\Di\Di
;
use
Minds\Core\Session
;
use
Minds\Core\Data\ElasticSearch
;
use
Minds\Core\Entities\Resolver
;
use
Minds\Common\Urn
;
class
ViewsTableMetric
extends
AbstractMetric
{
/** @var Elasticsearch\Client */
private
$es
;
/** @var Resolver */
private
$entitiesResolver
;
/** @var string */
protected
$id
=
'views_table'
;
...
...
@@ -25,6 +29,7 @@ class ViewsTableMetric extends AbstractMetric
public
function
__construct
(
$es
=
null
)
{
$this
->
es
=
$es
??
Di
::
_
()
->
get
(
'Database\ElasticSearch'
);
$this
->
entitiesResolver
=
$entitiesResolver
??
new
Resolver
();
}
/**
...
...
@@ -67,11 +72,11 @@ class ViewsTableMetric extends AbstractMetric
];
// Specify the resolution to avoid duplicates
$must
[]
=
[
'term'
=>
[
'resolution'
=>
$timespan
->
getInterval
(),
],
];
//
$must[] = [
//
'term' => [
//
'resolution' => $timespan->getInterval(),
//
],
//
];
if
(
$userGuid
=
$this
->
getUserGuid
())
{
$must
[]
=
[
...
...
@@ -107,10 +112,10 @@ class ViewsTableMetric extends AbstractMetric
],
],
'views::organic'
=>
[
'sum'
=>
[
'sum'
=>
[
'field'
=>
'views::organic'
,
],
],
],
'views::single'
=>
[
'sum'
=>
[
'field'
=>
'views::single'
,
...
...
@@ -126,45 +131,47 @@ class ViewsTableMetric extends AbstractMetric
$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
);
$
subBuckets
=
[]
;
$
entity
=
$this
->
entitiesResolver
->
single
(
new
Urn
(
$bucket
[
'key'
]))
;
$buckets
[]
=
[
'key'
=>
$bucket
[
'key'
],
'values'
=>
[
'views::total'
=>
$bucket
[
'views::total'
][
'value'
],
'views::organic'
=>
$bucket
[
'views::organic'
][
'value'
],
'views::single'
=>
$bucket
[
'views::single'
][
'value'
],
],
'entity'
=>
$entity
?
$entity
->
export
()
:
null
,
'views::total'
=>
$bucket
[
'views::total'
][
'value'
],
'views::organic'
=>
$bucket
[
'views::organic'
][
'value'
],
'views::single'
=>
$bucket
[
'views::single'
][
'value'
],
],
];
}
$this
->
visualisation
=
(
new
Visualisations\TableVisualisation
())
->
setBuckets
(
$buckets
)
->
setColumns
([
'views::total'
,
'views::organic'
,
'views::single'
]);
->
setColumns
([
[
'id'
=>
'entity'
,
'label'
=>
''
,
'order'
=>
0
,
],
[
'id'
=>
'views::total'
,
'label'
=>
'Total Views'
,
'order'
=>
1
,
],
[
'id'
=>
'views::organic'
,
'label'
=>
'Organic'
,
'order'
=>
2
,
],
[
'id'
=>
'views::single'
,
'label'
=>
'Single'
,
'order'
=>
3
,
]
]);
return
$this
;
}
private
function
getUserGuid
()
:
?
string
{
$filters
=
$this
->
filtersCollection
->
getSelected
();
$channelFilter
=
$filters
[
'channel'
];
if
(
!
$channelFilter
)
{
return
""
;
}
if
(
$channelFilter
->
getSelectedOption
()
===
'self'
)
{
return
Session
::
getLoggedInUserGuid
();
}
if
(
$channelFilter
->
getSelectedOption
()
===
'all'
)
{
return
""
;
}
// TODO: check permissions first
return
$channelFilter
->
getSelectedOption
();
}
}
This diff is collapsed.
Click to expand it.
Core/Analytics/Dashboards/TrafficDashboard.php
View file @
cfaac31d
...
...
@@ -63,7 +63,7 @@ class TrafficDashboard implements DashboardInterface
$this
->
filtersCollection
->
setSelectedIds
(
$this
->
filterIds
)
->
addFilters
(
new
Filters\PlatformFilter
(),
//
new Filters\PlatformFilter(),
new
Filters\ViewTypeFilter
(),
new
Filters\ChannelFilter
()
);
...
...
This diff is collapsed.
Click to expand it.
Core/Analytics/Dashboards/TrendingDashboard.php
View file @
cfaac31d
...
...
@@ -60,7 +60,7 @@ class TrendingDashboard implements DashboardInterface
$this
->
filtersCollection
->
setSelectedIds
(
$this
->
filterIds
)
->
addFilters
(
new
Filters\PlatformFilter
(),
//
new Filters\PlatformFilter(),
new
Filters\ViewTypeFilter
(),
new
Filters\ChannelFilter
()
);
...
...
This diff is collapsed.
Click to expand it.
Core/Analytics/EntityCentric/EntityCentricRecord.php
View file @
cfaac31d
...
...
@@ -60,4 +60,12 @@ class EntityCentricRecord
$this
->
sums
[
$metric
]
=
$this
->
sums
[
$metric
]
+
$value
;
return
$this
;
}
/**
* @return string
*/
public
function
getUrn
()
:
string
{
return
(
string
)
implode
(
'-'
,
[
$this
->
getEntityUrn
(),
$this
->
getResolution
(),
$this
->
getTimestamp
()
]);
}
}
This diff is collapsed.
Click to expand it.
Core/Analytics/EntityCentric/Manager.php
View file @
cfaac31d
...
...
@@ -13,6 +13,7 @@ class Manager
{
/** @var array */
const
SYNCHRONISERS
=
[
PartnerEarningsSynchroniser
::
class
,
SignupsSynchroniser
::
class
,
ActiveUsersSynchroniser
::
class
,
ViewsSynchroniser
::
class
,
...
...
@@ -21,6 +22,9 @@ class Manager
/** @var Repository */
protected
$repository
;
/** @var Sums */
protected
$sums
;
/** @var int */
private
$from
;
...
...
@@ -28,9 +32,11 @@ class Manager
private
$to
;
public
function
__construct
(
$repository
=
null
$repository
=
null
,
$sums
=
null
)
{
$this
->
repository
=
$repository
?:
new
Repository
();
$this
->
repository
=
$repository
??
new
Repository
();
$this
->
sums
=
$sums
??
new
Sums
();
}
/**
...
...
@@ -81,4 +87,13 @@ class Manager
public
function
getAggregateByQuery
(
array
$query
)
:
array
{
}
/**
* @param array $opts
* @retun iterable
*/
public
function
getListAggregatedByOwner
(
array
$opts
=
[])
:
iterable
{
return
$this
->
sums
->
getByOwner
(
$opts
);
}
}
This diff is collapsed.
Click to expand it.
Core/Analytics/EntityCentric/PartnerEarningsSynchroniser.php
0 → 100644
View file @
cfaac31d
<?php
namespace
Minds\Core\Analytics\EntityCentric
;
use
Minds\Core\Monetization\Partners\Manager
as
PartnersManager
;
use
DateTime
;
use
Exception
;
class
PartnerEarningsSynchroniser
{
/** @var PartnersManager */
private
$partnersManager
;
public
function
__construct
(
$partnersManager
=
null
)
{
$this
->
partnersManager
=
$partnersManager
??
new
PartnersManager
;
}
/**
* @param int $from
* @return self
*/
public
function
setFrom
(
$from
)
:
self
{
$this
->
from
=
$from
;
return
$this
;
}
/**
* Convert to records
* @return iterable
*/
public
function
toRecords
()
:
iterable
{
$opts
=
[];
$opts
[
'from'
]
=
$this
->
from
;
$records
=
[];
$i
=
0
;
while
(
true
)
{
$result
=
$this
->
partnersManager
->
getList
(
$opts
);
$opts
[
'offset'
]
=
$result
->
getPagingToken
();
foreach
(
$result
as
$deposit
)
{
$urn
=
"urn:user:
{
$deposit
->
getUserGuid
()
}
"
;
$record
=
new
EntityCentricRecord
();
$record
->
setEntityUrn
(
$urn
)
->
setOwnerGuid
(
$deposit
->
getUserGuid
())
->
setTimestamp
(
$deposit
->
getTimestamp
())
// TODO: confirm if this should be rounded to midnight
->
setResolution
(
'day'
);
// In order to increment sums, replace with what has already been seen
if
(
isset
(
$records
[
$record
->
getUrn
()]))
{
$record
=
$records
[
$record
->
getUrn
()];
}
$record
->
incrementSum
(
'usd_earnings::total'
,
$deposit
->
getAmountCents
());
$record
->
incrementSum
(
"usd_earnings::
{
$deposit
->
getItem
()
}
"
,
$deposit
->
getAmountCents
());
$records
[
$record
->
getUrn
()]
=
$record
;
}
if
(
$result
->
isLastPage
())
{
break
;
}
}
foreach
(
$records
as
$record
)
{
var_dump
(
$record
);
yield
$record
;
}
}
}
This diff is collapsed.
Click to expand it.
Core/Analytics/EntityCentric/Sums.php
0 → 100644
View file @
cfaac31d
<?php
/**
* EntityCentric Sums
* @author Mark
*/
namespace
Minds\Core\Analytics\EntityCentric
;
use
DateTime
;
use
DateTimeZone
;
use
Exception
;
use
Minds\Common\Repository\Response
;
use
Minds\Core\Data\ElasticSearch\Client
as
ElasticClient
;
use
Minds\Core\Data\ElasticSearch
;
use
Minds\Core\Di\Di
;
class
Sums
{
/** @var ElasticClient */
protected
$es
;
/**
* Repository constructor.
* @param ElasticClient $es
*/
public
function
__construct
(
$es
=
null
)
{
$this
->
es
=
$es
?:
Di
::
_
()
->
get
(
'Database\ElasticSearch'
);
}
public
function
getByOwner
(
array
$opts
=
[])
:
iterable
{
$opts
=
array_merge
([
'fields'
=>
[],
'from'
=>
time
(),
],
$opts
);
$must
=
[];
$must
[]
=
[
'range'
=>
[
'@timestamp'
=>
[
'gte'
=>
$opts
[
'from'
]
*
1000
,
'lt'
=>
strtotime
(
'+1 day'
,
$opts
[
'from'
])
*
1000
,
],
],
];
$termsAgg
=
[];
foreach
(
$opts
[
'fields'
]
as
$field
)
{
$termsAgg
[
$field
]
=
[
'sum'
=>
[
'field'
=>
$field
,
],
];
$must
[]
=
[
'exists'
=>
[
'field'
=>
$field
,
],
];
}
$partition
=
0
;
$partitions
=
100
;
$partitionSize
=
5000
;
// Allows for 500,000 users
while
(
++
$partition
<
$partitions
)
{
// Do the query
$query
=
[
'index'
=>
'minds-entitycentric-*'
,
'size'
=>
0
,
'body'
=>
[
'query'
=>
[
'bool'
=>
[
'must'
=>
$must
,
],
],
'aggs'
=>
[
'1'
=>
[
'terms'
=>
[
'field'
=>
'owner_guid'
,
'min_doc_count'
=>
1
,
'size'
=>
$partitionSize
,
'include'
=>
[
'partition'
=>
$partition
,
'num_partitions'
=>
$partitions
,
],
],
'aggs'
=>
$termsAgg
,
],
],
],
];
// Query elasticsearch
$prepared
=
new
ElasticSearch\Prepared\Search
();
$prepared
->
query
(
$query
);
$response
=
$this
->
es
->
request
(
$prepared
);
foreach
(
$response
[
'aggregations'
][
'1'
][
'buckets'
]
as
$bucket
)
{
yield
$bucket
;
}
}
}
}
This diff is collapsed.
Click to expand it.
Core/Monetization/Partners/EarningsDeposit.php
0 → 100644
View file @
cfaac31d
<?php
/**
* EarningsDeposit
*/
namespace
Minds\Core\Monetization\Partners
;
use
Minds\Traits\MagicAttributes
;
class
EarningsDeposit
{
use
MagicAttributes
;
/** @var string */
private
$userGuid
;
/** @var int */
private
$timestamp
;
/** @var string */
private
$item
;
/** @var int */
private
$amountCents
;
/** @var int */
private
$amountTokens
;
/**
* Export
* @param array $extras
* @return array
*/
public
function
export
(
$extras
=
[])
:
array
{
return
[
'user_guid'
=>
$this
->
userGuid
,
'timestamp'
=>
$this
->
timestamp
,
'item'
=>
$this
->
item
,
'amount_cents'
=>
(
int
)
$this
->
amountCents
,
'amount_usd'
=>
(
int
)
$this
->
amountCents
/
100
,
'amount_tokens'
=>
(
string
)
$this
->
amountTokens
,
];
}
}
This diff is collapsed.
Click to expand it.
Core/Monetization/Partners/Manager.php
0 → 100644
View file @
cfaac31d
<?php
/**
* Manager
*/
namespace
Minds\Core\Monetization\Partners
;
use
Minds\Core\Analytics\EntityCentric\Manager
as
EntityCentricManager
;
use
Minds\Core\EntitiesBuilder
;
use
Minds\Common\Repository\Response
;
use
Minds\Core\Di\Di
;
use
DateTime
;
class
Manager
{
const
VIEWS_RPM_CENTS
=
100
;
// $1 USD
/** @var Repository */
private
$repository
;
/** @var EntityCentricManager */
private
$entityCentricManager
;
/** @var EntitiesBuilder */
private
$entitiesBuilder
;
public
function
__construct
(
$repository
=
null
,
$entityCentricManager
=
null
,
$entitiesBuilder
=
null
)
{
$this
->
repository
=
$repository
??
new
Repository
();
$this
->
entityCentricManager
=
$entityCentricManager
??
new
EntityCentricManager
();
$this
->
entitiesBuilder
=
$entitiesBuilder
??
Di
::
_
()
->
get
(
'EntitiesBuilder'
);
}
/**
* Return a list of earning deposits
* @param array $opts
* @return Response
*/
public
function
getList
(
array
$opts
=
[])
:
Response
{
return
$this
->
repository
->
getList
(
$opts
);
}
/**
* Add an earnings deposit
* @param EarningsDeposit $deposit
* @return bool
*/
public
function
add
(
EarningsDeposit
$deposit
)
:
bool
{
$this
->
repository
->
add
(
$deposit
);
return
true
;
}
/**
* @param array $opts
* @return iterable
*/
public
function
issueDeposits
(
array
$opts
=
[])
:
iterable
{
$opts
=
array_merge
([
'from'
=>
strtotime
(
'midnight'
),
],
$opts
);
$users
=
[];
foreach
(
$this
->
entityCentricManager
->
getListAggregatedByOwner
([
'fields'
=>
[
'views::single'
],
'from'
=>
$opts
[
'from'
],
])
as
$ownerSum
)
{
$views
=
$ownerSum
[
'views::single'
][
'value'
];
$amountCents
=
(
$views
/
1000
)
*
static
::
VIEWS_RPM_CENTS
;
if
(
$amountCents
<
1
)
{
// Has to be at least 1 cent / $0.01
continue
;
}
// Is this user in the pro program?
$owner
=
$this
->
entitiesBuilder
->
single
(
$ownerSum
[
'key'
]);
if
(
!
$owner
||
!
$owner
->
isPro
())
{
continue
;
}
$deposit
=
new
EarningsDeposit
();
$deposit
->
setTimestamp
(
$opts
[
'from'
])
->
setUserGuid
(
$ownerSum
[
'key'
])
->
setAmountCents
(
$amountCents
)
->
setItem
(
"views"
);
$this
->
repository
->
add
(
$deposit
);
yield
$deposit
;
}
}
}
This diff is collapsed.
Click to expand it.
Core/Monetization/Partners/Repository.php
0 → 100644
View file @
cfaac31d
<?php
namespace
Minds\Core\Monetization\Partners
;
use
Minds\Core\Data\Cassandra\Client
;
use
Minds\Core\Data\Cassandra\Prepared\Custom
as
Prepared
;
use
Minds\Common\Repository\Response
;
use
Minds\Core\Di\Di
;
use
Cassandra\Bigint
;
use
Cassandra\Timestamp
;
class
Repository
{
/** @var Client */
private
$db
;
public
function
__construct
(
$db
=
null
)
{
$this
->
db
=
$db
??
Di
::
_
()
->
get
(
'Database\Cassandra\Cql'
);
}
/**
* @param array $opts
* @return Response
*/
public
function
getList
(
array
$opts
=
[])
:
Response
{
$opts
=
array_merge
([
'from'
=>
null
,
'to'
=>
null
,
'user_guid'
=>
null
,
'allow_filtering'
=>
false
,
],
$opts
);
$statement
=
"SELECT * FROM partner_earnings_ledger"
;
$values
=
[];
$where
=
[];
if
(
$opts
[
'user_guid'
])
{
$where
[]
=
"user_guid = ?"
;
$values
[]
=
new
Bigint
(
$opts
[
'user_guid'
]);
}
if
(
$opts
[
'from'
])
{
$where
[]
=
"timestamp >= ?"
;
$values
[]
=
new
Timestamp
(
$opts
[
'from'
]);
if
(
!
$opts
[
'user_guid'
])
{
// This is a temporary work around (MH)
$opts
[
'allow_filtering'
]
=
true
;
}
}
if
(
$opts
[
'to'
])
{
$where
[]
=
"timestamp < ?"
;
$values
[]
=
new
Timestamp
(
$opts
[
'to'
]);
}
$statement
.=
" WHERE "
.
implode
(
' '
,
$where
);
if
(
$opts
[
'allow_filtering'
])
{
$statement
.=
" ALLOW FILTERING"
;
}
$prepared
=
new
Prepared
();
$prepared
->
query
(
$statement
,
$values
);
$result
=
$this
->
db
->
request
(
$prepared
);
if
(
!
$result
||
!
$result
[
0
])
{
return
new
Response
();
}
$response
=
new
Response
();
foreach
(
$result
as
$row
)
{
$deposit
=
new
EarningsDeposit
();
$deposit
->
setTimestamp
(
$row
[
'timestamp'
]
->
time
())
->
setItem
(
$row
[
'item'
])
->
setUserGuid
((
string
)
$row
[
'user_guid'
])
->
setAmountCents
(
$row
[
'amount_cents'
])
->
setAmountTokens
(
$row
[
'amount_tokens'
]
?
$row
[
'amount_tokens'
]
->
value
()
:
0
);
$response
[]
=
$deposit
;
}
$response
->
setLastPage
(
$result
->
isLastPage
());
return
$response
;
}
/**
* @param string $urn
* @return EarningsDeposit
*/
public
function
get
(
$urn
)
:
EarningsDeposit
{
// TODO
}
/**
* @param EarningsDeposit $deposit
* @return bool
*/
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 (?,?,?,?,?)"
,
[
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
);
}
/**
* @param EarningsDeposit $deposit
* @param array $fields
* @return bool
*/
public
function
update
(
EarningsDeposit
$deposit
,
$fields
=
[])
:
bool
{
}
/**
* @param EarningsDeposit $deposit
* @return bool
*/
public
function
delete
(
EarningsDeposit
$deposit
)
:
bool
{
}
}
This diff is collapsed.
Click to expand it.