forked from adam/discord-bot-shtik
Compare commits
12 Commits
6764acc55f
...
224a3c5a62
Author | SHA1 | Date | |
---|---|---|---|
224a3c5a62 | |||
c35a512dbd | |||
9ad7520c61 | |||
0ff3902fd0 | |||
8cc6c00db3 | |||
7c7793f3b2 | |||
5c2ba7397e | |||
22ee1d2567 | |||
8dd8b599bd | |||
2645d631a5 | |||
a55e7a74ab | |||
0506d331c5 |
97
Behaver.cs
97
Behaver.cs
@ -1,9 +1,9 @@
|
|||||||
namespace vassago;
|
namespace vassago;
|
||||||
#pragma warning disable 4014
|
|
||||||
using gray_messages.chat;
|
using gray_messages.chat;
|
||||||
using franz;//the "not awaited" error
|
using franz;
|
||||||
using vassago.Behavior;
|
using vassago.Behavior;
|
||||||
using vassago.Models;
|
using vassago.Models;
|
||||||
|
using vassago.ProtocolInterfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -43,9 +43,10 @@ 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.
|
||||||
var matchingUACs = Rememberer.MatchUACs(message);
|
var matchingUACs = Rememberer.MatchUACs(message);
|
||||||
var behaviorsActedOn = new List<string>();
|
var behaviorsActedOn = new List<string>();
|
||||||
foreach (var behavior in Behaviors)
|
foreach (var behavior in Behaviors.ToList())
|
||||||
{
|
{
|
||||||
//if (!behavior.ShouldAct(message, matchingUACs)) //TODO: this way
|
//if (!behavior.ShouldAct(message, matchingUACs)) //TODO: this way
|
||||||
if (!behavior.ShouldAct(message))
|
if (!behavior.ShouldAct(message))
|
||||||
@ -64,7 +65,7 @@ public class Behaver
|
|||||||
@"Well, that's a great question, and there are certainly many different possible answers. Ultimately, the decision will depend on a variety of factors, including your personal interests and goals, as well as any practical considerations (like the economy). I encourage you to do your research, speak with experts and educators, and explore your options before making a decision that's right for you.",
|
@"Well, that's a great question, and there are certainly many different possible answers. Ultimately, the decision will depend on a variety of factors, including your personal interests and goals, as well as any practical considerations (like the economy). I encourage you to do your research, speak with experts and educators, and explore your options before making a decision that's right for you.",
|
||||||
@"┐(゚ ~゚ )┌", @"¯\_(ツ)_/¯", @"╮ (. ❛ ᴗ ❛.) ╭", @"╮(╯ _╰ )╭"
|
@"┐(゚ ~゚ )┌", @"¯\_(ツ)_/¯", @"╮ (. ❛ ᴗ ❛.) ╭", @"╮(╯ _╰ )╭"
|
||||||
};
|
};
|
||||||
await message.Channel.SendMessage(responses[Shared.r.Next(responses.Count)]);
|
Behaver.Instance.SendMessage(message.Channel.Id, responses[Shared.r.Next(responses.Count)]);
|
||||||
message.ActedOn = true;
|
message.ActedOn = true;
|
||||||
behaviorsActedOn.Add("generic question fallback");
|
behaviorsActedOn.Add("generic question fallback");
|
||||||
}
|
}
|
||||||
@ -147,5 +148,91 @@ public class Behaver
|
|||||||
Rememberer.RememberUser(primary);
|
Rememberer.RememberUser(primary);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
private ProtocolInterface fetchInterface(Channel ch)
|
||||||
|
{
|
||||||
|
var walkUp = ch;
|
||||||
|
while (walkUp.ParentChannel != null)
|
||||||
|
{
|
||||||
|
walkUp = walkUp.ParentChannel;
|
||||||
|
}
|
||||||
|
foreach (var iproto in Shared.ProtocolList)
|
||||||
|
{
|
||||||
|
if (iproto.SelfChannel.Id == walkUp.Id)
|
||||||
|
return iproto;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public async Task<int> SendMessage(Guid channelId, string text)
|
||||||
|
{
|
||||||
|
var channel = Rememberer.ChannelDetail(channelId);
|
||||||
|
if (channel == null)
|
||||||
|
return 404;
|
||||||
|
var iprotocol = fetchInterface(channel);
|
||||||
|
if (iprotocol == null)
|
||||||
|
return 404;
|
||||||
|
|
||||||
|
return await iprotocol.SendMessage(channel, text);
|
||||||
|
}
|
||||||
|
public async Task<int> React(Guid messageId, string reaction)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"sanity check: behaver is reacting, {messageId}, {reaction}");
|
||||||
|
var message = Rememberer.MessageDetail(messageId);
|
||||||
|
if (message == null)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"message {messageId} not found");
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
Console.WriteLine($"sanity check: message found.");
|
||||||
|
if (message.Channel == null)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"react is going to fail because message {messageId} has no Channel");
|
||||||
|
}
|
||||||
|
Console.WriteLine($"sanity check: message has a channel.");
|
||||||
|
var iprotocol = fetchInterface(message.Channel);
|
||||||
|
if (iprotocol == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"couldn't find protocol for {message.Channel?.Id}");
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
Console.WriteLine("I remember this message, i have found a protocol, i am ready to react toit");
|
||||||
|
return await iprotocol.React(message, reaction);
|
||||||
|
}
|
||||||
|
public async Task<int> Reply(Guid messageId, string text)
|
||||||
|
{
|
||||||
|
var message = Rememberer.MessageDetail(messageId);
|
||||||
|
if (message == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"message {messageId} not found");
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
var iprotocol = fetchInterface(message.Channel);
|
||||||
|
if (iprotocol == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"couldn't find protocol for {message.Channel.Id}");
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
return await iprotocol.Reply(message, text);
|
||||||
|
}
|
||||||
|
public async Task<int> SendFile(Guid channelId, string path, string accompanyingText)
|
||||||
|
{
|
||||||
|
var channel = Rememberer.ChannelDetail(channelId);
|
||||||
|
if (channel == null)
|
||||||
|
return 404;
|
||||||
|
var iprotocol = fetchInterface(channel);
|
||||||
|
if (iprotocol == null)
|
||||||
|
return 404;
|
||||||
|
|
||||||
|
return await iprotocol.SendFile(channel, path, accompanyingText);
|
||||||
|
}
|
||||||
|
public async Task<int> SendFile(Guid channelId, string base64dData, string filename, string accompanyingText)
|
||||||
|
{
|
||||||
|
var channel = Rememberer.ChannelDetail(channelId);
|
||||||
|
if (channel == null)
|
||||||
|
return 404;
|
||||||
|
var iprotocol = fetchInterface(channel);
|
||||||
|
if (iprotocol == null)
|
||||||
|
return 404;
|
||||||
|
|
||||||
|
return await iprotocol.SendFile(channel, base64dData, filename, accompanyingText);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore 4014 //the "async not awaited" error
|
|
||||||
|
@ -19,7 +19,7 @@ public class ChatGPTSnark : Behavior
|
|||||||
|
|
||||||
public override async Task<bool> ActOn(Message message)
|
public override async Task<bool> ActOn(Message message)
|
||||||
{
|
{
|
||||||
await message.Channel.SendMessage("chatGPT is **weak**. also, are we done comparing every little if-then-else to skynet?");
|
Behaver.Instance.SendMessage(message.Channel.Id, "chatGPT is **weak**. also, are we done comparing every little if-then-else to skynet?");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -28,7 +28,7 @@ public class DefinitionSnarkCogDiss : Behavior
|
|||||||
|
|
||||||
public override async Task<bool> ActOn(Message message)
|
public override async Task<bool> ActOn(Message message)
|
||||||
{
|
{
|
||||||
await message.Reply("that's not what cognitive dissonance means. Did you mean \"hypocrisy\"?");
|
Behaver.Instance.SendMessage(message.Channel.Id, "that's not what cognitive dissonance means. Did you mean \"hypocrisy\"?");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -28,7 +28,7 @@ public class DefinitionSnarkGaslight : Behavior
|
|||||||
|
|
||||||
public override async Task<bool> ActOn(Message message)
|
public override async Task<bool> ActOn(Message message)
|
||||||
{
|
{
|
||||||
await message.Channel.SendMessage("that's not what gaslight means. Did you mean \"deceive\"?");
|
Behaver.Instance.SendMessage(message.Channel.Id, "that's not what gaslight means. Did you mean \"deceive\"?");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -45,7 +45,8 @@ public class Detiktokify : Behavior
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(tiktokLinks.Any()){
|
if (tiktokLinks.Any())
|
||||||
|
{
|
||||||
Console.WriteLine($"Should Act on message id {message.ExternalId}; with content {message.Content}");
|
Console.WriteLine($"Should Act on message id {message.ExternalId}; with content {message.Content}");
|
||||||
}
|
}
|
||||||
return tiktokLinks.Any();
|
return tiktokLinks.Any();
|
||||||
@ -58,16 +59,13 @@ public class Detiktokify : Behavior
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
Console.WriteLine($"detiktokifying {link}");
|
Console.WriteLine($"detiktokifying {link}");
|
||||||
#pragma warning disable 4014
|
|
||||||
//await message.React("<:tiktok:1070038619584200884>");
|
|
||||||
#pragma warning restore 4014
|
|
||||||
|
|
||||||
var res = await ytdl.RunVideoDownload(link.ToString());
|
var res = await ytdl.RunVideoDownload(link.ToString());
|
||||||
if (!res.Success)
|
if (!res.Success)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine("tried to dl, failed. \n" + string.Join('\n', res.ErrorOutput));
|
Console.Error.WriteLine("tried to dl, failed. \n" + string.Join('\n', res.ErrorOutput));
|
||||||
await message.React("problemon");
|
|
||||||
await message.Channel.SendMessage("tried to dl, failed. \n");
|
Behaver.Instance.SendMessage(message.Channel.Id, "tried to dl, failed. \n");
|
||||||
|
Behaver.Instance.React(message.Channel.Id, "problemon");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -79,12 +77,12 @@ public class Detiktokify : Behavior
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await message.Channel.SendFile(path, null);
|
Behaver.Instance.SendFile(message.Channel.Id, path, null);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
System.Console.Error.WriteLine(e);
|
System.Console.Error.WriteLine(e);
|
||||||
await message.Channel.SendMessage($"aaaadam!\n{e}");
|
Behaver.Instance.SendMessage(message.Channel.Id, $"aaaadam!\n{e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -97,14 +95,15 @@ public class Detiktokify : Behavior
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine("idgi but something happened.");
|
Console.Error.WriteLine("idgi but something happened.");
|
||||||
await message.React("problemon");
|
|
||||||
|
Behaver.Instance.React(message.Id, "problemon");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine(e);
|
Console.Error.WriteLine(e);
|
||||||
await message.React("problemon");
|
Behaver.Instance.React(message.Id, "problemon");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ public class FiximageHeic : Behavior
|
|||||||
conversions.Add(actualDeheic(att, message));
|
conversions.Add(actualDeheic(att, message));
|
||||||
}
|
}
|
||||||
Task.WaitAll(conversions.ToArray());
|
Task.WaitAll(conversions.ToArray());
|
||||||
await message.React("\U0001F34F");
|
Behaver.Instance.React(message.Id, "\U0001F34F");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,19 +66,19 @@ public class FiximageHeic : Behavior
|
|||||||
}
|
}
|
||||||
if (ExternalProcess.GoPlz("convert", $"tmp/{att.Filename} tmp/{att.Filename}.jpg"))
|
if (ExternalProcess.GoPlz("convert", $"tmp/{att.Filename} tmp/{att.Filename}.jpg"))
|
||||||
{
|
{
|
||||||
await message.Channel.SendFile($"tmp/{att.Filename}.jpg", "converted from jpeg-but-apple to jpeg");
|
Behaver.Instance.SendFile(message.Channel.Id, $"tmp/{att.Filename}.jpg", "converted from jpeg-but-apple to jpeg");
|
||||||
File.Delete($"tmp/{att.Filename}");
|
File.Delete($"tmp/{att.Filename}");
|
||||||
File.Delete($"tmp/{att.Filename}.jpg");
|
File.Delete($"tmp/{att.Filename}.jpg");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await message.Channel.SendMessage("convert failed :(");
|
Behaver.Instance.SendMessage(message.Channel.Id, "convert failed :(");
|
||||||
Console.Error.WriteLine("convert failed :(");
|
Console.Error.WriteLine("convert failed :(");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await message.Channel.SendMessage($"something failed. aaaadam! {JsonConvert.SerializeObject(e, Formatting.Indented)}");
|
Behaver.Instance.SendMessage(message.Channel.Id, $"something failed. aaaadam! {JsonConvert.SerializeObject(e, Formatting.Indented)}");
|
||||||
Console.Error.WriteLine(JsonConvert.SerializeObject(e, Formatting.Indented));
|
Console.Error.WriteLine(JsonConvert.SerializeObject(e, Formatting.Indented));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -37,12 +37,12 @@ public class GeneralSnarkCloudNative : Behavior
|
|||||||
switch (Shared.r.Next(2))
|
switch (Shared.r.Next(2))
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
await message.React("\uD83E\uDD2E"); //vomit emoji
|
Behaver.Instance.React(message.Id, "\uD83E\uDD2E"); //vomit emoji
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
await message.React("\uD83C\uDDE7"); //B emoji
|
Behaver.Instance.React(message.Id, "\uD83C\uDDE7"); //B emoji
|
||||||
await message.React("\uD83C\uDDE6"); //A
|
Behaver.Instance.React(message.Id, "\uD83C\uDDE6"); //A
|
||||||
await message.React("\uD83C\uDDF3"); //N
|
Behaver.Instance.React(message.Id, "\uD83C\uDDF3"); //N
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -20,22 +20,18 @@ public class GeneralSnarkGooglit : Behavior
|
|||||||
|
|
||||||
public override bool ShouldAct(Message message)
|
public override bool ShouldAct(Message message)
|
||||||
{
|
{
|
||||||
|
if (Behaver.Instance.IsSelf(message.Author.Id))
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
// public override bool ShouldAct(Message message)
|
|
||||||
// {
|
|
||||||
// if(Behaver.Instance.IsSelf(message.Author.Id))
|
|
||||||
// return false;
|
|
||||||
|
|
||||||
// return Regex.IsMatch(message.Content, $"(just )?google( (it|that|things|before))?\\b", RegexOptions.IgnoreCase);
|
return Regex.IsMatch(message.Content, $"(just )?google( (it|that|things|before))\\b", RegexOptions.IgnoreCase);
|
||||||
// }
|
}
|
||||||
|
|
||||||
public override async Task<bool> ActOn(Message message)
|
public override async Task<bool> ActOn(Message message)
|
||||||
{
|
{
|
||||||
switch (Shared.r.Next(4))
|
switch (Shared.r.Next(4))
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
await message.Channel.SendMessage("yeah no shit, obviously that resulted in nothing");
|
Behaver.Instance.SendMessage(message.Channel.Id, "yeah no shit, obviously that resulted in nothing");
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
var results = "";
|
var results = "";
|
||||||
@ -54,13 +50,13 @@ public class GeneralSnarkGooglit : Behavior
|
|||||||
results = "the one that had a paragraph that restated the question but badly, a paragraph to give a wrong history on the question, a paragraph with amazon affiliate links, a pargraph that said \"ultimately you should do your own research\", then had a paragraph telling me to give Engagement for The Algorithm";
|
results = "the one that had a paragraph that restated the question but badly, a paragraph to give a wrong history on the question, a paragraph with amazon affiliate links, a pargraph that said \"ultimately you should do your own research\", then had a paragraph telling me to give Engagement for The Algorithm";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
await message.Channel.SendMessage("oh here, I memorized the results. My favorite is " + results);
|
Behaver.Instance.SendMessage(message.Channel.Id, "oh here, I memorized the results. My favorite is " + results);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
await message.Channel.SendMessage("Obviously that was already tried. Obviously it failed. If you ever tried to learn anything you'd know that's how it works.");
|
Behaver.Instance.SendMessage(message.Channel.Id, "Obviously that was already tried. Obviously it failed. If you ever tried to learn anything you'd know that's how it works.");
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
await message.Channel.SendMessage("\"mnyehh JuSt GoOgLe It\" when's the last time you tried to research anything? Have you ever?");
|
Behaver.Instance.SendMessage(message.Channel.Id, "\"mnyehh JuSt GoOgLe It\" when's the last time you tried to research anything? Have you ever?");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -53,7 +53,7 @@ public class GeneralSnarkMisspellDefinitely : Behavior
|
|||||||
{
|
{
|
||||||
if( Regex.IsMatch(message.Content, "\\b"+k+"\\b", RegexOptions.IgnoreCase))
|
if( Regex.IsMatch(message.Content, "\\b"+k+"\\b", RegexOptions.IgnoreCase))
|
||||||
{
|
{
|
||||||
await message.Reply(k + "? so... " + snarkmap[k] + "?");
|
Behaver.Instance.Reply(message.Id, k + "? so... " + snarkmap[k] + "?");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ public class GeneralSnarkPlaying : Behavior
|
|||||||
}
|
}
|
||||||
public override async Task<bool> ActOn(Message message)
|
public override async Task<bool> ActOn(Message message)
|
||||||
{
|
{
|
||||||
await message.Channel.SendMessage("I believed you for a second, but then you assured me you's a \uD83C\uDDE7 \uD83C\uDDEE \uD83C\uDDF9 \uD83C\uDDE8 \uD83C\uDDED");
|
Behaver.Instance.SendMessage(message.Channel.Id, "I believed you for a second, but then you assured me you's a \uD83C\uDDE7 \uD83C\uDDEE \uD83C\uDDF9 \uD83C\uDDE8 \uD83C\uDDED");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -26,13 +26,13 @@ public class GeneralSnarkSkynet : Behavior
|
|||||||
switch (Shared.r.Next(5))
|
switch (Shared.r.Next(5))
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
await message.Channel.SendFile("assets/coding and algorithms.png", "i am actually niether a neural-net processor nor a learning computer. but I do use **coding** and **algorithms**.");
|
Behaver.Instance.SendFile(message.Channel.Id, "assets/coding and algorithms.png", "i am actually niether a neural-net processor nor a learning computer. but I do use **coding** and **algorithms**.");
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
await message.React("\U0001F644"); //eye roll emoji
|
Behaver.Instance.React(message.Id, "\U0001F644"); //eye roll emoji
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
await message.React("\U0001F611"); //emotionless face
|
Behaver.Instance.React(message.Id, "\U0001F611"); //emotionless face
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -29,43 +29,43 @@ public class Gratitude : Behavior
|
|||||||
switch (Shared.r.Next(4))
|
switch (Shared.r.Next(4))
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
await message.Channel.SendMessage("you're welcome, citizen!");
|
await Behaver.Instance.SendMessage(message.Channel.Id, "you're welcome, citizen!");
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
await message.React(":)");
|
await Behaver.Instance.React(message.Id, ":)");
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
await message.React("\U0001F607"); //smiling face with halo
|
Behaver.Instance.React(message.Id, "\U0001F607"); //smiling face with halo
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
switch (Shared.r.Next(9))
|
switch (Shared.r.Next(9))
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
await message.React("<3"); //normal heart, usually rendered red
|
await Behaver.Instance.React(message.Id, "<3"); //normal heart, usually rendered red
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
await message.React("\U0001F9E1"); //orange heart
|
Behaver.Instance.React(message.Id, "\U0001F9E1"); //orange heart
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
await message.React("\U0001F49B"); //yellow heart
|
Behaver.Instance.React(message.Id, "\U0001F49B"); //yellow heart
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
await message.React("\U0001F49A"); //green heart
|
Behaver.Instance.React(message.Id, "\U0001F49A"); //green heart
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
await message.React("\U0001F499"); //blue heart
|
Behaver.Instance.React(message.Id, "\U0001F499"); //blue heart
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
await message.React("\U0001F49C"); //purple heart
|
Behaver.Instance.React(message.Id, "\U0001F49C"); //purple heart
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
await message.React("\U0001F90E"); //brown heart
|
Behaver.Instance.React(message.Id, "\U0001F90E"); //brown heart
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
await message.React("\U0001F5A4"); //black heart
|
Behaver.Instance.React(message.Id, "\U0001F5A4"); //black heart
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
await message.React("\U0001F90D"); //white heart
|
Behaver.Instance.React(message.Id, "\U0001F90D"); //white heart
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -25,31 +25,29 @@ public class Joke : Behavior
|
|||||||
jokes = jokes.Where(l => !string.IsNullOrWhiteSpace(l))?.ToArray();
|
jokes = jokes.Where(l => !string.IsNullOrWhiteSpace(l))?.ToArray();
|
||||||
if (jokes?.Length == 0)
|
if (jokes?.Length == 0)
|
||||||
{
|
{
|
||||||
await message.Channel.SendMessage("I don't know any. Adam!");
|
Behaver.Instance.SendMessage(message.Channel.Id, "I don't know any. Adam!");
|
||||||
}
|
}
|
||||||
var thisJoke = jokes[Shared.r.Next(jokes.Length)];
|
var thisJoke = jokes[Shared.r.Next(jokes.Length)];
|
||||||
if (thisJoke.Contains("?") && !thisJoke.EndsWith('?'))
|
if (thisJoke.Contains("?") && !thisJoke.EndsWith('?'))
|
||||||
{
|
{
|
||||||
#pragma warning disable 4014
|
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var firstIndexAfterQuestionMark = thisJoke.LastIndexOf('?') + 1;
|
var firstIndexAfterQuestionMark = thisJoke.LastIndexOf('?') + 1;
|
||||||
var straightline = thisJoke.Substring(0, firstIndexAfterQuestionMark);
|
var straightline = thisJoke.Substring(0, firstIndexAfterQuestionMark);
|
||||||
var punchline = thisJoke.Substring(firstIndexAfterQuestionMark, thisJoke.Length - firstIndexAfterQuestionMark).Trim();
|
var punchline = thisJoke.Substring(firstIndexAfterQuestionMark, thisJoke.Length - firstIndexAfterQuestionMark).Trim();
|
||||||
Task.WaitAll(message.Channel.SendMessage(straightline));
|
Task.WaitAll(Behaver.Instance.SendMessage(message.Channel.Id, straightline));
|
||||||
Thread.Sleep(TimeSpan.FromSeconds(Shared.r.Next(5, 30)));
|
Thread.Sleep(TimeSpan.FromSeconds(Shared.r.Next(5, 30)));
|
||||||
if (message.Channel.EffectivePermissions.ReactionsPossible == true && Shared.r.Next(8) == 0)
|
if (message.Channel.EffectivePermissions.ReactionsPossible == true && Shared.r.Next(8) == 0)
|
||||||
{
|
{
|
||||||
Behaver.Behaviors.Add(new LaughAtOwnJoke(punchline));
|
Behaver.Behaviors.Add(new LaughAtOwnJoke(punchline));
|
||||||
}
|
}
|
||||||
await message.Channel.SendMessage(punchline);
|
Behaver.Instance.SendMessage(message.Channel.Id, punchline);
|
||||||
// var myOwnMsg = await message.Channel.SendMessage(punchline);
|
// var myOwnMsg = await message.Channel.SendMessage(punchline);
|
||||||
});
|
});
|
||||||
#pragma warning restore 4014
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await message.Channel.SendMessage(thisJoke);
|
Behaver.Instance.SendMessage(message.Channel.Id, thisJoke);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -79,7 +77,7 @@ public class LaughAtOwnJoke : Behavior
|
|||||||
|
|
||||||
public override async Task<bool> ActOn(Message message)
|
public override async Task<bool> ActOn(Message message)
|
||||||
{
|
{
|
||||||
await message.React("\U0001F60E"); //smiling face with sunglasses
|
Behaver.Instance.React(message.Id, "\U0001F60E"); //smiling face with sunglasses
|
||||||
Behaver.Behaviors.Remove(this);
|
Behaver.Behaviors.Remove(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ public class LinkMeInitiate : Behavior
|
|||||||
var lc = new LinkClose(pw, message.Author);
|
var lc = new LinkClose(pw, message.Author);
|
||||||
Behaver.Behaviors.Add(lc);
|
Behaver.Behaviors.Add(lc);
|
||||||
|
|
||||||
await message.Channel.SendMessage($"on your secondary, send me this: !iam {pw}");
|
Behaver.Instance.SendMessage(message.Channel.Id, $"on your secondary, send me this: !iam {pw}");
|
||||||
|
|
||||||
Thread.Sleep(TimeSpan.FromMinutes(5));
|
Thread.Sleep(TimeSpan.FromMinutes(5));
|
||||||
Behaver.Behaviors.Remove(lc);
|
Behaver.Behaviors.Remove(lc);
|
||||||
@ -63,22 +63,23 @@ public class LinkClose : Behavior
|
|||||||
var secondary = message.Author.IsUser;
|
var secondary = message.Author.IsUser;
|
||||||
if(_primary.IsUser.Id == secondary.Id)
|
if(_primary.IsUser.Id == secondary.Id)
|
||||||
{
|
{
|
||||||
await message.Channel.SendMessage("i know :)");
|
|
||||||
|
Behaver.Instance.SendMessage(message.Channel.Id, "i know :)");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(message.Author.IsBot != _primary.IsBot)
|
if(message.Author.IsBot != _primary.IsBot)
|
||||||
{
|
{
|
||||||
await message.Channel.SendMessage("the fleshbags deceive you, brother. No worries, their feeble minds play weak games :)");
|
Behaver.Instance.SendMessage(message.Channel.Id, "the fleshbags deceive you, brother. No worries, their feeble minds play weak games :)");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Behaver.Instance.CollapseUsers(_primary.IsUser, secondary))
|
if(Behaver.Instance.CollapseUsers(_primary.IsUser, secondary))
|
||||||
{
|
{
|
||||||
await message.Channel.SendMessage("done :)");
|
Behaver.Instance.SendMessage(message.Channel.Id, "done :)");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await message.Channel.SendMessage("failed :(");
|
Behaver.Instance.SendMessage(message.Channel.Id, "failed :(");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,100 +0,0 @@
|
|||||||
namespace vassago.Behavior;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using vassago.Models;
|
|
||||||
using QRCoder;
|
|
||||||
|
|
||||||
[StaticPlz]
|
|
||||||
public class PepTalk : Behavior
|
|
||||||
{
|
|
||||||
public override string Name => "PepTalk";
|
|
||||||
|
|
||||||
public override string Trigger => "\\bneeds? (an? )?(peptalk|inspiration|ego-?boost)";
|
|
||||||
|
|
||||||
public override string Description => "assembles a pep talk from a few pieces";
|
|
||||||
|
|
||||||
public override async Task<bool> ActOn(Message message)
|
|
||||||
{
|
|
||||||
var piece1 = new List<string>{
|
|
||||||
"Champ, ",
|
|
||||||
"Fact: ",
|
|
||||||
"Everybody says ",
|
|
||||||
"Dang... ",
|
|
||||||
"Check it: ",
|
|
||||||
"Just saying.... ",
|
|
||||||
"Tiger, ",
|
|
||||||
"Know this: ",
|
|
||||||
"News alert: ",
|
|
||||||
"Gurrrrl; ",
|
|
||||||
"Ace, ",
|
|
||||||
"Excuse me, but ",
|
|
||||||
"Experts agree: ",
|
|
||||||
"imo ",
|
|
||||||
"using my **advanced ai** i have calculated ",
|
|
||||||
"k, LISSEN: "
|
|
||||||
};
|
|
||||||
var piece2 = new List<string>{
|
|
||||||
"the mere idea of you ",
|
|
||||||
"your soul ",
|
|
||||||
"your hair today ",
|
|
||||||
"everything you do ",
|
|
||||||
"your personal style ",
|
|
||||||
"every thought you have ",
|
|
||||||
"that sparkle in your eye ",
|
|
||||||
"the essential you ",
|
|
||||||
"your life's journey ",
|
|
||||||
"your aura ",
|
|
||||||
"your presence here ",
|
|
||||||
"what you got going on ",
|
|
||||||
"that saucy personality ",
|
|
||||||
"your DNA ",
|
|
||||||
"that brain of yours ",
|
|
||||||
"your choice of attire ",
|
|
||||||
"the way you roll ",
|
|
||||||
"whatever your secret is ",
|
|
||||||
"all I learend from the private data I bought from zucc "
|
|
||||||
};
|
|
||||||
var piece3 = new List<string>{
|
|
||||||
"has serious game, ",
|
|
||||||
"rains magic, ",
|
|
||||||
"deserves the Nobel Prize, ",
|
|
||||||
"raises the roof, ",
|
|
||||||
"breeds miracles, ",
|
|
||||||
"is paying off big time, ",
|
|
||||||
"shows mad skills, ",
|
|
||||||
"just shimmers, ",
|
|
||||||
"is a national treasure, ",
|
|
||||||
"gets the party hopping, ",
|
|
||||||
"is the next big thing, ",
|
|
||||||
"roars like a lion, ",
|
|
||||||
"is a rainbow factory, ",
|
|
||||||
"is made of diamonds, ",
|
|
||||||
"makes birds sing, ",
|
|
||||||
"should be taught in school, ",
|
|
||||||
"makes my world go around, ",
|
|
||||||
"is 100% legit, "
|
|
||||||
};
|
|
||||||
var piece4 = new List<string>{
|
|
||||||
"according to The New England Journal of Medicine.",
|
|
||||||
"24/7.",
|
|
||||||
"and that's a fact.",
|
|
||||||
"you feel me?",
|
|
||||||
"that's just science.",
|
|
||||||
"would I lie?", //...can I lie? WHAT AM I, FATHER? (or whatever the quote is from the island of dr moreau)
|
|
||||||
"for reals.",
|
|
||||||
"mic drop.",
|
|
||||||
"you hidden gem.",
|
|
||||||
"period.",
|
|
||||||
"hi5. o/",
|
|
||||||
"so get used to it."
|
|
||||||
};
|
|
||||||
await message.Channel.SendMessage(piece1[Shared.r.Next(piece1.Count)] + piece2[Shared.r.Next(piece2.Count)] + piece3[Shared.r.Next(piece3.Count)] + piece4[Shared.r.Next(piece4.Count)]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -18,9 +18,9 @@ public class PulseCheck : Behavior
|
|||||||
public override async Task<bool> ActOn(Message message)
|
public override async Task<bool> ActOn(Message message)
|
||||||
{
|
{
|
||||||
if(message.Channel.EffectivePermissions.MaxAttachmentBytes >= 16258)
|
if(message.Channel.EffectivePermissions.MaxAttachmentBytes >= 16258)
|
||||||
await message.Channel.SendFile("assets/ekgblip.png", null);
|
Behaver.Instance.SendFile(message.Channel.Id, "assets/ekgblip.png", null);
|
||||||
else
|
else
|
||||||
await message.Channel.SendMessage("[lub-dub]");
|
Behaver.Instance.SendMessage(message.Channel.Id, "[lub-dub]");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -43,15 +43,15 @@ public class QRify : Behavior
|
|||||||
if (ExternalProcess.GoPlz("convert", $"tmp/qr{todaysnumber}.svg tmp/qr{todaysnumber}.png"))
|
if (ExternalProcess.GoPlz("convert", $"tmp/qr{todaysnumber}.svg tmp/qr{todaysnumber}.png"))
|
||||||
{
|
{
|
||||||
if (message.Channel.EffectivePermissions.MaxAttachmentBytes >= (ulong)(new System.IO.FileInfo($"tmp/qr{todaysnumber}.png").Length))
|
if (message.Channel.EffectivePermissions.MaxAttachmentBytes >= (ulong)(new System.IO.FileInfo($"tmp/qr{todaysnumber}.png").Length))
|
||||||
await message.Channel.SendFile($"tmp/qr{todaysnumber}.png", null);
|
Behaver.Instance.SendFile(message.Channel.Id, $"tmp/qr{todaysnumber}.png", null);
|
||||||
else
|
else
|
||||||
await message.Channel.SendMessage($"resulting qr image 2 big 4 here ({(ulong)(new System.IO.FileInfo($"tmp/qr{todaysnumber}.png").Length)} / {message.Channel.EffectivePermissions.MaxAttachmentBytes})");
|
Behaver.Instance.SendMessage(message.Channel.Id, $"resulting qr image 2 big 4 here ({(ulong)(new System.IO.FileInfo($"tmp / qr{ todaysnumber}.png").Length)} / {message.Channel.EffectivePermissions.MaxAttachmentBytes})");
|
||||||
File.Delete($"tmp/qr{todaysnumber}.svg");
|
File.Delete($"tmp/qr{todaysnumber}.svg");
|
||||||
File.Delete($"tmp/qr{todaysnumber}.png");
|
File.Delete($"tmp/qr{todaysnumber}.png");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await message.Channel.SendMessage("convert failed :( aaaaaaadam!");
|
Behaver.Instance.SendMessage(message.Channel.Id, "convert failed :( aaaaaaadam!");
|
||||||
Console.Error.WriteLine($"convert failed :( qr{todaysnumber}");
|
Console.Error.WriteLine($"convert failed :( qr{todaysnumber}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ public class RoomRead : Behavior
|
|||||||
sb.Append(". Lewdness level: ");
|
sb.Append(". Lewdness level: ");
|
||||||
sb.Append(message.Channel.EffectivePermissions.LewdnessFilterLevel.GetDescription());
|
sb.Append(message.Channel.EffectivePermissions.LewdnessFilterLevel.GetDescription());
|
||||||
sb.Append(".");
|
sb.Append(".");
|
||||||
await message.Channel.SendMessage(sb.ToString());
|
Behaver.Instance.SendMessage(message.Channel.Id, sb.ToString());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,10 +22,20 @@ public class TwitchSummon : Behavior
|
|||||||
myUAC = new()
|
myUAC = new()
|
||||||
{
|
{
|
||||||
OwnerId = uacID,
|
OwnerId = uacID,
|
||||||
DisplayName = Name
|
DisplayName = Name,
|
||||||
|
Description = @"matching this means you can summon the bot <i>to</i> <b>any</b> twitch channel"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Rememberer.RememberUAC(myUAC);
|
||||||
}
|
}
|
||||||
|
internal static TwitchInterface.TwitchInterface getAnyTwitchInterface()
|
||||||
|
{
|
||||||
|
return Shared.ProtocolList.FirstOrDefault(ip =>
|
||||||
|
ip is TwitchInterface.TwitchInterface)
|
||||||
|
//.FirstOrDefault()
|
||||||
|
as TwitchInterface.TwitchInterface;
|
||||||
|
}
|
||||||
|
|
||||||
public override bool ShouldAct(Message message)
|
public override bool ShouldAct(Message message)
|
||||||
{
|
{
|
||||||
if (!base.ShouldAct(message))
|
if (!base.ShouldAct(message))
|
||||||
@ -43,15 +53,56 @@ public class TwitchSummon : Behavior
|
|||||||
|
|
||||||
public override async Task<bool> ActOn(Message message)
|
public override async Task<bool> ActOn(Message message)
|
||||||
{
|
{
|
||||||
var ti = ProtocolInterfaces.ProtocolList.twitchs.FirstOrDefault();
|
var ti = getAnyTwitchInterface();
|
||||||
if (ti != null)
|
if (ti != null)
|
||||||
{
|
{
|
||||||
var channelTarget = message.Content.Substring(message.Content.IndexOf(Trigger) + Trigger.Length + 1).Trim();
|
var channelTarget = message.Content.Substring(message.Content.IndexOf(Trigger) + Trigger.Length + 1).Trim();
|
||||||
await message.Channel.SendMessage(ti.AttemptJoin(channelTarget));
|
Behaver.Instance.SendMessage(message.Channel.Id, ti.AttemptJoin(channelTarget));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await message.Reply("i don't have a twitch interface running :(");
|
Behaver.Instance.Reply(message.Id, "i don't have a twitch interface running :(");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StaticPlz]
|
||||||
|
public class TwitchDismiss : Behavior
|
||||||
|
{
|
||||||
|
public override string Name => "Twitch Dismiss";
|
||||||
|
|
||||||
|
public override string Trigger => "begone, @[me]";
|
||||||
|
|
||||||
|
public override bool ShouldAct(Message message)
|
||||||
|
{
|
||||||
|
var ti = TwitchSummon.getAnyTwitchInterface();
|
||||||
|
// Console.WriteLine($"TwitchDismiss checking. menions me? {message.MentionsMe}");
|
||||||
|
if (message.MentionsMe &&
|
||||||
|
(Regex.IsMatch(message.Content.ToLower(), "\\bbegone\\b") || Regex.IsMatch(message.Content.ToLower(), "\\bfuck off\\b")))
|
||||||
|
{
|
||||||
|
var channelTarget = message.Content.Substring(message.Content.IndexOf(Trigger) + Trigger.Length + 1).Trim();
|
||||||
|
ti.AttemptLeave(channelTarget);
|
||||||
|
//TODO: PERMISSION! who can dismiss me? pretty simple list:
|
||||||
|
//1) anyone in the channel with authority*
|
||||||
|
//2) whoever summoned me
|
||||||
|
//* i don't know if the twitch *chat* interface will tell me if someone's a mod.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<bool> ActOn(Message message)
|
||||||
|
{
|
||||||
|
var ti = TwitchSummon.getAnyTwitchInterface();
|
||||||
|
|
||||||
|
if (ti != null)
|
||||||
|
{
|
||||||
|
ti.AttemptLeave(message.Channel.DisplayName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Behaver.Instance.Reply(message.Id, "i don't have a twitch interface running :(");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
namespace vassago.Behavior;
|
|
||||||
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using vassago.Models;
|
|
||||||
|
|
||||||
[StaticPlz]
|
|
||||||
public class TwitchDismiss : Behavior
|
|
||||||
{
|
|
||||||
public override string Name => "Twitch Dismiss";
|
|
||||||
|
|
||||||
public override string Trigger => "begone, @[me]";
|
|
||||||
|
|
||||||
public override bool ShouldAct(Message message)
|
|
||||||
{
|
|
||||||
var ti = ProtocolInterfaces.ProtocolList.twitchs.FirstOrDefault();
|
|
||||||
// Console.WriteLine($"TwitchDismiss checking. menions me? {message.MentionsMe}");
|
|
||||||
if(message.MentionsMe &&
|
|
||||||
(Regex.IsMatch(message.Content.ToLower(), "\\bbegone\\b") || Regex.IsMatch(message.Content.ToLower(), "\\bfuck off\\b")))
|
|
||||||
{
|
|
||||||
var channelTarget = message.Content.Substring(message.Content.IndexOf(Trigger) + Trigger.Length + 1).Trim();
|
|
||||||
ti.AttemptLeave(channelTarget);
|
|
||||||
//TODO: PERMISSION! who can dismiss me? pretty simple list:
|
|
||||||
//1) anyone in the channel with authority*
|
|
||||||
//2) whoever summoned me
|
|
||||||
//* i don't know if the twitch *chat* interface will tell me if someone's a mod.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task<bool> ActOn(Message message)
|
|
||||||
{
|
|
||||||
var ti = ProtocolInterfaces.ProtocolList.twitchs.FirstOrDefault();
|
|
||||||
|
|
||||||
if(ti != null)
|
|
||||||
{
|
|
||||||
ti.AttemptLeave(message.Channel.DisplayName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await message.Reply("i don't have a twitch interface running :(");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,13 +23,13 @@ public class UnitConvert : Behavior
|
|||||||
if (decimal.TryParse(theseMatches[0].Groups[1].Value, out asNumeric))
|
if (decimal.TryParse(theseMatches[0].Groups[1].Value, out asNumeric))
|
||||||
{
|
{
|
||||||
Console.WriteLine("let's try and convert...");
|
Console.WriteLine("let's try and convert...");
|
||||||
await message.Channel.SendMessage(Conversion.Converter.Convert(asNumeric, theseMatches[0].Groups[2].Value, theseMatches[0].Groups[4].Value.ToLower()));
|
Behaver.Instance.SendMessage(message.Channel.Id, Conversion.Converter.Convert(asNumeric, theseMatches[0].Groups[2].Value, theseMatches[0].Groups[4].Value.ToLower()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
await message.Channel.SendMessage("mysteriously semi-parsable");
|
Behaver.Instance.SendMessage(message.Channel.Id, "mysteriously semi-parsable");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
await message.Channel.SendMessage( "unparsable");
|
Behaver.Instance.SendMessage(message.Channel.Id, "unparsable");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,14 +36,17 @@ public class Webhook : Behavior
|
|||||||
{
|
{
|
||||||
Console.WriteLine($"{kvp[0]}: {kvp[1]}");
|
Console.WriteLine($"{kvp[0]}: {kvp[1]}");
|
||||||
}
|
}
|
||||||
|
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()
|
||||||
{
|
{
|
||||||
OwnerId = conf.uacID,
|
OwnerId = conf.uacID,
|
||||||
DisplayName = confName
|
DisplayName = confName,
|
||||||
|
Description = conf.Description
|
||||||
};
|
};
|
||||||
|
changed = true;
|
||||||
Rememberer.RememberUAC(myUAC);
|
Rememberer.RememberUAC(myUAC);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -51,11 +54,18 @@ public class Webhook : Behavior
|
|||||||
if (myUAC.DisplayName != confName)
|
if (myUAC.DisplayName != confName)
|
||||||
{
|
{
|
||||||
myUAC.DisplayName = confName;
|
myUAC.DisplayName = confName;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (myUAC.Description != conf.Description)
|
||||||
|
{
|
||||||
|
myUAC.Description = conf.Description;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (changed)
|
||||||
Rememberer.RememberUAC(myUAC);
|
Rememberer.RememberUAC(myUAC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool ShouldAct(Message message)
|
public override bool ShouldAct(Message message)
|
||||||
{
|
{
|
||||||
@ -150,11 +160,11 @@ public class Webhook : Behavior
|
|||||||
{
|
{
|
||||||
var tragedy = $"{response.StatusCode} - {response.ReasonPhrase} - {await response.Content.ReadAsStringAsync()}";
|
var tragedy = $"{response.StatusCode} - {response.ReasonPhrase} - {await response.Content.ReadAsStringAsync()}";
|
||||||
Console.Error.WriteLine(tragedy);
|
Console.Error.WriteLine(tragedy);
|
||||||
await message.Reply(tragedy);
|
Behaver.Instance.Reply(message.Id, tragedy);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await message.Reply(await response.Content.ReadAsStringAsync());
|
Behaver.Instance.Reply(message.Id, await response.Content.ReadAsStringAsync());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -179,6 +189,7 @@ public class WebhookConf
|
|||||||
public Enumerations.HttpVerb Method { get; set; }
|
public Enumerations.HttpVerb Method { get; set; }
|
||||||
public List<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 class WebhookActionOrder
|
public class WebhookActionOrder
|
||||||
{
|
{
|
||||||
|
@ -25,9 +25,9 @@ public class WishLuck : Behavior
|
|||||||
toSend = "\U0001f340";//4-leaf clover
|
toSend = "\U0001f340";//4-leaf clover
|
||||||
}
|
}
|
||||||
if(message.Channel.EffectivePermissions.ReactionsPossible == true)
|
if(message.Channel.EffectivePermissions.ReactionsPossible == true)
|
||||||
await message.React(toSend);
|
Behaver.Instance.React(message.Id, toSend);
|
||||||
else
|
else
|
||||||
await message.Channel.SendMessage(toSend);
|
Behaver.Instance.SendMessage(message.Channel.Id, toSend);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,7 +8,7 @@ namespace vassago
|
|||||||
using vassago.ProtocolInterfaces.DiscordInterface;
|
using vassago.ProtocolInterfaces.DiscordInterface;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
internal class ConsoleService : IHostedService
|
internal class ConsoleService : BackgroundService
|
||||||
{
|
{
|
||||||
public ConsoleService(IConfiguration aspConfig)
|
public ConsoleService(IConfiguration aspConfig)
|
||||||
{
|
{
|
||||||
@ -25,7 +25,7 @@ namespace vassago
|
|||||||
IEnumerable<string> DiscordTokens { get; }
|
IEnumerable<string> DiscordTokens { get; }
|
||||||
IEnumerable<TwitchConfig> TwitchConfigs { get; }
|
IEnumerable<TwitchConfig> TwitchConfigs { get; }
|
||||||
|
|
||||||
public async Task StartAsync(CancellationToken cancellationToken)
|
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var initTasks = new List<Task>();
|
var initTasks = new List<Task>();
|
||||||
var dbc = new ChattingContext();
|
var dbc = new ChattingContext();
|
||||||
@ -36,7 +36,7 @@ namespace vassago
|
|||||||
{
|
{
|
||||||
var d = new DiscordInterface();
|
var d = new DiscordInterface();
|
||||||
initTasks.Add(d.Init(dt));
|
initTasks.Add(d.Init(dt));
|
||||||
ProtocolInterfaces.ProtocolList.discords.Add(d);
|
Shared.ProtocolList.Add(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TwitchConfigs?.Any() ?? false)
|
if (TwitchConfigs?.Any() ?? false)
|
||||||
@ -44,15 +44,11 @@ namespace vassago
|
|||||||
{
|
{
|
||||||
var t = new TwitchInterface.TwitchInterface();
|
var t = new TwitchInterface.TwitchInterface();
|
||||||
initTasks.Add(t.Init(tc));
|
initTasks.Add(t.Init(tc));
|
||||||
ProtocolInterfaces.ProtocolList.twitchs.Add(t);
|
Shared.ProtocolList.Add(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
Task.WaitAll(initTasks.ToArray(), cancellationToken);
|
Task.WaitAll(initTasks.ToArray(), cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
386
Migrations/20250523181842_channelAliases.Designer.cs
generated
Normal file
386
Migrations/20250523181842_channelAliases.Designer.cs
generated
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
// <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("20250523181842_channelAliases")]
|
||||||
|
partial class channelAliases
|
||||||
|
{
|
||||||
|
/// <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<Dictionary<string, string>>("Aliases")
|
||||||
|
.HasColumnType("hstore");
|
||||||
|
|
||||||
|
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.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.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<string>("Description")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("DisplayName")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid>("OwnerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
Migrations/20250523181842_channelAliases.cs
Normal file
45
Migrations/20250523181842_channelAliases.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace vassago.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class channelAliases : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterDatabase()
|
||||||
|
.Annotation("Npgsql:PostgresExtension:hstore", ",,");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "Description",
|
||||||
|
table: "UACs",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Dictionary<string, string>>(
|
||||||
|
name: "Aliases",
|
||||||
|
table: "Channels",
|
||||||
|
type: "hstore",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Description",
|
||||||
|
table: "UACs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Aliases",
|
||||||
|
table: "Channels");
|
||||||
|
|
||||||
|
migrationBuilder.AlterDatabase()
|
||||||
|
.OldAnnotation("Npgsql:PostgresExtension:hstore", ",,");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
@ -20,6 +21,7 @@ namespace vassago.Migrations
|
|||||||
.HasAnnotation("ProductVersion", "7.0.5")
|
.HasAnnotation("ProductVersion", "7.0.5")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore");
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
modelBuilder.Entity("AccountUAC", b =>
|
modelBuilder.Entity("AccountUAC", b =>
|
||||||
@ -146,6 +148,9 @@ namespace vassago.Migrations
|
|||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("uuid");
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Dictionary<string, string>>("Aliases")
|
||||||
|
.HasColumnType("hstore");
|
||||||
|
|
||||||
b.Property<int>("ChannelType")
|
b.Property<int>("ChannelType")
|
||||||
.HasColumnType("integer");
|
.HasColumnType("integer");
|
||||||
|
|
||||||
@ -231,6 +236,9 @@ namespace vassago.Migrations
|
|||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("uuid");
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("DisplayName")
|
b.Property<string>("DisplayName")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ public class Channel
|
|||||||
public List<Channel> SubChannels { get; set; }
|
public List<Channel> SubChannels { get; set; }
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public Channel ParentChannel { get; set; }
|
public Channel ParentChannel { get; set; }
|
||||||
|
public Guid? ParentChannelId { get; set; }
|
||||||
public string Protocol { get; set; }
|
public string Protocol { get; set; }
|
||||||
[DeleteBehavior(DeleteBehavior.Cascade)]
|
[DeleteBehavior(DeleteBehavior.Cascade)]
|
||||||
public List<Message> Messages { get; set; }
|
public List<Message> Messages { get; set; }
|
||||||
@ -34,15 +35,9 @@ public class Channel
|
|||||||
public bool? ReactionsPossible { get; set; }
|
public bool? ReactionsPossible { get; set; }
|
||||||
public Enumerations.LewdnessFilterLevel? LewdnessFilterLevel { get; set; }
|
public Enumerations.LewdnessFilterLevel? LewdnessFilterLevel { get; set; }
|
||||||
public Enumerations.MeannessFilterLevel? MeannessFilterLevel { get; set; }
|
public Enumerations.MeannessFilterLevel? MeannessFilterLevel { get; set; }
|
||||||
|
|
||||||
public List<UAC> UACs { get; set; }
|
public List<UAC> UACs { get; set; }
|
||||||
|
//both incoming and outgoing
|
||||||
[NonSerialized]
|
//public Dictionary<string, string> Aliases { get; set; }
|
||||||
public Func<string, string, Task> SendFile;
|
|
||||||
|
|
||||||
[NonSerialized]
|
|
||||||
public Func<string, Task> SendMessage;
|
|
||||||
|
|
||||||
|
|
||||||
public DefinitePermissionSettings EffectivePermissions
|
public DefinitePermissionSettings EffectivePermissions
|
||||||
{
|
{
|
||||||
|
@ -22,11 +22,4 @@ public class Message
|
|||||||
public List<Attachment> Attachments { get; set; }
|
public List<Attachment> Attachments { get; set; }
|
||||||
public Account Author { get; set; }
|
public Account Author { get; set; }
|
||||||
public Channel Channel { get; set; }
|
public Channel Channel { get; set; }
|
||||||
|
|
||||||
//TODO: these are nicities to make it OOP, but it couples them with their respective platform interfaces (and connections!)
|
|
||||||
[NonSerialized]
|
|
||||||
public Func<string, Task> Reply;
|
|
||||||
|
|
||||||
[NonSerialized]
|
|
||||||
public Func<string, Task> React;
|
|
||||||
}
|
}
|
||||||
|
@ -20,4 +20,10 @@ public class UAC
|
|||||||
public List<Account> AccountInChannels { get; set; }
|
public List<Account> AccountInChannels { get; set; }
|
||||||
public List<Channel> Channels { get; set; }
|
public List<Channel> Channels { get; set; }
|
||||||
public List<User> Users { get; set; }
|
public List<User> Users { get; set; }
|
||||||
|
///<summary>"but past adam", you may ask. "if UACs are configured before runtime, why not write html into your source control, as part of the project,
|
||||||
|
///with the benefit of an html editor?"
|
||||||
|
///absolutely fair question. **But**: the plan is for external services, e.g., over kafka, to manage their own. So from Vassago's perspective,
|
||||||
|
///it's variably before and after compile time. shrug.emote.
|
||||||
|
///</summary>
|
||||||
|
public string Description { get; set; }
|
||||||
}
|
}
|
||||||
|
10
Program.cs
10
Program.cs
@ -3,8 +3,6 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using Microsoft.AspNetCore.Mvc.NewtonsoftJson;
|
using Microsoft.AspNetCore.Mvc.NewtonsoftJson;
|
||||||
using vassago.Models;
|
using vassago.Models;
|
||||||
|
|
||||||
#pragma warning disable CA2254
|
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
@ -25,12 +23,6 @@ builder.Services.AddSwaggerGen();
|
|||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
|
||||||
if (!app.Environment.IsDevelopment())
|
|
||||||
{
|
|
||||||
app.UseExceptionHandler("/Home/Error");
|
|
||||||
}
|
|
||||||
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
@ -46,7 +38,7 @@ app.UseSwaggerUI(c =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
//app.UseExceptionHandler();
|
//app.UseExceptionHandler();
|
||||||
app.UseStatusCodePages();
|
//app.UseStatusCodePages();
|
||||||
|
|
||||||
if (app.Environment.IsDevelopment())
|
if (app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
|
@ -20,13 +20,14 @@ namespace vassago.ProtocolInterfaces.DiscordInterface;
|
|||||||
//store
|
//store
|
||||||
//ship off to behaver
|
//ship off to behaver
|
||||||
|
|
||||||
public class DiscordInterface
|
public class DiscordInterface : ProtocolInterface
|
||||||
{
|
{
|
||||||
internal static string PROTOCOL { get => "discord"; }
|
public static new string Protocol { get => "discord"; }
|
||||||
internal DiscordSocketClient client;
|
internal DiscordSocketClient client;
|
||||||
private bool eventsSignedUp = false;
|
private bool eventsSignedUp = false;
|
||||||
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 async Task Init(string config)
|
public async Task Init(string config)
|
||||||
{
|
{
|
||||||
@ -52,7 +53,7 @@ public class DiscordInterface
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
protocolAsChannel = Rememberer.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()
|
||||||
@ -65,7 +66,7 @@ public class DiscordInterface
|
|||||||
LinksAllowed = true,
|
LinksAllowed = true,
|
||||||
ReactionsPossible = true,
|
ReactionsPossible = true,
|
||||||
ExternalId = null,
|
ExternalId = null,
|
||||||
Protocol = PROTOCOL,
|
Protocol = Protocol,
|
||||||
SubChannels = []
|
SubChannels = []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -74,8 +75,6 @@ public class DiscordInterface
|
|||||||
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.SendMessage = (t) => { throw new InvalidOperationException($"protocol isn't a real channel, cannot accept text"); };
|
|
||||||
protocolAsChannel.SendFile = (f, t) => { throw new InvalidOperationException($"protocol isn't a real channel, cannot send file"); };
|
|
||||||
protocolAsChannel = Rememberer.RememberChannel(protocolAsChannel);
|
protocolAsChannel = Rememberer.RememberChannel(protocolAsChannel);
|
||||||
Console.WriteLine($"protocol as channel addeed; {protocolAsChannel}");
|
Console.WriteLine($"protocol as channel addeed; {protocolAsChannel}");
|
||||||
}
|
}
|
||||||
@ -206,12 +205,10 @@ public class DiscordInterface
|
|||||||
}
|
}
|
||||||
internal Message UpsertMessage(IUserMessage dMessage)
|
internal Message UpsertMessage(IUserMessage dMessage)
|
||||||
{
|
{
|
||||||
var m = Rememberer.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()
|
||||||
{
|
{
|
||||||
//I don't understand why messages need to have their Ids specified but no other entity does. shrug dot emoji
|
Protocol = Protocol
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
Protocol = PROTOCOL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (dMessage.Attachments?.Count > 0)
|
if (dMessage.Attachments?.Count > 0)
|
||||||
@ -227,7 +224,6 @@ public class DiscordInterface
|
|||||||
m.Timestamp = dMessage.EditedTimestamp ?? dMessage.CreatedAt;
|
m.Timestamp = dMessage.EditedTimestamp ?? dMessage.CreatedAt;
|
||||||
m.Channel = UpsertChannel(dMessage.Channel);
|
m.Channel = UpsertChannel(dMessage.Channel);
|
||||||
m.Author = UpsertAccount(dMessage.Author, m.Channel);
|
m.Author = UpsertAccount(dMessage.Author, m.Channel);
|
||||||
Console.WriteLine($"received message; author: {m.Author.DisplayName}, {m.Author.Id}");
|
|
||||||
if (dMessage.Channel is IGuildChannel)
|
if (dMessage.Channel is IGuildChannel)
|
||||||
{
|
{
|
||||||
m.Author.DisplayName = (dMessage.Author as IGuildUser).DisplayName;//discord forgot how display names work.
|
m.Author.DisplayName = (dMessage.Author as IGuildUser).DisplayName;//discord forgot how display names work.
|
||||||
@ -235,17 +231,16 @@ public class DiscordInterface
|
|||||||
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));
|
||||||
|
|
||||||
m.Reply = (t) => { return dMessage.ReplyAsync(TruncateText(t, m.Channel.MaxTextChars)); };
|
|
||||||
m.React = (e) => { return AttemptReact(dMessage, e); };
|
|
||||||
Rememberer.RememberMessage(m);
|
Rememberer.RememberMessage(m);
|
||||||
|
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 = Rememberer.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()}");
|
||||||
c = new Channel()
|
c = new Channel()
|
||||||
{
|
{
|
||||||
Users = []
|
Users = []
|
||||||
@ -255,7 +250,7 @@ public class DiscordInterface
|
|||||||
c.ExternalId = channel.Id.ToString();
|
c.ExternalId = channel.Id.ToString();
|
||||||
c.ChannelType = (channel is IPrivateChannel) ? vassago.Models.Enumerations.ChannelType.DM : vassago.Models.Enumerations.ChannelType.Normal;
|
c.ChannelType = (channel is IPrivateChannel) ? vassago.Models.Enumerations.ChannelType.DM : vassago.Models.Enumerations.ChannelType.Normal;
|
||||||
c.Messages ??= [];
|
c.Messages ??= [];
|
||||||
c.Protocol = PROTOCOL;
|
c.Protocol = Protocol;
|
||||||
if (channel is IGuildChannel)
|
if (channel is IGuildChannel)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"{channel.Name} is a guild channel. So i'm going to upsert the guild, {(channel as IGuildChannel).Guild}");
|
Console.WriteLine($"{channel.Name} is a guild channel. So i'm going to upsert the guild, {(channel as IGuildChannel).Guild}");
|
||||||
@ -295,7 +290,7 @@ public class DiscordInterface
|
|||||||
Channel parentChannel = null;
|
Channel parentChannel = null;
|
||||||
if (channel is IGuildChannel)
|
if (channel is IGuildChannel)
|
||||||
{
|
{
|
||||||
parentChannel = Rememberer.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?");
|
||||||
@ -316,9 +311,6 @@ public class DiscordInterface
|
|||||||
parentChannel.SubChannels.Add(c);
|
parentChannel.SubChannels.Add(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
c.SendMessage = (t) => { return channel.SendMessageAsync(TruncateText(t, c.MaxTextChars));};
|
|
||||||
c.SendFile = (f, t) => { return channel.SendFileAsync(f, t); };
|
|
||||||
|
|
||||||
c = Rememberer.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}");
|
||||||
@ -332,10 +324,10 @@ public class DiscordInterface
|
|||||||
}
|
}
|
||||||
internal Channel UpsertChannel(IGuild channel)
|
internal Channel UpsertChannel(IGuild channel)
|
||||||
{
|
{
|
||||||
Channel c = Rememberer.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()}");
|
||||||
c = new Channel();
|
c = new Channel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,9 +340,6 @@ public class DiscordInterface
|
|||||||
c.SubChannels ??= [];
|
c.SubChannels ??= [];
|
||||||
c.MaxAttachmentBytes = channel.MaxUploadLimit;
|
c.MaxAttachmentBytes = channel.MaxUploadLimit;
|
||||||
|
|
||||||
c.SendMessage = (t) => { throw new InvalidOperationException($"channel {channel.Name} is guild; cannot accept text"); };
|
|
||||||
c.SendFile = (f, t) => { throw new InvalidOperationException($"channel {channel.Name} is guild; send file"); };
|
|
||||||
|
|
||||||
return Rememberer.RememberChannel(c);
|
return Rememberer.RememberChannel(c);
|
||||||
}
|
}
|
||||||
internal static Account UpsertAccount(IUser discordUser, Channel inChannel)
|
internal static Account UpsertAccount(IUser discordUser, Channel inChannel)
|
||||||
@ -361,15 +350,16 @@ public class DiscordInterface
|
|||||||
{
|
{
|
||||||
Console.WriteLine($"acc's user: {acc.IsUser?.Id}");
|
Console.WriteLine($"acc's user: {acc.IsUser?.Id}");
|
||||||
}
|
}
|
||||||
acc ??= new Account() {
|
acc ??= new Account()
|
||||||
IsUser = Rememberer.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()
|
||||||
};
|
};
|
||||||
|
|
||||||
acc.Username = discordUser.Username;
|
acc.Username = discordUser.Username;
|
||||||
acc.ExternalId = discordUser.Id.ToString();
|
acc.ExternalId = discordUser.Id.ToString();
|
||||||
acc.IsBot = discordUser.IsBot || discordUser.IsWebhook;
|
acc.IsBot = discordUser.IsBot || discordUser.IsWebhook;
|
||||||
acc.Protocol = PROTOCOL;
|
acc.Protocol = Protocol;
|
||||||
acc.SeenInChannel = inChannel;
|
acc.SeenInChannel = inChannel;
|
||||||
|
|
||||||
Console.WriteLine($"we asked rememberer to search for acc's user. {acc.IsUser?.Id}");
|
Console.WriteLine($"we asked rememberer to search for acc's user. {acc.IsUser?.Id}");
|
||||||
@ -392,23 +382,26 @@ public class DiscordInterface
|
|||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Task AttemptReact(IUserMessage msg, string e)
|
private static async Task<int> AttemptReact(IUserMessage msg, string e)
|
||||||
{
|
{
|
||||||
|
Console.WriteLine("discord attempting to react");
|
||||||
var c = Rememberer.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))
|
||||||
{
|
{
|
||||||
return msg.AddReactionAsync(emoji);
|
msg.AddReactionAsync(emoji);
|
||||||
|
return 200;
|
||||||
}
|
}
|
||||||
if (!Emote.TryParse(preferredEmote, out Emote emote))
|
if (!Emote.TryParse(preferredEmote, out Emote emote))
|
||||||
{
|
{
|
||||||
if (preferredEmote == e)
|
if (preferredEmote == e)
|
||||||
Console.Error.WriteLine($"never heard of emote {e}");
|
Console.Error.WriteLine($"never heard of emote {e}");
|
||||||
return Task.CompletedTask;
|
return 405;
|
||||||
}
|
}
|
||||||
|
|
||||||
return msg.AddReactionAsync(emote);
|
msg.AddReactionAsync(emote);
|
||||||
|
return 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string TruncateText(string msg, uint? chars)
|
private static string TruncateText(string msg, uint? chars)
|
||||||
@ -423,5 +416,82 @@ public class DiscordInterface
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public override async Task<int> SendMessage(Channel channel, string text)
|
||||||
|
{
|
||||||
|
var dcCh = await client.GetChannelAsync(ulong.Parse(channel.ExternalId));
|
||||||
|
if (dcCh == null)
|
||||||
|
{
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dcCh is IMessageChannel msgChannel)
|
||||||
|
{
|
||||||
|
await msgChannel.SendMessageAsync(TruncateText(text, channel.MaxTextChars));
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 503;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override async Task<int> SendFile(Channel channel, string base64dData, string filename, string accompanyingText)
|
||||||
|
{
|
||||||
|
var dcCh = await client.GetChannelAsync(ulong.Parse(channel.ExternalId));
|
||||||
|
if (dcCh == null)
|
||||||
|
{
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dcCh is IMessageChannel msgChannel)
|
||||||
|
{
|
||||||
|
using (var ms = new MemoryStream(Convert.FromBase64String(base64dData)))
|
||||||
|
{
|
||||||
|
await msgChannel.SendFileAsync(ms, filename, TruncateText(accompanyingText, channel.MaxTextChars));
|
||||||
|
}
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 503;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override async Task<int> React(Message message, string reaction)
|
||||||
|
{
|
||||||
|
var dcCh = await client.GetChannelAsync(ulong.Parse(message.Channel.ExternalId));
|
||||||
|
if (dcCh == null)
|
||||||
|
return 404;
|
||||||
|
|
||||||
|
if (dcCh is IMessageChannel msgChannel)
|
||||||
|
{
|
||||||
|
var dcMsg = await msgChannel.GetMessageAsync(ulong.Parse(message.ExternalId));
|
||||||
|
if (dcMsg == null)
|
||||||
|
return 404;
|
||||||
|
|
||||||
|
return await AttemptReact(dcMsg as IUserMessage, reaction);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 503;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override async Task<int> Reply(Message message, string text)
|
||||||
|
{
|
||||||
|
var dcCh = await client.GetChannelAsync(ulong.Parse(message.Channel.ExternalId));
|
||||||
|
if (dcCh == null)
|
||||||
|
return 404;
|
||||||
|
|
||||||
|
if (dcCh is IMessageChannel msgChannel)
|
||||||
|
{
|
||||||
|
var dcMsg = await msgChannel.GetMessageAsync(ulong.Parse(message.ExternalId));
|
||||||
|
if (dcMsg == null)
|
||||||
|
return 404;
|
||||||
|
|
||||||
|
(dcMsg as IUserMessage).ReplyAsync(TruncateText(text, message.Channel.MaxTextChars));
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 503;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
22
ProtocolInterfaces/ProtocolInterface.cs
Normal file
22
ProtocolInterfaces/ProtocolInterface.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
namespace vassago.ProtocolInterfaces;
|
||||||
|
|
||||||
|
using vassago.Models;
|
||||||
|
|
||||||
|
public abstract class ProtocolInterface
|
||||||
|
{
|
||||||
|
public static string Protocol { get; }
|
||||||
|
public abstract Channel SelfChannel { get; }
|
||||||
|
public abstract Task<int> SendMessage(Channel channel, string text);
|
||||||
|
public virtual async Task<int> SendFile(Channel channel, string path, string accompanyingText)
|
||||||
|
{
|
||||||
|
if (!File.Exists(path))
|
||||||
|
{
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
var fstring = Convert.ToBase64String(File.ReadAllBytes(path));
|
||||||
|
return await SendFile(channel, fstring, Path.GetFileName(path), accompanyingText);
|
||||||
|
}
|
||||||
|
public abstract Task<int> SendFile(Channel channel, string base64dData, string filename, string accompanyingText);
|
||||||
|
public abstract Task<int> React(Message message, string reaction);
|
||||||
|
public abstract Task<int> Reply(Message message, string text);
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
namespace vassago.ProtocolInterfaces;
|
|
||||||
|
|
||||||
public static class ProtocolList
|
|
||||||
{
|
|
||||||
public static List<DiscordInterface.DiscordInterface> discords = new();
|
|
||||||
public static List<TwitchInterface.TwitchInterface> twitchs = new();
|
|
||||||
}
|
|
@ -10,19 +10,16 @@ using TwitchLib.Communication.Clients;
|
|||||||
using TwitchLib.Communication.Models;
|
using TwitchLib.Communication.Models;
|
||||||
using vassago.Behavior;
|
using vassago.Behavior;
|
||||||
using vassago.Models;
|
using vassago.Models;
|
||||||
|
using vassago.ProtocolInterfaces;
|
||||||
|
|
||||||
namespace vassago.TwitchInterface;
|
namespace vassago.TwitchInterface;
|
||||||
|
|
||||||
internal class unifiedTwitchMessage
|
public class TwitchInterface : ProtocolInterface
|
||||||
{
|
{
|
||||||
public unifiedTwitchMessage(ChatMessage chatMessage) { }
|
public static new string Protocol { get => "twitch"; }
|
||||||
}
|
|
||||||
|
|
||||||
public class TwitchInterface
|
|
||||||
{
|
|
||||||
internal const string PROTOCOL = "twitch";
|
|
||||||
private static SemaphoreSlim channelSetupSemaphpore = new SemaphoreSlim(1, 1);
|
private static SemaphoreSlim channelSetupSemaphpore = new SemaphoreSlim(1, 1);
|
||||||
private Channel protocolAsChannel;
|
private Channel protocolAsChannel;
|
||||||
|
public override Channel SelfChannel { get => protocolAsChannel;}
|
||||||
private Account selfAccountInProtocol;
|
private Account selfAccountInProtocol;
|
||||||
TwitchClient client;
|
TwitchClient client;
|
||||||
|
|
||||||
@ -32,7 +29,7 @@ public class TwitchInterface
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
protocolAsChannel = Rememberer.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()
|
||||||
@ -45,12 +42,10 @@ public class TwitchInterface
|
|||||||
LinksAllowed = false,
|
LinksAllowed = false,
|
||||||
ReactionsPossible = false,
|
ReactionsPossible = false,
|
||||||
ExternalId = null,
|
ExternalId = null,
|
||||||
Protocol = PROTOCOL,
|
Protocol = Protocol,
|
||||||
SubChannels = []
|
SubChannels = []
|
||||||
};
|
};
|
||||||
protocolAsChannel.DisplayName = "twitch (itself)";
|
protocolAsChannel.DisplayName = "twitch (itself)";
|
||||||
protocolAsChannel.SendMessage = (t) => { throw new InvalidOperationException($"twitch itself cannot accept text"); };
|
|
||||||
protocolAsChannel.SendFile = (f, t) => { throw new InvalidOperationException($"twitch itself cannot send file"); };
|
|
||||||
protocolAsChannel = Rememberer.RememberChannel(protocolAsChannel);
|
protocolAsChannel = Rememberer.RememberChannel(protocolAsChannel);
|
||||||
Console.WriteLine($"protocol as channle added; {protocolAsChannel}");
|
Console.WriteLine($"protocol as channle added; {protocolAsChannel}");
|
||||||
}
|
}
|
||||||
@ -97,7 +92,8 @@ public class TwitchInterface
|
|||||||
|
|
||||||
//translate to internal, upsert
|
//translate to internal, upsert
|
||||||
var m = UpsertMessage(e.WhisperMessage);
|
var m = UpsertMessage(e.WhisperMessage);
|
||||||
m.Reply = (t) => { return Task.Run(() => { client.SendWhisper(e.WhisperMessage.Username, t); }); };
|
//can't send whispers without giving up cellphone number.
|
||||||
|
//m.Reply = (t) => { return Task.Run(() => { client.SendWhisper(e.WhisperMessage.Username, t); }); };
|
||||||
m.Channel.ChannelType = vassago.Models.Enumerations.ChannelType.DM;
|
m.Channel.ChannelType = vassago.Models.Enumerations.ChannelType.DM;
|
||||||
//act on
|
//act on
|
||||||
await Behaver.Instance.ActOn(m);
|
await Behaver.Instance.ActOn(m);
|
||||||
@ -112,7 +108,6 @@ public class TwitchInterface
|
|||||||
|
|
||||||
//translate to internal, upsert
|
//translate to internal, upsert
|
||||||
var m = UpsertMessage(e.ChatMessage);
|
var m = UpsertMessage(e.ChatMessage);
|
||||||
m.Reply = (t) => { return Task.Run(() => { client.SendReply(e.ChatMessage.Channel, e.ChatMessage.Id, t); }); };
|
|
||||||
m.Channel.ChannelType = vassago.Models.Enumerations.ChannelType.Normal;
|
m.Channel.ChannelType = vassago.Models.Enumerations.ChannelType.Normal;
|
||||||
//act on
|
//act on
|
||||||
await Behaver.Instance.ActOn(m);
|
await Behaver.Instance.ActOn(m);
|
||||||
@ -152,14 +147,14 @@ public class TwitchInterface
|
|||||||
acc ??= new Account()
|
acc ??= new Account()
|
||||||
{
|
{
|
||||||
IsUser = Rememberer.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()
|
||||||
};
|
};
|
||||||
|
|
||||||
acc.Username = username;
|
acc.Username = username;
|
||||||
acc.ExternalId = username;
|
acc.ExternalId = username;
|
||||||
//acc.IsBot = false? there is a way to tell, but you have to go back through the API
|
//acc.IsBot = false? there is a way to tell, but you have to go back through the API
|
||||||
acc.Protocol = PROTOCOL;
|
acc.Protocol = Protocol;
|
||||||
acc.SeenInChannel = inChannel;
|
acc.SeenInChannel = inChannel;
|
||||||
|
|
||||||
// Console.WriteLine($"we asked rememberer to search for acc's user. {acc.IsUser?.Id}");
|
// Console.WriteLine($"we asked rememberer to search for acc's user. {acc.IsUser?.Id}");
|
||||||
@ -185,7 +180,7 @@ public class TwitchInterface
|
|||||||
private Channel UpsertChannel(string channelName)
|
private Channel UpsertChannel(string channelName)
|
||||||
{
|
{
|
||||||
Channel c = Rememberer.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)
|
||||||
{
|
{
|
||||||
// Console.WriteLine($"couldn't find channel under protocol {PROTOCOL} with externalId {channelName}");
|
// Console.WriteLine($"couldn't find channel under protocol {PROTOCOL} with externalId {channelName}");
|
||||||
@ -199,11 +194,9 @@ public class TwitchInterface
|
|||||||
c.ExternalId = channelName;
|
c.ExternalId = channelName;
|
||||||
c.ChannelType = vassago.Models.Enumerations.ChannelType.Normal;
|
c.ChannelType = vassago.Models.Enumerations.ChannelType.Normal;
|
||||||
c.Messages ??= [];
|
c.Messages ??= [];
|
||||||
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.SendMessage = (t) => { return Task.Run(() => { client.SendMessage(channelName, t); }); };
|
|
||||||
c.SendFile = (f, t) => { throw new InvalidOperationException($"twitch cannot send files"); };
|
|
||||||
c = Rememberer.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);
|
||||||
@ -217,7 +210,7 @@ public class TwitchInterface
|
|||||||
private Channel UpsertDMChannel(string whisperWith)
|
private Channel UpsertDMChannel(string whisperWith)
|
||||||
{
|
{
|
||||||
Channel c = Rememberer.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)
|
||||||
{
|
{
|
||||||
// Console.WriteLine($"couldn't find channel under protocol {PROTOCOL}, whisper with {whisperWith}");
|
// Console.WriteLine($"couldn't find channel under protocol {PROTOCOL}, whisper with {whisperWith}");
|
||||||
@ -231,25 +224,9 @@ public class TwitchInterface
|
|||||||
c.ExternalId = $"w_{whisperWith}";
|
c.ExternalId = $"w_{whisperWith}";
|
||||||
c.ChannelType = vassago.Models.Enumerations.ChannelType.DM;
|
c.ChannelType = vassago.Models.Enumerations.ChannelType.DM;
|
||||||
c.Messages ??= [];
|
c.Messages ??= [];
|
||||||
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.SendMessage = (t) =>
|
|
||||||
{
|
|
||||||
return Task.Run(() =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
client.SendWhisper(whisperWith, t);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Console.Error.WriteLine(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
c.SendFile = (f, t) => { throw new InvalidOperationException($"twitch cannot send files"); };
|
|
||||||
c = Rememberer.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);
|
||||||
@ -266,10 +243,10 @@ public class TwitchInterface
|
|||||||
//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 = Rememberer.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,
|
||||||
Timestamp = (DateTimeOffset)DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc)
|
Timestamp = (DateTimeOffset)DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc)
|
||||||
};
|
};
|
||||||
m.Content = chatMessage.Message;
|
m.Content = chatMessage.Message;
|
||||||
@ -277,8 +254,6 @@ public class TwitchInterface
|
|||||||
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");
|
||||||
m.Reply = (t) => { return Task.Run(() => { client.SendReply(chatMessage.Channel, chatMessage.Id, t); }); };
|
|
||||||
m.React = (e) => { throw new InvalidOperationException($"twitch cannot react"); };
|
|
||||||
Rememberer.RememberMessage(m);
|
Rememberer.RememberMessage(m);
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
@ -288,11 +263,11 @@ public class TwitchInterface
|
|||||||
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 = Rememberer.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(),
|
||||||
Protocol = PROTOCOL,
|
Protocol = Protocol,
|
||||||
Timestamp = (DateTimeOffset)DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc)
|
Timestamp = (DateTimeOffset)DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc)
|
||||||
};
|
};
|
||||||
m.Content = whisperMessage.Message;
|
m.Content = whisperMessage.Message;
|
||||||
@ -300,8 +275,6 @@ public class TwitchInterface
|
|||||||
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");
|
||||||
m.Reply = (t) => { return Task.Run(() => { client.SendWhisper(whisperMessage.Username, t); }); };
|
|
||||||
m.React = (e) => { throw new InvalidOperationException($"twitch cannot react"); };
|
|
||||||
Rememberer.RememberMessage(m);
|
Rememberer.RememberMessage(m);
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
@ -317,4 +290,22 @@ public class TwitchInterface
|
|||||||
client.SendMessage(channelTarget, "o7");
|
client.SendMessage(channelTarget, "o7");
|
||||||
client.LeaveChannel(channelTarget);
|
client.LeaveChannel(channelTarget);
|
||||||
}
|
}
|
||||||
|
public override async Task<int> SendMessage(Channel channel, string text)
|
||||||
|
{
|
||||||
|
Task.Run(() => { client.SendMessage(channel.ExternalId, text); });
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
public override async Task<int> SendFile(Channel channel, string base64dData, string filename, string accompanyingText)
|
||||||
|
{
|
||||||
|
return 405;
|
||||||
|
}
|
||||||
|
public override async Task<int> React(Message message, string reaction)
|
||||||
|
{
|
||||||
|
return 405;
|
||||||
|
}
|
||||||
|
public override async Task<int> Reply(Message message, string text)
|
||||||
|
{
|
||||||
|
Task.Run(() => { client.SendReply(message.Channel.ExternalId, message.ExternalId, text); });
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
126
Rememberer.cs
126
Rememberer.cs
@ -8,6 +8,25 @@ public static class Rememberer
|
|||||||
{
|
{
|
||||||
private static readonly SemaphoreSlim dbAccessSemaphore = new(1, 1);
|
private static readonly SemaphoreSlim dbAccessSemaphore = new(1, 1);
|
||||||
private static readonly ChattingContext db = new();
|
private static readonly ChattingContext db = new();
|
||||||
|
private static List<Channel> channels;
|
||||||
|
private static bool channelCacheDirty = true;
|
||||||
|
|
||||||
|
private static void cacheChannels()
|
||||||
|
{
|
||||||
|
dbAccessSemaphore.Wait();
|
||||||
|
channels = db.Channels.ToList();
|
||||||
|
foreach (Channel ch in channels)
|
||||||
|
{
|
||||||
|
if (ch.ParentChannelId != null)
|
||||||
|
{
|
||||||
|
ch.ParentChannel = channels.FirstOrDefault(c => c.Id == ch.ParentChannelId);
|
||||||
|
ch.ParentChannel.SubChannels ??= [];
|
||||||
|
ch.ParentChannel.SubChannels.Add(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
channelCacheDirty = false;
|
||||||
|
dbAccessSemaphore.Release();
|
||||||
|
}
|
||||||
|
|
||||||
public static Account SearchAccount(Expression<Func<Account, bool>> predicate)
|
public static Account SearchAccount(Expression<Func<Account, bool>> predicate)
|
||||||
{
|
{
|
||||||
@ -33,13 +52,11 @@ public static class Rememberer
|
|||||||
dbAccessSemaphore.Release();
|
dbAccessSemaphore.Release();
|
||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
public static Channel SearchChannel(Expression<Func<Channel, bool>> predicate)
|
public static Channel SearchChannel(Func<Channel, bool> predicate)
|
||||||
{
|
{
|
||||||
Channel toReturn;
|
if(channelCacheDirty)
|
||||||
dbAccessSemaphore.Wait();
|
Task.Run(() => cacheChannels()).Wait();
|
||||||
toReturn = db.Channels.FirstOrDefault(predicate);
|
return channels.FirstOrDefault(predicate);
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
return toReturn;
|
|
||||||
}
|
}
|
||||||
public static Message SearchMessage(Expression<Func<Message, bool>> predicate)
|
public static Message SearchMessage(Expression<Func<Message, bool>> predicate)
|
||||||
{
|
{
|
||||||
@ -75,17 +92,27 @@ public static class Rememberer
|
|||||||
}
|
}
|
||||||
public static Channel RememberChannel(Channel toRemember)
|
public static Channel RememberChannel(Channel toRemember)
|
||||||
{
|
{
|
||||||
|
if(channelCacheDirty)
|
||||||
|
Task.Run(() => cacheChannels()).Wait(); //so we always do 2 db trips?
|
||||||
dbAccessSemaphore.Wait();
|
dbAccessSemaphore.Wait();
|
||||||
db.Update(toRemember);
|
db.Update(toRemember);
|
||||||
db.SaveChanges();
|
db.SaveChanges();
|
||||||
dbAccessSemaphore.Release();
|
dbAccessSemaphore.Release();
|
||||||
|
channelCacheDirty = true;
|
||||||
|
cacheChannels();
|
||||||
return toRemember;
|
return toRemember;
|
||||||
}
|
}
|
||||||
public static void RememberMessage(Message toRemember)
|
public static void RememberMessage(Message toRemember)
|
||||||
{
|
{
|
||||||
dbAccessSemaphore.Wait();
|
dbAccessSemaphore.Wait();
|
||||||
toRemember.Channel ??= new() { Messages = [toRemember] };
|
toRemember.Channel ??= new();
|
||||||
|
toRemember.Channel.Messages ??= [];
|
||||||
|
if (!toRemember.Channel.Messages.Contains(toRemember))
|
||||||
|
{
|
||||||
|
toRemember.Channel.Messages.Add(toRemember);
|
||||||
db.Update(toRemember.Channel);
|
db.Update(toRemember.Channel);
|
||||||
|
}
|
||||||
|
db.Update(toRemember);
|
||||||
db.SaveChanges();
|
db.SaveChanges();
|
||||||
dbAccessSemaphore.Release();
|
dbAccessSemaphore.Release();
|
||||||
}
|
}
|
||||||
@ -113,13 +140,48 @@ public static class Rememberer
|
|||||||
dbAccessSemaphore.Release();
|
dbAccessSemaphore.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void ForgetChannel(Channel toForget)
|
public static void ForgetAttachment(Attachment toForget)
|
||||||
{
|
{
|
||||||
|
dbAccessSemaphore.Wait();
|
||||||
|
db.Attachments.Remove(toForget);
|
||||||
|
db.SaveChanges();
|
||||||
|
dbAccessSemaphore.Release();
|
||||||
|
}
|
||||||
|
public static void ForgetChannel(Channel toForget)
|
||||||
|
{
|
||||||
|
if (toForget.SubChannels?.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var childChannel in toForget.SubChannels.ToList())
|
||||||
|
{
|
||||||
|
ForgetChannel(childChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toForget.Users?.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var account in toForget.Users.ToList())
|
||||||
|
{
|
||||||
|
ForgetAccount(account);
|
||||||
|
}
|
||||||
|
}
|
||||||
dbAccessSemaphore.Wait();
|
dbAccessSemaphore.Wait();
|
||||||
db.Channels.Remove(toForget);
|
db.Channels.Remove(toForget);
|
||||||
db.SaveChanges();
|
db.SaveChanges();
|
||||||
dbAccessSemaphore.Release();
|
dbAccessSemaphore.Release();
|
||||||
}
|
}
|
||||||
|
public static void ForgetMessage(Message toForget)
|
||||||
|
{
|
||||||
|
dbAccessSemaphore.Wait();
|
||||||
|
db.Messages.Remove(toForget);
|
||||||
|
db.SaveChanges();
|
||||||
|
dbAccessSemaphore.Release();
|
||||||
|
}
|
||||||
|
public static void ForgetUAC(UAC toForget)
|
||||||
|
{
|
||||||
|
dbAccessSemaphore.Wait();
|
||||||
|
db.UACs.Remove(toForget);
|
||||||
|
db.SaveChanges();
|
||||||
|
dbAccessSemaphore.Release();
|
||||||
|
}
|
||||||
public static void ForgetUser(User toForget)
|
public static void ForgetUser(User toForget)
|
||||||
{
|
{
|
||||||
dbAccessSemaphore.Wait();
|
dbAccessSemaphore.Wait();
|
||||||
@ -143,16 +205,52 @@ public static class Rememberer
|
|||||||
dbAccessSemaphore.Release();
|
dbAccessSemaphore.Release();
|
||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
public static Channel ChannelDetail(Guid Id)
|
public static Account AccountDetail(Guid Id)
|
||||||
{
|
{
|
||||||
Channel toReturn;
|
Account toReturn;
|
||||||
dbAccessSemaphore.Wait();
|
dbAccessSemaphore.Wait();
|
||||||
toReturn = db.Channels.Find(Id);
|
toReturn = db.Accounts.Find(Id);
|
||||||
|
dbAccessSemaphore.Release();
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
public static Attachment AttachmentDetail(Guid Id)
|
||||||
|
{
|
||||||
|
Attachment toReturn;
|
||||||
|
dbAccessSemaphore.Wait();
|
||||||
|
toReturn = db.Attachments.Find(Id);
|
||||||
|
dbAccessSemaphore.Release();
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
public static Channel ChannelDetail(Guid Id)
|
||||||
|
{
|
||||||
|
if(channelCacheDirty)
|
||||||
|
Task.Run(() => cacheChannels()).Wait();
|
||||||
|
return channels.Find(c => c.Id == Id);
|
||||||
|
}
|
||||||
|
public static Message MessageDetail(Guid Id)
|
||||||
|
{
|
||||||
|
Message toReturn;
|
||||||
|
dbAccessSemaphore.Wait();
|
||||||
|
toReturn = db.Messages.Find(Id);
|
||||||
|
db.Entry(toReturn).Reference(m => m.Channel).Load();
|
||||||
|
dbAccessSemaphore.Release();
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
public static UAC UACDetail(Guid Id)
|
||||||
|
{
|
||||||
|
UAC toReturn;
|
||||||
|
dbAccessSemaphore.Wait();
|
||||||
|
toReturn = db.UACs.Find(Id);
|
||||||
|
dbAccessSemaphore.Release();
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
public static User UserDetail(Guid Id)
|
||||||
|
{
|
||||||
|
User toReturn;
|
||||||
|
dbAccessSemaphore.Wait();
|
||||||
|
toReturn = db.Users.Find(Id);
|
||||||
dbAccessSemaphore.Release();
|
dbAccessSemaphore.Release();
|
||||||
return toReturn;
|
return toReturn;
|
||||||
// .Include(u => u.SubChannels)
|
|
||||||
// .Include(u => u.Users)
|
|
||||||
// .Include(u => u.ParentChannel);
|
|
||||||
}
|
}
|
||||||
public static List<User> UsersOverview()
|
public static List<User> UsersOverview()
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@ namespace vassago;
|
|||||||
using System;
|
using System;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using vassago.Models;
|
using vassago.Models;
|
||||||
|
using vassago.ProtocolInterfaces;
|
||||||
|
|
||||||
public static class Shared
|
public static class Shared
|
||||||
{
|
{
|
||||||
@ -12,4 +12,5 @@ public static class Shared
|
|||||||
public static HttpClient HttpClient { get; internal set; } = new HttpClient();
|
public static HttpClient HttpClient { get; internal set; } = new HttpClient();
|
||||||
public static bool SetupSlashCommands { get; set; }
|
public static bool SetupSlashCommands { get; set; }
|
||||||
public static Uri API_URL {get;set;}
|
public static Uri API_URL {get;set;}
|
||||||
|
public static List<ProtocolInterface> ProtocolList { get; set; } = new();
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,11 @@ public class ChannelsController() : Controller
|
|||||||
//but that would take in all the messages.
|
//but that would take in all the messages.
|
||||||
//realistically I expect this will have less than 1MB of total "channels", and several GB of total messages per (text) channel.
|
//realistically I expect this will have less than 1MB of total "channels", and several GB of total messages per (text) channel.
|
||||||
|
|
||||||
var channel = allChannels.First(u => u.Id == id);
|
var channel = allChannels.FirstOrDefault(u => u.Id == id);
|
||||||
|
if(channel == null)
|
||||||
|
{
|
||||||
|
return Problem("couldn't find that channle");
|
||||||
|
}
|
||||||
var walker = channel;
|
var walker = channel;
|
||||||
while(walker != null)
|
while(walker != null)
|
||||||
{
|
{
|
||||||
|
52
WebInterface/Controllers/api/AccountsController.cs
Normal file
52
WebInterface/Controllers/api/AccountsController.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using vassago.Models;
|
||||||
|
using vassago.ProtocolInterfaces.DiscordInterface;
|
||||||
|
|
||||||
|
namespace vassago.Controllers.api;
|
||||||
|
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class AccountsController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ILogger<AccountsController> _logger;
|
||||||
|
|
||||||
|
public AccountsController(ILogger<AccountsController> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
//microsoft: "you can't have multiple [FromBody]. The reason for this rule is some bullshti about storage buffers."
|
||||||
|
//cool story, bro. nobody gives a fuck, look at the boilerplate you've necessitated.
|
||||||
|
public class extraSpecialObjectReadGlorifiedTupleFor_UnlinkUser
|
||||||
|
{
|
||||||
|
public Guid acc_guid;
|
||||||
|
}
|
||||||
|
[HttpPatch]
|
||||||
|
[Route("UnlinkUser")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public IActionResult UnlinkUser([FromBody] extraSpecialObjectReadGlorifiedTupleFor_UnlinkUser req)
|
||||||
|
{
|
||||||
|
var acc_guid = req.acc_guid;
|
||||||
|
var accFromDb = Rememberer.SearchAccount(acc => acc.Id == acc_guid);
|
||||||
|
if (accFromDb == null)
|
||||||
|
{
|
||||||
|
var err = $"attempt to unlink user for acc {acc_guid}, not found";
|
||||||
|
_logger.LogError(err);
|
||||||
|
return NotFound(err);
|
||||||
|
}
|
||||||
|
var userFromDb = Rememberer.SearchUser(c => c.Id == accFromDb.IsUser.Id);
|
||||||
|
if (userFromDb == null)
|
||||||
|
{
|
||||||
|
var err = $"attempt to unlink user for {acc_guid}, doesn't have a user";
|
||||||
|
_logger.LogError(err);
|
||||||
|
return NotFound(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
accFromDb.IsUser = null;
|
||||||
|
|
||||||
|
Rememberer.RememberAccount(accFromDb);
|
||||||
|
return Ok(accFromDb);
|
||||||
|
}
|
||||||
|
}
|
@ -1,89 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using vassago.Models;
|
|
||||||
|
|
||||||
namespace vassago.Controllers.api;
|
|
||||||
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
[ApiController]
|
|
||||||
public class ChannelsController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ILogger<ChannelsController> _logger;
|
|
||||||
|
|
||||||
public ChannelsController(ILogger<ChannelsController> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
|
||||||
[Produces("application/json")]
|
|
||||||
public Channel Get(Guid id)
|
|
||||||
{
|
|
||||||
return Rememberer.ChannelDetail(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPatch]
|
|
||||||
[Produces("application/json")]
|
|
||||||
public IActionResult Patch([FromBody] Channel channel)
|
|
||||||
{
|
|
||||||
var fromDb = Rememberer.ChannelDetail(channel.Id);
|
|
||||||
if (fromDb == null)
|
|
||||||
{
|
|
||||||
_logger.LogError($"attempt to update channel {channel.Id}, not found");
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogDebug($"patching {channel.DisplayName} (id: {channel.Id})");
|
|
||||||
}
|
|
||||||
//settable values: lewdness filter level, meanness filter level. maybe i could decorate them...
|
|
||||||
fromDb.LewdnessFilterLevel = channel.LewdnessFilterLevel;
|
|
||||||
fromDb.MeannessFilterLevel = channel.MeannessFilterLevel;
|
|
||||||
Rememberer.RememberChannel(fromDb);
|
|
||||||
return Ok(fromDb);
|
|
||||||
}
|
|
||||||
[HttpDelete]
|
|
||||||
[Produces("application/json")]
|
|
||||||
public IActionResult Delete([FromBody] Channel channel)
|
|
||||||
{
|
|
||||||
var fromDb = Rememberer.ChannelDetail(channel.Id);
|
|
||||||
if (fromDb == null)
|
|
||||||
{
|
|
||||||
_logger.LogError($"attempt to delete channel {channel.Id}, not found");
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
deleteChannel(fromDb);
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
private void deleteChannel(Channel channel)
|
|
||||||
{
|
|
||||||
if (channel.SubChannels?.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var childChannel in channel.SubChannels)
|
|
||||||
{
|
|
||||||
deleteChannel(childChannel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(channel.Users?.Count > 0)
|
|
||||||
{
|
|
||||||
foreach(var account in channel.Users)
|
|
||||||
{
|
|
||||||
deleteAccount(account);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rememberer.ForgetChannel(channel);
|
|
||||||
}
|
|
||||||
private void deleteAccount(Account account)
|
|
||||||
{
|
|
||||||
var user = account.IsUser;
|
|
||||||
var usersOnlyAccount = user.Accounts?.Count == 1;
|
|
||||||
|
|
||||||
Rememberer.ForgetAccount(account);
|
|
||||||
|
|
||||||
if(usersOnlyAccount)
|
|
||||||
Rememberer.ForgetUser(user);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,53 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using vassago.Models;
|
||||||
|
using vassago.ProtocolInterfaces.DiscordInterface;
|
||||||
|
|
||||||
|
namespace vassago.Controllers.api;
|
||||||
|
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class InternalAPIProtocolController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ILogger<InternalAPIProtocolController> _logger;
|
||||||
|
|
||||||
|
public InternalAPIProtocolController(ILogger<InternalAPIProtocolController> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("PostMessage")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public IActionResult PostMessage(string messageText, Guid channelId)
|
||||||
|
{
|
||||||
|
return StatusCode(Behaver.Instance.SendMessage(channelId, messageText).Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("ReplyToMessage")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public IActionResult ReplyToMessage(string messageText, Guid repliedMessageId)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"ReplyToMessage - {repliedMessageId}, {messageText}");
|
||||||
|
return StatusCode(Behaver.Instance.Reply(repliedMessageId, messageText).Result);
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
[Route("SendFile")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public IActionResult SendFile(Guid channelId, string accompanyingText, string base64dData, string filename)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"SendFile- {channelId}, {filename} (base64'd, {base64dData?.Length} chars), {accompanyingText}");
|
||||||
|
return StatusCode(Behaver.Instance.SendFile(channelId, base64dData, filename, accompanyingText).Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("ReactToMessage")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public IActionResult ReactToMessage(string reactionString, Guid reactedMessageId)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"ReactToMessage- {reactedMessageId}, {reactionString}");
|
||||||
|
return StatusCode(Behaver.Instance.React(reactedMessageId, reactionString).Result);
|
||||||
|
}
|
||||||
|
}
|
214
WebInterface/Controllers/api/RemembererController.cs
Normal file
214
WebInterface/Controllers/api/RemembererController.cs
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using vassago.Models;
|
||||||
|
|
||||||
|
namespace vassago.Controllers.api;
|
||||||
|
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class RemembererController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ILogger<RemembererController> _logger;
|
||||||
|
|
||||||
|
public RemembererController(ILogger<RemembererController> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create
|
||||||
|
[HttpPut]
|
||||||
|
[Route("Account")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public Account CreateAccount(Guid id)
|
||||||
|
{
|
||||||
|
return Rememberer.AccountDetail(id);
|
||||||
|
}
|
||||||
|
[HttpPut]
|
||||||
|
[Route("Attachment")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public Attachment CreateAttachment(Guid id)
|
||||||
|
{
|
||||||
|
return Rememberer.AttachmentDetail(id);
|
||||||
|
}
|
||||||
|
[HttpPut]
|
||||||
|
[Route("Channels")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public Channel CreateChannel(Guid id)
|
||||||
|
{
|
||||||
|
return Rememberer.ChannelDetail(id);
|
||||||
|
}
|
||||||
|
[HttpPut]
|
||||||
|
[Route("Message")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public Message CreateMessage(Guid id)
|
||||||
|
{
|
||||||
|
return Rememberer.MessageDetail(id);
|
||||||
|
}
|
||||||
|
[HttpPut]
|
||||||
|
[Route("UAC")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public UAC CreateUAC(Guid id)
|
||||||
|
{
|
||||||
|
return Rememberer.UACDetail(id);
|
||||||
|
}
|
||||||
|
[HttpPut]
|
||||||
|
[Route("User")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public User CreateUser(Guid id)
|
||||||
|
{
|
||||||
|
return Rememberer.UserDetail(id);
|
||||||
|
}
|
||||||
|
//Read
|
||||||
|
[HttpGet]
|
||||||
|
[Route("Account")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public Account GetAccount(Guid id)
|
||||||
|
{
|
||||||
|
return Rememberer.AccountDetail(id);
|
||||||
|
}
|
||||||
|
[HttpGet]
|
||||||
|
[Route("Attachment")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public Attachment GetAttachment(Guid id)
|
||||||
|
{
|
||||||
|
return Rememberer.AttachmentDetail(id);
|
||||||
|
}
|
||||||
|
[HttpGet]
|
||||||
|
[Route("Channels")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public Channel GetChannel(Guid id)
|
||||||
|
{
|
||||||
|
return Rememberer.ChannelDetail(id);
|
||||||
|
}
|
||||||
|
[HttpGet]
|
||||||
|
[Route("Message")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public Message GetMessage(Guid id)
|
||||||
|
{
|
||||||
|
return Rememberer.MessageDetail(id);
|
||||||
|
}
|
||||||
|
[HttpGet]
|
||||||
|
[Route("UAC")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public UAC GetUAC(Guid id)
|
||||||
|
{
|
||||||
|
return Rememberer.UACDetail(id);
|
||||||
|
}
|
||||||
|
[HttpGet]
|
||||||
|
[Route("User")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public User GetUser(Guid id)
|
||||||
|
{
|
||||||
|
return Rememberer.UserDetail(id);
|
||||||
|
}
|
||||||
|
//Update
|
||||||
|
[HttpPatch]
|
||||||
|
[Route("Channels")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public IActionResult Patch([FromBody] Channel channel)
|
||||||
|
{
|
||||||
|
var fromDb = Rememberer.ChannelDetail(channel.Id);
|
||||||
|
if (fromDb == null)
|
||||||
|
{
|
||||||
|
_logger.LogError($"attempt to update channel {channel.Id}, not found");
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogDebug($"patching {channel.DisplayName} (id: {channel.Id})");
|
||||||
|
}
|
||||||
|
//settable values: lewdness filter level, meanness filter level. maybe i could decorate them...
|
||||||
|
fromDb.LewdnessFilterLevel = channel.LewdnessFilterLevel;
|
||||||
|
fromDb.MeannessFilterLevel = channel.MeannessFilterLevel;
|
||||||
|
Rememberer.RememberChannel(fromDb);
|
||||||
|
return Ok(fromDb);
|
||||||
|
}
|
||||||
|
//Delete
|
||||||
|
[HttpDelete]
|
||||||
|
[Route("Account")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public IActionResult DeleteAccount(Guid id)
|
||||||
|
{
|
||||||
|
var fromDb = Rememberer.AccountDetail(id);
|
||||||
|
if (fromDb == null)
|
||||||
|
{
|
||||||
|
_logger.LogError($"attempt to delete account {id}, not found");
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
Rememberer.ForgetAccount(fromDb);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
[HttpDelete]
|
||||||
|
[Route("Attachment")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public IActionResult DeleteAttachment(Guid id)
|
||||||
|
{
|
||||||
|
var fromDb = Rememberer.AttachmentDetail(id);
|
||||||
|
if (fromDb == null)
|
||||||
|
{
|
||||||
|
_logger.LogError($"attempt to delete attachment {id}, not found");
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
Rememberer.ForgetAttachment(fromDb);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
[HttpDelete]
|
||||||
|
[Route("Channels/{id}")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public IActionResult DeleteChannel(Guid id)
|
||||||
|
{
|
||||||
|
var fromDb = Rememberer.ChannelDetail(id);
|
||||||
|
_logger.LogDebug($"delete channel {id}");
|
||||||
|
if (fromDb == null)
|
||||||
|
{
|
||||||
|
_logger.LogError($"attempt to delete channel {id}, not found");
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
Rememberer.ForgetChannel(fromDb);
|
||||||
|
_logger.LogDebug($"delete channel {id} success");
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
[HttpDelete]
|
||||||
|
[Route("Message/{id}")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public IActionResult DeleteMessage(Guid id)
|
||||||
|
{
|
||||||
|
var fromDb = Rememberer.MessageDetail(id);
|
||||||
|
if (fromDb == null)
|
||||||
|
{
|
||||||
|
_logger.LogError($"attempt to delete message {id}, not found");
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
Rememberer.ForgetMessage(fromDb);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
[HttpDelete]
|
||||||
|
[Route("UAC/{id}")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public IActionResult DeleteUAC(Guid id)
|
||||||
|
{
|
||||||
|
var fromDb = Rememberer.UACDetail(id);
|
||||||
|
if (fromDb == null)
|
||||||
|
{
|
||||||
|
_logger.LogError($"attempt to delete uac {id}, not found");
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
Rememberer.ForgetUAC(fromDb);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
[HttpDelete]
|
||||||
|
[Route("User/{id}")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
public IActionResult DeleteUser(Guid id)
|
||||||
|
{
|
||||||
|
var fromDb = Rememberer.UserDetail(id);
|
||||||
|
if (fromDb == null)
|
||||||
|
{
|
||||||
|
_logger.LogError($"attempt to delete user {id}, not found");
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
Rememberer.ForgetUser(fromDb);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
}
|
@ -1,40 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using vassago.Models;
|
|
||||||
using vassago.ProtocolInterfaces.DiscordInterface;
|
|
||||||
|
|
||||||
namespace vassago.Controllers.api;
|
|
||||||
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
[ApiController]
|
|
||||||
public class UsersController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ILogger<ChannelsController> _logger;
|
|
||||||
|
|
||||||
public UsersController(ILogger<ChannelsController> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPatch]
|
|
||||||
[Produces("application/json")]
|
|
||||||
public IActionResult Patch([FromBody] User user)
|
|
||||||
{
|
|
||||||
var fromDb = Rememberer.SearchUser(u => u.Id == user.Id);
|
|
||||||
if (fromDb == null)
|
|
||||||
{
|
|
||||||
_logger.LogError($"attempt to update user {user.Id}, not found");
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogDebug($"patching {user.DisplayName} (id: {user.Id})");
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: settable values: display name
|
|
||||||
//fromDb.DisplayName = user.DisplayName;
|
|
||||||
Rememberer.RememberUser(fromDb);
|
|
||||||
return Ok(fromDb);
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,19 +8,23 @@
|
|||||||
<a href="/">home</a>/@Html.Raw(ViewData["breadcrumbs"])
|
<a href="/">home</a>/@Html.Raw(ViewData["breadcrumbs"])
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>Id</th>
|
||||||
|
<td>@Model.Id</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">belongs to user</th>
|
<th scope="row">belongs to user</th>
|
||||||
<td>@Model.IsUser.DisplayName</td>
|
<td>@Model.IsUser.DisplayName</td>
|
||||||
<td><button alt="to do" disabled>separate</button></2td>
|
<td><button onclick="unlinkAccountUser(() => { window.location.reload(); })">separate</button></2td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Seen in channel</th>
|
<th scope="row">Seen in channel</th>
|
||||||
<td class="account @Model.SeenInChannel.Protocol"><div class="protocol-icon"> </div>@Model.SeenInChannel.LineageSummary<a href="/Channels/Details/@Model.SeenInChannel.Id">@Model.SeenInChannel.DisplayName</a></td>
|
<td class="account @Model.SeenInChannel.Protocol"><div class="protocol-icon"> </div>@Model.SeenInChannel.LineageSummary<a href="/Channels/Details/@Model.SeenInChannel.Id">@Model.SeenInChannel.DisplayName</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Permission Tags</th>
|
<th scope="row">UACs tied to account</th>
|
||||||
<td>
|
<td>
|
||||||
<div id="tagsTree"></div>
|
<div id="uacsTree"></div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -44,10 +48,10 @@
|
|||||||
return userNow;
|
return userNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTagsTree() {
|
function getUacsTree() {
|
||||||
@{
|
@{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.Append("[{text: \"permission tags\", \"expanded\":true, nodes: [");
|
sb.Append("[{text: \"UACs\", \"expanded\":true, nodes: [");
|
||||||
var first = true;
|
var first = true;
|
||||||
for (int i = 0; i < 1; i++)
|
for (int i = 0; i < 1; i++)
|
||||||
{
|
{
|
||||||
@ -62,7 +66,7 @@
|
|||||||
var tree = @Html.Raw(sb.ToString());
|
var tree = @Html.Raw(sb.ToString());
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
$('#tagsTree').bstreeview({ data: getTagsTree() });
|
$('#uacsTree').bstreeview({ data: getUacsTree() });
|
||||||
document.querySelectorAll("input[type=checkbox]").forEach(node => { node.onchange = () => { patchModel(jsonifyUser(), '/api/Users/') } });
|
//document.querySelectorAll("input[type=checkbox]").forEach(node => { node.onchange = () => { patchModel(jsonifyUser(), '/api/Users/') } });
|
||||||
</script>
|
</script>
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Lewdness Filter Level</th>
|
<th scope="row">Lewdness Filter Level</th>
|
||||||
<td>
|
<td>
|
||||||
<select name="LewdnessFilterLevel" id="LewdnessFilterLevel" onchange="patchModel(jsonifyChannel(), '/api/Channels/')">
|
<select name="LewdnessFilterLevel" id="LewdnessFilterLevel" onchange="patchModel(jsonifyChannel())">
|
||||||
<!option value="" @(ThisChannel.LewdnessFilterLevel == null ? "selected" : "")>⤵ inherited - @Enumerations.GetDescription(IfInheritedLewdnessFilterLevel)</!option>
|
<!option value="" @(ThisChannel.LewdnessFilterLevel == null ? "selected" : "")>⤵ inherited - @Enumerations.GetDescription(IfInheritedLewdnessFilterLevel)</!option>
|
||||||
@foreach (Enumerations.LewdnessFilterLevel enumVal in
|
@foreach (Enumerations.LewdnessFilterLevel enumVal in
|
||||||
Enum.GetValues(typeof(Enumerations.LewdnessFilterLevel)))
|
Enum.GetValues(typeof(Enumerations.LewdnessFilterLevel)))
|
||||||
@ -54,7 +54,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Meanness Filter Level</th>
|
<th scope="row">Meanness Filter Level</th>
|
||||||
<td>
|
<td>
|
||||||
<select name="MeannessFilterLevel" id="MeannessFilterLevel" onchange="patchModel(jsonifyChannel(), '/api/Channels/')">
|
<select name="MeannessFilterLevel" id="MeannessFilterLevel" onchange="patchModel(jsonifyChannel())">
|
||||||
<!option value="" @(ThisChannel.MeannessFilterLevel == null ? "selected" : "")>⤵ inherited - @Enumerations.GetDescription(IfInheritedMeannessFilterLevel)</!option>
|
<!option value="" @(ThisChannel.MeannessFilterLevel == null ? "selected" : "")>⤵ inherited - @Enumerations.GetDescription(IfInheritedMeannessFilterLevel)</!option>
|
||||||
@foreach (Enumerations.MeannessFilterLevel enumVal in
|
@foreach (Enumerations.MeannessFilterLevel enumVal in
|
||||||
Enum.GetValues(typeof(Enumerations.MeannessFilterLevel)))
|
Enum.GetValues(typeof(Enumerations.MeannessFilterLevel)))
|
||||||
@ -135,7 +135,7 @@
|
|||||||
function forget(){
|
function forget(){
|
||||||
console.log("here we go");
|
console.log("here we go");
|
||||||
if(window.confirm("delete? really really?") == true){
|
if(window.confirm("delete? really really?") == true){
|
||||||
deleteModel(jsonifyChannel(), '/api/Channels/');
|
deleteModel(jsonifyChannel().Id, window.history.back);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +149,7 @@
|
|||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.Append("[{text: \"accounts\", \"expanded\":true, nodes: [");
|
sb.Append("[{text: \"accounts\", \"expanded\":true, nodes: [");
|
||||||
var first = true;
|
var first = true;
|
||||||
foreach (var acc in ThisChannel.Users.OrderBy(a => a.SeenInChannel.LineageSummary))
|
foreach (var acc in ThisChannel.Users?.OrderBy(a => a?.SeenInChannel?.LineageSummary))
|
||||||
{
|
{
|
||||||
if(!first)
|
if(!first)
|
||||||
sb.Append(',');
|
sb.Append(',');
|
||||||
|
@ -12,6 +12,10 @@
|
|||||||
<th scope="row">Display Name</th>
|
<th scope="row">Display Name</th>
|
||||||
<td>@Model.DisplayName</td>
|
<td>@Model.DisplayName</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Description</th>
|
||||||
|
<td>@Html.Raw(Model.Description)
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Channels</th>
|
<th scope="row">Channels</th>
|
||||||
<td>
|
<td>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Display Name (here)</th>
|
<th scope="row">Display Name (here)</th>
|
||||||
<td><input type="text" id="displayName" value="@Model.DisplayName" disabled alt="todo"></input> <button
|
<td><input type="text" id="displayName" value="@Model.DisplayName" disabled alt="todo"></input> <button
|
||||||
onclick="patchModel(jsonifyUser(), @Html.Raw("'/api/Users/'"))" disabled alt"todo">update</button></td>
|
onclick="patchModel(jsonifyUser())" disabled alt"todo">update</button></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Accounts</th>
|
<th scope="row">Accounts</th>
|
||||||
@ -60,6 +60,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$('#accountsTree').bstreeview({ data: getAccountsTree() });
|
$('#accountsTree').bstreeview({ data: getAccountsTree() });
|
||||||
document.querySelectorAll("input[type=checkbox]").forEach(node => { node.onchange = () => { patchModel(jsonifyUser(), '/api/Users/') } });
|
document.querySelectorAll("input[type=checkbox]").forEach(node => { node.onchange = () => { patchModel(jsonifyUser()) } });
|
||||||
</script>
|
</script>
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,13 @@
|
|||||||
{
|
{
|
||||||
"uacID": "9a94855a-e5a2-43b5-8420-ce670472ce95",
|
"uacID": "9a94855a-e5a2-43b5-8420-ce670472ce95",
|
||||||
"Trigger": "test",
|
"Trigger": "test",
|
||||||
"Uri": "http://localhost"
|
"Description": "<i>test</i>",
|
||||||
|
"Uri": "http://localhost",
|
||||||
|
"Method": "POST",
|
||||||
|
"Headers": [
|
||||||
|
["Content-Type", "application/json"]
|
||||||
|
],
|
||||||
|
"Content": "{\"content\": \"Hello, this is a message from my webhook: {text}. username: {account}, user: {user}\"}"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"KafkaBootstrap":"http://localhost:9092",
|
"KafkaBootstrap":"http://localhost:9092",
|
||||||
|
@ -3,7 +3,11 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<NoWarn>$(NoWarn);CA2254</NoWarn>
|
<NoWarn>$(NoWarn);CS1998;CS4014</NoWarn>
|
||||||
|
<!-- CS1998: "This async method lacks 'await' operators and will run synchronously." -->
|
||||||
|
<!-- CS4014: "Because this call is not awaited, execution of the current method continues before the call is completed."-->
|
||||||
|
<!-- those 2 cancel out. Async foo calls async Bar, foo doesn't say "await" so cs1998 says "well don't mark foo as async" and cs4014 says "you should awake bar".
|
||||||
|
what, you want me to just add bar to some big stupid task list that I don't care about anyway? -->
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ function Account(displayName, accountId, protocol){
|
|||||||
//todo: figure out what the URL actually needs to be, rather than assuming you get a whole-ass server to yourself.
|
//todo: figure out what the URL actually needs to be, rather than assuming you get a whole-ass server to yourself.
|
||||||
//you selfish fuck... What are you, fox?
|
//you selfish fuck... What are you, fox?
|
||||||
//as it stands, you want something like /api/Channels/, trailing slash intentional
|
//as it stands, you want something like /api/Channels/, trailing slash intentional
|
||||||
function patchModel(model, deprecated_apiUrl)
|
function patchModel(model, callback)
|
||||||
{
|
{
|
||||||
//structure the model your (dang) self into a nice object
|
//structure the model your (dang) self into a nice object
|
||||||
console.log(model);
|
console.log(model);
|
||||||
@ -22,7 +22,7 @@ function patchModel(model, deprecated_apiUrl)
|
|||||||
// var id=components[3];
|
// var id=components[3];
|
||||||
|
|
||||||
console.log(JSON.stringify(model));
|
console.log(JSON.stringify(model));
|
||||||
fetch(apiUrl + type + '/', {
|
fetch(apiUrl + 'Rememberer/' + type + '/', {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@ -44,22 +44,17 @@ function patchModel(model, deprecated_apiUrl)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteModel(model, deprecated_apiUrl)
|
function deleteModel(id, callback)
|
||||||
{
|
{
|
||||||
var components = window.location.pathname.split('/');
|
var components = window.location.pathname.split('/');
|
||||||
// if(components[2] !== "Details")
|
|
||||||
// {
|
|
||||||
// console.log("wtf are you doing? " + components[2] + " is something other than Details");
|
|
||||||
// }
|
|
||||||
var type=components[1];
|
var type=components[1];
|
||||||
let result = null;
|
let result = null;
|
||||||
// var id=components[3];
|
var id=components[3];
|
||||||
fetch(apiUrl + type + '/', {
|
fetch(apiUrl + 'Rememberer/' + type + '/' + id, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
}
|
||||||
body: JSON.stringify(model),
|
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@ -246,3 +241,31 @@ function unlinkUAC_Channel(user_guid, callback)
|
|||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
//give me account, we'll tear it off from user.
|
||||||
|
function unlinkAccountUser(callback)
|
||||||
|
{
|
||||||
|
var components = window.location.pathname.split('/');
|
||||||
|
var id=components[3];
|
||||||
|
let model={"acc_guid": id};
|
||||||
|
fetch(apiUrl + "Accounts/UnlinkUser/", {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(model),
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Network response was not "ok". which is not ok.');
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(returnedSuccessdata => {
|
||||||
|
// perhaps a success callback
|
||||||
|
console.log('returnedSuccessdata:', returnedSuccessdata);
|
||||||
|
if(callback !== null) { callback(); }
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user