Add core models, DTOs, and services for EchoHub chat application

- Created User, Channel, Message, and ServerInfo models with necessary properties.
- Added DTOs for user profiles, server information, and message handling.
- Implemented JWT authentication service for user login and token generation.
- Developed Entity Framework Core DbContext for database interactions.
- Introduced SignalR ChatHub for real-time messaging and presence tracking.
- Implemented file storage and image to ASCII conversion services.
- Set up CORS and middleware for API endpoints.
- Created launch settings and development configuration for server and web projects.
This commit is contained in:
HueByte
2026-02-18 13:52:19 +01:00
parent 20a341947a
commit cfa8b90d04
47 changed files with 4596 additions and 0 deletions
@@ -0,0 +1,76 @@
using EchoHub.Core.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace EchoHub.Server.Data;
public class EchoHubDbContext(DbContextOptions<EchoHubDbContext> options) : DbContext(options)
{
public DbSet<User> Users => Set<User>();
public DbSet<Channel> Channels => Set<Channel>();
public DbSet<Message> Messages => Set<Message>();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlite("Data Source=echohub.db");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>(entity =>
{
entity.HasKey(u => u.Id);
entity.HasIndex(u => u.Username).IsUnique();
entity.Property(u => u.Username).IsRequired().HasMaxLength(50);
entity.Property(u => u.PasswordHash).IsRequired();
entity.Property(u => u.DisplayName).HasMaxLength(100);
entity.Property(u => u.Bio).HasMaxLength(500);
entity.Property(u => u.NicknameColor).HasMaxLength(7);
entity.Property(u => u.AvatarAscii).HasMaxLength(10000);
entity.Property(u => u.StatusMessage).HasMaxLength(100);
});
modelBuilder.Entity<Channel>(entity =>
{
entity.HasKey(c => c.Id);
entity.HasIndex(c => c.Name);
entity.Property(c => c.Name).IsRequired().HasMaxLength(100);
entity.Property(c => c.Topic).HasMaxLength(500);
entity.HasMany(c => c.Messages)
.WithOne(m => m.Channel)
.HasForeignKey(m => m.ChannelId)
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity<Message>(entity =>
{
entity.HasKey(m => m.Id);
entity.HasIndex(m => m.SentAt);
entity.Property(m => m.Content).IsRequired().HasMaxLength(2000);
entity.Property(m => m.SenderUsername).IsRequired().HasMaxLength(50);
entity.Property(m => m.AttachmentUrl).HasMaxLength(500);
entity.Property(m => m.AttachmentFileName).HasMaxLength(255);
});
// SQLite does not support DateTimeOffset in ORDER BY clauses.
// Convert all DateTimeOffset properties to Unix milliseconds (long) for storage.
var dateTimeOffsetConverter = new ValueConverter<DateTimeOffset, long>(
v => v.ToUnixTimeMilliseconds(),
v => DateTimeOffset.FromUnixTimeMilliseconds(v));
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
foreach (var property in entityType.GetProperties())
{
if (property.ClrType == typeof(DateTimeOffset) || property.ClrType == typeof(DateTimeOffset?))
{
property.SetValueConverter(dateTimeOffsetConverter);
}
}
}
}
}