Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
408c9cb09b |
15 changed files with 2718 additions and 2 deletions
|
|
@ -36,6 +36,8 @@ namespace LANCommander.Data
|
||||||
builder.ConfigureBaseRelationships<ServerConsole>();
|
builder.ConfigureBaseRelationships<ServerConsole>();
|
||||||
builder.ConfigureBaseRelationships<ServerHttpPath>();
|
builder.ConfigureBaseRelationships<ServerHttpPath>();
|
||||||
builder.ConfigureBaseRelationships<Tag>();
|
builder.ConfigureBaseRelationships<Tag>();
|
||||||
|
builder.ConfigureBaseRelationships<Message>();
|
||||||
|
builder.ConfigureBaseRelationships<Channel>();
|
||||||
|
|
||||||
builder.Entity<Genre>()
|
builder.Entity<Genre>()
|
||||||
.HasMany(g => g.Games)
|
.HasMany(g => g.Games)
|
||||||
|
|
@ -229,6 +231,23 @@ namespace LANCommander.Data
|
||||||
rc => rc.HasOne<Role>().WithMany().HasForeignKey("RoleId")
|
rc => rc.HasOne<Role>().WithMany().HasForeignKey("RoleId")
|
||||||
);
|
);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Chat Relationships
|
||||||
|
builder.Entity<Channel>()
|
||||||
|
.HasMany(c => c.Messages)
|
||||||
|
.WithOne(m => m.Channel)
|
||||||
|
.IsRequired(true)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
builder.Entity<Channel>()
|
||||||
|
.HasMany(c => c.Users)
|
||||||
|
.WithMany(u => u.Channels)
|
||||||
|
.UsingEntity<Dictionary<string, object>>(
|
||||||
|
"ChannelUsers",
|
||||||
|
cu => cu.HasOne<User>().WithMany().HasForeignKey("UserId"),
|
||||||
|
cu => cu.HasOne<Channel>().WithMany().HasForeignKey("ChannelId")
|
||||||
|
);
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
public DbSet<Game>? Games { get; set; }
|
public DbSet<Game>? Games { get; set; }
|
||||||
|
|
@ -254,5 +273,8 @@ namespace LANCommander.Data
|
||||||
public DbSet<Redistributable>? Redistributables { get; set; }
|
public DbSet<Redistributable>? Redistributables { get; set; }
|
||||||
|
|
||||||
public DbSet<Media>? Media { get; set; }
|
public DbSet<Media>? Media { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Message>? Messages { get; set; }
|
||||||
|
public DbSet<Channel>? Channels { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
9
LANCommander/Data/Enums/ChannelType.cs
Normal file
9
LANCommander/Data/Enums/ChannelType.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
namespace LANCommander.Data.Enums
|
||||||
|
{
|
||||||
|
public enum ChannelType
|
||||||
|
{
|
||||||
|
Standard,
|
||||||
|
DirectMessage,
|
||||||
|
Game,
|
||||||
|
}
|
||||||
|
}
|
||||||
18
LANCommander/Data/Models/Channel.cs
Normal file
18
LANCommander/Data/Models/Channel.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
using LANCommander.Data.Enums;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace LANCommander.Data.Models
|
||||||
|
{
|
||||||
|
[Table("Channels")]
|
||||||
|
public class Channel : BaseModel
|
||||||
|
{
|
||||||
|
[MaxLength(128)]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public ChannelType Type { get; set; } = ChannelType.Standard;
|
||||||
|
|
||||||
|
public virtual ICollection<Message>? Messages { get; set; }
|
||||||
|
public virtual ICollection<User>? Users { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
18
LANCommander/Data/Models/Message.cs
Normal file
18
LANCommander/Data/Models/Message.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace LANCommander.Data.Models
|
||||||
|
{
|
||||||
|
[Table("Messages")]
|
||||||
|
public class Message : BaseModel
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
[MaxLength(1024)]
|
||||||
|
public string Contents { get; set; }
|
||||||
|
|
||||||
|
public virtual User? Sender { get; set; }
|
||||||
|
public virtual Channel? Channel { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -51,6 +51,10 @@ namespace LANCommander.Data.Models
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual ICollection<Media>? Media { get; set; }
|
public virtual ICollection<Media>? Media { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual ICollection<Message>? Messages { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual ICollection<Channel>? Channels { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public bool Approved { get; set; }
|
public bool Approved { get; set; }
|
||||||
|
|
|
||||||
50
LANCommander/Hubs/ChatHub.cs
Normal file
50
LANCommander/Hubs/ChatHub.cs
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
using LANCommander.Data.Models;
|
||||||
|
using LANCommander.Services;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
|
namespace LANCommander.Hubs
|
||||||
|
{
|
||||||
|
[Authorize]
|
||||||
|
public class ChatHub : Hub
|
||||||
|
{
|
||||||
|
public static ChatService ChatService;
|
||||||
|
|
||||||
|
public ChatHub(ChatService chatService)
|
||||||
|
{
|
||||||
|
ChatService = chatService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Connect()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ChatService.Connect(Context.ConnectionId, Context.User.Identity.Name);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendMessage(Guid recipient, string message)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await ChatService.SendMessageToUserAsync(ChatService.GetUser(Context.ConnectionId).Id, recipient, message);
|
||||||
|
|
||||||
|
await Clients.Users(recipient.ToString()).SendAsync("ReceiveMessage", result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Message>> GetMessages(Guid channelId, int skip = 0, int take = 25)
|
||||||
|
{
|
||||||
|
return await ChatService.GetMessages(channelId, skip, take);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2148
LANCommander/Migrations/20240208020739_AddChat.Designer.cs
generated
Normal file
2148
LANCommander/Migrations/20240208020739_AddChat.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
157
LANCommander/Migrations/20240208020739_AddChat.cs
Normal file
157
LANCommander/Migrations/20240208020739_AddChat.cs
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LANCommander.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddChat : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Channels",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "TEXT", maxLength: 128, nullable: false),
|
||||||
|
Type = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
CreatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
CreatedById = table.Column<Guid>(type: "TEXT", nullable: true),
|
||||||
|
UpdatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
UpdatedById = table.Column<Guid>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Channels", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Channels_AspNetUsers_CreatedById",
|
||||||
|
column: x => x.CreatedById,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Channels_AspNetUsers_UpdatedById",
|
||||||
|
column: x => x.UpdatedById,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ChannelUsers",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
ChannelId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
UserId = table.Column<Guid>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ChannelUsers", x => new { x.ChannelId, x.UserId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ChannelUsers_AspNetUsers_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ChannelUsers_Channels_ChannelId",
|
||||||
|
column: x => x.ChannelId,
|
||||||
|
principalTable: "Channels",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Messages",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
Contents = table.Column<string>(type: "TEXT", maxLength: 1024, nullable: false),
|
||||||
|
SenderId = table.Column<Guid>(type: "TEXT", nullable: true),
|
||||||
|
ChannelId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
CreatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
CreatedById = table.Column<Guid>(type: "TEXT", nullable: true),
|
||||||
|
UpdatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
UpdatedById = table.Column<Guid>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Messages", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Messages_AspNetUsers_CreatedById",
|
||||||
|
column: x => x.CreatedById,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Messages_AspNetUsers_SenderId",
|
||||||
|
column: x => x.SenderId,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Messages_AspNetUsers_UpdatedById",
|
||||||
|
column: x => x.UpdatedById,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Messages_Channels_ChannelId",
|
||||||
|
column: x => x.ChannelId,
|
||||||
|
principalTable: "Channels",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Channels_CreatedById",
|
||||||
|
table: "Channels",
|
||||||
|
column: "CreatedById");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Channels_UpdatedById",
|
||||||
|
table: "Channels",
|
||||||
|
column: "UpdatedById");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ChannelUsers_UserId",
|
||||||
|
table: "ChannelUsers",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Messages_ChannelId",
|
||||||
|
table: "Messages",
|
||||||
|
column: "ChannelId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Messages_CreatedById",
|
||||||
|
table: "Messages",
|
||||||
|
column: "CreatedById");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Messages_SenderId",
|
||||||
|
table: "Messages",
|
||||||
|
column: "SenderId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Messages_UpdatedById",
|
||||||
|
table: "Messages",
|
||||||
|
column: "UpdatedById");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ChannelUsers");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Messages");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Channels");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,7 +16,7 @@ namespace LANCommander.Migrations
|
||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "8.0.0")
|
.HasAnnotation("ProductVersion", "8.0.1")
|
||||||
.HasAnnotation("Proxies:ChangeTracking", false)
|
.HasAnnotation("Proxies:ChangeTracking", false)
|
||||||
.HasAnnotation("Proxies:CheckEquality", false)
|
.HasAnnotation("Proxies:CheckEquality", false)
|
||||||
.HasAnnotation("Proxies:LazyLoading", true);
|
.HasAnnotation("Proxies:LazyLoading", true);
|
||||||
|
|
@ -36,6 +36,21 @@ namespace LANCommander.Migrations
|
||||||
b.ToTable("CategoryGame");
|
b.ToTable("CategoryGame");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ChannelUsers", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("ChannelId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("ChannelId", "UserId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("ChannelUsers");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("CollectionGame", b =>
|
modelBuilder.Entity("CollectionGame", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("CollectionId")
|
b.Property<Guid>("CollectionId")
|
||||||
|
|
@ -277,6 +292,41 @@ namespace LANCommander.Migrations
|
||||||
b.ToTable("Categories");
|
b.ToTable("Categories");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LANCommander.Data.Models.Channel", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CreatedById")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedOn")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UpdatedById")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedOn")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CreatedById");
|
||||||
|
|
||||||
|
b.HasIndex("UpdatedById");
|
||||||
|
|
||||||
|
b.ToTable("Channels");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LANCommander.Data.Models.Collection", b =>
|
modelBuilder.Entity("LANCommander.Data.Models.Collection", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
|
|
@ -583,6 +633,48 @@ namespace LANCommander.Migrations
|
||||||
b.ToTable("Media");
|
b.ToTable("Media");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LANCommander.Data.Models.Message", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("ChannelId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Contents")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CreatedById")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedOn")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("SenderId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UpdatedById")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedOn")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ChannelId");
|
||||||
|
|
||||||
|
b.HasIndex("CreatedById");
|
||||||
|
|
||||||
|
b.HasIndex("SenderId");
|
||||||
|
|
||||||
|
b.HasIndex("UpdatedById");
|
||||||
|
|
||||||
|
b.ToTable("Messages");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LANCommander.Data.Models.MultiplayerMode", b =>
|
modelBuilder.Entity("LANCommander.Data.Models.MultiplayerMode", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
|
|
@ -1270,6 +1362,21 @@ namespace LANCommander.Migrations
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ChannelUsers", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LANCommander.Data.Models.Channel", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ChannelId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LANCommander.Data.Models.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("CollectionGame", b =>
|
modelBuilder.Entity("CollectionGame", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.Collection", null)
|
b.HasOne("LANCommander.Data.Models.Collection", null)
|
||||||
|
|
@ -1451,6 +1558,23 @@ namespace LANCommander.Migrations
|
||||||
b.Navigation("UpdatedBy");
|
b.Navigation("UpdatedBy");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LANCommander.Data.Models.Channel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
b.Navigation("UpdatedBy");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LANCommander.Data.Models.Collection", b =>
|
modelBuilder.Entity("LANCommander.Data.Models.Collection", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
|
|
@ -1620,6 +1744,37 @@ namespace LANCommander.Migrations
|
||||||
b.Navigation("User");
|
b.Navigation("User");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LANCommander.Data.Models.Message", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LANCommander.Data.Models.Channel", "Channel")
|
||||||
|
.WithMany("Messages")
|
||||||
|
.HasForeignKey("ChannelId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.HasOne("LANCommander.Data.Models.User", "Sender")
|
||||||
|
.WithMany("Messages")
|
||||||
|
.HasForeignKey("SenderId");
|
||||||
|
|
||||||
|
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UpdatedById")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("Channel");
|
||||||
|
|
||||||
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
b.Navigation("Sender");
|
||||||
|
|
||||||
|
b.Navigation("UpdatedBy");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LANCommander.Data.Models.MultiplayerMode", b =>
|
modelBuilder.Entity("LANCommander.Data.Models.MultiplayerMode", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||||
|
|
@ -1926,6 +2081,11 @@ namespace LANCommander.Migrations
|
||||||
b.Navigation("Children");
|
b.Navigation("Children");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LANCommander.Data.Models.Channel", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Messages");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LANCommander.Data.Models.Game", b =>
|
modelBuilder.Entity("LANCommander.Data.Models.Game", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Actions");
|
b.Navigation("Actions");
|
||||||
|
|
@ -1975,6 +2135,8 @@ namespace LANCommander.Migrations
|
||||||
|
|
||||||
b.Navigation("Media");
|
b.Navigation("Media");
|
||||||
|
|
||||||
|
b.Navigation("Messages");
|
||||||
|
|
||||||
b.Navigation("PlaySessions");
|
b.Navigation("PlaySessions");
|
||||||
});
|
});
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,10 @@ namespace LANCommander
|
||||||
builder.Services.AddScoped<IMediaGrabberService, SteamGridDBMediaGrabber>();
|
builder.Services.AddScoped<IMediaGrabberService, SteamGridDBMediaGrabber>();
|
||||||
builder.Services.AddScoped<WikiService>();
|
builder.Services.AddScoped<WikiService>();
|
||||||
builder.Services.AddScoped<UpdateService>();
|
builder.Services.AddScoped<UpdateService>();
|
||||||
|
builder.Services.AddScoped<MessageService>();
|
||||||
|
builder.Services.AddScoped<ChannelService>();
|
||||||
|
|
||||||
|
builder.Services.AddSingleton<ChatService>();
|
||||||
|
|
||||||
builder.Services.AddSingleton<ServerProcessService>();
|
builder.Services.AddSingleton<ServerProcessService>();
|
||||||
builder.Services.AddSingleton<IPXRelayService>();
|
builder.Services.AddSingleton<IPXRelayService>();
|
||||||
|
|
@ -241,6 +245,7 @@ namespace LANCommander
|
||||||
|
|
||||||
app.MapHub<LoggingHub>("/hubs/logging");
|
app.MapHub<LoggingHub>("/hubs/logging");
|
||||||
app.MapHub<GameServerHub>("/hubs/gameserver");
|
app.MapHub<GameServerHub>("/hubs/gameserver");
|
||||||
|
app.MapHub<ChatHub>("/hubs/chat");
|
||||||
|
|
||||||
Logger.Debug("Registering Endpoints");
|
Logger.Debug("Registering Endpoints");
|
||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
|
|
|
||||||
12
LANCommander/Services/ChannelService.cs
Normal file
12
LANCommander/Services/ChannelService.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
using LANCommander.Data;
|
||||||
|
using LANCommander.Data.Models;
|
||||||
|
|
||||||
|
namespace LANCommander.Services
|
||||||
|
{
|
||||||
|
public class ChannelService : BaseDatabaseService<Channel>
|
||||||
|
{
|
||||||
|
public ChannelService(DatabaseContext dbContext, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
91
LANCommander/Services/ChatService.cs
Normal file
91
LANCommander/Services/ChatService.cs
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
using LANCommander.Data;
|
||||||
|
using LANCommander.Data.Models;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LANCommander.Services
|
||||||
|
{
|
||||||
|
public class ChatService
|
||||||
|
{
|
||||||
|
private readonly IServiceScopeFactory ScopeFactory;
|
||||||
|
private Dictionary<string, User> Connections { get; set; }
|
||||||
|
|
||||||
|
public ChatService(IServiceScopeFactory scopeFactory)
|
||||||
|
{
|
||||||
|
ScopeFactory = scopeFactory;
|
||||||
|
Connections = new Dictionary<string, User>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Connect(string connectionId, string username)
|
||||||
|
{
|
||||||
|
using (var scope = ScopeFactory.CreateScope())
|
||||||
|
{
|
||||||
|
var context = scope.ServiceProvider.GetRequiredService<DatabaseContext>();
|
||||||
|
|
||||||
|
var user = await context.Users.FirstOrDefaultAsync(u => u.UserName == username);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
throw new UnauthorizedAccessException();
|
||||||
|
|
||||||
|
Connections[connectionId] = user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public User GetUser(string connectionId)
|
||||||
|
{
|
||||||
|
return Connections[connectionId];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Message> SendMessageToUserAsync(Guid senderId, Guid recipientId, string contents)
|
||||||
|
{
|
||||||
|
using (var scope = ScopeFactory.CreateScope())
|
||||||
|
{
|
||||||
|
var context = scope.ServiceProvider.GetRequiredService<DatabaseContext>();
|
||||||
|
|
||||||
|
var sender = await context.Users.FirstOrDefaultAsync(u => u.Id == senderId);
|
||||||
|
var recipient = await context.Users.FirstOrDefaultAsync(u => u.Id == recipientId);
|
||||||
|
|
||||||
|
var channel = sender.Channels.FirstOrDefault(c => c.Users.Count() == 2 && c.Users.Any(u => u.Id == recipientId));
|
||||||
|
|
||||||
|
// Create DM channel if it doesn't already exist
|
||||||
|
if (channel == null)
|
||||||
|
{
|
||||||
|
channel = new Channel
|
||||||
|
{
|
||||||
|
Type = Data.Enums.ChannelType.DirectMessage,
|
||||||
|
CreatedBy = sender,
|
||||||
|
Users = new List<User> { sender, recipient },
|
||||||
|
Name = "Direct Message",
|
||||||
|
CreatedOn = DateTime.Now
|
||||||
|
};
|
||||||
|
|
||||||
|
await context.AddAsync(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = new Message
|
||||||
|
{
|
||||||
|
Channel = channel,
|
||||||
|
Contents = contents,
|
||||||
|
CreatedBy = sender,
|
||||||
|
Sender = sender,
|
||||||
|
CreatedOn = DateTime.Now
|
||||||
|
};
|
||||||
|
|
||||||
|
await context.AddAsync(message);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Message>> GetMessages(Guid channelId, int skip = 0, int take = 25)
|
||||||
|
{
|
||||||
|
using (var scope = ScopeFactory.CreateScope())
|
||||||
|
{
|
||||||
|
var context = scope.ServiceProvider.GetRequiredService<DatabaseContext>();
|
||||||
|
|
||||||
|
return await context.Messages.Where(m => m.Channel.Id == channelId).OrderByDescending(m => m.CreatedOn).Skip(skip).Take(take).ToListAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
LANCommander/Services/MessageService.cs
Normal file
12
LANCommander/Services/MessageService.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
using LANCommander.Data;
|
||||||
|
using LANCommander.Data.Models;
|
||||||
|
|
||||||
|
namespace LANCommander.Services
|
||||||
|
{
|
||||||
|
public class MessageService : BaseDatabaseService<Message>
|
||||||
|
{
|
||||||
|
public MessageService(DatabaseContext dbContext, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,7 +23,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
<link href="_content/XtermBlazor/XtermBlazor.css" rel="stylesheet" />
|
<link href="_content/XtermBlazor/XtermBlazor.css" rel="stylesheet" />
|
||||||
|
|
||||||
<link href="~/css/site.css" rel="stylesheet" />
|
<link href="~/css/site.css" rel="stylesheet" />
|
||||||
</head>
|
</head>
|
||||||
<body data-theme="@SettingService.GetSettings().Theme">
|
<body data-theme="@SettingService.GetSettings().Theme">
|
||||||
|
|
@ -37,6 +36,7 @@
|
||||||
<script src="~/_content/AntDesign/js/ant-design-blazor.js"></script>
|
<script src="~/_content/AntDesign/js/ant-design-blazor.js"></script>
|
||||||
<script src="~/_content/AntDesign.Charts/ant-design-charts-blazor.js"></script>
|
<script src="~/_content/AntDesign.Charts/ant-design-charts-blazor.js"></script>
|
||||||
<script src="~/_framework/blazor.server.js"></script>
|
<script src="~/_framework/blazor.server.js"></script>
|
||||||
|
<script src="~/lib/signalr/dist/browser/signalr.min.js"></script>
|
||||||
|
|
||||||
<script src="~/_content/XtermBlazor/XtermBlazor.min.js"></script>
|
<script src="~/_content/XtermBlazor/XtermBlazor.min.js"></script>
|
||||||
<script src="~/lib/xterm-addon-fit/lib/xterm-addon-fit.min.js"></script>
|
<script src="~/lib/xterm-addon-fit/lib/xterm-addon-fit.min.js"></script>
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,14 @@
|
||||||
"files": [
|
"files": [
|
||||||
"axios.min.js"
|
"axios.min.js"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"provider": "unpkg",
|
||||||
|
"library": "@microsoft/signalr@latest",
|
||||||
|
"destination": "wwwroot/lib/signalr/",
|
||||||
|
"files": [
|
||||||
|
"dist/browser/signalr.min.js"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue