Merge pull request #158 from Moonlight-Panel/ImproveStatistics
Added better statistics calculation and active user messurement
This commit is contained in:
@@ -43,6 +43,7 @@ public class User
|
|||||||
// Date stuff
|
// Date stuff
|
||||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
public DateTime LastVisitedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
// Subscriptions
|
// Subscriptions
|
||||||
|
|
||||||
|
|||||||
1059
Moonlight/App/Database/Migrations/20230611152138_AddLastVisitedTimestamp.Designer.cs
generated
Normal file
1059
Moonlight/App/Database/Migrations/20230611152138_AddLastVisitedTimestamp.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddLastVisitedTimestamp : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "LastVisitedAt",
|
||||||
|
table: "Users",
|
||||||
|
type: "datetime(6)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LastVisitedAt",
|
||||||
|
table: "Users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -762,6 +762,9 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastVisitedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
b.Property<string>("Password")
|
b.Property<string>("Password")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|||||||
39
Moonlight/App/Helpers/AvgHelper.cs
Normal file
39
Moonlight/App/Helpers/AvgHelper.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public static class AvgHelper
|
||||||
|
{
|
||||||
|
public static StatisticsData[] Calculate(StatisticsData[] data, int splitSize = 40)
|
||||||
|
{
|
||||||
|
if (data.Length <= splitSize)
|
||||||
|
return data;
|
||||||
|
|
||||||
|
var result = new List<StatisticsData>();
|
||||||
|
|
||||||
|
var i = data.Length / (float)splitSize;
|
||||||
|
var pc = (int)Math.Round(i);
|
||||||
|
|
||||||
|
foreach (var part in data.Chunk(pc))
|
||||||
|
{
|
||||||
|
double d = 0;
|
||||||
|
var res = new StatisticsData();
|
||||||
|
|
||||||
|
foreach (var entry in part)
|
||||||
|
{
|
||||||
|
d += entry.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Chart = part.First().Chart;
|
||||||
|
res.Date = part.First().Date;
|
||||||
|
|
||||||
|
if (d == 0)
|
||||||
|
res.Value = 0;
|
||||||
|
|
||||||
|
res.Value = d / part.Length;
|
||||||
|
result.Add(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ namespace Moonlight.App.Services.Sessions;
|
|||||||
public class SessionService
|
public class SessionService
|
||||||
{
|
{
|
||||||
private readonly SessionRepository SessionRepository;
|
private readonly SessionRepository SessionRepository;
|
||||||
|
private Repository<User> UserRepository;
|
||||||
private readonly IdentityService IdentityService;
|
private readonly IdentityService IdentityService;
|
||||||
private readonly NavigationManager NavigationManager;
|
private readonly NavigationManager NavigationManager;
|
||||||
private readonly AlertService AlertService;
|
private readonly AlertService AlertService;
|
||||||
@@ -21,13 +22,15 @@ public class SessionService
|
|||||||
IdentityService identityService,
|
IdentityService identityService,
|
||||||
NavigationManager navigationManager,
|
NavigationManager navigationManager,
|
||||||
AlertService alertService,
|
AlertService alertService,
|
||||||
DateTimeService dateTimeService)
|
DateTimeService dateTimeService,
|
||||||
|
Repository<User> userRepository)
|
||||||
{
|
{
|
||||||
SessionRepository = sessionRepository;
|
SessionRepository = sessionRepository;
|
||||||
IdentityService = identityService;
|
IdentityService = identityService;
|
||||||
NavigationManager = navigationManager;
|
NavigationManager = navigationManager;
|
||||||
AlertService = alertService;
|
AlertService = alertService;
|
||||||
DateTimeService = dateTimeService;
|
DateTimeService = dateTimeService;
|
||||||
|
UserRepository = userRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Register()
|
public async Task Register()
|
||||||
@@ -46,6 +49,12 @@ public class SessionService
|
|||||||
};
|
};
|
||||||
|
|
||||||
SessionRepository.Add(OwnSession);
|
SessionRepository.Add(OwnSession);
|
||||||
|
|
||||||
|
if (user != null) // Track last session init of user as last visited timestamp
|
||||||
|
{
|
||||||
|
user.LastVisitedAt = DateTimeService.GetCurrent();
|
||||||
|
UserRepository.Update(user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Refresh()
|
public void Refresh()
|
||||||
|
|||||||
@@ -7,20 +7,33 @@ namespace Moonlight.App.Services.Statistics;
|
|||||||
public class StatisticsViewService
|
public class StatisticsViewService
|
||||||
{
|
{
|
||||||
private readonly StatisticsRepository StatisticsRepository;
|
private readonly StatisticsRepository StatisticsRepository;
|
||||||
|
private readonly Repository<User> UserRepository;
|
||||||
private readonly DateTimeService DateTimeService;
|
private readonly DateTimeService DateTimeService;
|
||||||
|
|
||||||
public StatisticsViewService(StatisticsRepository statisticsRepository, DateTimeService dateTimeService)
|
public StatisticsViewService(StatisticsRepository statisticsRepository, DateTimeService dateTimeService, Repository<User> userRepository)
|
||||||
{
|
{
|
||||||
StatisticsRepository = statisticsRepository;
|
StatisticsRepository = statisticsRepository;
|
||||||
DateTimeService = dateTimeService;
|
DateTimeService = dateTimeService;
|
||||||
|
UserRepository = userRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StatisticsData[] GetData(string chart, StatisticsTimeSpan timeSpan)
|
public StatisticsData[] GetData(string chart, StatisticsTimeSpan timeSpan)
|
||||||
{
|
{
|
||||||
var startDate = DateTimeService.GetCurrent() - TimeSpan.FromHours((int)timeSpan);
|
var startDate = DateTimeService.GetCurrent() - TimeSpan.FromHours((int)timeSpan);
|
||||||
|
|
||||||
var objs = StatisticsRepository.Get().Where(x => x.Date > startDate && x.Chart == chart);
|
var objs = StatisticsRepository
|
||||||
|
.Get()
|
||||||
|
.Where(x => x.Date > startDate && x.Chart == chart);
|
||||||
|
|
||||||
return objs.ToArray();
|
return objs.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetActiveUsers(StatisticsTimeSpan timeSpan)
|
||||||
|
{
|
||||||
|
var startDate = DateTimeService.GetCurrent() - TimeSpan.FromHours((int)timeSpan);
|
||||||
|
|
||||||
|
return UserRepository
|
||||||
|
.Get()
|
||||||
|
.Count(x => x.LastVisitedAt > startDate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -66,6 +66,20 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="card mt-4">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title">
|
||||||
|
<TL>Active users</TL>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<span class="fs-2">@(ActiveUsers)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
</OnlyAdmin>
|
</OnlyAdmin>
|
||||||
|
|
||||||
@@ -73,7 +87,9 @@
|
|||||||
{
|
{
|
||||||
private StatisticsTimeSpan StatisticsTimeSpan = StatisticsTimeSpan.Day;
|
private StatisticsTimeSpan StatisticsTimeSpan = StatisticsTimeSpan.Day;
|
||||||
private LazyLoader Loader;
|
private LazyLoader Loader;
|
||||||
|
|
||||||
private Dictionary<string, StatisticsData[]> Charts = new();
|
private Dictionary<string, StatisticsData[]> Charts = new();
|
||||||
|
private int ActiveUsers = 0;
|
||||||
|
|
||||||
private int TimeSpanBind
|
private int TimeSpanBind
|
||||||
{
|
{
|
||||||
@@ -91,34 +107,48 @@
|
|||||||
|
|
||||||
Charts.Add(
|
Charts.Add(
|
||||||
SmartTranslateService.Translate("Servers"),
|
SmartTranslateService.Translate("Servers"),
|
||||||
StatisticsViewService.GetData("serversCount", StatisticsTimeSpan)
|
AvgHelper.Calculate(
|
||||||
|
StatisticsViewService.GetData("serversCount", StatisticsTimeSpan)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
Charts.Add(
|
Charts.Add(
|
||||||
SmartTranslateService.Translate("Users"),
|
SmartTranslateService.Translate("Users"),
|
||||||
StatisticsViewService.GetData("usersCount", StatisticsTimeSpan)
|
AvgHelper.Calculate(
|
||||||
|
StatisticsViewService.GetData("usersCount", StatisticsTimeSpan)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
Charts.Add(
|
Charts.Add(
|
||||||
SmartTranslateService.Translate("Domains"),
|
SmartTranslateService.Translate("Domains"),
|
||||||
StatisticsViewService.GetData("domainsCount", StatisticsTimeSpan)
|
AvgHelper.Calculate(
|
||||||
|
StatisticsViewService.GetData("domainsCount", StatisticsTimeSpan)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
Charts.Add(
|
Charts.Add(
|
||||||
SmartTranslateService.Translate("Databases"),
|
SmartTranslateService.Translate("Databases"),
|
||||||
StatisticsViewService.GetData("databasesCount", StatisticsTimeSpan)
|
AvgHelper.Calculate(
|
||||||
|
StatisticsViewService.GetData("databasesCount", StatisticsTimeSpan)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
Charts.Add(
|
Charts.Add(
|
||||||
SmartTranslateService.Translate("Webspaces"),
|
SmartTranslateService.Translate("Webspaces"),
|
||||||
StatisticsViewService.GetData("webspacesCount", StatisticsTimeSpan)
|
AvgHelper.Calculate(
|
||||||
|
StatisticsViewService.GetData("webspacesCount", StatisticsTimeSpan)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
Charts.Add(
|
Charts.Add(
|
||||||
SmartTranslateService.Translate("Sessions"),
|
SmartTranslateService.Translate("Sessions"),
|
||||||
StatisticsViewService.GetData("sessionsCount", StatisticsTimeSpan)
|
AvgHelper.Calculate(
|
||||||
|
StatisticsViewService.GetData("sessionsCount", StatisticsTimeSpan)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ActiveUsers = StatisticsViewService.GetActiveUsers(StatisticsTimeSpan);
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user