Merge pull request #158 from Moonlight-Panel/ImproveStatistics

Added better statistics calculation and active user messurement
This commit is contained in:
Marcel Baumgartner
2023-06-11 17:57:01 +02:00
committed by GitHub
8 changed files with 1193 additions and 9 deletions

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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");
}
}
}

View File

@@ -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");

View 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();
}
}

View File

@@ -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()

View File

@@ -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);
}
} }

View File

@@ -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"),
AvgHelper.Calculate(
StatisticsViewService.GetData("serversCount", StatisticsTimeSpan) StatisticsViewService.GetData("serversCount", StatisticsTimeSpan)
)
); );
Charts.Add( Charts.Add(
SmartTranslateService.Translate("Users"), SmartTranslateService.Translate("Users"),
AvgHelper.Calculate(
StatisticsViewService.GetData("usersCount", StatisticsTimeSpan) StatisticsViewService.GetData("usersCount", StatisticsTimeSpan)
)
); );
Charts.Add( Charts.Add(
SmartTranslateService.Translate("Domains"), SmartTranslateService.Translate("Domains"),
AvgHelper.Calculate(
StatisticsViewService.GetData("domainsCount", StatisticsTimeSpan) StatisticsViewService.GetData("domainsCount", StatisticsTimeSpan)
)
); );
Charts.Add( Charts.Add(
SmartTranslateService.Translate("Databases"), SmartTranslateService.Translate("Databases"),
AvgHelper.Calculate(
StatisticsViewService.GetData("databasesCount", StatisticsTimeSpan) StatisticsViewService.GetData("databasesCount", StatisticsTimeSpan)
)
); );
Charts.Add( Charts.Add(
SmartTranslateService.Translate("Webspaces"), SmartTranslateService.Translate("Webspaces"),
AvgHelper.Calculate(
StatisticsViewService.GetData("webspacesCount", StatisticsTimeSpan) StatisticsViewService.GetData("webspacesCount", StatisticsTimeSpan)
)
); );
Charts.Add( Charts.Add(
SmartTranslateService.Translate("Sessions"), SmartTranslateService.Translate("Sessions"),
AvgHelper.Calculate(
StatisticsViewService.GetData("sessionsCount", StatisticsTimeSpan) StatisticsViewService.GetData("sessionsCount", StatisticsTimeSpan)
)
); );
ActiveUsers = StatisticsViewService.GetActiveUsers(StatisticsTimeSpan);
return Task.CompletedTask; return Task.CompletedTask;
} }