fix: перенёс уровни в бд и пофиксид их отображение на фронте
Backend CI / build-and-test (push) Successful in 52s
Frontend CI / build-and-check (push) Failing after 5m15s
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 16s
🚀 Create and publish a Docker image / Build & publish backend image (push) Successful in 1m0s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Successful in 32s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Successful in 13s

This commit is contained in:
2026-05-18 02:28:05 +03:00
parent 302e01d705
commit 811b6ef51a
27 changed files with 1526 additions and 51 deletions
@@ -1,5 +1,4 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging.Abstractions;
using NSubstitute;
using UniVerse.Application.DTOs.Notifications;
@@ -18,6 +17,7 @@ public class GamificationServiceTests
public async Task CheckAndAwardAchievementsAsync_AwardsModernConditionsOnce()
{
await using var db = CreateDbContext();
SeedLevelThresholds(db);
var service = CreateService(db);
db.Users.Add(new User
@@ -78,6 +78,7 @@ public class GamificationServiceTests
public async Task CheckAndAwardAchievementsAsync_CountsConsecutiveIsoWeeksAcrossYears()
{
await using var db = CreateDbContext();
SeedLevelThresholds(db);
var service = CreateService(db);
db.Users.Add(new User { Id = 1, Email = "student@test.local" });
@@ -98,6 +99,38 @@ public class GamificationServiceTests
Assert.True(await db.UserAchievements.AnyAsync(ua => ua.UserId == 1 && ua.AchievementId == 1001));
}
[Theory]
[InlineData(0, 1)]
[InlineData(99, 1)]
[InlineData(100, 2)]
[InlineData(299, 2)]
[InlineData(300, 3)]
public async Task CalculateLevelAsync_UsesDatabaseThresholds(int xp, int expectedLevel)
{
await using var db = CreateDbContext();
SeedLevelThresholds(db);
var service = CreateService(db);
var level = await service.CalculateLevelAsync(xp);
Assert.Equal(expectedLevel, level);
}
[Theory]
[InlineData(120, 100, 300)]
[InlineData(350, 300, null)]
public async Task GetLevelProgressAsync_ReturnsCurrentAndNextThresholds(int xp, int currentLevelXp, int? nextLevelXp)
{
await using var db = CreateDbContext();
SeedLevelThresholds(db);
var service = CreateService(db);
var progress = await service.GetLevelProgressAsync(xp);
Assert.Equal(currentLevelXp, progress.CurrentLevelXp);
Assert.Equal(nextLevelXp, progress.NextLevelXp);
}
private static AppDbContext CreateDbContext()
{
var options = new DbContextOptionsBuilder<AppDbContext>()
@@ -119,16 +152,16 @@ public class GamificationServiceTests
notifications.SendAsync(Arg.Any<NotificationMessage>(), Arg.Any<CancellationToken>())
.Returns(Task.CompletedTask);
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["Gamification:XpThresholds:0"] = "0",
["Gamification:XpThresholds:1"] = "100",
["Gamification:XpThresholds:2"] = "300"
})
.Build();
return new GamificationService(db, notifications, NullLogger<GamificationService>.Instance);
}
return new GamificationService(db, configuration, notifications, NullLogger<GamificationService>.Instance);
private static void SeedLevelThresholds(AppDbContext db)
{
db.LevelThresholds.AddRange(
new LevelThreshold { Level = 1, RequiredXp = 0 },
new LevelThreshold { Level = 2, RequiredXp = 100 },
new LevelThreshold { Level = 3, RequiredXp = 300 });
db.SaveChanges();
}
private static Achievement Achievement(int id, string name, string condition, int coinReward) => new()