Добавил слой Infrastructure

This commit is contained in:
2026-04-28 15:52:19 +03:00
parent 25d617639c
commit df0e30a1ae
32 changed files with 4139 additions and 0 deletions
@@ -0,0 +1,62 @@
using Microsoft.EntityFrameworkCore;
using Npgsql;
using UniVerse.Domain.Entities;
using UniVerse.Domain.Enums;
namespace UniVerse.Infrastructure.Data;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<User> Users { get; set; } = null!;
public DbSet<StudentProfile> StudentProfiles { get; set; } = null!;
public DbSet<TeacherProfile> TeacherProfiles { get; set; } = null!;
public DbSet<Course> Courses { get; set; } = null!;
public DbSet<Lecture> Lectures { get; set; } = null!;
public DbSet<Location> Locations { get; set; } = null!;
public DbSet<Tag> Tags { get; set; } = null!;
public DbSet<CourseTag> CourseTags { get; set; } = null!;
public DbSet<LectureEnrollment> LectureEnrollments { get; set; } = null!;
public DbSet<Review> Reviews { get; set; } = null!;
public DbSet<Achievement> Achievements { get; set; } = null!;
public DbSet<UserAchievement> UserAchievements { get; set; } = null!;
public DbSet<CoinTransaction> CoinTransactions { get; set; } = null!;
public DbSet<RefreshToken> RefreshTokens { get; set; } = null!;
static AppDbContext()
{
NpgsqlConnection.GlobalTypeMapper.MapEnum<UserRole>("user_role");
NpgsqlConnection.GlobalTypeMapper.MapEnum<TagType>("tag_type");
NpgsqlConnection.GlobalTypeMapper.MapEnum<ReviewLlmStatus>("review_llm_status");
NpgsqlConnection.GlobalTypeMapper.MapEnum<ReviewSentiment>("review_sentiment");
NpgsqlConnection.GlobalTypeMapper.MapEnum<CoinTransactionType>("coin_transaction_type");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasPostgresEnum<UserRole>("user_role");
modelBuilder.HasPostgresEnum<TagType>("tag_type");
modelBuilder.HasPostgresEnum<ReviewLlmStatus>("review_llm_status");
modelBuilder.HasPostgresEnum<ReviewSentiment>("review_sentiment");
modelBuilder.HasPostgresEnum<CoinTransactionType>("coin_transaction_type");
modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
// Basic PK setups if they weren't fully in assembly
modelBuilder.Entity<CourseTag>().HasKey(ct => new { ct.CourseId, ct.TagId });
modelBuilder.Entity<LectureEnrollment>().HasKey(le => new { le.LectureId, le.UserId });
modelBuilder.Entity<UserAchievement>().HasKey(ua => new { ua.UserId, ua.AchievementId });
foreach (var entity in modelBuilder.Model.GetEntityTypes())
{
entity.SetTableName(entity.GetTableName()?.ToLowerInvariant());
foreach (var property in entity.GetProperties())
{
property.SetColumnName(string.Concat(property.Name.Select((x, i) => i > 0 && char.IsUpper(x) ? "_" + x.ToString() : x.ToString())).ToLowerInvariant());
}
}
}
}
@@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using UniVerse.Domain.Entities;
namespace UniVerse.Infrastructure.Data.Configurations;
public class AchievementConfiguration : IEntityTypeConfiguration<Achievement>
{
public void Configure(EntityTypeBuilder<Achievement> builder)
{
builder.ToTable("achievements");
builder.HasKey(a => a.Id);
builder.Property(a => a.Id).HasColumnName("id");
builder.Property(a => a.Name).HasColumnName("name").HasMaxLength(255).IsRequired();
builder.Property(a => a.Description).HasColumnName("description");
builder.Property(a => a.IconUrl).HasColumnName("icon_url").HasMaxLength(500);
builder.Property(a => a.XpReward).HasColumnName("xp_reward").HasDefaultValue(0);
builder.Property(a => a.CoinReward).HasColumnName("coin_reward").HasDefaultValue(0);
builder.Property(a => a.Condition).HasColumnName("condition");
builder.Property(a => a.CreatedAt).HasColumnName("created_at").HasDefaultValueSql("NOW()");
}
}
@@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using UniVerse.Domain.Entities;
namespace UniVerse.Infrastructure.Data.Configurations;
public class CoinTransactionConfiguration : IEntityTypeConfiguration<CoinTransaction>
{
public void Configure(EntityTypeBuilder<CoinTransaction> builder)
{
builder.ToTable("coin_transactions");
builder.HasKey(ct => ct.Id);
builder.Property(ct => ct.Id).HasColumnName("id");
builder.Property(ct => ct.UserId).HasColumnName("user_id");
builder.Property(ct => ct.Amount).HasColumnName("amount");
builder.Property(ct => ct.Type).HasColumnName("type");
builder.Property(ct => ct.ReviewId).HasColumnName("review_id");
builder.Property(ct => ct.AchievementId).HasColumnName("achievement_id");
builder.Property(ct => ct.Description).HasColumnName("description").HasMaxLength(500);
builder.Property(ct => ct.CreatedAt).HasColumnName("created_at").HasDefaultValueSql("NOW()");
builder.HasOne(ct => ct.User)
.WithMany(u => u.CoinTransactions)
.HasForeignKey(ct => ct.UserId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne(ct => ct.Review)
.WithMany(r => r.CoinTransactions)
.HasForeignKey(ct => ct.ReviewId)
.OnDelete(DeleteBehavior.SetNull);
builder.HasOne(ct => ct.Achievement)
.WithMany()
.HasForeignKey(ct => ct.AchievementId)
.OnDelete(DeleteBehavior.SetNull);
builder.HasIndex(ct => ct.UserId);
}
}
@@ -0,0 +1,24 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using UniVerse.Domain.Entities;
namespace UniVerse.Infrastructure.Data.Configurations;
public class CourseConfiguration : IEntityTypeConfiguration<Course>
{
public void Configure(EntityTypeBuilder<Course> builder)
{
builder.ToTable("courses");
builder.HasKey(c => c.Id);
builder.Property(c => c.Id).HasColumnName("id");
builder.Property(c => c.Name).HasColumnName("name").HasMaxLength(500).IsRequired();
builder.Property(c => c.Description).HasColumnName("description");
builder.Property(c => c.ExternalId).HasColumnName("external_id").HasMaxLength(255);
builder.Property(c => c.IsSynced).HasColumnName("is_synced").HasDefaultValue(false);
builder.Property(c => c.CreatedAt).HasColumnName("created_at").HasDefaultValueSql("NOW()");
builder.Property(c => c.UpdatedAt).HasColumnName("updated_at").HasDefaultValueSql("NOW()");
builder.HasIndex(c => c.ExternalId).IsUnique().HasFilter("external_id IS NOT NULL");
}
}
@@ -0,0 +1,30 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using UniVerse.Domain.Entities;
namespace UniVerse.Infrastructure.Data.Configurations;
public class CourseTagConfiguration : IEntityTypeConfiguration<CourseTag>
{
public void Configure(EntityTypeBuilder<CourseTag> builder)
{
builder.ToTable("course_tags");
builder.HasKey(ct => ct.Id);
builder.Property(ct => ct.Id).HasColumnName("id");
builder.Property(ct => ct.CourseId).HasColumnName("course_id");
builder.Property(ct => ct.TagId).HasColumnName("tag_id");
builder.HasOne(ct => ct.Course)
.WithMany(c => c.CourseTags)
.HasForeignKey(ct => ct.CourseId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne(ct => ct.Tag)
.WithMany(t => t.CourseTags)
.HasForeignKey(ct => ct.TagId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasIndex(ct => new { ct.CourseId, ct.TagId }).IsUnique();
}
}
@@ -0,0 +1,49 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using UniVerse.Domain.Entities;
namespace UniVerse.Infrastructure.Data.Configurations;
public class LectureConfiguration : IEntityTypeConfiguration<Lecture>
{
public void Configure(EntityTypeBuilder<Lecture> builder)
{
builder.ToTable("lectures");
builder.HasKey(l => l.Id);
builder.Property(l => l.Id).HasColumnName("id");
builder.Property(l => l.CourseId).HasColumnName("course_id");
builder.Property(l => l.TeacherId).HasColumnName("teacher_id");
builder.Property(l => l.LocationId).HasColumnName("location_id");
builder.Property(l => l.Title).HasColumnName("title").HasMaxLength(500).IsRequired();
builder.Property(l => l.Description).HasColumnName("description");
builder.Property(l => l.Format).HasColumnName("format");
builder.Property(l => l.StartsAt).HasColumnName("starts_at");
builder.Property(l => l.EndsAt).HasColumnName("ends_at");
builder.Property(l => l.IsOpen).HasColumnName("is_open").HasDefaultValue(true);
builder.Property(l => l.MaxEnrollments).HasColumnName("max_enrollments").HasDefaultValue(0);
builder.Property(l => l.ExternalId).HasColumnName("external_id").HasMaxLength(255);
builder.Property(l => l.OnlineUrl).HasColumnName("online_url").HasMaxLength(500);
builder.Property(l => l.CreatedAt).HasColumnName("created_at").HasDefaultValueSql("NOW()");
builder.Property(l => l.UpdatedAt).HasColumnName("updated_at").HasDefaultValueSql("NOW()");
builder.HasOne(l => l.Course)
.WithMany(c => c.Lectures)
.HasForeignKey(l => l.CourseId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne(l => l.Teacher)
.WithMany()
.HasForeignKey(l => l.TeacherId)
.OnDelete(DeleteBehavior.SetNull);
builder.HasOne(l => l.Location)
.WithMany(loc => loc.Lectures)
.HasForeignKey(l => l.LocationId)
.OnDelete(DeleteBehavior.SetNull);
builder.HasIndex(l => l.ExternalId).IsUnique().HasFilter("external_id IS NOT NULL");
builder.HasIndex(l => l.StartsAt);
builder.HasIndex(l => l.CourseId);
}
}
@@ -0,0 +1,32 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using UniVerse.Domain.Entities;
namespace UniVerse.Infrastructure.Data.Configurations;
public class LectureEnrollmentConfiguration : IEntityTypeConfiguration<LectureEnrollment>
{
public void Configure(EntityTypeBuilder<LectureEnrollment> builder)
{
builder.ToTable("lecture_enrollments");
builder.HasKey(le => le.Id);
builder.Property(le => le.Id).HasColumnName("id");
builder.Property(le => le.LectureId).HasColumnName("lecture_id");
builder.Property(le => le.UserId).HasColumnName("user_id");
builder.Property(le => le.Attended).HasColumnName("attended").HasDefaultValue(false);
builder.Property(le => le.CreatedAt).HasColumnName("created_at").HasDefaultValueSql("NOW()");
builder.HasOne(le => le.Lecture)
.WithMany(l => l.Enrollments)
.HasForeignKey(le => le.LectureId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne(le => le.User)
.WithMany(u => u.Enrollments)
.HasForeignKey(le => le.UserId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasIndex(le => new { le.LectureId, le.UserId }).IsUnique();
}
}
@@ -0,0 +1,24 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using UniVerse.Domain.Entities;
namespace UniVerse.Infrastructure.Data.Configurations;
public class LocationConfiguration : IEntityTypeConfiguration<Location>
{
public void Configure(EntityTypeBuilder<Location> builder)
{
builder.ToTable("locations");
builder.HasKey(l => l.Id);
builder.Property(l => l.Id).HasColumnName("id");
builder.Property(l => l.Name).HasColumnName("name").HasMaxLength(255).IsRequired();
builder.Property(l => l.Building).HasColumnName("building").HasMaxLength(255);
builder.Property(l => l.Room).HasColumnName("room").HasMaxLength(100);
builder.Property(l => l.Address).HasColumnName("address").HasMaxLength(500);
builder.Property(l => l.ExternalId).HasColumnName("external_id").HasMaxLength(255);
builder.Property(l => l.CreatedAt).HasColumnName("created_at").HasDefaultValueSql("NOW()");
builder.HasIndex(l => l.ExternalId).IsUnique().HasFilter("external_id IS NOT NULL");
}
}
@@ -0,0 +1,34 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using UniVerse.Domain.Entities;
namespace UniVerse.Infrastructure.Data.Configurations;
public class RefreshTokenConfiguration : IEntityTypeConfiguration<RefreshToken>
{
public void Configure(EntityTypeBuilder<RefreshToken> builder)
{
builder.ToTable("refresh_tokens");
builder.HasKey(rt => rt.Id);
builder.Property(rt => rt.Id).HasColumnName("id");
builder.Property(rt => rt.UserId).HasColumnName("user_id");
builder.Property(rt => rt.Token).HasColumnName("token").HasMaxLength(500).IsRequired();
builder.Property(rt => rt.ExpiresAt).HasColumnName("expires_at");
builder.Property(rt => rt.CreatedAt).HasColumnName("created_at").HasDefaultValueSql("NOW()");
builder.Property(rt => rt.RevokedAt).HasColumnName("revoked_at");
builder.HasOne(rt => rt.User)
.WithMany(u => u.RefreshTokens)
.HasForeignKey(rt => rt.UserId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasIndex(rt => rt.Token).IsUnique();
builder.HasIndex(rt => rt.UserId);
// Computed properties should be ignored by EF
builder.Ignore(rt => rt.IsExpired);
builder.Ignore(rt => rt.IsRevoked);
builder.Ignore(rt => rt.IsActive);
}
}
@@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using UniVerse.Domain.Entities;
namespace UniVerse.Infrastructure.Data.Configurations;
public class ReviewConfiguration : IEntityTypeConfiguration<Review>
{
public void Configure(EntityTypeBuilder<Review> builder)
{
builder.ToTable("reviews");
builder.HasKey(r => r.Id);
builder.Property(r => r.Id).HasColumnName("id");
builder.Property(r => r.LectureId).HasColumnName("lecture_id");
builder.Property(r => r.UserId).HasColumnName("user_id");
builder.Property(r => r.Rating).HasColumnName("rating");
builder.Property(r => r.Text).HasColumnName("text");
builder.Property(r => r.LlmStatus).HasColumnName("llm_status").HasDefaultValue(Domain.Enums.ReviewLlmStatus.Pending);
builder.Property(r => r.Sentiment).HasColumnName("sentiment");
builder.Property(r => r.QualityScore).HasColumnName("quality_score");
builder.Property(r => r.IsInformative).HasColumnName("is_informative");
builder.Property(r => r.LlmTags).HasColumnName("llm_tags");
builder.Property(r => r.CreatedAt).HasColumnName("created_at").HasDefaultValueSql("NOW()");
builder.Property(r => r.UpdatedAt).HasColumnName("updated_at").HasDefaultValueSql("NOW()");
builder.HasOne(r => r.Lecture)
.WithMany(l => l.Reviews)
.HasForeignKey(r => r.LectureId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne(r => r.User)
.WithMany(u => u.Reviews)
.HasForeignKey(r => r.UserId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasIndex(r => new { r.LectureId, r.UserId }).IsUnique();
builder.HasIndex(r => r.LlmStatus);
}
}
@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using UniVerse.Domain.Entities;
namespace UniVerse.Infrastructure.Data.Configurations;
public class StudentProfileConfiguration : IEntityTypeConfiguration<StudentProfile>
{
public void Configure(EntityTypeBuilder<StudentProfile> builder)
{
builder.ToTable("student_profiles");
builder.HasKey(s => s.Id);
builder.Property(s => s.Id).HasColumnName("id");
builder.Property(s => s.UserId).HasColumnName("user_id");
builder.Property(s => s.StudentId).HasColumnName("student_id").HasMaxLength(50);
builder.Property(s => s.GroupName).HasColumnName("group_name").HasMaxLength(100);
builder.Property(s => s.EnrollmentYear).HasColumnName("enrollment_year");
builder.Property(s => s.Faculty).HasColumnName("faculty").HasMaxLength(255);
builder.Property(s => s.Specialty).HasColumnName("specialty").HasMaxLength(255);
builder.HasOne(s => s.User)
.WithOne(u => u.StudentProfile)
.HasForeignKey<StudentProfile>(s => s.UserId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasIndex(s => s.UserId).IsUnique();
}
}
@@ -0,0 +1,25 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using UniVerse.Domain.Entities;
namespace UniVerse.Infrastructure.Data.Configurations;
public class TagConfiguration : IEntityTypeConfiguration<Tag>
{
public void Configure(EntityTypeBuilder<Tag> builder)
{
builder.ToTable("tags");
builder.HasKey(t => t.Id);
builder.Property(t => t.Id).HasColumnName("id");
builder.Property(t => t.Name).HasColumnName("name").HasMaxLength(255).IsRequired();
builder.Property(t => t.Type).HasColumnName("type");
builder.Property(t => t.ParentId).HasColumnName("parent_id");
builder.Property(t => t.CreatedAt).HasColumnName("created_at").HasDefaultValueSql("NOW()");
builder.HasOne(t => t.Parent)
.WithMany(t => t.Children)
.HasForeignKey(t => t.ParentId)
.OnDelete(DeleteBehavior.SetNull);
}
}
@@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using UniVerse.Domain.Entities;
namespace UniVerse.Infrastructure.Data.Configurations;
public class TeacherProfileConfiguration : IEntityTypeConfiguration<TeacherProfile>
{
public void Configure(EntityTypeBuilder<TeacherProfile> builder)
{
builder.ToTable("teacher_profiles");
builder.HasKey(t => t.Id);
builder.Property(t => t.Id).HasColumnName("id");
builder.Property(t => t.UserId).HasColumnName("user_id");
builder.Property(t => t.Department).HasColumnName("department").HasMaxLength(255);
builder.Property(t => t.Title).HasColumnName("title").HasMaxLength(255);
builder.Property(t => t.Bio).HasColumnName("bio");
builder.Property(t => t.ModeusId).HasColumnName("modeus_id").HasMaxLength(255);
builder.HasOne(t => t.User)
.WithOne(u => u.TeacherProfile)
.HasForeignKey<TeacherProfile>(t => t.UserId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasIndex(t => t.UserId).IsUnique();
}
}
@@ -0,0 +1,31 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using UniVerse.Domain.Entities;
namespace UniVerse.Infrastructure.Data.Configurations;
public class UserAchievementConfiguration : IEntityTypeConfiguration<UserAchievement>
{
public void Configure(EntityTypeBuilder<UserAchievement> builder)
{
builder.ToTable("user_achievements");
builder.HasKey(ua => ua.Id);
builder.Property(ua => ua.Id).HasColumnName("id");
builder.Property(ua => ua.UserId).HasColumnName("user_id");
builder.Property(ua => ua.AchievementId).HasColumnName("achievement_id");
builder.Property(ua => ua.AwardedAt).HasColumnName("awarded_at").HasDefaultValueSql("NOW()");
builder.HasOne(ua => ua.User)
.WithMany(u => u.UserAchievements)
.HasForeignKey(ua => ua.UserId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne(ua => ua.Achievement)
.WithMany(a => a.UserAchievements)
.HasForeignKey(ua => ua.AchievementId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasIndex(ua => new { ua.UserId, ua.AchievementId }).IsUnique();
}
}
@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using UniVerse.Domain.Entities;
namespace UniVerse.Infrastructure.Data.Configurations;
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("users");
builder.HasKey(u => u.Id);
builder.Property(u => u.Id).HasColumnName("id");
builder.Property(u => u.Email).HasColumnName("email").HasMaxLength(255).IsRequired();
builder.Property(u => u.DisplayName).HasColumnName("display_name").HasMaxLength(255);
builder.Property(u => u.AvatarUrl).HasColumnName("avatar_url").HasMaxLength(500);
builder.Property(u => u.Role).HasColumnName("role");
builder.Property(u => u.IsActive).HasColumnName("is_active").HasDefaultValue(true);
builder.Property(u => u.MicrosoftId).HasColumnName("microsoft_id").HasMaxLength(255);
builder.Property(u => u.Xp).HasColumnName("xp").HasDefaultValue(0);
builder.Property(u => u.Coins).HasColumnName("coins").HasDefaultValue(0);
builder.Property(u => u.CreatedAt).HasColumnName("created_at").HasDefaultValueSql("NOW()");
builder.Property(u => u.UpdatedAt).HasColumnName("updated_at").HasDefaultValueSql("NOW()");
builder.HasIndex(u => u.Email).IsUnique();
builder.HasIndex(u => u.MicrosoftId).IsUnique().HasFilter("microsoft_id IS NOT NULL");
}
}
@@ -0,0 +1,955 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using UniVerse.Infrastructure.Data;
#nullable disable
namespace UniVerse.Infrastructure.Data.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20260428124938_Initial")]
partial class Initial
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "coin_transaction_type", "coin_transaction_type", new[] { "review_reward", "achievement_reward", "attendance_reward", "admin_adjustment" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "review_llm_status", "review_llm_status", new[] { "pending", "analyzed", "rejected" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "review_sentiment", "review_sentiment", new[] { "positive", "neutral", "negative" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "tag_type", "tag_type", new[] { "institute", "faculty", "subject", "organization", "topic", "other" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "user_role", "user_role", new[] { "student", "teacher", "admin" });
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("UniVerse.Domain.Entities.Achievement", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("CoinReward")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("coin_reward");
b.Property<string>("Condition")
.HasColumnType("text")
.HasColumnName("condition");
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<string>("Description")
.HasColumnType("text")
.HasColumnName("description");
b.Property<string>("IconUrl")
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("icon_url");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("name");
b.Property<int>("XpReward")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("xp_reward");
b.HasKey("Id");
b.ToTable("achievements", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.CoinTransaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int?>("AchievementId")
.HasColumnType("integer")
.HasColumnName("achievement_id");
b.Property<int>("Amount")
.HasColumnType("integer")
.HasColumnName("amount");
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<string>("Description")
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("description");
b.Property<int?>("ReviewId")
.HasColumnType("integer")
.HasColumnName("review_id");
b.Property<int>("Type")
.HasColumnType("integer")
.HasColumnName("type");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.HasKey("Id");
b.HasIndex("AchievementId");
b.HasIndex("ReviewId");
b.HasIndex("UserId");
b.ToTable("coin_transactions", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.Course", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<string>("Description")
.HasColumnType("text")
.HasColumnName("description");
b.Property<string>("ExternalId")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("external_id");
b.Property<bool>("IsSynced")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(false)
.HasColumnName("is_synced");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("name");
b.Property<DateTime>("UpdatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("updated_at")
.HasDefaultValueSql("NOW()");
b.HasKey("Id");
b.HasIndex("ExternalId")
.IsUnique()
.HasFilter("external_id IS NOT NULL");
b.ToTable("courses", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.CourseTag", b =>
{
b.Property<int>("CourseId")
.HasColumnType("integer")
.HasColumnName("course_id");
b.Property<int>("TagId")
.HasColumnType("integer")
.HasColumnName("tag_id");
b.Property<int>("Id")
.HasColumnType("integer")
.HasColumnName("id");
b.HasKey("CourseId", "TagId");
b.HasIndex("TagId");
b.HasIndex("CourseId", "TagId")
.IsUnique();
b.ToTable("course_tags", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.Lecture", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("CourseId")
.HasColumnType("integer")
.HasColumnName("course_id");
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<string>("Description")
.HasColumnType("text")
.HasColumnName("description");
b.Property<DateTime>("EndsAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("ends_at");
b.Property<string>("ExternalId")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("external_id");
b.Property<int>("Format")
.HasColumnType("integer")
.HasColumnName("format");
b.Property<bool>("IsOpen")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(true)
.HasColumnName("is_open");
b.Property<int?>("LocationId")
.HasColumnType("integer")
.HasColumnName("location_id");
b.Property<int>("MaxEnrollments")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("max_enrollments");
b.Property<string>("OnlineUrl")
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("online_url");
b.Property<DateTime>("StartsAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("starts_at");
b.Property<int?>("TeacherId")
.HasColumnType("integer")
.HasColumnName("teacher_id");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("title");
b.Property<DateTime>("UpdatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("updated_at")
.HasDefaultValueSql("NOW()");
b.HasKey("Id");
b.HasIndex("CourseId");
b.HasIndex("ExternalId")
.IsUnique()
.HasFilter("external_id IS NOT NULL");
b.HasIndex("LocationId");
b.HasIndex("StartsAt");
b.HasIndex("TeacherId");
b.ToTable("lectures", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.LectureEnrollment", b =>
{
b.Property<int>("LectureId")
.HasColumnType("integer")
.HasColumnName("lecture_id");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.Property<bool>("Attended")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(false)
.HasColumnName("attended");
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<int>("Id")
.HasColumnType("integer")
.HasColumnName("id");
b.HasKey("LectureId", "UserId");
b.HasIndex("UserId");
b.HasIndex("LectureId", "UserId")
.IsUnique();
b.ToTable("lecture_enrollments", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.Location", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Address")
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("address");
b.Property<string>("Building")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("building");
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<string>("ExternalId")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("external_id");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("name");
b.Property<string>("Room")
.HasMaxLength(100)
.HasColumnType("character varying(100)")
.HasColumnName("room");
b.HasKey("Id");
b.HasIndex("ExternalId")
.IsUnique()
.HasFilter("external_id IS NOT NULL");
b.ToTable("locations", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.RefreshToken", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<DateTime>("ExpiresAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("expires_at");
b.Property<DateTime?>("RevokedAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("revoked_at");
b.Property<string>("Token")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("token");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.HasKey("Id");
b.HasIndex("Token")
.IsUnique();
b.HasIndex("UserId");
b.ToTable("refresh_tokens", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.Review", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<bool?>("IsInformative")
.HasColumnType("boolean")
.HasColumnName("is_informative");
b.Property<int>("LectureId")
.HasColumnType("integer")
.HasColumnName("lecture_id");
b.Property<int>("LlmStatus")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("llm_status");
b.PrimitiveCollection<string[]>("LlmTags")
.HasColumnType("text[]")
.HasColumnName("llm_tags");
b.Property<double?>("QualityScore")
.HasColumnType("double precision")
.HasColumnName("quality_score");
b.Property<int>("Rating")
.HasColumnType("integer")
.HasColumnName("rating");
b.Property<int?>("Sentiment")
.HasColumnType("integer")
.HasColumnName("sentiment");
b.Property<string>("Text")
.HasColumnType("text")
.HasColumnName("text");
b.Property<DateTime>("UpdatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("updated_at")
.HasDefaultValueSql("NOW()");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.HasKey("Id");
b.HasIndex("LlmStatus");
b.HasIndex("UserId");
b.HasIndex("LectureId", "UserId")
.IsUnique();
b.ToTable("reviews", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.StudentProfile", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int?>("EnrollmentYear")
.HasColumnType("integer")
.HasColumnName("enrollment_year");
b.Property<string>("Faculty")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("faculty");
b.Property<string>("GroupName")
.HasMaxLength(100)
.HasColumnType("character varying(100)")
.HasColumnName("group_name");
b.Property<string>("Specialty")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("specialty");
b.Property<string>("StudentId")
.HasMaxLength(50)
.HasColumnType("character varying(50)")
.HasColumnName("student_id");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("student_profiles", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.Tag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("name");
b.Property<int?>("ParentId")
.HasColumnType("integer")
.HasColumnName("parent_id");
b.Property<int>("Type")
.HasColumnType("integer")
.HasColumnName("type");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("tags", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.TeacherProfile", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Bio")
.HasColumnType("text")
.HasColumnName("bio");
b.Property<string>("Department")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("department");
b.Property<string>("ModeusId")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("modeus_id");
b.Property<string>("Title")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("title");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("teacher_profiles", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("AvatarUrl")
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("avatar_url");
b.Property<int>("Coins")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("coins");
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<string>("DisplayName")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("display_name");
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("email");
b.Property<bool>("IsActive")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(true)
.HasColumnName("is_active");
b.Property<string>("MicrosoftId")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("microsoft_id");
b.Property<int>("Role")
.HasColumnType("integer")
.HasColumnName("role");
b.Property<DateTime>("UpdatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("updated_at")
.HasDefaultValueSql("NOW()");
b.Property<int>("Xp")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("xp");
b.HasKey("Id");
b.HasIndex("Email")
.IsUnique();
b.HasIndex("MicrosoftId")
.IsUnique()
.HasFilter("microsoft_id IS NOT NULL");
b.ToTable("users", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.UserAchievement", b =>
{
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.Property<int>("AchievementId")
.HasColumnType("integer")
.HasColumnName("achievement_id");
b.Property<DateTime>("AwardedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("awarded_at")
.HasDefaultValueSql("NOW()");
b.Property<int>("Id")
.HasColumnType("integer")
.HasColumnName("id");
b.HasKey("UserId", "AchievementId");
b.HasIndex("AchievementId");
b.HasIndex("UserId", "AchievementId")
.IsUnique();
b.ToTable("user_achievements", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.CoinTransaction", b =>
{
b.HasOne("UniVerse.Domain.Entities.Achievement", "Achievement")
.WithMany()
.HasForeignKey("AchievementId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("UniVerse.Domain.Entities.Review", "Review")
.WithMany("CoinTransactions")
.HasForeignKey("ReviewId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("UniVerse.Domain.Entities.User", "User")
.WithMany("CoinTransactions")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Achievement");
b.Navigation("Review");
b.Navigation("User");
});
modelBuilder.Entity("UniVerse.Domain.Entities.CourseTag", b =>
{
b.HasOne("UniVerse.Domain.Entities.Course", "Course")
.WithMany("CourseTags")
.HasForeignKey("CourseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniVerse.Domain.Entities.Tag", "Tag")
.WithMany("CourseTags")
.HasForeignKey("TagId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Course");
b.Navigation("Tag");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Lecture", b =>
{
b.HasOne("UniVerse.Domain.Entities.Course", "Course")
.WithMany("Lectures")
.HasForeignKey("CourseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniVerse.Domain.Entities.Location", "Location")
.WithMany("Lectures")
.HasForeignKey("LocationId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("UniVerse.Domain.Entities.User", "Teacher")
.WithMany()
.HasForeignKey("TeacherId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Course");
b.Navigation("Location");
b.Navigation("Teacher");
});
modelBuilder.Entity("UniVerse.Domain.Entities.LectureEnrollment", b =>
{
b.HasOne("UniVerse.Domain.Entities.Lecture", "Lecture")
.WithMany("Enrollments")
.HasForeignKey("LectureId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniVerse.Domain.Entities.User", "User")
.WithMany("Enrollments")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Lecture");
b.Navigation("User");
});
modelBuilder.Entity("UniVerse.Domain.Entities.RefreshToken", b =>
{
b.HasOne("UniVerse.Domain.Entities.User", "User")
.WithMany("RefreshTokens")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Review", b =>
{
b.HasOne("UniVerse.Domain.Entities.Lecture", "Lecture")
.WithMany("Reviews")
.HasForeignKey("LectureId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniVerse.Domain.Entities.User", "User")
.WithMany("Reviews")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Lecture");
b.Navigation("User");
});
modelBuilder.Entity("UniVerse.Domain.Entities.StudentProfile", b =>
{
b.HasOne("UniVerse.Domain.Entities.User", "User")
.WithOne("StudentProfile")
.HasForeignKey("UniVerse.Domain.Entities.StudentProfile", "UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Tag", b =>
{
b.HasOne("UniVerse.Domain.Entities.Tag", "Parent")
.WithMany("Children")
.HasForeignKey("ParentId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Parent");
});
modelBuilder.Entity("UniVerse.Domain.Entities.TeacherProfile", b =>
{
b.HasOne("UniVerse.Domain.Entities.User", "User")
.WithOne("TeacherProfile")
.HasForeignKey("UniVerse.Domain.Entities.TeacherProfile", "UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("UniVerse.Domain.Entities.UserAchievement", b =>
{
b.HasOne("UniVerse.Domain.Entities.Achievement", "Achievement")
.WithMany("UserAchievements")
.HasForeignKey("AchievementId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniVerse.Domain.Entities.User", "User")
.WithMany("UserAchievements")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Achievement");
b.Navigation("User");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Achievement", b =>
{
b.Navigation("UserAchievements");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Course", b =>
{
b.Navigation("CourseTags");
b.Navigation("Lectures");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Lecture", b =>
{
b.Navigation("Enrollments");
b.Navigation("Reviews");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Location", b =>
{
b.Navigation("Lectures");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Review", b =>
{
b.Navigation("CoinTransactions");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Tag", b =>
{
b.Navigation("Children");
b.Navigation("CourseTags");
});
modelBuilder.Entity("UniVerse.Domain.Entities.User", b =>
{
b.Navigation("CoinTransactions");
b.Navigation("Enrollments");
b.Navigation("RefreshTokens");
b.Navigation("Reviews");
b.Navigation("StudentProfile");
b.Navigation("TeacherProfile");
b.Navigation("UserAchievements");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,578 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace UniVerse.Infrastructure.Data.Migrations
{
/// <inheritdoc />
public partial class Initial : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterDatabase()
.Annotation("Npgsql:Enum:coin_transaction_type.coin_transaction_type", "review_reward,achievement_reward,attendance_reward,admin_adjustment")
.Annotation("Npgsql:Enum:review_llm_status.review_llm_status", "pending,analyzed,rejected")
.Annotation("Npgsql:Enum:review_sentiment.review_sentiment", "positive,neutral,negative")
.Annotation("Npgsql:Enum:tag_type.tag_type", "institute,faculty,subject,organization,topic,other")
.Annotation("Npgsql:Enum:user_role.user_role", "student,teacher,admin");
migrationBuilder.CreateTable(
name: "achievements",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
name = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
description = table.Column<string>(type: "text", nullable: true),
icon_url = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: true),
xp_reward = table.Column<int>(type: "integer", nullable: false, defaultValue: 0),
coin_reward = table.Column<int>(type: "integer", nullable: false, defaultValue: 0),
condition = table.Column<string>(type: "text", nullable: true),
created_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()")
},
constraints: table =>
{
table.PrimaryKey("PK_achievements", x => x.id);
});
migrationBuilder.CreateTable(
name: "courses",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
name = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: false),
description = table.Column<string>(type: "text", nullable: true),
external_id = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
is_synced = table.Column<bool>(type: "boolean", nullable: false, defaultValue: false),
created_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()"),
updated_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()")
},
constraints: table =>
{
table.PrimaryKey("PK_courses", x => x.id);
});
migrationBuilder.CreateTable(
name: "locations",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
name = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
building = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
room = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
address = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: true),
external_id = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
created_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()")
},
constraints: table =>
{
table.PrimaryKey("PK_locations", x => x.id);
});
migrationBuilder.CreateTable(
name: "tags",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
name = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
type = table.Column<int>(type: "integer", nullable: false),
parent_id = table.Column<int>(type: "integer", nullable: true),
created_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()")
},
constraints: table =>
{
table.PrimaryKey("PK_tags", x => x.id);
table.ForeignKey(
name: "FK_tags_tags_parent_id",
column: x => x.parent_id,
principalTable: "tags",
principalColumn: "id",
onDelete: ReferentialAction.SetNull);
});
migrationBuilder.CreateTable(
name: "users",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
email = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
display_name = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
avatar_url = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: true),
role = table.Column<int>(type: "integer", nullable: false),
is_active = table.Column<bool>(type: "boolean", nullable: false, defaultValue: true),
microsoft_id = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
xp = table.Column<int>(type: "integer", nullable: false, defaultValue: 0),
coins = table.Column<int>(type: "integer", nullable: false, defaultValue: 0),
created_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()"),
updated_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()")
},
constraints: table =>
{
table.PrimaryKey("PK_users", x => x.id);
});
migrationBuilder.CreateTable(
name: "course_tags",
columns: table => new
{
course_id = table.Column<int>(type: "integer", nullable: false),
tag_id = table.Column<int>(type: "integer", nullable: false),
id = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_course_tags", x => new { x.course_id, x.tag_id });
table.ForeignKey(
name: "FK_course_tags_courses_course_id",
column: x => x.course_id,
principalTable: "courses",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_course_tags_tags_tag_id",
column: x => x.tag_id,
principalTable: "tags",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "lectures",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
course_id = table.Column<int>(type: "integer", nullable: false),
teacher_id = table.Column<int>(type: "integer", nullable: true),
location_id = table.Column<int>(type: "integer", nullable: true),
title = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: false),
description = table.Column<string>(type: "text", nullable: true),
format = table.Column<int>(type: "integer", nullable: false),
starts_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
ends_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
is_open = table.Column<bool>(type: "boolean", nullable: false, defaultValue: true),
max_enrollments = table.Column<int>(type: "integer", nullable: false, defaultValue: 0),
external_id = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
online_url = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: true),
created_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()"),
updated_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()")
},
constraints: table =>
{
table.PrimaryKey("PK_lectures", x => x.id);
table.ForeignKey(
name: "FK_lectures_courses_course_id",
column: x => x.course_id,
principalTable: "courses",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_lectures_locations_location_id",
column: x => x.location_id,
principalTable: "locations",
principalColumn: "id",
onDelete: ReferentialAction.SetNull);
table.ForeignKey(
name: "FK_lectures_users_teacher_id",
column: x => x.teacher_id,
principalTable: "users",
principalColumn: "id",
onDelete: ReferentialAction.SetNull);
});
migrationBuilder.CreateTable(
name: "refresh_tokens",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
user_id = table.Column<int>(type: "integer", nullable: false),
token = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: false),
expires_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
created_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()"),
revoked_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_refresh_tokens", x => x.id);
table.ForeignKey(
name: "FK_refresh_tokens_users_user_id",
column: x => x.user_id,
principalTable: "users",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "student_profiles",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
user_id = table.Column<int>(type: "integer", nullable: false),
student_id = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
group_name = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
enrollment_year = table.Column<int>(type: "integer", nullable: true),
faculty = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
specialty = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_student_profiles", x => x.id);
table.ForeignKey(
name: "FK_student_profiles_users_user_id",
column: x => x.user_id,
principalTable: "users",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "teacher_profiles",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
user_id = table.Column<int>(type: "integer", nullable: false),
department = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
title = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
bio = table.Column<string>(type: "text", nullable: true),
modeus_id = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_teacher_profiles", x => x.id);
table.ForeignKey(
name: "FK_teacher_profiles_users_user_id",
column: x => x.user_id,
principalTable: "users",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "user_achievements",
columns: table => new
{
user_id = table.Column<int>(type: "integer", nullable: false),
achievement_id = table.Column<int>(type: "integer", nullable: false),
id = table.Column<int>(type: "integer", nullable: false),
awarded_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()")
},
constraints: table =>
{
table.PrimaryKey("PK_user_achievements", x => new { x.user_id, x.achievement_id });
table.ForeignKey(
name: "FK_user_achievements_achievements_achievement_id",
column: x => x.achievement_id,
principalTable: "achievements",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_user_achievements_users_user_id",
column: x => x.user_id,
principalTable: "users",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "lecture_enrollments",
columns: table => new
{
lecture_id = table.Column<int>(type: "integer", nullable: false),
user_id = table.Column<int>(type: "integer", nullable: false),
id = table.Column<int>(type: "integer", nullable: false),
attended = table.Column<bool>(type: "boolean", nullable: false, defaultValue: false),
created_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()")
},
constraints: table =>
{
table.PrimaryKey("PK_lecture_enrollments", x => new { x.lecture_id, x.user_id });
table.ForeignKey(
name: "FK_lecture_enrollments_lectures_lecture_id",
column: x => x.lecture_id,
principalTable: "lectures",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_lecture_enrollments_users_user_id",
column: x => x.user_id,
principalTable: "users",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "reviews",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
lecture_id = table.Column<int>(type: "integer", nullable: false),
user_id = table.Column<int>(type: "integer", nullable: false),
rating = table.Column<int>(type: "integer", nullable: false),
text = table.Column<string>(type: "text", nullable: true),
llm_status = table.Column<int>(type: "integer", nullable: false, defaultValue: 0),
sentiment = table.Column<int>(type: "integer", nullable: true),
quality_score = table.Column<double>(type: "double precision", nullable: true),
is_informative = table.Column<bool>(type: "boolean", nullable: true),
llm_tags = table.Column<string[]>(type: "text[]", nullable: true),
created_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()"),
updated_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()")
},
constraints: table =>
{
table.PrimaryKey("PK_reviews", x => x.id);
table.ForeignKey(
name: "FK_reviews_lectures_lecture_id",
column: x => x.lecture_id,
principalTable: "lectures",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_reviews_users_user_id",
column: x => x.user_id,
principalTable: "users",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "coin_transactions",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
user_id = table.Column<int>(type: "integer", nullable: false),
amount = table.Column<int>(type: "integer", nullable: false),
type = table.Column<int>(type: "integer", nullable: false),
review_id = table.Column<int>(type: "integer", nullable: true),
achievement_id = table.Column<int>(type: "integer", nullable: true),
description = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: true),
created_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()")
},
constraints: table =>
{
table.PrimaryKey("PK_coin_transactions", x => x.id);
table.ForeignKey(
name: "FK_coin_transactions_achievements_achievement_id",
column: x => x.achievement_id,
principalTable: "achievements",
principalColumn: "id",
onDelete: ReferentialAction.SetNull);
table.ForeignKey(
name: "FK_coin_transactions_reviews_review_id",
column: x => x.review_id,
principalTable: "reviews",
principalColumn: "id",
onDelete: ReferentialAction.SetNull);
table.ForeignKey(
name: "FK_coin_transactions_users_user_id",
column: x => x.user_id,
principalTable: "users",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_coin_transactions_achievement_id",
table: "coin_transactions",
column: "achievement_id");
migrationBuilder.CreateIndex(
name: "IX_coin_transactions_review_id",
table: "coin_transactions",
column: "review_id");
migrationBuilder.CreateIndex(
name: "IX_coin_transactions_user_id",
table: "coin_transactions",
column: "user_id");
migrationBuilder.CreateIndex(
name: "IX_course_tags_course_id_tag_id",
table: "course_tags",
columns: new[] { "course_id", "tag_id" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_course_tags_tag_id",
table: "course_tags",
column: "tag_id");
migrationBuilder.CreateIndex(
name: "IX_courses_external_id",
table: "courses",
column: "external_id",
unique: true,
filter: "external_id IS NOT NULL");
migrationBuilder.CreateIndex(
name: "IX_lecture_enrollments_lecture_id_user_id",
table: "lecture_enrollments",
columns: new[] { "lecture_id", "user_id" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_lecture_enrollments_user_id",
table: "lecture_enrollments",
column: "user_id");
migrationBuilder.CreateIndex(
name: "IX_lectures_course_id",
table: "lectures",
column: "course_id");
migrationBuilder.CreateIndex(
name: "IX_lectures_external_id",
table: "lectures",
column: "external_id",
unique: true,
filter: "external_id IS NOT NULL");
migrationBuilder.CreateIndex(
name: "IX_lectures_location_id",
table: "lectures",
column: "location_id");
migrationBuilder.CreateIndex(
name: "IX_lectures_starts_at",
table: "lectures",
column: "starts_at");
migrationBuilder.CreateIndex(
name: "IX_lectures_teacher_id",
table: "lectures",
column: "teacher_id");
migrationBuilder.CreateIndex(
name: "IX_locations_external_id",
table: "locations",
column: "external_id",
unique: true,
filter: "external_id IS NOT NULL");
migrationBuilder.CreateIndex(
name: "IX_refresh_tokens_token",
table: "refresh_tokens",
column: "token",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_refresh_tokens_user_id",
table: "refresh_tokens",
column: "user_id");
migrationBuilder.CreateIndex(
name: "IX_reviews_lecture_id_user_id",
table: "reviews",
columns: new[] { "lecture_id", "user_id" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_reviews_llm_status",
table: "reviews",
column: "llm_status");
migrationBuilder.CreateIndex(
name: "IX_reviews_user_id",
table: "reviews",
column: "user_id");
migrationBuilder.CreateIndex(
name: "IX_student_profiles_user_id",
table: "student_profiles",
column: "user_id",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_tags_parent_id",
table: "tags",
column: "parent_id");
migrationBuilder.CreateIndex(
name: "IX_teacher_profiles_user_id",
table: "teacher_profiles",
column: "user_id",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_user_achievements_achievement_id",
table: "user_achievements",
column: "achievement_id");
migrationBuilder.CreateIndex(
name: "IX_user_achievements_user_id_achievement_id",
table: "user_achievements",
columns: new[] { "user_id", "achievement_id" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_users_email",
table: "users",
column: "email",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_users_microsoft_id",
table: "users",
column: "microsoft_id",
unique: true,
filter: "microsoft_id IS NOT NULL");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "coin_transactions");
migrationBuilder.DropTable(
name: "course_tags");
migrationBuilder.DropTable(
name: "lecture_enrollments");
migrationBuilder.DropTable(
name: "refresh_tokens");
migrationBuilder.DropTable(
name: "student_profiles");
migrationBuilder.DropTable(
name: "teacher_profiles");
migrationBuilder.DropTable(
name: "user_achievements");
migrationBuilder.DropTable(
name: "reviews");
migrationBuilder.DropTable(
name: "tags");
migrationBuilder.DropTable(
name: "achievements");
migrationBuilder.DropTable(
name: "lectures");
migrationBuilder.DropTable(
name: "courses");
migrationBuilder.DropTable(
name: "locations");
migrationBuilder.DropTable(
name: "users");
}
}
}
@@ -0,0 +1,952 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using UniVerse.Infrastructure.Data;
#nullable disable
namespace UniVerse.Infrastructure.Data.Migrations
{
[DbContext(typeof(AppDbContext))]
partial class AppDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "coin_transaction_type", "coin_transaction_type", new[] { "review_reward", "achievement_reward", "attendance_reward", "admin_adjustment" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "review_llm_status", "review_llm_status", new[] { "pending", "analyzed", "rejected" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "review_sentiment", "review_sentiment", new[] { "positive", "neutral", "negative" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "tag_type", "tag_type", new[] { "institute", "faculty", "subject", "organization", "topic", "other" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "user_role", "user_role", new[] { "student", "teacher", "admin" });
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("UniVerse.Domain.Entities.Achievement", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("CoinReward")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("coin_reward");
b.Property<string>("Condition")
.HasColumnType("text")
.HasColumnName("condition");
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<string>("Description")
.HasColumnType("text")
.HasColumnName("description");
b.Property<string>("IconUrl")
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("icon_url");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("name");
b.Property<int>("XpReward")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("xp_reward");
b.HasKey("Id");
b.ToTable("achievements", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.CoinTransaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int?>("AchievementId")
.HasColumnType("integer")
.HasColumnName("achievement_id");
b.Property<int>("Amount")
.HasColumnType("integer")
.HasColumnName("amount");
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<string>("Description")
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("description");
b.Property<int?>("ReviewId")
.HasColumnType("integer")
.HasColumnName("review_id");
b.Property<int>("Type")
.HasColumnType("integer")
.HasColumnName("type");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.HasKey("Id");
b.HasIndex("AchievementId");
b.HasIndex("ReviewId");
b.HasIndex("UserId");
b.ToTable("coin_transactions", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.Course", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<string>("Description")
.HasColumnType("text")
.HasColumnName("description");
b.Property<string>("ExternalId")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("external_id");
b.Property<bool>("IsSynced")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(false)
.HasColumnName("is_synced");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("name");
b.Property<DateTime>("UpdatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("updated_at")
.HasDefaultValueSql("NOW()");
b.HasKey("Id");
b.HasIndex("ExternalId")
.IsUnique()
.HasFilter("external_id IS NOT NULL");
b.ToTable("courses", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.CourseTag", b =>
{
b.Property<int>("CourseId")
.HasColumnType("integer")
.HasColumnName("course_id");
b.Property<int>("TagId")
.HasColumnType("integer")
.HasColumnName("tag_id");
b.Property<int>("Id")
.HasColumnType("integer")
.HasColumnName("id");
b.HasKey("CourseId", "TagId");
b.HasIndex("TagId");
b.HasIndex("CourseId", "TagId")
.IsUnique();
b.ToTable("course_tags", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.Lecture", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("CourseId")
.HasColumnType("integer")
.HasColumnName("course_id");
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<string>("Description")
.HasColumnType("text")
.HasColumnName("description");
b.Property<DateTime>("EndsAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("ends_at");
b.Property<string>("ExternalId")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("external_id");
b.Property<int>("Format")
.HasColumnType("integer")
.HasColumnName("format");
b.Property<bool>("IsOpen")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(true)
.HasColumnName("is_open");
b.Property<int?>("LocationId")
.HasColumnType("integer")
.HasColumnName("location_id");
b.Property<int>("MaxEnrollments")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("max_enrollments");
b.Property<string>("OnlineUrl")
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("online_url");
b.Property<DateTime>("StartsAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("starts_at");
b.Property<int?>("TeacherId")
.HasColumnType("integer")
.HasColumnName("teacher_id");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("title");
b.Property<DateTime>("UpdatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("updated_at")
.HasDefaultValueSql("NOW()");
b.HasKey("Id");
b.HasIndex("CourseId");
b.HasIndex("ExternalId")
.IsUnique()
.HasFilter("external_id IS NOT NULL");
b.HasIndex("LocationId");
b.HasIndex("StartsAt");
b.HasIndex("TeacherId");
b.ToTable("lectures", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.LectureEnrollment", b =>
{
b.Property<int>("LectureId")
.HasColumnType("integer")
.HasColumnName("lecture_id");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.Property<bool>("Attended")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(false)
.HasColumnName("attended");
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<int>("Id")
.HasColumnType("integer")
.HasColumnName("id");
b.HasKey("LectureId", "UserId");
b.HasIndex("UserId");
b.HasIndex("LectureId", "UserId")
.IsUnique();
b.ToTable("lecture_enrollments", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.Location", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Address")
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("address");
b.Property<string>("Building")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("building");
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<string>("ExternalId")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("external_id");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("name");
b.Property<string>("Room")
.HasMaxLength(100)
.HasColumnType("character varying(100)")
.HasColumnName("room");
b.HasKey("Id");
b.HasIndex("ExternalId")
.IsUnique()
.HasFilter("external_id IS NOT NULL");
b.ToTable("locations", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.RefreshToken", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<DateTime>("ExpiresAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("expires_at");
b.Property<DateTime?>("RevokedAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("revoked_at");
b.Property<string>("Token")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("token");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.HasKey("Id");
b.HasIndex("Token")
.IsUnique();
b.HasIndex("UserId");
b.ToTable("refresh_tokens", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.Review", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<bool?>("IsInformative")
.HasColumnType("boolean")
.HasColumnName("is_informative");
b.Property<int>("LectureId")
.HasColumnType("integer")
.HasColumnName("lecture_id");
b.Property<int>("LlmStatus")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("llm_status");
b.PrimitiveCollection<string[]>("LlmTags")
.HasColumnType("text[]")
.HasColumnName("llm_tags");
b.Property<double?>("QualityScore")
.HasColumnType("double precision")
.HasColumnName("quality_score");
b.Property<int>("Rating")
.HasColumnType("integer")
.HasColumnName("rating");
b.Property<int?>("Sentiment")
.HasColumnType("integer")
.HasColumnName("sentiment");
b.Property<string>("Text")
.HasColumnType("text")
.HasColumnName("text");
b.Property<DateTime>("UpdatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("updated_at")
.HasDefaultValueSql("NOW()");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.HasKey("Id");
b.HasIndex("LlmStatus");
b.HasIndex("UserId");
b.HasIndex("LectureId", "UserId")
.IsUnique();
b.ToTable("reviews", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.StudentProfile", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int?>("EnrollmentYear")
.HasColumnType("integer")
.HasColumnName("enrollment_year");
b.Property<string>("Faculty")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("faculty");
b.Property<string>("GroupName")
.HasMaxLength(100)
.HasColumnType("character varying(100)")
.HasColumnName("group_name");
b.Property<string>("Specialty")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("specialty");
b.Property<string>("StudentId")
.HasMaxLength(50)
.HasColumnType("character varying(50)")
.HasColumnName("student_id");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("student_profiles", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.Tag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("name");
b.Property<int?>("ParentId")
.HasColumnType("integer")
.HasColumnName("parent_id");
b.Property<int>("Type")
.HasColumnType("integer")
.HasColumnName("type");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("tags", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.TeacherProfile", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Bio")
.HasColumnType("text")
.HasColumnName("bio");
b.Property<string>("Department")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("department");
b.Property<string>("ModeusId")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("modeus_id");
b.Property<string>("Title")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("title");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("teacher_profiles", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("AvatarUrl")
.HasMaxLength(500)
.HasColumnType("character varying(500)")
.HasColumnName("avatar_url");
b.Property<int>("Coins")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("coins");
b.Property<DateTime>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");
b.Property<string>("DisplayName")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("display_name");
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("email");
b.Property<bool>("IsActive")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(true)
.HasColumnName("is_active");
b.Property<string>("MicrosoftId")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("microsoft_id");
b.Property<int>("Role")
.HasColumnType("integer")
.HasColumnName("role");
b.Property<DateTime>("UpdatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("updated_at")
.HasDefaultValueSql("NOW()");
b.Property<int>("Xp")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("xp");
b.HasKey("Id");
b.HasIndex("Email")
.IsUnique();
b.HasIndex("MicrosoftId")
.IsUnique()
.HasFilter("microsoft_id IS NOT NULL");
b.ToTable("users", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.UserAchievement", b =>
{
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.Property<int>("AchievementId")
.HasColumnType("integer")
.HasColumnName("achievement_id");
b.Property<DateTime>("AwardedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("awarded_at")
.HasDefaultValueSql("NOW()");
b.Property<int>("Id")
.HasColumnType("integer")
.HasColumnName("id");
b.HasKey("UserId", "AchievementId");
b.HasIndex("AchievementId");
b.HasIndex("UserId", "AchievementId")
.IsUnique();
b.ToTable("user_achievements", (string)null);
});
modelBuilder.Entity("UniVerse.Domain.Entities.CoinTransaction", b =>
{
b.HasOne("UniVerse.Domain.Entities.Achievement", "Achievement")
.WithMany()
.HasForeignKey("AchievementId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("UniVerse.Domain.Entities.Review", "Review")
.WithMany("CoinTransactions")
.HasForeignKey("ReviewId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("UniVerse.Domain.Entities.User", "User")
.WithMany("CoinTransactions")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Achievement");
b.Navigation("Review");
b.Navigation("User");
});
modelBuilder.Entity("UniVerse.Domain.Entities.CourseTag", b =>
{
b.HasOne("UniVerse.Domain.Entities.Course", "Course")
.WithMany("CourseTags")
.HasForeignKey("CourseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniVerse.Domain.Entities.Tag", "Tag")
.WithMany("CourseTags")
.HasForeignKey("TagId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Course");
b.Navigation("Tag");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Lecture", b =>
{
b.HasOne("UniVerse.Domain.Entities.Course", "Course")
.WithMany("Lectures")
.HasForeignKey("CourseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniVerse.Domain.Entities.Location", "Location")
.WithMany("Lectures")
.HasForeignKey("LocationId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("UniVerse.Domain.Entities.User", "Teacher")
.WithMany()
.HasForeignKey("TeacherId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Course");
b.Navigation("Location");
b.Navigation("Teacher");
});
modelBuilder.Entity("UniVerse.Domain.Entities.LectureEnrollment", b =>
{
b.HasOne("UniVerse.Domain.Entities.Lecture", "Lecture")
.WithMany("Enrollments")
.HasForeignKey("LectureId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniVerse.Domain.Entities.User", "User")
.WithMany("Enrollments")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Lecture");
b.Navigation("User");
});
modelBuilder.Entity("UniVerse.Domain.Entities.RefreshToken", b =>
{
b.HasOne("UniVerse.Domain.Entities.User", "User")
.WithMany("RefreshTokens")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Review", b =>
{
b.HasOne("UniVerse.Domain.Entities.Lecture", "Lecture")
.WithMany("Reviews")
.HasForeignKey("LectureId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniVerse.Domain.Entities.User", "User")
.WithMany("Reviews")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Lecture");
b.Navigation("User");
});
modelBuilder.Entity("UniVerse.Domain.Entities.StudentProfile", b =>
{
b.HasOne("UniVerse.Domain.Entities.User", "User")
.WithOne("StudentProfile")
.HasForeignKey("UniVerse.Domain.Entities.StudentProfile", "UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Tag", b =>
{
b.HasOne("UniVerse.Domain.Entities.Tag", "Parent")
.WithMany("Children")
.HasForeignKey("ParentId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Parent");
});
modelBuilder.Entity("UniVerse.Domain.Entities.TeacherProfile", b =>
{
b.HasOne("UniVerse.Domain.Entities.User", "User")
.WithOne("TeacherProfile")
.HasForeignKey("UniVerse.Domain.Entities.TeacherProfile", "UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("UniVerse.Domain.Entities.UserAchievement", b =>
{
b.HasOne("UniVerse.Domain.Entities.Achievement", "Achievement")
.WithMany("UserAchievements")
.HasForeignKey("AchievementId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniVerse.Domain.Entities.User", "User")
.WithMany("UserAchievements")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Achievement");
b.Navigation("User");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Achievement", b =>
{
b.Navigation("UserAchievements");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Course", b =>
{
b.Navigation("CourseTags");
b.Navigation("Lectures");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Lecture", b =>
{
b.Navigation("Enrollments");
b.Navigation("Reviews");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Location", b =>
{
b.Navigation("Lectures");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Review", b =>
{
b.Navigation("CoinTransactions");
});
modelBuilder.Entity("UniVerse.Domain.Entities.Tag", b =>
{
b.Navigation("Children");
b.Navigation("CourseTags");
});
modelBuilder.Entity("UniVerse.Domain.Entities.User", b =>
{
b.Navigation("CoinTransactions");
b.Navigation("Enrollments");
b.Navigation("RefreshTokens");
b.Navigation("Reviews");
b.Navigation("StudentProfile");
b.Navigation("TeacherProfile");
b.Navigation("UserAchievements");
});
#pragma warning restore 612, 618
}
}
}