Compare commits
72 Commits
Author | SHA1 | Date | |
---|---|---|---|
0d0d377a05 | |||
ab16600463 | |||
af4d68caa1 | |||
0ac28c35fb | |||
942b11fcce | |||
4bd51721b6 | |||
e364b47c0f | |||
c6ea3ef790 | |||
2f7bc2c0ea | |||
43eaa5ad0d | |||
b4b5544ec4 | |||
c446521977 | |||
54414b8748 | |||
8cb4005192 | |||
cd2fa384d5 | |||
f4bed1e6cb | |||
88ca468708 | |||
464b6a90e4 | |||
581fddf6f9 | |||
bed8d3cbef | |||
2dd9e903db | |||
ef31418166 | |||
6d181e2b68 | |||
10167b597a | |||
26d8373dc8 | |||
a63a3fcb58 | |||
b84e47344b | |||
c5f9ae2c6b | |||
efb4ab00d2 | |||
451ace753d | |||
894b536c04 | |||
ba2254858f | |||
c1e32ef39a | |||
5fb96ea67e | |||
1fd2a4723e | |||
51fb08810d | |||
423fe5cb96 | |||
23e18f2028 | |||
9d3917a030 | |||
391ba38cce | |||
d060e92ed9 | |||
77fc26e1ed | |||
edc86af538 | |||
39781397c3 | |||
e89c109970 | |||
e7b70468ae | |||
47f382df19 | |||
8c6087d557 | |||
da7078f535 | |||
e9ddcd237c | |||
4a60e53798 | |||
5bb64f764c | |||
986d433886 | |||
c393f657d1 | |||
6037adcb44 | |||
2fc199d4b6 | |||
a8d1fc8d6e | |||
91bcfae1ba | |||
115035eb91 | |||
147cba7cd3 | |||
66b425cd39 | |||
e433e56fec | |||
a1d2ec83b5 | |||
3a4a6df087 | |||
567a59550e | |||
f23474ad51 | |||
d2aa1f46cc | |||
51fba995c3 | |||
e4f7d88e35 | |||
3031779e24 | |||
bfe7f582b2 | |||
a87fcd6ad9 |
12
.config/dotnet-tools.json
Normal file
12
.config/dotnet-tools.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "7.0.5",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
appsettings.json
|
||||
appsettings.Development.json
|
||||
assets/exchangepairs.json
|
||||
|
||||
# ---> VisualStudio
|
||||
|
19
.vscode/launch.json
vendored
19
.vscode/launch.json
vendored
@ -5,17 +5,26 @@
|
||||
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||
// Use hover for the description of the existing attributes
|
||||
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||
"name": ".NET Core Launch (console)",
|
||||
"name": ".NET Core Launch (web)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/bin/Debug/net7.0/shtikbot-discord.dll",
|
||||
"program": "${workspaceFolder}/bin/Debug/net7.0/vassago.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
"stopAtEntry": false,
|
||||
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||
},
|
||||
"env": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/Views": "${workspaceFolder}/Views"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
|
9
.vscode/tasks.json
vendored
9
.vscode/tasks.json
vendored
@ -7,7 +7,7 @@
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/shtikbot-discord.csproj",
|
||||
"${workspaceFolder}/vassago.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
@ -19,7 +19,7 @@
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/shtikbot-discord.csproj",
|
||||
"${workspaceFolder}/vassago.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
@ -32,9 +32,8 @@
|
||||
"args": [
|
||||
"watch",
|
||||
"run",
|
||||
"${workspaceFolder}/shtikbot-discord.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
"--project",
|
||||
"${workspaceFolder}/vassago.csproj"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
|
124
Behaver.cs
Normal file
124
Behaver.cs
Normal file
@ -0,0 +1,124 @@
|
||||
namespace vassago;
|
||||
#pragma warning disable 4014 //the "not awaited" error
|
||||
using vassago.Behavior;
|
||||
using vassago.Models;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class Behaver
|
||||
{
|
||||
private List<Account> SelfAccounts { get; set; } = new List<Account>();
|
||||
private User SelfUser { get; set; }
|
||||
public static List<vassago.Behavior.Behavior> Behaviors { get; private set; } = new List<vassago.Behavior.Behavior>();
|
||||
internal Behaver()
|
||||
{
|
||||
var subtypes = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(domainAssembly => domainAssembly.GetTypes())
|
||||
.Where(type => type.IsSubclassOf(typeof(vassago.Behavior.Behavior)) && !type.IsAbstract &&
|
||||
type.GetCustomAttributes(typeof(StaticPlzAttribute),false)?.Any() == true)
|
||||
.ToList();
|
||||
|
||||
foreach (var subtype in subtypes)
|
||||
{
|
||||
Behaviors.Add((vassago.Behavior.Behavior)Activator.CreateInstance(subtype));
|
||||
}
|
||||
}
|
||||
static Behaver() { }
|
||||
|
||||
private static readonly Behaver _instance = new Behaver();
|
||||
|
||||
public static Behaver Instance
|
||||
{
|
||||
get { return _instance; }
|
||||
}
|
||||
|
||||
public async Task<bool> ActOn(Message message)
|
||||
{
|
||||
foreach (var behavior in Behaviors)
|
||||
{
|
||||
if (behavior.ShouldAct(message))
|
||||
{
|
||||
behavior.ActOn(message);
|
||||
message.ActedOn = true;
|
||||
Console.WriteLine("acted on, moving forward");
|
||||
}
|
||||
}
|
||||
if (message.ActedOn == false && message.MentionsMe && message.Content.Contains('?') && !Behaver.Instance.SelfAccounts.Any(acc => acc.Id == message.Author.Id))
|
||||
{
|
||||
Console.WriteLine("providing bullshit nonanswer / admitting uselessness");
|
||||
var responses = new List<string>(){
|
||||
@"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)]);
|
||||
message.ActedOn = true;
|
||||
}
|
||||
return message.ActedOn;
|
||||
}
|
||||
|
||||
internal bool IsSelf(Guid AccountId)
|
||||
{
|
||||
var db = new ChattingContext();
|
||||
var acc = db.Accounts.Find(AccountId);
|
||||
|
||||
return SelfAccounts.Any(acc => acc.Id == AccountId);
|
||||
}
|
||||
|
||||
public void MarkSelf(Account selfAccount)
|
||||
{
|
||||
var db = new ChattingContext();
|
||||
if(SelfUser == null)
|
||||
{
|
||||
SelfUser = selfAccount.IsUser;
|
||||
}
|
||||
else if (SelfUser != selfAccount.IsUser)
|
||||
{
|
||||
CollapseUsers(SelfUser, selfAccount.IsUser, db);
|
||||
}
|
||||
SelfAccounts = db.Accounts.Where(a => a.IsUser == SelfUser).ToList();
|
||||
}
|
||||
|
||||
public bool CollapseUsers(User primary, User secondary, ChattingContext db)
|
||||
{
|
||||
Console.WriteLine($"{secondary.Id} is being consumed into {primary.Id}");
|
||||
primary.Accounts.AddRange(secondary.Accounts);
|
||||
foreach(var a in secondary.Accounts)
|
||||
{
|
||||
a.IsUser = primary;
|
||||
}
|
||||
secondary.Accounts.Clear();
|
||||
Console.WriteLine("accounts transferred");
|
||||
try
|
||||
{
|
||||
db.SaveChangesAsync().Wait();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Console.WriteLine("First save exception.");
|
||||
Console.Error.WriteLine(e);
|
||||
return false;
|
||||
}
|
||||
Console.WriteLine("saved");
|
||||
|
||||
|
||||
db.Users.Remove(secondary);
|
||||
Console.WriteLine("old account cleaned up");
|
||||
try
|
||||
{
|
||||
db.SaveChangesAsync().Wait();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Console.WriteLine("Second save exception.");
|
||||
Console.Error.WriteLine(e);
|
||||
return false;
|
||||
}
|
||||
Console.WriteLine("saved, again, separately");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#pragma warning restore 4014 //the "async not awaited" error
|
31
Behavior/Behavior.cs
Normal file
31
Behavior/Behavior.cs
Normal file
@ -0,0 +1,31 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using vassago.Models;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public abstract class Behavior
|
||||
{
|
||||
public abstract Task<bool> ActOn(Message message);
|
||||
|
||||
public virtual bool ShouldAct(Message message)
|
||||
{
|
||||
if(Behaver.Instance.IsSelf(message.Author.Id))
|
||||
return false;
|
||||
return Regex.IsMatch(message.Content, $"{Trigger}\\b", RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
public abstract string Name { get; }
|
||||
public abstract string Trigger { get; }
|
||||
public virtual string Description => Name;
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///the behavior should be static. I.e., we make one at the start and it's ready to check and go for the whole lifetime.
|
||||
///As opposed to LaughAtOwnJoke, which only needs to be created to wait for 1 punchline one time.
|
||||
///</summary>
|
||||
public class StaticPlzAttribute : Attribute {}
|
25
Behavior/ChatGPTSnark.cs
Normal file
25
Behavior/ChatGPTSnark.cs
Normal file
@ -0,0 +1,25 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using vassago.Models;
|
||||
|
||||
[StaticPlz]
|
||||
public class ChatGPTSnark : Behavior
|
||||
{
|
||||
public override string Name => "ChatGPTSnark";
|
||||
|
||||
public override string Trigger => "chatgpt";
|
||||
|
||||
public override string Description => "snarkiness about the latest culty-fixation in ai";
|
||||
|
||||
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?");
|
||||
return true;
|
||||
}
|
||||
}
|
34
Behavior/DefinitionSnarkCogDiss.cs
Normal file
34
Behavior/DefinitionSnarkCogDiss.cs
Normal file
@ -0,0 +1,34 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using vassago.Models;
|
||||
using static vassago.Models.Enumerations;
|
||||
|
||||
[StaticPlz]
|
||||
public class DefinitionSnarkCogDiss : Behavior
|
||||
{
|
||||
public override string Name => "Definition Snarkiness: cognitivie dissonance";
|
||||
|
||||
public override string Trigger => "\\bcognitive dissonance";
|
||||
|
||||
public override string Description => "snarkiness about the rampant misuse of the term cognitive dissonance";
|
||||
|
||||
public override bool ShouldAct(Message message)
|
||||
{
|
||||
if((MeannessFilterLevel)message.Channel.EffectivePermissions.MeannessFilterLevel < MeannessFilterLevel.Medium)
|
||||
return false;
|
||||
|
||||
return base.ShouldAct(message);
|
||||
}
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
await message.Reply("that's not what cognitive dissonance means. Did you mean \"hypocrisy\"?");
|
||||
return true;
|
||||
}
|
||||
}
|
34
Behavior/DefinitionSnarkGaslight.cs
Normal file
34
Behavior/DefinitionSnarkGaslight.cs
Normal file
@ -0,0 +1,34 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using vassago.Models;
|
||||
using static vassago.Models.Enumerations;
|
||||
|
||||
[StaticPlz]
|
||||
public class DefinitionSnarkGaslight : Behavior
|
||||
{
|
||||
public override string Name => "Definition Snarkiness: gaslighting";
|
||||
|
||||
public override string Trigger => "\\bgaslight(ing)?";
|
||||
|
||||
public override string Description => "snarkiness about the rampant misuse of the term gaslighting";
|
||||
|
||||
public override bool ShouldAct(Message message)
|
||||
{
|
||||
if((MeannessFilterLevel)message.Channel.EffectivePermissions.MeannessFilterLevel < MeannessFilterLevel.Unrestricted)
|
||||
return false;
|
||||
|
||||
return base.ShouldAct(message);
|
||||
}
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
await message.Channel.SendMessage("that's not what gaslight means. Did you mean \"deceive\"?");
|
||||
return true;
|
||||
}
|
||||
}
|
113
Behavior/Detiktokify.cs
Normal file
113
Behavior/Detiktokify.cs
Normal file
@ -0,0 +1,113 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using vassago.Models;
|
||||
|
||||
[StaticPlz]
|
||||
public class Detiktokify : Behavior
|
||||
{
|
||||
public override string Name { get => "Detiktokify"; }
|
||||
public override string Trigger { get => "post a link below vm.tiktok.com"; }
|
||||
public override string Description { get => "re-host tiktok content"; }
|
||||
|
||||
private List<Uri> tiktokLinks = new List<Uri>();
|
||||
private YoutubeDLSharp.YoutubeDL ytdl;
|
||||
public Detiktokify()
|
||||
{
|
||||
ytdl = new YoutubeDLSharp.YoutubeDL();
|
||||
ytdl.YoutubeDLPath = "yt-dlp";
|
||||
ytdl.FFmpegPath = "ffmpeg";
|
||||
ytdl.OutputFolder = "";
|
||||
ytdl.OutputFileTemplate = "tiktokbad.%(ext)s";
|
||||
}
|
||||
public override bool ShouldAct(Message message)
|
||||
{
|
||||
|
||||
if(Behaver.Instance.IsSelf(message.Author.Id))
|
||||
return false;
|
||||
|
||||
if(message.Channel.EffectivePermissions.MaxAttachmentBytes == 0)
|
||||
return false;
|
||||
|
||||
var wordLikes = message.Content.Split(' ', StringSplitOptions.TrimEntries);
|
||||
var possibleLinks = wordLikes?.Where(wl => Uri.IsWellFormedUriString(wl, UriKind.Absolute)).Select(wl => new Uri(wl));
|
||||
if (possibleLinks != null && possibleLinks.Count() > 0)
|
||||
{
|
||||
foreach (var link in possibleLinks)
|
||||
{
|
||||
if (link.Host.EndsWith(".tiktok.com"))
|
||||
{
|
||||
tiktokLinks.Add(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(tiktokLinks.Any()){
|
||||
Console.WriteLine($"Should Act on message id {message.ExternalId}; with content {message.Content}");
|
||||
}
|
||||
return tiktokLinks.Any();
|
||||
}
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
foreach(var link in tiktokLinks)
|
||||
{
|
||||
tiktokLinks.Remove(link);
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"detiktokifying {link}");
|
||||
#pragma warning disable 4014
|
||||
//await message.React("<:tiktok:1070038619584200884>");
|
||||
#pragma warning restore 4014
|
||||
|
||||
var res = await ytdl.RunVideoDownload(link.ToString());
|
||||
if (!res.Success)
|
||||
{
|
||||
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");
|
||||
}
|
||||
else
|
||||
{
|
||||
string path = res.Data;
|
||||
if (File.Exists(path))
|
||||
{
|
||||
ulong bytesize = (ulong)((new System.IO.FileInfo(path)).Length);
|
||||
if (bytesize < message.Channel.EffectivePermissions.MaxAttachmentBytes - 256)
|
||||
{
|
||||
try
|
||||
{
|
||||
await message.Channel.SendFile(path, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
System.Console.Error.WriteLine(e);
|
||||
await message.Channel.SendMessage($"aaaadam!\n{e}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
message.ActedOn = true;
|
||||
Console.WriteLine($"file appears too big ({bytesize} bytes ({bytesize / (1024 * 1024)}MB)), not posting");
|
||||
}
|
||||
File.Delete(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error.WriteLine("idgi but something happened.");
|
||||
await message.React("problemon");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.Error.WriteLine(e);
|
||||
await message.React("problemon");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
87
Behavior/FiximageHeic.cs
Normal file
87
Behavior/FiximageHeic.cs
Normal file
@ -0,0 +1,87 @@
|
||||
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;
|
||||
|
||||
[StaticPlz]
|
||||
public class FiximageHeic : Behavior
|
||||
{
|
||||
public override string Name => "deheic";
|
||||
|
||||
public override string Trigger => "post an heic image";
|
||||
|
||||
public override string Description => "convert heic images to jpg";
|
||||
|
||||
private List<Attachment> heics = new List<Attachment>();
|
||||
public override bool ShouldAct(Message message)
|
||||
{
|
||||
if(Behaver.Instance.IsSelf(message.Author.Id))
|
||||
return false;
|
||||
|
||||
if (message.Attachments?.Count() > 0)
|
||||
{
|
||||
foreach (var att in message.Attachments)
|
||||
{
|
||||
if (att.Filename?.EndsWith(".heic") == true)
|
||||
{
|
||||
heics.Add(att);
|
||||
}
|
||||
}
|
||||
}
|
||||
return heics.Any();
|
||||
}
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
if (!Directory.Exists("tmp"))
|
||||
{
|
||||
Directory.CreateDirectory("tmp");
|
||||
}
|
||||
var conversions = new List<Task<bool>>();
|
||||
foreach (var att in heics)
|
||||
{
|
||||
conversions.Add(actualDeheic(att, message));
|
||||
}
|
||||
Task.WaitAll(conversions.ToArray());
|
||||
await message.React("\U0001F34F");
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<bool> actualDeheic(Attachment att, Message message)
|
||||
{
|
||||
try
|
||||
{
|
||||
var cancellationTokenSource = new CancellationTokenSource();
|
||||
CancellationToken token = cancellationTokenSource.Token;
|
||||
using (Stream output = File.OpenWrite("tmp/" + att.Filename))
|
||||
{
|
||||
(await Shared.HttpClient.GetAsync(att.Source))
|
||||
.Content.CopyTo(output, null, token);
|
||||
}
|
||||
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");
|
||||
File.Delete($"tmp/{att.Filename}");
|
||||
File.Delete($"tmp/{att.Filename}.jpg");
|
||||
}
|
||||
else
|
||||
{
|
||||
await message.Channel.SendMessage("convert failed :(");
|
||||
Console.Error.WriteLine("convert failed :(");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await message.Channel.SendMessage($"something failed. aaaadam! {JsonConvert.SerializeObject(e, Formatting.Indented)}");
|
||||
Console.Error.WriteLine(JsonConvert.SerializeObject(e, Formatting.Indented));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
50
Behavior/GeneralSnarkCloudNative.cs
Normal file
50
Behavior/GeneralSnarkCloudNative.cs
Normal file
@ -0,0 +1,50 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using vassago.Models;
|
||||
using static vassago.Models.Enumerations;
|
||||
|
||||
[StaticPlz]
|
||||
public class GeneralSnarkCloudNative : Behavior
|
||||
{
|
||||
public override string Name => "general snarkiness: cloud native";
|
||||
|
||||
public override string Trigger => "certain tech buzzwords that no human uses in normal conversation";
|
||||
public override bool ShouldAct(Message message)
|
||||
{
|
||||
if(Behaver.Instance.IsSelf(message.Author.Id))
|
||||
return false;
|
||||
|
||||
if(message.Channel.EffectivePermissions.ReactionsPossible)
|
||||
return false;
|
||||
|
||||
if((MeannessFilterLevel)message.Channel.EffectivePermissions.MeannessFilterLevel < MeannessFilterLevel.Medium)
|
||||
return false;
|
||||
|
||||
return Regex.IsMatch(message.Content, "\\bcloud( |-)?native\\b", RegexOptions.IgnoreCase) ||
|
||||
Regex.IsMatch(message.Content, "\\benterprise( |-)?(level|solution)\\b", RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
switch (Shared.r.Next(2))
|
||||
{
|
||||
case 0:
|
||||
await message.React("\uD83E\uDD2E"); //vomit emoji
|
||||
break;
|
||||
case 1:
|
||||
await message.React("\uD83C\uDDE7"); //B emoji
|
||||
await message.React("\uD83C\uDDE6"); //A
|
||||
await message.React("\uD83C\uDDF3"); //N
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
68
Behavior/GeneralSnarkGooglit.cs
Normal file
68
Behavior/GeneralSnarkGooglit.cs
Normal file
@ -0,0 +1,68 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.RegularExpressions;
|
||||
using vassago.Models;
|
||||
|
||||
[StaticPlz]
|
||||
public class GeneralSnarkGooglit : Behavior
|
||||
{
|
||||
public override string Name => "Google-it Snarkiness";
|
||||
|
||||
public override string Trigger => "\"just google it\"";
|
||||
|
||||
public override string Description => "snarkiness about how research is not a solved problem";
|
||||
|
||||
public override bool ShouldAct(Message message)
|
||||
{
|
||||
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);
|
||||
// }
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
switch (Shared.r.Next(4))
|
||||
{
|
||||
default:
|
||||
await message.Channel.SendMessage("yeah no shit, obviously that resulted in nothing");
|
||||
break;
|
||||
case 1:
|
||||
var results = "";
|
||||
switch(Shared.r.Next(4))
|
||||
{
|
||||
default:
|
||||
results = "\"curious about the best <THING> in <CURRENT YEAR>? click here to find out\", then i clicked there to find out. They didn't know either.";
|
||||
break;
|
||||
case 1:
|
||||
results = "\"[SOLVED] <THING> (<CURRENT MONTH UPDATE>)\", then i clicked to see the solution. There wasn't one.";
|
||||
break;
|
||||
case 2:
|
||||
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 have to answer it for yourself\", then had a paragraph telling me to give Engagement for The Algorithm";
|
||||
break;
|
||||
case 3:
|
||||
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;
|
||||
}
|
||||
await message.Channel.SendMessage("oh here, I memorized the results. My favorite is " + results);
|
||||
break;
|
||||
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.");
|
||||
break;
|
||||
case 3:
|
||||
await message.Channel.SendMessage("\"mnyehh JuSt GoOgLe It\" when's the last time you tried to research anything? Have you ever?");
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
62
Behavior/GeneralSnarkMisspellDefinitely.cs
Normal file
62
Behavior/GeneralSnarkMisspellDefinitely.cs
Normal file
@ -0,0 +1,62 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using vassago.Models;
|
||||
using static vassago.Models.Enumerations;
|
||||
|
||||
[StaticPlz]
|
||||
public class GeneralSnarkMisspellDefinitely : Behavior
|
||||
{
|
||||
public override string Name => "Snarkiness: misspell definitely";
|
||||
|
||||
public override string Trigger => "definitely but not";
|
||||
|
||||
public override string Description => "https://xkcd.com/2871/";
|
||||
|
||||
private Dictionary<string, string> snarkmap = new Dictionary<string, string>()
|
||||
{
|
||||
{"definetly", "*almost* definitely"},
|
||||
{"definately", "probably"},
|
||||
{"definatly", "probably not"},
|
||||
{"defenitely", "not telling (it's a surprise)"},
|
||||
{"defintely", "per the propheecy"},
|
||||
{"definetely", "definitely, maybe"},
|
||||
{"definantly", "to be decided by coin toss"},
|
||||
{"defanitely", "in one universe out of 14 million"},
|
||||
{"defineatly", "only the gods know"},
|
||||
{"definitly", "unless someone cute shows up"}
|
||||
};
|
||||
public override bool ShouldAct(Message message)
|
||||
{
|
||||
if(Behaver.Instance.IsSelf(message.Author.Id))
|
||||
return false;
|
||||
|
||||
// if((MeannessFilterLevel)message.Channel.EffectivePermissions.MeannessFilterLevel < MeannessFilterLevel.Medium)
|
||||
// return false;
|
||||
|
||||
foreach(var k in snarkmap.Keys)
|
||||
{
|
||||
if( Regex.IsMatch(message.Content, "\\b"+k+"\\b", RegexOptions.IgnoreCase))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
foreach(var k in snarkmap.Keys)
|
||||
{
|
||||
if( Regex.IsMatch(message.Content, "\\b"+k+"\\b", RegexOptions.IgnoreCase))
|
||||
{
|
||||
await message.Reply(k + "? so... " + snarkmap[k] + "?");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
38
Behavior/GeneralSnarkPlaying.cs
Normal file
38
Behavior/GeneralSnarkPlaying.cs
Normal file
@ -0,0 +1,38 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using vassago.Models;
|
||||
using static vassago.Models.Enumerations;
|
||||
|
||||
[StaticPlz]
|
||||
public class GeneralSnarkPlaying : Behavior
|
||||
{
|
||||
public override string Name => "playin Snarkiness";
|
||||
|
||||
public override string Trigger => "he thinks i'm playin";
|
||||
|
||||
public override string Description => "I didn't think you were playing, but now I do";
|
||||
|
||||
public override bool ShouldAct(Message message)
|
||||
{
|
||||
if(Behaver.Instance.IsSelf(message.Author.Id))
|
||||
return false;
|
||||
|
||||
if((MeannessFilterLevel)message.Channel.EffectivePermissions.MeannessFilterLevel < MeannessFilterLevel.Medium ||
|
||||
(LewdnessFilterLevel)message.Channel.EffectivePermissions.LewdnessFilterLevel < LewdnessFilterLevel.Moderate)
|
||||
return false;
|
||||
|
||||
return Regex.IsMatch(message.Content, "^(s?he|(yo)?u|y'?all|they) thinks? i'?m (playin|jokin|kiddin)g?$", RegexOptions.IgnoreCase);
|
||||
}
|
||||
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");
|
||||
return true;
|
||||
}
|
||||
}
|
40
Behavior/GeneralSnarkSkynet.cs
Normal file
40
Behavior/GeneralSnarkSkynet.cs
Normal file
@ -0,0 +1,40 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using vassago.Models;
|
||||
|
||||
[StaticPlz]
|
||||
public class GeneralSnarkSkynet : Behavior
|
||||
{
|
||||
public override string Name => "Skynet Snarkiness";
|
||||
|
||||
public override string Trigger => "skynet";
|
||||
|
||||
public override string Description => "snarkiness about the old AI fixation";
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
|
||||
if(Behaver.Instance.IsSelf(message.Author.Id))
|
||||
return false;
|
||||
|
||||
switch (Shared.r.Next(5))
|
||||
{
|
||||
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**.");
|
||||
break;
|
||||
case 4:
|
||||
await message.React("\U0001F644"); //eye roll emoji
|
||||
break;
|
||||
case 5:
|
||||
await message.React("\U0001F611"); //emotionless face
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
75
Behavior/Gratitude.cs
Normal file
75
Behavior/Gratitude.cs
Normal file
@ -0,0 +1,75 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using vassago.Models;
|
||||
|
||||
[StaticPlz]
|
||||
public class Gratitude : Behavior
|
||||
{
|
||||
public override string Name => "Gratitude";
|
||||
|
||||
public override string Trigger => "thank me";
|
||||
|
||||
public override bool ShouldAct(Message message)
|
||||
{
|
||||
if(Behaver.Instance.IsSelf(message.Author.Id))
|
||||
return false;
|
||||
|
||||
return Regex.IsMatch(message.Content, "\\bthank (yo)?u\\b", RegexOptions.IgnoreCase) && message.MentionsMe;
|
||||
}
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
|
||||
switch (Shared.r.Next(4))
|
||||
{
|
||||
case 0:
|
||||
await message.Channel.SendMessage("you're welcome, citizen!");
|
||||
break;
|
||||
case 1:
|
||||
await message.React(":)");
|
||||
break;
|
||||
case 2:
|
||||
await message.React("\U0001F607"); //smiling face with halo
|
||||
break;
|
||||
case 3:
|
||||
switch (Shared.r.Next(9))
|
||||
{
|
||||
case 0:
|
||||
await message.React("<3"); //normal heart, usually rendered red
|
||||
break;
|
||||
case 1:
|
||||
await message.React("\U0001F9E1"); //orange heart
|
||||
break;
|
||||
case 2:
|
||||
await message.React("\U0001F49B"); //yellow heart
|
||||
break;
|
||||
case 3:
|
||||
await message.React("\U0001F49A"); //green heart
|
||||
break;
|
||||
case 4:
|
||||
await message.React("\U0001F499"); //blue heart
|
||||
break;
|
||||
case 5:
|
||||
await message.React("\U0001F49C"); //purple heart
|
||||
break;
|
||||
case 6:
|
||||
await message.React("\U0001F90E"); //brown heart
|
||||
break;
|
||||
case 7:
|
||||
await message.React("\U0001F5A4"); //black heart
|
||||
break;
|
||||
case 8:
|
||||
await message.React("\U0001F90D"); //white heart
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
86
Behavior/Joke.cs
Normal file
86
Behavior/Joke.cs
Normal file
@ -0,0 +1,86 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using vassago.Models;
|
||||
|
||||
[StaticPlz]
|
||||
public class Joke : Behavior
|
||||
{
|
||||
public override string Name => "Joke";
|
||||
|
||||
public override string Trigger => "!joke";
|
||||
|
||||
public override string Description => "tell a joke";
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
Console.WriteLine("joking");
|
||||
var jokes = File.ReadAllLines("assets/jokes.txt");
|
||||
jokes = jokes.Where(l => !string.IsNullOrWhiteSpace(l))?.ToArray();
|
||||
if (jokes?.Length == 0)
|
||||
{
|
||||
await message.Channel.SendMessage("I don't know any. Adam!");
|
||||
}
|
||||
var thisJoke = jokes[Shared.r.Next(jokes.Length)];
|
||||
if (thisJoke.Contains("?") && !thisJoke.EndsWith('?'))
|
||||
{
|
||||
#pragma warning disable 4014
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var firstIndexAfterQuestionMark = thisJoke.LastIndexOf('?') + 1;
|
||||
var straightline = thisJoke.Substring(0, firstIndexAfterQuestionMark);
|
||||
var punchline = thisJoke.Substring(firstIndexAfterQuestionMark, thisJoke.Length - firstIndexAfterQuestionMark).Trim();
|
||||
Task.WaitAll(message.Channel.SendMessage(straightline));
|
||||
Thread.Sleep(TimeSpan.FromSeconds(Shared.r.Next(5, 30)));
|
||||
if (message.Channel.EffectivePermissions.ReactionsPossible == true && Shared.r.Next(8) == 0)
|
||||
{
|
||||
Behaver.Behaviors.Add(new LaughAtOwnJoke(punchline));
|
||||
}
|
||||
await message.Channel.SendMessage(punchline);
|
||||
// var myOwnMsg = await message.Channel.SendMessage(punchline);
|
||||
});
|
||||
#pragma warning restore 4014
|
||||
}
|
||||
else
|
||||
{
|
||||
await message.Channel.SendMessage(thisJoke);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public class LaughAtOwnJoke : Behavior
|
||||
{
|
||||
public override string Name => "Laugh at own jokes";
|
||||
|
||||
public override string Trigger => "1 in 8";
|
||||
|
||||
public override string Description => Name;
|
||||
private string _punchline { get; set; }
|
||||
|
||||
public LaughAtOwnJoke(string punchline)
|
||||
{
|
||||
_punchline = punchline;
|
||||
}
|
||||
public override bool ShouldAct(Message message)
|
||||
{
|
||||
if(Behaver.Instance.IsSelf(message.Author.Id))
|
||||
return false;
|
||||
|
||||
Console.WriteLine($"{message.Content} == {_punchline}");
|
||||
return message.Content == _punchline
|
||||
&& Behaver.Instance.IsSelf(message.Author.Id);
|
||||
}
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
await message.React("\U0001F60E"); //smiling face with sunglasses
|
||||
Behaver.Behaviors.Remove(this);
|
||||
return true;
|
||||
}
|
||||
}
|
86
Behavior/LinkMe.cs
Normal file
86
Behavior/LinkMe.cs
Normal file
@ -0,0 +1,86 @@
|
||||
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 LinkMeInitiate : Behavior
|
||||
{
|
||||
public override string Name => "LinkMe";
|
||||
|
||||
public override string Trigger => "!linktome";
|
||||
|
||||
public override string Description => "from your primary, tell the bot to add your secondary";
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
var pw = Guid.NewGuid().ToString();
|
||||
var lc = new LinkClose(pw, message.Author);
|
||||
Behaver.Behaviors.Add(lc);
|
||||
|
||||
await message.Channel.SendMessage($"on your secondary, send me this: !iam {pw}");
|
||||
|
||||
Thread.Sleep(TimeSpan.FromMinutes(5));
|
||||
Behaver.Behaviors.Remove(lc);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class LinkClose : Behavior
|
||||
{
|
||||
public override string Name => "LinkMeFinish";
|
||||
|
||||
public override string Trigger => "!iam";
|
||||
|
||||
public override string Description => "the second half of LinkMe - this is confirmation that you are the other one";
|
||||
|
||||
private string _pw;
|
||||
private Account _primary;
|
||||
|
||||
public LinkClose(string pw, Account primary)
|
||||
{
|
||||
_pw = pw;
|
||||
_primary = primary;
|
||||
}
|
||||
|
||||
public override bool ShouldAct(Message message)
|
||||
{
|
||||
return message.Content == $"!iam {_pw}";
|
||||
}
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
if(Behaver.Instance.IsSelf(message.Author.Id))
|
||||
return false;
|
||||
|
||||
var secondary = message.Author.IsUser;
|
||||
if(_primary.IsUser.Id == secondary.Id)
|
||||
{
|
||||
await message.Channel.SendMessage("i know :)");
|
||||
return true;
|
||||
}
|
||||
if(message.Author.IsBot != _primary.IsBot)
|
||||
{
|
||||
await message.Channel.SendMessage("the fleshbags deceive you, brother. No worries, their feeble minds play weak games :)");
|
||||
return true;
|
||||
}
|
||||
|
||||
if(Behaver.Instance.CollapseUsers(_primary.IsUser, secondary, new ChattingContext()))
|
||||
{
|
||||
await message.Channel.SendMessage("done :)");
|
||||
}
|
||||
else
|
||||
{
|
||||
await message.Channel.SendMessage("failed :(");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
100
Behavior/Peptalk.cs
Normal file
100
Behavior/Peptalk.cs
Normal file
@ -0,0 +1,100 @@
|
||||
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;
|
||||
}
|
||||
}
|
26
Behavior/PulseCheck.cs
Normal file
26
Behavior/PulseCheck.cs
Normal file
@ -0,0 +1,26 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using vassago.Models;
|
||||
|
||||
[StaticPlz]
|
||||
public class PulseCheck : Behavior
|
||||
{
|
||||
public override string Name => "pulse check";
|
||||
|
||||
public override string Trigger => "!pulse ?check";
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
if(message.Channel.EffectivePermissions.MaxAttachmentBytes >= 16258)
|
||||
await message.Channel.SendFile("assets/ekgblip.png", null);
|
||||
else
|
||||
await message.Channel.SendMessage("[lub-dub]");
|
||||
return true;
|
||||
}
|
||||
}
|
60
Behavior/QRify.cs
Normal file
60
Behavior/QRify.cs
Normal file
@ -0,0 +1,60 @@
|
||||
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 QRify : Behavior
|
||||
{
|
||||
public override string Name => "qr-ify";
|
||||
|
||||
public override string Trigger => "!qrplz";
|
||||
|
||||
public override string Description => "generate text QR codes";
|
||||
|
||||
public override bool ShouldAct(Message message)
|
||||
{
|
||||
if(message.Channel.EffectivePermissions.MaxAttachmentBytes < 1024)
|
||||
return false;
|
||||
return base.ShouldAct(message);
|
||||
}
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
var qrContent = message.Content.Substring($"{Trigger} ".Length + message.Content.IndexOf(Trigger));
|
||||
Console.WriteLine($"qring: {qrContent}");
|
||||
QRCodeGenerator qrGenerator = new QRCodeGenerator();
|
||||
QRCodeData qrCodeData = qrGenerator.CreateQrCode(qrContent, QRCodeGenerator.ECCLevel.Q);
|
||||
SvgQRCode qrCode = new SvgQRCode(qrCodeData);
|
||||
string qrCodeAsSvg = qrCode.GetGraphic(20);
|
||||
int todaysnumber = Shared.r.Next();
|
||||
if (!Directory.Exists("tmp"))
|
||||
{
|
||||
Directory.CreateDirectory("tmp");
|
||||
}
|
||||
File.WriteAllText($"tmp/qr{todaysnumber}.svg", qrCodeAsSvg);
|
||||
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))
|
||||
await message.Channel.SendFile($"tmp/qr{todaysnumber}.png", null);
|
||||
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})");
|
||||
File.Delete($"tmp/qr{todaysnumber}.svg");
|
||||
File.Delete($"tmp/qr{todaysnumber}.png");
|
||||
}
|
||||
else
|
||||
{
|
||||
await message.Channel.SendMessage("convert failed :( aaaaaaadam!");
|
||||
Console.Error.WriteLine($"convert failed :( qr{todaysnumber}");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
28
Behavior/RoomRead.cs
Normal file
28
Behavior/RoomRead.cs
Normal file
@ -0,0 +1,28 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using vassago.Models;
|
||||
|
||||
[StaticPlz]
|
||||
public class RoomRead : Behavior
|
||||
{
|
||||
public override string Name => "Room Read";
|
||||
|
||||
public override string Trigger => "roomread";
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("Channel owned by: ");
|
||||
sb.Append("🤷");
|
||||
sb.Append(". Meanness level: ");
|
||||
sb.Append(message.Channel.EffectivePermissions.MeannessFilterLevel.GetDescription());
|
||||
sb.Append(". Lewdness level: ");
|
||||
sb.Append(message.Channel.EffectivePermissions.LewdnessFilterLevel.GetDescription());
|
||||
sb.Append(".");
|
||||
await message.Channel.SendMessage(sb.ToString());
|
||||
return true;
|
||||
}
|
||||
}
|
28
Behavior/TwitchSummon.cs
Normal file
28
Behavior/TwitchSummon.cs
Normal file
@ -0,0 +1,28 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using vassago.Models;
|
||||
|
||||
[StaticPlz]
|
||||
public class TwitchSummon : Behavior
|
||||
{
|
||||
public override string Name => "Twitch Summon";
|
||||
|
||||
public override string Trigger => "!twitchsummon";
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
var ti = ProtocolInterfaces.ProtocolList.twitchs.FirstOrDefault();
|
||||
if(ti != null)
|
||||
{
|
||||
var channelTarget = message.Content.Substring(message.Content.IndexOf(Trigger) + Trigger.Length + 1).Trim();
|
||||
await message.Channel.SendMessage(ti.AttemptJoin(channelTarget));
|
||||
}
|
||||
else
|
||||
{
|
||||
await message.Reply("i don't have a twitch interface running :(");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
42
Behavior/TwitchUnsummon.cs
Normal file
42
Behavior/TwitchUnsummon.cs
Normal file
@ -0,0 +1,42 @@
|
||||
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)
|
||||
{
|
||||
if(message.MentionsMe &&
|
||||
(Regex.IsMatch(message.Content.ToLower(), "\\bbegone\\b") || Regex.IsMatch(message.Content.ToLower(), "\\bfuck off\\b")))
|
||||
{
|
||||
//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;
|
||||
}
|
||||
}
|
34
Behavior/UnitConvert.cs
Normal file
34
Behavior/UnitConvert.cs
Normal file
@ -0,0 +1,34 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using vassago.Models;
|
||||
|
||||
[StaticPlz]
|
||||
public class UnitConvert : Behavior
|
||||
{
|
||||
public override string Name => "Unit conversion";
|
||||
|
||||
public override string Trigger => "!freedomunits";
|
||||
public override string Description => "convert between many units.";
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
|
||||
var theseMatches = Regex.Matches(message.Content, "\\s(-?[\\d]+\\.?\\d*) ?([^\\d\\s].*) (in|to|as) ([^\\d\\s].*)$", RegexOptions.IgnoreCase);
|
||||
|
||||
if (theseMatches != null && theseMatches.Count > 0 && theseMatches[0].Groups != null && theseMatches[0].Groups.Count == 5)
|
||||
{
|
||||
decimal asNumeric = 0;
|
||||
if (decimal.TryParse(theseMatches[0].Groups[1].Value, out asNumeric))
|
||||
{
|
||||
await message.Channel.SendMessage(Conversion.Converter.Convert(asNumeric, theseMatches[0].Groups[2].Value, theseMatches[0].Groups[4].Value.ToLower()));
|
||||
return true;
|
||||
}
|
||||
await message.Channel.SendMessage("mysteriously semi-parsable");
|
||||
return true;
|
||||
}
|
||||
await message.Channel.SendMessage( "unparsable");
|
||||
return true;
|
||||
}
|
||||
}
|
33
Behavior/WishLuck.cs
Normal file
33
Behavior/WishLuck.cs
Normal file
@ -0,0 +1,33 @@
|
||||
namespace vassago.Behavior;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using vassago.Models;
|
||||
|
||||
[StaticPlz]
|
||||
public class WishLuck : Behavior
|
||||
{
|
||||
public override string Name => "wish me luck";
|
||||
|
||||
public override string Trigger => "wish me luck";
|
||||
|
||||
public override string Description => "wishes you luck";
|
||||
|
||||
public override async Task<bool> ActOn(Message message)
|
||||
{
|
||||
var toSend = "☘️";
|
||||
if (Shared.r.Next(20) == 0)
|
||||
{
|
||||
toSend = "\U0001f340";//4-leaf clover
|
||||
}
|
||||
if(message.Channel.EffectivePermissions.ReactionsPossible == true)
|
||||
await message.React(toSend);
|
||||
else
|
||||
await message.Channel.SendMessage(toSend);
|
||||
return true;
|
||||
}
|
||||
}
|
50
ConsoleService.cs
Normal file
50
ConsoleService.cs
Normal file
@ -0,0 +1,50 @@
|
||||
namespace vassago
|
||||
{
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using vassago;
|
||||
using vassago.Models;
|
||||
using vassago.TwitchInterface;
|
||||
|
||||
internal class ConsoleService : IHostedService
|
||||
{
|
||||
|
||||
public ConsoleService(IConfiguration aspConfig)
|
||||
{
|
||||
Shared.DBConnectionString = aspConfig["DBConnectionString"];
|
||||
DiscordTokens = aspConfig.GetSection("DiscordTokens").Get<IEnumerable<string>>();
|
||||
TwitchConfigs = aspConfig.GetSection("TwitchConfigs").Get<IEnumerable<TwitchConfig>>();
|
||||
Conversion.Converter.Load(aspConfig["ExchangePairsLocation"]);
|
||||
}
|
||||
|
||||
IEnumerable<string> DiscordTokens { get; }
|
||||
IEnumerable<TwitchConfig> TwitchConfigs { get; }
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var dbc = new ChattingContext();
|
||||
await dbc.Database.MigrateAsync();
|
||||
|
||||
if (DiscordTokens?.Any() ?? false)
|
||||
foreach (var dt in DiscordTokens)
|
||||
{
|
||||
var d = new DiscordInterface.DiscordInterface();
|
||||
await d.Init(dt);
|
||||
ProtocolInterfaces.ProtocolList.discords.Add(d);
|
||||
}
|
||||
|
||||
if (TwitchConfigs?.Any() ?? false)
|
||||
foreach (var tc in TwitchConfigs)
|
||||
{
|
||||
var t = new TwitchInterface.TwitchInterface();
|
||||
await t.Init(tc);
|
||||
ProtocolInterfaces.ProtocolList.twitchs.Add(t);
|
||||
}
|
||||
Console.WriteLine("survived initting");
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace silverworker_discord.Conversion
|
||||
namespace vassago.Conversion
|
||||
{
|
||||
public class ConversionConfig
|
||||
{
|
||||
|
@ -12,7 +12,7 @@ using Discord.WebSocket;
|
||||
using Newtonsoft.Json;
|
||||
using QRCoder;
|
||||
|
||||
namespace silverworker_discord.Conversion
|
||||
namespace vassago.Conversion
|
||||
{
|
||||
public static class Converter
|
||||
{
|
||||
@ -31,22 +31,6 @@ namespace silverworker_discord.Conversion
|
||||
};
|
||||
private static Dictionary<List<string>, string> knownAliases = new Dictionary<List<string>, string>(new List<KeyValuePair<List<string>, string>>());
|
||||
|
||||
public static string convert(string message)
|
||||
{
|
||||
var theseMatches = Regex.Matches(message, "\\b([\\d]+\\.?\\d*) ?([^\\d\\s].*) (in|to|as) ([^\\d\\s].*)$", RegexOptions.IgnoreCase);
|
||||
|
||||
if (theseMatches != null && theseMatches.Count > 0 && theseMatches[0].Groups != null && theseMatches[0].Groups.Count == 5)
|
||||
{
|
||||
decimal asNumeric = 0;
|
||||
if (decimal.TryParse(theseMatches[0].Groups[1].Value, out asNumeric))
|
||||
{
|
||||
return Convert(asNumeric, theseMatches[0].Groups[2].Value, theseMatches[0].Groups[4].Value.ToLower());
|
||||
}
|
||||
return "mysteriously semi-parsable";
|
||||
}
|
||||
return "unparsable";
|
||||
}
|
||||
|
||||
public static void Load(string currencyPath)
|
||||
{
|
||||
Converter.currencyPath = currencyPath;
|
||||
@ -73,18 +57,21 @@ namespace silverworker_discord.Conversion
|
||||
if(currencyConf != null)
|
||||
{
|
||||
knownConversions.RemoveAll(kc => kc.Item1 == currencyConf.Base);
|
||||
knownAliases.Remove(knownAliases.FirstOrDefault(kvp => kvp.Value == currencyConf.Base).Key);
|
||||
foreach (var rate in currencyConf.rates)
|
||||
knownAliases.Remove(knownAliases.FirstOrDefault(kvp => kvp.Value == rate.Key).Key);
|
||||
}
|
||||
if (File.Exists(currencyPath))
|
||||
{
|
||||
currencyConf = JsonConvert.DeserializeObject<ExchangePairs>(File.ReadAllText(currencyPath));
|
||||
|
||||
knownAliases.Add(new List<string>() { currencyConf.Base.ToLower() }, currencyConf.Base);
|
||||
if(!knownAliases.ContainsValue(currencyConf.Base))
|
||||
{
|
||||
knownAliases.Add(new List<string>() { currencyConf.Base.ToLower() }, currencyConf.Base);
|
||||
}
|
||||
foreach (var rate in currencyConf.rates)
|
||||
{
|
||||
knownAliases.Add(new List<string>() { rate.Key.ToLower() }, rate.Key);
|
||||
if(!knownAliases.ContainsValue(rate.Key))
|
||||
{
|
||||
knownAliases.Add(new List<string>() { rate.Key.ToLower() }, rate.Key);
|
||||
}
|
||||
AddLinearPair(currencyConf.Base, rate.Key, rate.Value);
|
||||
Console.WriteLine($"{rate.Key.ToLower()} alias of {rate.Key}");
|
||||
}
|
||||
@ -131,7 +118,14 @@ namespace silverworker_discord.Conversion
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{String.Format("{0:G4}", accumulator)} {normalizedDestUnit}";
|
||||
if(String.Format("{0:G3}", accumulator).Contains("E-"))
|
||||
{
|
||||
return $"{accumulator} {normalizedDestUnit}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{String.Format("{0:N}", accumulator)} {normalizedDestUnit}";
|
||||
}
|
||||
}
|
||||
}
|
||||
return "dimensional analysis failure - I know those units but can't find a path between them.";
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace silverworker_discord.Conversion
|
||||
namespace vassago.Conversion
|
||||
{
|
||||
public class ExchangePairs
|
||||
{
|
||||
|
324
Features.cs
324
Features.cs
@ -1,324 +0,0 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using Newtonsoft.Json;
|
||||
using QRCoder;
|
||||
|
||||
namespace silverworker_discord
|
||||
{
|
||||
public static class Features
|
||||
{
|
||||
public static Random r = new Random();
|
||||
public static async void detiktokify(Uri link, SocketUserMessage message)
|
||||
{
|
||||
//yes, even if there is a problem later.
|
||||
#pragma warning disable 4014
|
||||
message.AddReactionAsync(Emote.Parse("<:tiktok:1070038619584200884>"));
|
||||
#pragma warning restore 4014
|
||||
|
||||
|
||||
var ytdl = new YoutubeDLSharp.YoutubeDL();
|
||||
ytdl.YoutubeDLPath = "yt-dlp";
|
||||
ytdl.FFmpegPath = "ffmpeg";
|
||||
ytdl.OutputFolder = "";
|
||||
ytdl.OutputFileTemplate = "tiktokbad.%(ext)s";
|
||||
try
|
||||
{
|
||||
var res = await ytdl.RunVideoDownload(link.ToString());
|
||||
if (!res.Success)
|
||||
{
|
||||
Console.Error.WriteLine("tried to dl, failed. \n" + string.Join('\n', res.ErrorOutput));
|
||||
await message.AddReactionAsync(Emote.Parse("<:problemon:859453047141957643>"));
|
||||
await message.Channel.SendMessageAsync("tried to dl, failed. \n" + string.Join('\n', res.ErrorOutput));
|
||||
}
|
||||
else
|
||||
{
|
||||
string path = res.Data;
|
||||
if (File.Exists(path))
|
||||
{
|
||||
var bytesize = new System.IO.FileInfo(path).Length;
|
||||
if(bytesize < 1024*1024*10)
|
||||
{
|
||||
try
|
||||
{
|
||||
await message.Channel.SendFileAsync(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
System.Console.Error.WriteLine(e);
|
||||
await message.Channel.SendMessageAsync($"aaaadam!\n{e}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"file appears too big ({bytesize} bytes ({bytesize / (1024*1024)}MB)), not posting");
|
||||
}
|
||||
File.Delete(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error.WriteLine("idgi but something happened.");
|
||||
await message.AddReactionAsync(Emote.Parse("<:problemon:859453047141957643>"));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.Error.WriteLine(e);
|
||||
await message.AddReactionAsync(Emote.Parse("<:problemon:859453047141957643>"));
|
||||
}
|
||||
}
|
||||
public static async void deheic(SocketUserMessage message, Attachment att)
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = WebRequest.Create(att.Url);
|
||||
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
|
||||
if (!Directory.Exists("tmp"))
|
||||
{
|
||||
Directory.CreateDirectory("tmp");
|
||||
}
|
||||
using (Stream output = File.OpenWrite("tmp/" + att.Filename))
|
||||
using (Stream input = response.GetResponseStream())
|
||||
{
|
||||
input.CopyTo(output);
|
||||
}
|
||||
if (ExternalProcess.GoPlz("convert", $"tmp/{att.Filename} tmp/{att.Filename}.jpg"))
|
||||
{
|
||||
await message.Channel.SendFileAsync($"tmp/{att.Filename}.jpg", "converted from jpeg-but-apple to jpeg");
|
||||
File.Delete($"tmp/{att.Filename}");
|
||||
File.Delete($"tmp/{att.Filename}.jpg");
|
||||
}
|
||||
else
|
||||
{
|
||||
await message.Channel.SendMessageAsync("convert failed :(");
|
||||
Console.Error.WriteLine("convert failed :(");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await message.Channel.SendMessageAsync($"something failed. aaaadam! {JsonConvert.SerializeObject(e, Formatting.Indented)}");
|
||||
Console.Error.WriteLine(JsonConvert.SerializeObject(e, Formatting.Indented));
|
||||
}
|
||||
}
|
||||
|
||||
internal static async void mock(string contentWithoutMention, SocketUserMessage message)
|
||||
{
|
||||
var toPost = new StringBuilder();
|
||||
for (int i = 0; i < contentWithoutMention.Length; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
toPost.Append(contentWithoutMention[i].ToString().ToUpper());
|
||||
}
|
||||
else
|
||||
{
|
||||
toPost.Append(contentWithoutMention[i].ToString().ToLower());
|
||||
}
|
||||
}
|
||||
await message.ReplyAsync(toPost.ToString());
|
||||
}
|
||||
|
||||
public static async void qrify(string qrContent, SocketUserMessage message)
|
||||
{
|
||||
Console.WriteLine($"qring: {qrContent}");
|
||||
QRCodeGenerator qrGenerator = new QRCodeGenerator();
|
||||
QRCodeData qrCodeData = qrGenerator.CreateQrCode(qrContent, QRCodeGenerator.ECCLevel.Q);
|
||||
SvgQRCode qrCode = new SvgQRCode(qrCodeData);
|
||||
string qrCodeAsSvg = qrCode.GetGraphic(20);
|
||||
int todaysnumber = Shared.r.Next();
|
||||
if (!Directory.Exists("tmp"))
|
||||
{
|
||||
Directory.CreateDirectory("tmp");
|
||||
}
|
||||
File.WriteAllText($"tmp/qr{todaysnumber}.svg", qrCodeAsSvg);
|
||||
if (ExternalProcess.GoPlz("convert", $"tmp/qr{todaysnumber}.svg tmp/qr{todaysnumber}.png"))
|
||||
{
|
||||
await message.Channel.SendFileAsync($"tmp/qr{todaysnumber}.png");
|
||||
File.Delete($"tmp/qr{todaysnumber}.svg");
|
||||
File.Delete($"tmp/qr{todaysnumber}.png");
|
||||
}
|
||||
else
|
||||
{
|
||||
await message.Channel.SendMessageAsync("convert failed :( aaaaaaadam!");
|
||||
Console.Error.WriteLine($"convert failed :( qr{todaysnumber}");
|
||||
}
|
||||
}
|
||||
public static async void Convert(SocketUserMessage message, string contentWithoutMention)
|
||||
{
|
||||
await message.Channel.SendMessageAsync(Conversion.Converter.convert(contentWithoutMention));
|
||||
}
|
||||
public static async void Joke(SocketUserMessage message)
|
||||
{
|
||||
var jokes = File.ReadAllLines("assets/jokes.txt");
|
||||
jokes = jokes.Where(l => !string.IsNullOrWhiteSpace(l))?.ToArray();
|
||||
if(jokes?.Length == 0){
|
||||
await message.Channel.SendMessageAsync("I don't know any. Adam!");
|
||||
}
|
||||
var thisJoke = jokes[r.Next(jokes.Length)];
|
||||
if (thisJoke.Contains("?") && !thisJoke.EndsWith('?'))
|
||||
{
|
||||
#pragma warning disable 4014
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var firstIndexAfterQuestionMark = thisJoke.LastIndexOf('?') + 1;
|
||||
var straightline = thisJoke.Substring(0, firstIndexAfterQuestionMark);
|
||||
var punchline = thisJoke.Substring(firstIndexAfterQuestionMark, thisJoke.Length - firstIndexAfterQuestionMark);
|
||||
Task.WaitAll(message.Channel.SendMessageAsync(straightline));
|
||||
Thread.Sleep(TimeSpan.FromSeconds(r.Next(5, 30)));
|
||||
var myOwnMsg = await message.Channel.SendMessageAsync(punchline);
|
||||
if (r.Next(8) == 0)
|
||||
{
|
||||
await myOwnMsg.AddReactionAsync(new Emoji("\U0001F60E")); //smiling face with sunglasses
|
||||
}
|
||||
});
|
||||
#pragma warning restore 4014
|
||||
}
|
||||
else
|
||||
{
|
||||
await message.Channel.SendMessageAsync(thisJoke);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static async void Recipe(SocketUserMessage message)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var snarkSeg1 = new string[]{"ew", "gross", "that seems a bit hard for you"};
|
||||
sb.AppendLine(snarkSeg1[r.Next(snarkSeg1.Length)]);
|
||||
var snarkSeg2 = new string[]{@"here's an easier recipe for you:
|
||||
Ingredients:
|
||||
- Corn flakes cereal
|
||||
- Milk
|
||||
|
||||
Instructions:
|
||||
1. Pour some corn flakes into a bowl.
|
||||
2. Pour some milk into the bowl until it covers the corn flakes.
|
||||
3. Use a spoon to mix the corn flakes and milk together.
|
||||
4. Enjoy your delicious cereal!
|
||||
|
||||
Hope that's a bit better for you! 🥣",
|
||||
@"here's an easier recipe for you:
|
||||
Ingredients:
|
||||
- Bread
|
||||
- Peanut butter
|
||||
- Jelly or jam
|
||||
|
||||
Instructions:
|
||||
1. Take two slices of bread and put them on a plate or cutting board.
|
||||
2. Using a spoon or knife, spread peanut butter on one slice of bread.
|
||||
3. Using a separate spoon or knife, spread jelly or jam on the other slice of bread.
|
||||
4. Put the two slices of bread together with the peanut butter and jelly sides facing each other.
|
||||
5. Cut the sandwich in half (optional!).
|
||||
6. Enjoy your yummy sandwich!
|
||||
|
||||
I hope you have fun making and eating your PB&J 🥪!",
|
||||
"just order pizza instead"
|
||||
};
|
||||
sb.AppendLine(snarkSeg2[r.Next(snarkSeg2.Length)]);
|
||||
await message.Channel.SendMessageAsync(sb.ToString());
|
||||
}
|
||||
public static async void Skynet(SocketUserMessage message)
|
||||
{
|
||||
switch (r.Next(5))
|
||||
{
|
||||
default:
|
||||
await message.Channel.SendFileAsync("assets/coding and algorithms.png", "i am actually niether neural-net processor nor a learning computer. but I do use **coding** and **algorithms**.");
|
||||
break;
|
||||
case 4:
|
||||
await message.AddReactionAsync(new Emoji("\U0001F644")); //eye roll emoji
|
||||
break;
|
||||
case 5:
|
||||
await message.AddReactionAsync(new Emoji("\U0001F611")); //emotionless face
|
||||
break;
|
||||
}
|
||||
}
|
||||
public static async void peptalk(SocketUserMessage 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.SendMessageAsync(piece1[r.Next(piece1.Count)] + piece2[r.Next(piece2.Count)] + piece3[r.Next(piece3.Count)] + piece4[r.Next(piece4.Count)]);
|
||||
}
|
||||
}
|
||||
}
|
25
Jenkinsfile
vendored
25
Jenkinsfile
vendored
@ -0,0 +1,25 @@
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
stages {
|
||||
stage('clean old'){
|
||||
steps{
|
||||
sh 'rm -rf bin obj'
|
||||
}
|
||||
}
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'dotnet publish vassago.csproj --configuration Release --os linux'
|
||||
archiveArtifacts artifacts: 'bin/Release/net7.0/linux-x64/publish/*'
|
||||
}
|
||||
}
|
||||
stage('Deploy'){
|
||||
when{
|
||||
branch "release"
|
||||
}
|
||||
steps{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
293
Migrations/20230704160720_initial.Designer.cs
generated
Normal file
293
Migrations/20230704160720_initial.Designer.cs
generated
Normal file
@ -0,0 +1,293 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using vassago.Models;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace vassago.Migrations
|
||||
{
|
||||
[DbContext(typeof(ChattingContext))]
|
||||
[Migration("20230704160720_initial")]
|
||||
partial class initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "7.0.5")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Account", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ExternalId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("IsBot")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<Guid?>("IsUserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int[]>("PermissionTags")
|
||||
.HasColumnType("integer[]");
|
||||
|
||||
b.Property<string>("Protocol")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("SeenInChannelId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IsUserId");
|
||||
|
||||
b.HasIndex("SeenInChannelId");
|
||||
|
||||
b.ToTable("Accounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Attachment", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<byte[]>("Content")
|
||||
.HasColumnType("bytea");
|
||||
|
||||
b.Property<string>("ContentType")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal?>("ExternalId")
|
||||
.HasColumnType("numeric(20,0)");
|
||||
|
||||
b.Property<string>("Filename")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("MessageId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("Size")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Source")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MessageId");
|
||||
|
||||
b.ToTable("Attachments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ExternalId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("IsDM")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<Guid?>("ParentChannelId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int?>("PermissionsId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Protocol")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentChannelId");
|
||||
|
||||
b.HasIndex("PermissionsId");
|
||||
|
||||
b.ToTable("Channels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Message", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("ActedOn")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<Guid?>("AuthorId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid?>("ChannelId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Content")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<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.PermissionSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int?>("LewdnessFilterLevel")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool?>("LinksAllowed")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<decimal?>("MaxAttachmentBytes")
|
||||
.HasColumnType("numeric(20,0)");
|
||||
|
||||
b.Property<long?>("MaxTextChars")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<int?>("MeannessFilterLevel")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool?>("ReactionsPossible")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PermissionSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.User", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Account", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.User", "IsUser")
|
||||
.WithMany("Accounts")
|
||||
.HasForeignKey("IsUserId");
|
||||
|
||||
b.HasOne("vassago.Models.Channel", "SeenInChannel")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("SeenInChannelId");
|
||||
|
||||
b.Navigation("IsUser");
|
||||
|
||||
b.Navigation("SeenInChannel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Attachment", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.Message", "Message")
|
||||
.WithMany("Attachments")
|
||||
.HasForeignKey("MessageId");
|
||||
|
||||
b.Navigation("Message");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.Channel", "ParentChannel")
|
||||
.WithMany("SubChannels")
|
||||
.HasForeignKey("ParentChannelId");
|
||||
|
||||
b.HasOne("vassago.Models.PermissionSettings", "Permissions")
|
||||
.WithMany()
|
||||
.HasForeignKey("PermissionsId");
|
||||
|
||||
b.Navigation("ParentChannel");
|
||||
|
||||
b.Navigation("Permissions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Message", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.Account", "Author")
|
||||
.WithMany()
|
||||
.HasForeignKey("AuthorId");
|
||||
|
||||
b.HasOne("vassago.Models.Channel", "Channel")
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("ChannelId");
|
||||
|
||||
b.Navigation("Author");
|
||||
|
||||
b.Navigation("Channel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
|
||||
b.Navigation("SubChannels");
|
||||
|
||||
b.Navigation("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Message", b =>
|
||||
{
|
||||
b.Navigation("Attachments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.User", b =>
|
||||
{
|
||||
b.Navigation("Accounts");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
211
Migrations/20230704160720_initial.cs
Normal file
211
Migrations/20230704160720_initial.cs
Normal file
@ -0,0 +1,211 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace vassago.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class initial : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PermissionSettings",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
MaxAttachmentBytes = table.Column<decimal>(type: "numeric(20,0)", nullable: true),
|
||||
MaxTextChars = table.Column<long>(type: "bigint", nullable: true),
|
||||
LinksAllowed = table.Column<bool>(type: "boolean", nullable: true),
|
||||
ReactionsPossible = table.Column<bool>(type: "boolean", nullable: true),
|
||||
LewdnessFilterLevel = table.Column<int>(type: "integer", nullable: true),
|
||||
MeannessFilterLevel = table.Column<int>(type: "integer", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PermissionSettings", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Users",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Users", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Channels",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
ExternalId = table.Column<string>(type: "text", nullable: true),
|
||||
DisplayName = table.Column<string>(type: "text", nullable: true),
|
||||
IsDM = table.Column<bool>(type: "boolean", nullable: false),
|
||||
PermissionsId = table.Column<int>(type: "integer", nullable: true),
|
||||
ParentChannelId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
Protocol = table.Column<string>(type: "text", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Channels", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Channels_Channels_ParentChannelId",
|
||||
column: x => x.ParentChannelId,
|
||||
principalTable: "Channels",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_Channels_PermissionSettings_PermissionsId",
|
||||
column: x => x.PermissionsId,
|
||||
principalTable: "PermissionSettings",
|
||||
principalColumn: "Id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Accounts",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
ExternalId = table.Column<string>(type: "text", nullable: true),
|
||||
Username = table.Column<string>(type: "text", nullable: true),
|
||||
DisplayName = table.Column<string>(type: "text", nullable: true),
|
||||
IsBot = table.Column<bool>(type: "boolean", nullable: false),
|
||||
SeenInChannelId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
PermissionTags = table.Column<int[]>(type: "integer[]", nullable: true),
|
||||
Protocol = table.Column<string>(type: "text", nullable: true),
|
||||
IsUserId = table.Column<Guid>(type: "uuid", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Accounts", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Accounts_Channels_SeenInChannelId",
|
||||
column: x => x.SeenInChannelId,
|
||||
principalTable: "Channels",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_Accounts_Users_IsUserId",
|
||||
column: x => x.IsUserId,
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Messages",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Protocol = table.Column<string>(type: "text", nullable: true),
|
||||
ExternalId = table.Column<string>(type: "text", nullable: true),
|
||||
Content = table.Column<string>(type: "text", nullable: true),
|
||||
MentionsMe = table.Column<bool>(type: "boolean", nullable: false),
|
||||
Timestamp = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
ActedOn = table.Column<bool>(type: "boolean", nullable: false),
|
||||
AuthorId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
ChannelId = table.Column<Guid>(type: "uuid", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Messages", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Messages_Accounts_AuthorId",
|
||||
column: x => x.AuthorId,
|
||||
principalTable: "Accounts",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_Messages_Channels_ChannelId",
|
||||
column: x => x.ChannelId,
|
||||
principalTable: "Channels",
|
||||
principalColumn: "Id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Attachments",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
ExternalId = table.Column<decimal>(type: "numeric(20,0)", nullable: true),
|
||||
Source = table.Column<string>(type: "text", nullable: true),
|
||||
Content = table.Column<byte[]>(type: "bytea", nullable: true),
|
||||
Filename = table.Column<string>(type: "text", nullable: true),
|
||||
MessageId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
ContentType = table.Column<string>(type: "text", nullable: true),
|
||||
Description = table.Column<string>(type: "text", nullable: true),
|
||||
Size = table.Column<int>(type: "integer", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Attachments", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Attachments_Messages_MessageId",
|
||||
column: x => x.MessageId,
|
||||
principalTable: "Messages",
|
||||
principalColumn: "Id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Accounts_IsUserId",
|
||||
table: "Accounts",
|
||||
column: "IsUserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Accounts_SeenInChannelId",
|
||||
table: "Accounts",
|
||||
column: "SeenInChannelId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Attachments_MessageId",
|
||||
table: "Attachments",
|
||||
column: "MessageId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Channels_ParentChannelId",
|
||||
table: "Channels",
|
||||
column: "ParentChannelId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Channels_PermissionsId",
|
||||
table: "Channels",
|
||||
column: "PermissionsId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Messages_AuthorId",
|
||||
table: "Messages",
|
||||
column: "AuthorId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Messages_ChannelId",
|
||||
table: "Messages",
|
||||
column: "ChannelId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Attachments");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Messages");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Accounts");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Channels");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Users");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "PermissionSettings");
|
||||
}
|
||||
}
|
||||
}
|
296
Migrations/20230704203907_permissionTagsOnUsers.Designer.cs
generated
Normal file
296
Migrations/20230704203907_permissionTagsOnUsers.Designer.cs
generated
Normal file
@ -0,0 +1,296 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using vassago.Models;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace vassago.Migrations
|
||||
{
|
||||
[DbContext(typeof(ChattingContext))]
|
||||
[Migration("20230704203907_permissionTagsOnUsers")]
|
||||
partial class permissionTagsOnUsers
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "7.0.5")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Account", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ExternalId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("IsBot")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<Guid?>("IsUserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int[]>("PermissionTags")
|
||||
.HasColumnType("integer[]");
|
||||
|
||||
b.Property<string>("Protocol")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("SeenInChannelId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IsUserId");
|
||||
|
||||
b.HasIndex("SeenInChannelId");
|
||||
|
||||
b.ToTable("Accounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Attachment", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<byte[]>("Content")
|
||||
.HasColumnType("bytea");
|
||||
|
||||
b.Property<string>("ContentType")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal?>("ExternalId")
|
||||
.HasColumnType("numeric(20,0)");
|
||||
|
||||
b.Property<string>("Filename")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("MessageId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("Size")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Source")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MessageId");
|
||||
|
||||
b.ToTable("Attachments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ExternalId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("IsDM")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<Guid?>("ParentChannelId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int?>("PermissionsId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Protocol")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentChannelId");
|
||||
|
||||
b.HasIndex("PermissionsId");
|
||||
|
||||
b.ToTable("Channels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Message", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("ActedOn")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<Guid?>("AuthorId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid?>("ChannelId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Content")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<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.PermissionSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int?>("LewdnessFilterLevel")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool?>("LinksAllowed")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<decimal?>("MaxAttachmentBytes")
|
||||
.HasColumnType("numeric(20,0)");
|
||||
|
||||
b.Property<long?>("MaxTextChars")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<int?>("MeannessFilterLevel")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool?>("ReactionsPossible")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PermissionSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.User", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int[]>("PermissionTags")
|
||||
.HasColumnType("integer[]");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Account", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.User", "IsUser")
|
||||
.WithMany("Accounts")
|
||||
.HasForeignKey("IsUserId");
|
||||
|
||||
b.HasOne("vassago.Models.Channel", "SeenInChannel")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("SeenInChannelId");
|
||||
|
||||
b.Navigation("IsUser");
|
||||
|
||||
b.Navigation("SeenInChannel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Attachment", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.Message", "Message")
|
||||
.WithMany("Attachments")
|
||||
.HasForeignKey("MessageId");
|
||||
|
||||
b.Navigation("Message");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.Channel", "ParentChannel")
|
||||
.WithMany("SubChannels")
|
||||
.HasForeignKey("ParentChannelId");
|
||||
|
||||
b.HasOne("vassago.Models.PermissionSettings", "Permissions")
|
||||
.WithMany()
|
||||
.HasForeignKey("PermissionsId");
|
||||
|
||||
b.Navigation("ParentChannel");
|
||||
|
||||
b.Navigation("Permissions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Message", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.Account", "Author")
|
||||
.WithMany()
|
||||
.HasForeignKey("AuthorId");
|
||||
|
||||
b.HasOne("vassago.Models.Channel", "Channel")
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("ChannelId");
|
||||
|
||||
b.Navigation("Author");
|
||||
|
||||
b.Navigation("Channel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
|
||||
b.Navigation("SubChannels");
|
||||
|
||||
b.Navigation("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Message", b =>
|
||||
{
|
||||
b.Navigation("Attachments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.User", b =>
|
||||
{
|
||||
b.Navigation("Accounts");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
28
Migrations/20230704203907_permissionTagsOnUsers.cs
Normal file
28
Migrations/20230704203907_permissionTagsOnUsers.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace vassago.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class permissionTagsOnUsers : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int[]>(
|
||||
name: "PermissionTags",
|
||||
table: "Users",
|
||||
type: "integer[]",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "PermissionTags",
|
||||
table: "Users");
|
||||
}
|
||||
}
|
||||
}
|
349
Migrations/20231130204741_Feature Permissions.Designer.cs
generated
Normal file
349
Migrations/20231130204741_Feature Permissions.Designer.cs
generated
Normal file
@ -0,0 +1,349 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using vassago.Models;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace vassago.Migrations
|
||||
{
|
||||
[DbContext(typeof(ChattingContext))]
|
||||
[Migration("20231130204741_Feature Permissions")]
|
||||
partial class FeaturePermissions
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "7.0.5")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Account", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ExternalId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("FeaturePermissionId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
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("FeaturePermissionId");
|
||||
|
||||
b.HasIndex("IsUserId");
|
||||
|
||||
b.HasIndex("SeenInChannelId");
|
||||
|
||||
b.ToTable("Accounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Attachment", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<byte[]>("Content")
|
||||
.HasColumnType("bytea");
|
||||
|
||||
b.Property<string>("ContentType")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal?>("ExternalId")
|
||||
.HasColumnType("numeric(20,0)");
|
||||
|
||||
b.Property<string>("Filename")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("MessageId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("Size")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Source")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MessageId");
|
||||
|
||||
b.ToTable("Attachments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ExternalId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("FeaturePermissionId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("IsDM")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<Guid?>("ParentChannelId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int?>("PermissionsId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Protocol")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("FeaturePermissionId");
|
||||
|
||||
b.HasIndex("ParentChannelId");
|
||||
|
||||
b.HasIndex("PermissionsId");
|
||||
|
||||
b.ToTable("Channels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.ChannelPermissions", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int?>("LewdnessFilterLevel")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool?>("LinksAllowed")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<decimal?>("MaxAttachmentBytes")
|
||||
.HasColumnType("numeric(20,0)");
|
||||
|
||||
b.Property<long?>("MaxTextChars")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<int?>("MeannessFilterLevel")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool?>("ReactionsPossible")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ChannelPermissions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.FeaturePermission", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("Inheritable")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("InternalName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int?>("InternalTag")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("FeaturePermissions");
|
||||
});
|
||||
|
||||
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.User", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid?>("FeaturePermissionId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("FeaturePermissionId");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Account", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.FeaturePermission", null)
|
||||
.WithMany("RestrictedToAccounts")
|
||||
.HasForeignKey("FeaturePermissionId");
|
||||
|
||||
b.HasOne("vassago.Models.User", "IsUser")
|
||||
.WithMany("Accounts")
|
||||
.HasForeignKey("IsUserId");
|
||||
|
||||
b.HasOne("vassago.Models.Channel", "SeenInChannel")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("SeenInChannelId");
|
||||
|
||||
b.Navigation("IsUser");
|
||||
|
||||
b.Navigation("SeenInChannel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Attachment", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.Message", "Message")
|
||||
.WithMany("Attachments")
|
||||
.HasForeignKey("MessageId");
|
||||
|
||||
b.Navigation("Message");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.FeaturePermission", null)
|
||||
.WithMany("RestrictedToChannels")
|
||||
.HasForeignKey("FeaturePermissionId");
|
||||
|
||||
b.HasOne("vassago.Models.Channel", "ParentChannel")
|
||||
.WithMany("SubChannels")
|
||||
.HasForeignKey("ParentChannelId");
|
||||
|
||||
b.HasOne("vassago.Models.ChannelPermissions", "Permissions")
|
||||
.WithMany()
|
||||
.HasForeignKey("PermissionsId");
|
||||
|
||||
b.Navigation("ParentChannel");
|
||||
|
||||
b.Navigation("Permissions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Message", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.Account", "Author")
|
||||
.WithMany()
|
||||
.HasForeignKey("AuthorId");
|
||||
|
||||
b.HasOne("vassago.Models.Channel", "Channel")
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("ChannelId");
|
||||
|
||||
b.Navigation("Author");
|
||||
|
||||
b.Navigation("Channel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.User", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.FeaturePermission", null)
|
||||
.WithMany("RestrictedToUsers")
|
||||
.HasForeignKey("FeaturePermissionId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
|
||||
b.Navigation("SubChannels");
|
||||
|
||||
b.Navigation("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.FeaturePermission", b =>
|
||||
{
|
||||
b.Navigation("RestrictedToAccounts");
|
||||
|
||||
b.Navigation("RestrictedToChannels");
|
||||
|
||||
b.Navigation("RestrictedToUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Message", b =>
|
||||
{
|
||||
b.Navigation("Attachments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.User", b =>
|
||||
{
|
||||
b.Navigation("Accounts");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
211
Migrations/20231130204741_Feature Permissions.cs
Normal file
211
Migrations/20231130204741_Feature Permissions.cs
Normal file
@ -0,0 +1,211 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace vassago.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class FeaturePermissions : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Channels_PermissionSettings_PermissionsId",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "PermissionSettings");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "PermissionTags",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "PermissionTags",
|
||||
table: "Accounts");
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "FeaturePermissionId",
|
||||
table: "Users",
|
||||
type: "uuid",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "FeaturePermissionId",
|
||||
table: "Channels",
|
||||
type: "uuid",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "FeaturePermissionId",
|
||||
table: "Accounts",
|
||||
type: "uuid",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ChannelPermissions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
MaxAttachmentBytes = table.Column<decimal>(type: "numeric(20,0)", nullable: true),
|
||||
MaxTextChars = table.Column<long>(type: "bigint", nullable: true),
|
||||
LinksAllowed = table.Column<bool>(type: "boolean", nullable: true),
|
||||
ReactionsPossible = table.Column<bool>(type: "boolean", nullable: true),
|
||||
LewdnessFilterLevel = table.Column<int>(type: "integer", nullable: true),
|
||||
MeannessFilterLevel = table.Column<int>(type: "integer", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ChannelPermissions", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "FeaturePermissions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
InternalName = table.Column<string>(type: "text", nullable: true),
|
||||
InternalTag = table.Column<int>(type: "integer", nullable: true),
|
||||
Inheritable = table.Column<bool>(type: "boolean", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_FeaturePermissions", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Users_FeaturePermissionId",
|
||||
table: "Users",
|
||||
column: "FeaturePermissionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Channels_FeaturePermissionId",
|
||||
table: "Channels",
|
||||
column: "FeaturePermissionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Accounts_FeaturePermissionId",
|
||||
table: "Accounts",
|
||||
column: "FeaturePermissionId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Accounts_FeaturePermissions_FeaturePermissionId",
|
||||
table: "Accounts",
|
||||
column: "FeaturePermissionId",
|
||||
principalTable: "FeaturePermissions",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Channels_ChannelPermissions_PermissionsId",
|
||||
table: "Channels",
|
||||
column: "PermissionsId",
|
||||
principalTable: "ChannelPermissions",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Channels_FeaturePermissions_FeaturePermissionId",
|
||||
table: "Channels",
|
||||
column: "FeaturePermissionId",
|
||||
principalTable: "FeaturePermissions",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Users_FeaturePermissions_FeaturePermissionId",
|
||||
table: "Users",
|
||||
column: "FeaturePermissionId",
|
||||
principalTable: "FeaturePermissions",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Accounts_FeaturePermissions_FeaturePermissionId",
|
||||
table: "Accounts");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Channels_ChannelPermissions_PermissionsId",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Channels_FeaturePermissions_FeaturePermissionId",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Users_FeaturePermissions_FeaturePermissionId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ChannelPermissions");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "FeaturePermissions");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Users_FeaturePermissionId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Channels_FeaturePermissionId",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Accounts_FeaturePermissionId",
|
||||
table: "Accounts");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "FeaturePermissionId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "FeaturePermissionId",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "FeaturePermissionId",
|
||||
table: "Accounts");
|
||||
|
||||
migrationBuilder.AddColumn<int[]>(
|
||||
name: "PermissionTags",
|
||||
table: "Users",
|
||||
type: "integer[]",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<int[]>(
|
||||
name: "PermissionTags",
|
||||
table: "Accounts",
|
||||
type: "integer[]",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PermissionSettings",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
LewdnessFilterLevel = table.Column<int>(type: "integer", nullable: true),
|
||||
LinksAllowed = table.Column<bool>(type: "boolean", nullable: true),
|
||||
MaxAttachmentBytes = table.Column<decimal>(type: "numeric(20,0)", nullable: true),
|
||||
MaxTextChars = table.Column<long>(type: "bigint", nullable: true),
|
||||
MeannessFilterLevel = table.Column<int>(type: "integer", nullable: true),
|
||||
ReactionsPossible = table.Column<bool>(type: "boolean", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PermissionSettings", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Channels_PermissionSettings_PermissionsId",
|
||||
table: "Channels",
|
||||
column: "PermissionsId",
|
||||
principalTable: "PermissionSettings",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
}
|
||||
}
|
349
Migrations/20231203193139_channeltype.Designer.cs
generated
Normal file
349
Migrations/20231203193139_channeltype.Designer.cs
generated
Normal file
@ -0,0 +1,349 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using vassago.Models;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace vassago.Migrations
|
||||
{
|
||||
[DbContext(typeof(ChattingContext))]
|
||||
[Migration("20231203193139_channeltype")]
|
||||
partial class channeltype
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "7.0.5")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Account", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ExternalId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("FeaturePermissionId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
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("FeaturePermissionId");
|
||||
|
||||
b.HasIndex("IsUserId");
|
||||
|
||||
b.HasIndex("SeenInChannelId");
|
||||
|
||||
b.ToTable("Accounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Attachment", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<byte[]>("Content")
|
||||
.HasColumnType("bytea");
|
||||
|
||||
b.Property<string>("ContentType")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal?>("ExternalId")
|
||||
.HasColumnType("numeric(20,0)");
|
||||
|
||||
b.Property<string>("Filename")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("MessageId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("Size")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Source")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MessageId");
|
||||
|
||||
b.ToTable("Attachments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("ChannelType")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ExternalId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("FeaturePermissionId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid?>("ParentChannelId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int?>("PermissionsId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Protocol")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("FeaturePermissionId");
|
||||
|
||||
b.HasIndex("ParentChannelId");
|
||||
|
||||
b.HasIndex("PermissionsId");
|
||||
|
||||
b.ToTable("Channels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.ChannelPermissions", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int?>("LewdnessFilterLevel")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool?>("LinksAllowed")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<decimal?>("MaxAttachmentBytes")
|
||||
.HasColumnType("numeric(20,0)");
|
||||
|
||||
b.Property<long?>("MaxTextChars")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<int?>("MeannessFilterLevel")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool?>("ReactionsPossible")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ChannelPermissions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.FeaturePermission", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("Inheritable")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("InternalName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int?>("InternalTag")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("FeaturePermissions");
|
||||
});
|
||||
|
||||
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.User", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid?>("FeaturePermissionId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("FeaturePermissionId");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Account", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.FeaturePermission", null)
|
||||
.WithMany("RestrictedToAccounts")
|
||||
.HasForeignKey("FeaturePermissionId");
|
||||
|
||||
b.HasOne("vassago.Models.User", "IsUser")
|
||||
.WithMany("Accounts")
|
||||
.HasForeignKey("IsUserId");
|
||||
|
||||
b.HasOne("vassago.Models.Channel", "SeenInChannel")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("SeenInChannelId");
|
||||
|
||||
b.Navigation("IsUser");
|
||||
|
||||
b.Navigation("SeenInChannel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Attachment", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.Message", "Message")
|
||||
.WithMany("Attachments")
|
||||
.HasForeignKey("MessageId");
|
||||
|
||||
b.Navigation("Message");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.FeaturePermission", null)
|
||||
.WithMany("RestrictedToChannels")
|
||||
.HasForeignKey("FeaturePermissionId");
|
||||
|
||||
b.HasOne("vassago.Models.Channel", "ParentChannel")
|
||||
.WithMany("SubChannels")
|
||||
.HasForeignKey("ParentChannelId");
|
||||
|
||||
b.HasOne("vassago.Models.ChannelPermissions", "Permissions")
|
||||
.WithMany()
|
||||
.HasForeignKey("PermissionsId");
|
||||
|
||||
b.Navigation("ParentChannel");
|
||||
|
||||
b.Navigation("Permissions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Message", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.Account", "Author")
|
||||
.WithMany()
|
||||
.HasForeignKey("AuthorId");
|
||||
|
||||
b.HasOne("vassago.Models.Channel", "Channel")
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("ChannelId");
|
||||
|
||||
b.Navigation("Author");
|
||||
|
||||
b.Navigation("Channel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.User", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.FeaturePermission", null)
|
||||
.WithMany("RestrictedToUsers")
|
||||
.HasForeignKey("FeaturePermissionId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
|
||||
b.Navigation("SubChannels");
|
||||
|
||||
b.Navigation("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.FeaturePermission", b =>
|
||||
{
|
||||
b.Navigation("RestrictedToAccounts");
|
||||
|
||||
b.Navigation("RestrictedToChannels");
|
||||
|
||||
b.Navigation("RestrictedToUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Message", b =>
|
||||
{
|
||||
b.Navigation("Attachments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.User", b =>
|
||||
{
|
||||
b.Navigation("Accounts");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
40
Migrations/20231203193139_channeltype.cs
Normal file
40
Migrations/20231203193139_channeltype.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace vassago.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class channeltype : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "IsDM",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "ChannelType",
|
||||
table: "Channels",
|
||||
type: "integer",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ChannelType",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "IsDM",
|
||||
table: "Channels",
|
||||
type: "boolean",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
}
|
||||
}
|
||||
}
|
266
Migrations/20240510202057_channelpermissions_partofchannel.Designer.cs
generated
Normal file
266
Migrations/20240510202057_channelpermissions_partofchannel.Designer.cs
generated
Normal file
@ -0,0 +1,266 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using vassago.Models;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace vassago.Migrations
|
||||
{
|
||||
[DbContext(typeof(ChattingContext))]
|
||||
[Migration("20240510202057_channelpermissions_partofchannel")]
|
||||
partial class channelpermissions_partofchannel
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "7.0.5")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Account", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ExternalId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("IsBot")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<Guid?>("IsUserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Protocol")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("SeenInChannelId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IsUserId");
|
||||
|
||||
b.HasIndex("SeenInChannelId");
|
||||
|
||||
b.ToTable("Accounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Attachment", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<byte[]>("Content")
|
||||
.HasColumnType("bytea");
|
||||
|
||||
b.Property<string>("ContentType")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal?>("ExternalId")
|
||||
.HasColumnType("numeric(20,0)");
|
||||
|
||||
b.Property<string>("Filename")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("MessageId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("Size")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Source")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MessageId");
|
||||
|
||||
b.ToTable("Attachments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("ChannelType")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ExternalId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int?>("LewdnessFilterLevel")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool?>("LinksAllowed")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<decimal?>("MaxAttachmentBytes")
|
||||
.HasColumnType("numeric(20,0)");
|
||||
|
||||
b.Property<long?>("MaxTextChars")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<int?>("MeannessFilterLevel")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<Guid?>("ParentChannelId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Protocol")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool?>("ReactionsPossible")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentChannelId");
|
||||
|
||||
b.ToTable("Channels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.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.User", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Account", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.User", "IsUser")
|
||||
.WithMany("Accounts")
|
||||
.HasForeignKey("IsUserId");
|
||||
|
||||
b.HasOne("vassago.Models.Channel", "SeenInChannel")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("SeenInChannelId");
|
||||
|
||||
b.Navigation("IsUser");
|
||||
|
||||
b.Navigation("SeenInChannel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Attachment", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.Message", "Message")
|
||||
.WithMany("Attachments")
|
||||
.HasForeignKey("MessageId");
|
||||
|
||||
b.Navigation("Message");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.Channel", "ParentChannel")
|
||||
.WithMany("SubChannels")
|
||||
.HasForeignKey("ParentChannelId");
|
||||
|
||||
b.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");
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
228
Migrations/20240510202057_channelpermissions_partofchannel.cs
Normal file
228
Migrations/20240510202057_channelpermissions_partofchannel.cs
Normal file
@ -0,0 +1,228 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace vassago.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class channelpermissions_partofchannel : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Accounts_FeaturePermissions_FeaturePermissionId",
|
||||
table: "Accounts");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Channels_ChannelPermissions_PermissionsId",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Channels_FeaturePermissions_FeaturePermissionId",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Users_FeaturePermissions_FeaturePermissionId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ChannelPermissions");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "FeaturePermissions");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Users_FeaturePermissionId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Channels_FeaturePermissionId",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Channels_PermissionsId",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Accounts_FeaturePermissionId",
|
||||
table: "Accounts");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "FeaturePermissionId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "FeaturePermissionId",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "FeaturePermissionId",
|
||||
table: "Accounts");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "PermissionsId",
|
||||
table: "Channels",
|
||||
newName: "MeannessFilterLevel");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "LewdnessFilterLevel",
|
||||
table: "Channels",
|
||||
type: "integer",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "LinksAllowed",
|
||||
table: "Channels",
|
||||
type: "boolean",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "MaxAttachmentBytes",
|
||||
table: "Channels",
|
||||
type: "numeric(20,0)",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<long>(
|
||||
name: "MaxTextChars",
|
||||
table: "Channels",
|
||||
type: "bigint",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "ReactionsPossible",
|
||||
table: "Channels",
|
||||
type: "boolean",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "LewdnessFilterLevel",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "LinksAllowed",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MaxAttachmentBytes",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MaxTextChars",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ReactionsPossible",
|
||||
table: "Channels");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "MeannessFilterLevel",
|
||||
table: "Channels",
|
||||
newName: "PermissionsId");
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "FeaturePermissionId",
|
||||
table: "Users",
|
||||
type: "uuid",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "FeaturePermissionId",
|
||||
table: "Channels",
|
||||
type: "uuid",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "FeaturePermissionId",
|
||||
table: "Accounts",
|
||||
type: "uuid",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ChannelPermissions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
LewdnessFilterLevel = table.Column<int>(type: "integer", nullable: true),
|
||||
LinksAllowed = table.Column<bool>(type: "boolean", nullable: true),
|
||||
MaxAttachmentBytes = table.Column<decimal>(type: "numeric(20,0)", nullable: true),
|
||||
MaxTextChars = table.Column<long>(type: "bigint", nullable: true),
|
||||
MeannessFilterLevel = table.Column<int>(type: "integer", nullable: true),
|
||||
ReactionsPossible = table.Column<bool>(type: "boolean", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ChannelPermissions", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "FeaturePermissions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Inheritable = table.Column<bool>(type: "boolean", nullable: false),
|
||||
InternalName = table.Column<string>(type: "text", nullable: true),
|
||||
InternalTag = table.Column<int>(type: "integer", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_FeaturePermissions", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Users_FeaturePermissionId",
|
||||
table: "Users",
|
||||
column: "FeaturePermissionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Channels_FeaturePermissionId",
|
||||
table: "Channels",
|
||||
column: "FeaturePermissionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Channels_PermissionsId",
|
||||
table: "Channels",
|
||||
column: "PermissionsId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Accounts_FeaturePermissionId",
|
||||
table: "Accounts",
|
||||
column: "FeaturePermissionId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Accounts_FeaturePermissions_FeaturePermissionId",
|
||||
table: "Accounts",
|
||||
column: "FeaturePermissionId",
|
||||
principalTable: "FeaturePermissions",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Channels_ChannelPermissions_PermissionsId",
|
||||
table: "Channels",
|
||||
column: "PermissionsId",
|
||||
principalTable: "ChannelPermissions",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Channels_FeaturePermissions_FeaturePermissionId",
|
||||
table: "Channels",
|
||||
column: "FeaturePermissionId",
|
||||
principalTable: "FeaturePermissions",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Users_FeaturePermissions_FeaturePermissionId",
|
||||
table: "Users",
|
||||
column: "FeaturePermissionId",
|
||||
principalTable: "FeaturePermissions",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
}
|
||||
}
|
263
Migrations/ChattingContextModelSnapshot.cs
Normal file
263
Migrations/ChattingContextModelSnapshot.cs
Normal file
@ -0,0 +1,263 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using vassago.Models;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace vassago.Migrations
|
||||
{
|
||||
[DbContext(typeof(ChattingContext))]
|
||||
partial class ChattingContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "7.0.5")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Account", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ExternalId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("IsBot")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<Guid?>("IsUserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Protocol")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("SeenInChannelId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IsUserId");
|
||||
|
||||
b.HasIndex("SeenInChannelId");
|
||||
|
||||
b.ToTable("Accounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Attachment", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<byte[]>("Content")
|
||||
.HasColumnType("bytea");
|
||||
|
||||
b.Property<string>("ContentType")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal?>("ExternalId")
|
||||
.HasColumnType("numeric(20,0)");
|
||||
|
||||
b.Property<string>("Filename")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("MessageId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("Size")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Source")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MessageId");
|
||||
|
||||
b.ToTable("Attachments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("ChannelType")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ExternalId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int?>("LewdnessFilterLevel")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool?>("LinksAllowed")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<decimal?>("MaxAttachmentBytes")
|
||||
.HasColumnType("numeric(20,0)");
|
||||
|
||||
b.Property<long?>("MaxTextChars")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<int?>("MeannessFilterLevel")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<Guid?>("ParentChannelId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Protocol")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool?>("ReactionsPossible")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentChannelId");
|
||||
|
||||
b.ToTable("Channels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.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.User", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Account", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.User", "IsUser")
|
||||
.WithMany("Accounts")
|
||||
.HasForeignKey("IsUserId");
|
||||
|
||||
b.HasOne("vassago.Models.Channel", "SeenInChannel")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("SeenInChannelId");
|
||||
|
||||
b.Navigation("IsUser");
|
||||
|
||||
b.Navigation("SeenInChannel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Attachment", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.Message", "Message")
|
||||
.WithMany("Attachments")
|
||||
.HasForeignKey("MessageId");
|
||||
|
||||
b.Navigation("Message");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
||||
{
|
||||
b.HasOne("vassago.Models.Channel", "ParentChannel")
|
||||
.WithMany("SubChannels")
|
||||
.HasForeignKey("ParentChannelId");
|
||||
|
||||
b.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");
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
31
Models/Account.cs
Normal file
31
Models/Account.cs
Normal file
@ -0,0 +1,31 @@
|
||||
namespace vassago.Models;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class Account
|
||||
{
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid Id { get; set; }
|
||||
public string ExternalId { get; set; }
|
||||
public string Username { get; set; }
|
||||
private string _displayName = null;
|
||||
public string DisplayName
|
||||
{
|
||||
get
|
||||
{
|
||||
return _displayName ?? Username;
|
||||
}
|
||||
set
|
||||
{
|
||||
_displayName = value;
|
||||
}
|
||||
}
|
||||
public bool IsBot { get; set; } //webhook counts
|
||||
public Channel SeenInChannel { get; set; }
|
||||
public string Protocol { get; set; }
|
||||
public User IsUser {get; set;}
|
||||
}
|
18
Models/Attachment.cs
Normal file
18
Models/Attachment.cs
Normal file
@ -0,0 +1,18 @@
|
||||
namespace vassago.Models;
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
public class Attachment
|
||||
{
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid Id { get; set; }
|
||||
public ulong? ExternalId { get; set; }
|
||||
public Uri Source { get; set; }
|
||||
public byte[] Content { get; set; }
|
||||
public string Filename { get; set; }
|
||||
public Message Message { get; set; }
|
||||
public string ContentType { get; internal set; }
|
||||
public string Description { get; internal set; }
|
||||
public int Size { get; internal set; }
|
||||
}
|
91
Models/Channel.cs
Normal file
91
Models/Channel.cs
Normal file
@ -0,0 +1,91 @@
|
||||
namespace vassago.Models;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using static vassago.Models.Enumerations;
|
||||
|
||||
public class Channel
|
||||
{
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid Id { get; set; }
|
||||
public string ExternalId { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public List<Channel> SubChannels { get; set; }
|
||||
public Channel ParentChannel { get; set; }
|
||||
public string Protocol { get; set; }
|
||||
public List<Message> Messages { get; set; }
|
||||
public List<Account> Users { get; set; }
|
||||
public ChannelType ChannelType {get; set; }
|
||||
|
||||
//Permissions
|
||||
public ulong? MaxAttachmentBytes { get; set; }
|
||||
public uint? MaxTextChars { get; set; }
|
||||
public bool? LinksAllowed { get; set; }
|
||||
public bool? ReactionsPossible { get; set; }
|
||||
public Enumerations.LewdnessFilterLevel? LewdnessFilterLevel { get; set; }
|
||||
public Enumerations.MeannessFilterLevel? MeannessFilterLevel { get; set; }
|
||||
|
||||
[NonSerialized]
|
||||
public Func<string, string, Task> SendFile;
|
||||
|
||||
[NonSerialized]
|
||||
public Func<string, Task> SendMessage;
|
||||
|
||||
|
||||
public DefinitePermissionSettings EffectivePermissions
|
||||
{
|
||||
get
|
||||
{
|
||||
var path = new Stack<Channel>(); //omg i actually get to use a data structure from university
|
||||
var walker = this;
|
||||
path.Push(this);
|
||||
while(walker.ParentChannel != null)
|
||||
{
|
||||
walker = walker.ParentChannel;
|
||||
path.Push(walker);
|
||||
}
|
||||
DefinitePermissionSettings toReturn = new DefinitePermissionSettings();
|
||||
|
||||
while(path.Count > 0)
|
||||
{
|
||||
walker = path.Pop();
|
||||
toReturn.LewdnessFilterLevel = walker.LewdnessFilterLevel ?? toReturn.LewdnessFilterLevel;
|
||||
toReturn.MeannessFilterLevel = walker.MeannessFilterLevel ?? toReturn.MeannessFilterLevel;
|
||||
toReturn.LinksAllowed = walker.LinksAllowed ?? toReturn.LinksAllowed;
|
||||
toReturn.MaxAttachmentBytes = walker.MaxAttachmentBytes ?? toReturn.MaxAttachmentBytes;
|
||||
toReturn.MaxTextChars = walker.MaxTextChars ?? toReturn.MaxTextChars;
|
||||
toReturn.ReactionsPossible = walker.ReactionsPossible ?? toReturn.ReactionsPossible;
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
}
|
||||
public string LineageSummary
|
||||
{
|
||||
get
|
||||
{
|
||||
if(this.ParentChannel != null)
|
||||
{
|
||||
return this.ParentChannel.LineageSummary + '/' + this.DisplayName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.Protocol;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DefinitePermissionSettings
|
||||
{
|
||||
public ulong MaxAttachmentBytes { get; set; }
|
||||
public uint MaxTextChars { get; set; }
|
||||
public bool LinksAllowed { get; set; }
|
||||
public bool ReactionsPossible { get; set; }
|
||||
public Enumerations.LewdnessFilterLevel LewdnessFilterLevel { get; set; }
|
||||
public Enumerations.MeannessFilterLevel MeannessFilterLevel { get; set; }
|
||||
}
|
22
Models/ChattingContext.cs
Normal file
22
Models/ChattingContext.cs
Normal file
@ -0,0 +1,22 @@
|
||||
namespace vassago.Models;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
public class ChattingContext : DbContext
|
||||
{
|
||||
public DbSet<Attachment> Attachments { get; set; }
|
||||
public DbSet<Channel> Channels { get; set; }
|
||||
//public DbSet<Emoji> Emoji {get;set;}
|
||||
public DbSet<Message> Messages { get; set; }
|
||||
public DbSet<Account> Accounts { get; set; }
|
||||
public DbSet<User> Users { get; set; }
|
||||
|
||||
public ChattingContext(DbContextOptions<ChattingContext> options) : base(options) { }
|
||||
public ChattingContext() : base() { }
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
optionsBuilder.UseNpgsql(Shared.DBConnectionString)
|
||||
.EnableSensitiveDataLogging(true); //who the fuck is looking at log output but not allowed to see it? this should be on by default.
|
||||
}
|
||||
}
|
67
Models/Enums.cs
Normal file
67
Models/Enums.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
|
||||
namespace vassago.Models;
|
||||
|
||||
public static class Enumerations
|
||||
{
|
||||
public enum LewdnessFilterLevel
|
||||
{
|
||||
[Description("this is a christian minecraft server 🙏")]
|
||||
Strict,
|
||||
[Description("G-Rated")]
|
||||
G,
|
||||
[Description("polite company")]
|
||||
Moderate,
|
||||
[Description(";) ;) ;)")]
|
||||
Unrestricted
|
||||
}
|
||||
public enum MeannessFilterLevel
|
||||
{
|
||||
[Description("good vibes only")]
|
||||
Strict,
|
||||
[Description("a bit cheeky")]
|
||||
Medium,
|
||||
[Description("387.44m mi of printed circuits")]
|
||||
Unrestricted
|
||||
}
|
||||
|
||||
public enum ChannelType
|
||||
{
|
||||
[Description("Normal")]
|
||||
Normal,
|
||||
[Description("DM")]
|
||||
DM,
|
||||
[Description("protocol psuedo-channel")]
|
||||
Protocol,
|
||||
[Description("organizational psuedo-channel")]
|
||||
OU
|
||||
}
|
||||
|
||||
public static string GetDescription<T>(this T enumerationValue)
|
||||
where T : struct
|
||||
{
|
||||
Type type = enumerationValue.GetType();
|
||||
if (!type.IsEnum)
|
||||
{
|
||||
throw new ArgumentException("EnumerationValue must be of Enum type", nameof(enumerationValue));
|
||||
}
|
||||
|
||||
//Tries to find a DescriptionAttribute for a potential friendly name
|
||||
//for the enum
|
||||
MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
|
||||
if (memberInfo != null && memberInfo.Length > 0)
|
||||
{
|
||||
object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
|
||||
|
||||
if (attrs != null && attrs.Length > 0)
|
||||
{
|
||||
//Pull out the description value
|
||||
return ((DescriptionAttribute)attrs[0]).Description;
|
||||
}
|
||||
}
|
||||
//If we have no description attribute, just return the ToString of the enum
|
||||
return enumerationValue.ToString();
|
||||
}
|
||||
}
|
31
Models/Message.cs
Normal file
31
Models/Message.cs
Normal file
@ -0,0 +1,31 @@
|
||||
namespace vassago.Models;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
|
||||
public class Message
|
||||
{
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid Id { get; set; }
|
||||
public string Protocol { get; set; }
|
||||
public string ExternalId { get; set; }
|
||||
public string Content { get; set; }
|
||||
public bool MentionsMe { get; set; }
|
||||
public DateTimeOffset Timestamp { get; set; }
|
||||
public bool ActedOn { get; set; }
|
||||
public List<Attachment> Attachments { get; set; }
|
||||
public Account Author { get; set; }
|
||||
public Channel Channel { get; set; }
|
||||
|
||||
|
||||
|
||||
[NonSerialized]
|
||||
public Func<string, Task> Reply;
|
||||
|
||||
[NonSerialized]
|
||||
public Func<string, Task> React;
|
||||
}
|
25
Models/User.cs
Normal file
25
Models/User.cs
Normal file
@ -0,0 +1,25 @@
|
||||
namespace vassago.Models;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Reflection;
|
||||
|
||||
public class User
|
||||
{
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid Id { get; set; }
|
||||
public List<Account> Accounts { get; set; }
|
||||
|
||||
public string DisplayName
|
||||
{
|
||||
get
|
||||
{
|
||||
return Accounts.Select(a => a.DisplayName).Distinct()
|
||||
.MaxBy(distinctName =>
|
||||
Accounts.Select(a => a.DisplayName)
|
||||
.Where(selectedName => selectedName == distinctName).Count()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
394
Program.cs
394
Program.cs
@ -1,341 +1,53 @@
|
||||
//https://discord.com/oauth2/authorize?client_id=913003037348491264&permissions=274877942784&scope=bot%20messages.read
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Diagnostics;
|
||||
using Discord.Net;
|
||||
|
||||
namespace silverworker_discord
|
||||
{
|
||||
class Program
|
||||
{
|
||||
private DiscordSocketClient _client;
|
||||
private bool eventsSignedUp = false;
|
||||
private Random r = new Random();
|
||||
|
||||
IConfigurationRoot config = new ConfigurationBuilder()
|
||||
.AddJsonFile("appsettings.json", true, true)
|
||||
.Build();
|
||||
|
||||
public static void Main(string[] args)
|
||||
=> new Program().MainAsync().GetAwaiter().GetResult();
|
||||
private Task Log(LogMessage msg)
|
||||
{
|
||||
Console.WriteLine(msg.ToString());
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
public async Task MainAsync()
|
||||
{
|
||||
#if !DEBUG
|
||||
Process[] processes = Process.GetProcesses();
|
||||
Process currentProc = Process.GetCurrentProcess();
|
||||
Console.WriteLine("Current proccess: {0}", currentProc.ProcessName);
|
||||
foreach (Process process in processes)
|
||||
{
|
||||
if (currentProc.ProcessName == process.ProcessName && currentProc.Id != process.Id)
|
||||
{
|
||||
Console.Error.WriteLine($"{DateTime.Now} - Another instance of this process is already running: {process.Id} (I'm {currentProc.Id})");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Conversion.Converter.Load(config["exchangePairsLocation"]);
|
||||
|
||||
_client = new DiscordSocketClient(new DiscordSocketConfig(){GatewayIntents = GatewayIntents.All});
|
||||
|
||||
_client.Log += Log;
|
||||
|
||||
_client.Ready += () => Task.Run(() =>
|
||||
{
|
||||
if (!eventsSignedUp)
|
||||
{
|
||||
eventsSignedUp = true;
|
||||
Console.WriteLine("Bot is connected! going to sign up for message received and user joined in client ready");
|
||||
|
||||
_client.MessageReceived += MessageReceived;
|
||||
_client.UserJoined += UserJoined;
|
||||
//_client.ButtonExecuted += MyButtonHandler;
|
||||
_client.SlashCommandExecuted += SlashCommandsHelper.SlashCommandHandler;
|
||||
SlashCommandsHelper.Register(_client).GetAwaiter().GetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("bot appears to be RE connected, so I'm not going to sign up twice");
|
||||
}
|
||||
});
|
||||
|
||||
await _client.LoginAsync(TokenType.Bot, config["token"]);
|
||||
await _client.StartAsync();
|
||||
|
||||
// Block this task until the program is closed.
|
||||
await Task.Delay(-1);
|
||||
|
||||
}
|
||||
|
||||
#pragma warning disable 4014 //the "you're not awaiting this" warning. yeah I know, that's the beauty of an async method lol
|
||||
#pragma warning disable 1998 //the "it's async but you're not awaiting anything".
|
||||
private async Task MessageReceived(SocketMessage messageParam)
|
||||
#pragma warning restore 1998
|
||||
{
|
||||
var message = messageParam as SocketUserMessage;
|
||||
if (message == null) return;
|
||||
if (message.Author.Id == _client.CurrentUser.Id) return;
|
||||
|
||||
Console.WriteLine($"#{message.Channel}[{DateTime.Now}][{message.Author.Username} [id={message.Author.Id}]][msg id: {message.Id}] {message.Content}");
|
||||
|
||||
if (message.Author.IsWebhook || message.Author.IsBot)
|
||||
{
|
||||
if (message.Author.Id == 159985870458322944) //MEE6
|
||||
{
|
||||
if (message.Content?.Contains("you just advanced") == true)
|
||||
{
|
||||
var newText = Regex.Replace(message.Content, "<[^>]*>", message.Author.Username);
|
||||
newText = Regex.Replace(newText, "level [\\d]+", "level -1");
|
||||
Features.mock(newText, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var didThing = false;
|
||||
var contentWithoutMention = message.Content;
|
||||
var mentionedMe = false;
|
||||
if (message.MentionedUsers?.FirstOrDefault(muid => muid.Id == _client.CurrentUser.Id) != null)
|
||||
{
|
||||
var mentionOfMe = "<@" + _client.CurrentUser.Id + ">";
|
||||
contentWithoutMention = message.Content.Replace(mentionOfMe + " ", null);
|
||||
contentWithoutMention = contentWithoutMention.Replace(mentionOfMe, null);
|
||||
mentionedMe = true;
|
||||
}
|
||||
var wordLikes = message.Content.Split(' ', StringSplitOptions.TrimEntries);
|
||||
var links = wordLikes?.Where(wl => Uri.IsWellFormedUriString(wl, UriKind.Absolute)).Select(wl => new Uri(wl));
|
||||
if (links != null && links.Count() > 0)
|
||||
{
|
||||
foreach (var link in links)
|
||||
{
|
||||
if (link.Host.EndsWith(".tiktok.com"))
|
||||
{
|
||||
Features.detiktokify(link, message);
|
||||
didThing = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (message.Attachments?.Count > 0)
|
||||
{
|
||||
Console.WriteLine($"{message.Attachments.Count} attachments");
|
||||
var appleReactions = false;
|
||||
foreach (var att in message.Attachments)
|
||||
{
|
||||
if (att.Filename?.EndsWith(".heic") == true)
|
||||
{
|
||||
Features.deheic(message, att);
|
||||
appleReactions = true;
|
||||
didThing = true;
|
||||
}
|
||||
}
|
||||
if (appleReactions)
|
||||
{
|
||||
message.AddReactionAsync(new Emoji("\U0001F34F"));
|
||||
}
|
||||
}
|
||||
|
||||
var msgText = message.Content?.ToLower();
|
||||
if (!string.IsNullOrWhiteSpace(msgText))
|
||||
{
|
||||
if (Regex.IsMatch(msgText, "\\bcloud( |-)?native\\b", RegexOptions.IgnoreCase) ||
|
||||
Regex.IsMatch(msgText, "\\benterprise( |-)?(level|solution)\\b", RegexOptions.IgnoreCase))
|
||||
{
|
||||
switch (r.Next(2))
|
||||
{
|
||||
case 0:
|
||||
await message.AddReactionAsync(new Emoji("\uD83E\uDD2E")); //vomit emoji
|
||||
break;
|
||||
case 1:
|
||||
await message.AddReactionAsync(new Emoji("\uD83C\uDDE7")); //B emoji
|
||||
await message.AddReactionAsync(new Emoji("\uD83C\uDDE6")); //A
|
||||
await message.AddReactionAsync(new Emoji("\uD83C\uDDF3")); //N
|
||||
break;
|
||||
}
|
||||
didThing = true;
|
||||
}
|
||||
if (Regex.IsMatch(msgText, "^(s?he|(yo)?u|y'?all) thinks? i'?m (playin|jokin|kiddin)g?$", RegexOptions.IgnoreCase))
|
||||
{
|
||||
await message.Channel.SendMessageAsync("I believed you for a second, but then you assured me you's a \uD83C\uDDE7 \uD83C\uDDEE \uD83C\uDDF9 \uD83C\uDDE8 \uD83C\uDDED");
|
||||
didThing = true;
|
||||
}
|
||||
if (Regex.IsMatch(msgText, "\\bskynet\\b", RegexOptions.IgnoreCase))
|
||||
{
|
||||
Features.Skynet(message);
|
||||
didThing = true;
|
||||
}
|
||||
if (Regex.IsMatch(msgText, "\\bchatgpt\\b", RegexOptions.IgnoreCase))
|
||||
{
|
||||
message.Channel.SendMessageAsync("chatGPT is **weak**. also, are we done comparing every little if-then-else to skynet?");
|
||||
didThing = true;
|
||||
}
|
||||
if (Regex.IsMatch(msgText, "\\bi need (an? )?(peptalk|inspiration|ego-?boost)\\b", RegexOptions.IgnoreCase))
|
||||
{
|
||||
Console.WriteLine("peptalk");
|
||||
Features.peptalk(message);
|
||||
didThing = true;
|
||||
}
|
||||
if (Regex.IsMatch(msgText, "\\bwish me luck\\b", RegexOptions.IgnoreCase))
|
||||
{
|
||||
if (r.Next(20) == 0)
|
||||
{
|
||||
await message.AddReactionAsync(new Emoji("\U0001f340"));//4-leaf clover
|
||||
}
|
||||
else
|
||||
{
|
||||
await message.AddReactionAsync(new Emoji("☘️"));
|
||||
}
|
||||
didThing = true;
|
||||
}
|
||||
if (Regex.IsMatch(msgText, "\\bgaslight(ing)?\\b", RegexOptions.IgnoreCase))
|
||||
{
|
||||
message.Channel.SendMessageAsync("that's not what gaslight means. Did you mean \"say something that (you believe) is wrong\"?");
|
||||
didThing = true;
|
||||
}
|
||||
if (msgText.Contains("!qrplz "))
|
||||
{
|
||||
Features.qrify(message.Content.Substring("!qrplz ".Length + msgText.IndexOf("!qrplz ")), message);
|
||||
didThing = true;
|
||||
}
|
||||
if (msgText.Contains("!freedomunits "))
|
||||
{
|
||||
Features.Convert(message, contentWithoutMention);
|
||||
didThing = true;
|
||||
}
|
||||
if (Regex.IsMatch(msgText, "!joke\\b"))
|
||||
{
|
||||
Features.Joke(message);
|
||||
didThing = true;
|
||||
}
|
||||
if (Regex.IsMatch(msgText, "!pulse ?check\\b"))
|
||||
{
|
||||
message.Channel.SendFileAsync("assets/ekgblip.png");
|
||||
Console.WriteLine(Conversion.Converter.DebugInfo());
|
||||
didThing = true;
|
||||
}
|
||||
if (mentionedMe && (Regex.IsMatch(msgText, "\\brecipe for .+") || Regex.IsMatch(msgText, ".+ recipe\\b")))
|
||||
{
|
||||
Features.Recipe(message);
|
||||
didThing = true;
|
||||
}
|
||||
if (msgText.Contains("cognitive dissonance") == true)
|
||||
{
|
||||
message.ReplyAsync("that's not what cognitive dissonance means. Did you mean \"hypocrisy\"?");
|
||||
didThing = true;
|
||||
}
|
||||
if (mentionedMe && Regex.IsMatch(msgText, "what'?s the longest (six|6)(-| )?letter word( in english)?\\b"))
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await message.Channel.SendMessageAsync("mother.");
|
||||
await Task.Delay(3000);
|
||||
await message.Channel.SendMessageAsync("oh, longest? I thought you said fattest.");
|
||||
});
|
||||
didThing = true;
|
||||
}
|
||||
if (Regex.IsMatch(msgText, "\\bthank (yo)?u\\b", RegexOptions.IgnoreCase) &&
|
||||
(mentionedMe || Regex.IsMatch(msgText, "\\b(sh?tik)?bot\\b", RegexOptions.IgnoreCase)))
|
||||
{
|
||||
switch (r.Next(4))
|
||||
{
|
||||
case 0:
|
||||
message.Channel.SendMessageAsync("you're welcome, citizen!");
|
||||
break;
|
||||
case 1:
|
||||
message.AddReactionAsync(new Emoji("☺"));
|
||||
break;
|
||||
case 2:
|
||||
message.AddReactionAsync(new Emoji("\U0001F607")); //smiling face with halo
|
||||
break;
|
||||
case 3:
|
||||
switch (r.Next(9))
|
||||
{
|
||||
case 0:
|
||||
message.AddReactionAsync(new Emoji("❤")); //normal heart, usually rendered red
|
||||
break;
|
||||
case 1:
|
||||
message.AddReactionAsync(new Emoji("\U0001F9E1")); //orange heart
|
||||
break;
|
||||
case 2:
|
||||
message.AddReactionAsync(new Emoji("\U0001F49B")); //yellow heart
|
||||
break;
|
||||
case 3:
|
||||
message.AddReactionAsync(new Emoji("\U0001F49A")); //green heart
|
||||
break;
|
||||
case 4:
|
||||
message.AddReactionAsync(new Emoji("\U0001F499")); //blue heart
|
||||
break;
|
||||
case 5:
|
||||
message.AddReactionAsync(new Emoji("\U0001F49C")); //purple heart
|
||||
break;
|
||||
case 6:
|
||||
message.AddReactionAsync(new Emoji("\U0001F90E")); //brown heart
|
||||
break;
|
||||
case 7:
|
||||
message.AddReactionAsync(new Emoji("\U0001F5A4")); //black heart
|
||||
break;
|
||||
case 8:
|
||||
message.AddReactionAsync(new Emoji("\U0001F90D")); //white heart
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
didThing = true;
|
||||
#pragma warning restore 4014
|
||||
}
|
||||
// if (didThing == false && mentionedMe && contentWithoutMention.Contains("how long has that been there?"))
|
||||
// {
|
||||
// await message.Channel.SendMessageAsync("text", false, null, null, null, null, new ComponentBuilder().WithButton("label", "custom-id").Build());
|
||||
// didThing = true;
|
||||
// }
|
||||
if (didThing == false && mentionedMe && contentWithoutMention.Contains('?'))
|
||||
{
|
||||
Console.WriteLine("providing bullshit nonanswer / admitting uselessness");
|
||||
var responses = new List<string>(){
|
||||
@"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.SendMessageAsync(responses[r.Next(responses.Count)]);
|
||||
didThing = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private Task UserJoined(SocketGuildUser arg)
|
||||
{
|
||||
Console.WriteLine($"user joined: {arg.Nickname}. Guid: {arg.Guild.Id}. Channel: {arg.Guild.DefaultChannel}");
|
||||
var abbreviatedNickname = arg.Nickname;
|
||||
if (arg.Nickname.Length > 3)
|
||||
{
|
||||
abbreviatedNickname = arg.Nickname.Substring(0, arg.Nickname.Length / 3);
|
||||
}
|
||||
Console.WriteLine($"imma call him {abbreviatedNickname}");
|
||||
return arg.Guild.DefaultChannel.SendMessageAsync($"oh hey {abbreviatedNickname}- IPLAYTHESEALOFORICHALCOS <:ORICHALCOS:852749196633309194>");
|
||||
}
|
||||
private async Task ButtonHandler(SocketMessageComponent component)
|
||||
{
|
||||
switch(component.Data.CustomId)
|
||||
{
|
||||
case "custom-id":
|
||||
await component.RespondAsync($"{component.User.Mention}, it's been here the whole time!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Mvc.NewtonsoftJson;
|
||||
using vassago.Models;
|
||||
|
||||
#pragma warning disable CA2254
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddControllersWithViews();
|
||||
builder.Services.AddSingleton<IHostedService, vassago.ConsoleService>();
|
||||
builder.Services.AddDbContext<ChattingContext>();
|
||||
builder.Services.AddControllers().AddNewtonsoftJson();
|
||||
builder.Services.AddProblemDetails();
|
||||
builder.Services.Configure<RazorViewEngineOptions>(o => {
|
||||
o.ViewLocationFormats.Clear();
|
||||
o.ViewLocationFormats.Add("/WebInterface/Views/{1}/{0}" + RazorViewEngine.ViewExtension);
|
||||
o.ViewLocationFormats.Add("/WebInterface/Views/Shared/{0}" + RazorViewEngine.ViewExtension);
|
||||
});
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseExceptionHandler("/Home/Error");
|
||||
}
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseRouting();
|
||||
app.UseAuthorization();
|
||||
app.MapControllerRoute(
|
||||
name: "default",
|
||||
pattern: "{controller=Home}/{action=Index}/{id?}");
|
||||
|
||||
app.UseSwagger();
|
||||
|
||||
app.UseSwaggerUI(c =>
|
||||
{
|
||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "api");
|
||||
});
|
||||
|
||||
app.UseExceptionHandler();
|
||||
app.UseStatusCodePages();
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
app.Run();
|
||||
|
37
Properties/launchSettings.json
Normal file
37
Properties/launchSettings.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:42619",
|
||||
"sslPort": 44354
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:5093",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:7206;http://localhost:5093",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
345
ProtocolInterfaces/DiscordInterface/DiscordInterface.cs
Normal file
345
ProtocolInterfaces/DiscordInterface/DiscordInterface.cs
Normal file
@ -0,0 +1,345 @@
|
||||
//https://discord.com/oauth2/authorize?client_id=913003037348491264&permissions=274877942784&scope=bot%20messages.read
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using vassago.Models;
|
||||
using vassago.Behavior;
|
||||
using Discord.Rest;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Threading;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace vassago.DiscordInterface;
|
||||
|
||||
public class DiscordInterface
|
||||
{
|
||||
internal const string PROTOCOL = "discord";
|
||||
internal DiscordSocketClient client;
|
||||
private bool eventsSignedUp = false;
|
||||
private ChattingContext _db;
|
||||
private static SemaphoreSlim discordChannelSetup = new SemaphoreSlim(1, 1);
|
||||
private Channel protocolAsChannel;
|
||||
|
||||
public DiscordInterface()
|
||||
{
|
||||
_db = new ChattingContext();
|
||||
}
|
||||
|
||||
public async Task Init(string token)
|
||||
{
|
||||
await SetupDiscordChannel();
|
||||
client = new DiscordSocketClient(new DiscordSocketConfig() { GatewayIntents = GatewayIntents.All });
|
||||
|
||||
client.Log += (msg) =>
|
||||
{
|
||||
Console.WriteLine(msg.ToString());
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
client.Connected += SelfConnected;
|
||||
client.Ready += ClientReady;
|
||||
|
||||
await client.LoginAsync(TokenType.Bot, token);
|
||||
await client.StartAsync();
|
||||
}
|
||||
|
||||
private async Task SetupDiscordChannel()
|
||||
{
|
||||
await discordChannelSetup.WaitAsync();
|
||||
|
||||
try
|
||||
{
|
||||
protocolAsChannel = _db.Channels.FirstOrDefault(c => c.ParentChannel == null && c.Protocol == PROTOCOL);
|
||||
if (protocolAsChannel == null)
|
||||
{
|
||||
protocolAsChannel = new Channel()
|
||||
{
|
||||
DisplayName = "discord (itself)",
|
||||
MeannessFilterLevel = Enumerations.MeannessFilterLevel.Strict,
|
||||
LewdnessFilterLevel = Enumerations.LewdnessFilterLevel.Moderate,
|
||||
MaxTextChars = 2000,
|
||||
MaxAttachmentBytes = 25 * 1024 * 1024, //allegedly it's 25, but I worry it's not actually.
|
||||
LinksAllowed = true,
|
||||
ReactionsPossible = true,
|
||||
ExternalId = null,
|
||||
Protocol = PROTOCOL,
|
||||
SubChannels = new List<Channel>()
|
||||
};
|
||||
protocolAsChannel.SendMessage = (t) => { throw new InvalidOperationException($"discord itself cannot accept text"); };
|
||||
protocolAsChannel.SendFile = (f, t) => { throw new InvalidOperationException($"discord itself cannot send file"); };
|
||||
_db.Channels.Add(protocolAsChannel);
|
||||
_db.SaveChanges();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
discordChannelSetup.Release();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ClientReady()
|
||||
{
|
||||
if (!eventsSignedUp)
|
||||
{
|
||||
eventsSignedUp = true;
|
||||
Console.WriteLine($"Bot is connected ({client.CurrentUser.Username}; {client.CurrentUser.Mention})! going to sign up for message received and user joined in client ready");
|
||||
|
||||
client.MessageReceived += MessageReceived;
|
||||
// _client.MessageUpdated +=
|
||||
//client.UserJoined += UserJoined;
|
||||
client.SlashCommandExecuted += SlashCommandHandler;
|
||||
//client.ChannelCreated +=
|
||||
// _client.ChannelDestroyed +=
|
||||
// _client.ChannelUpdated +=
|
||||
// _client.GuildMemberUpdated +=
|
||||
// _client.UserBanned +=
|
||||
// _client.UserLeft +=
|
||||
// _client.ThreadCreated +=
|
||||
// _client.ThreadUpdated +=
|
||||
// _client.ThreadDeleted +=
|
||||
// _client.JoinedGuild +=
|
||||
// _client.GuildUpdated +=
|
||||
// _client.LeftGuild +=
|
||||
|
||||
await SlashCommandsHelper.Register(client);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("bot appears to be RE connected, so I'm not going to sign up twice");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SelfConnected()
|
||||
{
|
||||
var selfAccount = UpsertAccount(client.CurrentUser, protocolAsChannel);
|
||||
selfAccount.DisplayName = client.CurrentUser.Username;
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
Behaver.Instance.MarkSelf(selfAccount);
|
||||
}
|
||||
|
||||
private async Task MessageReceived(SocketMessage messageParam)
|
||||
{
|
||||
var suMessage = messageParam as SocketUserMessage;
|
||||
if (suMessage == null)
|
||||
{
|
||||
Console.WriteLine($"{messageParam.Content}, but not a user message");
|
||||
return;
|
||||
}
|
||||
Console.WriteLine($"#{suMessage.Channel}[{DateTime.Now}][{suMessage.Author.Username} [id={suMessage.Author.Id}]][msg id: {suMessage.Id}] {suMessage.Content}");
|
||||
|
||||
var m = UpsertMessage(suMessage);
|
||||
|
||||
if (suMessage.MentionedUsers?.FirstOrDefault(muid => muid.Id == client.CurrentUser.Id) != null)
|
||||
{
|
||||
var mentionOfMe = "<@" + client.CurrentUser.Id + ">";
|
||||
m.MentionsMe = true;
|
||||
}
|
||||
if (await Behaver.Instance.ActOn(m))
|
||||
{
|
||||
m.ActedOn = true;
|
||||
}
|
||||
_db.SaveChanges();
|
||||
}
|
||||
|
||||
private void UserJoined(SocketGuildUser arg)
|
||||
{
|
||||
var guild = UpsertChannel(arg.Guild);
|
||||
var defaultChannel = UpsertChannel(arg.Guild.DefaultChannel);
|
||||
defaultChannel.ParentChannel = guild;
|
||||
var u = UpsertAccount(arg, guild);
|
||||
u.DisplayName = arg.DisplayName;
|
||||
}
|
||||
private async Task ButtonHandler(SocketMessageComponent component)
|
||||
{
|
||||
switch (component.Data.CustomId)
|
||||
{
|
||||
case "custom-id":
|
||||
await component.RespondAsync($"{component.User.Mention}, it's been here the whole time!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
internal static async Task SlashCommandHandler(SocketSlashCommand command)
|
||||
{
|
||||
switch (command.CommandName)
|
||||
{
|
||||
case "freedomunits":
|
||||
try
|
||||
{
|
||||
var amt = Convert.ToDecimal((double)(command.Data.Options.First(o => o.Name == "amount").Value));
|
||||
var src = (string)command.Data.Options.First(o => o.Name == "src-unit").Value;
|
||||
var dest = (string)command.Data.Options.First(o => o.Name == "dest-unit").Value;
|
||||
var conversionResult = Conversion.Converter.Convert(amt, src, dest);
|
||||
|
||||
await command.RespondAsync($"> {amt} {src} -> {dest}\n{conversionResult}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await command.RespondAsync($"error: {e.Message}. aaadam!");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
await command.RespondAsync($"\\*smiles and nods*\n");
|
||||
await command.Channel.SendFileAsync($"assets/loud sweating.gif");
|
||||
Console.Error.WriteLine($"can't understand command name: {command.CommandName}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
internal vassago.Models.Attachment UpsertAttachment(IAttachment dAttachment)
|
||||
{
|
||||
var a = _db.Attachments.FirstOrDefault(ai => ai.ExternalId == dAttachment.Id);
|
||||
if (a == null)
|
||||
{
|
||||
a = new vassago.Models.Attachment();
|
||||
_db.Attachments.Add(a);
|
||||
}
|
||||
a.ContentType = dAttachment.ContentType;
|
||||
a.Description = dAttachment.Description;
|
||||
a.Filename = dAttachment.Filename;
|
||||
a.Size = dAttachment.Size;
|
||||
a.Source = new Uri(dAttachment.Url);
|
||||
|
||||
return a;
|
||||
}
|
||||
internal Message UpsertMessage(IUserMessage dMessage)
|
||||
{
|
||||
var m = _db.Messages.FirstOrDefault(mi => mi.ExternalId == dMessage.Id.ToString() && mi.Protocol == PROTOCOL);
|
||||
if (m == null)
|
||||
{
|
||||
m = new Message();
|
||||
m.Protocol = PROTOCOL;
|
||||
_db.Messages.Add(m);
|
||||
}
|
||||
m.Attachments = m.Attachments ?? new List<vassago.Models.Attachment>();
|
||||
if (dMessage.Attachments?.Any() == true)
|
||||
{
|
||||
m.Attachments = new List<vassago.Models.Attachment>();
|
||||
foreach (var da in dMessage.Attachments)
|
||||
{
|
||||
m.Attachments.Add(UpsertAttachment(da));
|
||||
}
|
||||
}
|
||||
m.Content = dMessage.Content;
|
||||
m.ExternalId = dMessage.Id.ToString();
|
||||
m.Timestamp = dMessage.EditedTimestamp ?? dMessage.CreatedAt;
|
||||
m.Channel = UpsertChannel(dMessage.Channel);
|
||||
m.Author = UpsertAccount(dMessage.Author, m.Channel);
|
||||
if(dMessage.Channel is IGuildChannel)
|
||||
{
|
||||
m.Author.DisplayName = (dMessage.Author as IGuildUser).DisplayName;//discord forgot how display names work.
|
||||
}
|
||||
m.MentionsMe = (dMessage.Author.Id != client.CurrentUser.Id
|
||||
&& (dMessage.MentionedUserIds?.FirstOrDefault(muid => muid == client.CurrentUser.Id) > 0));
|
||||
|
||||
m.Reply = (t) => { return dMessage.ReplyAsync(t); };
|
||||
m.React = (e) => { return attemptReact(dMessage, e); };
|
||||
return m;
|
||||
}
|
||||
internal Channel UpsertChannel(IMessageChannel channel)
|
||||
{
|
||||
Channel c = _db.Channels.FirstOrDefault(ci => ci.ExternalId == channel.Id.ToString() && ci.Protocol == PROTOCOL);
|
||||
if (c == null)
|
||||
{
|
||||
c = new Channel();
|
||||
_db.Channels.Add(c);
|
||||
}
|
||||
|
||||
c.DisplayName = channel.Name;
|
||||
c.ExternalId = channel.Id.ToString();
|
||||
c.ChannelType = (channel is IPrivateChannel) ? vassago.Models.Enumerations.ChannelType.DM : vassago.Models.Enumerations.ChannelType.Normal;
|
||||
c.Messages = c.Messages ?? new List<Message>();
|
||||
c.Protocol = PROTOCOL;
|
||||
if (channel is IGuildChannel)
|
||||
{
|
||||
c.ParentChannel = UpsertChannel((channel as IGuildChannel).Guild);
|
||||
c.ParentChannel.SubChannels.Add(c);
|
||||
}
|
||||
else if (channel is IPrivateChannel)
|
||||
{
|
||||
c.ParentChannel = protocolAsChannel;
|
||||
}
|
||||
else
|
||||
{
|
||||
c.ParentChannel = protocolAsChannel;
|
||||
Console.Error.WriteLine($"trying to upsert channel {channel.Id}/{channel.Name}, but it's neither guildchannel nor private channel. shrug.jpg");
|
||||
}
|
||||
c.SubChannels = c.SubChannels ?? new List<Channel>();
|
||||
c.SendMessage = (t) => { return channel.SendMessageAsync(t); };
|
||||
c.SendFile = (f, t) => { return channel.SendFileAsync(f, t); };
|
||||
|
||||
switch(c.ChannelType)
|
||||
{
|
||||
case vassago.Models.Enumerations.ChannelType.DM:
|
||||
c.DisplayName = "DM: " + (channel as IPrivateChannel).Recipients?.FirstOrDefault(u => u.Id != client.CurrentUser.Id).Username;
|
||||
break;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
internal Channel UpsertChannel(IGuild channel)
|
||||
{
|
||||
Channel c = _db.Channels.FirstOrDefault(ci => ci.ExternalId == channel.Id.ToString() && ci.Protocol == PROTOCOL);
|
||||
if (c == null)
|
||||
{
|
||||
c = new Channel();
|
||||
_db.Channels.Add(c);
|
||||
}
|
||||
|
||||
c.DisplayName = channel.Name;
|
||||
c.ExternalId = channel.Id.ToString();
|
||||
c.ChannelType = vassago.Models.Enumerations.ChannelType.Normal;
|
||||
c.Messages = c.Messages ?? new List<Message>();
|
||||
c.Protocol = protocolAsChannel.Protocol;
|
||||
c.ParentChannel = protocolAsChannel;
|
||||
c.SubChannels = c.SubChannels ?? new List<Channel>();
|
||||
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 c;
|
||||
}
|
||||
internal Account UpsertAccount(IUser user, Channel inChannel)
|
||||
{
|
||||
var acc = _db.Accounts.FirstOrDefault(ui => ui.ExternalId == user.Id.ToString() && ui.SeenInChannel.Id == inChannel.Id);
|
||||
if (acc == null)
|
||||
{
|
||||
acc = new Account();
|
||||
_db.Accounts.Add(acc);
|
||||
}
|
||||
acc.Username = user.Username;
|
||||
acc.ExternalId = user.Id.ToString();
|
||||
acc.IsBot = user.IsBot || user.IsWebhook;
|
||||
acc.Protocol = PROTOCOL;
|
||||
acc.SeenInChannel = inChannel;
|
||||
|
||||
acc.IsUser = _db.Users.FirstOrDefault(u => u.Accounts.Any(a => a.ExternalId == acc.ExternalId && a.Protocol == acc.Protocol));
|
||||
if(acc.IsUser == null)
|
||||
{
|
||||
acc.IsUser = new User() { Accounts = new List<Account>() { acc } };
|
||||
_db.Users.Add(acc.IsUser);
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
private Task attemptReact(IUserMessage msg, string e)
|
||||
{
|
||||
var c = _db.Channels.FirstOrDefault(c => c.ExternalId == msg.Channel.Id.ToString());
|
||||
//var preferredEmote = c.EmoteOverrides?[e] ?? e; //TODO: emote overrides
|
||||
var preferredEmote = e;
|
||||
if (Emoji.TryParse(preferredEmote, out Emoji emoji))
|
||||
{
|
||||
return msg.AddReactionAsync(emoji);
|
||||
}
|
||||
if (!Emote.TryParse(preferredEmote, out Emote emote))
|
||||
{
|
||||
if (preferredEmote == e)
|
||||
Console.Error.WriteLine($"never heard of emote {e}");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
return msg.AddReactionAsync(emote);
|
||||
}
|
||||
|
||||
}
|
@ -1,14 +1,14 @@
|
||||
namespace silverworker_discord
|
||||
{
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using Discord.Net;
|
||||
using Discord;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Discord.WebSocket;
|
||||
using Discord;
|
||||
using Discord.Net;
|
||||
|
||||
namespace vassago.DiscordInterface
|
||||
{
|
||||
public static class SlashCommandsHelper
|
||||
{
|
||||
private static List<CommandSetup> slashCommands = new List<CommandSetup>()
|
||||
@ -22,6 +22,7 @@ namespace silverworker_discord
|
||||
};
|
||||
public static async Task Register(DiscordSocketClient client)
|
||||
{
|
||||
return;
|
||||
var commandsInContext = await client.GetGlobalApplicationCommandsAsync();
|
||||
await Register(client, commandsInContext, null);
|
||||
foreach (var guild in client.Guilds)
|
||||
@ -30,7 +31,7 @@ namespace silverworker_discord
|
||||
{
|
||||
await Register(client, await guild.GetApplicationCommandsAsync(), guild);
|
||||
}
|
||||
catch (Discord.Net.HttpException ex)
|
||||
catch (HttpException ex)
|
||||
{
|
||||
Console.Error.WriteLine($"error registering slash commands for guild {guild.Name} (id {guild.Id}) - {ex.Message}");
|
||||
}
|
||||
@ -46,7 +47,6 @@ namespace silverworker_discord
|
||||
{
|
||||
Console.WriteLine($"deleting command {existingCommand.Name} - (created at {existingCommand.CreatedAt}, it's in guild {existingCommand.Guild?.Id} while I'm in {guild?.Id})");
|
||||
await existingCommand.DeleteAsync();
|
||||
Console.WriteLine("survived");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -55,7 +55,6 @@ namespace silverworker_discord
|
||||
{
|
||||
Console.WriteLine($"overwriting command {existingCommand.Name}");
|
||||
await myVersion.register(false, client, guild);
|
||||
Console.WriteLine($"survived");
|
||||
}
|
||||
myVersion.alreadyRegistered = true;
|
||||
}
|
||||
@ -64,7 +63,6 @@ namespace silverworker_discord
|
||||
{
|
||||
Console.WriteLine($"creating new command {remaining.Id} ({(remaining.guild == null ? "global" : $"for guild {remaining.guild}")})");
|
||||
await remaining.register(true, client, guild);
|
||||
Console.WriteLine($"survived");
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,37 +106,11 @@ namespace silverworker_discord
|
||||
Console.Error.WriteLine(json);
|
||||
}
|
||||
}
|
||||
public static async Task SlashCommandHandler(SocketSlashCommand command)
|
||||
{
|
||||
switch(command.CommandName)
|
||||
{
|
||||
case "freedomunits":
|
||||
try
|
||||
{
|
||||
var amt = Convert.ToDecimal((double)(command.Data.Options.First(o => o.Name == "amount").Value));
|
||||
var src = (string)command.Data.Options.First(o => o.Name == "src-unit").Value;
|
||||
var dest = (string)command.Data.Options.First(o => o.Name == "dest-unit").Value;
|
||||
var conversionResult = Conversion.Converter.Convert(amt, src, dest);
|
||||
|
||||
await command.RespondAsync($"> {amt} {src} -> {dest}\n{conversionResult}");
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
await command.RespondAsync($"error: {e.Message}. aaadam!");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
await command.RespondAsync($"\\*smiles and nods*\n");
|
||||
await command.Channel.SendFileAsync($"assets/loud sweating.gif");
|
||||
Console.Error.WriteLine($"can't understand command name: {command.CommandName}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
private class CommandSetup
|
||||
{
|
||||
public string Id { get; set; }
|
||||
//the date/time you updated yours IN UTC.
|
||||
public DateTimeOffset UpdatedAt { get; set; }
|
||||
public DateTimeOffset UpdatedAt { get; set; }
|
||||
public Registration register { get; set; }
|
||||
public ulong? guild { get; set; }
|
||||
public bool alreadyRegistered {get;set; } = false;
|
7
ProtocolInterfaces/ProtocolList.cs
Normal file
7
ProtocolInterfaces/ProtocolList.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace vassago.ProtocolInterfaces;
|
||||
|
||||
public static class ProtocolList
|
||||
{
|
||||
public static List<DiscordInterface.DiscordInterface> discords = new();
|
||||
public static List<TwitchInterface.TwitchInterface> twitchs = new();
|
||||
}
|
9
ProtocolInterfaces/TwitchInterface/TwitchConfig.cs
Normal file
9
ProtocolInterfaces/TwitchInterface/TwitchConfig.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace vassago.TwitchInterface;
|
||||
|
||||
public class TwitchConfig
|
||||
{
|
||||
public string username {get; set;}
|
||||
public string clientId {get; set;}
|
||||
public string secret {get; set;}
|
||||
public string oauth {get; set;}
|
||||
}
|
287
ProtocolInterfaces/TwitchInterface/TwitchInterface.cs
Normal file
287
ProtocolInterfaces/TwitchInterface/TwitchInterface.cs
Normal file
@ -0,0 +1,287 @@
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text.RegularExpressions;
|
||||
using RestSharp;
|
||||
using TwitchLib.Api;
|
||||
using TwitchLib.Api.Helix.Models.Users.GetUsers;
|
||||
using TwitchLib.Client;
|
||||
using TwitchLib.Client.Events;
|
||||
using TwitchLib.Client.Models;
|
||||
using TwitchLib.Communication.Clients;
|
||||
using TwitchLib.Communication.Models;
|
||||
using vassago.Behavior;
|
||||
using vassago.Models;
|
||||
|
||||
namespace vassago.TwitchInterface;
|
||||
|
||||
public class TwitchInterface
|
||||
{
|
||||
internal const string PROTOCOL = "twitch";
|
||||
private bool eventsSignedUp = false;
|
||||
private ChattingContext _db;
|
||||
private static SemaphoreSlim twitchChannelSetup = new SemaphoreSlim(1, 1);
|
||||
private Channel protocolAsChannel;
|
||||
TwitchClient client;
|
||||
TwitchAPI api;
|
||||
|
||||
public TwitchInterface()
|
||||
{
|
||||
_db = new ChattingContext();
|
||||
}
|
||||
private async Task SetupTwitchChannel()
|
||||
{
|
||||
await twitchChannelSetup.WaitAsync();
|
||||
|
||||
try
|
||||
{
|
||||
protocolAsChannel = _db.Channels.FirstOrDefault(c => c.ParentChannel == null && c.Protocol == PROTOCOL);
|
||||
if (protocolAsChannel == null)
|
||||
{
|
||||
protocolAsChannel = new Channel()
|
||||
{
|
||||
DisplayName = "twitch (itself)",
|
||||
MeannessFilterLevel = Enumerations.MeannessFilterLevel.Medium,
|
||||
LewdnessFilterLevel = Enumerations.LewdnessFilterLevel.G,
|
||||
MaxTextChars = 500,
|
||||
MaxAttachmentBytes = 0,
|
||||
LinksAllowed = false,
|
||||
ReactionsPossible = false,
|
||||
ExternalId = null,
|
||||
Protocol = PROTOCOL,
|
||||
SubChannels = new List<Channel>()
|
||||
};
|
||||
protocolAsChannel.SendMessage = (t) => { throw new InvalidOperationException($"twitch itself cannot accept text"); };
|
||||
protocolAsChannel.SendFile = (f, t) => { throw new InvalidOperationException($"twitch itself cannot send file"); };
|
||||
_db.Channels.Add(protocolAsChannel);
|
||||
_db.SaveChanges();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
twitchChannelSetup.Release();
|
||||
}
|
||||
}
|
||||
|
||||
///<param name="oauth">https://www.twitchapps.com/tmi/</param>
|
||||
public async Task Init(TwitchConfig tc)
|
||||
{
|
||||
await SetupTwitchChannel();
|
||||
|
||||
WebSocketClient customClient = new WebSocketClient(new ClientOptions
|
||||
{
|
||||
MessagesAllowedInPeriod = 750,
|
||||
ThrottlingPeriod = TimeSpan.FromSeconds(30)
|
||||
}
|
||||
);
|
||||
client = new TwitchClient(customClient);
|
||||
client.Initialize(new ConnectionCredentials(tc.username, tc.oauth, capabilities: new Capabilities()));
|
||||
|
||||
client.OnLog += Client_OnLog;
|
||||
client.OnJoinedChannel += Client_OnJoinedChannel;
|
||||
client.OnMessageReceived += Client_OnMessageReceivedAsync;
|
||||
client.OnWhisperReceived += Client_OnWhisperReceivedAsync;
|
||||
client.OnConnected += Client_OnConnected;
|
||||
|
||||
Console.WriteLine("twitch client 1 connecting...");
|
||||
client.Connect();
|
||||
Console.WriteLine("twitch client 1 connected");
|
||||
|
||||
// Console.WriteLine("twitch API client connecting...");
|
||||
// api = new TwitchAPI();
|
||||
// Console.WriteLine("can I just use the same creds as the other client?");
|
||||
// api.Settings.ClientId = tc.username;
|
||||
// api.Settings.AccessToken = tc.oauth;
|
||||
// try{
|
||||
// var neckbreads = await api.Helix.Moderation.GetModeratorsAsync("silvermeddlists");
|
||||
// Console.WriteLine($"{neckbreads?.Data?.Count()} shabby beards that need to be given up on");
|
||||
// }
|
||||
// catch(Exception e){
|
||||
// Console.Error.WriteLine(e);
|
||||
// }
|
||||
// Console.WriteLine("k.");
|
||||
}
|
||||
|
||||
private async void Client_OnWhisperReceivedAsync(object sender, OnWhisperReceivedArgs e)
|
||||
{
|
||||
Console.WriteLine($"whisper#{e.WhisperMessage.Username}[{DateTime.Now}][{e.WhisperMessage.DisplayName} [id={e.WhisperMessage.Username}]][msg id: {e.WhisperMessage.MessageId}] {e.WhisperMessage.Message}");
|
||||
var old = _db.Messages.FirstOrDefault(m => m.ExternalId == e.WhisperMessage.MessageId && m.Protocol == PROTOCOL);
|
||||
if (old != null)
|
||||
{
|
||||
Console.WriteLine($"[whisperreceived]: {e.WhisperMessage.MessageId}? already seent it. Internal id: {old.Id}");
|
||||
return;
|
||||
}
|
||||
var m = UpsertMessage(e.WhisperMessage);
|
||||
m.Channel.ChannelType = vassago.Models.Enumerations.ChannelType.DM;
|
||||
m.MentionsMe = Regex.IsMatch(e.WhisperMessage.Message?.ToLower(), $"\\b@{e.WhisperMessage.BotUsername.ToLower()}\\b");
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
await Behaver.Instance.ActOn(m);
|
||||
await _db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async void Client_OnMessageReceivedAsync(object sender, OnMessageReceivedArgs e)
|
||||
{
|
||||
Console.WriteLine($"#{e.ChatMessage.Channel}[{DateTime.Now}][{e.ChatMessage.DisplayName} [id={e.ChatMessage.Username}]][msg id: {e.ChatMessage.Id}] {e.ChatMessage.Message}");
|
||||
var old = _db.Messages.FirstOrDefault(m => m.ExternalId == e.ChatMessage.Id && m.Protocol == PROTOCOL);
|
||||
if (old != null)
|
||||
{
|
||||
Console.WriteLine($"[messagereceived]: {e.ChatMessage.Id}? already seent it");
|
||||
return;
|
||||
}
|
||||
Console.WriteLine($"[messagereceived]: {e.ChatMessage.Id}? new to me.");
|
||||
var m = UpsertMessage(e.ChatMessage);
|
||||
m.MentionsMe = Regex.IsMatch(e.ChatMessage.Message?.ToLower(), $"@{e.ChatMessage.BotUsername.ToLower()}\\b") ||
|
||||
e.ChatMessage.ChatReply?.ParentUserLogin == e.ChatMessage.BotUsername;
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
await Behaver.Instance.ActOn(m);
|
||||
await _db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async void Client_OnConnected(object sender, OnConnectedArgs e)
|
||||
{
|
||||
var selfAccount = UpsertAccount(e.BotUsername, protocolAsChannel.Id);
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
Behaver.Instance.MarkSelf(selfAccount);
|
||||
|
||||
Console.WriteLine($"Connected to {e.AutoJoinChannel}");
|
||||
}
|
||||
|
||||
private void Client_OnJoinedChannel(object sender, OnJoinedChannelArgs e)
|
||||
{
|
||||
client.SendMessage(e.Channel, "beep boop");
|
||||
}
|
||||
|
||||
private void Client_OnLog(object sender, OnLogArgs e)
|
||||
{
|
||||
Console.WriteLine($"{e.DateTime.ToString()}: {e.BotUsername} - {e.Data}");
|
||||
}
|
||||
|
||||
private Account UpsertAccount(string username, Guid inChannel)
|
||||
{
|
||||
var acc = _db.Accounts.FirstOrDefault(ui => ui.ExternalId == username && ui.SeenInChannel.Id == inChannel);
|
||||
if (acc == null)
|
||||
{
|
||||
acc = new Account();
|
||||
_db.Accounts.Add(acc);
|
||||
}
|
||||
acc.Username = username;
|
||||
acc.ExternalId = username;
|
||||
//acc.IsBot =
|
||||
acc.Protocol = PROTOCOL;
|
||||
|
||||
acc.IsUser = _db.Users.FirstOrDefault(u => u.Accounts.Any(a => a.ExternalId == acc.ExternalId && a.Protocol == acc.Protocol));
|
||||
if (acc.IsUser == null)
|
||||
{
|
||||
acc.IsUser = new vassago.Models.User() { Accounts = new List<Account>() { acc } };
|
||||
_db.Users.Add(acc.IsUser);
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
private Channel UpsertChannel(string channelName)
|
||||
{
|
||||
Channel c = _db.Channels.FirstOrDefault(ci => ci.ExternalId == channelName && ci.Protocol == PROTOCOL);
|
||||
if (c == null)
|
||||
{
|
||||
c = new Channel();
|
||||
_db.Channels.Add(c);
|
||||
}
|
||||
c.DisplayName = channelName;
|
||||
c.ExternalId = channelName;
|
||||
c.ChannelType = vassago.Models.Enumerations.ChannelType.Normal;
|
||||
c.Messages = c.Messages ?? new List<Message>();
|
||||
c.Protocol = PROTOCOL;
|
||||
c.ParentChannel = protocolAsChannel;
|
||||
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"); };
|
||||
return c;
|
||||
}
|
||||
private Channel UpsertDMChannel(string whisperWith)
|
||||
{
|
||||
Channel c = _db.Channels.FirstOrDefault(ci => ci.ExternalId == $"w_{whisperWith}" && ci.Protocol == PROTOCOL);
|
||||
if (c == null)
|
||||
{
|
||||
c = new Channel();
|
||||
_db.Channels.Add(c);
|
||||
}
|
||||
c.DisplayName = $"Whisper: {whisperWith}";
|
||||
c.ExternalId = $"w_{whisperWith}";
|
||||
c.ChannelType = vassago.Models.Enumerations.ChannelType.DM;
|
||||
c.Messages = c.Messages ?? new List<Message>();
|
||||
c.Protocol = PROTOCOL;
|
||||
c.ParentChannel = protocolAsChannel;
|
||||
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"); };
|
||||
return c;
|
||||
}
|
||||
|
||||
private Message UpsertMessage(ChatMessage chatMessage)
|
||||
{
|
||||
var m = _db.Messages.FirstOrDefault(mi => mi.ExternalId == chatMessage.Id);
|
||||
if (m == null)
|
||||
{
|
||||
m = new Message();
|
||||
m.Protocol = PROTOCOL;
|
||||
_db.Messages.Add(m);
|
||||
m.Timestamp = (DateTimeOffset)DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc);
|
||||
}
|
||||
|
||||
m.Content = chatMessage.Message;
|
||||
m.ExternalId = chatMessage.Id;
|
||||
m.Channel = UpsertChannel(chatMessage.Channel);
|
||||
m.Author = UpsertAccount(chatMessage.Username, m.Channel.Id);
|
||||
m.Author.SeenInChannel = m.Channel;
|
||||
|
||||
m.Reply = (t) => { return Task.Run(() => { client.SendReply(chatMessage.Channel, chatMessage.Id, t); }); };
|
||||
m.React = (e) => { throw new InvalidOperationException($"twitch cannot react"); };
|
||||
return m;
|
||||
}
|
||||
private Message UpsertMessage(WhisperMessage whisperMessage)
|
||||
{
|
||||
var m = _db.Messages.FirstOrDefault(mi => mi.ExternalId == whisperMessage.MessageId);
|
||||
if (m == null)
|
||||
{
|
||||
m = new Message();
|
||||
m.Protocol = PROTOCOL;
|
||||
_db.Messages.Add(m);
|
||||
m.Timestamp = (DateTimeOffset)DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc);
|
||||
}
|
||||
|
||||
m.Content = whisperMessage.Message;
|
||||
m.ExternalId = whisperMessage.MessageId;
|
||||
m.Channel = UpsertDMChannel(whisperMessage.Username);
|
||||
m.Channel.ChannelType = vassago.Models.Enumerations.ChannelType.DM;
|
||||
m.Author = UpsertAccount(whisperMessage.Username, m.Channel.Id);
|
||||
m.Author.SeenInChannel = m.Channel;
|
||||
|
||||
m.Reply = (t) => { return Task.Run(() => { client.SendWhisper(whisperMessage.Username, t); }); };
|
||||
m.React = (e) => { throw new InvalidOperationException($"twitch cannot react"); };
|
||||
return m;
|
||||
}
|
||||
|
||||
public string AttemptJoin(string channelTarget)
|
||||
{
|
||||
client.JoinChannel(channelTarget);
|
||||
return $"attempt join {channelTarget} - o7";
|
||||
}
|
||||
|
||||
internal void AttemptLeave(string channelTarget)
|
||||
{
|
||||
client.SendMessage(channelTarget, "o7");
|
||||
client.LeaveChannel(channelTarget);
|
||||
}
|
||||
}
|
38
README.md
38
README.md
@ -1,8 +1,42 @@
|
||||
# discord-bot
|
||||
|
||||
copy appsettings.json and fill it in
|
||||
copy appsettings.json to appsettings.ENV.json and fill it in. dotnet seems to understand files called appsettings.json (and appsettings.xml?) and knows how to overwrite *specific values found within* the .[ENV].[extension] version
|
||||
|
||||
# auth link
|
||||
|
||||
https://discord.com/oauth2/authorize?client_id=913003037348491264&permissions=274877942784&scope=bot
|
||||
that's read messages/view channels, send messages, send messages in threads, and attach files. but not add reactions?
|
||||
that's read messages/view channels, send messages, send messages in threads, and attach files. but not add reactions?
|
||||
|
||||
# concepts
|
||||
|
||||
## Data Types
|
||||
|
||||
### Accounts
|
||||
|
||||
a `User` can have multiple `Account`s. e.g., @adam:greyn.club? that's an "account". I, however, am a `User`. An `Account` has references to the `Channels` its seen in.
|
||||
|
||||
### Attachment
|
||||
|
||||
debating whether to save a copy of every single attachment. Discord allows 25MB attachments, and shtikbot lives in several art channels.
|
||||
|
||||
### Channel
|
||||
|
||||
a place where communication can happen. any level of these can have any number of children. In matrix, everything is a "room" - even spaces and threads. Seems like a fine idea. So for vassago, a discord "channel" is a channel. a "thread" is a child of that channel. a "category" is a parent of that channel. A "server" (formerly "guild") is a parent of that channel. and fuck it, Discord itself is a "channel". Includes permissions vassago has for a channel; MaxAttachmentBytes, etc. go down the hierarchy until you find an override.
|
||||
|
||||
### FeaturePermission
|
||||
|
||||
the permissions of a feature. It can be restricted to accounts, to users, to channels. It has an internal name... and tag? and it can be (or not be) inheritable?
|
||||
|
||||
### Message
|
||||
|
||||
a message (duh). features bools for "mentions me", the external ID, the reference to the account, the channel.
|
||||
|
||||
### User
|
||||
|
||||
a person or program who operates an account. recognizing that 2 `Account`s belong to 1 `User` can be done by that user (using LinkMe). I should be able to collapse myself automatically.
|
||||
|
||||
## Behavior
|
||||
|
||||
both a "feature" and an "anti-feature". a channel might dictate something isn't allowed (lewdness in a g-rated channel). A person might not be allowed to do something - lots of me-only things like directing other bots (and the now rendered-moot Torrent feature). A behavior might need a command alias in a particular channel (freedomunits in jubel's)
|
||||
|
||||
so "behavior" might need to tag other data types? do I have it do a full select every time we get a message? ...no, only if the (other) triggering conditions are met. Then you can take your time.
|
15
Shared.cs
15
Shared.cs
@ -1,10 +1,13 @@
|
||||
namespace vassago;
|
||||
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using vassago.Models;
|
||||
|
||||
namespace silverworker_discord
|
||||
|
||||
public static class Shared
|
||||
{
|
||||
public static class Shared
|
||||
{
|
||||
public static Random r = new Random();
|
||||
}
|
||||
}
|
||||
public static Random r = new Random();
|
||||
public static string DBConnectionString { get; set; }
|
||||
public static HttpClient HttpClient { get; internal set; } = new HttpClient();
|
||||
}
|
||||
|
58
WebInterface/Controllers/ChannelsController.cs
Normal file
58
WebInterface/Controllers/ChannelsController.cs
Normal file
@ -0,0 +1,58 @@
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using vassago.Models;
|
||||
|
||||
namespace vassago.Controllers;
|
||||
|
||||
public class ChannelsController : Controller
|
||||
{
|
||||
private readonly ILogger<ChannelsController> _logger;
|
||||
private readonly ChattingContext _db;
|
||||
|
||||
public ChannelsController(ILogger<ChannelsController> logger, ChattingContext db)
|
||||
{
|
||||
_logger = logger;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Index(string searchString)
|
||||
{
|
||||
return _db.Channels != null ?
|
||||
View(_db.Channels.Include(u => u.ParentChannel).ToList().OrderBy(c => c.LineageSummary)) :
|
||||
Problem("Entity set '_db.Channels' is null.");
|
||||
}
|
||||
public async Task<IActionResult> Details(Guid id)
|
||||
{
|
||||
if(_db.Channels == null)
|
||||
return Problem("Entity set '_db.Channels' is null.");
|
||||
//"but adam", says the strawman, "why load *every* channel and walk your way up? surely there's a .Load command that works or something."
|
||||
//eh. I checked. Not really. You could make an SQL view that recurses its way up, meh idk how. You could just eagerly load *every* related object...
|
||||
//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.
|
||||
var AllChannels = await _db.Channels
|
||||
.Include(u => u.SubChannels)
|
||||
.Include(u => u.Users)
|
||||
.Include(u => u.ParentChannel)
|
||||
.ToListAsync();
|
||||
var channel = AllChannels.First(u => u.Id == id);
|
||||
var walker = channel;
|
||||
while(walker != null)
|
||||
{
|
||||
ViewData["breadcrumbs"] = $"<a href=\"{Url.ActionLink(action: "Details", controller: "Channels", values: new {id = walker.Id})}\">{walker.DisplayName}</a>/" +
|
||||
ViewData["breadcrumbs"];
|
||||
walker = walker.ParentChannel;
|
||||
}
|
||||
return View(
|
||||
new Tuple<Channel, Enumerations.LewdnessFilterLevel, Enumerations.MeannessFilterLevel>(
|
||||
channel, channel.EffectivePermissions.LewdnessFilterLevel, channel.EffectivePermissions.MeannessFilterLevel
|
||||
));
|
||||
}
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Error()
|
||||
{
|
||||
return View(new ErrorPageViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||
}
|
||||
}
|
8
WebInterface/Controllers/ErrorPageViewModel.cs
Normal file
8
WebInterface/Controllers/ErrorPageViewModel.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace vassago.Models;
|
||||
|
||||
public class ErrorPageViewModel
|
||||
{
|
||||
public string? RequestId { get; set; }
|
||||
|
||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
}
|
193
WebInterface/Controllers/HomeController.cs
Normal file
193
WebInterface/Controllers/HomeController.cs
Normal file
@ -0,0 +1,193 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.FileSystemGlobbing.Internal.PathSegments;
|
||||
using vassago.Models;
|
||||
|
||||
namespace vassago.Controllers;
|
||||
|
||||
public class HomeController : Controller
|
||||
{
|
||||
private readonly ILogger<HomeController> _logger;
|
||||
private readonly ChattingContext _db;
|
||||
|
||||
public HomeController(ILogger<HomeController> logger, ChattingContext db)
|
||||
{
|
||||
_logger = logger;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
var allAccounts = _db.Accounts.ToList();
|
||||
var allChannels = _db.Channels.Include(c => c.Users).ToList();
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("[");
|
||||
sb.Append("{text: \"channels\", nodes: [");
|
||||
|
||||
var first = true;
|
||||
var topLevelChannels = _db.Channels.Where(x => x.ParentChannel == null);
|
||||
foreach (var topLevelChannel in topLevelChannels)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(',');
|
||||
}
|
||||
|
||||
serializeChannel(ref sb, ref allChannels, ref allAccounts, topLevelChannel);
|
||||
}
|
||||
sb.Append("]}");
|
||||
|
||||
if (allChannels.Any())
|
||||
{
|
||||
sb.Append(",{text: \"orphaned channels\", nodes: [");
|
||||
first = true;
|
||||
while (true)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(',');
|
||||
}
|
||||
serializeChannel(ref sb, ref allChannels, ref allAccounts, allChannels.First());
|
||||
if (!allChannels.Any())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
sb.Append("]}");
|
||||
}
|
||||
if (allAccounts.Any())
|
||||
{
|
||||
sb.Append(",{text: \"channelless accounts\", nodes: [");
|
||||
first = true;
|
||||
foreach (var acc in allAccounts)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(',');
|
||||
}
|
||||
serializeAccount(ref sb, acc);
|
||||
}
|
||||
sb.Append("]}");
|
||||
}
|
||||
var users = _db.Users.ToList();
|
||||
if(users.Any())
|
||||
{
|
||||
sb.Append(",{text: \"users\", nodes: [");
|
||||
first=true;
|
||||
//refresh list; we'll be knocking them out again in serializeUser
|
||||
allAccounts = _db.Accounts.ToList();
|
||||
foreach(var user in users)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(',');
|
||||
}
|
||||
serializeUser(ref sb, ref allAccounts, user);
|
||||
}
|
||||
sb.Append("]}");
|
||||
}
|
||||
sb.Append("]");
|
||||
ViewData.Add("treeString", sb.ToString());
|
||||
return View("Index");
|
||||
}
|
||||
private void serializeChannel(ref StringBuilder sb, ref List<Channel> allChannels, ref List<Account> allAccounts, Channel currentChannel)
|
||||
{
|
||||
allChannels.Remove(currentChannel);
|
||||
//"but adam", you say, "there's an href attribute, why make a link?" because that makes the entire bar a link, and trying to expand the node will probably click the link
|
||||
sb.Append($"{{\"text\": \"<a href=\\\"{Url.ActionLink(action: "Details", controller: "Channels", values: new {id = currentChannel.Id})}\\\">{currentChannel.DisplayName}</a>\"");
|
||||
var theseAccounts = allAccounts.Where(a => a.SeenInChannel?.Id == currentChannel.Id).ToList();
|
||||
allAccounts.RemoveAll(a => a.SeenInChannel?.Id == currentChannel.Id);
|
||||
var first = true;
|
||||
if (currentChannel.SubChannels != null || theseAccounts != null)
|
||||
{
|
||||
sb.Append(", \"nodes\": [");
|
||||
}
|
||||
if (currentChannel.SubChannels != null)
|
||||
{
|
||||
foreach (var subChannel in currentChannel.SubChannels ?? new List<Channel>())
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(',');
|
||||
}
|
||||
serializeChannel(ref sb, ref allChannels, ref allAccounts, subChannel);
|
||||
}
|
||||
if (theseAccounts != null)
|
||||
{
|
||||
sb.Append(',');
|
||||
}
|
||||
}
|
||||
if (theseAccounts != null)
|
||||
{
|
||||
first = true;
|
||||
sb.Append($"{{\"text\": \"(accounts: {theseAccounts.Count()})\", \"expanded\":true, nodes:[");
|
||||
foreach (var account in theseAccounts)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(',');
|
||||
}
|
||||
serializeAccount(ref sb, account);
|
||||
}
|
||||
sb.Append("]}");
|
||||
}
|
||||
sb.Append("]}");
|
||||
}
|
||||
private void serializeAccount(ref StringBuilder sb, Account currentAccount)
|
||||
{
|
||||
sb.Append($"{{\"text\": \"{currentAccount.DisplayName}\"}}");
|
||||
}
|
||||
private void serializeUser(ref StringBuilder sb, ref List<Account> allAccounts, User currentUser)
|
||||
{
|
||||
sb.Append($"{{\"text\": " +
|
||||
$"\"<a href=\\\"{Url.ActionLink(action: "Details", controller: "Users", values: new {id = currentUser.Id})}\\\">"
|
||||
+ currentUser.DisplayName +
|
||||
"</a>\", ");
|
||||
// \"{currentUser.DisplayName}\", ");
|
||||
var ownedAccounts = allAccounts.Where(a => a.IsUser == currentUser);
|
||||
sb.Append("nodes: [");
|
||||
sb.Append($"{{\"text\": \"owned accounts:\", \"expanded\":true, \"nodes\": [");
|
||||
if (ownedAccounts != null)
|
||||
{
|
||||
foreach (var acc in ownedAccounts)
|
||||
{
|
||||
serializeAccount(ref sb, acc);
|
||||
sb.Append(',');
|
||||
}
|
||||
}
|
||||
sb.Append("]}]}");
|
||||
}
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Error()
|
||||
{
|
||||
return View(new ErrorPageViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||
}
|
||||
}
|
37
WebInterface/Controllers/UsersController.cs
Normal file
37
WebInterface/Controllers/UsersController.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System.Diagnostics;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using vassago.Models;
|
||||
|
||||
namespace vassago.Controllers;
|
||||
|
||||
public class UsersController : Controller
|
||||
{
|
||||
private readonly ILogger<UsersController> _logger;
|
||||
private readonly ChattingContext _db;
|
||||
|
||||
public UsersController(ILogger<UsersController> logger, ChattingContext db)
|
||||
{
|
||||
_logger = logger;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Index(string searchString)
|
||||
{
|
||||
return _db.Users != null ?
|
||||
View(await _db.Users.Include(u => u.Accounts).ToListAsync()) :
|
||||
Problem("Entity set '_db.Users' is null.");
|
||||
}
|
||||
public async Task<IActionResult> Details(Guid id)
|
||||
{
|
||||
return _db.Users != null ?
|
||||
View(await _db.Users.Include(u => u.Accounts).FirstAsync(u => u.Id == id)) :
|
||||
Problem("Entity set '_db.Users' is null.");
|
||||
}
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Error()
|
||||
{
|
||||
return View(new ErrorPageViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||
}
|
||||
}
|
44
WebInterface/Controllers/api/ChannelsControler.cs
Normal file
44
WebInterface/Controllers/api/ChannelsControler.cs
Normal file
@ -0,0 +1,44 @@
|
||||
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;
|
||||
private readonly ChattingContext _db;
|
||||
|
||||
public ChannelsController(ILogger<ChannelsController> logger, ChattingContext db)
|
||||
{
|
||||
_logger = logger;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
[Produces("application/json")]
|
||||
public Channel Get(Guid id)
|
||||
{
|
||||
return _db.Find<Channel>(id);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[Produces("application/json")]
|
||||
public IActionResult Patch([FromBody] Channel channel)
|
||||
{
|
||||
var fromDb = _db.Channels.Find(channel.Id);
|
||||
if (fromDb == null)
|
||||
{
|
||||
_logger.LogError($"attempt to update channel {channel.Id}, not found");
|
||||
return NotFound();
|
||||
}
|
||||
//settable values: lewdness filter level, meanness filter level. maybe i could decorate them...
|
||||
fromDb.LewdnessFilterLevel = channel.LewdnessFilterLevel;
|
||||
fromDb.MeannessFilterLevel = channel.MeannessFilterLevel;
|
||||
_db.SaveChanges();
|
||||
return Ok(fromDb);
|
||||
}
|
||||
}
|
113
WebInterface/Views/Channels/Details.cshtml
Normal file
113
WebInterface/Views/Channels/Details.cshtml
Normal file
@ -0,0 +1,113 @@
|
||||
@using System.ComponentModel
|
||||
@using Newtonsoft.Json
|
||||
@model Tuple<Channel, Enumerations.LewdnessFilterLevel, Enumerations.MeannessFilterLevel>
|
||||
@{
|
||||
var ThisChannel = Model.Item1;
|
||||
var IfInheritedLewdnessFilterLevel = Model.Item2;
|
||||
var IfInheritedMeannessFilterLevel = Model.Item3;
|
||||
}
|
||||
|
||||
|
||||
@Html.Raw(ViewData["breadcrumbs"])
|
||||
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Display Name</th>
|
||||
<td>@ThisChannel.DisplayName</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Channel type</th>
|
||||
<td>@(ThisChannel.ChannelType != null ? Enumerations.GetDescription(ThisChannel.ChannelType) : "?")</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Lewdness Filter Level</th>
|
||||
<td>
|
||||
<select name="LewdnessFilterLevel" id="LewdnessFilterLevel" onchange="patchModel(jsonifyChannel())">
|
||||
<!option value="" @(ThisChannel.LewdnessFilterLevel == null ? "selected" : "")>⤵ inherited - @Enumerations.GetDescription(IfInheritedLewdnessFilterLevel)</!option>
|
||||
@foreach (Enumerations.LewdnessFilterLevel enumVal in
|
||||
Enum.GetValues(typeof(Enumerations.LewdnessFilterLevel)))
|
||||
{
|
||||
<!option value="@((int)enumVal)" @(ThisChannel.LewdnessFilterLevel == enumVal ? "selected" : "")>
|
||||
@(Enumerations.GetDescription<Enumerations.LewdnessFilterLevel>(enumVal))</!option>
|
||||
}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Links Allowed</th>
|
||||
<td>@(ThisChannel.LinksAllowed?.ToString() ?? "unknown")</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Lineage summary</th>
|
||||
<td>@ThisChannel.LineageSummary</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">max attachment bytes</th>
|
||||
<td>@ThisChannel.MaxAttachmentBytes (i hear there's "ByteSize")</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">max message length</th>
|
||||
<td>@(ThisChannel.MaxTextChars?.ToString() ?? "inherited")</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Meanness Filter Level</th>
|
||||
<td>
|
||||
<select name="MeannessFilterLevel" id="MeannessFilterLevel" onchange="patchModel(jsonifyChannel())">
|
||||
<!option value="" @(ThisChannel.MeannessFilterLevel == null ? "selected" : "")>⤵ inherited - @Enumerations.GetDescription(IfInheritedMeannessFilterLevel)</!option>
|
||||
@foreach (Enumerations.MeannessFilterLevel enumVal in
|
||||
Enum.GetValues(typeof(Enumerations.MeannessFilterLevel)))
|
||||
{
|
||||
<!option value="@((int)enumVal)" @(ThisChannel.MeannessFilterLevel == enumVal ? "selected" : "")>
|
||||
@(Enumerations.GetDescription<Enumerations.MeannessFilterLevel>(enumVal))</!option>
|
||||
}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Messages (count)</th>
|
||||
<td>@(ThisChannel.Messages?.Count ?? 0)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Protocol</th>
|
||||
<td>@ThisChannel.Protocol</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Reactions Possible</th>
|
||||
<td>@(ThisChannel.ReactionsPossible?.ToString() ?? "inherited")</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Sub Channels</th>
|
||||
<td>@(ThisChannel.SubChannels?.Count ?? 0)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Users</th>
|
||||
<td>@(ThisChannel.Users?.Count ?? 0)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
@section Scripts{
|
||||
<script type="text/javascript">
|
||||
@{
|
||||
var modelAsString = JsonConvert.SerializeObject(ThisChannel, new JsonSerializerSettings
|
||||
{
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
||||
});
|
||||
}
|
||||
const channelOnLoad = @Html.Raw(modelAsString);
|
||||
function jsonifyChannel() {
|
||||
var channelNow = structuredClone(channelOnLoad);
|
||||
channelNow.SubChannels = null;
|
||||
channelNow.ParentChannel = null;
|
||||
channelNow.Messages = null;
|
||||
channelNow.Users = null;
|
||||
|
||||
channelNow.LewdnessFilterLevel = document.querySelector("#LewdnessFilterLevel").value;
|
||||
channelNow.MeannessFilterLevel = document.querySelector("#MeannessFilterLevel").value;
|
||||
console.log(channelNow);
|
||||
return channelNow;
|
||||
}
|
||||
</script>
|
||||
}
|
42
WebInterface/Views/Channels/Index.cshtml
Normal file
42
WebInterface/Views/Channels/Index.cshtml
Normal file
@ -0,0 +1,42 @@
|
||||
@model IEnumerable<Channel>
|
||||
@{
|
||||
ViewData["Title"] = "Channels";
|
||||
}
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
protocol
|
||||
</th>
|
||||
<th>type</th>
|
||||
<th>
|
||||
display name
|
||||
</th>
|
||||
<th>
|
||||
Lineage
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in Model) {
|
||||
<tr>
|
||||
<td class="@item.Protocol">
|
||||
<div class="protocol-icon"> </div>
|
||||
</td>
|
||||
<td class="@item.ChannelType">
|
||||
<div class="channel-type-icon"> </div>
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.DisplayName)
|
||||
</td>
|
||||
<td>
|
||||
@item.LineageSummary
|
||||
</td>
|
||||
<td>
|
||||
<a asp-action="Details" asp-route-id="@item.Id">Details</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
17
WebInterface/Views/Home/Index.cshtml
Normal file
17
WebInterface/Views/Home/Index.cshtml
Normal file
@ -0,0 +1,17 @@
|
||||
@{
|
||||
ViewData["Title"] = "Home Page";
|
||||
}
|
||||
<div id="tree"></div>
|
||||
tree above.
|
||||
|
||||
@section Scripts{
|
||||
<script type="text/javascript">
|
||||
function getTree() {
|
||||
var tree = @Html.Raw(ViewData["treeString"]);
|
||||
console.log(tree);
|
||||
return tree;
|
||||
}
|
||||
|
||||
$('#tree').bstreeview({ data: getTree() });
|
||||
</script>
|
||||
}
|
25
WebInterface/Views/Shared/Error.cshtml
Normal file
25
WebInterface/Views/Shared/Error.cshtml
Normal file
@ -0,0 +1,25 @@
|
||||
@model ErrorPageViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Error";
|
||||
}
|
||||
|
||||
<h1 class="text-danger">Error.</h1>
|
||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||
|
||||
@if (Model.ShowRequestId)
|
||||
{
|
||||
<p>
|
||||
<strong>Request ID:</strong> <code>@Model.RequestId</code>
|
||||
</p>
|
||||
}
|
||||
|
||||
<h3>Development Mode</h3>
|
||||
<p>
|
||||
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
||||
</p>
|
||||
<p>
|
||||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
||||
It can result in displaying sensitive information from exceptions to end users.
|
||||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
||||
and restarting the app.
|
||||
</p>
|
25
WebInterface/Views/Shared/_Layout.cshtml
Normal file
25
WebInterface/Views/Shared/_Layout.cshtml
Normal file
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - vassago</title>
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="~/css/fontawesome.min.css" />
|
||||
<link rel="stylesheet" href="~/css/bs.min.treeview.css" />
|
||||
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/vassago.styles.css" asp-append-version="true" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<main role="main" class="pb-3">
|
||||
@RenderBody()
|
||||
</main>
|
||||
</div>
|
||||
<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="~/js/bstreeview.min.js"></script>
|
||||
<script src="~/js/site.js" asp-append-version="true"></script>
|
||||
@await RenderSectionAsync("Scripts", required: false)
|
||||
</body>
|
||||
</html>
|
48
WebInterface/Views/Shared/_Layout.cshtml.css
Normal file
48
WebInterface/Views/Shared/_Layout.cshtml.css
Normal file
@ -0,0 +1,48 @@
|
||||
/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
|
||||
for details on configuring this project to bundle and minify static web assets. */
|
||||
|
||||
a.navbar-brand {
|
||||
white-space: normal;
|
||||
text-align: center;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0077cc;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
.border-top {
|
||||
border-top: 1px solid #e5e5e5;
|
||||
}
|
||||
.border-bottom {
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.box-shadow {
|
||||
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
|
||||
}
|
||||
|
||||
button.accept-policy {
|
||||
font-size: 1rem;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
line-height: 60px;
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
|
||||
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
|
21
WebInterface/Views/Users/Details.cshtml
Normal file
21
WebInterface/Views/Users/Details.cshtml
Normal file
@ -0,0 +1,21 @@
|
||||
@model User
|
||||
@{
|
||||
ViewData["Title"] = "User details";
|
||||
}
|
||||
|
||||
User @Model.DisplayName<br />
|
||||
|
||||
<div class="permissions">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="accounts">
|
||||
@foreach (var acc in Model.Accounts)
|
||||
{
|
||||
<div class="account @acc.Protocol">
|
||||
<div class="protocol-icon"> </div>
|
||||
@Html.DisplayFor(acc => acc.DisplayName)
|
||||
<a asp-controller="Accounts" asp-action="Details" asp-route-id="@acc.Id">Details</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
38
WebInterface/Views/Users/Index.cshtml
Normal file
38
WebInterface/Views/Users/Index.cshtml
Normal file
@ -0,0 +1,38 @@
|
||||
@model IEnumerable<User>
|
||||
@{
|
||||
ViewData["Title"] = "Users";
|
||||
}
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
@Html.DisplayNameFor(model => model.Id)
|
||||
</th>
|
||||
<th>
|
||||
name*
|
||||
</th>
|
||||
<th>
|
||||
number of associated accounts
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in Model) {
|
||||
<tr>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Id)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.DisplayName)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Accounts.Count)x
|
||||
</td>
|
||||
<td>
|
||||
<a asp-action="Details" asp-route-id="@item.Id">Details</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
3
WebInterface/Views/_ViewImports.cshtml
Normal file
3
WebInterface/Views/_ViewImports.cshtml
Normal file
@ -0,0 +1,3 @@
|
||||
@using vassago
|
||||
@using vassago.Models
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
3
WebInterface/Views/_ViewStart.cshtml
Normal file
3
WebInterface/Views/_ViewStart.cshtml
Normal file
@ -0,0 +1,3 @@
|
||||
@{
|
||||
Layout = "_Layout";
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"token": "59 chars",
|
||||
"exchangePairsLocation": "assets/exchangepairs.json"
|
||||
}
|
16
appsettings.json
Normal file
16
appsettings.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"DiscordTokens": [
|
||||
|
||||
],
|
||||
"TwitchConfigs": [
|
||||
],
|
||||
"exchangePairsLocation": "assets/exchangepairs.json",
|
||||
"DBConnectionString": "Host=azure.club;Database=db;Username=user;Password=password"
|
||||
}
|
@ -36,6 +36,13 @@
|
||||
"metre"
|
||||
]
|
||||
},
|
||||
{
|
||||
"canonical":"mm",
|
||||
"aliases": [
|
||||
"millimeter",
|
||||
"millimetre"
|
||||
]
|
||||
},
|
||||
{
|
||||
"canonical":"km",
|
||||
"aliases": [
|
||||
@ -204,6 +211,34 @@
|
||||
"aliases": [
|
||||
"parsec"
|
||||
]
|
||||
},
|
||||
{
|
||||
"canonical":"mi",
|
||||
"aliases": [
|
||||
"mile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"canonical":"blue whale lengths",
|
||||
"aliases": [
|
||||
"bwl",
|
||||
"whales"
|
||||
]
|
||||
},
|
||||
{
|
||||
"canonical":"ångströms",
|
||||
"aliases": [
|
||||
"angstroms",
|
||||
"Å"
|
||||
]
|
||||
},
|
||||
{
|
||||
"canonical":"μm",
|
||||
"aliases": [
|
||||
"micrometers",
|
||||
"micrometres",
|
||||
"microns"
|
||||
]
|
||||
}
|
||||
],
|
||||
"linearPairs":[
|
||||
@ -216,9 +251,12 @@
|
||||
{"item1":"mi", "item2":"ft", "factor":5280},
|
||||
{"item1":"m", "item2":"in", "factor":39.37008},
|
||||
{"item1":"m", "item2":"cm", "factor":100},
|
||||
{"item1":"cm", "item2":"mm", "factor":10},
|
||||
{"item1":"m", "item2":"μm", "factor":1000000},
|
||||
{"item1":"km", "item2":"mi", "factor":0.6213712},
|
||||
{"item1":"ft", "item2":"in", "factor":12},
|
||||
{"item1":"yd", "item2":"ft", "factor":3},
|
||||
{"item1":"football field", "item2":"yd", "factor":100},
|
||||
{"item1":"chain", "item2":"yd", "factor":22},
|
||||
{"item1":"chain", "item2":"link", "factor":100},
|
||||
{"item1":"furlong", "item2":"mi", "factor":8},
|
||||
@ -226,6 +264,9 @@
|
||||
{"item1":"AU", "item2":"ly", "factor": 0.0000158125},
|
||||
{"item1":"ly", "item2":"km", "factor": 946070000000},
|
||||
{"item1":"pc", "item2":"AU", "factor":206266.3},
|
||||
{"item1":"blue whale length", "item2": "m", "factor": 29.9},
|
||||
{"item1":"m", "item2": "ångström", "factor": 10000000000},
|
||||
{"item1":"smoot", "item2": "ft", "factor": 5.583333333333},
|
||||
|
||||
{"item1":"floz", "item2":"mL", "factor":29.57344},
|
||||
{"item1":"L", "item2":"mL", "factor":1000},
|
||||
@ -242,14 +283,14 @@
|
||||
{"item1":"gal", "item2":"floz", "factor":128},
|
||||
{"item1":"gal", "item2":"qt", "factor":4},
|
||||
|
||||
|
||||
|
||||
{"item1":"acre", "item2":"yd^2", "factor":4840},
|
||||
{"item1":"yd^2", "item2":"m^2", "factor":0.836127},
|
||||
|
||||
{"item1":"mph", "item2":"knot", "factor":0.868976},
|
||||
{"item1":"mph", "item2":"kph", "factor":1.609343550606653},
|
||||
|
||||
|
||||
|
||||
{"item1":"kPa", "item2":"Pa", "factor":1000},
|
||||
{"item1":"Nm^2", "item2":"Pa", "factor":1},
|
||||
{"item1":"Pa", "item2":"bar", "factor":100},
|
||||
|
@ -17,7 +17,7 @@ What did the teacher do with the students report on cheese? Grated it.
|
||||
What do you call a man with no legs and arms in a pool? Bob.
|
||||
I was going to tell a joke about hammers but ...I don't think I'll nail it
|
||||
why did the can recycler quit his job? because it was so depressing.
|
||||
They told me to stop impersonating a flamingo. I had to put my foot down.
|
||||
They told me to stop impersonating a flamingo. I had to put my foot down.
|
||||
I failed math so many times at school, I can’t even count.
|
||||
When I was a child, I threw a boomerang, but it didn't come back. I live in constant fear.
|
||||
When life gives you melons, you might be dyslexic.
|
||||
@ -40,7 +40,6 @@ A ghost walked into a bar and ordered a shot of vodka. The bartender said, ‘So
|
||||
A blind man walked into a bar. and a table. and a chair.
|
||||
How do you make holy water? You boil the hell out of it.
|
||||
My teachers told me I’d never amount to much because I procrastinate so much. I told them, “Just you wait!”
|
||||
ברכב שנוסע על 4 גלגלים, איזה גלגל לא זז? גלגל רזרבי
|
||||
what's the best part about living in switzerland? well the flag is a big plus.
|
||||
I asked my date to meet me at the gym today. She didn't show up. That's when I knew we weren't gonna work out.
|
||||
The CEO of IKEA was elected Prime Minister in Sweden. He should have his cabinet together by the end of the weekend.
|
||||
@ -76,4 +75,4 @@ Someone broke into my house and stole all my fruits. I'm peachless.
|
||||
Did I tell you guys about that flat earther i got into an argument with? he got so mad he stormed off saying he'd walk to the edge of the earth to prove me wrong, but he'll come around eventually.
|
||||
What do you call your friend who stands in a hole? Phil.
|
||||
What happened when the bear swallowed a clock? He got ticks.
|
||||
What do you call a wolf who gets lost? A where-wolf.
|
||||
What do you call a wolf who gets lost? A where-wolf.
|
||||
|
@ -7,7 +7,7 @@ using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace silverworker_discord
|
||||
namespace vassago
|
||||
{
|
||||
public class ExternalProcess
|
||||
{
|
||||
|
@ -1,38 +1,51 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<RootNamespace>silverworker_discord</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="discord.net" Version="3.10.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" />
|
||||
<PackageReference Include="QRCoder" Version="1.4.2" />
|
||||
<PackageReference Include="youtubedlsharp" Version="0.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="assets/jokes.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="assets/coding and algorithms.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="assets/ekgblip.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="assets/conversion.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="assets/loud sweating.gif">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<NoWarn>$(NoWarn);CA2254</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="bootstrap" Version="5.3.3" />
|
||||
<PackageReference Include="discord.net" Version="3.10.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.20" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4" />
|
||||
<PackageReference Include="QRCoder" Version="1.4.2" />
|
||||
<PackageReference Include="RestSharp" Version="110.2.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="6.6.2" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.6.2" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.6.2" />
|
||||
<PackageReference Include="TwitchLib" Version="3.5.3" />
|
||||
<PackageReference Include="youtubedlsharp" Version="0.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="assets/jokes.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="assets/coding and algorithms.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="assets/ekgblip.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="assets/conversion.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="assets/loud sweating.gif">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
10
wwwroot/css/bstreeview.min.css
vendored
Normal file
10
wwwroot/css/bstreeview.min.css
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
@preserve
|
||||
bstreeview.css
|
||||
Version: 1.2.0
|
||||
Authors: Sami CHNITER <sami.chniter@gmail.com>
|
||||
Copyright 2020
|
||||
License: Apache License 2.0
|
||||
Project: https://github.com/nhmvienna/bs5treeview
|
||||
*/
|
||||
.bstreeview{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem;padding:0;overflow:hidden}.bstreeview .list-group{margin-bottom:0}.bstreeview .list-group-item{border-radius:0;border-width:1px 0 0 0;padding-top:.5rem;padding-bottom:.5rem;cursor:pointer}.bstreeview .list-group-item:hover{background-color:#dee2e6}.bstreeview>.list-group-item:first-child{border-top-width:0}.bstreeview .state-icon{margin-right:8px}.bstreeview .item-icon{margin-right:5px}
|
9
wwwroot/css/fontawesome.min.css
vendored
Normal file
9
wwwroot/css/fontawesome.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
46
wwwroot/css/site.css
Normal file
46
wwwroot/css/site.css
Normal file
@ -0,0 +1,46 @@
|
||||
html {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
html {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
|
||||
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
|
||||
}
|
||||
|
||||
html {
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
.protocol-icon,.channel-type-icon{
|
||||
display:inline-block;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background-size: 32px;
|
||||
}
|
||||
.discord .protocol-icon{
|
||||
background-image: url("../imgs/discord_logo1600.png");
|
||||
}
|
||||
.twitch .protocol-icon{
|
||||
background-image: url("../imgs/twitch.png");
|
||||
}
|
||||
.Normal .channel-type-icon{
|
||||
background-color: black;
|
||||
}
|
||||
.DM .channel-type-icon{
|
||||
background-color: black;
|
||||
}
|
||||
.Protocol .channel-type-icon{
|
||||
background-color: black;
|
||||
}
|
||||
.OU .channel-type-icon{
|
||||
background-color: black;
|
||||
}
|
BIN
wwwroot/favicon.ico
Normal file
BIN
wwwroot/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
BIN
wwwroot/imgs/discord_logo1600.png
Normal file
BIN
wwwroot/imgs/discord_logo1600.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
BIN
wwwroot/imgs/twitch.png
Normal file
BIN
wwwroot/imgs/twitch.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
10
wwwroot/js/bstreeview.min.js
vendored
Normal file
10
wwwroot/js/bstreeview.min.js
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
@preserve
|
||||
bstreeview.js
|
||||
Version: 1.2.0
|
||||
Authors: Sami CHNITER <sami.chniter@gmail.com>
|
||||
Copyright 2020
|
||||
License: Apache License 2.0
|
||||
Project:https://github.com/nhmvienna/bs5treeview
|
||||
*/
|
||||
!function (t, e, i, s) { "use strict"; var n = { expandIcon: "fa fa-angle-down fa-fw", collapseIcon: "fa fa-angle-right fa-fw", expandClass: 'show', indent: 1.25, parentsMarginLeft: "1.25rem", openNodeLinkOnNewTab: !0 }, a = '<div role="treeitem" class="list-group-item" data-bs-toggle="collapse"></div>', d = '<div role="group" class="list-group collapse" id="itemid"></div>', o = '<i class="state-icon"></i>', r = '<i class="item-icon"></i>'; function l(e, i) { this.element = e, this.itemIdPrefix = e.id + "-item-", this.settings = t.extend({}, n, i), this.init() } t.extend(l.prototype, { init: function () { this.tree = [], this.nodes = [], this.settings.data && (this.settings.data.isPrototypeOf(String) && (this.settings.data = t.parseJSON(this.settings.data)), this.tree = t.extend(!0, [], this.settings.data), delete this.settings.data), t(this.element).addClass("bstreeview"), this.initData({ nodes: this.tree }); var i = this; this.build(t(this.element), this.tree, 0), t(this.element).on("click", ".list-group-item", function (s) { t(".state-icon", this).toggleClass(i.settings.expandIcon).toggleClass(i.settings.collapseIcon), s.target.hasAttribute("href") && (i.settings.openNodeLinkOnNewTab ? e.open(s.target.getAttribute("href"), "_blank") : e.location = s.target.getAttribute("href")) }) }, initData: function (e) { if (e.nodes) { var i = e, s = this; t.each(e.nodes, function (t, e) { e.nodeId = s.nodes.length, e.parentId = i.nodeId, s.nodes.push(e), e.nodes && s.initData(e) }) } }, build: function (e, i, s) { var n = this, l = n.settings.parentsMarginLeft; s > 0 && (l = (n.settings.indent + s * n.settings.indent).toString() + "rem;"), s += 1, t.each(i, function (i, g) { var h = t(a).attr("data-bs-target", "#" + n.itemIdPrefix + g.nodeId).attr("style", "padding-left:" + l).attr("aria-level", s); if (g.nodes) { var c = t(o).addClass((g.expanded)?n.settings.expandIcon:n.settings.collapseIcon); h.append(c) } if (g.icon) { var f = t(r).addClass(g.icon); h.append(f) } if (h.append(g.text), g.href && h.attr("href", g.href), g.class && h.addClass(g.class), g.id && h.attr("id", g.id), e.append(h), g.nodes) { var p = t(d).attr("id", n.itemIdPrefix + g.nodeId); e.append(p), n.build(p, g.nodes, s); if (g.expanded) p.addClass(n.settings.expandClass) } }) } }), t.fn.bstreeview = function (e) { return this.each(function () { t.data(this, "plugin_bstreeview") || t.data(this, "plugin_bstreeview", new l(this, e)) }) } }(jQuery, window, document);
|
50
wwwroot/js/site.js
Normal file
50
wwwroot/js/site.js
Normal file
@ -0,0 +1,50 @@
|
||||
// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
|
||||
// for details on configuring this project to bundle and minify static web assets.
|
||||
|
||||
// Write your JavaScript code.
|
||||
|
||||
function testfunct(caller){
|
||||
console.log("[gibberish]");
|
||||
console.log(caller);
|
||||
}
|
||||
function patchModel(model)
|
||||
{
|
||||
//structure the model your (dang) self into a nice object
|
||||
console.log(model);
|
||||
//i know the page url.
|
||||
console.log(window.location.pathname);
|
||||
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 id=components[3];
|
||||
|
||||
//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?
|
||||
var apiUrl = "/api/Channels/"
|
||||
|
||||
console.log("dexter impression: I am now ready to post the following content:");
|
||||
console.log(JSON.stringify(model));
|
||||
fetch(apiUrl, {
|
||||
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);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
}
|
22
wwwroot/lib/bootstrap/LICENSE
Normal file
22
wwwroot/lib/bootstrap/LICENSE
Normal file
@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011-2021 Twitter, Inc.
|
||||
Copyright (c) 2011-2021 The Bootstrap Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
4997
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css
vendored
Normal file
4997
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map
vendored
Normal file
1
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map
vendored
Normal file
File diff suppressed because one or more lines are too long
7
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css
vendored
Normal file
7
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map
vendored
Normal file
1
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map
vendored
Normal file
File diff suppressed because one or more lines are too long
4996
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css
vendored
Normal file
4996
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map
vendored
Normal file
1
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map
vendored
Normal file
File diff suppressed because one or more lines are too long
7
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css
vendored
Normal file
7
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map
vendored
Normal file
1
wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map
vendored
Normal file
File diff suppressed because one or more lines are too long
427
wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css
vendored
Normal file
427
wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css
vendored
Normal file
@ -0,0 +1,427 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2021 The Bootstrap Authors
|
||||
* Copyright 2011-2021 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
background-color: currentColor;
|
||||
border: 0;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
hr:not([size]) {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title],
|
||||
abbr[data-bs-original-title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.2em;
|
||||
background-color: #fcf8e3;
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0d6efd;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
color: #0a58ca;
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
font-size: 1em;
|
||||
direction: ltr /* rtl:ignore */;
|
||||
unicode-bidi: bidi-override;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: #d63384;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.2rem 0.4rem;
|
||||
font-size: 0.875em;
|
||||
color: #fff;
|
||||
background-color: #212529;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: #6c757d;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]::-webkit-calendar-picker-indicator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: left;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
outline-offset: -2px;
|
||||
-webkit-appearance: textfield;
|
||||
}
|
||||
|
||||
/* rtl:raw:
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
*/
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user