diff --git a/Behavior/Detiktokify.cs b/Behavior/Detiktokify.cs index 0864860..e80bb68 100644 --- a/Behavior/Detiktokify.cs +++ b/Behavior/Detiktokify.cs @@ -29,6 +29,9 @@ public class Detiktokify : Behavior if(message.Channel.EffectivePermissions.MaxAttachmentBytes == 0) return false; + if(Behaver.Instance.Selves.Any(acc => acc.Id == message.Author.Id)) + return false; + var wordLikes = message.Content.Split(' ', StringSplitOptions.TrimEntries); var possibleLinks = wordLikes?.Where(wl => Uri.IsWellFormedUriString(wl, UriKind.Absolute)).Select(wl => new Uri(wl)); if (possibleLinks != null && possibleLinks.Count() > 0) @@ -51,7 +54,7 @@ public class Detiktokify : Behavior { Console.WriteLine("detiktokifying"); #pragma warning disable 4014 - await message.React("<:tiktok:1070038619584200884>"); + //await message.React("<:tiktok:1070038619584200884>"); #pragma warning restore 4014 var res = await ytdl.RunVideoDownload(link.ToString()); @@ -66,7 +69,7 @@ public class Detiktokify : Behavior string path = res.Data; if (File.Exists(path)) { - var bytesize = new System.IO.FileInfo(path).Length; + ulong bytesize = (ulong)((new System.IO.FileInfo(path)).Length); if (bytesize < message.Channel.EffectivePermissions.MaxAttachmentBytes - 256) { try diff --git a/DiscordInterface/DiscordInterface.cs b/DiscordInterface/DiscordInterface.cs index 0b51883..c483d63 100644 --- a/DiscordInterface/DiscordInterface.cs +++ b/DiscordInterface/DiscordInterface.cs @@ -9,6 +9,9 @@ using Discord.WebSocket; using vassago.Models; using vassago.Behavior; using Discord.Rest; +using Microsoft.EntityFrameworkCore; +using System.Threading; +using System.Reactive.Linq; namespace vassago.DiscordInterface; @@ -18,15 +21,11 @@ public class DiscordInterface internal DiscordSocketClient client; private bool eventsSignedUp = false; private ChattingContext _db; - private static PermissionSettings defaultPermissions = new PermissionSettings() - { - MeannessFilterLevel = 1, - LewdnessFilterLevel = 3, - MaxTextChars = 2000, - MaxAttachmentBytes = 8 * 1024 * 1024, - LinksAllowed = true, - ReactionsPossible = true - }; + private static SemaphoreSlim discordChannelSetup = new SemaphoreSlim(1, 1); + private Channel protocolAsChannel; + private Queue backfillChannels = new Queue(); + private Queue backfillAccounts = new Queue(); + public DiscordInterface() { _db = new ChattingContext(); @@ -34,6 +33,7 @@ public class DiscordInterface public async Task Init(string token) { + await SetupDiscordChannel(); client = new DiscordSocketClient(new DiscordSocketConfig() { GatewayIntents = GatewayIntents.All }); client.Log += (msg) => @@ -42,55 +42,91 @@ public class DiscordInterface return Task.CompletedTask; }; client.Connected += SelfConnected; - - client.Ready += () => Task.Run(() => - { - if (!eventsSignedUp) - { - eventsSignedUp = true; - Console.WriteLine($"Bot is connected {client.CurrentUser.Mention}! going to sign up for message received and user joined in client ready"); - - client.MessageReceived += MessageReceived; - // _client.MessageUpdated += - // client.UserJoined += UserJoined; - client.SlashCommandExecuted += SlashCommandHandler; - // _client.ChannelCreated += - // _client.ChannelDestroyed += - // _client.ChannelUpdated += - // _client.GuildMemberUpdated += - // _client.UserBanned += - // _client.UserLeft += - // _client.ThreadCreated += - // _client.ThreadUpdated += - // _client.ThreadDeleted += - // _client.JoinedGuild += - // _client.GuildUpdated += - // _client.LeftGuild += - - SlashCommandsHelper.Register(client).GetAwaiter().GetResult(); - } - else - { - Console.WriteLine("bot appears to be RE connected, so I'm not going to sign up twice"); - } - }); + client.Ready += ClientReady; await client.LoginAsync(TokenType.Bot, token); await client.StartAsync(); + + BackfillLoop(); + } + + private async Task SetupDiscordChannel() + { + await discordChannelSetup.WaitAsync(); + + try + { + protocolAsChannel = _db.Channels.FirstOrDefault(c => c.ParentChannel == null && c.Protocol == "discord"); + if (protocolAsChannel == null) + { + protocolAsChannel = new Channel() + { + DisplayName = "discord (itself)", + Permissions = new PermissionSettings() + { + MeannessFilterLevel = 1, + LewdnessFilterLevel = 3, + MaxTextChars = 2000, + MaxAttachmentBytes = 25 * 1024 * 1024, //allegedly it's 25, but I worry it's not actually. + LinksAllowed = true, + ReactionsPossible = true + }, + ExternalId = null, + Protocol = PROTOCOL, + SubChannels = new List() + }; + protocolAsChannel.SendMessage = (t) => { throw new InvalidOperationException($"discord itself cannot accept text"); }; + protocolAsChannel.SendFile = (f, t) => { throw new InvalidOperationException($"discord itself cannot send file"); }; + _db.Channels.Add(protocolAsChannel); + _db.SaveChanges(); + } + } + finally + { + discordChannelSetup.Release(); + } + } + + private async Task ClientReady() + { + if (!eventsSignedUp) + { + eventsSignedUp = true; + Console.WriteLine($"Bot is connected ({client.CurrentUser.Username}; {client.CurrentUser.Mention})! going to sign up for message received and user joined in client ready"); + + client.MessageReceived += MessageReceived; + // _client.MessageUpdated += + //client.UserJoined += UserJoined; + client.SlashCommandExecuted += SlashCommandHandler; + //client.ChannelCreated += + // _client.ChannelDestroyed += + // _client.ChannelUpdated += + // _client.GuildMemberUpdated += + // _client.UserBanned += + // _client.UserLeft += + // _client.ThreadCreated += + // _client.ThreadUpdated += + // _client.ThreadDeleted += + // _client.JoinedGuild += + // _client.GuildUpdated += + // _client.LeftGuild += + + await SlashCommandsHelper.Register(client); + } + else + { + Console.WriteLine("bot appears to be RE connected, so I'm not going to sign up twice"); + } } private async Task SelfConnected() { - var selfUser = UpsertAccount(client.CurrentUser); await _db.SaveChangesAsync(); Behaver.Instance.Selves.Add(selfUser); } -#pragma warning disable 4014 //the "you're not awaiting this" warning. yeah I know, that's the beauty of an async method lol -#pragma warning disable 1998 //the "it's async but you're not awaiting anything". private async Task MessageReceived(SocketMessage messageParam) -#pragma warning restore 1998 { var suMessage = messageParam as SocketUserMessage; if (suMessage == null) @@ -107,24 +143,21 @@ public class DiscordInterface var mentionOfMe = "<@" + client.CurrentUser.Id + ">"; m.MentionsMe = true; } - - // if ((suMessage.Author.Id != client.CurrentUser.Id)) + if (await Behaver.Instance.ActOn(m)) { - if (await Behaver.Instance.ActOn(m)) - { - m.ActedOn = true; - } + m.ActedOn = true; } _db.SaveChanges(); } private void UserJoined(SocketGuildUser arg) { - var guild = UpsertChannel(arg.Guild); var defaultChannel = UpsertChannel(arg.Guild.DefaultChannel); defaultChannel.ParentChannel = guild; var u = UpsertAccount(arg); + u.SeenInChannel = guild; + u.DisplayName = arg.DisplayName; } private async Task ButtonHandler(SocketMessageComponent component) { @@ -164,12 +197,11 @@ public class DiscordInterface internal vassago.Models.Attachment UpsertAttachment(IAttachment dAttachment) { - var addPlease = false; var a = _db.Attachments.FirstOrDefault(ai => ai.ExternalId == dAttachment.Id); if (a == null) { - addPlease = true; a = new vassago.Models.Attachment(); + _db.Attachments.Add(a); } a.ContentType = dAttachment.ContentType; a.Description = dAttachment.Description; @@ -177,20 +209,15 @@ public class DiscordInterface a.Size = dAttachment.Size; a.Source = new Uri(dAttachment.Url); - if (addPlease) - { - _db.Attachments.Add(a); - } return a; } internal Message UpsertMessage(IUserMessage dMessage) { - var addPlease = false; var m = _db.Messages.FirstOrDefault(mi => mi.ExternalId == dMessage.Id); if (m == null) { - addPlease = true; m = new Message(); + _db.Messages.Add(m); } m.Attachments = m.Attachments ?? new List(); if (dMessage.Attachments?.Any() == true) @@ -208,19 +235,89 @@ public class DiscordInterface m.Timestamp = dMessage.EditedTimestamp ?? dMessage.CreatedAt; - if(dMessage.Author.Id != client.CurrentUser.Id && dMessage.MentionedUserIds?.FirstOrDefault(muid => muid == client.CurrentUser.Id) != null) + if (dMessage.Author.Id != client.CurrentUser.Id && dMessage.MentionedUserIds?.FirstOrDefault(muid => muid == client.CurrentUser.Id) != null) { m.MentionsMe = true; } - if (addPlease) - { - _db.Messages.Add(m); - } m.Reply = (t) => { return dMessage.ReplyAsync(t); }; m.React = (e) => { return attemptReact(dMessage, e); }; return m; } + internal Channel UpsertChannel(IMessageChannel channel) + { + Channel c = _db.Channels.FirstOrDefault(ci => ci.ExternalId == channel.Id); + if (c == null) + { + c = new Channel(); + _db.Channels.Add(c); + backfillChannels.Enqueue(channel.Id); + } + + c.DisplayName = channel.Name; + c.ExternalId = channel.Id; + c.IsDM = channel is IPrivateChannel; + c.Messages = c.Messages ?? new List(); + c.Protocol = PROTOCOL; + if (channel is IGuildChannel) + { + c.ParentChannel = UpsertChannel((channel as IGuildChannel).Guild); + c.ParentChannel.SubChannels.Add(c); + } + else if (channel is IPrivateChannel) + { + c.ParentChannel = protocolAsChannel; + } + else + { + c.ParentChannel = protocolAsChannel; + Console.Error.WriteLine($"trying to upsert channel {channel.Id}/{channel.Name}, but it's neither guildchannel nor private channel. shrug.jpg"); + } + c.SubChannels = c.SubChannels ?? new List(); + c.SendMessage = (t) => { return channel.SendMessageAsync(t); }; + c.SendFile = (f, t) => { return channel.SendFileAsync(f, t); }; + return c; + } + internal Channel UpsertChannel(IGuild channel) + { + Channel c = _db.Channels.FirstOrDefault(ci => ci.ExternalId == channel.Id); + if (c == null) + { + c = new Channel(); + _db.Channels.Add(c); + backfillChannels.Enqueue(channel.Id); + } + + c.DisplayName = channel.Name; + c.ExternalId = channel.Id; + c.IsDM = false; + c.Messages = c.Messages ?? new List(); + c.Protocol = protocolAsChannel.Protocol; + c.ParentChannel = protocolAsChannel; + c.SubChannels = c.SubChannels ?? new List(); + c.Permissions = c.Permissions ?? new PermissionSettings(); + c.Permissions.MaxAttachmentBytes = channel.MaxUploadLimit; + + c.SendMessage = (t) => { throw new InvalidOperationException($"channel {channel.Name} is guild; cannot accept text"); }; + c.SendFile = (f, t) => { throw new InvalidOperationException($"channel {channel.Name} is guild; send file"); }; + return c; + } + internal Account UpsertAccount(IUser user) + { + var acc = _db.Accounts.FirstOrDefault(ui => ui.ExternalId == user.Id); + if (acc == null) + { + acc = new Account(); + _db.Accounts.Add(acc); + backfillAccounts.Enqueue(user.Id); + } + acc.Username = user.Username; + acc.ExternalId = user.Id; + acc.IsBot = user.IsBot || user.IsWebhook; + acc.Protocol = PROTOCOL; + + return acc; + } private Task attemptReact(IUserMessage msg, string e) { @@ -243,110 +340,68 @@ public class DiscordInterface return msg.AddReactionAsync(emote); } - internal Channel UpsertChannel(IMessageChannel channel) + internal async void BackfillLoop() { - var addPlease = false; - Channel c = _db.Channels.FirstOrDefault(ci => ci.ExternalId == channel.Id); - if (c == null) + while (true) { - addPlease = true; - c = new Channel(); - } + Thread.Sleep(TimeSpan.FromMinutes(2)); + if(backfillChannels.Any()) + { + var ch = backfillChannels.Dequeue(); + var channelFromDiscord = client.GetChannel(ch); + if(channelFromDiscord is ITextChannel) + { + var textChannel = channelFromDiscord as ITextChannel; + var msgs = await textChannel.GetMessagesAsync().FlattenAsync(); + foreach(var msg in msgs) + { + if(msg.Type == MessageType.Default) + { + UpsertMessage((IUserMessage)msg); + } + } + } + if(channelFromDiscord is IGuild) + { + var guild = (channelFromDiscord as IGuild); + foreach(var subCh in await guild.GetChannelsAsync()) + { + //UpsertChannel(subCh); + } + } + if(channelFromDiscord is IGuildChannel) + { + var guildChannel = channelFromDiscord as IGuildChannel; + var users = await guildChannel.GetUsersAsync().FlattenAsync(); + foreach(var user in users) + { + UpsertAccount(user); + } + } + _db.SaveChanges(); + } - c.DisplayName = channel.Name; - c.ExternalId = channel.Id; - c.IsDM = channel is IPrivateChannel; - c.Messages = c.Messages ?? new List(); - c.Protocol = PROTOCOL; - if (channel is IGuildChannel) - { - c.ParentChannel = UpsertChannel((channel as IGuildChannel).Guild); - c.ParentChannel.SubChannels.Add(c); - } - else if (channel is IPrivateChannel) - { - c.ParentChannel = null; - } - else - { - c.ParentChannel = null; - Console.Error.WriteLine($"trying to upsert channel {channel.Id}/{channel.Name}, but it's neither guildchannel nor private channel. shrug.jpg"); - } - c.SubChannels = c.SubChannels ?? new List(); - if (addPlease) - { - _db.Channels.Add(c); - } + for(int i = 0; i < 10 && backfillAccounts.Any(); i++) + { + var aci = backfillAccounts.Dequeue(); - c.SendMessage = (t) => { return channel.SendMessageAsync(t); }; - c.SendFile = (f, t) => { return channel.SendFileAsync(f, t); }; - return c; - } - internal Channel UpsertChannel(IGuild channel) - { - var addPlease = false; - Channel c = _db.Channels.FirstOrDefault(ci => ci.ExternalId == channel.Id); - if (c == null) - { - addPlease = true; - c = new Channel(); - } - - c.DisplayName = channel.Name; - c.ExternalId = channel.Id; - c.IsDM = false; - c.Messages = c.Messages ?? new List(); - c.Protocol = PROTOCOL; - c.ParentChannel = null; - c.SubChannels = c.SubChannels ?? new List(); - if (addPlease) - { - _db.Channels.Add(c); - } - - c.SendMessage = (t) => { throw new InvalidOperationException($"channel {channel.Name} is guild; cannot accept text"); }; - c.SendFile = (f, t) => { throw new InvalidOperationException($"channel {channel.Name} is guild; send file"); }; - return c; - } - internal Account UpsertAccount(IUser user) - { - var addPlease = false; - var u = _db.Users.FirstOrDefault(ui => ui.ExternalId == user.Id); - if (u == null) - { - addPlease = true; - u = new Account(); - } - u.Username = user.Username; - u.ExternalId = user.Id; - u.IsBot = user.IsBot || user.IsWebhook; - u.Protocol = PROTOCOL; - if (addPlease) - { - _db.Users.Add(u); - } - - return u; - } - internal async void BackfillChannelInfo(Channel channel) - { - //TODO: some sort of "when you get around to it" task queue - - //c.Messages = await channel.GetMessagesAsync(); //TODO: this - //c.OtherUsers = c.OtherUsers ?? new List(); - //c.OtherUsers = await channel.GetUsersAsync(); - var dChannel = client.GetChannel(channel.ExternalId.Value); - if (dChannel is IGuild) - { - var guild = channel as IGuild; - } - else if (dChannel is IGuildChannel) - { - var gc = dChannel as IGuildChannel; - } - else if (dChannel is IPrivateChannel) - { - var dm = dChannel as IPrivateChannel; + var acc = UpsertAccount(await client.GetUserAsync(aci)); + if (acc.IsUser == null) + { + var internalUser = _db.Users.FirstOrDefault(u => + u.Accounts.Any(ua => ua.ExternalId == acc.ExternalId && ua.Protocol == acc.Protocol)); + if (internalUser == null) + { + internalUser = new User() + { + Accounts = new List() { acc } + }; + _db.Users.Add(internalUser); + } + acc.IsUser = internalUser; + } + } + _db.SaveChanges(); } } } \ No newline at end of file diff --git a/Migrations/20230628035812_NotionOfUserAccount.Designer.cs b/Migrations/20230628035812_NotionOfUserAccount.Designer.cs new file mode 100644 index 0000000..f241c74 --- /dev/null +++ b/Migrations/20230628035812_NotionOfUserAccount.Designer.cs @@ -0,0 +1,290 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using vassago.Models; + +#nullable disable + +namespace vassago.Migrations +{ + [DbContext(typeof(ChattingContext))] + [Migration("20230628035812_NotionOfUserAccount")] + partial class NotionOfUserAccount + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("vassago.Models.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("numeric(20,0)"); + + b.Property("IsBot") + .HasColumnType("boolean"); + + b.Property("IsUserId") + .HasColumnType("uuid"); + + b.Property("PermissionTags") + .HasColumnType("integer[]"); + + b.Property("Protocol") + .HasColumnType("text"); + + b.Property("SeenInChannelId") + .HasColumnType("uuid"); + + b.Property("Username") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("IsUserId"); + + b.HasIndex("SeenInChannelId"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("vassago.Models.Attachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Content") + .HasColumnType("bytea"); + + b.Property("ContentType") + .HasColumnType("text"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("numeric(20,0)"); + + b.Property("Filename") + .HasColumnType("text"); + + b.Property("MessageId") + .HasColumnType("uuid"); + + b.Property("Size") + .HasColumnType("integer"); + + b.Property("Source") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("MessageId"); + + b.ToTable("Attachments"); + }); + + modelBuilder.Entity("vassago.Models.Channel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("numeric(20,0)"); + + b.Property("IsDM") + .HasColumnType("boolean"); + + b.Property("ParentChannelId") + .HasColumnType("uuid"); + + b.Property("PermissionsId") + .HasColumnType("integer"); + + b.Property("Protocol") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ParentChannelId"); + + b.HasIndex("PermissionsId"); + + b.ToTable("Channels"); + }); + + modelBuilder.Entity("vassago.Models.Message", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ActedOn") + .HasColumnType("boolean"); + + b.Property("AuthorId") + .HasColumnType("uuid"); + + b.Property("ChannelId") + .HasColumnType("uuid"); + + b.Property("Content") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("numeric(20,0)"); + + b.Property("MentionsMe") + .HasColumnType("boolean"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.HasIndex("ChannelId"); + + b.ToTable("Messages"); + }); + + modelBuilder.Entity("vassago.Models.PermissionSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("LewdnessFilterLevel") + .HasColumnType("integer"); + + b.Property("LinksAllowed") + .HasColumnType("boolean"); + + b.Property("MaxAttachmentBytes") + .HasColumnType("numeric(20,0)"); + + b.Property("MaxTextChars") + .HasColumnType("bigint"); + + b.Property("MeannessFilterLevel") + .HasColumnType("integer"); + + b.Property("ReactionsPossible") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("PermissionSettings"); + }); + + modelBuilder.Entity("vassago.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("vassago.Models.Account", b => + { + b.HasOne("vassago.Models.User", "IsUser") + .WithMany("Accounts") + .HasForeignKey("IsUserId"); + + b.HasOne("vassago.Models.Channel", "SeenInChannel") + .WithMany("Users") + .HasForeignKey("SeenInChannelId"); + + b.Navigation("IsUser"); + + b.Navigation("SeenInChannel"); + }); + + modelBuilder.Entity("vassago.Models.Attachment", b => + { + b.HasOne("vassago.Models.Message", "Message") + .WithMany("Attachments") + .HasForeignKey("MessageId"); + + b.Navigation("Message"); + }); + + modelBuilder.Entity("vassago.Models.Channel", b => + { + b.HasOne("vassago.Models.Channel", "ParentChannel") + .WithMany("SubChannels") + .HasForeignKey("ParentChannelId"); + + b.HasOne("vassago.Models.PermissionSettings", "Permissions") + .WithMany() + .HasForeignKey("PermissionsId"); + + b.Navigation("ParentChannel"); + + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("vassago.Models.Message", b => + { + b.HasOne("vassago.Models.Account", "Author") + .WithMany() + .HasForeignKey("AuthorId"); + + b.HasOne("vassago.Models.Channel", "Channel") + .WithMany("Messages") + .HasForeignKey("ChannelId"); + + b.Navigation("Author"); + + b.Navigation("Channel"); + }); + + modelBuilder.Entity("vassago.Models.Channel", b => + { + b.Navigation("Messages"); + + b.Navigation("SubChannels"); + + b.Navigation("Users"); + }); + + modelBuilder.Entity("vassago.Models.Message", b => + { + b.Navigation("Attachments"); + }); + + modelBuilder.Entity("vassago.Models.User", b => + { + b.Navigation("Accounts"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/20230628035812_NotionOfUserAccount.cs b/Migrations/20230628035812_NotionOfUserAccount.cs new file mode 100644 index 0000000..703a199 --- /dev/null +++ b/Migrations/20230628035812_NotionOfUserAccount.cs @@ -0,0 +1,192 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace vassago.Migrations +{ + /// + public partial class NotionOfUserAccount : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Messages_Users_AuthorId", + table: "Messages"); + + migrationBuilder.DropForeignKey( + name: "FK_Users_Channels_SeenInChannelId", + table: "Users"); + + migrationBuilder.DropIndex( + name: "IX_Users_SeenInChannelId", + table: "Users"); + + migrationBuilder.DropColumn( + name: "DisplayName", + table: "Users"); + + migrationBuilder.DropColumn( + name: "ExternalId", + table: "Users"); + + migrationBuilder.DropColumn( + name: "IsBot", + table: "Users"); + + migrationBuilder.DropColumn( + name: "PermissionTags", + table: "Users"); + + migrationBuilder.DropColumn( + name: "Protocol", + table: "Users"); + + migrationBuilder.DropColumn( + name: "SeenInChannelId", + table: "Users"); + + migrationBuilder.DropColumn( + name: "Username", + table: "Users"); + + migrationBuilder.AlterColumn( + name: "MaxAttachmentBytes", + table: "PermissionSettings", + type: "numeric(20,0)", + nullable: true, + oldClrType: typeof(long), + oldType: "bigint", + oldNullable: true); + + migrationBuilder.CreateTable( + name: "Accounts", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + ExternalId = table.Column(type: "numeric(20,0)", nullable: true), + Username = table.Column(type: "text", nullable: true), + DisplayName = table.Column(type: "text", nullable: true), + IsBot = table.Column(type: "boolean", nullable: false), + SeenInChannelId = table.Column(type: "uuid", nullable: true), + PermissionTags = table.Column(type: "integer[]", nullable: true), + Protocol = table.Column(type: "text", nullable: true), + IsUserId = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Accounts", x => x.Id); + table.ForeignKey( + name: "FK_Accounts_Channels_SeenInChannelId", + column: x => x.SeenInChannelId, + principalTable: "Channels", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_Accounts_Users_IsUserId", + column: x => x.IsUserId, + principalTable: "Users", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_Accounts_IsUserId", + table: "Accounts", + column: "IsUserId"); + + migrationBuilder.CreateIndex( + name: "IX_Accounts_SeenInChannelId", + table: "Accounts", + column: "SeenInChannelId"); + + migrationBuilder.AddForeignKey( + name: "FK_Messages_Accounts_AuthorId", + table: "Messages", + column: "AuthorId", + principalTable: "Accounts", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Messages_Accounts_AuthorId", + table: "Messages"); + + migrationBuilder.DropTable( + name: "Accounts"); + + migrationBuilder.AddColumn( + name: "DisplayName", + table: "Users", + type: "text", + nullable: true); + + migrationBuilder.AddColumn( + name: "ExternalId", + table: "Users", + type: "numeric(20,0)", + nullable: true); + + migrationBuilder.AddColumn( + name: "IsBot", + table: "Users", + type: "boolean", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "PermissionTags", + table: "Users", + type: "integer[]", + nullable: true); + + migrationBuilder.AddColumn( + name: "Protocol", + table: "Users", + type: "text", + nullable: true); + + migrationBuilder.AddColumn( + name: "SeenInChannelId", + table: "Users", + type: "uuid", + nullable: true); + + migrationBuilder.AddColumn( + name: "Username", + table: "Users", + type: "text", + nullable: true); + + migrationBuilder.AlterColumn( + name: "MaxAttachmentBytes", + table: "PermissionSettings", + type: "bigint", + nullable: true, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)", + oldNullable: true); + + migrationBuilder.CreateIndex( + name: "IX_Users_SeenInChannelId", + table: "Users", + column: "SeenInChannelId"); + + migrationBuilder.AddForeignKey( + name: "FK_Messages_Users_AuthorId", + table: "Messages", + column: "AuthorId", + principalTable: "Users", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_Users_Channels_SeenInChannelId", + table: "Users", + column: "SeenInChannelId", + principalTable: "Channels", + principalColumn: "Id"); + } + } +} diff --git a/Migrations/ChattingContextModelSnapshot.cs b/Migrations/ChattingContextModelSnapshot.cs index 35bf3c4..fa29f04 100644 --- a/Migrations/ChattingContextModelSnapshot.cs +++ b/Migrations/ChattingContextModelSnapshot.cs @@ -37,6 +37,9 @@ namespace vassago.Migrations b.Property("IsBot") .HasColumnType("boolean"); + b.Property("IsUserId") + .HasColumnType("uuid"); + b.Property("PermissionTags") .HasColumnType("integer[]"); @@ -51,9 +54,11 @@ namespace vassago.Migrations b.HasKey("Id"); + b.HasIndex("IsUserId"); + b.HasIndex("SeenInChannelId"); - b.ToTable("Users"); + b.ToTable("Accounts"); }); modelBuilder.Entity("vassago.Models.Attachment", b => @@ -176,8 +181,8 @@ namespace vassago.Migrations b.Property("LinksAllowed") .HasColumnType("boolean"); - b.Property("MaxAttachmentBytes") - .HasColumnType("bigint"); + b.Property("MaxAttachmentBytes") + .HasColumnType("numeric(20,0)"); b.Property("MaxTextChars") .HasColumnType("bigint"); @@ -193,12 +198,29 @@ namespace vassago.Migrations b.ToTable("PermissionSettings"); }); + modelBuilder.Entity("vassago.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + modelBuilder.Entity("vassago.Models.Account", b => { + b.HasOne("vassago.Models.User", "IsUser") + .WithMany("Accounts") + .HasForeignKey("IsUserId"); + b.HasOne("vassago.Models.Channel", "SeenInChannel") .WithMany("Users") .HasForeignKey("SeenInChannelId"); + b.Navigation("IsUser"); + b.Navigation("SeenInChannel"); }); @@ -254,6 +276,11 @@ namespace vassago.Migrations { b.Navigation("Attachments"); }); + + modelBuilder.Entity("vassago.Models.User", b => + { + b.Navigation("Accounts"); + }); #pragma warning restore 612, 618 } } diff --git a/Models/Account.cs b/Models/Account.cs index 124c65a..7b14c4c 100644 --- a/Models/Account.cs +++ b/Models/Account.cs @@ -12,7 +12,7 @@ public class Account public ulong? ExternalId { get; set; } public string Username { get; set; } private string _displayName = null; - public string DisplayName //TODO: fill + public string DisplayName { get { @@ -28,4 +28,5 @@ public class Account //permissions are per account-in-channel, and always propagate down. and since protocol will be a channel, I'll set the "is adam" permission on myself 1x/protocol. public List PermissionTags{get;set;} public string Protocol { get; set; } + public User IsUser {get; set;} } \ No newline at end of file diff --git a/Models/ChattingContext.cs b/Models/ChattingContext.cs index d088c7d..cfe3532 100644 --- a/Models/ChattingContext.cs +++ b/Models/ChattingContext.cs @@ -10,7 +10,8 @@ public class ChattingContext : DbContext //public DbSet Emoji {get;set;} public DbSet Messages { get; set; } public DbSet PermissionSettings{get;set;} - public DbSet Users { get; set; } + public DbSet Accounts { get; set; } + public DbSet Users { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseNpgsql(Shared.DBConnectionString) diff --git a/Models/PermissionSettings.cs b/Models/PermissionSettings.cs index 3883ca8..831fa67 100644 --- a/Models/PermissionSettings.cs +++ b/Models/PermissionSettings.cs @@ -7,7 +7,7 @@ public class PermissionSettings { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } - public uint? MaxAttachmentBytes { get; set; } + public ulong? MaxAttachmentBytes { get; set; } public uint? MaxTextChars { get; set; } public bool? LinksAllowed { get; set; } public bool? ReactionsPossible { get; set; }