From 25d617639cfc3f033b0bc9792574bb969c815263 Mon Sep 17 00:00:00 2001 From: Sergey Karmanov Date: Tue, 28 Apr 2026 15:52:05 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=BC=D0=B5=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UniVerse.Domain/Entities/Achievement.cs | 16 ++++++++++ .../Entities/CoinTransaction.cs | 20 +++++++++++++ backend/UniVerse.Domain/Entities/Course.cs | 16 ++++++++++ backend/UniVerse.Domain/Entities/CourseTag.cs | 12 ++++++++ backend/UniVerse.Domain/Entities/Lecture.cs | 29 +++++++++++++++++++ .../Entities/LectureEnrollment.cs | 14 +++++++++ backend/UniVerse.Domain/Entities/Location.cs | 15 ++++++++++ .../UniVerse.Domain/Entities/RefreshToken.cs | 18 ++++++++++++ backend/UniVerse.Domain/Entities/Review.cs | 24 +++++++++++++++ .../Entities/StudentProfile.cs | 15 ++++++++++ backend/UniVerse.Domain/Entities/Tag.cs | 17 +++++++++++ .../Entities/TeacherProfile.cs | 14 +++++++++ backend/UniVerse.Domain/Entities/User.cs | 27 +++++++++++++++++ .../Entities/UserAchievement.cs | 13 +++++++++ .../Enums/CoinTransactionType.cs | 9 ++++++ .../UniVerse.Domain/Enums/LectureFormat.cs | 7 +++++ .../UniVerse.Domain/Enums/ReviewLlmStatus.cs | 8 +++++ backend/UniVerse.Domain/Enums/ReviewRating.cs | 8 +++++ .../UniVerse.Domain/Enums/ReviewSentiment.cs | 8 +++++ backend/UniVerse.Domain/Enums/TagType.cs | 11 +++++++ backend/UniVerse.Domain/Enums/UserRole.cs | 8 +++++ .../Exceptions/ConflictException.cs | 8 +++++ .../Exceptions/ForbiddenException.cs | 9 ++++++ .../Exceptions/NotFoundException.cs | 13 +++++++++ .../UniVerse.Domain/UniVerse.Domain.csproj | 10 +++++++ 25 files changed, 349 insertions(+) create mode 100644 backend/UniVerse.Domain/Entities/Achievement.cs create mode 100644 backend/UniVerse.Domain/Entities/CoinTransaction.cs create mode 100644 backend/UniVerse.Domain/Entities/Course.cs create mode 100644 backend/UniVerse.Domain/Entities/CourseTag.cs create mode 100644 backend/UniVerse.Domain/Entities/Lecture.cs create mode 100644 backend/UniVerse.Domain/Entities/LectureEnrollment.cs create mode 100644 backend/UniVerse.Domain/Entities/Location.cs create mode 100644 backend/UniVerse.Domain/Entities/RefreshToken.cs create mode 100644 backend/UniVerse.Domain/Entities/Review.cs create mode 100644 backend/UniVerse.Domain/Entities/StudentProfile.cs create mode 100644 backend/UniVerse.Domain/Entities/Tag.cs create mode 100644 backend/UniVerse.Domain/Entities/TeacherProfile.cs create mode 100644 backend/UniVerse.Domain/Entities/User.cs create mode 100644 backend/UniVerse.Domain/Entities/UserAchievement.cs create mode 100644 backend/UniVerse.Domain/Enums/CoinTransactionType.cs create mode 100644 backend/UniVerse.Domain/Enums/LectureFormat.cs create mode 100644 backend/UniVerse.Domain/Enums/ReviewLlmStatus.cs create mode 100644 backend/UniVerse.Domain/Enums/ReviewRating.cs create mode 100644 backend/UniVerse.Domain/Enums/ReviewSentiment.cs create mode 100644 backend/UniVerse.Domain/Enums/TagType.cs create mode 100644 backend/UniVerse.Domain/Enums/UserRole.cs create mode 100644 backend/UniVerse.Domain/Exceptions/ConflictException.cs create mode 100644 backend/UniVerse.Domain/Exceptions/ForbiddenException.cs create mode 100644 backend/UniVerse.Domain/Exceptions/NotFoundException.cs create mode 100644 backend/UniVerse.Domain/UniVerse.Domain.csproj diff --git a/backend/UniVerse.Domain/Entities/Achievement.cs b/backend/UniVerse.Domain/Entities/Achievement.cs new file mode 100644 index 0000000..e17c88d --- /dev/null +++ b/backend/UniVerse.Domain/Entities/Achievement.cs @@ -0,0 +1,16 @@ +namespace UniVerse.Domain.Entities; + +public class Achievement +{ + public int Id { get; set; } + public string Name { get; set; } = string.Empty; + public string? Description { get; set; } + public string? IconUrl { get; set; } + public int XpReward { get; set; } + public int CoinReward { get; set; } + public string? Condition { get; set; } + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + + // Navigation properties + public ICollection UserAchievements { get; set; } = new List(); +} diff --git a/backend/UniVerse.Domain/Entities/CoinTransaction.cs b/backend/UniVerse.Domain/Entities/CoinTransaction.cs new file mode 100644 index 0000000..457f2db --- /dev/null +++ b/backend/UniVerse.Domain/Entities/CoinTransaction.cs @@ -0,0 +1,20 @@ +using UniVerse.Domain.Enums; + +namespace UniVerse.Domain.Entities; + +public class CoinTransaction +{ + public int Id { get; set; } + public int UserId { get; set; } + public int Amount { get; set; } + public CoinTransactionType Type { get; set; } + public int? ReviewId { get; set; } + public int? AchievementId { get; set; } + public string? Description { get; set; } + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + + // Navigation properties + public User User { get; set; } = null!; + public Review? Review { get; set; } + public Achievement? Achievement { get; set; } +} diff --git a/backend/UniVerse.Domain/Entities/Course.cs b/backend/UniVerse.Domain/Entities/Course.cs new file mode 100644 index 0000000..3825db9 --- /dev/null +++ b/backend/UniVerse.Domain/Entities/Course.cs @@ -0,0 +1,16 @@ +namespace UniVerse.Domain.Entities; + +public class Course +{ + public int Id { get; set; } + public string Name { get; set; } = string.Empty; + public string? Description { get; set; } + public string? ExternalId { get; set; } + public bool IsSynced { get; set; } + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; + + // Navigation properties + public ICollection Lectures { get; set; } = new List(); + public ICollection CourseTags { get; set; } = new List(); +} diff --git a/backend/UniVerse.Domain/Entities/CourseTag.cs b/backend/UniVerse.Domain/Entities/CourseTag.cs new file mode 100644 index 0000000..4c15c51 --- /dev/null +++ b/backend/UniVerse.Domain/Entities/CourseTag.cs @@ -0,0 +1,12 @@ +namespace UniVerse.Domain.Entities; + +public class CourseTag +{ + public int Id { get; set; } + public int CourseId { get; set; } + public int TagId { get; set; } + + // Navigation properties + public Course Course { get; set; } = null!; + public Tag Tag { get; set; } = null!; +} diff --git a/backend/UniVerse.Domain/Entities/Lecture.cs b/backend/UniVerse.Domain/Entities/Lecture.cs new file mode 100644 index 0000000..37a732b --- /dev/null +++ b/backend/UniVerse.Domain/Entities/Lecture.cs @@ -0,0 +1,29 @@ +using UniVerse.Domain.Enums; + +namespace UniVerse.Domain.Entities; + +public class Lecture +{ + public int Id { get; set; } + public int CourseId { get; set; } + public int? TeacherId { get; set; } + public int? LocationId { get; set; } + public string Title { get; set; } = string.Empty; + public string? Description { get; set; } + public LectureFormat Format { get; set; } = LectureFormat.Offline; + public DateTime StartsAt { get; set; } + public DateTime EndsAt { get; set; } + public bool IsOpen { get; set; } = true; + public int MaxEnrollments { get; set; } + public string? ExternalId { get; set; } + public string? OnlineUrl { get; set; } + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; + + // Navigation properties + public Course Course { get; set; } = null!; + public User? Teacher { get; set; } + public Location? Location { get; set; } + public ICollection Enrollments { get; set; } = new List(); + public ICollection Reviews { get; set; } = new List(); +} diff --git a/backend/UniVerse.Domain/Entities/LectureEnrollment.cs b/backend/UniVerse.Domain/Entities/LectureEnrollment.cs new file mode 100644 index 0000000..712f757 --- /dev/null +++ b/backend/UniVerse.Domain/Entities/LectureEnrollment.cs @@ -0,0 +1,14 @@ +namespace UniVerse.Domain.Entities; + +public class LectureEnrollment +{ + public int Id { get; set; } + public int LectureId { get; set; } + public int UserId { get; set; } + public bool Attended { get; set; } + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + + // Navigation properties + public Lecture Lecture { get; set; } = null!; + public User User { get; set; } = null!; +} diff --git a/backend/UniVerse.Domain/Entities/Location.cs b/backend/UniVerse.Domain/Entities/Location.cs new file mode 100644 index 0000000..18c9339 --- /dev/null +++ b/backend/UniVerse.Domain/Entities/Location.cs @@ -0,0 +1,15 @@ +namespace UniVerse.Domain.Entities; + +public class Location +{ + public int Id { get; set; } + public string Name { get; set; } = string.Empty; + public string? Building { get; set; } + public string? Room { get; set; } + public string? Address { get; set; } + public string? ExternalId { get; set; } + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + + // Navigation properties + public ICollection Lectures { get; set; } = new List(); +} diff --git a/backend/UniVerse.Domain/Entities/RefreshToken.cs b/backend/UniVerse.Domain/Entities/RefreshToken.cs new file mode 100644 index 0000000..486ace4 --- /dev/null +++ b/backend/UniVerse.Domain/Entities/RefreshToken.cs @@ -0,0 +1,18 @@ +namespace UniVerse.Domain.Entities; + +public class RefreshToken +{ + public int Id { get; set; } + public int UserId { get; set; } + public string Token { get; set; } = string.Empty; + public DateTime ExpiresAt { get; set; } + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + public DateTime? RevokedAt { get; set; } + + public bool IsExpired => DateTime.UtcNow >= ExpiresAt; + public bool IsRevoked => RevokedAt != null; + public bool IsActive => !IsRevoked && !IsExpired; + + // Navigation properties + public User User { get; set; } = null!; +} diff --git a/backend/UniVerse.Domain/Entities/Review.cs b/backend/UniVerse.Domain/Entities/Review.cs new file mode 100644 index 0000000..9883dcd --- /dev/null +++ b/backend/UniVerse.Domain/Entities/Review.cs @@ -0,0 +1,24 @@ +using UniVerse.Domain.Enums; + +namespace UniVerse.Domain.Entities; + +public class Review +{ + public int Id { get; set; } + public int LectureId { get; set; } + public int UserId { get; set; } + public ReviewRating Rating { get; set; } + public string? Text { get; set; } + public ReviewLlmStatus LlmStatus { get; set; } = ReviewLlmStatus.Pending; + public ReviewSentiment? Sentiment { get; set; } + public double? QualityScore { get; set; } + public bool? IsInformative { get; set; } + public string[]? LlmTags { get; set; } + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; + + // Navigation properties + public Lecture Lecture { get; set; } = null!; + public User User { get; set; } = null!; + public ICollection CoinTransactions { get; set; } = new List(); +} diff --git a/backend/UniVerse.Domain/Entities/StudentProfile.cs b/backend/UniVerse.Domain/Entities/StudentProfile.cs new file mode 100644 index 0000000..1e47b76 --- /dev/null +++ b/backend/UniVerse.Domain/Entities/StudentProfile.cs @@ -0,0 +1,15 @@ +namespace UniVerse.Domain.Entities; + +public class StudentProfile +{ + public int Id { get; set; } + public int UserId { get; set; } + public string? StudentId { get; set; } + public string? GroupName { get; set; } + public int? EnrollmentYear { get; set; } + public string? Faculty { get; set; } + public string? Specialty { get; set; } + + // Navigation properties + public User User { get; set; } = null!; +} diff --git a/backend/UniVerse.Domain/Entities/Tag.cs b/backend/UniVerse.Domain/Entities/Tag.cs new file mode 100644 index 0000000..56b804a --- /dev/null +++ b/backend/UniVerse.Domain/Entities/Tag.cs @@ -0,0 +1,17 @@ +using UniVerse.Domain.Enums; + +namespace UniVerse.Domain.Entities; + +public class Tag +{ + public int Id { get; set; } + public string Name { get; set; } = string.Empty; + public TagType Type { get; set; } + public int? ParentId { get; set; } + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + + // Navigation properties + public Tag? Parent { get; set; } + public ICollection Children { get; set; } = new List(); + public ICollection CourseTags { get; set; } = new List(); +} diff --git a/backend/UniVerse.Domain/Entities/TeacherProfile.cs b/backend/UniVerse.Domain/Entities/TeacherProfile.cs new file mode 100644 index 0000000..8766ec0 --- /dev/null +++ b/backend/UniVerse.Domain/Entities/TeacherProfile.cs @@ -0,0 +1,14 @@ +namespace UniVerse.Domain.Entities; + +public class TeacherProfile +{ + public int Id { get; set; } + public int UserId { get; set; } + public string? Department { get; set; } + public string? Title { get; set; } + public string? Bio { get; set; } + public string? ModeusId { get; set; } + + // Navigation properties + public User User { get; set; } = null!; +} diff --git a/backend/UniVerse.Domain/Entities/User.cs b/backend/UniVerse.Domain/Entities/User.cs new file mode 100644 index 0000000..d7893de --- /dev/null +++ b/backend/UniVerse.Domain/Entities/User.cs @@ -0,0 +1,27 @@ +using UniVerse.Domain.Enums; + +namespace UniVerse.Domain.Entities; + +public class User +{ + public int Id { get; set; } + public string Email { get; set; } = string.Empty; + public string? DisplayName { get; set; } + public string? AvatarUrl { get; set; } + public UserRole Role { get; set; } = UserRole.Student; + public bool IsActive { get; set; } = true; + public string? MicrosoftId { get; set; } + public int Xp { get; set; } + public int Coins { get; set; } + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; + + // Navigation properties + public StudentProfile? StudentProfile { get; set; } + public TeacherProfile? TeacherProfile { get; set; } + public ICollection Enrollments { get; set; } = new List(); + public ICollection Reviews { get; set; } = new List(); + public ICollection UserAchievements { get; set; } = new List(); + public ICollection CoinTransactions { get; set; } = new List(); + public ICollection RefreshTokens { get; set; } = new List(); +} diff --git a/backend/UniVerse.Domain/Entities/UserAchievement.cs b/backend/UniVerse.Domain/Entities/UserAchievement.cs new file mode 100644 index 0000000..6f3fcd1 --- /dev/null +++ b/backend/UniVerse.Domain/Entities/UserAchievement.cs @@ -0,0 +1,13 @@ +namespace UniVerse.Domain.Entities; + +public class UserAchievement +{ + public int Id { get; set; } + public int UserId { get; set; } + public int AchievementId { get; set; } + public DateTime AwardedAt { get; set; } = DateTime.UtcNow; + + // Navigation properties + public User User { get; set; } = null!; + public Achievement Achievement { get; set; } = null!; +} diff --git a/backend/UniVerse.Domain/Enums/CoinTransactionType.cs b/backend/UniVerse.Domain/Enums/CoinTransactionType.cs new file mode 100644 index 0000000..0654fbe --- /dev/null +++ b/backend/UniVerse.Domain/Enums/CoinTransactionType.cs @@ -0,0 +1,9 @@ +namespace UniVerse.Domain.Enums; + +public enum CoinTransactionType +{ + ReviewReward, + AchievementReward, + AttendanceReward, + AdminAdjustment +} diff --git a/backend/UniVerse.Domain/Enums/LectureFormat.cs b/backend/UniVerse.Domain/Enums/LectureFormat.cs new file mode 100644 index 0000000..738d9d8 --- /dev/null +++ b/backend/UniVerse.Domain/Enums/LectureFormat.cs @@ -0,0 +1,7 @@ +namespace UniVerse.Domain.Enums; + +public enum LectureFormat +{ + Online, + Offline +} diff --git a/backend/UniVerse.Domain/Enums/ReviewLlmStatus.cs b/backend/UniVerse.Domain/Enums/ReviewLlmStatus.cs new file mode 100644 index 0000000..937b0ef --- /dev/null +++ b/backend/UniVerse.Domain/Enums/ReviewLlmStatus.cs @@ -0,0 +1,8 @@ +namespace UniVerse.Domain.Enums; + +public enum ReviewLlmStatus +{ + Pending, + Analyzed, + Rejected +} diff --git a/backend/UniVerse.Domain/Enums/ReviewRating.cs b/backend/UniVerse.Domain/Enums/ReviewRating.cs new file mode 100644 index 0000000..e5d9f23 --- /dev/null +++ b/backend/UniVerse.Domain/Enums/ReviewRating.cs @@ -0,0 +1,8 @@ +namespace UniVerse.Domain.Enums; + +public enum ReviewRating +{ + Like, + Neutral, + Dislike +} diff --git a/backend/UniVerse.Domain/Enums/ReviewSentiment.cs b/backend/UniVerse.Domain/Enums/ReviewSentiment.cs new file mode 100644 index 0000000..c3b6964 --- /dev/null +++ b/backend/UniVerse.Domain/Enums/ReviewSentiment.cs @@ -0,0 +1,8 @@ +namespace UniVerse.Domain.Enums; + +public enum ReviewSentiment +{ + Positive, + Neutral, + Negative +} diff --git a/backend/UniVerse.Domain/Enums/TagType.cs b/backend/UniVerse.Domain/Enums/TagType.cs new file mode 100644 index 0000000..caef984 --- /dev/null +++ b/backend/UniVerse.Domain/Enums/TagType.cs @@ -0,0 +1,11 @@ +namespace UniVerse.Domain.Enums; + +public enum TagType +{ + Institute, + Faculty, + Subject, + Organization, + Topic, + Other +} diff --git a/backend/UniVerse.Domain/Enums/UserRole.cs b/backend/UniVerse.Domain/Enums/UserRole.cs new file mode 100644 index 0000000..b664823 --- /dev/null +++ b/backend/UniVerse.Domain/Enums/UserRole.cs @@ -0,0 +1,8 @@ +namespace UniVerse.Domain.Enums; + +public enum UserRole +{ + Student, + Teacher, + Admin +} diff --git a/backend/UniVerse.Domain/Exceptions/ConflictException.cs b/backend/UniVerse.Domain/Exceptions/ConflictException.cs new file mode 100644 index 0000000..500fe71 --- /dev/null +++ b/backend/UniVerse.Domain/Exceptions/ConflictException.cs @@ -0,0 +1,8 @@ +namespace UniVerse.Domain.Exceptions; + +public class ConflictException : Exception +{ + public ConflictException(string message) : base(message) + { + } +} diff --git a/backend/UniVerse.Domain/Exceptions/ForbiddenException.cs b/backend/UniVerse.Domain/Exceptions/ForbiddenException.cs new file mode 100644 index 0000000..1188d6a --- /dev/null +++ b/backend/UniVerse.Domain/Exceptions/ForbiddenException.cs @@ -0,0 +1,9 @@ +namespace UniVerse.Domain.Exceptions; + +public class ForbiddenException : Exception +{ + public ForbiddenException(string message = "You do not have permission to perform this action.") + : base(message) + { + } +} diff --git a/backend/UniVerse.Domain/Exceptions/NotFoundException.cs b/backend/UniVerse.Domain/Exceptions/NotFoundException.cs new file mode 100644 index 0000000..9651bd1 --- /dev/null +++ b/backend/UniVerse.Domain/Exceptions/NotFoundException.cs @@ -0,0 +1,13 @@ +namespace UniVerse.Domain.Exceptions; + +public class NotFoundException : Exception +{ + public NotFoundException(string entityName, object key) + : base($"{entityName} with key '{key}' was not found.") + { + } + + public NotFoundException(string message) : base(message) + { + } +} diff --git a/backend/UniVerse.Domain/UniVerse.Domain.csproj b/backend/UniVerse.Domain/UniVerse.Domain.csproj new file mode 100644 index 0000000..e450d5e --- /dev/null +++ b/backend/UniVerse.Domain/UniVerse.Domain.csproj @@ -0,0 +1,10 @@ + + + + net10.0 + enable + enable + UniVerse.Domain + + +