Compare commits

..

No commits in common. "unified-configuration" and "master" have entirely different histories.

25 changed files with 194 additions and 1220 deletions

View File

@ -17,7 +17,6 @@ public class Behaver
private List<Account> SelfAccounts { get; set; } = new List<Account>(); private List<Account> SelfAccounts { get; set; } = new List<Account>();
private User SelfUser { get; set; } private User SelfUser { get; set; }
public static List<vassago.Behavior.Behavior> Behaviors { get; private set; } = new List<vassago.Behavior.Behavior>(); public static List<vassago.Behavior.Behavior> Behaviors { get; private set; } = new List<vassago.Behavior.Behavior>();
private static Rememberer r = Rememberer.Instance;
internal Behaver() internal Behaver()
{ {
var subtypes = AppDomain.CurrentDomain.GetAssemblies() var subtypes = AppDomain.CurrentDomain.GetAssemblies()
@ -45,7 +44,7 @@ public class Behaver
public async Task<bool> ActOn(Message message) public async Task<bool> ActOn(Message message)
{ {
//TODO: this is yet another hit to the database, and a big one. cache them in memory! there needs to be a feasibly-viewable amount, anyway. //TODO: this is yet another hit to the database, and a big one. cache them in memory! there needs to be a feasibly-viewable amount, anyway.
var matchingUACs = r.MatchUACs(message); var matchingUACs = Rememberer.MatchUACs(message);
message.TranslatedContent = message.Content; message.TranslatedContent = message.Content;
foreach (var uacMatch in matchingUACs) foreach (var uacMatch in matchingUACs)
{ {
@ -80,7 +79,7 @@ public class Behaver
message.ActedOn = true; message.ActedOn = true;
behaviorsActedOn.Add("generic question fallback"); behaviorsActedOn.Add("generic question fallback");
} }
r.RememberMessage(message); Rememberer.RememberMessage(message);
ForwardToKafka(message, behaviorsActedOn, matchingUACs); ForwardToKafka(message, behaviorsActedOn, matchingUACs);
return message.ActedOn; return message.ActedOn;
} }
@ -118,7 +117,7 @@ public class Behaver
internal bool IsSelf(Guid AccountId) internal bool IsSelf(Guid AccountId)
{ {
var acc = r.SearchAccount(a => a.Id == AccountId); var acc = Rememberer.SearchAccount(a => a.Id == AccountId);
return SelfAccounts.Any(acc => acc.Id == AccountId); return SelfAccounts.Any(acc => acc.Id == AccountId);
} }
@ -133,8 +132,8 @@ public class Behaver
{ {
CollapseUsers(SelfUser, selfAccount.IsUser); CollapseUsers(SelfUser, selfAccount.IsUser);
} }
SelfAccounts = r.SearchAccounts(a => a.IsUser == SelfUser); SelfAccounts = Rememberer.SearchAccounts(a => a.IsUser == SelfUser);
r.RememberAccount(selfAccount); Rememberer.RememberAccount(selfAccount);
} }
public bool CollapseUsers(User primary, User secondary) public bool CollapseUsers(User primary, User secondary)
@ -148,18 +147,18 @@ public class Behaver
a.IsUser = primary; a.IsUser = primary;
} }
secondary.Accounts.Clear(); secondary.Accounts.Clear();
var uacs = r.SearchUACs(u => u.Users.FirstOrDefault(u => u.Id == secondary.Id) != null); var uacs = Rememberer.SearchUACs(u => u.Users.FirstOrDefault(u => u.Id == secondary.Id) != null);
if (uacs.Count() > 0) if (uacs.Count() > 0)
{ {
foreach (var uac in uacs) foreach (var uac in uacs)
{ {
uac.Users.RemoveAll(u => u.Id == secondary.Id); uac.Users.RemoveAll(u => u.Id == secondary.Id);
uac.Users.Add(primary); uac.Users.Add(primary);
r.RememberUAC(uac); Rememberer.RememberUAC(uac);
} }
} }
r.ForgetUser(secondary); Rememberer.ForgetUser(secondary);
r.RememberUser(primary); Rememberer.RememberUser(primary);
return true; return true;
} }
private ProtocolInterface fetchInterface(Channel ch) private ProtocolInterface fetchInterface(Channel ch)
@ -178,7 +177,7 @@ public class Behaver
} }
public async Task<int> SendMessage(Guid channelId, string text) public async Task<int> SendMessage(Guid channelId, string text)
{ {
var channel = r.ChannelDetail(channelId); var channel = Rememberer.ChannelDetail(channelId);
if (channel == null) if (channel == null)
return 404; return 404;
var iprotocol = fetchInterface(channel); var iprotocol = fetchInterface(channel);
@ -190,7 +189,7 @@ public class Behaver
public async Task<int> React(Guid messageId, string reaction) public async Task<int> React(Guid messageId, string reaction)
{ {
Console.WriteLine($"sanity check: behaver is reacting, {messageId}, {reaction}"); Console.WriteLine($"sanity check: behaver is reacting, {messageId}, {reaction}");
var message = r.MessageDetail(messageId); var message = Rememberer.MessageDetail(messageId);
if (message == null) if (message == null)
{ {
Console.Error.WriteLine($"message {messageId} not found"); Console.Error.WriteLine($"message {messageId} not found");
@ -213,7 +212,7 @@ public class Behaver
} }
public async Task<int> Reply(Guid messageId, string text) public async Task<int> Reply(Guid messageId, string text)
{ {
var message = r.MessageDetail(messageId); var message = Rememberer.MessageDetail(messageId);
if (message == null) if (message == null)
{ {
Console.WriteLine($"message {messageId} not found"); Console.WriteLine($"message {messageId} not found");
@ -229,7 +228,7 @@ public class Behaver
} }
public async Task<int> SendFile(Guid channelId, string path, string accompanyingText) public async Task<int> SendFile(Guid channelId, string path, string accompanyingText)
{ {
var channel = r.ChannelDetail(channelId); var channel = Rememberer.ChannelDetail(channelId);
if (channel == null) if (channel == null)
return 404; return 404;
var iprotocol = fetchInterface(channel); var iprotocol = fetchInterface(channel);
@ -240,7 +239,7 @@ public class Behaver
} }
public async Task<int> SendFile(Guid channelId, string base64dData, string filename, string accompanyingText) public async Task<int> SendFile(Guid channelId, string base64dData, string filename, string accompanyingText)
{ {
var channel = r.ChannelDetail(channelId); var channel = Rememberer.ChannelDetail(channelId);
if (channel == null) if (channel == null)
return 404; return 404;
var iprotocol = fetchInterface(channel); var iprotocol = fetchInterface(channel);

View File

@ -12,7 +12,6 @@ public abstract class Behavior
{ {
//recommendation: set up your UACs in your constructor. //recommendation: set up your UACs in your constructor.
public abstract Task<bool> ActOn(Message message); public abstract Task<bool> ActOn(Message message);
protected static Rememberer rememberer = Rememberer.Instance;
public virtual bool ShouldAct(Message message, List<UAC> matchedUACs) public virtual bool ShouldAct(Message message, List<UAC> matchedUACs)
{ {

View File

@ -16,7 +16,7 @@ public class Ripcord: Behavior
public Ripcord() public Ripcord()
{ {
myUAC = rememberer.SearchUAC(uac => uac.OwnerId == uacID); myUAC = Rememberer.SearchUAC(uac => uac.OwnerId == uacID);
if (myUAC == null) if (myUAC == null)
{ {
myUAC = new() myUAC = new()
@ -26,7 +26,7 @@ public class Ripcord: Behavior
Description = @"matching this means you can tell the bot to shutdown, now" Description = @"matching this means you can tell the bot to shutdown, now"
}; };
} }
rememberer.RememberUAC(myUAC); Rememberer.RememberUAC(myUAC);
} }
public override bool ShouldAct(Message message, List<UAC> matchedUACs) public override bool ShouldAct(Message message, List<UAC> matchedUACs)
{ {

View File

@ -16,7 +16,7 @@ public class TwitchSummon : Behavior
public TwitchSummon() public TwitchSummon()
{ {
myUAC = rememberer.SearchUAC(uac => uac.OwnerId == uacID); myUAC = Rememberer.SearchUAC(uac => uac.OwnerId == uacID);
if (myUAC == null) if (myUAC == null)
{ {
myUAC = new() myUAC = new()
@ -26,7 +26,7 @@ public class TwitchSummon : Behavior
Description = @"matching this means you can summon the bot <i>to</i> <b>any</b> twitch channel" Description = @"matching this means you can summon the bot <i>to</i> <b>any</b> twitch channel"
}; };
} }
rememberer.RememberUAC(myUAC); Rememberer.RememberUAC(myUAC);
} }
internal static TwitchInterface.TwitchInterface getAnyTwitchInterface() internal static TwitchInterface.TwitchInterface getAnyTwitchInterface()
{ {

View File

@ -10,7 +10,6 @@ using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using vassago.Models; using vassago.Models;
using Newtonsoft.Json;
[StaticPlz] [StaticPlz]
public class Webhook : Behavior public class Webhook : Behavior
@ -25,15 +24,20 @@ public class Webhook : Behavior
private ConcurrentDictionary<Guid, WebhookActionOrder> authedCache = new ConcurrentDictionary<Guid, WebhookActionOrder>(); private ConcurrentDictionary<Guid, WebhookActionOrder> authedCache = new ConcurrentDictionary<Guid, WebhookActionOrder>();
private HttpClient hc = new HttpClient(); private HttpClient hc = new HttpClient();
public static void SetupWebhooks(IEnumerable<string> confSection) public static void SetupWebhooks(IConfigurationSection confSection)
{ {
//configuredWebhooks = confSection.Get<List<vassago.Behavior.WebhookConf>>(); configuredWebhooks = confSection.Get<List<vassago.Behavior.WebhookConf>>();
if(confSection != null) foreach (var confLine in confSection)
foreach (var conf in configuredWebhooks)
{ {
var conf = JsonConvert.DeserializeObject<WebhookConf>(confLine);
var confName = $"Webhook: {conf.Trigger}"; var confName = $"Webhook: {conf.Trigger}";
Console.WriteLine($"confName: {confName}; conf.uri: {conf.Uri}, conf.uacID: {conf.uacID}, conf.Method: {conf.Method}, conf.Headers: {conf.Headers?.Count() ?? 0}, conf.Content: {conf.Content}");
foreach (var kvp in conf.Headers)
{
Console.WriteLine($"{kvp[0]}: {kvp[1]}");
}
var changed = false; var changed = false;
var myUAC = rememberer.SearchUAC(uac => uac.OwnerId == conf.uacID); var myUAC = Rememberer.SearchUAC(uac => uac.OwnerId == conf.uacID);
if (myUAC == null) if (myUAC == null)
{ {
myUAC = new() myUAC = new()
@ -43,7 +47,7 @@ public class Webhook : Behavior
Description = conf.Description Description = conf.Description
}; };
changed = true; changed = true;
rememberer.RememberUAC(myUAC); Rememberer.RememberUAC(myUAC);
} }
else else
{ {
@ -59,7 +63,7 @@ public class Webhook : Behavior
} }
} }
if (changed) if (changed)
rememberer.RememberUAC(myUAC); Rememberer.RememberUAC(myUAC);
} }
} }
@ -84,7 +88,7 @@ public class Webhook : Behavior
{ {
var webhookableMessageContent = message.Content.Substring(message.Content.IndexOf(triggerTarget) + triggerTarget.Length + 1); var webhookableMessageContent = message.Content.Substring(message.Content.IndexOf(triggerTarget) + triggerTarget.Length + 1);
Console.WriteLine($"webhookable content: {webhookableMessageContent}"); Console.WriteLine($"webhookable content: {webhookableMessageContent}");
var uacConf = rememberer.SearchUAC(uac => uac.OwnerId == wh.uacID); var uacConf = Rememberer.SearchUAC(uac => uac.OwnerId == wh.uacID);
if (uacConf.Users.Contains(message.Author.IsUser) || uacConf.Channels.Contains(message.Channel) || uacConf.AccountInChannels.Contains(message.Author)) if (uacConf.Users.Contains(message.Author.IsUser) || uacConf.Channels.Contains(message.Channel) || uacConf.AccountInChannels.Contains(message.Author))
{ {
Console.WriteLine("webhook UAC passed, preparing WebhookActionOrder"); Console.WriteLine("webhook UAC passed, preparing WebhookActionOrder");
@ -186,7 +190,7 @@ public class WebhookConf
public Uri Uri { get; set; } public Uri Uri { get; set; }
//public HttpMethod Method { get; set; } //public HttpMethod Method { get; set; }
public Enumerations.HttpVerb Method { get; set; } public Enumerations.HttpVerb Method { get; set; }
public List<string> Headers { get; set; } public List<List<string>> Headers { get; set; }
public string Content { get; set; } public string Content { get; set; }
public string Description { get; set; } public string Description { get; set; }
} }

View File

@ -7,17 +7,24 @@ namespace vassago
using vassago.TwitchInterface; using vassago.TwitchInterface;
using vassago.ProtocolInterfaces.DiscordInterface; using vassago.ProtocolInterfaces.DiscordInterface;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Newtonsoft.Json;
internal class ConsoleService : BackgroundService internal class ConsoleService : BackgroundService
{ {
public ConsoleService(IConfiguration aspConfig) public ConsoleService(IConfiguration aspConfig)
{ {
Shared.DBConnectionString = aspConfig["DBConnectionString"]; Shared.DBConnectionString = aspConfig["DBConnectionString"];
Shared.SetupSlashCommands = aspConfig["SetupSlashCommands"]?.ToLower() == "true";
Shared.API_URL = new Uri(aspConfig["API_URL"]);
DiscordTokens = aspConfig.GetSection("DiscordTokens").Get<IEnumerable<string>>();
TwitchConfigs = aspConfig.GetSection("TwitchConfigs").Get<IEnumerable<TwitchConfig>>();
Conversion.Converter.Load(aspConfig["ExchangePairsLocation"]);
Telefranz.Configure(aspConfig["KafkaName"], aspConfig["KafkaBootstrap"]);
Console.WriteLine($"Telefranz.Configure({aspConfig["KafkaName"]}, {aspConfig["KafkaBootstrap"]});");
vassago.Behavior.Webhook.SetupWebhooks(aspConfig.GetSection("Webhooks"));
} }
List<string> DiscordTokens; IEnumerable<string> DiscordTokens { get; }
List<TwitchConfig> TwitchConfigs; IEnumerable<TwitchConfig> TwitchConfigs { get; }
protected override async Task ExecuteAsync(CancellationToken cancellationToken) protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{ {
@ -25,31 +32,14 @@ namespace vassago
var dbc = new ChattingContext(); var dbc = new ChattingContext();
await dbc.Database.MigrateAsync(cancellationToken); await dbc.Database.MigrateAsync(cancellationToken);
var confEntity = dbc.Configurations.FirstOrDefault() ?? new Configuration();
if (dbc.Configurations.Count() == 0)
{
dbc.Configurations.Add(confEntity);
dbc.SaveChanges();
}
dbConfig(ref confEntity);
if (DiscordTokens?.Any() ?? false) if (DiscordTokens?.Any() ?? false)
foreach (var dt in DiscordTokens) foreach (var dt in DiscordTokens)
{ {
var d = new DiscordInterface(); var d = new DiscordInterface();
initTasks.Add(Task.Run(() => initTasks.Add(d.Init(dt));
{ Shared.ProtocolList.Add(d);
try
{
d.Init(dt);
Shared.ProtocolList.Add(d);
}
catch (Exception e){
Console.Error.WriteLine($"couldn't initialize discord interface with token {dt}");
Console.Error.WriteLine(e);
}
}));
} }
if (TwitchConfigs?.Any() ?? false) if (TwitchConfigs?.Any() ?? false)
foreach (var tc in TwitchConfigs) foreach (var tc in TwitchConfigs)
{ {
@ -57,23 +47,9 @@ namespace vassago
initTasks.Add(t.Init(tc)); initTasks.Add(t.Init(tc));
Shared.ProtocolList.Add(t); Shared.ProtocolList.Add(t);
} }
Task.WaitAll(initTasks.ToArray(), cancellationToken); Task.WaitAll(initTasks.ToArray(), cancellationToken);
Console.WriteLine("init tasks are done");
}
private void dbConfig(ref vassago.Models.Configuration confEntity)
{
Shared.SetupSlashCommands = confEntity.SetupDiscordSlashCommands;
Shared.API_URL = new Uri(confEntity.reportedApiUrl);
DiscordTokens = confEntity.DiscordTokens;
TwitchConfigs = new List<TwitchConfig>();
if (confEntity.TwitchConfigs != null) foreach (var twitchConfString in confEntity.TwitchConfigs)
{
TwitchConfigs.Add(JsonConvert.DeserializeObject<TwitchConfig>(twitchConfString));
}
Conversion.Converter.Load(confEntity.ExchangePairsLocation);
Telefranz.Configure(confEntity.KafkaName, confEntity.KafkaBootstrap);
vassago.Behavior.Webhook.SetupWebhooks(confEntity.Webhooks);
} }
} }
} }

View File

@ -1,427 +0,0 @@
// <auto-generated />
using System;
using System.Collections.Generic;
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("20250628034005_ConfigInDatabase")]
partial class ConfigInDatabase
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore");
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("AccountUAC", b =>
{
b.Property<Guid>("AccountInChannelsId")
.HasColumnType("uuid");
b.Property<Guid>("UACsId")
.HasColumnType("uuid");
b.HasKey("AccountInChannelsId", "UACsId");
b.HasIndex("UACsId");
b.ToTable("AccountUAC");
});
modelBuilder.Entity("ChannelUAC", b =>
{
b.Property<Guid>("ChannelsId")
.HasColumnType("uuid");
b.Property<Guid>("UACsId")
.HasColumnType("uuid");
b.HasKey("ChannelsId", "UACsId");
b.HasIndex("UACsId");
b.ToTable("ChannelUAC");
});
modelBuilder.Entity("UACUser", b =>
{
b.Property<Guid>("UACsId")
.HasColumnType("uuid");
b.Property<Guid>("UsersId")
.HasColumnType("uuid");
b.HasKey("UACsId", "UsersId");
b.HasIndex("UsersId");
b.ToTable("UACUser");
});
modelBuilder.Entity("vassago.Models.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("DisplayName")
.HasColumnType("text");
b.Property<string>("ExternalId")
.HasColumnType("text");
b.Property<bool>("IsBot")
.HasColumnType("boolean");
b.Property<Guid?>("IsUserId")
.HasColumnType("uuid");
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<int>("ChannelType")
.HasColumnType("integer");
b.Property<string>("DisplayName")
.HasColumnType("text");
b.Property<string>("ExternalId")
.HasColumnType("text");
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<Guid?>("ParentChannelId")
.HasColumnType("uuid");
b.Property<string>("Protocol")
.HasColumnType("text");
b.Property<bool?>("ReactionsPossible")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("ParentChannelId");
b.ToTable("Channels");
});
modelBuilder.Entity("vassago.Models.Configuration", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<List<string>>("DiscordTokens")
.HasColumnType("text[]");
b.Property<string>("ExchangePairsLocation")
.HasColumnType("text");
b.Property<string>("KafkaBootstrap")
.HasColumnType("text");
b.Property<string>("KafkaName")
.HasColumnType("text");
b.Property<bool>("SetupDiscordSlashCommands")
.HasColumnType("boolean");
b.Property<List<string>>("TwitchConfigs")
.HasColumnType("text[]");
b.Property<List<string>>("Webhooks")
.HasColumnType("text[]");
b.Property<string>("reportedApiUrl")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Configurations");
});
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<string>("ExternalId")
.HasColumnType("text");
b.Property<bool>("MentionsMe")
.HasColumnType("boolean");
b.Property<string>("Protocol")
.HasColumnType("text");
b.Property<DateTimeOffset>("Timestamp")
.HasColumnType("timestamp with time zone");
b.Property<string>("TranslatedContent")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("AuthorId");
b.HasIndex("ChannelId");
b.ToTable("Messages");
});
modelBuilder.Entity("vassago.Models.UAC", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Dictionary<string, string>>("CommandAlterations")
.HasColumnType("hstore");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<string>("DisplayName")
.HasColumnType("text");
b.Property<Guid>("OwnerId")
.HasColumnType("uuid");
b.Property<Dictionary<string, string>>("Translations")
.HasColumnType("hstore");
b.HasKey("Id");
b.ToTable("UACs");
});
modelBuilder.Entity("vassago.Models.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.HasKey("Id");
b.ToTable("Users");
});
modelBuilder.Entity("AccountUAC", b =>
{
b.HasOne("vassago.Models.Account", null)
.WithMany()
.HasForeignKey("AccountInChannelsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("vassago.Models.UAC", null)
.WithMany()
.HasForeignKey("UACsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ChannelUAC", b =>
{
b.HasOne("vassago.Models.Channel", null)
.WithMany()
.HasForeignKey("ChannelsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("vassago.Models.UAC", null)
.WithMany()
.HasForeignKey("UACsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("UACUser", b =>
{
b.HasOne("vassago.Models.UAC", null)
.WithMany()
.HasForeignKey("UACsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("vassago.Models.User", null)
.WithMany()
.HasForeignKey("UsersId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("vassago.Models.Account", b =>
{
b.HasOne("vassago.Models.User", "IsUser")
.WithMany("Accounts")
.HasForeignKey("IsUserId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("vassago.Models.Channel", "SeenInChannel")
.WithMany("Users")
.HasForeignKey("SeenInChannelId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("IsUser");
b.Navigation("SeenInChannel");
});
modelBuilder.Entity("vassago.Models.Attachment", b =>
{
b.HasOne("vassago.Models.Message", "Message")
.WithMany("Attachments")
.HasForeignKey("MessageId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Message");
});
modelBuilder.Entity("vassago.Models.Channel", b =>
{
b.HasOne("vassago.Models.Channel", "ParentChannel")
.WithMany("SubChannels")
.HasForeignKey("ParentChannelId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("ParentChannel");
});
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")
.OnDelete(DeleteBehavior.Cascade);
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

@ -1,42 +0,0 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace vassago.Migrations
{
/// <inheritdoc />
public partial class ConfigInDatabase : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Configurations",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
DiscordTokens = table.Column<List<string>>(type: "text[]", nullable: true),
TwitchConfigs = table.Column<List<string>>(type: "text[]", nullable: true),
ExchangePairsLocation = table.Column<string>(type: "text", nullable: true),
SetupDiscordSlashCommands = table.Column<bool>(type: "boolean", nullable: false),
Webhooks = table.Column<List<string>>(type: "text[]", nullable: true),
KafkaBootstrap = table.Column<string>(type: "text", nullable: true),
KafkaName = table.Column<string>(type: "text", nullable: true),
reportedApiUrl = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Configurations", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Configurations");
}
}
}

View File

@ -188,41 +188,6 @@ namespace vassago.Migrations
b.ToTable("Channels"); b.ToTable("Channels");
}); });
modelBuilder.Entity("vassago.Models.Configuration", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<List<string>>("DiscordTokens")
.HasColumnType("text[]");
b.Property<string>("ExchangePairsLocation")
.HasColumnType("text");
b.Property<string>("KafkaBootstrap")
.HasColumnType("text");
b.Property<string>("KafkaName")
.HasColumnType("text");
b.Property<bool>("SetupDiscordSlashCommands")
.HasColumnType("boolean");
b.Property<List<string>>("TwitchConfigs")
.HasColumnType("text[]");
b.Property<List<string>>("Webhooks")
.HasColumnType("text[]");
b.Property<string>("reportedApiUrl")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Configurations");
});
modelBuilder.Entity("vassago.Models.Message", b => modelBuilder.Entity("vassago.Models.Message", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")

View File

@ -11,7 +11,6 @@ public class ChattingContext : DbContext
public DbSet<Message> Messages { get; set; } public DbSet<Message> Messages { get; set; }
public DbSet<Account> Accounts { get; set; } public DbSet<Account> Accounts { get; set; }
public DbSet<User> Users { get; set; } public DbSet<User> Users { get; set; }
public DbSet<Configuration> Configurations {get; set;}
public ChattingContext(DbContextOptions<ChattingContext> options) : base(options) { } public ChattingContext(DbContextOptions<ChattingContext> options) : base(options) { }
public ChattingContext() : base() { } public ChattingContext() : base() { }

View File

@ -1,28 +0,0 @@
namespace vassago.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection;
using System.Threading.Tasks;
using Discord.WebSocket;
using Microsoft.EntityFrameworkCore;
using vassago.TwitchInterface;
using vassago.Behavior;
//TODO: it feels gross to have a *table* in a database that's intended to hold 1 **UND EXACTLY ONE** row, ever.
//but also it feels worse to scatter my configuraiton-y data across external files and the database.
public class Configuration
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public List<string> DiscordTokens { get; set; }
public List<string> TwitchConfigs { get; set; }
public string ExchangePairsLocation { get; set; } = "assets/exchangepairs.json"; //TODO: have this be "exchange API key", so you can have it continually update.
public bool SetupDiscordSlashCommands { get; set; } = false; //i'm kind of idealogically opposed to these.
public List<string> Webhooks { get; set; }
public string KafkaBootstrap { get; set; } = "http://localhost:9092";
public string KafkaName { get; set; } = "vassago";
public string reportedApiUrl { get; set; } = "http://localhost:5093/api";
}

View File

@ -28,13 +28,10 @@ public class DiscordInterface : ProtocolInterface
private static readonly SemaphoreSlim discordChannelSetup = new(1, 1); private static readonly SemaphoreSlim discordChannelSetup = new(1, 1);
private Channel protocolAsChannel; private Channel protocolAsChannel;
public override Channel SelfChannel { get => protocolAsChannel; } public override Channel SelfChannel { get => protocolAsChannel; }
private static Rememberer r = Rememberer.Instance;
public async Task Init(string config) public async Task Init(string config)
{ {
var token = config; var token = config;
Console.WriteLine($"going to validate token {token}");
Discord.TokenUtils.ValidateToken(TokenType.Bot, token);//throws an exception if invalid
await SetupDiscordChannel(); await SetupDiscordChannel();
client = new DiscordSocketClient(new DiscordSocketConfig() { GatewayIntents = GatewayIntents.All }); client = new DiscordSocketClient(new DiscordSocketConfig() { GatewayIntents = GatewayIntents.All });
@ -43,18 +40,12 @@ public class DiscordInterface : ProtocolInterface
Console.WriteLine(msg.ToString()); Console.WriteLine(msg.ToString());
return Task.CompletedTask; return Task.CompletedTask;
}; };
client.Connected += this.SelfConnected; client.Connected += () => Task.Run(SelfConnected);
client.Disconnected += this.ClientDisconnected; client.Ready += () => Task.Run(ClientReady);
client.Ready += this.ClientReady;
await client.LoginAsync(TokenType.Bot, token); await client.LoginAsync(TokenType.Bot, token);
await client.StartAsync(); await client.StartAsync();
} }
private async Task ClientDisconnected(Exception e)
{
Console.WriteLine("client disconnected!");
Console.WriteLine(e?.Message);
}
private async Task SetupDiscordChannel() private async Task SetupDiscordChannel()
{ {
@ -62,7 +53,7 @@ public class DiscordInterface : ProtocolInterface
try try
{ {
protocolAsChannel = r.SearchChannel(c => c.ParentChannel == null && c.Protocol == Protocol); protocolAsChannel = Rememberer.SearchChannel(c => c.ParentChannel == null && c.Protocol == Protocol);
if (protocolAsChannel == null) if (protocolAsChannel == null)
{ {
protocolAsChannel = new Channel() protocolAsChannel = new Channel()
@ -84,7 +75,7 @@ public class DiscordInterface : ProtocolInterface
Console.WriteLine($"discord, channel with id {protocolAsChannel.Id}, already exists"); Console.WriteLine($"discord, channel with id {protocolAsChannel.Id}, already exists");
} }
protocolAsChannel.DisplayName = "discord (itself)"; protocolAsChannel.DisplayName = "discord (itself)";
protocolAsChannel = r.RememberChannel(protocolAsChannel); protocolAsChannel = Rememberer.RememberChannel(protocolAsChannel);
Console.WriteLine($"protocol as channel addeed; {protocolAsChannel}"); Console.WriteLine($"protocol as channel addeed; {protocolAsChannel}");
} }
finally finally
@ -201,7 +192,7 @@ public class DiscordInterface : ProtocolInterface
} }
internal static vassago.Models.Attachment UpsertAttachment(IAttachment dAttachment) internal static vassago.Models.Attachment UpsertAttachment(IAttachment dAttachment)
{ {
var a = r.SearchAttachment(ai => ai.ExternalId == dAttachment.Id) var a = Rememberer.SearchAttachment(ai => ai.ExternalId == dAttachment.Id)
?? new vassago.Models.Attachment(); ?? new vassago.Models.Attachment();
a.ContentType = dAttachment.ContentType; a.ContentType = dAttachment.ContentType;
@ -209,12 +200,12 @@ public class DiscordInterface : ProtocolInterface
a.Filename = dAttachment.Filename; a.Filename = dAttachment.Filename;
a.Size = dAttachment.Size; a.Size = dAttachment.Size;
a.Source = new Uri(dAttachment.Url); a.Source = new Uri(dAttachment.Url);
r.RememberAttachment(a); Rememberer.RememberAttachment(a);
return a; return a;
} }
internal Message UpsertMessage(IUserMessage dMessage) internal Message UpsertMessage(IUserMessage dMessage)
{ {
var m = r.SearchMessage(mi => mi.ExternalId == dMessage.Id.ToString() && mi.Protocol == Protocol) var m = Rememberer.SearchMessage(mi => mi.ExternalId == dMessage.Id.ToString() && mi.Protocol == Protocol)
?? new() ?? new()
{ {
Protocol = Protocol Protocol = Protocol
@ -240,13 +231,13 @@ public class DiscordInterface : ProtocolInterface
m.MentionsMe = (dMessage.Author.Id != client.CurrentUser.Id m.MentionsMe = (dMessage.Author.Id != client.CurrentUser.Id
&& (dMessage.MentionedUserIds?.FirstOrDefault(muid => muid == client.CurrentUser.Id) > 0)); && (dMessage.MentionedUserIds?.FirstOrDefault(muid => muid == client.CurrentUser.Id) > 0));
r.RememberMessage(m); Rememberer.RememberMessage(m);
Console.WriteLine($"received message; author: {m.Author.DisplayName}, {m.Author.Id}. messageid:{m.Id}"); Console.WriteLine($"received message; author: {m.Author.DisplayName}, {m.Author.Id}. messageid:{m.Id}");
return m; return m;
} }
internal Channel UpsertChannel(IMessageChannel channel) internal Channel UpsertChannel(IMessageChannel channel)
{ {
Channel c = r.SearchChannel(ci => ci.ExternalId == channel.Id.ToString() && ci.Protocol == Protocol); Channel c = Rememberer.SearchChannel(ci => ci.ExternalId == channel.Id.ToString() && ci.Protocol == Protocol);
if (c == null) if (c == null)
{ {
Console.WriteLine($"couldn't find channel under protocol {Protocol} with externalId {channel.Id.ToString()}"); Console.WriteLine($"couldn't find channel under protocol {Protocol} with externalId {channel.Id.ToString()}");
@ -299,7 +290,7 @@ public class DiscordInterface : ProtocolInterface
Channel parentChannel = null; Channel parentChannel = null;
if (channel is IGuildChannel) if (channel is IGuildChannel)
{ {
parentChannel = r.SearchChannel(c => c.ExternalId == (channel as IGuildChannel).Guild.Id.ToString() && c.Protocol == Protocol); parentChannel = Rememberer.SearchChannel(c => c.ExternalId == (channel as IGuildChannel).Guild.Id.ToString() && c.Protocol == Protocol);
if (parentChannel is null) if (parentChannel is null)
{ {
Console.Error.WriteLine("why am I still null?"); Console.Error.WriteLine("why am I still null?");
@ -320,7 +311,7 @@ public class DiscordInterface : ProtocolInterface
parentChannel.SubChannels.Add(c); parentChannel.SubChannels.Add(c);
} }
c = r.RememberChannel(c); c = Rememberer.RememberChannel(c);
//Console.WriteLine($"no one knows how to make good tooling. c.users.first, which needs client currentuser id tostring. c: {c}, c.Users {c.Users}, client: {client}, client.CurrentUser: {client.CurrentUser}, client.currentUser.Id: {client.CurrentUser.Id}"); //Console.WriteLine($"no one knows how to make good tooling. c.users.first, which needs client currentuser id tostring. c: {c}, c.Users {c.Users}, client: {client}, client.CurrentUser: {client.CurrentUser}, client.currentUser.Id: {client.CurrentUser.Id}");
var selfAccountInChannel = c.Users?.FirstOrDefault(a => a.ExternalId == client.CurrentUser.Id.ToString()); var selfAccountInChannel = c.Users?.FirstOrDefault(a => a.ExternalId == client.CurrentUser.Id.ToString());
@ -333,7 +324,7 @@ public class DiscordInterface : ProtocolInterface
} }
internal Channel UpsertChannel(IGuild channel) internal Channel UpsertChannel(IGuild channel)
{ {
Channel c = r.SearchChannel(ci => ci.ExternalId == channel.Id.ToString() && ci.Protocol == Protocol); Channel c = Rememberer.SearchChannel(ci => ci.ExternalId == channel.Id.ToString() && ci.Protocol == Protocol);
if (c == null) if (c == null)
{ {
Console.WriteLine($"couldn't find channel under protocol {Protocol} with externalId {channel.Id.ToString()}"); Console.WriteLine($"couldn't find channel under protocol {Protocol} with externalId {channel.Id.ToString()}");
@ -349,11 +340,11 @@ public class DiscordInterface : ProtocolInterface
c.SubChannels ??= []; c.SubChannels ??= [];
c.MaxAttachmentBytes = channel.MaxUploadLimit; c.MaxAttachmentBytes = channel.MaxUploadLimit;
return r.RememberChannel(c); return Rememberer.RememberChannel(c);
} }
internal static Account UpsertAccount(IUser discordUser, Channel inChannel) internal static Account UpsertAccount(IUser discordUser, Channel inChannel)
{ {
var acc = r.SearchAccount(ui => ui.ExternalId == discordUser.Id.ToString() && ui.SeenInChannel.Id == inChannel.Id); var acc = Rememberer.SearchAccount(ui => ui.ExternalId == discordUser.Id.ToString() && ui.SeenInChannel.Id == inChannel.Id);
Console.WriteLine($"upserting account, retrieved {acc?.Id}."); Console.WriteLine($"upserting account, retrieved {acc?.Id}.");
if (acc != null) if (acc != null)
{ {
@ -361,7 +352,7 @@ public class DiscordInterface : ProtocolInterface
} }
acc ??= new Account() acc ??= new Account()
{ {
IsUser = r.SearchUser(u => u.Accounts.Any(a => a.ExternalId == discordUser.Id.ToString() && a.Protocol == Protocol)) IsUser = Rememberer.SearchUser(u => u.Accounts.Any(a => a.ExternalId == discordUser.Id.ToString() && a.Protocol == Protocol))
?? new User() ?? new User()
}; };
@ -381,12 +372,12 @@ public class DiscordInterface : ProtocolInterface
{ {
Console.WriteLine($"channel has {inChannel.Users.Count} accounts"); Console.WriteLine($"channel has {inChannel.Users.Count} accounts");
} }
r.RememberAccount(acc); Rememberer.RememberAccount(acc);
inChannel.Users ??= []; inChannel.Users ??= [];
if (!inChannel.Users.Contains(acc)) if (!inChannel.Users.Contains(acc))
{ {
inChannel.Users.Add(acc); inChannel.Users.Add(acc);
r.RememberChannel(inChannel); Rememberer.RememberChannel(inChannel);
} }
return acc; return acc;
} }
@ -394,7 +385,7 @@ public class DiscordInterface : ProtocolInterface
private static async Task<int> AttemptReact(IUserMessage msg, string e) private static async Task<int> AttemptReact(IUserMessage msg, string e)
{ {
Console.WriteLine("discord attempting to react"); Console.WriteLine("discord attempting to react");
var c = r.SearchChannel(c => c.ExternalId == msg.Channel.Id.ToString());// db.Channels.FirstOrDefault(c => c.ExternalId == msg.Channel.Id.ToString()); var c = Rememberer.SearchChannel(c => c.ExternalId == msg.Channel.Id.ToString());// db.Channels.FirstOrDefault(c => c.ExternalId == msg.Channel.Id.ToString());
//var preferredEmote = c.EmoteOverrides?[e] ?? e; //TODO: emote overrides //var preferredEmote = c.EmoteOverrides?[e] ?? e; //TODO: emote overrides
var preferredEmote = e; var preferredEmote = e;
if (Emoji.TryParse(preferredEmote, out Emoji emoji)) if (Emoji.TryParse(preferredEmote, out Emoji emoji))

View File

@ -21,7 +21,6 @@ public class TwitchInterface : ProtocolInterface
private Channel protocolAsChannel; private Channel protocolAsChannel;
public override Channel SelfChannel { get => protocolAsChannel;} public override Channel SelfChannel { get => protocolAsChannel;}
private Account selfAccountInProtocol; private Account selfAccountInProtocol;
private static Rememberer r = Rememberer.Instance;
TwitchClient client; TwitchClient client;
private async Task SetupTwitchChannel() private async Task SetupTwitchChannel()
@ -30,7 +29,7 @@ public class TwitchInterface : ProtocolInterface
try try
{ {
protocolAsChannel = r.SearchChannel(c => c.ParentChannel == null && c.Protocol == Protocol); protocolAsChannel = Rememberer.SearchChannel(c => c.ParentChannel == null && c.Protocol == Protocol);
if (protocolAsChannel == null) if (protocolAsChannel == null)
{ {
protocolAsChannel = new Channel() protocolAsChannel = new Channel()
@ -47,7 +46,7 @@ public class TwitchInterface : ProtocolInterface
SubChannels = [] SubChannels = []
}; };
protocolAsChannel.DisplayName = "twitch (itself)"; protocolAsChannel.DisplayName = "twitch (itself)";
protocolAsChannel = r.RememberChannel(protocolAsChannel); protocolAsChannel = Rememberer.RememberChannel(protocolAsChannel);
Console.WriteLine($"protocol as channle added; {protocolAsChannel}"); Console.WriteLine($"protocol as channle added; {protocolAsChannel}");
} }
else else
@ -140,7 +139,7 @@ public class TwitchInterface : ProtocolInterface
private Account UpsertAccount(string username, Channel inChannel) private Account UpsertAccount(string username, Channel inChannel)
{ {
//Console.WriteLine($"upserting twitch account. username: {username}. inChannel: {inChannel?.Id}"); //Console.WriteLine($"upserting twitch account. username: {username}. inChannel: {inChannel?.Id}");
var acc = r.SearchAccount(ui => ui.ExternalId == username && ui.SeenInChannel.ExternalId == inChannel.ExternalId); var acc = Rememberer.SearchAccount(ui => ui.ExternalId == username && ui.SeenInChannel.ExternalId == inChannel.ExternalId);
// Console.WriteLine($"upserting twitch account, retrieved {acc?.Id}."); // Console.WriteLine($"upserting twitch account, retrieved {acc?.Id}.");
if (acc != null) if (acc != null)
{ {
@ -148,7 +147,7 @@ public class TwitchInterface : ProtocolInterface
} }
acc ??= new Account() acc ??= new Account()
{ {
IsUser = r.SearchUser( IsUser = Rememberer.SearchUser(
u => u.Accounts.Any(a => a.ExternalId == username && a.Protocol == Protocol)) u => u.Accounts.Any(a => a.ExternalId == username && a.Protocol == Protocol))
?? new vassago.Models.User() ?? new vassago.Models.User()
}; };
@ -169,19 +168,19 @@ public class TwitchInterface : ProtocolInterface
// { // {
// Console.WriteLine($"channel has {inChannel.Users.Count} accounts"); // Console.WriteLine($"channel has {inChannel.Users.Count} accounts");
// } // }
r.RememberAccount(acc); Rememberer.RememberAccount(acc);
inChannel.Users ??= []; inChannel.Users ??= [];
if (!inChannel.Users.Contains(acc)) if (!inChannel.Users.Contains(acc))
{ {
inChannel.Users.Add(acc); inChannel.Users.Add(acc);
r.RememberChannel(inChannel); Rememberer.RememberChannel(inChannel);
} }
return acc; return acc;
} }
private Channel UpsertChannel(string channelName) private Channel UpsertChannel(string channelName)
{ {
Channel c = r.SearchChannel(ci => ci.ExternalId == channelName Channel c = Rememberer.SearchChannel(ci => ci.ExternalId == channelName
&& ci.Protocol == Protocol); && ci.Protocol == Protocol);
if (c == null) if (c == null)
{ {
@ -199,7 +198,7 @@ public class TwitchInterface : ProtocolInterface
c.Protocol = Protocol; c.Protocol = Protocol;
c.ParentChannel = protocolAsChannel; c.ParentChannel = protocolAsChannel;
c.SubChannels = c.SubChannels ?? new List<Channel>(); c.SubChannels = c.SubChannels ?? new List<Channel>();
c = r.RememberChannel(c); c = Rememberer.RememberChannel(c);
var selfAccountInChannel = c.Users?.FirstOrDefault(a => a.ExternalId == selfAccountInProtocol.ExternalId); var selfAccountInChannel = c.Users?.FirstOrDefault(a => a.ExternalId == selfAccountInProtocol.ExternalId);
if (selfAccountInChannel == null) if (selfAccountInChannel == null)
@ -211,7 +210,7 @@ public class TwitchInterface : ProtocolInterface
} }
private Channel UpsertDMChannel(string whisperWith) private Channel UpsertDMChannel(string whisperWith)
{ {
Channel c = r.SearchChannel(ci => ci.ExternalId == $"w_{whisperWith}" Channel c = Rememberer.SearchChannel(ci => ci.ExternalId == $"w_{whisperWith}"
&& ci.Protocol == Protocol); && ci.Protocol == Protocol);
if (c == null) if (c == null)
{ {
@ -229,7 +228,7 @@ public class TwitchInterface : ProtocolInterface
c.Protocol = Protocol; c.Protocol = Protocol;
c.ParentChannel = protocolAsChannel; c.ParentChannel = protocolAsChannel;
c.SubChannels = c.SubChannels ?? new List<Channel>(); c.SubChannels = c.SubChannels ?? new List<Channel>();
c = r.RememberChannel(c); c = Rememberer.RememberChannel(c);
var selfAccountInChannel = c.Users.FirstOrDefault(a => a.ExternalId == selfAccountInProtocol.ExternalId); var selfAccountInChannel = c.Users.FirstOrDefault(a => a.ExternalId == selfAccountInProtocol.ExternalId);
if (selfAccountInChannel == null) if (selfAccountInChannel == null)
@ -245,7 +244,7 @@ public class TwitchInterface : ProtocolInterface
//none of the features we care about are on it! //none of the features we care about are on it!
private Message UpsertMessage(ChatMessage chatMessage) private Message UpsertMessage(ChatMessage chatMessage)
{ {
var m = r.SearchMessage(mi => mi.ExternalId == chatMessage.Id && mi.Protocol == Protocol) var m = Rememberer.SearchMessage(mi => mi.ExternalId == chatMessage.Id && mi.Protocol == Protocol)
?? new() ?? new()
{ {
Protocol = Protocol, Protocol = Protocol,
@ -256,7 +255,7 @@ public class TwitchInterface : ProtocolInterface
m.Channel = UpsertChannel(chatMessage.Channel); m.Channel = UpsertChannel(chatMessage.Channel);
m.Author = UpsertAccount(chatMessage.Username, m.Channel); m.Author = UpsertAccount(chatMessage.Username, m.Channel);
m.MentionsMe = Regex.IsMatch(m.Content?.ToLower(), $"@\\b{selfAccountInProtocol.Username.ToLower()}\\b"); m.MentionsMe = Regex.IsMatch(m.Content?.ToLower(), $"@\\b{selfAccountInProtocol.Username.ToLower()}\\b");
r.RememberMessage(m); Rememberer.RememberMessage(m);
return m; return m;
} }
//n.b., I see you future adam. "we should unify these, they're redundant". //n.b., I see you future adam. "we should unify these, they're redundant".
@ -265,7 +264,7 @@ public class TwitchInterface : ProtocolInterface
private Message UpsertMessage(WhisperMessage whisperMessage) private Message UpsertMessage(WhisperMessage whisperMessage)
{ {
//WhisperMessage.Id corresponds to chatMessage.Id. \*eye twitch* //WhisperMessage.Id corresponds to chatMessage.Id. \*eye twitch*
var m = r.SearchMessage(mi => mi.ExternalId == whisperMessage.MessageId && mi.Protocol == Protocol) var m = Rememberer.SearchMessage(mi => mi.ExternalId == whisperMessage.MessageId && mi.Protocol == Protocol)
?? new() ?? new()
{ {
Id = Guid.NewGuid(), Id = Guid.NewGuid(),
@ -277,7 +276,7 @@ public class TwitchInterface : ProtocolInterface
m.Channel = UpsertDMChannel(whisperMessage.Username); m.Channel = UpsertDMChannel(whisperMessage.Username);
m.Author = UpsertAccount(whisperMessage.Username, m.Channel); m.Author = UpsertAccount(whisperMessage.Username, m.Channel);
m.MentionsMe = Regex.IsMatch(m.Content?.ToLower(), $"@\\b{selfAccountInProtocol.Username.ToLower()}\\b"); m.MentionsMe = Regex.IsMatch(m.Content?.ToLower(), $"@\\b{selfAccountInProtocol.Username.ToLower()}\\b");
r.RememberMessage(m); Rememberer.RememberMessage(m);
return m; return m;
} }

View File

@ -4,38 +4,18 @@ using System.Linq.Expressions;
using vassago.Models; using vassago.Models;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
public class Rememberer public static class Rememberer
{ {
private readonly SemaphoreSlim dbAccessSemaphore = new(1, 1); private static readonly SemaphoreSlim dbAccessSemaphore = new(1, 1);
private readonly ChattingContext db = new(); private static readonly ChattingContext db = new();
private List<Channel> channels; private static List<Channel> channels;
private bool channelCacheDirty = true; private static bool channelCacheDirty = true;
private Rememberer() { }
private static Rememberer _instance = null;
public static Rememberer Instance
{
get
{
if (_instance == null)
{
lock (instantiationLock) private static void cacheChannels()
{
if (_instance == null)
{
_instance = new Rememberer();
}
}
}
return _instance;
}
}
private static readonly object instantiationLock = new();
private void cacheChannels()
{ {
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
channels = db.Channels.ToList(); channels = db.Channels.ToList();
Console.WriteLine($"caching channels. {channels.Count} channels retrieved");
foreach (Channel ch in channels) foreach (Channel ch in channels)
{ {
if (ch.ParentChannelId != null) if (ch.ParentChannelId != null)
@ -47,13 +27,17 @@ public class Rememberer
ch.ParentChannel.SubChannels.Add(ch); ch.ParentChannel.SubChannels.Add(ch);
} }
} }
if (ch.Messages?.Count > 0)
{
Console.WriteLine($"{ch.DisplayName} got {ch.Messages.Count} messages");
}
ch.SubChannels ??= []; ch.SubChannels ??= [];
} }
channelCacheDirty = false; channelCacheDirty = false;
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
} }
public Account SearchAccount(Expression<Func<Account, bool>> predicate) public static Account SearchAccount(Expression<Func<Account, bool>> predicate)
{ {
Account toReturn; Account toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -61,7 +45,7 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
public List<Account> SearchAccounts(Expression<Func<Account, bool>> predicate) public static List<Account> SearchAccounts(Expression<Func<Account, bool>> predicate)
{ {
List<Account> toReturn; List<Account> toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -69,7 +53,7 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
public Attachment SearchAttachment(Expression<Func<Attachment, bool>> predicate) public static Attachment SearchAttachment(Expression<Func<Attachment, bool>> predicate)
{ {
Attachment toReturn; Attachment toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -77,13 +61,13 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
public Channel SearchChannel(Func<Channel, bool> predicate) public static Channel SearchChannel(Func<Channel, bool> predicate)
{ {
if (channelCacheDirty) if (channelCacheDirty)
Task.Run(() => cacheChannels()).Wait(); Task.Run(() => cacheChannels()).Wait();
return channels.FirstOrDefault(predicate); return channels.FirstOrDefault(predicate);
} }
public Message SearchMessage(Expression<Func<Message, bool>> predicate) public static Message SearchMessage(Expression<Func<Message, bool>> predicate)
{ {
Message toReturn; Message toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -91,7 +75,7 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
public List<Message> SearchMessages(Expression<Func<Message, bool>> predicate) public static List<Message> SearchMessages(Expression<Func<Message, bool>> predicate)
{ {
List<Message> toReturn; List<Message> toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -99,7 +83,7 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
public User SearchUser(Expression<Func<User, bool>> predicate) public static User SearchUser(Expression<Func<User, bool>> predicate)
{ {
User toReturn; User toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -107,7 +91,7 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
public void RememberAccount(Account toRemember) public static void RememberAccount(Account toRemember)
{ {
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
toRemember.IsUser ??= new User { Accounts = [toRemember] }; toRemember.IsUser ??= new User { Accounts = [toRemember] };
@ -115,7 +99,7 @@ public class Rememberer
db.SaveChanges(); db.SaveChanges();
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
} }
public void RememberAttachment(Attachment toRemember) public static void RememberAttachment(Attachment toRemember)
{ {
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
toRemember.Message ??= new Message() { Attachments = [toRemember] }; toRemember.Message ??= new Message() { Attachments = [toRemember] };
@ -123,7 +107,7 @@ public class Rememberer
db.SaveChanges(); db.SaveChanges();
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
} }
public Channel RememberChannel(Channel toRemember) public static Channel RememberChannel(Channel toRemember)
{ {
if (channelCacheDirty) if (channelCacheDirty)
Task.Run(() => cacheChannels()).Wait(); //so we always do 2 db trips? Task.Run(() => cacheChannels()).Wait(); //so we always do 2 db trips?
@ -135,7 +119,7 @@ public class Rememberer
cacheChannels(); cacheChannels();
return toRemember; return toRemember;
} }
public void RememberMessage(Message toRemember) public static void RememberMessage(Message toRemember)
{ {
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
toRemember.Channel ??= new(); toRemember.Channel ??= new();
@ -149,21 +133,21 @@ public class Rememberer
db.SaveChanges(); db.SaveChanges();
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
} }
public void RememberUser(User toRemember) public static void RememberUser(User toRemember)
{ {
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
db.Users.Update(toRemember); db.Users.Update(toRemember);
db.SaveChanges(); db.SaveChanges();
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
} }
public void ForgetAccount(Account toForget) public static void ForgetAccount(Account toForget)
{ {
var user = toForget.IsUser; var user = toForget.IsUser;
var usersOnlyAccount = user.Accounts?.Count == 1; var usersOnlyAccount = user.Accounts?.Count == 1;
if (usersOnlyAccount) if (usersOnlyAccount)
{ {
ForgetUser(user); Rememberer.ForgetUser(user);
} }
else else
{ {
@ -173,14 +157,14 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
} }
} }
public void ForgetAttachment(Attachment toForget) public static void ForgetAttachment(Attachment toForget)
{ {
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
db.Attachments.Remove(toForget); db.Attachments.Remove(toForget);
db.SaveChanges(); db.SaveChanges();
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
} }
public void ForgetChannel(Channel toForget) public static void ForgetChannel(Channel toForget)
{ {
if (toForget.SubChannels?.Count > 0) if (toForget.SubChannels?.Count > 0)
{ {
@ -203,28 +187,28 @@ public class Rememberer
channelCacheDirty = true; channelCacheDirty = true;
cacheChannels(); cacheChannels();
} }
public void ForgetMessage(Message toForget) public static void ForgetMessage(Message toForget)
{ {
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
db.Messages.Remove(toForget); db.Messages.Remove(toForget);
db.SaveChanges(); db.SaveChanges();
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
} }
public void ForgetUAC(UAC toForget) public static void ForgetUAC(UAC toForget)
{ {
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
db.UACs.Remove(toForget); db.UACs.Remove(toForget);
db.SaveChanges(); db.SaveChanges();
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
} }
public void ForgetUser(User toForget) public static void ForgetUser(User toForget)
{ {
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
db.Users.Remove(toForget); db.Users.Remove(toForget);
db.SaveChanges(); db.SaveChanges();
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
} }
public List<Account> AccountsOverview() public static List<Account> AccountsOverview()
{ {
List<Account> toReturn; List<Account> toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -232,16 +216,13 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
///<summary> public static List<Channel> ChannelsOverview()
///intentionally does not include Users; to help search for orphaned accounts.
///</summary>
public List<Channel> ChannelsOverview()
{ {
if (channelCacheDirty) if (channelCacheDirty)
Task.Run(() => cacheChannels()).Wait(); Task.Run(() => cacheChannels()).Wait();
return channels.ToList(); return channels;
} }
public Account AccountDetail(Guid Id) public static Account AccountDetail(Guid Id)
{ {
Account toReturn; Account toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -249,7 +230,7 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
public Attachment AttachmentDetail(Guid Id) public static Attachment AttachmentDetail(Guid Id)
{ {
Attachment toReturn; Attachment toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -257,18 +238,16 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
public Channel ChannelDetail(Guid Id, bool accounts = true, bool messages = false) public static Channel ChannelDetail(Guid Id, bool messages = false)
{ {
if (channelCacheDirty) if (channelCacheDirty)
Task.Run(() => cacheChannels()).Wait(); Task.Run(() => cacheChannels()).Wait();
var ch = channels.Find(c => c.Id == Id); var ch = channels.Find(c => c.Id == Id);
if(accounts)
ch.Users = SearchAccounts(a => a.SeenInChannel == ch);
if (messages) if (messages)
ch.Messages = SearchMessages(m => m.ChannelId == ch.Id); ch.Messages = SearchMessages(m => m.ChannelId == ch.Id);
return ch; return ch;
} }
public Message MessageDetail(Guid Id) public static Message MessageDetail(Guid Id)
{ {
Message toReturn; Message toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -277,7 +256,7 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
public UAC UACDetail(Guid Id) public static UAC UACDetail(Guid Id)
{ {
UAC toReturn; UAC toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -285,7 +264,7 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
public User UserDetail(Guid Id) public static User UserDetail(Guid Id)
{ {
User toReturn; User toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -293,7 +272,7 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
public List<User> UsersOverview() public static List<User> UsersOverview()
{ {
List<User> toReturn; List<User> toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -301,7 +280,7 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
public List<UAC> UACsOverview() public static List<UAC> UACsOverview()
{ {
List<UAC> toReturn; List<UAC> toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -309,7 +288,7 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
public UAC SearchUAC(Expression<Func<UAC, bool>> predicate) public static UAC SearchUAC(Expression<Func<UAC, bool>> predicate)
{ {
UAC toReturn; UAC toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -318,7 +297,7 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
public List<UAC> MatchUACs(Message message) public static List<UAC> MatchUACs(Message message)
{ {
var msgId = message.Id; var msgId = message.Id;
var accId = message.Author.Id; var accId = message.Author.Id;
@ -329,7 +308,7 @@ public class Rememberer
|| uac.Users.FirstOrDefault(usr => usr.Id == usrId) != null || uac.Users.FirstOrDefault(usr => usr.Id == usrId) != null
|| uac.Channels.FirstOrDefault(ch => ch.Id == chId) != null); || uac.Channels.FirstOrDefault(ch => ch.Id == chId) != null);
} }
public List<UAC> SearchUACs(Expression<Func<UAC, bool>> predicate) public static List<UAC> SearchUACs(Expression<Func<UAC, bool>> predicate)
{ {
List<UAC> toReturn; List<UAC> toReturn;
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
@ -338,7 +317,7 @@ public class Rememberer
dbAccessSemaphore.Release(); dbAccessSemaphore.Release();
return toReturn; return toReturn;
} }
public void RememberUAC(UAC toRemember) public static void RememberUAC(UAC toRemember)
{ {
dbAccessSemaphore.Wait(); dbAccessSemaphore.Wait();
db.Update(toRemember); db.Update(toRemember);
@ -347,18 +326,4 @@ public class Rememberer
if (toRemember.Channels?.Count() > 0) if (toRemember.Channels?.Count() > 0)
cacheChannels(); cacheChannels();
} }
public Configuration Configuration()
{
dbAccessSemaphore.Wait();
var toReturn = db.Configurations.FirstOrDefault();
dbAccessSemaphore.Release();
return toReturn;
}
public void RememberConfiguration(Configuration conf)
{
dbAccessSemaphore.Wait();
db.Update(conf);
db.SaveChanges();
dbAccessSemaphore.Release();
}
} }

View File

@ -10,17 +10,17 @@ namespace vassago.WebInterface.Controllers;
public class ChannelsController() : Controller public class ChannelsController() : Controller
{ {
private static Rememberer r = Rememberer.Instance;
public IActionResult Details(Guid id) public IActionResult Details(Guid id)
{ {
var channel = r.ChannelDetail(id); var allChannels = Rememberer.ChannelsOverview();
if (allChannels == null)
return Problem("no channels.");
var channel = allChannels.FirstOrDefault(u => u.Id == id);
if (channel == null) if (channel == null)
{ {
return Problem($"couldn't find channle {id}"); return Problem($"couldn't find channle {id}");
} }
else {
Console.WriteLine($"details.cshtml will have a channel; {channel}.");
}
var walker = channel; var walker = channel;
while (walker != null) while (walker != null)
{ {

View File

@ -1,129 +0,0 @@
using System.Diagnostics;
using System.Text;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using vassago;
using vassago.Behavior;
using vassago.Models;
using vassago.WebInterface.Models;
using vassago.TwitchInterface;
namespace vassago.WebInterface.Controllers;
public class ConfigurationController() : Controller
{
private static Rememberer r = Rememberer.Instance;
public IActionResult Index()
{
var conf = r.Configuration() ?? new Configuration();
ViewData.Add("Serialized", JsonConvert.SerializeObject(conf));
return View(conf);
}
[HttpPost]
public IActionResult Submit(Configuration incoming)
{
var conf = r.Configuration() ?? new Configuration();
conf.DiscordTokens = incoming.DiscordTokens;
conf.TwitchConfigs = incoming.TwitchConfigs;
conf.ExchangePairsLocation = incoming.ExchangePairsLocation;
conf.SetupDiscordSlashCommands = incoming.SetupDiscordSlashCommands;
conf.Webhooks = incoming.Webhooks;
conf.KafkaBootstrap = incoming.KafkaBootstrap;
conf.KafkaName = incoming.KafkaName;
conf.reportedApiUrl = incoming.reportedApiUrl;
r.RememberConfiguration(conf);
return RedirectToAction("Index", "Configuration");
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorPageViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
[HttpPost]
public IActionResult AddDiscord(string newToken)
{
Console.WriteLine($"adding discord, {newToken}");
var conf = r.Configuration();
conf.DiscordTokens ??= [];
conf.DiscordTokens.Add(newToken);
r.RememberConfiguration(conf);
return RedirectToAction("Index", "Configuration");
}
[HttpPost]
public IActionResult RemoveDiscord(int index)
{
Console.WriteLine($"removing discord[{index}]");
var conf = r.Configuration();
if (conf.DiscordTokens?.Count <= index)
{
Console.Error.WriteLine("error removing discord {index} from configuration, only have {conf.DiscordTokens?.Count}.");
return RedirectToAction("Index", "Configuration");
}
conf.DiscordTokens.RemoveAt(index);
r.RememberConfiguration(conf);
return RedirectToAction("Index", "Configuration");
}
[HttpPost]
public IActionResult AddTwitch(string newUsername, string newOauth)
{
Console.WriteLine($"adding twitch, {newUsername}/{newOauth}");
var conf = r.Configuration();
conf.TwitchConfigs ??= [];
var thisOne = new TwitchConfig()
{
username = newUsername,
oauth = newOauth
};
conf.TwitchConfigs.Add(JsonConvert.SerializeObject(thisOne));
r.RememberConfiguration(conf);
return RedirectToAction("Index", "Configuration");
}
[HttpPost]
public IActionResult RemoveTwitch(int index)
{
Console.WriteLine($"removing twitch[{index}]");
var conf = r.Configuration();
if (conf.TwitchConfigs?.Count <= index)
{
Console.Error.WriteLine("error removing twitch {index} from configuration, only have {conf.TwitchConfigs?.Count}.");
return RedirectToAction("Index", "Configuration");
}
conf.TwitchConfigs.RemoveAt(index);
r.RememberConfiguration(conf);
return RedirectToAction("Index", "Configuration");
}
[HttpPost]
public IActionResult AddWebhook(WebhookConf newWebhook)
{
Console.WriteLine($"adding webhook, {newWebhook}");
var conf = r.Configuration();
conf.Webhooks??= [];
conf.Webhooks.Add(JsonConvert.SerializeObject(newWebhook));
r.RememberConfiguration(conf);
return RedirectToAction("Index", "Configuration");
}
[HttpPost]
public IActionResult RemoveWebhook(int index)
{
Console.WriteLine($"removing webhook[{index}]");
var conf = r.Configuration();
if (conf.Webhooks?.Count <= index)
{
Console.Error.WriteLine("error removing webhook {index} from configuration, only have {conf.Webhooks?.Count}.");
return RedirectToAction("Index", "Configuration");
}
conf.Webhooks.RemoveAt(index);
r.RememberConfiguration(conf);
return RedirectToAction("Index", "Configuration");
}
}

View File

@ -12,7 +12,6 @@ namespace vassago.Controllers;
public class HomeController : Controller public class HomeController : Controller
{ {
private readonly ILogger<HomeController> _logger; private readonly ILogger<HomeController> _logger;
private static Rememberer r = Rememberer.Instance;
public HomeController(ILogger<HomeController> logger) public HomeController(ILogger<HomeController> logger)
{ {
@ -21,16 +20,14 @@ public class HomeController : Controller
public IActionResult Index() public IActionResult Index()
{ {
var allAccounts = r.AccountsOverview(); var allAccounts = Rememberer.AccountsOverview();
var allChannels = r.ChannelsOverview(); var allChannels = Rememberer.ChannelsOverview();
Console.WriteLine($"accounts: {allAccounts?.Count ?? 0}, channels: {allChannels?.Count ?? 0}"); Console.WriteLine($"accounts: {allAccounts?.Count ?? 0}, channels: {allChannels?.Count ?? 0}");
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.Append('['); sb.Append('[');
sb.Append($"{{\"text\": \"<a href=\\\"{Url.ActionLink(action: "Index", controller: "Configuration")}\\\">Configuration</a>\"}},");
//UACs //UACs
var allUACs = r.UACsOverview(); var allUACs = Rememberer.UACsOverview();
var first = true; var first = true;
if(allUACs.Any()) if(allUACs.Any())
{ {
@ -61,13 +58,13 @@ public class HomeController : Controller
} }
//users //users
var users = r.UsersOverview(); var users = Rememberer.UsersOverview();
if(users.Any()) if(users.Any())
{ {
sb.Append(",{text: \"users\", expanded:true, nodes: ["); sb.Append(",{text: \"users\", expanded:true, nodes: [");
first=true; first=true;
//refresh list; we'll be knocking them out again in serializeUser //refresh list; we'll be knocking them out again in serializeUser
allAccounts = r.AccountsOverview(); allAccounts = Rememberer.AccountsOverview();
foreach(var user in users) foreach(var user in users)
{ {
if (first) if (first)
@ -83,9 +80,10 @@ public class HomeController : Controller
sb.Append("]}"); sb.Append("]}");
} }
//type error, e is not defined
//channels //channels
sb.Append(",{text: \"channels\", expanded:true, nodes: ["); sb.Append(",{text: \"channels\", expanded:true, nodes: [");
var topLevelChannels = r.ChannelsOverview().Where(x => x.ParentChannel == null).ToList(); var topLevelChannels = Rememberer.ChannelsOverview().Where(x => x.ParentChannel == null).ToList();
first = true; first = true;
foreach (var topLevelChannel in topLevelChannels) foreach (var topLevelChannel in topLevelChannels)
{ {

View File

@ -10,11 +10,11 @@ public class UACsController() : Controller
{ {
public IActionResult Index() public IActionResult Index()
{ {
return View(Rememberer.Instance.UACsOverview()); return View(Rememberer.UACsOverview());
} }
public IActionResult Details(Guid id) public IActionResult Details(Guid id)
{ {
return View(Rememberer.Instance.SearchUAC(uac => uac.Id == id)); return View(Rememberer.SearchUAC(uac => uac.Id == id));
} }
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

View File

@ -11,7 +11,6 @@ namespace vassago.Controllers.api;
public class AccountsController : ControllerBase public class AccountsController : ControllerBase
{ {
private readonly ILogger<AccountsController> _logger; private readonly ILogger<AccountsController> _logger;
private static Rememberer r = Rememberer.Instance;
public AccountsController(ILogger<AccountsController> logger) public AccountsController(ILogger<AccountsController> logger)
{ {
@ -30,14 +29,14 @@ public class AccountsController : ControllerBase
public IActionResult UnlinkUser([FromBody] extraSpecialObjectReadGlorifiedTupleFor_UnlinkUser req) public IActionResult UnlinkUser([FromBody] extraSpecialObjectReadGlorifiedTupleFor_UnlinkUser req)
{ {
var acc_guid = req.acc_guid; var acc_guid = req.acc_guid;
var accFromDb = r.SearchAccount(acc => acc.Id == acc_guid); var accFromDb = Rememberer.SearchAccount(acc => acc.Id == acc_guid);
if (accFromDb == null) if (accFromDb == null)
{ {
var err = $"attempt to unlink user for acc {acc_guid}, not found"; var err = $"attempt to unlink user for acc {acc_guid}, not found";
_logger.LogError(err); _logger.LogError(err);
return NotFound(err); return NotFound(err);
} }
var userFromDb = r.SearchUser(c => c.Id == accFromDb.IsUser.Id); var userFromDb = Rememberer.SearchUser(c => c.Id == accFromDb.IsUser.Id);
if (userFromDb == null) if (userFromDb == null)
{ {
var err = $"attempt to unlink user for {acc_guid}, doesn't have a user"; var err = $"attempt to unlink user for {acc_guid}, doesn't have a user";
@ -47,7 +46,7 @@ public class AccountsController : ControllerBase
accFromDb.IsUser = null; accFromDb.IsUser = null;
r.RememberAccount(accFromDb); Rememberer.RememberAccount(accFromDb);
return Ok(accFromDb); return Ok(accFromDb);
} }
} }

View File

@ -10,7 +10,6 @@ namespace vassago.Controllers.api;
public class RemembererController : ControllerBase public class RemembererController : ControllerBase
{ {
private readonly ILogger<RemembererController> _logger; private readonly ILogger<RemembererController> _logger;
private static Rememberer r = Rememberer.Instance;
public RemembererController(ILogger<RemembererController> logger) public RemembererController(ILogger<RemembererController> logger)
{ {
@ -23,42 +22,42 @@ public class RemembererController : ControllerBase
[Produces("application/json")] [Produces("application/json")]
public Account CreateAccount(Guid id) public Account CreateAccount(Guid id)
{ {
return r.AccountDetail(id); return Rememberer.AccountDetail(id);
} }
[HttpPut] [HttpPut]
[Route("Attachment")] [Route("Attachment")]
[Produces("application/json")] [Produces("application/json")]
public Attachment CreateAttachment(Guid id) public Attachment CreateAttachment(Guid id)
{ {
return r.AttachmentDetail(id); return Rememberer.AttachmentDetail(id);
} }
[HttpPut] [HttpPut]
[Route("Channels")] [Route("Channels")]
[Produces("application/json")] [Produces("application/json")]
public Channel CreateChannel(Guid id) public Channel CreateChannel(Guid id)
{ {
return r.ChannelDetail(id); return Rememberer.ChannelDetail(id);
} }
[HttpPut] [HttpPut]
[Route("Message")] [Route("Message")]
[Produces("application/json")] [Produces("application/json")]
public Message CreateMessage(Guid id) public Message CreateMessage(Guid id)
{ {
return r.MessageDetail(id); return Rememberer.MessageDetail(id);
} }
[HttpPut] [HttpPut]
[Route("UAC")] [Route("UAC")]
[Produces("application/json")] [Produces("application/json")]
public UAC CreateUAC(Guid id) public UAC CreateUAC(Guid id)
{ {
return r.UACDetail(id); return Rememberer.UACDetail(id);
} }
[HttpPut] [HttpPut]
[Route("User")] [Route("User")]
[Produces("application/json")] [Produces("application/json")]
public User CreateUser(Guid id) public User CreateUser(Guid id)
{ {
return r.UserDetail(id); return Rememberer.UserDetail(id);
} }
//Read //Read
[HttpGet] [HttpGet]
@ -66,42 +65,42 @@ public class RemembererController : ControllerBase
[Produces("application/json")] [Produces("application/json")]
public Account GetAccount(Guid id) public Account GetAccount(Guid id)
{ {
return r.AccountDetail(id); return Rememberer.AccountDetail(id);
} }
[HttpGet] [HttpGet]
[Route("Attachment")] [Route("Attachment")]
[Produces("application/json")] [Produces("application/json")]
public Attachment GetAttachment(Guid id) public Attachment GetAttachment(Guid id)
{ {
return r.AttachmentDetail(id); return Rememberer.AttachmentDetail(id);
} }
[HttpGet] [HttpGet]
[Route("Channels")] [Route("Channels")]
[Produces("application/json")] [Produces("application/json")]
public Channel GetChannel(Guid id) public Channel GetChannel(Guid id)
{ {
return r.ChannelDetail(id); return Rememberer.ChannelDetail(id);
} }
[HttpGet] [HttpGet]
[Route("Message")] [Route("Message")]
[Produces("application/json")] [Produces("application/json")]
public Message GetMessage(Guid id) public Message GetMessage(Guid id)
{ {
return r.MessageDetail(id); return Rememberer.MessageDetail(id);
} }
[HttpGet] [HttpGet]
[Route("UAC")] [Route("UAC")]
[Produces("application/json")] [Produces("application/json")]
public UAC GetUAC(Guid id) public UAC GetUAC(Guid id)
{ {
return r.UACDetail(id); return Rememberer.UACDetail(id);
} }
[HttpGet] [HttpGet]
[Route("User")] [Route("User")]
[Produces("application/json")] [Produces("application/json")]
public User GetUser(Guid id) public User GetUser(Guid id)
{ {
return r.UserDetail(id); return Rememberer.UserDetail(id);
} }
//Update //Update
[HttpPatch] [HttpPatch]
@ -109,7 +108,7 @@ public class RemembererController : ControllerBase
[Produces("application/json")] [Produces("application/json")]
public IActionResult Patch([FromBody] Channel channel) public IActionResult Patch([FromBody] Channel channel)
{ {
var fromDb = r.ChannelDetail(channel.Id); var fromDb = Rememberer.ChannelDetail(channel.Id);
if (fromDb == null) if (fromDb == null)
{ {
_logger.LogError($"attempt to update channel {channel.Id}, not found"); _logger.LogError($"attempt to update channel {channel.Id}, not found");
@ -122,7 +121,7 @@ public class RemembererController : ControllerBase
//settable values: lewdness filter level, meanness filter level. maybe i could decorate them... //settable values: lewdness filter level, meanness filter level. maybe i could decorate them...
fromDb.LewdnessFilterLevel = channel.LewdnessFilterLevel; fromDb.LewdnessFilterLevel = channel.LewdnessFilterLevel;
fromDb.MeannessFilterLevel = channel.MeannessFilterLevel; fromDb.MeannessFilterLevel = channel.MeannessFilterLevel;
r.RememberChannel(fromDb); Rememberer.RememberChannel(fromDb);
return Ok(fromDb); return Ok(fromDb);
} }
//Delete //Delete
@ -131,13 +130,13 @@ public class RemembererController : ControllerBase
[Produces("application/json")] [Produces("application/json")]
public IActionResult DeleteAccount(Guid id) public IActionResult DeleteAccount(Guid id)
{ {
var fromDb = r.AccountDetail(id); var fromDb = Rememberer.AccountDetail(id);
if (fromDb == null) if (fromDb == null)
{ {
_logger.LogError($"attempt to delete account {id}, not found"); _logger.LogError($"attempt to delete account {id}, not found");
return NotFound(); return NotFound();
} }
r.ForgetAccount(fromDb); Rememberer.ForgetAccount(fromDb);
return Ok(); return Ok();
} }
[HttpDelete] [HttpDelete]
@ -145,13 +144,13 @@ public class RemembererController : ControllerBase
[Produces("application/json")] [Produces("application/json")]
public IActionResult DeleteAttachment(Guid id) public IActionResult DeleteAttachment(Guid id)
{ {
var fromDb = r.AttachmentDetail(id); var fromDb = Rememberer.AttachmentDetail(id);
if (fromDb == null) if (fromDb == null)
{ {
_logger.LogError($"attempt to delete attachment {id}, not found"); _logger.LogError($"attempt to delete attachment {id}, not found");
return NotFound(); return NotFound();
} }
r.ForgetAttachment(fromDb); Rememberer.ForgetAttachment(fromDb);
return Ok(); return Ok();
} }
[HttpDelete] [HttpDelete]
@ -159,14 +158,14 @@ public class RemembererController : ControllerBase
[Produces("application/json")] [Produces("application/json")]
public IActionResult DeleteChannel(Guid id) public IActionResult DeleteChannel(Guid id)
{ {
var fromDb = r.ChannelDetail(id); var fromDb = Rememberer.ChannelDetail(id);
_logger.LogDebug($"delete channel {id}"); _logger.LogDebug($"delete channel {id}");
if (fromDb == null) if (fromDb == null)
{ {
_logger.LogError($"attempt to delete channel {id}, not found"); _logger.LogError($"attempt to delete channel {id}, not found");
return NotFound(); return NotFound();
} }
r.ForgetChannel(fromDb); Rememberer.ForgetChannel(fromDb);
_logger.LogDebug($"delete channel {id} success"); _logger.LogDebug($"delete channel {id} success");
return Ok(); return Ok();
} }
@ -175,13 +174,13 @@ public class RemembererController : ControllerBase
[Produces("application/json")] [Produces("application/json")]
public IActionResult DeleteMessage(Guid id) public IActionResult DeleteMessage(Guid id)
{ {
var fromDb = r.MessageDetail(id); var fromDb = Rememberer.MessageDetail(id);
if (fromDb == null) if (fromDb == null)
{ {
_logger.LogError($"attempt to delete message {id}, not found"); _logger.LogError($"attempt to delete message {id}, not found");
return NotFound(); return NotFound();
} }
r.ForgetMessage(fromDb); Rememberer.ForgetMessage(fromDb);
return Ok(); return Ok();
} }
[HttpDelete] [HttpDelete]
@ -189,13 +188,13 @@ public class RemembererController : ControllerBase
[Produces("application/json")] [Produces("application/json")]
public IActionResult DeleteUAC(Guid id) public IActionResult DeleteUAC(Guid id)
{ {
var fromDb = r.UACDetail(id); var fromDb = Rememberer.UACDetail(id);
if (fromDb == null) if (fromDb == null)
{ {
_logger.LogError($"attempt to delete uac {id}, not found"); _logger.LogError($"attempt to delete uac {id}, not found");
return NotFound(); return NotFound();
} }
r.ForgetUAC(fromDb); Rememberer.ForgetUAC(fromDb);
return Ok(); return Ok();
} }
[HttpDelete] [HttpDelete]
@ -203,13 +202,13 @@ public class RemembererController : ControllerBase
[Produces("application/json")] [Produces("application/json")]
public IActionResult DeleteUser(Guid id) public IActionResult DeleteUser(Guid id)
{ {
var fromDb = r.UserDetail(id); var fromDb = Rememberer.UserDetail(id);
if (fromDb == null) if (fromDb == null)
{ {
_logger.LogError($"attempt to delete user {id}, not found"); _logger.LogError($"attempt to delete user {id}, not found");
return NotFound(); return NotFound();
} }
r.ForgetUser(fromDb); Rememberer.ForgetUser(fromDb);
return Ok(); return Ok();
} }
} }

View File

@ -11,7 +11,6 @@ namespace vassago.Controllers.api;
public class UACController : ControllerBase public class UACController : ControllerBase
{ {
private readonly ILogger<UACController> _logger; private readonly ILogger<UACController> _logger;
private static Rememberer r = Rememberer.Instance;
public UACController(ILogger<UACController> logger) public UACController(ILogger<UACController> logger)
{ {
@ -32,14 +31,14 @@ public class UACController : ControllerBase
{ {
var uac_guid = req.uac_guid; var uac_guid = req.uac_guid;
var channel_guid = req.channel_guid; var channel_guid = req.channel_guid;
var uacFromDb = r.SearchUAC(uac => uac.Id == uac_guid); var uacFromDb = Rememberer.SearchUAC(uac => uac.Id == uac_guid);
if (uacFromDb == null) if (uacFromDb == null)
{ {
var err = $"attempt to link channel for uac {uac_guid}, not found"; var err = $"attempt to link channel for uac {uac_guid}, not found";
_logger.LogError(err); _logger.LogError(err);
return NotFound(err); return NotFound(err);
} }
var channelFromDb = r.SearchChannel(c => c.Id == channel_guid); var channelFromDb = Rememberer.SearchChannel(c => c.Id == channel_guid);
if (channelFromDb == null) if (channelFromDb == null)
{ {
var err = $"attempt to link channel for channel {channel_guid}, not found"; var err = $"attempt to link channel for channel {channel_guid}, not found";
@ -53,7 +52,7 @@ public class UACController : ControllerBase
return BadRequest("channel already linked"); return BadRequest("channel already linked");
} }
uacFromDb.Channels.Add(channelFromDb); uacFromDb.Channels.Add(channelFromDb);
r.RememberUAC(uacFromDb); Rememberer.RememberUAC(uacFromDb);
return Ok(uacFromDb); return Ok(uacFromDb);
} }
public class extraSpecialObjectReadGlorifiedTupleFor_LinkUser public class extraSpecialObjectReadGlorifiedTupleFor_LinkUser
@ -68,13 +67,13 @@ public class UACController : ControllerBase
{ {
var uac_guid = req.uac_guid; var uac_guid = req.uac_guid;
var user_guid = req.user_guid; var user_guid = req.user_guid;
var uacFromDb = r.SearchUAC(uac => uac.Id == uac_guid); var uacFromDb = Rememberer.SearchUAC(uac => uac.Id == uac_guid);
if (uacFromDb == null) if (uacFromDb == null)
{ {
_logger.LogError($"attempt to link channal for uac {uac_guid}, not found"); _logger.LogError($"attempt to link channal for uac {uac_guid}, not found");
return NotFound(); return NotFound();
} }
var userFromDb = r.SearchUser(c => c.Id == user_guid); var userFromDb = Rememberer.SearchUser(c => c.Id == user_guid);
if (userFromDb == null) if (userFromDb == null)
{ {
_logger.LogError($"attempt to link user for user {user_guid}, not found"); _logger.LogError($"attempt to link user for user {user_guid}, not found");
@ -87,7 +86,7 @@ public class UACController : ControllerBase
return BadRequest("user already linked"); return BadRequest("user already linked");
} }
uacFromDb.Users.Add(userFromDb); uacFromDb.Users.Add(userFromDb);
r.RememberUAC(uacFromDb); Rememberer.RememberUAC(uacFromDb);
return Ok(uacFromDb); return Ok(uacFromDb);
} }
public class extraSpecialObjectReadGlorifiedTupleFor_LinkAccount public class extraSpecialObjectReadGlorifiedTupleFor_LinkAccount
@ -102,13 +101,13 @@ public class UACController : ControllerBase
{ {
var uac_guid = req.uac_guid; var uac_guid = req.uac_guid;
var account_guid = req.account_guid; var account_guid = req.account_guid;
var uacFromDb = r.SearchUAC(uac => uac.Id == uac_guid); var uacFromDb = Rememberer.SearchUAC(uac => uac.Id == uac_guid);
if (uacFromDb == null) if (uacFromDb == null)
{ {
_logger.LogError($"attempt to link channal for uac {uac_guid}, not found"); _logger.LogError($"attempt to link channal for uac {uac_guid}, not found");
return NotFound(); return NotFound();
} }
var accountFromDb = r.SearchAccount(c => c.Id == account_guid); var accountFromDb = Rememberer.SearchAccount(c => c.Id == account_guid);
if (accountFromDb == null) if (accountFromDb == null)
{ {
_logger.LogError($"attempt to link account for user {account_guid}, not found"); _logger.LogError($"attempt to link account for user {account_guid}, not found");
@ -121,7 +120,7 @@ public class UACController : ControllerBase
return BadRequest("account already linked"); return BadRequest("account already linked");
} }
uacFromDb.AccountInChannels.Add(accountFromDb); uacFromDb.AccountInChannels.Add(accountFromDb);
r.RememberUAC(uacFromDb); Rememberer.RememberUAC(uacFromDb);
return Ok(uacFromDb); return Ok(uacFromDb);
} }
[HttpPatch] [HttpPatch]
@ -131,13 +130,13 @@ public class UACController : ControllerBase
{ {
var uac_guid = req.uac_guid; var uac_guid = req.uac_guid;
var user_guid = req.user_guid; var user_guid = req.user_guid;
var uacFromDb = r.SearchUAC(uac => uac.Id == uac_guid); var uacFromDb = Rememberer.SearchUAC(uac => uac.Id == uac_guid);
if (uacFromDb == null) if (uacFromDb == null)
{ {
_logger.LogError($"attempt to unlink uac for uac {uac_guid}, not found"); _logger.LogError($"attempt to unlink uac for uac {uac_guid}, not found");
return NotFound(); return NotFound();
} }
var userFromDb = r.SearchUser(c => c.Id == user_guid); var userFromDb = Rememberer.SearchUser(c => c.Id == user_guid);
if (userFromDb == null) if (userFromDb == null)
{ {
_logger.LogError($"attempt to unlink user for user {user_guid}, not found"); _logger.LogError($"attempt to unlink user for user {user_guid}, not found");
@ -150,7 +149,7 @@ public class UACController : ControllerBase
return BadRequest("user not linked"); return BadRequest("user not linked");
} }
uacFromDb.Users.Remove(userFromDb); uacFromDb.Users.Remove(userFromDb);
r.RememberUAC(uacFromDb); Rememberer.RememberUAC(uacFromDb);
return Ok(uacFromDb); return Ok(uacFromDb);
} }
[HttpPatch] [HttpPatch]
@ -160,13 +159,13 @@ public class UACController : ControllerBase
{ {
var uac_guid = req.uac_guid; var uac_guid = req.uac_guid;
var account_guid = req.account_guid; var account_guid = req.account_guid;
var uacFromDb = r.SearchUAC(uac => uac.Id == uac_guid); var uacFromDb = Rememberer.SearchUAC(uac => uac.Id == uac_guid);
if (uacFromDb == null) if (uacFromDb == null)
{ {
_logger.LogError($"attempt to unlink uac for uac {uac_guid}, not found"); _logger.LogError($"attempt to unlink uac for uac {uac_guid}, not found");
return NotFound(); return NotFound();
} }
var accountFromDb = r.SearchAccount(a => a.Id == account_guid); var accountFromDb = Rememberer.SearchAccount(a => a.Id == account_guid);
if (accountFromDb == null) if (accountFromDb == null)
{ {
_logger.LogError($"attempt to unlink account for user {account_guid}, not found"); _logger.LogError($"attempt to unlink account for user {account_guid}, not found");
@ -179,7 +178,7 @@ public class UACController : ControllerBase
return BadRequest("account not linked"); return BadRequest("account not linked");
} }
uacFromDb.AccountInChannels.Remove(accountFromDb); uacFromDb.AccountInChannels.Remove(accountFromDb);
r.RememberUAC(uacFromDb); Rememberer.RememberUAC(uacFromDb);
return Ok(uacFromDb); return Ok(uacFromDb);
} }
[HttpPatch] [HttpPatch]
@ -189,13 +188,13 @@ public class UACController : ControllerBase
{ {
var uac_guid = req.uac_guid; var uac_guid = req.uac_guid;
var channel_guid = req.channel_guid; var channel_guid = req.channel_guid;
var uacFromDb = r.SearchUAC(uac => uac.Id == uac_guid); var uacFromDb = Rememberer.SearchUAC(uac => uac.Id == uac_guid);
if (uacFromDb == null) if (uacFromDb == null)
{ {
_logger.LogError($"attempt to unlink channal for uac {uac_guid}, not found"); _logger.LogError($"attempt to unlink channal for uac {uac_guid}, not found");
return NotFound(); return NotFound();
} }
var channelFromDb = r.SearchChannel(c => c.Id == channel_guid); var channelFromDb = Rememberer.SearchChannel(c => c.Id == channel_guid);
if (channelFromDb == null) if (channelFromDb == null)
{ {
_logger.LogError($"attempt to unlink user for user {channel_guid}, not found"); _logger.LogError($"attempt to unlink user for user {channel_guid}, not found");
@ -208,7 +207,7 @@ public class UACController : ControllerBase
return BadRequest("user not linked"); return BadRequest("user not linked");
} }
uacFromDb.Channels.Remove(channelFromDb); uacFromDb.Channels.Remove(channelFromDb);
r.RememberUAC(uacFromDb); Rememberer.RememberUAC(uacFromDb);
return Ok(uacFromDb); return Ok(uacFromDb);
} }
[HttpPut] [HttpPut]
@ -217,7 +216,7 @@ public class UACController : ControllerBase
public IActionResult CreateForChannels(Guid Id) public IActionResult CreateForChannels(Guid Id)
{ {
_logger.LogDebug($"made it to controller. creating for channel {Id}"); _logger.LogDebug($"made it to controller. creating for channel {Id}");
var targetChannel = r.ChannelDetail(Id); var targetChannel = Rememberer.ChannelDetail(Id);
if (targetChannel == null) if (targetChannel == null)
{ {
return NotFound(); return NotFound();
@ -226,8 +225,8 @@ public class UACController : ControllerBase
{ {
Channels = [targetChannel] Channels = [targetChannel]
}; };
r.RememberUAC(newUAC); Rememberer.RememberUAC(newUAC);
r.RememberChannel(targetChannel); Rememberer.RememberChannel(targetChannel);
return Ok(newUAC.Id); return Ok(newUAC.Id);
} }
[HttpPut] [HttpPut]
@ -236,7 +235,7 @@ public class UACController : ControllerBase
public IActionResult AddTranslation(Guid Id) public IActionResult AddTranslation(Guid Id)
{ {
_logger.LogDebug($"made it to controller. creating translation for uac {Id}"); _logger.LogDebug($"made it to controller. creating translation for uac {Id}");
var uacFromDb = r.SearchUAC(uac => uac.Id == Id); var uacFromDb = Rememberer.SearchUAC(uac => uac.Id == Id);
if (uacFromDb == null) if (uacFromDb == null)
{ {
_logger.LogError($"attempt to create translation for uac {Id}, not found"); _logger.LogError($"attempt to create translation for uac {Id}, not found");
@ -244,7 +243,7 @@ public class UACController : ControllerBase
} }
uacFromDb.Translations ??= []; uacFromDb.Translations ??= [];
uacFromDb.Translations.Add(Guid.NewGuid().ToString(), Guid.NewGuid().ToString()); uacFromDb.Translations.Add(Guid.NewGuid().ToString(), Guid.NewGuid().ToString());
r.RememberUAC(uacFromDb); Rememberer.RememberUAC(uacFromDb);
return Ok(uacFromDb.Translations.Count); return Ok(uacFromDb.Translations.Count);
} }
[HttpPut] [HttpPut]
@ -253,7 +252,7 @@ public class UACController : ControllerBase
public IActionResult AddCommandAlteration(Guid Id) public IActionResult AddCommandAlteration(Guid Id)
{ {
_logger.LogDebug($"made it to controller. creating command alteration for uac {Id}"); _logger.LogDebug($"made it to controller. creating command alteration for uac {Id}");
var uacFromDb = r.SearchUAC(uac => uac.Id == Id); var uacFromDb = Rememberer.SearchUAC(uac => uac.Id == Id);
if (uacFromDb == null) if (uacFromDb == null)
{ {
_logger.LogError($"attempt to create command alteration for uac {Id}, not found"); _logger.LogError($"attempt to create command alteration for uac {Id}, not found");
@ -261,7 +260,7 @@ public class UACController : ControllerBase
} }
uacFromDb.CommandAlterations ??= []; uacFromDb.CommandAlterations ??= [];
uacFromDb.CommandAlterations.Add(Guid.NewGuid().ToString(), Guid.NewGuid().ToString()); uacFromDb.CommandAlterations.Add(Guid.NewGuid().ToString(), Guid.NewGuid().ToString());
r.RememberUAC(uacFromDb); Rememberer.RememberUAC(uacFromDb);
return Ok(uacFromDb.CommandAlterations.Count); return Ok(uacFromDb.CommandAlterations.Count);
} }

View File

@ -189,8 +189,7 @@
sb.Append("[{text: \"accounts\", \"expanded\":true, nodes: ["); sb.Append("[{text: \"accounts\", \"expanded\":true, nodes: [");
var first = true; var first = true;
Console.WriteLine($"{ThisChannel.DisplayName} has {ThisChannel.Users?.Count ?? 0} users."); foreach (var acc in ThisChannel.Users?.OrderBy(a => a?.SeenInChannel?.LineageSummary))
foreach (var acc in ThisChannel.Users?.OrderBy(a => a?.SeenInChannel?.LineageSummary ?? " ERROR"))
{ {
if(!first) if(!first)
sb.Append(','); sb.Append(',');

View File

@ -1,283 +0,0 @@
@model vassago.Models.Configuration
@using Newtonsoft.Json;
@using vassago.Behavior;
@using vassago.TwitchInterface;
@using System.Text;
<a href="/">home</a>/configuration
<form action="@Url.Action("submit", "Configuration")" method="post" id="theForm">
<table class="table">
<tbody>
<tr>
<th colspan="2">Discord (@(Model?.DiscordTokens?.Count ?? 0) accounts)</th>
</tr>
@{
if(Model.DiscordTokens != null) for(var i = 0; i < Model.DiscordTokens.Count; i++)
{
<tr>
<th><label for="DiscordTokens[@i]"></label></th>
<td>
<input type="text" class="form-control" name="DiscordTokens[@i]" value="@Model.DiscordTokens[i]"/>
<button type="button" onclick="removeDiscord(@i)" class="btn btn-danger">del</button>
</td>
</tr>
}
}
<tr>
<td></td>
<td>
<button type="button" onclick="addDiscord.showModal()">add</button>
</td>
</tr>
<tr>
<th><label class="form-check-label" for="SetupDiscordSlashCommands">Setup Discord Slash Commands</label>
<td><input type="checkbox" class="form-check-input position-static" name="SetupDiscordSlashCommands" checked="@Model.SetupDiscordSlashCommands" value="true"/></td>
</tr>
<tr>
<th colspan="2">Twitch (@(Model?.TwitchConfigs?.Count ?? 0) accounts)</th>
</tr>
@{
if(Model.TwitchConfigs != null) for(var i = 0; i < Model.TwitchConfigs.Count; i++)
{
var tc = JsonConvert.DeserializeObject<TwitchConfig>(Model.TwitchConfigs[i]);
<tr>
<th><label for="TwitchConfigs[@i]"></label></th>
<td>
<input type="hidden" name="TwitchConfigs[@i]" id="TwitchConfigs_@i" value="@Model.TwitchConfigs[i]" />
<input type="text" class="form-control" data-name="username" value="@tc.username"/>
<input type="text" class="form-control" data-name="oauth" value="@tc.oauth"/>
<button type="button" onclick="removeTwitch(@i);" class="btn btn-danger">del</button>
</td>
</tr>
}
}
<tr>
<td></td>
<td>
<button type="button" onclick="addTwitch.showModal()">add</button>
</td>
</tr>
<tr class="form-text">
<th><label for="ExchangePairsLocation">Exchange Pairs Location</label></th>
<td><input type="text" class="form-control" name="ExchangePairsLocation" value="@Model.ExchangePairsLocation"/></td>
</tr>
<tr>
<th colspan="2">Webhooks</th>
</tr>
@{
if(Model.Webhooks != null) for(var i = 0; i < Model.Webhooks.Count; i++)
{
if(Model.Webhooks[i] == null) continue;
Console.WriteLine(Model.Webhooks[i]);
var wh = JsonConvert.DeserializeObject<WebhookConf>(Model.Webhooks[i]);
if(wh == null) continue;
var sb = new StringBuilder();
if(wh.Headers != null) foreach(var header in wh.Headers)
{
sb.Append($"{header[0]}:");
if(header.Count == 2)
sb.Append(header[1]);
sb.AppendLine();
}
<tr>
<th><label for="Webhooks[@i]">@wh.Trigger</label></th>
<td>
<input type="hidden" name="Webhooks[@i]" id="Webhooks_@i" value="@Model.Webhooks[i]" />
<input type="text" class="form-control" data-name="Trigger" value="@wh.Trigger"/>
<input type="text" class="form-control" data-name="Uri" value="@wh.Uri"/>
<input type="text" class="form-control" data-name="Method" value="@wh.Method"/>
<input type="textarea" class="form-control" data-name="Headers" value="@sb.ToString()"/>
<input type="text" class="form-control" data-name="Content" value="@wh.Content"/>
<input type="text" class="form-control" data-name="Description" value="@wh.Description"/>
<button type="button" onclick="removeWebhook(@i);" class="btn btn-danger">del</button>
</td>
</tr>
}
}
<tr>
<td></td>
<td>
<button type="button" onclick="addWebhookDialog.showModal()">add</button>
</td>
</tr>
<tr class="form-text">
<th><label for="KafkaBootstrap">Kafka Bootstrap Server</label></th>
<td><input type="text" class="form-control" name="KafkaBootstrap" value="@Model.KafkaBootstrap"/></td>
</tr>
<tr class="form-text">
<th><label for="KafkaName">Kafka Name</label></th>
<td><input type="text" class="form-control" name="KafkaName" value="@Model.KafkaName"/></td>
</tr>
<tr class="form-text">
<th><label for="reportedApiUrl">reportedApiUrl</label></th>
<td><input type="text" class="form-control" name="reportedApiUrl" value="@Model.reportedApiUrl"/></td>
</tr>
<tr class="form-text">
<td colspan="2"><button class="btn btn-success" type="button" onclick="complexSubmit()">save</button></td>
</tr>
</tbody>
</table>
</form>
<dialog id="addDiscord">
<form action="@Url.Action("AddDiscord", "Configuration")" method="post">
<input type="text" class="form-control" name="newToken" />
<button class="btn btn-secondary" type="button" onclick="addDiscord.close()">cancel</button>
<button class="btn btn-success" type="submit">save</button>
</form>
</dialog>
<dialog id="removeDiscordDialog">
<form action="@Url.Action("RemoveDiscord", "Configuration")" method="post">
Are you sure?
<input type="hidden" name="index" id="removeDiscordTarget" />
<button class="btn btn-secondary" type="button" onclick="removeDiscordDialog.close()">cancel</button>
<button class="btn btn-danger" type="submit">delete</button>
</form>
</dialog>
<dialog id="addTwitch">
<form action="@Url.Action("AddTwitch", "Configuration")" method="post">
username: <input type="text" class="form-control" name="newUsername" />
oauth: <input type="text" class="form-control" name="newOauth" />
<button class="btn btn-secondary" type="button" onclick="addTwitch.close()">cancel</button>
<button class="btn btn-success" type="submit">save</button>
</form>
</dialog>
<dialog id="removeTwitchDialog">
<form action="@Url.Action("RemoveTwitch", "Configuration")" method="post">
Are you sure?
<input type="hidden" name="id" id="removeTwitchTarget" />
<button class="btn btn-secondary" type="button" onclick="removeTwitchDialog.close()">cancel</button>
<button class="btn btn-danger" type="submit">delete</button>
</form>
</dialog>
<dialog id="addWebhookDialog">
<form action="@Url.Action("AddWebhook", "Configuration")" method="post">
trigger
<input type="text" class="form-control" name="Trigger" />
Uri
<input type="text" class="form-control" name="Uri" />
Method
<input type="text" class="form-control" name="Method" />
Headers
<input type="textarea" class="form-control" id="newWebhookHeaders" />
<input type="hidden" name="Headers" />
Content
<input type="text" class="form-control" name="Content" />
Description
<input type="text" class="form-control" name="Description" />
<button class="btn btn-secondary" type="button" onclick="addWebhookDialog.close()">cancel</button>
<button class="btn btn-success" type="button" onclick="addWebhookComplexSubmit()">save</button>
</form>
</dialog>
<dialog id="removeWebhookDialog">
<form action="@Url.Action("RemoveWebhook", "Configuration")" method="post">
Are you sure?
<input type="hidden" name="id" id="removeWebhookTarget" />
<button class="btn btn-secondary" type="button" onclick="removeWebhookDialog.close()">cancel</button>
<button class="btn btn-danger" type="submit">delete</button>
</form>
</dialog>
@section scripts{
<script type="text/javascript">
function removeDiscord(idx){
removeDiscordTarget.Value = idx;
console.log("removeDiscordTarget is now " + idx);
removeDiscordDialog.showModal();
}
function removeTwitch(idx){
removeTwitchTarget.value = idx;
removeTwitchDialog.showModal();
}
function removeWebhook(idx){
removeWebhookTarget.value = idx;
removeWebhookDialog.showModal();
}
function complexSubmit()
{
for (let i = 0; true; i++)
{
let thisCell = document.querySelector("td>#TwitchConfigs_" + i);
if(thisCell !== null)
{
let usernameElem = thisCell.nextElementSibling;
let oauthElem = usernameElem.nextElementSibling;
let asObj = {username: usernameElem.value, oauth: oauthElem.value};
thisCell.value = JSON.stringify(asObj);
}
else
{
break;
}
}
for (let i = 0; true; i++)
{
let thisCell = document.querySelector("td>#Webhooks_" + i);
if(thisCell !== null)
{
let nextCell = thisCell;
let asObj = {};
while(true){
nextCell = nextCell.nextElementSibling;
if(nextCell == null)
break;
if(!nextCell.hasAttribute("data-name"))
continue;
let dataname = nextCell.attributes["data-name"].value;
if(nextCell.value != "")
{
if(dataname == "Headers")
{
asObj["Headers"] = [];
let headerArray = nextCell.value.split('\n');
headerArray.forEach((elem) => {
if(elem.indexOf(":") > -1)
{
asObj["Headers"].push(elem.split(":"));
}
});
}
else
{
asObj[dataname] = nextCell.value;
}
}
}
thisCell.value = JSON.stringify(asObj);
}
else
{
break;
}
}
theForm.submit();
}
function addWebhookComplexSubmit()
{
let headersInput = document.querySelector("#newWebhookHeaders");
if(headersInput.value != "")
{
if(headersInput.value.indexOf("\n") == -1)
{
headersInput.value += "\n";
}
let headers = headersInput.value.split("\n");
let i = 0;
headers.forEach((headerInputLine) => {
console.log(headerInputLine);
if(headerInputLine.indexOf(":") > -1)
{
var newElem = document.createElement("input");
newElem.setAttribute("type", "hidden");
newElem.setAttribute("name", "Headers[" + i + "]");
newElem.value = JSON.stringify(headerInputLine.split(":"));
headersInput.parentElement.appendChild(newElem);
console.log(newElem.value);
i++;
}
});
}
document.querySelector("#addWebhookDialog form").submit();
}
</script>
}

View File

@ -18,7 +18,7 @@
"Webhooks": [ "Webhooks": [
{ {
"uacID": "9a94855a-e5a2-43b5-8420-ce670472ce95", "uacID": "9a94855a-e5a2-43b5-8420-ce670472ce95",
"Trigger": "!test", "Trigger": "test",
"Description": "<i>test</i>", "Description": "<i>test</i>",
"Uri": "http://localhost", "Uri": "http://localhost",
"Method": "POST", "Method": "POST",

View File

@ -19,14 +19,6 @@ case "$1" in
dotnet ef migrations add "$2" dotnet ef migrations add "$2"
dotnet ef database update --connection "$connnectionstr" dotnet ef database update --connection "$connnectionstr"
;; ;;
"remove-migration")
echo "ef migrations will tell you you can use dotnet ef migrations remove."
echo ""
echo "LIES."
echo ""
echo "it doesn't have a way to specify the connection string. can't be done."
echo "edit the db the hard way."
;;
"dbupdate") "dbupdate")
dotnet ef database update --connection "$connnectionstr" dotnet ef database update --connection "$connnectionstr"