migration for accounts vs user distinction

This commit is contained in:
Adam R Grey 2023-06-28 00:14:32 -04:00
parent 115035eb91
commit 91bcfae1ba
8 changed files with 742 additions and 173 deletions

View File

@ -29,6 +29,9 @@ public class Detiktokify : Behavior
if(message.Channel.EffectivePermissions.MaxAttachmentBytes == 0) if(message.Channel.EffectivePermissions.MaxAttachmentBytes == 0)
return false; return false;
if(Behaver.Instance.Selves.Any(acc => acc.Id == message.Author.Id))
return false;
var wordLikes = message.Content.Split(' ', StringSplitOptions.TrimEntries); var wordLikes = message.Content.Split(' ', StringSplitOptions.TrimEntries);
var possibleLinks = wordLikes?.Where(wl => Uri.IsWellFormedUriString(wl, UriKind.Absolute)).Select(wl => new Uri(wl)); var possibleLinks = wordLikes?.Where(wl => Uri.IsWellFormedUriString(wl, UriKind.Absolute)).Select(wl => new Uri(wl));
if (possibleLinks != null && possibleLinks.Count() > 0) if (possibleLinks != null && possibleLinks.Count() > 0)
@ -51,7 +54,7 @@ public class Detiktokify : Behavior
{ {
Console.WriteLine("detiktokifying"); Console.WriteLine("detiktokifying");
#pragma warning disable 4014 #pragma warning disable 4014
await message.React("<:tiktok:1070038619584200884>"); //await message.React("<:tiktok:1070038619584200884>");
#pragma warning restore 4014 #pragma warning restore 4014
var res = await ytdl.RunVideoDownload(link.ToString()); var res = await ytdl.RunVideoDownload(link.ToString());
@ -66,7 +69,7 @@ public class Detiktokify : Behavior
string path = res.Data; string path = res.Data;
if (File.Exists(path)) 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) if (bytesize < message.Channel.EffectivePermissions.MaxAttachmentBytes - 256)
{ {
try try

View File

@ -9,6 +9,9 @@ using Discord.WebSocket;
using vassago.Models; using vassago.Models;
using vassago.Behavior; using vassago.Behavior;
using Discord.Rest; using Discord.Rest;
using Microsoft.EntityFrameworkCore;
using System.Threading;
using System.Reactive.Linq;
namespace vassago.DiscordInterface; namespace vassago.DiscordInterface;
@ -18,15 +21,11 @@ public class DiscordInterface
internal DiscordSocketClient client; internal DiscordSocketClient client;
private bool eventsSignedUp = false; private bool eventsSignedUp = false;
private ChattingContext _db; private ChattingContext _db;
private static PermissionSettings defaultPermissions = new PermissionSettings() private static SemaphoreSlim discordChannelSetup = new SemaphoreSlim(1, 1);
{ private Channel protocolAsChannel;
MeannessFilterLevel = 1, private Queue<ulong> backfillChannels = new Queue<ulong>();
LewdnessFilterLevel = 3, private Queue<ulong> backfillAccounts = new Queue<ulong>();
MaxTextChars = 2000,
MaxAttachmentBytes = 8 * 1024 * 1024,
LinksAllowed = true,
ReactionsPossible = true
};
public DiscordInterface() public DiscordInterface()
{ {
_db = new ChattingContext(); _db = new ChattingContext();
@ -34,6 +33,7 @@ public class DiscordInterface
public async Task Init(string token) public async Task Init(string token)
{ {
await SetupDiscordChannel();
client = new DiscordSocketClient(new DiscordSocketConfig() { GatewayIntents = GatewayIntents.All }); client = new DiscordSocketClient(new DiscordSocketConfig() { GatewayIntents = GatewayIntents.All });
client.Log += (msg) => client.Log += (msg) =>
@ -42,55 +42,91 @@ public class DiscordInterface
return Task.CompletedTask; return Task.CompletedTask;
}; };
client.Connected += SelfConnected; client.Connected += SelfConnected;
client.Ready += ClientReady;
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");
}
});
await client.LoginAsync(TokenType.Bot, token); await client.LoginAsync(TokenType.Bot, token);
await client.StartAsync(); 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<Channel>()
};
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() private async Task SelfConnected()
{ {
var selfUser = UpsertAccount(client.CurrentUser); var selfUser = UpsertAccount(client.CurrentUser);
await _db.SaveChangesAsync(); await _db.SaveChangesAsync();
Behaver.Instance.Selves.Add(selfUser); 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) private async Task MessageReceived(SocketMessage messageParam)
#pragma warning restore 1998
{ {
var suMessage = messageParam as SocketUserMessage; var suMessage = messageParam as SocketUserMessage;
if (suMessage == null) if (suMessage == null)
@ -107,24 +143,21 @@ public class DiscordInterface
var mentionOfMe = "<@" + client.CurrentUser.Id + ">"; var mentionOfMe = "<@" + client.CurrentUser.Id + ">";
m.MentionsMe = true; m.MentionsMe = true;
} }
if (await Behaver.Instance.ActOn(m))
// if ((suMessage.Author.Id != client.CurrentUser.Id))
{ {
if (await Behaver.Instance.ActOn(m)) m.ActedOn = true;
{
m.ActedOn = true;
}
} }
_db.SaveChanges(); _db.SaveChanges();
} }
private void UserJoined(SocketGuildUser arg) private void UserJoined(SocketGuildUser arg)
{ {
var guild = UpsertChannel(arg.Guild); var guild = UpsertChannel(arg.Guild);
var defaultChannel = UpsertChannel(arg.Guild.DefaultChannel); var defaultChannel = UpsertChannel(arg.Guild.DefaultChannel);
defaultChannel.ParentChannel = guild; defaultChannel.ParentChannel = guild;
var u = UpsertAccount(arg); var u = UpsertAccount(arg);
u.SeenInChannel = guild;
u.DisplayName = arg.DisplayName;
} }
private async Task ButtonHandler(SocketMessageComponent component) private async Task ButtonHandler(SocketMessageComponent component)
{ {
@ -164,12 +197,11 @@ public class DiscordInterface
internal vassago.Models.Attachment UpsertAttachment(IAttachment dAttachment) internal vassago.Models.Attachment UpsertAttachment(IAttachment dAttachment)
{ {
var addPlease = false;
var a = _db.Attachments.FirstOrDefault(ai => ai.ExternalId == dAttachment.Id); var a = _db.Attachments.FirstOrDefault(ai => ai.ExternalId == dAttachment.Id);
if (a == null) if (a == null)
{ {
addPlease = true;
a = new vassago.Models.Attachment(); a = new vassago.Models.Attachment();
_db.Attachments.Add(a);
} }
a.ContentType = dAttachment.ContentType; a.ContentType = dAttachment.ContentType;
a.Description = dAttachment.Description; a.Description = dAttachment.Description;
@ -177,20 +209,15 @@ public class DiscordInterface
a.Size = dAttachment.Size; a.Size = dAttachment.Size;
a.Source = new Uri(dAttachment.Url); a.Source = new Uri(dAttachment.Url);
if (addPlease)
{
_db.Attachments.Add(a);
}
return a; return a;
} }
internal Message UpsertMessage(IUserMessage dMessage) internal Message UpsertMessage(IUserMessage dMessage)
{ {
var addPlease = false;
var m = _db.Messages.FirstOrDefault(mi => mi.ExternalId == dMessage.Id); var m = _db.Messages.FirstOrDefault(mi => mi.ExternalId == dMessage.Id);
if (m == null) if (m == null)
{ {
addPlease = true;
m = new Message(); m = new Message();
_db.Messages.Add(m);
} }
m.Attachments = m.Attachments ?? new List<vassago.Models.Attachment>(); m.Attachments = m.Attachments ?? new List<vassago.Models.Attachment>();
if (dMessage.Attachments?.Any() == true) if (dMessage.Attachments?.Any() == true)
@ -208,19 +235,89 @@ public class DiscordInterface
m.Timestamp = dMessage.EditedTimestamp ?? dMessage.CreatedAt; 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; m.MentionsMe = true;
} }
if (addPlease)
{
_db.Messages.Add(m);
}
m.Reply = (t) => { return dMessage.ReplyAsync(t); }; m.Reply = (t) => { return dMessage.ReplyAsync(t); };
m.React = (e) => { return attemptReact(dMessage, e); }; m.React = (e) => { return attemptReact(dMessage, e); };
return m; 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<Message>();
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<Channel>();
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<Message>();
c.Protocol = protocolAsChannel.Protocol;
c.ParentChannel = protocolAsChannel;
c.SubChannels = c.SubChannels ?? new List<Channel>();
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) private Task attemptReact(IUserMessage msg, string e)
{ {
@ -243,110 +340,68 @@ public class DiscordInterface
return msg.AddReactionAsync(emote); return msg.AddReactionAsync(emote);
} }
internal Channel UpsertChannel(IMessageChannel channel) internal async void BackfillLoop()
{ {
var addPlease = false; while (true)
Channel c = _db.Channels.FirstOrDefault(ci => ci.ExternalId == channel.Id);
if (c == null)
{ {
addPlease = true; Thread.Sleep(TimeSpan.FromMinutes(2));
c = new Channel(); 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; for(int i = 0; i < 10 && backfillAccounts.Any(); i++)
c.ExternalId = channel.Id; {
c.IsDM = channel is IPrivateChannel; var aci = backfillAccounts.Dequeue();
c.Messages = c.Messages ?? new List<Message>();
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<Channel>();
if (addPlease)
{
_db.Channels.Add(c);
}
c.SendMessage = (t) => { return channel.SendMessageAsync(t); }; var acc = UpsertAccount(await client.GetUserAsync(aci));
c.SendFile = (f, t) => { return channel.SendFileAsync(f, t); }; if (acc.IsUser == null)
return c; {
} var internalUser = _db.Users.FirstOrDefault(u =>
internal Channel UpsertChannel(IGuild channel) u.Accounts.Any(ua => ua.ExternalId == acc.ExternalId && ua.Protocol == acc.Protocol));
{ if (internalUser == null)
var addPlease = false; {
Channel c = _db.Channels.FirstOrDefault(ci => ci.ExternalId == channel.Id); internalUser = new User()
if (c == null) {
{ Accounts = new List<Account>() { acc }
addPlease = true; };
c = new Channel(); _db.Users.Add(internalUser);
} }
acc.IsUser = internalUser;
c.DisplayName = channel.Name; }
c.ExternalId = channel.Id; }
c.IsDM = false; _db.SaveChanges();
c.Messages = c.Messages ?? new List<Message>();
c.Protocol = PROTOCOL;
c.ParentChannel = null;
c.SubChannels = c.SubChannels ?? new List<Channel>();
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<User>();
//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;
} }
} }
} }

