mirror of
https://github.com/flarum/framework.git
synced 2025-02-28 16:05:27 +08:00
Add "today" period with hourly breakdown, and fix timezone issues
This fix ensures that before aggregating daily/hourly statistics, dates are converted into the local timezone ("flarum-statistics.timezone" in the settings table).
This commit is contained in:
parent
8860def12e
commit
6857d32d22
61
extensions/statistics/js/admin/dist/extension.js
vendored
61
extensions/statistics/js/admin/dist/extension.js
vendored
@ -36,14 +36,14 @@ System.register('flarum/statistics/components/StatisticsWidget', ['flarum/compon
|
|||||||
value: function init() {
|
value: function init() {
|
||||||
babelHelpers.get(StatisticsWidget.prototype.__proto__ || Object.getPrototypeOf(StatisticsWidget.prototype), 'init', this).call(this);
|
babelHelpers.get(StatisticsWidget.prototype.__proto__ || Object.getPrototypeOf(StatisticsWidget.prototype), 'init', this).call(this);
|
||||||
|
|
||||||
var today = new Date();
|
var today = new Date().setHours(0, 0, 0, 0) / 1000;
|
||||||
today.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
this.entities = ['users', 'discussions', 'posts'];
|
this.entities = ['users', 'discussions', 'posts'];
|
||||||
this.periods = {
|
this.periods = {
|
||||||
last_7_days: { start: today - 86400000 * 6, end: today, step: 86400000 },
|
today: { start: today, end: today + 86400, step: 3600 },
|
||||||
last_28_days: { start: today - 86400000 * 27, end: today, step: 86400000 },
|
last_7_days: { start: today - 86400 * 7, end: today, step: 86400 },
|
||||||
last_12_months: { start: today - 86400000 * 364, end: today, step: 86400000 * 7 }
|
last_28_days: { start: today - 86400 * 28, end: today, step: 86400 },
|
||||||
|
last_12_months: { start: today - 86400 * 364, end: today, step: 86400 * 7 }
|
||||||
};
|
};
|
||||||
|
|
||||||
this.selectedEntity = 'users';
|
this.selectedEntity = 'users';
|
||||||
@ -81,7 +81,10 @@ System.register('flarum/statistics/components/StatisticsWidget', ['flarum/compon
|
|||||||
Object.keys(this.periods).map(function (period) {
|
Object.keys(this.periods).map(function (period) {
|
||||||
return m(
|
return m(
|
||||||
Button,
|
Button,
|
||||||
{ active: period === _this2.selectedPeriod, onclick: _this2.changePeriod.bind(_this2, period) },
|
{
|
||||||
|
active: period === _this2.selectedPeriod,
|
||||||
|
onclick: _this2.changePeriod.bind(_this2, period),
|
||||||
|
icon: period === _this2.selectedPeriod ? 'check' : true },
|
||||||
app.translator.trans('flarum-statistics.admin.statistics.' + period + '_label')
|
app.translator.trans('flarum-statistics.admin.statistics.' + period + '_label')
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@ -128,22 +131,37 @@ System.register('flarum/statistics/components/StatisticsWidget', ['flarum/compon
|
|||||||
}, {
|
}, {
|
||||||
key: 'drawChart',
|
key: 'drawChart',
|
||||||
value: function drawChart(elm, isInitialized, context) {
|
value: function drawChart(elm, isInitialized, context) {
|
||||||
var entity = this.selectedEntity;
|
if (context.chart && context.entity === this.selectedEntity && context.period === this.selectedPeriod) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var period = this.periods[this.selectedPeriod];
|
var period = this.periods[this.selectedPeriod];
|
||||||
|
var periodLength = period.end - period.start;
|
||||||
var labels = [];
|
var labels = [];
|
||||||
var thisPeriod = [];
|
var thisPeriod = [];
|
||||||
var lastPeriod = [];
|
var lastPeriod = [];
|
||||||
|
|
||||||
for (var i = period.start; i <= period.end; i += period.step) {
|
for (var i = period.start; i < period.end; i += period.step) {
|
||||||
labels.push(moment(i).format('D MMM'));
|
var label = void 0;
|
||||||
|
|
||||||
thisPeriod.push(this.getPeriodCount(entity, { start: i, end: i + period.step }));
|
if (period.step < 86400) {
|
||||||
|
label = moment.unix(i).format('h A');
|
||||||
|
} else {
|
||||||
|
label = moment.unix(i).format('D MMM');
|
||||||
|
|
||||||
var periodLength = period.end - period.start;
|
if (period.step > 86400) {
|
||||||
lastPeriod.push(this.getPeriodCount(entity, { start: i - periodLength, end: i - periodLength + period.step }));
|
label += ' - ' + moment.unix(i + period.step - 1).format('D MMM');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
labels.push(label);
|
||||||
|
|
||||||
|
thisPeriod.push(this.getPeriodCount(this.selectedEntity, { start: i, end: i + period.step }));
|
||||||
|
|
||||||
|
lastPeriod.push(this.getPeriodCount(this.selectedEntity, { start: i - periodLength, end: i - periodLength + period.step }));
|
||||||
}
|
}
|
||||||
|
|
||||||
var datasets = [{ values: lastPeriod, title: 'Last period ➡' }, { values: thisPeriod, title: 'This period' }];
|
var datasets = [{ values: lastPeriod }, { values: thisPeriod }];
|
||||||
|
|
||||||
if (!context.chart) {
|
if (!context.chart) {
|
||||||
context.chart = new Chart({
|
context.chart = new Chart({
|
||||||
@ -155,17 +173,14 @@ System.register('flarum/statistics/components/StatisticsWidget', ['flarum/compon
|
|||||||
y_axis_mode: 'span',
|
y_axis_mode: 'span',
|
||||||
is_series: 1,
|
is_series: 1,
|
||||||
show_dots: 0,
|
show_dots: 0,
|
||||||
colors: ['rgba(0,0,0,0.1)', app.forum.attribute('themePrimaryColor')],
|
colors: ['rgba(0, 0, 0, 0.1)', app.forum.attribute('themePrimaryColor')]
|
||||||
format_tooltip_x: function format_tooltip_x(d) {
|
|
||||||
return d;
|
|
||||||
},
|
|
||||||
format_tooltip_y: function format_tooltip_y(d) {
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
context.chart.update_values(datasets, labels);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.chart.update_values(datasets, labels);
|
context.entity = this.selectedEntity;
|
||||||
|
context.period = this.selectedPeriod;
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: 'changeEntity',
|
key: 'changeEntity',
|
||||||
@ -189,9 +204,7 @@ System.register('flarum/statistics/components/StatisticsWidget', ['flarum/compon
|
|||||||
var count = 0;
|
var count = 0;
|
||||||
|
|
||||||
for (var day in daily) {
|
for (var day in daily) {
|
||||||
var date = new Date(day);
|
if (day >= period.start && day < period.end) {
|
||||||
|
|
||||||
if (date > period.start && date < period.end) {
|
|
||||||
count += daily[day];
|
count += daily[day];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,14 +19,14 @@ export default class StatisticsWidget extends DashboardWidget {
|
|||||||
init() {
|
init() {
|
||||||
super.init();
|
super.init();
|
||||||
|
|
||||||
const today = new Date();
|
const today = new Date().setHours(0, 0, 0, 0) / 1000;
|
||||||
today.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
this.entities = ['users', 'discussions', 'posts'];
|
this.entities = ['users', 'discussions', 'posts'];
|
||||||
this.periods = {
|
this.periods = {
|
||||||
last_7_days: {start: today - 86400000 * 6, end: today, step: 86400000},
|
today: {start: today, end: today + 86400, step: 3600},
|
||||||
last_28_days: {start: today - 86400000 * 27, end: today, step: 86400000},
|
last_7_days: {start: today - 86400 * 7, end: today, step: 86400},
|
||||||
last_12_months: {start: today - 86400000 * 364, end: today, step: 86400000 * 7}
|
last_28_days: {start: today - 86400 * 28, end: today, step: 86400},
|
||||||
|
last_12_months: {start: today - 86400 * 364, end: today, step: 86400 * 7}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.selectedEntity = 'users';
|
this.selectedEntity = 'users';
|
||||||
@ -91,19 +91,30 @@ export default class StatisticsWidget extends DashboardWidget {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const entity = this.selectedEntity;
|
|
||||||
const period = this.periods[this.selectedPeriod];
|
const period = this.periods[this.selectedPeriod];
|
||||||
|
const periodLength = period.end - period.start;
|
||||||
const labels = [];
|
const labels = [];
|
||||||
const thisPeriod = [];
|
const thisPeriod = [];
|
||||||
const lastPeriod = [];
|
const lastPeriod = [];
|
||||||
|
|
||||||
for (let i = period.start; i <= period.end; i += period.step) {
|
for (let i = period.start; i < period.end; i += period.step) {
|
||||||
labels.push(moment(i).format('D MMM'));
|
let label;
|
||||||
|
|
||||||
thisPeriod.push(this.getPeriodCount(entity, {start: i, end: i + period.step}));
|
if (period.step < 86400) {
|
||||||
|
label = moment.unix(i).format('h A');
|
||||||
|
} else {
|
||||||
|
label = moment.unix(i).format('D MMM');
|
||||||
|
|
||||||
const periodLength = period.end - period.start;
|
if (period.step > 86400) {
|
||||||
lastPeriod.push(this.getPeriodCount(entity, {start: i - periodLength, end: i - periodLength + period.step}));
|
label += ' - ' + moment.unix(i + period.step - 1).format('D MMM');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
labels.push(label);
|
||||||
|
|
||||||
|
thisPeriod.push(this.getPeriodCount(this.selectedEntity, {start: i, end: i + period.step}));
|
||||||
|
|
||||||
|
lastPeriod.push(this.getPeriodCount(this.selectedEntity, {start: i - periodLength, end: i - periodLength + period.step}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const datasets = [
|
const datasets = [
|
||||||
@ -148,9 +159,7 @@ export default class StatisticsWidget extends DashboardWidget {
|
|||||||
let count = 0;
|
let count = 0;
|
||||||
|
|
||||||
for (const day in daily) {
|
for (const day in daily) {
|
||||||
const date = new Date(day);
|
if (day >= period.start && day < period.end) {
|
||||||
|
|
||||||
if (date > period.start && date < period.end) {
|
|
||||||
count += daily[day];
|
count += daily[day];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,20 +12,41 @@
|
|||||||
namespace Flarum\Statistics\Listener;
|
namespace Flarum\Statistics\Listener;
|
||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
|
use DateTimeZone;
|
||||||
use Flarum\Core\Discussion;
|
use Flarum\Core\Discussion;
|
||||||
use Flarum\Core\Post;
|
use Flarum\Core\Post;
|
||||||
use Flarum\Core\User;
|
use Flarum\Core\User;
|
||||||
use Flarum\Event\ConfigureWebApp;
|
use Flarum\Event\ConfigureWebApp;
|
||||||
|
use Flarum\Settings\SettingsRepositoryInterface;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Contracts\Events\Dispatcher;
|
use Illuminate\Contracts\Events\Dispatcher;
|
||||||
|
|
||||||
class AddStatisticsData
|
class AddStatisticsData
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var SettingsRepositoryInterface
|
||||||
|
*/
|
||||||
|
protected $settings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param SettingsRepositoryInterface $settings
|
||||||
|
*/
|
||||||
|
public function __construct(SettingsRepositoryInterface $settings)
|
||||||
|
{
|
||||||
|
$this->settings = $settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Dispatcher $events
|
||||||
|
*/
|
||||||
public function subscribe(Dispatcher $events)
|
public function subscribe(Dispatcher $events)
|
||||||
{
|
{
|
||||||
$events->listen(ConfigureWebApp::class, [$this, 'addStatisticsData']);
|
$events->listen(ConfigureWebApp::class, [$this, 'addStatisticsData']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ConfigureWebApp $event
|
||||||
|
*/
|
||||||
public function addStatisticsData(ConfigureWebApp $event)
|
public function addStatisticsData(ConfigureWebApp $event)
|
||||||
{
|
{
|
||||||
$event->view->setVariable('statistics', $this->getStatistics());
|
$event->view->setVariable('statistics', $this->getStatistics());
|
||||||
@ -49,11 +70,33 @@ class AddStatisticsData
|
|||||||
|
|
||||||
private function getDailyCounts(Builder $query, $column)
|
private function getDailyCounts(Builder $query, $column)
|
||||||
{
|
{
|
||||||
|
// Calculate the offset between the server timezone (which is used for
|
||||||
|
// dates stored in the database) and the user's timezone (set via the
|
||||||
|
// settings table). We will use this to adjust dates before aggregating
|
||||||
|
// daily/hourly statistics.
|
||||||
|
$offset = $this->getTimezoneOffset();
|
||||||
|
|
||||||
return $query
|
return $query
|
||||||
->selectRaw('DATE('.$column.') as date')
|
->selectRaw(
|
||||||
|
'UNIX_TIMESTAMP(
|
||||||
|
DATE_FORMAT(
|
||||||
|
@date := DATE_ADD('.$column.', INTERVAL ? SECOND), -- correct for timezone
|
||||||
|
IF(@date > ?, \'%Y-%m-%d %H:00:00\', \'%Y-%m-%d\') -- if within the last 48 hours, group by hour
|
||||||
|
)
|
||||||
|
) as period',
|
||||||
|
[$offset, new DateTime('-48 hours')]
|
||||||
|
)
|
||||||
->selectRaw('COUNT(id) as count')
|
->selectRaw('COUNT(id) as count')
|
||||||
->where($column, '>', new DateTime('-24 months'))
|
->where($column, '>', new DateTime('-24 months'))
|
||||||
->groupBy('date')
|
->groupBy('period')
|
||||||
->lists('count', 'date');
|
->lists('count', 'period');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getTimezoneOffset()
|
||||||
|
{
|
||||||
|
$dataTimezone = new DateTimeZone(date_default_timezone_get());
|
||||||
|
$displayTimezone = new DateTimeZone($this->settings->get('flarum-statistics.timezone', date_default_timezone_get()));
|
||||||
|
|
||||||
|
return $displayTimezone->getOffset(new DateTime('now', $dataTimezone));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user