feat: добавил каталог достижений и автоначисление
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 10s
🚀 Create and publish a Docker image / Build & publish backend image (push) Successful in 2m53s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Successful in 28s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Successful in 7s
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 10s
🚀 Create and publish a Docker image / Build & publish backend image (push) Successful in 2m53s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Successful in 28s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Successful in 7s
Реализовал автосоздание и обновление каталога достижений на бэке и синхронизацию на фронте.
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using UniVerse.Domain.Entities;
|
||||
using UniVerse.Domain.Enums;
|
||||
using UniVerse.Infrastructure.Data;
|
||||
using UniVerse.Infrastructure.Services;
|
||||
using Xunit;
|
||||
|
||||
namespace UniVerse.Api.Tests.Gamification;
|
||||
|
||||
public class GamificationServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task CheckAndAwardAchievementsAsync_AwardsModernConditionsOnce()
|
||||
{
|
||||
await using var db = CreateDbContext();
|
||||
var service = CreateService(db);
|
||||
|
||||
db.Users.Add(new User
|
||||
{
|
||||
Id = 1,
|
||||
Email = "student@test.local",
|
||||
DisplayName = "Student",
|
||||
AvatarUrl = "avatar.png",
|
||||
Xp = 100,
|
||||
Coins = 510
|
||||
});
|
||||
db.Courses.Add(new Course { Id = 1, Name = "Course" });
|
||||
db.Lectures.Add(new Lecture
|
||||
{
|
||||
Id = 1,
|
||||
CourseId = 1,
|
||||
Title = "Future lecture",
|
||||
StartsAt = DateTime.UtcNow.AddDays(1),
|
||||
EndsAt = DateTime.UtcNow.AddDays(1).AddHours(2),
|
||||
IsOpen = true
|
||||
});
|
||||
db.LectureEnrollments.Add(new LectureEnrollment { UserId = 1, LectureId = 1 });
|
||||
db.Reviews.AddRange(
|
||||
new Review { Id = 1, UserId = 1, LectureId = 1, Rating = ReviewRating.Like },
|
||||
new Review { Id = 2, UserId = 1, LectureId = 1, Rating = ReviewRating.Neutral },
|
||||
new Review { Id = 3, UserId = 1, LectureId = 1, Rating = ReviewRating.Dislike });
|
||||
db.CoinTransactions.Add(new CoinTransaction
|
||||
{
|
||||
UserId = 1,
|
||||
Amount = 510,
|
||||
Type = CoinTransactionType.AdminAdjustment,
|
||||
Description = "Initial coins"
|
||||
});
|
||||
db.Achievements.AddRange(
|
||||
Achievement(1001, "First activity", "first_activity:1", 10),
|
||||
Achievement(1002, "Reviews", "reviews_written:3", 20),
|
||||
Achievement(1003, "Active registrations", "active_registrations:1", 30),
|
||||
Achievement(1004, "Coins earned", "coins_earned:500", 40),
|
||||
Achievement(1005, "Level reached", "level_reached:2", 50),
|
||||
Achievement(1006, "Profile completed", "profile_completed:1", 60),
|
||||
Achievement(1007, "Old condition", "reviews_1", 100));
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
await service.CheckAndAwardAchievementsAsync(1);
|
||||
await service.CheckAndAwardAchievementsAsync(1);
|
||||
|
||||
var user = await db.Users.FindAsync(1);
|
||||
Assert.NotNull(user);
|
||||
Assert.Equal(720, user!.Coins);
|
||||
Assert.Equal(310, user.Xp);
|
||||
Assert.Equal(6, await db.UserAchievements.CountAsync(ua => ua.UserId == 1));
|
||||
Assert.False(await db.UserAchievements.AnyAsync(ua => ua.AchievementId == 1007));
|
||||
Assert.Equal(6, await db.CoinTransactions.CountAsync(ct =>
|
||||
ct.UserId == 1 && ct.Type == CoinTransactionType.AchievementReward));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CheckAndAwardAchievementsAsync_CountsConsecutiveIsoWeeksAcrossYears()
|
||||
{
|
||||
await using var db = CreateDbContext();
|
||||
var service = CreateService(db);
|
||||
|
||||
db.Users.Add(new User { Id = 1, Email = "student@test.local" });
|
||||
db.Courses.Add(new Course { Id = 1, Name = "Course" });
|
||||
db.Lectures.AddRange(
|
||||
Lecture(1, new DateTime(2025, 12, 29, 10, 0, 0, DateTimeKind.Utc)),
|
||||
Lecture(2, new DateTime(2026, 1, 5, 10, 0, 0, DateTimeKind.Utc)),
|
||||
Lecture(3, new DateTime(2026, 1, 12, 10, 0, 0, DateTimeKind.Utc)));
|
||||
db.LectureEnrollments.AddRange(
|
||||
new LectureEnrollment { UserId = 1, LectureId = 1, Attended = true },
|
||||
new LectureEnrollment { UserId = 1, LectureId = 2, Attended = true },
|
||||
new LectureEnrollment { UserId = 1, LectureId = 3, Attended = true });
|
||||
db.Achievements.Add(Achievement(1001, "Streak", "attendance_streak_weeks:3", 10));
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
await service.CheckAndAwardAchievementsAsync(1);
|
||||
|
||||
Assert.True(await db.UserAchievements.AnyAsync(ua => ua.UserId == 1 && ua.AchievementId == 1001));
|
||||
}
|
||||
|
||||
private static AppDbContext CreateDbContext()
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<AppDbContext>()
|
||||
.UseInMemoryDatabase($"GamificationTests_{Guid.NewGuid()}")
|
||||
.Options;
|
||||
return new AppDbContext(options);
|
||||
}
|
||||
|
||||
private static GamificationService CreateService(AppDbContext db)
|
||||
{
|
||||
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, configuration, NullLogger<GamificationService>.Instance);
|
||||
}
|
||||
|
||||
private static Achievement Achievement(int id, string name, string condition, int coinReward) => new()
|
||||
{
|
||||
Id = id,
|
||||
Name = name,
|
||||
Condition = condition,
|
||||
CoinReward = coinReward
|
||||
};
|
||||
|
||||
private static Lecture Lecture(int id, DateTime startsAt) => new()
|
||||
{
|
||||
Id = id,
|
||||
CourseId = 1,
|
||||
Title = $"Lecture {id}",
|
||||
StartsAt = startsAt,
|
||||
EndsAt = startsAt.AddHours(2)
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user