View File

@ -0,0 +1,290 @@
// <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 vassago.Models;
#nullable disable
namespace vassago.Migrations
{
[DbContext(typeof(ChattingContext))]
[Migration("20230628035812_NotionOfUserAccount")]
partial class NotionOfUserAccount
{
/// <inheritdoc />
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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("DisplayName")
.HasColumnType("text");
b.Property<decimal?>("ExternalId")
.HasColumnType("numeric(20,0)");
b.Property<bool>("IsBot")
.HasColumnType("boolean");
b.Property<Guid?>("IsUserId")
.HasColumnType("uuid");
b.Property<int[]>("PermissionTags")
.HasColumnType("integer[]");
b.Property<string>("Protocol")
.HasColumnType("text");
b.Property<Guid?>("SeenInChannelId")
.HasColumnType("uuid");
b.Property<string>("Username")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("IsUserId");
b.HasIndex("SeenInChannelId");
b.ToTable("Accounts");
});
modelBuilder.Entity("vassago.Models.Attachment", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte[]>("Content")
.HasColumnType("bytea");
b.Property<string>("ContentType")
.HasColumnType("text");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<decimal?>("ExternalId")
.HasColumnType("numeric(20,0)");
b.Property<string>("Filename")
.HasColumnType("text");
b.Property<Guid?>("MessageId")
.HasColumnType("uuid");
b.Property<int>("Size")
.HasColumnType("integer");
b.Property<string>("Source")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("MessageId");
b.ToTable("Attachments");
});
modelBuilder.Entity("vassago.Models.Channel", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("DisplayName")
.HasColumnType("text");
b.Property<decimal?>("ExternalId")
.HasColumnType("numeric(20,0)");
b.Property<bool>("IsDM")
.HasColumnType("boolean");
b.Property<Guid?>("ParentChannelId")
.HasColumnType("uuid");
b.Property<int?>("PermissionsId")
.HasColumnType("integer");
b.Property<string>("Protocol")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("ParentChannelId");
b.HasIndex("PermissionsId");
b.ToTable("Channels");
});
modelBuilder.Entity("vassago.Models.Message", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("ActedOn")
.HasColumnType("boolean");
b.Property<Guid?>("AuthorId")
.HasColumnType("uuid");
b.Property<Guid?>("ChannelId")
.HasColumnType("uuid");
b.Property<string>("Content")
.HasColumnType("text");
b.Property<decimal?>("ExternalId")
.HasColumnType("numeric(20,0)");
b.Property<bool>("MentionsMe")
.HasColumnType("boolean");
b.Property<DateTimeOffset>("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<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int?>("LewdnessFilterLevel")
.HasColumnType("integer");
b.Property<bool?>("LinksAllowed")
.HasColumnType("boolean");
b.Property<decimal?>("MaxAttachmentBytes")
.HasColumnType("numeric(20,0)");
b.Property<long?>("MaxTextChars")
.HasColumnType("bigint");
b.Property<int?>("MeannessFilterLevel")
.HasColumnType("integer");
b.Property<bool?>("ReactionsPossible")
.HasColumnType("boolean");
b.HasKey("Id");
b.ToTable("PermissionSettings");
});
modelBuilder.Entity("vassago.Models.User", b =>
{
b.Property<Guid>("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
}
}
}

View File

@ -0,0 +1,192 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace vassago.Migrations
{
/// <inheritdoc />
public partial class NotionOfUserAccount : Migration
{
/// <inheritdoc />
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<decimal>(
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<Guid>(type: "uuid", nullable: false),
ExternalId = table.Column<decimal>(type: "numeric(20,0)", nullable: true),
Username = table.Column<string>(type: "text", nullable: true),
DisplayName = table.Column<string>(type: "text", nullable: true),
IsBot = table.Column<bool>(type: "boolean", nullable: false),
SeenInChannelId = table.Column<Guid>(type: "uuid", nullable: true),
PermissionTags = table.Column<int[]>(type: "integer[]", nullable: true),
Protocol = table.Column<string>(type: "text", nullable: true),
IsUserId = table.Column<Guid>(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");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Messages_Accounts_AuthorId",
table: "Messages");
migrationBuilder.DropTable(
name: "Accounts");
migrationBuilder.AddColumn<string>(
name: "DisplayName",
table: "Users",
type: "text",
nullable: true);
migrationBuilder.AddColumn<decimal>(
name: "ExternalId",
table: "Users",
type: "numeric(20,0)",
nullable: true);
migrationBuilder.AddColumn<bool>(
name: "IsBot",
table: "Users",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<int[]>(
name: "PermissionTags",
table: "Users",
type: "integer[]",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Protocol",
table: "Users",
type: "text",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "SeenInChannelId",
table: "Users",
type: "uuid",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Username",
table: "Users",
type: "text",
nullable: true);
migrationBuilder.AlterColumn<long>(
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");
}
}
}

View File

@ -37,6 +37,9 @@ namespace vassago.Migrations
b.Property<bool>("IsBot") b.Property<bool>("IsBot")
.HasColumnType("boolean"); .HasColumnType("boolean");
b.Property<Guid?>("IsUserId")
.HasColumnType("uuid");
b.Property<int[]>("PermissionTags") b.Property<int[]>("PermissionTags")
.HasColumnType("integer[]"); .HasColumnType("integer[]");
@ -51,9 +54,11 @@ namespace vassago.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("IsUserId");
b.HasIndex("SeenInChannelId"); b.HasIndex("SeenInChannelId");
b.ToTable("Users"); b.ToTable("Accounts");
}); });
modelBuilder.Entity("vassago.Models.Attachment", b => modelBuilder.Entity("vassago.Models.Attachment", b =>
@ -176,8 +181,8 @@ namespace vassago.Migrations
b.Property<bool?>("LinksAllowed") b.Property<bool?>("LinksAllowed")
.HasColumnType("boolean"); .HasColumnType("boolean");
b.Property<long?>("MaxAttachmentBytes") b.Property<decimal?>("MaxAttachmentBytes")
.HasColumnType("bigint"); .HasColumnType("numeric(20,0)");
b.Property<long?>("MaxTextChars") b.Property<long?>("MaxTextChars")
.HasColumnType("bigint"); .HasColumnType("bigint");
@ -193,12 +198,29 @@ namespace vassago.Migrations
b.ToTable("PermissionSettings"); b.ToTable("PermissionSettings");
}); });
modelBuilder.Entity("vassago.Models.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.HasKey("Id");
b.ToTable("Users");
});
modelBuilder.Entity("vassago.Models.Account", b => modelBuilder.Entity("vassago.Models.Account", b =>
{ {
b.HasOne("vassago.Models.User", "IsUser")
.WithMany("Accounts")
.HasForeignKey("IsUserId");
b.HasOne("vassago.Models.Channel", "SeenInChannel") b.HasOne("vassago.Models.Channel", "SeenInChannel")
.WithMany("Users") .WithMany("Users")
.HasForeignKey("SeenInChannelId"); .HasForeignKey("SeenInChannelId");
b.Navigation("IsUser");
b.Navigation("SeenInChannel"); b.Navigation("SeenInChannel");
}); });
@ -254,6 +276,11 @@ namespace vassago.Migrations
{ {
b.Navigation("Attachments"); b.Navigation("Attachments");
}); });
modelBuilder.Entity("vassago.Models.User", b =>
{
b.Navigation("Accounts");
});
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }
} }

View File

@ -12,7 +12,7 @@ public class Account
public ulong? ExternalId { get; set; } public ulong? ExternalId { get; set; }
public string Username { get; set; } public string Username { get; set; }
private string _displayName = null; private string _displayName = null;
public string DisplayName //TODO: fill public string DisplayName
{ {
get 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. //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<Enumerations.WellknownPermissions> PermissionTags{get;set;} public List<Enumerations.WellknownPermissions> PermissionTags{get;set;}
public string Protocol { get; set; } public string Protocol { get; set; }
public User IsUser {get; set;}
} }

View File

@ -10,7 +10,8 @@ public class ChattingContext : DbContext
//public DbSet<Emoji> Emoji {get;set;} //public DbSet<Emoji> Emoji {get;set;}
public DbSet<Message> Messages { get; set; } public DbSet<Message> Messages { get; set; }
public DbSet<PermissionSettings> PermissionSettings{get;set;} public DbSet<PermissionSettings> PermissionSettings{get;set;}
public DbSet<Account> Users { get; set; } public DbSet<Account> Accounts { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseNpgsql(Shared.DBConnectionString) => optionsBuilder.UseNpgsql(Shared.DBConnectionString)

View File

@ -7,7 +7,7 @@ public class PermissionSettings
{ {
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; } public int Id { get; set; }
public uint? MaxAttachmentBytes { get; set; } public ulong? MaxAttachmentBytes { get; set; }
public uint? MaxTextChars { get; set; } public uint? MaxTextChars { get; set; }
public bool? LinksAllowed { get; set; } public bool? LinksAllowed { get; set; }
public bool? ReactionsPossible { get; set; } public bool? ReactionsPossible { get; set; }