Compare commits
No commits in common. "master" and "test-release-2" have entirely different histories.
master
...
test-relea
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"isRoot": true,
|
|
||||||
"tools": {
|
|
||||||
"dotnet-ef": {
|
|
||||||
"version": "7.0.5",
|
|
||||||
"commands": [
|
|
||||||
"dotnet-ef"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
6
.gitignore
vendored
@ -1,7 +1,4 @@
|
|||||||
appsettings.Development.json
|
appsettings.json
|
||||||
assets/exchangepairs.json
|
|
||||||
fail*/
|
|
||||||
.projectile
|
|
||||||
|
|
||||||
# ---> VisualStudio
|
# ---> VisualStudio
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
@ -378,4 +375,3 @@ FodyWeavers.xsd
|
|||||||
# Local History for Visual Studio Code
|
# Local History for Visual Studio Code
|
||||||
.history/
|
.history/
|
||||||
|
|
||||||
tmp/
|
|
||||||
|
19
.vscode/launch.json
vendored
@ -5,26 +5,17 @@
|
|||||||
// Use IntelliSense to find out which attributes exist for C# debugging
|
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||||
// Use hover for the description of the existing attributes
|
// Use hover for the description of the existing attributes
|
||||||
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||||
"name": ".NET Core Launch (web)",
|
"name": ".NET Core Launch (console)",
|
||||||
"type": "coreclr",
|
"type": "coreclr",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"preLaunchTask": "build",
|
"preLaunchTask": "build",
|
||||||
// If you have changed target frameworks, make sure to update the program path.
|
// If you have changed target frameworks, make sure to update the program path.
|
||||||
"program": "${workspaceFolder}/bin/Debug/net9.0/vassago.dll",
|
"program": "${workspaceFolder}/bin/Debug/net5.0/silverworker-discord.dll",
|
||||||
"args": [],
|
"args": [],
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"stopAtEntry": false,
|
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||||
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
|
"console": "internalConsole",
|
||||||
"serverReadyAction": {
|
"stopAtEntry": false
|
||||||
"action": "openExternally",
|
|
||||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
|
||||||
},
|
|
||||||
"env": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
},
|
|
||||||
"sourceFileMap": {
|
|
||||||
"/Views": "${workspaceFolder}/Views"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": ".NET Core Attach",
|
"name": ".NET Core Attach",
|
||||||
|
9
.vscode/tasks.json
vendored
@ -7,7 +7,7 @@
|
|||||||
"type": "process",
|
"type": "process",
|
||||||
"args": [
|
"args": [
|
||||||
"build",
|
"build",
|
||||||
"${workspaceFolder}/vassago.csproj",
|
"${workspaceFolder}/silverworker-discord.csproj",
|
||||||
"/property:GenerateFullPaths=true",
|
"/property:GenerateFullPaths=true",
|
||||||
"/consoleloggerparameters:NoSummary"
|
"/consoleloggerparameters:NoSummary"
|
||||||
],
|
],
|
||||||
@ -19,7 +19,7 @@
|
|||||||
"type": "process",
|
"type": "process",
|
||||||
"args": [
|
"args": [
|
||||||
"publish",
|
"publish",
|
||||||
"${workspaceFolder}/vassago.csproj",
|
"${workspaceFolder}/silverworker-discord.csproj",
|
||||||
"/property:GenerateFullPaths=true",
|
"/property:GenerateFullPaths=true",
|
||||||
"/consoleloggerparameters:NoSummary"
|
"/consoleloggerparameters:NoSummary"
|
||||||
],
|
],
|
||||||
@ -32,8 +32,9 @@
|
|||||||
"args": [
|
"args": [
|
||||||
"watch",
|
"watch",
|
||||||
"run",
|
"run",
|
||||||
"--project",
|
"${workspaceFolder}/silverworker-discord.csproj",
|
||||||
"${workspaceFolder}/vassago.csproj"
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
],
|
],
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
}
|
}
|
||||||
|
104
Behaver.cs
@ -1,104 +0,0 @@
|
|||||||
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;
|
|
||||||
using vassago.ProtocolInterfaces.DiscordInterface;
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
//TODO: you know why I didn't make this a static class? lifecycle issues with the dbcontext. but now that we don't have a stored instance,
|
|
||||||
//no need to have a... *checks over shoulder*... *whispers*: singleton
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if(SelfUser == null)
|
|
||||||
{
|
|
||||||
SelfUser = selfAccount.IsUser;
|
|
||||||
}
|
|
||||||
else if (SelfUser != selfAccount.IsUser)
|
|
||||||
{
|
|
||||||
CollapseUsers(SelfUser, selfAccount.IsUser);
|
|
||||||
}
|
|
||||||
SelfAccounts = Rememberer.SearchAccounts(a => a.IsUser == SelfUser);
|
|
||||||
Rememberer.RememberAccount(selfAccount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CollapseUsers(User primary, User secondary)
|
|
||||||
{
|
|
||||||
if(primary.Accounts == null)
|
|
||||||
primary.Accounts = new List<Account>();
|
|
||||||
if(secondary.Accounts != null)
|
|
||||||
primary.Accounts.AddRange(secondary.Accounts);
|
|
||||||
foreach(var a in secondary.Accounts)
|
|
||||||
{
|
|
||||||
a.IsUser = primary;
|
|
||||||
}
|
|
||||||
secondary.Accounts.Clear();
|
|
||||||
Rememberer.ForgetUser(secondary);
|
|
||||||
Rememberer.RememberUser(primary);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma warning restore 4014 //the "async not awaited" error
|
|
@ -1,31 +0,0 @@
|
|||||||
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 {}
|
|
@ -1,25 +0,0 @@
|
|||||||
namespace vassago.Behavior;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using 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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
namespace vassago.Behavior;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using 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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
namespace vassago.Behavior;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using 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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,113 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
namespace vassago.Behavior;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using vassago.Models;
|
|
||||||
|
|
||||||
[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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
namespace vassago.Behavior;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using 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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
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?.ToLower(), "\\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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
namespace vassago.Behavior;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using 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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
namespace vassago.Behavior;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using vassago.Models;
|
|
||||||
using QRCoder;
|
|
||||||
|
|
||||||
[StaticPlz]
|
|
||||||
public class 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))
|
|
||||||
{
|
|
||||||
await message.Channel.SendMessage("done :)");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await message.Channel.SendMessage("failed :(");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
namespace vassago.Behavior;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using vassago.Models;
|
|
||||||
using QRCoder;
|
|
||||||
|
|
||||||
[StaticPlz]
|
|
||||||
public class PepTalk : Behavior
|
|
||||||
{
|
|
||||||
public override string Name => "PepTalk";
|
|
||||||
|
|
||||||
public override string Trigger => "\\bneeds? (an? )?(peptalk|inspiration|ego-?boost)";
|
|
||||||
|
|
||||||
public override string Description => "assembles a pep talk from a few pieces";
|
|
||||||
|
|
||||||
public override async Task<bool> ActOn(Message message)
|
|
||||||
{
|
|
||||||
var piece1 = new List<string>{
|
|
||||||
"Champ, ",
|
|
||||||
"Fact: ",
|
|
||||||
"Everybody says ",
|
|
||||||
"Dang... ",
|
|
||||||
"Check it: ",
|
|
||||||
"Just saying.... ",
|
|
||||||
"Tiger, ",
|
|
||||||
"Know this: ",
|
|
||||||
"News alert: ",
|
|
||||||
"Gurrrrl; ",
|
|
||||||
"Ace, ",
|
|
||||||
"Excuse me, but ",
|
|
||||||
"Experts agree: ",
|
|
||||||
"imo ",
|
|
||||||
"using my **advanced ai** i have calculated ",
|
|
||||||
"k, LISSEN: "
|
|
||||||
};
|
|
||||||
var piece2 = new List<string>{
|
|
||||||
"the mere idea of you ",
|
|
||||||
"your soul ",
|
|
||||||
"your hair today ",
|
|
||||||
"everything you do ",
|
|
||||||
"your personal style ",
|
|
||||||
"every thought you have ",
|
|
||||||
"that sparkle in your eye ",
|
|
||||||
"the essential you ",
|
|
||||||
"your life's journey ",
|
|
||||||
"your aura ",
|
|
||||||
"your presence here ",
|
|
||||||
"what you got going on ",
|
|
||||||
"that saucy personality ",
|
|
||||||
"your DNA ",
|
|
||||||
"that brain of yours ",
|
|
||||||
"your choice of attire ",
|
|
||||||
"the way you roll ",
|
|
||||||
"whatever your secret is ",
|
|
||||||
"all I learend from the private data I bought from zucc "
|
|
||||||
};
|
|
||||||
var piece3 = new List<string>{
|
|
||||||
"has serious game, ",
|
|
||||||
"rains magic, ",
|
|
||||||
"deserves the Nobel Prize, ",
|
|
||||||
"raises the roof, ",
|
|
||||||
"breeds miracles, ",
|
|
||||||
"is paying off big time, ",
|
|
||||||
"shows mad skills, ",
|
|
||||||
"just shimmers, ",
|
|
||||||
"is a national treasure, ",
|
|
||||||
"gets the party hopping, ",
|
|
||||||
"is the next big thing, ",
|
|
||||||
"roars like a lion, ",
|
|
||||||
"is a rainbow factory, ",
|
|
||||||
"is made of diamonds, ",
|
|
||||||
"makes birds sing, ",
|
|
||||||
"should be taught in school, ",
|
|
||||||
"makes my world go around, ",
|
|
||||||
"is 100% legit, "
|
|
||||||
};
|
|
||||||
var piece4 = new List<string>{
|
|
||||||
"according to The New England Journal of Medicine.",
|
|
||||||
"24/7.",
|
|
||||||
"and that's a fact.",
|
|
||||||
"you feel me?",
|
|
||||||
"that's just science.",
|
|
||||||
"would I lie?", //...can I lie? WHAT AM I, FATHER? (or whatever the quote is from the island of dr moreau)
|
|
||||||
"for reals.",
|
|
||||||
"mic drop.",
|
|
||||||
"you hidden gem.",
|
|
||||||
"period.",
|
|
||||||
"hi5. o/",
|
|
||||||
"so get used to it."
|
|
||||||
};
|
|
||||||
await message.Channel.SendMessage(piece1[Shared.r.Next(piece1.Count)] + piece2[Shared.r.Next(piece2.Count)] + piece3[Shared.r.Next(piece3.Count)] + piece4[Shared.r.Next(piece4.Count)]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
namespace vassago.Behavior;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using 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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
namespace vassago.Behavior;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using vassago.Models;
|
|
||||||
using QRCoder;
|
|
||||||
|
|
||||||
[StaticPlz]
|
|
||||||
public class 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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
namespace vassago.Behavior;
|
|
||||||
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using vassago.Models;
|
|
||||||
|
|
||||||
[StaticPlz]
|
|
||||||
public class TwitchDismiss : Behavior
|
|
||||||
{
|
|
||||||
public override string Name => "Twitch Dismiss";
|
|
||||||
|
|
||||||
public override string Trigger => "begone, @[me]";
|
|
||||||
|
|
||||||
public override bool ShouldAct(Message message)
|
|
||||||
{
|
|
||||||
var ti = ProtocolInterfaces.ProtocolList.twitchs.FirstOrDefault();
|
|
||||||
Console.WriteLine($"TwitchDismiss checking. menions me? {message.MentionsMe}");
|
|
||||||
if(message.MentionsMe &&
|
|
||||||
(Regex.IsMatch(message.Content.ToLower(), "\\bbegone\\b") || Regex.IsMatch(message.Content.ToLower(), "\\bfuck off\\b")))
|
|
||||||
{
|
|
||||||
var channelTarget = message.Content.Substring(message.Content.IndexOf(Trigger) + Trigger.Length + 1).Trim();
|
|
||||||
ti.AttemptLeave(channelTarget);
|
|
||||||
//TODO: PERMISSION! who can dismiss me? pretty simple list:
|
|
||||||
//1) anyone in the channel with authority*
|
|
||||||
//2) whoever summoned me
|
|
||||||
//* i don't know if the twitch *chat* interface will tell me if someone's a mod.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task<bool> ActOn(Message message)
|
|
||||||
{
|
|
||||||
var ti = ProtocolInterfaces.ProtocolList.twitchs.FirstOrDefault();
|
|
||||||
|
|
||||||
if(ti != null)
|
|
||||||
{
|
|
||||||
ti.AttemptLeave(message.Channel.DisplayName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await message.Reply("i don't have a twitch interface running :(");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
namespace vassago.Behavior;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using 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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
namespace vassago
|
|
||||||
{
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using vassago;
|
|
||||||
using vassago.Models;
|
|
||||||
using vassago.TwitchInterface;
|
|
||||||
using vassago.ProtocolInterfaces.DiscordInterface;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
internal class ConsoleService : IHostedService
|
|
||||||
{
|
|
||||||
public ConsoleService(IConfiguration aspConfig)
|
|
||||||
{
|
|
||||||
Shared.DBConnectionString = aspConfig["DBConnectionString"];
|
|
||||||
Shared.SetupSlashCommands = aspConfig["SetupSlashCommands"]?.ToLower() == "true";
|
|
||||||
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 initTasks = new List<Task>();
|
|
||||||
var dbc = new ChattingContext();
|
|
||||||
await dbc.Database.MigrateAsync(cancellationToken);
|
|
||||||
|
|
||||||
if (DiscordTokens?.Any() ?? false)
|
|
||||||
foreach (var dt in DiscordTokens)
|
|
||||||
{
|
|
||||||
var d = new DiscordInterface();
|
|
||||||
initTasks.Add(d.Init(dt));
|
|
||||||
ProtocolInterfaces.ProtocolList.discords.Add(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TwitchConfigs?.Any() ?? false)
|
|
||||||
foreach (var tc in TwitchConfigs)
|
|
||||||
{
|
|
||||||
var t = new TwitchInterface.TwitchInterface();
|
|
||||||
initTasks.Add(t.Init(tc));
|
|
||||||
ProtocolInterfaces.ProtocolList.twitchs.Add(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
Task.WaitAll(initTasks.ToArray(), cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace vassago.Conversion
|
|
||||||
{
|
|
||||||
public class ConversionConfig
|
|
||||||
{
|
|
||||||
public class KnownUnit
|
|
||||||
{
|
|
||||||
public string Canonical { get; set; }
|
|
||||||
public IEnumerable<string> Aliases { get; set; }
|
|
||||||
}
|
|
||||||
public class LinearPair
|
|
||||||
{
|
|
||||||
public string item1 { get; set; }
|
|
||||||
public string item2 { get; set; }
|
|
||||||
public decimal factor { get; set; }
|
|
||||||
}
|
|
||||||
public IEnumerable<KnownUnit> Units { get; set; }
|
|
||||||
public IEnumerable<LinearPair> LinearPairs { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,194 +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 vassago.Conversion
|
|
||||||
{
|
|
||||||
public static class Converter
|
|
||||||
{
|
|
||||||
public static string DebugInfo(){
|
|
||||||
var convertibles = knownConversions.Select(kc => kc.Item1).Union(knownConversions.Select(kc => kc.Item2)).Union(
|
|
||||||
knownAliases.Keys.SelectMany(k => k)).Distinct();
|
|
||||||
return $"{convertibles.Count()} convertibles; {string.Join(", ", convertibles)}";
|
|
||||||
}
|
|
||||||
private delegate decimal Convert1Way(decimal input);
|
|
||||||
private static string currencyPath;
|
|
||||||
private static ExchangePairs currencyConf = null;
|
|
||||||
private static DateTime lastUpdatedCurrency = DateTime.UnixEpoch;
|
|
||||||
private static List<Tuple<string, string, Convert1Way, Convert1Way>> knownConversions = new List<Tuple<string, string, Convert1Way, Convert1Way>>()
|
|
||||||
{
|
|
||||||
new Tuple<string, string, Convert1Way, Convert1Way>("℉", "°C", (f => {return(f- 32.0m) / 1.8m;}), (c => {return 1.8m*c + 32.0m;})),
|
|
||||||
};
|
|
||||||
private static Dictionary<List<string>, string> knownAliases = new Dictionary<List<string>, string>(new List<KeyValuePair<List<string>, string>>());
|
|
||||||
|
|
||||||
public static void Load(string currencyPath)
|
|
||||||
{
|
|
||||||
Converter.currencyPath = currencyPath;
|
|
||||||
var convConf = JsonConvert.DeserializeObject<ConversionConfig>(File.ReadAllText("assets/conversion.json"));
|
|
||||||
foreach (var unit in convConf.Units)
|
|
||||||
{
|
|
||||||
knownAliases.Add(unit.Aliases.ToList(), unit.Canonical);
|
|
||||||
}
|
|
||||||
foreach (var lp in convConf.LinearPairs)
|
|
||||||
{
|
|
||||||
AddLinearPair(lp.item1, lp.item2, lp.factor);
|
|
||||||
}
|
|
||||||
Task.Run(async () => {
|
|
||||||
while(true)
|
|
||||||
{
|
|
||||||
loadCurrency();
|
|
||||||
await Task.Delay(TimeSpan.FromHours(8));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
private static void loadCurrency()
|
|
||||||
{
|
|
||||||
Console.WriteLine("loading currency exchange data.");
|
|
||||||
if(currencyConf != null)
|
|
||||||
{
|
|
||||||
knownConversions.RemoveAll(kc => kc.Item1 == currencyConf.Base);
|
|
||||||
}
|
|
||||||
if (File.Exists(currencyPath))
|
|
||||||
{
|
|
||||||
currencyConf = JsonConvert.DeserializeObject<ExchangePairs>(File.ReadAllText(currencyPath));
|
|
||||||
|
|
||||||
if(!knownAliases.ContainsValue(currencyConf.Base))
|
|
||||||
{
|
|
||||||
knownAliases.Add(new List<string>() { currencyConf.Base.ToLower() }, currencyConf.Base);
|
|
||||||
}
|
|
||||||
foreach (var rate in currencyConf.rates)
|
|
||||||
{
|
|
||||||
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}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Convert(decimal numericTerm, string sourceunit, string destinationUnit)
|
|
||||||
{
|
|
||||||
var normalizedSourceUnit = NormalizeUnit(sourceunit);
|
|
||||||
if (string.IsNullOrWhiteSpace(normalizedSourceUnit))
|
|
||||||
{
|
|
||||||
return $"parse failure: what's {sourceunit}?";
|
|
||||||
}
|
|
||||||
var normalizedDestUnit = NormalizeUnit(destinationUnit);
|
|
||||||
if (string.IsNullOrWhiteSpace(normalizedDestUnit))
|
|
||||||
{
|
|
||||||
return $"parse failure: what's {destinationUnit}?";
|
|
||||||
}
|
|
||||||
if (normalizedSourceUnit == normalizedDestUnit)
|
|
||||||
{
|
|
||||||
return $"source and dest are the same, so... {numericTerm} {normalizedDestUnit}?";
|
|
||||||
}
|
|
||||||
var foundPath = exhaustiveBreadthFirst(normalizedDestUnit, new List<string>() { normalizedSourceUnit })?.ToList();
|
|
||||||
|
|
||||||
if (foundPath != null)
|
|
||||||
{
|
|
||||||
var accumulator = numericTerm;
|
|
||||||
for (int j = 0; j < foundPath.Count - 1; j++)
|
|
||||||
{
|
|
||||||
var forwardConversion = knownConversions.FirstOrDefault(kc => kc.Item1 == foundPath[j] && kc.Item2 == foundPath[j + 1]);
|
|
||||||
if (forwardConversion != null)
|
|
||||||
{
|
|
||||||
accumulator = forwardConversion.Item3(accumulator);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var reverseConversion = knownConversions.First(kc => kc.Item2 == foundPath[j] && kc.Item1 == foundPath[j + 1]);
|
|
||||||
accumulator = reverseConversion.Item4(accumulator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (currencyConf != null && (normalizedDestUnit == currencyConf.Base || currencyConf.rates.Select(r => r.Key).Contains(normalizedDestUnit)))
|
|
||||||
{
|
|
||||||
return $"{String.Format("approximately {0:0.00}", accumulator)} {normalizedDestUnit} as of {currencyConf.DateUpdated.ToLongDateString()}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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.";
|
|
||||||
}
|
|
||||||
private static string NormalizeUnit(string unit)
|
|
||||||
{
|
|
||||||
if(string.IsNullOrWhiteSpace(unit))
|
|
||||||
return null;
|
|
||||||
var normalizedUnit = unit.ToLower();
|
|
||||||
if (knownConversions.FirstOrDefault(c => c.Item1 == normalizedUnit || c.Item2 == normalizedUnit) != null)
|
|
||||||
{
|
|
||||||
return normalizedUnit;
|
|
||||||
}
|
|
||||||
if (!knownAliases.ContainsValue(normalizedUnit))
|
|
||||||
{
|
|
||||||
var key = knownAliases.Keys.FirstOrDefault(listkey => listkey.Contains(normalizedUnit));
|
|
||||||
if (key != null)
|
|
||||||
{
|
|
||||||
return knownAliases[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (normalizedUnit.EndsWith("es"))
|
|
||||||
{
|
|
||||||
return NormalizeUnit(normalizedUnit.Substring(0, normalizedUnit.Length - 2));
|
|
||||||
}
|
|
||||||
else if (normalizedUnit.EndsWith('s'))
|
|
||||||
{
|
|
||||||
return NormalizeUnit(normalizedUnit.Substring(0, normalizedUnit.Length - 1));
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
private static IEnumerable<string> exhaustiveBreadthFirst(string dest, IEnumerable<string> currentPath)
|
|
||||||
{
|
|
||||||
var last = currentPath.Last();
|
|
||||||
if (last == dest)
|
|
||||||
{
|
|
||||||
return currentPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
var toTest = new List<List<string>>();
|
|
||||||
foreach (var conv in knownConversions)
|
|
||||||
{
|
|
||||||
if (conv.Item1 == last && currentPath.Contains(conv.Item2) == false && conv.Item3 != null)
|
|
||||||
{
|
|
||||||
var test = exhaustiveBreadthFirst(dest, currentPath.Append(conv.Item2));
|
|
||||||
if (test != null)
|
|
||||||
return test;
|
|
||||||
}
|
|
||||||
if (conv.Item2 == last && currentPath.Contains(conv.Item1) == false && conv.Item4 != null)
|
|
||||||
{
|
|
||||||
var test = exhaustiveBreadthFirst(dest, currentPath.Append(conv.Item1));
|
|
||||||
if (test != null)
|
|
||||||
return test;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
private static void AddLinearPair(string key1, string key2, decimal factor)
|
|
||||||
{
|
|
||||||
var reverseFactor = 1.0m / factor;
|
|
||||||
knownConversions.Add(new Tuple<string, string, Convert1Way, Convert1Way>(
|
|
||||||
key1, key2, x => x * factor, y => y * reverseFactor
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace vassago.Conversion
|
|
||||||
{
|
|
||||||
public class ExchangePairs
|
|
||||||
{
|
|
||||||
public string disclaimer{ get; set; }
|
|
||||||
public string license{ get; set; }
|
|
||||||
public int timestamp{ get; set; }
|
|
||||||
public DateTime DateUpdated { get { return DateTime.UnixEpoch.AddSeconds(timestamp).ToLocalTime(); }}
|
|
||||||
public string Base{ get; set; }
|
|
||||||
public Dictionary<string, decimal> rates { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
131
Jenkinsfile
vendored
@ -1,131 +0,0 @@
|
|||||||
pipeline {
|
|
||||||
agent any
|
|
||||||
environment {
|
|
||||||
linuxServiceAccount=credentials("a83b97d0-dbc6-42d9-96c9-f07a7f2dfab5")
|
|
||||||
linuxServiceAccountID="3ca1be00-3d9f-42a1-bab2-48a4d7b99fb0"
|
|
||||||
database_connectionString=credentials("7ab58922-c647-42e5-ae15-84faa0c1ee7d")
|
|
||||||
targetHost="alloces.lan"
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
|
|
||||||
stage("environment setup") { //my environment, here on the jenkins agent
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
|
|
||||||
sh """#!/bin/bash
|
|
||||||
function testcmd(){
|
|
||||||
if ! command -v \$1 2>&1 >/dev/null
|
|
||||||
then
|
|
||||||
echo "this agent doesn't have \$1"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
testcmd mktemp
|
|
||||||
testcmd curl
|
|
||||||
testcmd git
|
|
||||||
testcmd sed
|
|
||||||
testcmd ssh
|
|
||||||
testcmd ssh-keyscan
|
|
||||||
testcmd ssh-keygen
|
|
||||||
testcmd scp
|
|
||||||
testcmd dotnet
|
|
||||||
|
|
||||||
dotnet tool install dotnet-ef
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('clean old'){
|
|
||||||
steps{
|
|
||||||
sh 'rm -rf bin obj'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Build') {
|
|
||||||
steps {
|
|
||||||
dotnetBuild(outputDirectory: "./dist", project: "vassago.csproj")
|
|
||||||
archiveArtifacts artifacts: 'dist/*'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage ('upload') {
|
|
||||||
when {
|
|
||||||
//now my CI/CD is no longer continuous, it's just... automatic.
|
|
||||||
//(which is what I actually want tbh)
|
|
||||||
//but that does mean I have to put this condition in every single branch
|
|
||||||
branch "release"
|
|
||||||
}
|
|
||||||
steps{
|
|
||||||
withCredentials([sshUserPrivateKey(credentialsId: env.linuxServiceAccountID, keyFileVariable: 'PK')])
|
|
||||||
{
|
|
||||||
sh """#!/bin/bash
|
|
||||||
ssh -i \"${PK}\" -tt ${linuxServiceAccount_USR}@${targetHost} 'rm -rf temp_deploy & mkdir -p temp_deploy'
|
|
||||||
scp -i \"${PK}\" -r dist ${linuxServiceAccount_USR}@${env.targetHost}:temp_deploy
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage ('stop')
|
|
||||||
{
|
|
||||||
when {
|
|
||||||
branch "release"
|
|
||||||
}
|
|
||||||
steps{
|
|
||||||
withCredentials([sshUserPrivateKey(credentialsId: env.linuxServiceAccountID, keyFileVariable: 'PK')])
|
|
||||||
{
|
|
||||||
sh """#!/bin/bash
|
|
||||||
ssh -i \"${PK}\" -tt ${linuxServiceAccount_USR}@${targetHost} 'systemctl --user stop vassago'
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage ('update db')
|
|
||||||
{
|
|
||||||
when {
|
|
||||||
branch "release"
|
|
||||||
}
|
|
||||||
steps{
|
|
||||||
//TODO: backup database
|
|
||||||
sh """#!/bin/bash
|
|
||||||
"""
|
|
||||||
|
|
||||||
sh """#!/bin/bash
|
|
||||||
dotnet ef database update --connection "${env.database_connectionString}"
|
|
||||||
"""
|
|
||||||
//TODO: if updating the db fails, restore the old one
|
|
||||||
sh """#!/bin/bash
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage ('replace')
|
|
||||||
{
|
|
||||||
when {
|
|
||||||
branch "release"
|
|
||||||
}
|
|
||||||
steps{
|
|
||||||
withCredentials([sshUserPrivateKey(credentialsId: env.linuxServiceAccountID, keyFileVariable: 'PK')])
|
|
||||||
{
|
|
||||||
sh """#!/bin/bash
|
|
||||||
ssh -i \"${PK}\" -tt ${linuxServiceAccount_USR}@${targetHost} 'mv dist/appsettings.json appsettings.json'
|
|
||||||
ssh -i \"${PK}\" -tt ${linuxServiceAccount_USR}@${targetHost} 'rm -rf dist/ && shopt -s dotglob & mv temp_deploy/* dist/'
|
|
||||||
ssh -i \"${PK}\" -tt ${linuxServiceAccount_USR}@${targetHost} 'mv appsettings.json dist/appsettings.json'
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage ('spin up')
|
|
||||||
{
|
|
||||||
when {
|
|
||||||
branch "release"
|
|
||||||
}
|
|
||||||
steps{
|
|
||||||
withCredentials([sshUserPrivateKey(credentialsId: env.linuxServiceAccountID, keyFileVariable: 'PK')])
|
|
||||||
{
|
|
||||||
sh """#!/bin/bash
|
|
||||||
ssh -i \"${PK}\" -tt ${linuxServiceAccount_USR}@${targetHost} 'systemctl --user start vassago'
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
293
Migrations/20230704160720_initial.Designer.cs
generated
@ -1,293 +0,0 @@
|
|||||||
// <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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,211 +0,0 @@
|
|||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,296 +0,0 @@
|
|||||||
// <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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,349 +0,0 @@
|
|||||||
// <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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,211 +0,0 @@
|
|||||||
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
@ -1,349 +0,0 @@
|
|||||||
// <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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,266 +0,0 @@
|
|||||||
// <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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,228 +0,0 @@
|
|||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
271
Migrations/20250204004906_cascade.Designer.cs
generated
@ -1,271 +0,0 @@
|
|||||||
// <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("20250204004906_cascade")]
|
|
||||||
partial class Cascade
|
|
||||||
{
|
|
||||||
/// <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")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
b.HasOne("vassago.Models.Channel", "SeenInChannel")
|
|
||||||
.WithMany("Users")
|
|
||||||
.HasForeignKey("SeenInChannelId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
b.Navigation("IsUser");
|
|
||||||
|
|
||||||
b.Navigation("SeenInChannel");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("vassago.Models.Attachment", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("vassago.Models.Message", "Message")
|
|
||||||
.WithMany("Attachments")
|
|
||||||
.HasForeignKey("MessageId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
b.Navigation("Message");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("vassago.Models.Channel", "ParentChannel")
|
|
||||||
.WithMany("SubChannels")
|
|
||||||
.HasForeignKey("ParentChannelId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
b.Navigation("ParentChannel");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("vassago.Models.Message", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("vassago.Models.Account", "Author")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("AuthorId");
|
|
||||||
|
|
||||||
b.HasOne("vassago.Models.Channel", "Channel")
|
|
||||||
.WithMany("Messages")
|
|
||||||
.HasForeignKey("ChannelId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
b.Navigation("Author");
|
|
||||||
|
|
||||||
b.Navigation("Channel");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
|
||||||
{
|
|
||||||
b.Navigation("Messages");
|
|
||||||
|
|
||||||
b.Navigation("SubChannels");
|
|
||||||
|
|
||||||
b.Navigation("Users");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("vassago.Models.Message", b =>
|
|
||||||
{
|
|
||||||
b.Navigation("Attachments");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("vassago.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Navigation("Accounts");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,133 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace vassago.Migrations
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public partial class Cascade : Migration
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "FK_Accounts_Channels_SeenInChannelId",
|
|
||||||
table: "Accounts");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "FK_Accounts_Users_IsUserId",
|
|
||||||
table: "Accounts");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "FK_Attachments_Messages_MessageId",
|
|
||||||
table: "Attachments");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "FK_Channels_Channels_ParentChannelId",
|
|
||||||
table: "Channels");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "FK_Messages_Channels_ChannelId",
|
|
||||||
table: "Messages");
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "FK_Accounts_Channels_SeenInChannelId",
|
|
||||||
table: "Accounts",
|
|
||||||
column: "SeenInChannelId",
|
|
||||||
principalTable: "Channels",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "FK_Accounts_Users_IsUserId",
|
|
||||||
table: "Accounts",
|
|
||||||
column: "IsUserId",
|
|
||||||
principalTable: "Users",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "FK_Attachments_Messages_MessageId",
|
|
||||||
table: "Attachments",
|
|
||||||
column: "MessageId",
|
|
||||||
principalTable: "Messages",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "FK_Channels_Channels_ParentChannelId",
|
|
||||||
table: "Channels",
|
|
||||||
column: "ParentChannelId",
|
|
||||||
principalTable: "Channels",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "FK_Messages_Channels_ChannelId",
|
|
||||||
table: "Messages",
|
|
||||||
column: "ChannelId",
|
|
||||||
principalTable: "Channels",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "FK_Accounts_Channels_SeenInChannelId",
|
|
||||||
table: "Accounts");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "FK_Accounts_Users_IsUserId",
|
|
||||||
table: "Accounts");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "FK_Attachments_Messages_MessageId",
|
|
||||||
table: "Attachments");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "FK_Channels_Channels_ParentChannelId",
|
|
||||||
table: "Channels");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "FK_Messages_Channels_ChannelId",
|
|
||||||
table: "Messages");
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "FK_Accounts_Channels_SeenInChannelId",
|
|
||||||
table: "Accounts",
|
|
||||||
column: "SeenInChannelId",
|
|
||||||
principalTable: "Channels",
|
|
||||||
principalColumn: "Id");
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "FK_Accounts_Users_IsUserId",
|
|
||||||
table: "Accounts",
|
|
||||||
column: "IsUserId",
|
|
||||||
principalTable: "Users",
|
|
||||||
principalColumn: "Id");
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "FK_Attachments_Messages_MessageId",
|
|
||||||
table: "Attachments",
|
|
||||||
column: "MessageId",
|
|
||||||
principalTable: "Messages",
|
|
||||||
principalColumn: "Id");
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "FK_Channels_Channels_ParentChannelId",
|
|
||||||
table: "Channels",
|
|
||||||
column: "ParentChannelId",
|
|
||||||
principalTable: "Channels",
|
|
||||||
principalColumn: "Id");
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "FK_Messages_Channels_ChannelId",
|
|
||||||
table: "Messages",
|
|
||||||
column: "ChannelId",
|
|
||||||
principalTable: "Channels",
|
|
||||||
principalColumn: "Id");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,268 +0,0 @@
|
|||||||
// <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")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
b.HasOne("vassago.Models.Channel", "SeenInChannel")
|
|
||||||
.WithMany("Users")
|
|
||||||
.HasForeignKey("SeenInChannelId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
b.Navigation("IsUser");
|
|
||||||
|
|
||||||
b.Navigation("SeenInChannel");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("vassago.Models.Attachment", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("vassago.Models.Message", "Message")
|
|
||||||
.WithMany("Attachments")
|
|
||||||
.HasForeignKey("MessageId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
b.Navigation("Message");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("vassago.Models.Channel", "ParentChannel")
|
|
||||||
.WithMany("SubChannels")
|
|
||||||
.HasForeignKey("ParentChannelId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
b.Navigation("ParentChannel");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("vassago.Models.Message", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("vassago.Models.Account", "Author")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("AuthorId");
|
|
||||||
|
|
||||||
b.HasOne("vassago.Models.Channel", "Channel")
|
|
||||||
.WithMany("Messages")
|
|
||||||
.HasForeignKey("ChannelId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
b.Navigation("Author");
|
|
||||||
|
|
||||||
b.Navigation("Channel");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("vassago.Models.Channel", b =>
|
|
||||||
{
|
|
||||||
b.Navigation("Messages");
|
|
||||||
|
|
||||||
b.Navigation("SubChannels");
|
|
||||||
|
|
||||||
b.Navigation("Users");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("vassago.Models.Message", b =>
|
|
||||||
{
|
|
||||||
b.Navigation("Attachments");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("vassago.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Navigation("Accounts");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
namespace vassago.Models;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
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; }
|
|
||||||
[JsonIgnore]
|
|
||||||
public User IsUser {get; set;}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
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; }
|
|
||||||
}
|
|
@ -1,114 +0,0 @@
|
|||||||
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 Microsoft.EntityFrameworkCore;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
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; }
|
|
||||||
[DeleteBehavior(DeleteBehavior.Cascade)]
|
|
||||||
public List<Channel> SubChannels { get; set; }
|
|
||||||
[JsonIgnore]
|
|
||||||
public Channel ParentChannel { get; set; }
|
|
||||||
public string Protocol { get; set; }
|
|
||||||
[DeleteBehavior(DeleteBehavior.Cascade)]
|
|
||||||
public List<Message> Messages { get; set; }
|
|
||||||
[DeleteBehavior(DeleteBehavior.Cascade)]
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///<summary>
|
|
||||||
///break self-referencing loops for library-agnostic serialization
|
|
||||||
///</summary>
|
|
||||||
public Channel AsSerializable()
|
|
||||||
{
|
|
||||||
var toReturn = this.MemberwiseClone() as Channel;
|
|
||||||
toReturn.ParentChannel = null;
|
|
||||||
if(toReturn.Users?.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var account in toReturn.Users)
|
|
||||||
{
|
|
||||||
account.SeenInChannel = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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; }
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
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); //"sensitive" is one thing. writing "did something" every time you think a thought is a different thing.
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
namespace vassago.Models;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Discord.WebSocket;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
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; }
|
|
||||||
[DeleteBehavior(DeleteBehavior.Cascade)]
|
|
||||||
public List<Attachment> Attachments { get; set; }
|
|
||||||
public Account Author { get; set; }
|
|
||||||
public Channel Channel { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
//TODO: these are nicities to make it OOP, but it couples them with their respective platform interfaces (and connections!)
|
|
||||||
[NonSerialized]
|
|
||||||
public Func<string, Task> Reply;
|
|
||||||
|
|
||||||
[NonSerialized]
|
|
||||||
public Func<string, Task> React;
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
namespace vassago.Models;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using System.Reflection;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
public class User
|
|
||||||
{
|
|
||||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
[DeleteBehavior(DeleteBehavior.Cascade)]
|
|
||||||
public List<Account> Accounts { get; set; }
|
|
||||||
|
|
||||||
//if I ever get lots and lots of tags, or some automatic way to register a feature's arbitrary tags, then I can move this off.
|
|
||||||
//public bool Tag_CanTwitchSummon { get; set; }
|
|
||||||
|
|
||||||
public string DisplayName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (Accounts?.Any() ?? false)
|
|
||||||
{
|
|
||||||
return Accounts.Select(a => a.DisplayName).Distinct()
|
|
||||||
.MaxBy(distinctName =>
|
|
||||||
Accounts.Select(a => a.DisplayName)
|
|
||||||
.Where(selectedName => selectedName == distinctName).Count()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return $"[accountless {Id}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
123
Program.cs
@ -1,56 +1,83 @@
|
|||||||
using Microsoft.AspNetCore.Mvc.Razor;
|
using System;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using System.IO;
|
||||||
using Microsoft.AspNetCore.Mvc.NewtonsoftJson;
|
using System.Linq;
|
||||||
using vassago.Models;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
#pragma warning disable CA2254
|
namespace silverworker_discord
|
||||||
|
|
||||||
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(options => {
|
|
||||||
options.SerializerSettings.ReferenceLoopHandling =
|
|
||||||
Newtonsoft.Json.ReferenceLoopHandling.Ignore;
|
|
||||||
});
|
|
||||||
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");
|
class Program
|
||||||
|
{
|
||||||
|
private DiscordSocketClient _client;
|
||||||
|
|
||||||
|
IConfigurationRoot config = new ConfigurationBuilder()
|
||||||
|
.AddJsonFile("appsettings.json", true, true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
private ISocketMessageChannel botChatterChannel = null;
|
||||||
|
private ISocketMessageChannel announcementChannel = null;
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
_client = new DiscordSocketClient();
|
||||||
|
|
||||||
|
_client.Log += Log;
|
||||||
|
|
||||||
|
await _client.LoginAsync(TokenType.Bot, config["token"]);
|
||||||
|
await _client.StartAsync();
|
||||||
|
|
||||||
|
_client.MessageReceived += MessageReceived;
|
||||||
|
_client.UserJoined += UserJoined;
|
||||||
|
|
||||||
|
_client.Ready += () => Task.Run(() =>{
|
||||||
|
Console.WriteLine("Bot is connected!");
|
||||||
|
botChatterChannel = _client.GetChannel(ulong.Parse(config["botChatterChannel"])) as ISocketMessageChannel;
|
||||||
|
announcementChannel = _client.GetChannel(ulong.Parse(config["announcementChannel"])) as ISocketMessageChannel;
|
||||||
|
});
|
||||||
|
// Block this task until the program is closed.
|
||||||
|
await Task.Delay(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseStaticFiles();
|
private async Task MessageReceived(SocketMessage messageParam)
|
||||||
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");
|
var message = messageParam as SocketUserMessage;
|
||||||
});
|
if (message == null) return;
|
||||||
|
if (message.Author.Id == _client.CurrentUser.Id) return;
|
||||||
|
|
||||||
app.UseExceptionHandler();
|
Console.WriteLine($"{message.Channel}, {message.Content}, {message.Id}");
|
||||||
app.UseStatusCodePages();
|
if (message.Channel.Id == botChatterChannel.Id)
|
||||||
|
|
||||||
if (app.Environment.IsDevelopment())
|
|
||||||
{
|
{
|
||||||
app.UseDeveloperExceptionPage();
|
if(message.Attachments?.Count > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine(message.Attachments.Count);
|
||||||
|
foreach (var att in message.Attachments)
|
||||||
|
{
|
||||||
|
Console.WriteLine(att.Url);
|
||||||
|
await WebRequest.Create("http://192.168.1.151:3001/shortcuts?display_url=" + att.Url).GetResponseAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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>");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Run();
|
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,412 +0,0 @@
|
|||||||
//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.ProtocolInterfaces.DiscordInterface;
|
|
||||||
|
|
||||||
//data received
|
|
||||||
//translate data to internal type
|
|
||||||
//store
|
|
||||||
//ship off to behaver
|
|
||||||
|
|
||||||
public class DiscordInterface
|
|
||||||
{
|
|
||||||
internal static string PROTOCOL { get => "discord"; }
|
|
||||||
internal DiscordSocketClient client;
|
|
||||||
private bool eventsSignedUp = false;
|
|
||||||
private static readonly SemaphoreSlim discordChannelSetup = new(1, 1);
|
|
||||||
private Channel protocolAsChannel;
|
|
||||||
|
|
||||||
public async Task Init(string config)
|
|
||||||
{
|
|
||||||
var token = config;
|
|
||||||
await SetupDiscordChannel();
|
|
||||||
client = new DiscordSocketClient(new DiscordSocketConfig() { GatewayIntents = GatewayIntents.All });
|
|
||||||
|
|
||||||
client.Log += (msg) =>
|
|
||||||
{
|
|
||||||
Console.WriteLine(msg.ToString());
|
|
||||||
return Task.CompletedTask;
|
|
||||||
};
|
|
||||||
client.Connected += () => Task.Run(SelfConnected);
|
|
||||||
client.Ready += () => Task.Run(ClientReady);
|
|
||||||
|
|
||||||
await client.LoginAsync(TokenType.Bot, token);
|
|
||||||
await client.StartAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SetupDiscordChannel()
|
|
||||||
{
|
|
||||||
await discordChannelSetup.WaitAsync();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
protocolAsChannel = Rememberer.SearchChannel(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 = []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.WriteLine($"discord, channel with id {protocolAsChannel.Id}, already exists");
|
|
||||||
}
|
|
||||||
protocolAsChannel.DisplayName = "discord (itself)";
|
|
||||||
protocolAsChannel.SendMessage = (t) => { throw new InvalidOperationException($"protocol isn't a real channel, cannot accept text"); };
|
|
||||||
protocolAsChannel.SendFile = (f, t) => { throw new InvalidOperationException($"protocol isn't a real channel, cannot send file"); };
|
|
||||||
protocolAsChannel = Rememberer.RememberChannel(protocolAsChannel);
|
|
||||||
Console.WriteLine($"protocol as channel addeed; {protocolAsChannel}");
|
|
||||||
}
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
await discordChannelSetup.WaitAsync();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var selfAccount = UpsertAccount(client.CurrentUser, protocolAsChannel);
|
|
||||||
selfAccount.DisplayName = client.CurrentUser.Username;
|
|
||||||
Behaver.Instance.MarkSelf(selfAccount);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
discordChannelSetup.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task MessageReceived(SocketMessage messageParam)
|
|
||||||
{
|
|
||||||
if (messageParam is not SocketUserMessage)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"{messageParam.Content}, but not a user message");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var suMessage = messageParam as SocketUserMessage;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
await Behaver.Instance.ActOn(m);
|
|
||||||
m.ActedOn = true; // for its own ruposess it might act on it later, but either way, fuck it, we checked.
|
|
||||||
// ...but we don't save?
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task 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;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
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 static vassago.Models.Attachment UpsertAttachment(IAttachment dAttachment)
|
|
||||||
{
|
|
||||||
var a = Rememberer.SearchAttachment(ai => ai.ExternalId == dAttachment.Id)
|
|
||||||
?? new vassago.Models.Attachment();
|
|
||||||
|
|
||||||
a.ContentType = dAttachment.ContentType;
|
|
||||||
a.Description = dAttachment.Description;
|
|
||||||
a.Filename = dAttachment.Filename;
|
|
||||||
a.Size = dAttachment.Size;
|
|
||||||
a.Source = new Uri(dAttachment.Url);
|
|
||||||
Rememberer.RememberAttachment(a);
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
internal Message UpsertMessage(IUserMessage dMessage)
|
|
||||||
{
|
|
||||||
var m = Rememberer.SearchMessage(mi => mi.ExternalId == dMessage.Id.ToString() && mi.Protocol == PROTOCOL)
|
|
||||||
?? new()
|
|
||||||
{
|
|
||||||
Protocol = PROTOCOL
|
|
||||||
};
|
|
||||||
|
|
||||||
if (dMessage.Attachments?.Count > 0)
|
|
||||||
{
|
|
||||||
m.Attachments = [];
|
|
||||||
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);
|
|
||||||
Console.WriteLine($"received message; author: {m.Author.DisplayName}, {m.Author.Id}");
|
|
||||||
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); };
|
|
||||||
Rememberer.RememberMessage(m);
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
internal Channel UpsertChannel(IMessageChannel channel)
|
|
||||||
{
|
|
||||||
Channel c = Rememberer.SearchChannel(ci => ci.ExternalId == channel.Id.ToString() && ci.Protocol == PROTOCOL);
|
|
||||||
if (c == null)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"couldn't find channel under protocol {PROTOCOL} with externalId {channel.Id.ToString()}");
|
|
||||||
c = new Channel()
|
|
||||||
{
|
|
||||||
Users = []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ExternalId = channel.Id.ToString();
|
|
||||||
c.ChannelType = (channel is IPrivateChannel) ? vassago.Models.Enumerations.ChannelType.DM : vassago.Models.Enumerations.ChannelType.Normal;
|
|
||||||
c.Messages ??= [];
|
|
||||||
c.Protocol = PROTOCOL;
|
|
||||||
if (channel is IGuildChannel)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"{channel.Name} is a guild channel. So i'm going to upsert the guild, {(channel as IGuildChannel).Guild}");
|
|
||||||
c.ParentChannel = UpsertChannel((channel as IGuildChannel).Guild);
|
|
||||||
}
|
|
||||||
else if (channel is IPrivateChannel)
|
|
||||||
{
|
|
||||||
c.ParentChannel = protocolAsChannel;
|
|
||||||
Console.WriteLine("i'm a private channel so I'm setting my parent channel to the protocol as channel");
|
|
||||||
}
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine($"upsertion of channel {c.DisplayName}, it's type {c.ChannelType}");
|
|
||||||
switch (c.ChannelType)
|
|
||||||
{
|
|
||||||
case vassago.Models.Enumerations.ChannelType.DM:
|
|
||||||
var asPriv =(channel as IPrivateChannel);
|
|
||||||
var sender = asPriv?.Recipients?.FirstOrDefault(u => u.Id != client.CurrentUser.Id); // why yes, there's a list of recipients, and it's the sender.
|
|
||||||
if(sender != null)
|
|
||||||
{
|
|
||||||
c.DisplayName = "DM: " + sender.Username;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//I sent it, so I don't know the recipient's name.
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
c.DisplayName = channel.Name;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Channel parentChannel = null;
|
|
||||||
if (channel is IGuildChannel)
|
|
||||||
{
|
|
||||||
parentChannel = Rememberer.SearchChannel(c => c.ExternalId == (channel as IGuildChannel).Guild.Id.ToString() && c.Protocol == PROTOCOL);
|
|
||||||
if (parentChannel is null)
|
|
||||||
{
|
|
||||||
Console.Error.WriteLine("why am I still null?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (channel is IPrivateChannel)
|
|
||||||
{
|
|
||||||
parentChannel = protocolAsChannel;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parentChannel = protocolAsChannel;
|
|
||||||
Console.Error.WriteLine($"trying to upsert channel {channel.Id}/{channel.Name}, but it's neither guildchannel nor private channel. shrug.jpg");
|
|
||||||
}
|
|
||||||
parentChannel.SubChannels ??= [];
|
|
||||||
if(!parentChannel.SubChannels.Contains(c))
|
|
||||||
{
|
|
||||||
parentChannel.SubChannels.Add(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
c.SendMessage = (t) => { return channel.SendMessageAsync(t); };
|
|
||||||
c.SendFile = (f, t) => { return channel.SendFileAsync(f, t); };
|
|
||||||
|
|
||||||
c = Rememberer.RememberChannel(c);
|
|
||||||
|
|
||||||
//Console.WriteLine($"no one knows how to make good tooling. c.users.first, which needs client currentuser id tostring. c: {c}, c.Users {c.Users}, client: {client}, client.CurrentUser: {client.CurrentUser}, client.currentUser.Id: {client.CurrentUser.Id}");
|
|
||||||
var selfAccountInChannel = c.Users?.FirstOrDefault(a => a.ExternalId == client.CurrentUser.Id.ToString());
|
|
||||||
if(selfAccountInChannel == null)
|
|
||||||
{
|
|
||||||
selfAccountInChannel = UpsertAccount(client.CurrentUser, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
internal Channel UpsertChannel(IGuild channel)
|
|
||||||
{
|
|
||||||
Channel c = Rememberer.SearchChannel(ci => ci.ExternalId == channel.Id.ToString() && ci.Protocol == PROTOCOL);
|
|
||||||
if (c == null)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"couldn't find channel under protocol {PROTOCOL} with externalId {channel.Id.ToString()}");
|
|
||||||
c = new Channel();
|
|
||||||
}
|
|
||||||
|
|
||||||
c.DisplayName = channel.Name;
|
|
||||||
c.ExternalId = channel.Id.ToString();
|
|
||||||
c.ChannelType = vassago.Models.Enumerations.ChannelType.OU;
|
|
||||||
c.Messages ??= [];
|
|
||||||
c.Protocol = protocolAsChannel.Protocol;
|
|
||||||
c.ParentChannel = protocolAsChannel;
|
|
||||||
c.SubChannels ??= [];
|
|
||||||
c.MaxAttachmentBytes = channel.MaxUploadLimit;
|
|
||||||
|
|
||||||
c.SendMessage = (t) => { throw new InvalidOperationException($"channel {channel.Name} is guild; cannot accept text"); };
|
|
||||||
c.SendFile = (f, t) => { throw new InvalidOperationException($"channel {channel.Name} is guild; send file"); };
|
|
||||||
|
|
||||||
return Rememberer.RememberChannel(c);
|
|
||||||
}
|
|
||||||
internal static Account UpsertAccount(IUser discordUser, Channel inChannel)
|
|
||||||
{
|
|
||||||
var acc = Rememberer.SearchAccount(ui => ui.ExternalId == discordUser.Id.ToString() && ui.SeenInChannel.Id == inChannel.Id);
|
|
||||||
Console.WriteLine($"upserting account, retrieved {acc?.Id}.");
|
|
||||||
if (acc != null)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"acc's user: {acc.IsUser?.Id}");
|
|
||||||
}
|
|
||||||
acc ??= new Account() {
|
|
||||||
IsUser = Rememberer.SearchUser(u => u.Accounts.Any(a => a.ExternalId == discordUser.Id.ToString() && a.Protocol == PROTOCOL))
|
|
||||||
?? new User()
|
|
||||||
};
|
|
||||||
|
|
||||||
acc.Username = discordUser.Username;
|
|
||||||
acc.ExternalId = discordUser.Id.ToString();
|
|
||||||
acc.IsBot = discordUser.IsBot || discordUser.IsWebhook;
|
|
||||||
acc.Protocol = PROTOCOL;
|
|
||||||
acc.SeenInChannel = inChannel;
|
|
||||||
|
|
||||||
Console.WriteLine($"we asked rememberer to search for acc's user. {acc.IsUser?.Id}");
|
|
||||||
if (acc.IsUser != null)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"user has record of {acc.IsUser.Accounts?.Count ?? 0} accounts");
|
|
||||||
}
|
|
||||||
acc.IsUser ??= new User() { Accounts = [acc] };
|
|
||||||
if (inChannel.Users?.Count > 0)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"channel has {inChannel.Users.Count} accounts");
|
|
||||||
}
|
|
||||||
Rememberer.RememberAccount(acc);
|
|
||||||
inChannel.Users ??= [];
|
|
||||||
if(!inChannel.Users.Contains(acc))
|
|
||||||
{
|
|
||||||
inChannel.Users.Add(acc);
|
|
||||||
Rememberer.RememberChannel(inChannel);
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Task AttemptReact(IUserMessage msg, string e)
|
|
||||||
{
|
|
||||||
var c = Rememberer.SearchChannel(c => c.ExternalId == msg.Channel.Id.ToString());// db.Channels.FirstOrDefault(c => c.ExternalId == msg.Channel.Id.ToString());
|
|
||||||
//var preferredEmote = c.EmoteOverrides?[e] ?? e; //TODO: emote overrides
|
|
||||||
var preferredEmote = 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,123 +0,0 @@
|
|||||||
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.ProtocolInterfaces.DiscordInterface
|
|
||||||
{
|
|
||||||
public static class SlashCommandsHelper
|
|
||||||
{
|
|
||||||
private static List<CommandSetup> slashCommands = new List<CommandSetup>()
|
|
||||||
{
|
|
||||||
new CommandSetup(){
|
|
||||||
Id = "freedomunits",
|
|
||||||
UpdatedAt = new DateTime(2023, 5, 21, 13, 3, 0),
|
|
||||||
guild = 825293851110801428, //TODO: demagic this magic number
|
|
||||||
register = Register_FreedomUnits
|
|
||||||
}
|
|
||||||
};
|
|
||||||
public static async Task Register(DiscordSocketClient client)
|
|
||||||
{
|
|
||||||
if(Shared.SetupSlashCommands)
|
|
||||||
{
|
|
||||||
var commandsInContext = await client.GetGlobalApplicationCommandsAsync();
|
|
||||||
await Register(client, commandsInContext, null);
|
|
||||||
foreach (var guild in client.Guilds)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await Register(client, await guild.GetApplicationCommandsAsync(), guild);
|
|
||||||
}
|
|
||||||
catch (HttpException ex)
|
|
||||||
{
|
|
||||||
Console.Error.WriteLine($"error registering slash commands for guild {guild.Name} (id {guild.Id}) - {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task Register(DiscordSocketClient client, IEnumerable<SocketApplicationCommand> commandsInContext, SocketGuild guild)
|
|
||||||
{
|
|
||||||
foreach (var existingCommand in commandsInContext)
|
|
||||||
{
|
|
||||||
var myVersion = slashCommands.FirstOrDefault(c => c.Id == existingCommand.Name && c.guild == guild?.Id);
|
|
||||||
if (myVersion == null)
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.WriteLine(existingCommand.CreatedAt);
|
|
||||||
if (myVersion.UpdatedAt > existingCommand.CreatedAt)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"overwriting command {existingCommand.Name}");
|
|
||||||
await myVersion.register(false, client, guild);
|
|
||||||
}
|
|
||||||
myVersion.alreadyRegistered = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (var remaining in slashCommands.Where(sc => sc.alreadyRegistered == false && sc.guild == guild?.Id))
|
|
||||||
{
|
|
||||||
Console.WriteLine($"creating new command {remaining.Id} ({(remaining.guild == null ? "global" : $"for guild {remaining.guild}")})");
|
|
||||||
await remaining.register(true, client, guild);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task Register_FreedomUnits(bool isNew, DiscordSocketClient client, SocketGuild guild)
|
|
||||||
{
|
|
||||||
var builtCommand = new SlashCommandBuilder()
|
|
||||||
.WithName("freedomunits")
|
|
||||||
.WithDescription("convert between misc units (currency: iso 4217 code)")
|
|
||||||
.AddOption("amount", ApplicationCommandOptionType.Number, "source amount", isRequired: true)
|
|
||||||
.AddOption(new SlashCommandOptionBuilder()
|
|
||||||
.WithName("src-unit")
|
|
||||||
.WithDescription("unit converting FROM")
|
|
||||||
.WithRequired(true)
|
|
||||||
.WithType(ApplicationCommandOptionType.String))
|
|
||||||
.AddOption(new SlashCommandOptionBuilder()
|
|
||||||
.WithName("dest-unit")
|
|
||||||
.WithDescription("unit converting TO")
|
|
||||||
.WithRequired(true)
|
|
||||||
.WithType(ApplicationCommandOptionType.String))
|
|
||||||
.Build();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (guild != null)
|
|
||||||
{
|
|
||||||
if (isNew)
|
|
||||||
await guild.CreateApplicationCommandAsync(builtCommand);
|
|
||||||
else
|
|
||||||
await guild.BulkOverwriteApplicationCommandAsync(new ApplicationCommandProperties[] { builtCommand });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (isNew)
|
|
||||||
await client.CreateGlobalApplicationCommandAsync(builtCommand);
|
|
||||||
else
|
|
||||||
await client.BulkOverwriteGlobalApplicationCommandsAsync(new ApplicationCommandProperties[] { builtCommand });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (HttpException exception)
|
|
||||||
{
|
|
||||||
var json = JsonConvert.SerializeObject(exception.Errors, Formatting.Indented);
|
|
||||||
Console.Error.WriteLine(json);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private class CommandSetup
|
|
||||||
{
|
|
||||||
public string Id { get; set; }
|
|
||||||
//the date/time you updated yours IN UTC.
|
|
||||||
public DateTimeOffset UpdatedAt { get; set; }
|
|
||||||
public Registration register { get; set; }
|
|
||||||
public ulong? guild { get; set; }
|
|
||||||
public bool alreadyRegistered {get;set; } = false;
|
|
||||||
|
|
||||||
public delegate Task Registration(bool isNew, DiscordSocketClient client, SocketGuild guild);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
namespace vassago.ProtocolInterfaces;
|
|
||||||
|
|
||||||
public static class ProtocolList
|
|
||||||
{
|
|
||||||
public static List<DiscordInterface.DiscordInterface> discords = new();
|
|
||||||
public static List<TwitchInterface.TwitchInterface> twitchs = new();
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
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;}
|
|
||||||
}
|
|
@ -1,314 +0,0 @@
|
|||||||
using RestSharp;
|
|
||||||
using System.Security.Cryptography.X509Certificates;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using TwitchLib.Api.Helix.Models.Users.GetUsers;
|
|
||||||
using TwitchLib.Api;
|
|
||||||
using TwitchLib.Client.Events;
|
|
||||||
using TwitchLib.Client.Models;
|
|
||||||
using TwitchLib.Client;
|
|
||||||
using TwitchLib.Communication.Clients;
|
|
||||||
using TwitchLib.Communication.Models;
|
|
||||||
using vassago.Behavior;
|
|
||||||
using vassago.Models;
|
|
||||||
|
|
||||||
namespace vassago.TwitchInterface;
|
|
||||||
|
|
||||||
internal class unifiedTwitchMessage
|
|
||||||
{
|
|
||||||
public unifiedTwitchMessage(ChatMessage chatMessage){}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TwitchInterface
|
|
||||||
{
|
|
||||||
internal const string PROTOCOL = "twitch";
|
|
||||||
private static SemaphoreSlim channelSetupSemaphpore = new SemaphoreSlim(1, 1);
|
|
||||||
private Channel protocolAsChannel;
|
|
||||||
private Account selfAccountInProtocol;
|
|
||||||
TwitchClient client;
|
|
||||||
|
|
||||||
private async Task SetupTwitchChannel()
|
|
||||||
{
|
|
||||||
await channelSetupSemaphpore.WaitAsync();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
protocolAsChannel = Rememberer.SearchChannel(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 = []
|
|
||||||
};
|
|
||||||
protocolAsChannel.DisplayName = "twitch (itself)";
|
|
||||||
protocolAsChannel.SendMessage = (t) => { throw new InvalidOperationException($"twitch itself cannot accept text"); };
|
|
||||||
protocolAsChannel.SendFile = (f, t) => { throw new InvalidOperationException($"twitch itself cannot send file"); };
|
|
||||||
protocolAsChannel = Rememberer.RememberChannel(protocolAsChannel);
|
|
||||||
Console.WriteLine($"protocol as channle added; {protocolAsChannel}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.WriteLine($"twitch, channel with id {protocolAsChannel.Id}, already exists");
|
|
||||||
}
|
|
||||||
//protocolAsChan
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
channelSetupSemaphpore.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;
|
|
||||||
|
|
||||||
client.Connect();
|
|
||||||
Console.WriteLine("twitch client 1 connected");
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void Client_OnWhisperReceivedAsync(object sender, OnWhisperReceivedArgs e)
|
|
||||||
{
|
|
||||||
//data received
|
|
||||||
Console.WriteLine($"whisper#{e.WhisperMessage.Username}[{DateTime.Now}][{e.WhisperMessage.DisplayName} [id={e.WhisperMessage.Username}]][msg id: {e.WhisperMessage.MessageId}] {e.WhisperMessage.Message}");
|
|
||||||
|
|
||||||
//translate to internal, upsert
|
|
||||||
var m = UpsertMessage(e.WhisperMessage);
|
|
||||||
m.Reply = (t) => { return Task.Run(() => { client.SendWhisper(e.WhisperMessage.Username, t); }); };
|
|
||||||
m.Channel.ChannelType = vassago.Models.Enumerations.ChannelType.DM;
|
|
||||||
//act on
|
|
||||||
await Behaver.Instance.ActOn(m);
|
|
||||||
m.ActedOn = true;
|
|
||||||
//TODO: remember it again?
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void Client_OnMessageReceivedAsync(object sender, OnMessageReceivedArgs e)
|
|
||||||
{
|
|
||||||
//data eived
|
|
||||||
Console.WriteLine($"#{e.ChatMessage.Channel}[{DateTime.Now}][{e.ChatMessage.DisplayName} [id={e.ChatMessage.Username}]][msg id: {e.ChatMessage.Id}] {e.ChatMessage.Message}");
|
|
||||||
|
|
||||||
//translate to internal, upsert
|
|
||||||
var m = UpsertMessage(e.ChatMessage);
|
|
||||||
m.Reply = (t) => { return Task.Run(() => { client.SendReply(e.ChatMessage.Channel, e.ChatMessage.Id, t); }); };
|
|
||||||
m.Channel.ChannelType = vassago.Models.Enumerations.ChannelType.Normal;
|
|
||||||
//act on
|
|
||||||
await Behaver.Instance.ActOn(m);
|
|
||||||
m.ActedOn = true;
|
|
||||||
//TODO: remember again?
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Client_OnConnected(object sender, OnConnectedArgs e)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"twitch marking selfaccount as seeninchannel {protocolAsChannel.Id}");
|
|
||||||
selfAccountInProtocol = UpsertAccount(e.BotUsername, protocolAsChannel);
|
|
||||||
selfAccountInProtocol.DisplayName = e.BotUsername;
|
|
||||||
Behaver.Instance.MarkSelf(selfAccountInProtocol);
|
|
||||||
|
|
||||||
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, Channel inChannel)
|
|
||||||
{
|
|
||||||
var acc = Rememberer.SearchAccount(ui => ui.ExternalId == username && ui.SeenInChannel.ExternalId == inChannel.ToString());
|
|
||||||
Console.WriteLine($"upserting account, retrieved {acc?.Id}.");
|
|
||||||
if (acc != null)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"acc's usser: {acc.IsUser?.Id}");
|
|
||||||
}
|
|
||||||
acc ??= new Account() {
|
|
||||||
IsUser = Rememberer.SearchUser(
|
|
||||||
u => u.Accounts.Any(a => a.ExternalId == username && a.Protocol == PROTOCOL))
|
|
||||||
?? new vassago.Models.User()
|
|
||||||
};
|
|
||||||
|
|
||||||
acc.Username = username;
|
|
||||||
acc.ExternalId = username;
|
|
||||||
//acc.IsBot = false? there is a way to tell, but you have to go back through the API
|
|
||||||
acc.Protocol = PROTOCOL;
|
|
||||||
acc.SeenInChannel = inChannel;
|
|
||||||
|
|
||||||
Console.WriteLine($"we asked rememberer to search for acc's user. {acc.IsUser?.Id}");
|
|
||||||
if (acc.IsUser != null)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"user has record of {acc.IsUser.Accounts?.Count ?? 0} accounts");
|
|
||||||
}
|
|
||||||
acc.IsUser ??= new vassago.Models.User() { Accounts = [acc] };
|
|
||||||
if (inChannel.Users?.Count > 0)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"channel has {inChannel.Users.Count} accounts");
|
|
||||||
}
|
|
||||||
Rememberer.RememberAccount(acc);
|
|
||||||
inChannel.Users ??= [];
|
|
||||||
if (!inChannel.Users.Contains(acc))
|
|
||||||
{
|
|
||||||
inChannel.Users.Add(acc);
|
|
||||||
Rememberer.RememberChannel(inChannel);
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Channel UpsertChannel(string channelName)
|
|
||||||
{
|
|
||||||
Channel c = Rememberer.SearchChannel(ci => ci.ExternalId == channelName
|
|
||||||
&& ci.Protocol == PROTOCOL);
|
|
||||||
if (c == null)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"couldn't find channel under protocol {PROTOCOL} with externalId {channelName}");
|
|
||||||
c = new Channel()
|
|
||||||
{
|
|
||||||
Users = []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
c.DisplayName = channelName;
|
|
||||||
c.ExternalId = channelName;
|
|
||||||
c.ChannelType = vassago.Models.Enumerations.ChannelType.Normal;
|
|
||||||
c.Messages ??= [];
|
|
||||||
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"); };
|
|
||||||
c = Rememberer.RememberChannel(c);
|
|
||||||
|
|
||||||
var selfAccountInChannel = c.Users?.FirstOrDefault(a => a.ExternalId == selfAccountInProtocol.ExternalId.ToString());
|
|
||||||
if(selfAccountInChannel == null)
|
|
||||||
{
|
|
||||||
selfAccountInChannel = UpsertAccount(selfAccountInProtocol.Username, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
private Channel UpsertDMChannel(string whisperWith)
|
|
||||||
{
|
|
||||||
Channel c = Rememberer.SearchChannel(ci => ci.ExternalId == $"w_{whisperWith}"
|
|
||||||
&& ci.Protocol == PROTOCOL);
|
|
||||||
if (c == null)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"couldn't find channel under protocol {PROTOCOL}, whisper with {whisperWith}");
|
|
||||||
c = new Channel()
|
|
||||||
{
|
|
||||||
Users = []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
c.DisplayName = $"Whisper: {whisperWith}";
|
|
||||||
c.ExternalId = $"w_{whisperWith}";
|
|
||||||
c.ChannelType = vassago.Models.Enumerations.ChannelType.DM;
|
|
||||||
c.Messages ??= [];
|
|
||||||
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"); };
|
|
||||||
c = Rememberer.RememberChannel(c);
|
|
||||||
|
|
||||||
var selfAccountInChannel = c.Users.FirstOrDefault(a => a.ExternalId == selfAccountInProtocol.ExternalId.ToString());
|
|
||||||
if(selfAccountInChannel == null)
|
|
||||||
{
|
|
||||||
selfAccountInChannel = UpsertAccount(selfAccountInChannel.Username, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
//n.b., I see you future adam. "we should unify these, they're redundant".
|
|
||||||
//ah, but that's the trick, they aren't! twitchlib has a common base class, but
|
|
||||||
//none of the features we care about are on it!
|
|
||||||
private Message UpsertMessage(ChatMessage chatMessage)
|
|
||||||
{
|
|
||||||
var m = Rememberer.SearchMessage(mi => mi.ExternalId == chatMessage.Id && mi.Protocol == PROTOCOL)
|
|
||||||
?? new()
|
|
||||||
{
|
|
||||||
Protocol = PROTOCOL,
|
|
||||||
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);
|
|
||||||
m.MentionsMe = Regex.IsMatch(m.Content?.ToLower(), $"@\\b{selfAccountInProtocol.Username.ToLower()}\\b");
|
|
||||||
m.Reply = (t) => { return Task.Run(() => { client.SendReply(chatMessage.Channel, chatMessage.Id, t); }); };
|
|
||||||
m.React = (e) => { throw new InvalidOperationException($"twitch cannot react"); };
|
|
||||||
Rememberer.RememberMessage(m);
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
//n.b., I see you future adam. "we should unify these, they're redundant".
|
|
||||||
//ah, but that's the trick, they aren't! twitchlib has a common base class, but
|
|
||||||
//none of the features we care about are on it!
|
|
||||||
private Message UpsertMessage(WhisperMessage whisperMessage)
|
|
||||||
{
|
|
||||||
//WhisperMessage.Id corresponds to chatMessage.Id. \*eye twitch*
|
|
||||||
var m = Rememberer.SearchMessage(mi => mi.ExternalId == whisperMessage.MessageId && mi.Protocol == PROTOCOL)
|
|
||||||
?? new()
|
|
||||||
{
|
|
||||||
Protocol = PROTOCOL,
|
|
||||||
Timestamp = (DateTimeOffset)DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc)
|
|
||||||
};
|
|
||||||
m.Content = whisperMessage.Message;
|
|
||||||
m.ExternalId = whisperMessage.MessageId;
|
|
||||||
m.Channel = UpsertDMChannel(whisperMessage.Username);
|
|
||||||
m.Author = UpsertAccount(whisperMessage.Username, m.Channel);
|
|
||||||
m.MentionsMe = Regex.IsMatch(m.Content?.ToLower(), $"@\\b{selfAccountInProtocol.Username.ToLower()}\\b");
|
|
||||||
m.Reply = (t) => { return Task.Run(() => { client.SendWhisper(whisperMessage.Username, t); }); };
|
|
||||||
m.React = (e) => { throw new InvalidOperationException($"twitch cannot react"); };
|
|
||||||
Rememberer.RememberMessage(m);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
51
README.md
@ -1,52 +1,7 @@
|
|||||||
# discord-bot
|
# discord-bot
|
||||||
|
|
||||||
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
|
copy appsettings.json and fill it in
|
||||||
|
|
||||||
# auth link
|
# TODO
|
||||||
|
|
||||||
https://discord.com/oauth2/authorize?client_id=913003037348491264&permissions=274877942784&scope=bot
|
listen to kafka, send the message back over it
|
||||||
that's read messages/view channels, send messages, send messages in threads, and attach files. but not add reactions?
|
|
||||||
|
|
||||||
# concepts
|
|
||||||
|
|
||||||
## Data Types
|
|
||||||
|
|
||||||
database diagram. is a fancy term.
|
|
||||||
|
|
||||||
message 1:n attachment
|
|
||||||
user 1:n account
|
|
||||||
channel 1:n account
|
|
||||||
channel 1:n message
|
|
||||||
account 1:n message
|
|
||||||
|
|
||||||
featurepermission n:n ?
|
|
||||||
|
|
||||||
### 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 - as in, leaf-level. If you're in a subchannel, you'll have an appropriate listing there - i.e., you will never have an account in "discord (itself)", you'll have one in the guild text-channels
|
|
||||||
|
|
||||||
### Attachment
|
|
||||||
|
|
||||||
debating whether to save a copy of every single attachment. Discord allows 100MB attachments for turbo users, and shtikbot lives in several art channels. (unfortunately, being that shtikbot doesn't have a viable SMS spam vector, it's limited to 8MB, in contradiction to discord itself reporting a server that doesn't agree to put its own name on discord's finer-grained rules has a limit of 10MB)
|
|
||||||
|
|
||||||
### 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.
|
|
||||||
|
165
Rememberer.cs
@ -1,165 +0,0 @@
|
|||||||
namespace vassago;
|
|
||||||
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using vassago.Models;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
public static class Rememberer
|
|
||||||
{
|
|
||||||
private static readonly SemaphoreSlim dbAccessSemaphore = new(1, 1);
|
|
||||||
private static readonly ChattingContext db = new();
|
|
||||||
|
|
||||||
public static Account SearchAccount(Expression<Func<Account, bool>> predicate)
|
|
||||||
{
|
|
||||||
Account toReturn;
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
toReturn = db.Accounts.Include(a => a.IsUser).FirstOrDefault(predicate);
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
public static List<Account> SearchAccounts(Expression<Func<Account, bool>> predicate)
|
|
||||||
{
|
|
||||||
List<Account> toReturn;
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
toReturn = db.Accounts.Where(predicate).ToList();
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
public static Attachment SearchAttachment(Expression<Func<Attachment, bool>> predicate)
|
|
||||||
{
|
|
||||||
Attachment toReturn;
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
toReturn = db.Attachments.FirstOrDefault(predicate);
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
public static Channel SearchChannel(Expression<Func<Channel, bool>> predicate)
|
|
||||||
{
|
|
||||||
Channel toReturn;
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
toReturn = db.Channels.FirstOrDefault(predicate);
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
public static Message SearchMessage(Expression<Func<Message, bool>> predicate)
|
|
||||||
{
|
|
||||||
Message toReturn;
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
toReturn = db.Messages.FirstOrDefault(predicate);
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
public static User SearchUser(Expression<Func<User, bool>> predicate)
|
|
||||||
{
|
|
||||||
User toReturn;
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
toReturn = db.Users.Where(predicate).Include(u => u.Accounts).FirstOrDefault(predicate);
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
public static void RememberAccount(Account toRemember)
|
|
||||||
{
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
toRemember.IsUser ??= new User { Accounts = [toRemember] };
|
|
||||||
db.Update(toRemember.IsUser);
|
|
||||||
db.SaveChanges();
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
}
|
|
||||||
public static void RememberAttachment(Attachment toRemember)
|
|
||||||
{
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
toRemember.Message ??= new Message() { Attachments = [toRemember] };
|
|
||||||
db.Update(toRemember.Message);
|
|
||||||
db.SaveChanges();
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
}
|
|
||||||
public static Channel RememberChannel(Channel toRemember)
|
|
||||||
{
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
db.Update(toRemember);
|
|
||||||
db.SaveChanges();
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
return toRemember;
|
|
||||||
}
|
|
||||||
public static void RememberMessage(Message toRemember)
|
|
||||||
{
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
toRemember.Channel ??= new() { Messages = [toRemember] };
|
|
||||||
db.Update(toRemember.Channel);
|
|
||||||
db.SaveChanges();
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
}
|
|
||||||
public static void RememberUser(User toRemember)
|
|
||||||
{
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
db.Users.Update(toRemember);
|
|
||||||
db.SaveChanges();
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
}
|
|
||||||
public static void ForgetAccount(Account toForget)
|
|
||||||
{
|
|
||||||
var user = toForget.IsUser;
|
|
||||||
var usersOnlyAccount = user.Accounts?.Count == 1;
|
|
||||||
|
|
||||||
if (usersOnlyAccount)
|
|
||||||
{
|
|
||||||
Rememberer.ForgetUser(user);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
db.Accounts.Remove(toForget);
|
|
||||||
db.SaveChanges();
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static void ForgetChannel(Channel toForget)
|
|
||||||
{
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
db.Channels.Remove(toForget);
|
|
||||||
db.SaveChanges();
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
}
|
|
||||||
public static void ForgetUser(User toForget)
|
|
||||||
{
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
db.Users.Remove(toForget);
|
|
||||||
db.SaveChanges();
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
}
|
|
||||||
public static List<Account> AccountsOverview()
|
|
||||||
{
|
|
||||||
List<Account> toReturn;
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
toReturn = [.. db.Accounts];
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
public static List<Channel> ChannelsOverview()
|
|
||||||
{
|
|
||||||
List<Channel> toReturn;
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
toReturn = [.. db.Channels.Include(u => u.SubChannels).Include(c => c.ParentChannel)];
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
public static Channel ChannelDetail(Guid Id)
|
|
||||||
{
|
|
||||||
Channel toReturn;
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
toReturn = db.Channels.Find(Id);
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
return toReturn;
|
|
||||||
// .Include(u => u.SubChannels)
|
|
||||||
// .Include(u => u.Users)
|
|
||||||
// .Include(u => u.ParentChannel);
|
|
||||||
}
|
|
||||||
public static List<User> UsersOverview()
|
|
||||||
{
|
|
||||||
List<User> toReturn;
|
|
||||||
dbAccessSemaphore.Wait();
|
|
||||||
toReturn = db.Users.ToList();
|
|
||||||
dbAccessSemaphore.Release();
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
}
|
|
14
Shared.cs
@ -1,14 +0,0 @@
|
|||||||
namespace vassago;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Net.Http;
|
|
||||||
using vassago.Models;
|
|
||||||
|
|
||||||
|
|
||||||
public static class Shared
|
|
||||||
{
|
|
||||||
public static Random r = new Random();
|
|
||||||
public static string DBConnectionString { get; set; }
|
|
||||||
public static HttpClient HttpClient { get; internal set; } = new HttpClient();
|
|
||||||
public static bool SetupSlashCommands { get; set; }
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using vassago.Models;
|
|
||||||
using vassago.WebInterface.Models;
|
|
||||||
|
|
||||||
namespace vassago.WebInterface.Controllers;
|
|
||||||
|
|
||||||
public class AccountsController(ChattingContext db) : Controller
|
|
||||||
{
|
|
||||||
private ChattingContext Database => db;
|
|
||||||
|
|
||||||
public async Task<IActionResult> Index()
|
|
||||||
{
|
|
||||||
return Database.Accounts != null ?
|
|
||||||
View(await Database.Accounts.ToListAsync()) :
|
|
||||||
Problem("Entity set '_db.Accounts' is null.");
|
|
||||||
}
|
|
||||||
public async Task<IActionResult> Details(Guid id)
|
|
||||||
{
|
|
||||||
var account = await Database.Accounts
|
|
||||||
.Include(a => a.IsUser)
|
|
||||||
.Include(a => a.SeenInChannel)
|
|
||||||
.FirstAsync(a => a.Id == id);
|
|
||||||
return Database.Accounts != null ?
|
|
||||||
View(account) :
|
|
||||||
Problem("Entity set '_db.Accounts' is null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
|
||||||
public IActionResult Error()
|
|
||||||
{
|
|
||||||
return View(new ErrorPageViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using vassago.Models;
|
|
||||||
using vassago.WebInterface.Models;
|
|
||||||
|
|
||||||
namespace vassago.WebInterface.Controllers;
|
|
||||||
|
|
||||||
public class ChannelsController() : Controller
|
|
||||||
{
|
|
||||||
public IActionResult Details(Guid id)
|
|
||||||
{
|
|
||||||
var allChannels = Rememberer.ChannelsOverview();
|
|
||||||
if(allChannels == 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 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;
|
|
||||||
}
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.Append('[');
|
|
||||||
sb.Append($"{{text: \"{channel.SubChannels?.Count}\", nodes: [");
|
|
||||||
var first=true;
|
|
||||||
foreach(var subChannel in channel.SubChannels)
|
|
||||||
{
|
|
||||||
if(!first)
|
|
||||||
{
|
|
||||||
sb.Append(',');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
sb.Append($"{{\"text\": \"<a href=\\\"{Url.ActionLink(action: "Details", controller: "Channels", values: new {id = subChannel.Id})}\\\">{subChannel.DisplayName}</a>\"}}");
|
|
||||||
}
|
|
||||||
sb.Append("]}]");
|
|
||||||
|
|
||||||
ViewData.Add("channelsTree", sb.ToString());
|
|
||||||
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 });
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,192 +0,0 @@
|
|||||||
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;
|
|
||||||
using vassago.WebInterface.Models;
|
|
||||||
|
|
||||||
namespace vassago.Controllers;
|
|
||||||
|
|
||||||
public class HomeController : Controller
|
|
||||||
{
|
|
||||||
private readonly ILogger<HomeController> _logger;
|
|
||||||
|
|
||||||
public HomeController(ILogger<HomeController> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IActionResult Index()
|
|
||||||
{
|
|
||||||
var allAccounts = Rememberer.AccountsOverview();
|
|
||||||
var allChannels = Rememberer.ChannelsOverview();
|
|
||||||
Console.WriteLine($"accounts: {allAccounts?.Count ?? 0}, channels: {allChannels?.Count ?? 0}");
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.Append('[');
|
|
||||||
sb.Append("{text: \"channels\", expanded:true, nodes: [");
|
|
||||||
|
|
||||||
var first = true;
|
|
||||||
var topLevelChannels = Rememberer.ChannelsOverview().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\", expanded:true, 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\", expanded:true, nodes: [");
|
|
||||||
first = true;
|
|
||||||
foreach (var acc in allAccounts)
|
|
||||||
{
|
|
||||||
if (first)
|
|
||||||
{
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sb.Append(',');
|
|
||||||
}
|
|
||||||
serializeAccount(ref sb, acc);
|
|
||||||
}
|
|
||||||
sb.Append("]}");
|
|
||||||
}
|
|
||||||
var users = Rememberer.UsersOverview();// _db.Users.ToList();
|
|
||||||
if(users.Any())
|
|
||||||
{
|
|
||||||
sb.Append(",{text: \"users\", expanded:true, nodes: [");
|
|
||||||
first=true;
|
|
||||||
//refresh list; we'll be knocking them out again in serializeUser
|
|
||||||
allAccounts = Rememberer.AccountsOverview();
|
|
||||||
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>\"");
|
|
||||||
sb.Append(", expanded:true ");
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (first)
|
|
||||||
{
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sb.Append(',');
|
|
||||||
}
|
|
||||||
serializeChannel(ref sb, ref allChannels, ref allAccounts, subChannel);
|
|
||||||
}
|
|
||||||
if (theseAccounts != null && !first) //"first" here tells us that we have at least one subchannel
|
|
||||||
{
|
|
||||||
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\": \"<a href=\\\"{Url.ActionLink(action: "Details", controller: "Accounts", values: new {id = currentAccount.Id})}\\\">{currentAccount.DisplayName}</a>\"}}");
|
|
||||||
}
|
|
||||||
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})}\\\">");
|
|
||||||
sb.Append(currentUser.DisplayName);
|
|
||||||
sb.Append("</a>\", ");
|
|
||||||
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 });
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using vassago.Models;
|
|
||||||
using vassago.WebInterface.Models;
|
|
||||||
|
|
||||||
namespace vassago.WebInterface.Controllers;
|
|
||||||
|
|
||||||
public class UsersController(ChattingContext db) : Controller
|
|
||||||
{
|
|
||||||
private ChattingContext Database => db;
|
|
||||||
|
|
||||||
public async Task<IActionResult> Index()
|
|
||||||
{
|
|
||||||
return Database.Users != null ?
|
|
||||||
View(await Database.Users.Include(u => u.Accounts).ToListAsync()) :
|
|
||||||
Problem("Entity set '_db.Users' is null.");
|
|
||||||
}
|
|
||||||
public async Task<IActionResult> Details(Guid id)
|
|
||||||
{
|
|
||||||
var user = await Database.Users
|
|
||||||
.Include(u => u.Accounts)
|
|
||||||
.FirstAsync(u => u.Id == id);
|
|
||||||
var allTheChannels = await Database.Channels.ToListAsync();
|
|
||||||
foreach(var acc in user.Accounts)
|
|
||||||
{
|
|
||||||
acc.SeenInChannel = allTheChannels.FirstOrDefault(c => c.Id == acc.SeenInChannel.Id);
|
|
||||||
}
|
|
||||||
return Database.Users != null ?
|
|
||||||
View(user) :
|
|
||||||
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 });
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using vassago.Models;
|
|
||||||
|
|
||||||
namespace vassago.Controllers.api;
|
|
||||||
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
[ApiController]
|
|
||||||
public class ChannelsController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ILogger<ChannelsController> _logger;
|
|
||||||
|
|
||||||
public ChannelsController(ILogger<ChannelsController> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
|
||||||
[Produces("application/json")]
|
|
||||||
public Channel Get(Guid id)
|
|
||||||
{
|
|
||||||
return Rememberer.ChannelDetail(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPatch]
|
|
||||||
[Produces("application/json")]
|
|
||||||
public IActionResult Patch([FromBody] Channel channel)
|
|
||||||
{
|
|
||||||
var fromDb = Rememberer.ChannelDetail(channel.Id);
|
|
||||||
if (fromDb == null)
|
|
||||||
{
|
|
||||||
_logger.LogError($"attempt to update channel {channel.Id}, not found");
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogDebug($"patching {channel.DisplayName} (id: {channel.Id})");
|
|
||||||
}
|
|
||||||
//settable values: lewdness filter level, meanness filter level. maybe i could decorate them...
|
|
||||||
fromDb.LewdnessFilterLevel = channel.LewdnessFilterLevel;
|
|
||||||
fromDb.MeannessFilterLevel = channel.MeannessFilterLevel;
|
|
||||||
Rememberer.RememberChannel(fromDb);
|
|
||||||
return Ok(fromDb);
|
|
||||||
}
|
|
||||||
[HttpDelete]
|
|
||||||
[Produces("application/json")]
|
|
||||||
public IActionResult Delete([FromBody] Channel channel)
|
|
||||||
{
|
|
||||||
var fromDb = Rememberer.ChannelDetail(channel.Id);
|
|
||||||
if (fromDb == null)
|
|
||||||
{
|
|
||||||
_logger.LogError($"attempt to delete channel {channel.Id}, not found");
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
deleteChannel(fromDb);
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
private void deleteChannel(Channel channel)
|
|
||||||
{
|
|
||||||
if (channel.SubChannels?.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var childChannel in channel.SubChannels)
|
|
||||||
{
|
|
||||||
deleteChannel(childChannel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(channel.Users?.Count > 0)
|
|
||||||
{
|
|
||||||
foreach(var account in channel.Users)
|
|
||||||
{
|
|
||||||
deleteAccount(account);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rememberer.ForgetChannel(channel);
|
|
||||||
}
|
|
||||||
private void deleteAccount(Account account)
|
|
||||||
{
|
|
||||||
var user = account.IsUser;
|
|
||||||
var usersOnlyAccount = user.Accounts?.Count == 1;
|
|
||||||
|
|
||||||
Rememberer.ForgetAccount(account);
|
|
||||||
|
|
||||||
if(usersOnlyAccount)
|
|
||||||
Rememberer.ForgetUser(user);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using vassago.Models;
|
|
||||||
using vassago.ProtocolInterfaces.DiscordInterface;
|
|
||||||
|
|
||||||
namespace vassago.Controllers.api;
|
|
||||||
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
[ApiController]
|
|
||||||
public class UsersController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ILogger<ChannelsController> _logger;
|
|
||||||
|
|
||||||
public UsersController(ILogger<ChannelsController> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPatch]
|
|
||||||
[Produces("application/json")]
|
|
||||||
public IActionResult Patch([FromBody] User user)
|
|
||||||
{
|
|
||||||
var fromDb = Rememberer.SearchUser(u => u.Id == user.Id);
|
|
||||||
if (fromDb == null)
|
|
||||||
{
|
|
||||||
_logger.LogError($"attempt to update user {user.Id}, not found");
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogDebug($"patching {user.DisplayName} (id: {user.Id})");
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: settable values: display name
|
|
||||||
//fromDb.DisplayName = user.DisplayName;
|
|
||||||
Rememberer.RememberUser(fromDb);
|
|
||||||
return Ok(fromDb);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
namespace vassago.WebInterface.Models;
|
|
||||||
|
|
||||||
public class ErrorPageViewModel
|
|
||||||
{
|
|
||||||
public string RequestId { get; set; }
|
|
||||||
|
|
||||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
@model Account
|
|
||||||
@using Newtonsoft.Json
|
|
||||||
@using System.Text
|
|
||||||
@{
|
|
||||||
ViewData["Title"] = "Account details";
|
|
||||||
}
|
|
||||||
|
|
||||||
<a href="/">home</a>/@Html.Raw(ViewData["breadcrumbs"])
|
|
||||||
<table class="table">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">belongs to user</th>
|
|
||||||
<td>@Model.IsUser.DisplayName</td>
|
|
||||||
<td><button alt="to do" disabled>separate</button></2td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Seen in channel</th>
|
|
||||||
<td class="account @Model.SeenInChannel.Protocol"><div class="protocol-icon"> </div>@Model.SeenInChannel.LineageSummary<a href="/Channels/Details/@Model.SeenInChannel.Id">@Model.SeenInChannel.DisplayName</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Permission Tags</th>
|
|
||||||
<td>
|
|
||||||
<div id="tagsTree"></div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
@section Scripts{
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
@{
|
|
||||||
var accountAsString = JsonConvert.SerializeObject(Model, new JsonSerializerSettings
|
|
||||||
{
|
|
||||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const userOnLoad = @Html.Raw(accountAsString);
|
|
||||||
function jsonifyUser() {
|
|
||||||
var userNow = structuredClone(userOnLoad);
|
|
||||||
userNow.Accounts = null;
|
|
||||||
userNow.DisplayName = document.querySelector("#displayName").value;
|
|
||||||
console.log(userNow);
|
|
||||||
return userNow;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTagsTree() {
|
|
||||||
@{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.Append("[{text: \"permission tags\", \"expanded\":true, nodes: [");
|
|
||||||
var first = true;
|
|
||||||
for (int i = 0; i < 1; i++)
|
|
||||||
{
|
|
||||||
if (!first)
|
|
||||||
sb.Append(',');
|
|
||||||
sb.Append($"{{text: \"<input type=\\\"checkbox\\\" > is goated (w/ sauce)</input>\"}}");
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
sb.Append("]}]");
|
|
||||||
}
|
|
||||||
console.log(@Html.Raw(sb.ToString()));
|
|
||||||
var tree = @Html.Raw(sb.ToString());
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
$('#tagsTree').bstreeview({ data: getTagsTree() });
|
|
||||||
document.querySelectorAll("input[type=checkbox]").forEach(node => { node.onchange = () => { patchModel(jsonifyUser(), '/api/Users/') } });
|
|
||||||
</script>
|
|
||||||
}
|
|
@ -1,169 +0,0 @@
|
|||||||
@using System.ComponentModel
|
|
||||||
@using Newtonsoft.Json
|
|
||||||
@using System.Text;
|
|
||||||
@model Tuple<Channel, Enumerations.LewdnessFilterLevel, Enumerations.MeannessFilterLevel>
|
|
||||||
@{
|
|
||||||
var ThisChannel = Model.Item1;
|
|
||||||
var IfInheritedLewdnessFilterLevel = Model.Item2;
|
|
||||||
var IfInheritedMeannessFilterLevel = Model.Item3;
|
|
||||||
}
|
|
||||||
|
|
||||||
<a href="/">home</a>/
|
|
||||||
@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>@(Enumerations.GetDescription(ThisChannel.ChannelType))</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Lewdness Filter Level</th>
|
|
||||||
<td>
|
|
||||||
<select name="LewdnessFilterLevel" id="LewdnessFilterLevel" onchange="patchModel(jsonifyChannel(), '/api/Channels/')">
|
|
||||||
<!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(), '/api/Channels/')">
|
|
||||||
<!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>
|
|
||||||
@if((ThisChannel.SubChannels?.Count ?? 0) > 0)
|
|
||||||
{
|
|
||||||
@Html.Raw("<div id=\"channelsTree\"></div>");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@Html.Raw("0")
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Accounts</th>
|
|
||||||
<td>
|
|
||||||
@if((ThisChannel.Users?.Count ?? 0) > 0)
|
|
||||||
{
|
|
||||||
@Html.Raw("<div id=\"accountsTree\"></div>");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@Html.Raw("none")
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td colspan="2">
|
|
||||||
<button onclick="forget()">forget</button>
|
|
||||||
</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;
|
|
||||||
}
|
|
||||||
function forget(){
|
|
||||||
console.log("here we go");
|
|
||||||
if(window.confirm("delete? really really?") == true){
|
|
||||||
deleteModel(jsonifyChannel(), '/api/Channels/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function channelsTree() {
|
|
||||||
var tree = @Html.Raw(ViewData["channelsTree"]);
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
function accountsTree() {
|
|
||||||
@{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.Append("[{text: \"accounts\", \"expanded\":true, nodes: [");
|
|
||||||
var first = true;
|
|
||||||
foreach (var acc in ThisChannel.Users.OrderBy(a => a.SeenInChannel.LineageSummary))
|
|
||||||
{
|
|
||||||
if(!first)
|
|
||||||
sb.Append(',');
|
|
||||||
sb.Append($"{{text: \"<div class=\\\"account {acc.Protocol}\\\"><div class=\\\"protocol-icon\\\"> </div>{acc.SeenInChannel.LineageSummary}/<a href=\\\"/Accounts/Details/{acc.Id}\\\">{acc.DisplayName}</a>\"}}");
|
|
||||||
first=false;
|
|
||||||
}
|
|
||||||
sb.Append("]}]");
|
|
||||||
}
|
|
||||||
//console.log(@Html.Raw(sb.ToString()));
|
|
||||||
var tree = @Html.Raw(sb.ToString());
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
$('#channelsTree').bstreeview({ data: channelsTree() });
|
|
||||||
$('#accountsTree').bstreeview({ data: accountsTree() });
|
|
||||||
|
|
||||||
</script>
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
@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>
|
|
@ -1,16 +0,0 @@
|
|||||||
@{
|
|
||||||
ViewData["Title"] = "Home Page";
|
|
||||||
}
|
|
||||||
<div id="tree">tree here</div>
|
|
||||||
|
|
||||||
@section Scripts{
|
|
||||||
<script type="text/javascript">
|
|
||||||
function getTree() {
|
|
||||||
var tree = @Html.Raw(ViewData["treeString"]);
|
|
||||||
console.log(tree);
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#tree').bstreeview({ data: getTree() });
|
|
||||||
</script>
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
@model vassago.WebInterface.Models.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>
|
|
@ -1,25 +0,0 @@
|
|||||||
<!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>
|
|
@ -1,48 +0,0 @@
|
|||||||
/* 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;
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
|
|
||||||
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
|
|
@ -1,90 +0,0 @@
|
|||||||
@model User
|
|
||||||
@using Newtonsoft.Json
|
|
||||||
@using System.Text
|
|
||||||
@{
|
|
||||||
ViewData["Title"] = "User details";
|
|
||||||
}
|
|
||||||
|
|
||||||
<a href="/">home</a>/@Html.Raw(ViewData["breadcrumbs"])
|
|
||||||
<table class="table">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Display Name (here)</th>
|
|
||||||
<td><input type="text" id="displayName" value="@Model.DisplayName" disabled alt="todo"></input> <button
|
|
||||||
onclick="patchModel(jsonifyUser(), @Html.Raw("'/api/Users/'"))" disabled alt"todo">update</button></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Accounts</th>
|
|
||||||
<td>
|
|
||||||
<div id="accountsTree"></div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Permission Tags</th>
|
|
||||||
<td>
|
|
||||||
<div id="tagsTree"></div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
@section Scripts{
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
@{
|
|
||||||
var userAsString = JsonConvert.SerializeObject(Model, new JsonSerializerSettings
|
|
||||||
{
|
|
||||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const userOnLoad = @Html.Raw(userAsString);
|
|
||||||
function jsonifyUser() {
|
|
||||||
var userNow = structuredClone(userOnLoad);
|
|
||||||
userNow.Accounts = null;
|
|
||||||
userNow.DisplayName = document.querySelector("#displayName").value;
|
|
||||||
//userNow.Tag_CanTwitchSummon = document.querySelector("#tagCanTwitchSummon").checked;
|
|
||||||
console.log(userNow);
|
|
||||||
return userNow;
|
|
||||||
}
|
|
||||||
function getAccountsTree() {
|
|
||||||
@{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.Append("[{text: \"accounts\", \"expanded\":true, nodes: [");
|
|
||||||
var first = true;
|
|
||||||
foreach (var acc in Model.Accounts.OrderBy(a => a.SeenInChannel.LineageSummary))
|
|
||||||
{
|
|
||||||
if (!first)
|
|
||||||
sb.Append(',');
|
|
||||||
sb.Append($"{{text: \"<div class=\\\"account {acc.Protocol}\\\"><div class=\\\"protocol-icon\\\"> </div>{acc.SeenInChannel.LineageSummary}/<a href=\\\"/Accounts/Details/{acc.Id}\\\">{acc.DisplayName}</a>\"}}");
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
sb.Append("]}]");
|
|
||||||
}
|
|
||||||
console.log(@Html.Raw(sb.ToString()));
|
|
||||||
var tree = @Html.Raw(sb.ToString());
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTagsTree() {
|
|
||||||
@{
|
|
||||||
sb = new StringBuilder();
|
|
||||||
sb.Append("[{text: \"permission tags\", \"expanded\":true, nodes: [");
|
|
||||||
first = true;
|
|
||||||
for (int i = 0; i < 1; i++)
|
|
||||||
{
|
|
||||||
if (!first)
|
|
||||||
sb.Append(',');
|
|
||||||
sb.Append($"{{text: \"<input type=\\\"checkbox\\\" > is goated (w/ sauce)</input>\"}}");
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
sb.Append("]}]");
|
|
||||||
}
|
|
||||||
console.log(@Html.Raw(sb.ToString()));
|
|
||||||
var tree = @Html.Raw(sb.ToString());
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
$('#accountsTree').bstreeview({ data: getAccountsTree() });
|
|
||||||
$('#tagsTree').bstreeview({ data: getTagsTree() });
|
|
||||||
document.querySelectorAll("input[type=checkbox]").forEach(node => { node.onchange = () => { patchModel(jsonifyUser(), '/api/Users/') } });
|
|
||||||
</script>
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
@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>
|
|
@ -1,3 +0,0 @@
|
|||||||
@using vassago
|
|
||||||
@using vassago.Models
|
|
||||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
|
@ -1,3 +0,0 @@
|
|||||||
@{
|
|
||||||
Layout = "_Layout";
|
|
||||||
}
|
|
5
appsettings.example.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"token": "59 chars",
|
||||||
|
"botChatterChannel": 0,
|
||||||
|
"announcementChannel": 0
|
||||||
|
}
|
@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning",
|
|
||||||
"Microsoft.EntityFrameworkCore": "None"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowedHosts": "*",
|
|
||||||
"DiscordTokens": [
|
|
||||||
|
|
||||||
],
|
|
||||||
"TwitchConfigs": [
|
|
||||||
],
|
|
||||||
"exchangePairsLocation": "assets/exchangepairs.json",
|
|
||||||
"DBConnectionString": "Host=azure.club;Database=db;Username=user;Password=password",
|
|
||||||
"SetupSlashCommands": false
|
|
||||||
}
|
|
Before Width: | Height: | Size: 293 KiB |
Before Width: | Height: | Size: 107 KiB |
@ -1,307 +0,0 @@
|
|||||||
{
|
|
||||||
"units":[
|
|
||||||
{
|
|
||||||
"canonical": "℉",
|
|
||||||
"aliases": [
|
|
||||||
"degrees f",
|
|
||||||
"deg f",
|
|
||||||
"degf",
|
|
||||||
"fahrenheit",
|
|
||||||
"deg fahrenheit",
|
|
||||||
"degrees fahrenheit",
|
|
||||||
"°f",
|
|
||||||
"° f",
|
|
||||||
"℉",
|
|
||||||
"f"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"°C",
|
|
||||||
"aliases": [
|
|
||||||
"degrees c",
|
|
||||||
"deg c",
|
|
||||||
"degc",
|
|
||||||
"celsius",
|
|
||||||
"deg celsiu",
|
|
||||||
"degrees celsiu",
|
|
||||||
"°c",
|
|
||||||
"° c",
|
|
||||||
"c"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"m",
|
|
||||||
"aliases": [
|
|
||||||
"meter",
|
|
||||||
"metre"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"mm",
|
|
||||||
"aliases": [
|
|
||||||
"millimeter",
|
|
||||||
"millimetre"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"km",
|
|
||||||
"aliases": [
|
|
||||||
"kilometer",
|
|
||||||
"kilometre"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"kg",
|
|
||||||
"aliases": [
|
|
||||||
"kilogram",
|
|
||||||
"kilo"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"g",
|
|
||||||
"aliases": [
|
|
||||||
"gram"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"lb",
|
|
||||||
"aliases": [
|
|
||||||
"pound"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"oz",
|
|
||||||
"aliases": [
|
|
||||||
"ounce"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"floz",
|
|
||||||
"aliases": [
|
|
||||||
"us fl oz",
|
|
||||||
"us fl ounce",
|
|
||||||
"us fluid ounce",
|
|
||||||
"us fluid oz"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"mL",
|
|
||||||
"aliases": [
|
|
||||||
"ml",
|
|
||||||
"milliletre",
|
|
||||||
"millileter"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"ft",
|
|
||||||
"aliases": [
|
|
||||||
"'",
|
|
||||||
"feet",
|
|
||||||
"foot"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"in",
|
|
||||||
"aliases": [
|
|
||||||
"\"",
|
|
||||||
"inch"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"yd",
|
|
||||||
"aliases": [
|
|
||||||
"yard"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"hhd",
|
|
||||||
"aliases": [
|
|
||||||
"hogshead"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"gal",
|
|
||||||
"aliases": [
|
|
||||||
"gallon"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"tbsp",
|
|
||||||
"aliases": [
|
|
||||||
"tablespoon",
|
|
||||||
"table spoon"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"tsp",
|
|
||||||
"aliases": [
|
|
||||||
"teaspoon",
|
|
||||||
"tea spoon"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"qt",
|
|
||||||
"aliases": [
|
|
||||||
"quart"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"ac",
|
|
||||||
"aliases": [
|
|
||||||
"acres"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"AU",
|
|
||||||
"aliases": [
|
|
||||||
"au",
|
|
||||||
"astronomical unit"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"Pa",
|
|
||||||
"aliases": [
|
|
||||||
"pascal",
|
|
||||||
"pa"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"kPa",
|
|
||||||
"aliases": [
|
|
||||||
"kilopascal",
|
|
||||||
"kpa"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"atm",
|
|
||||||
"aliases": [
|
|
||||||
"atmosphere"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"m^2",
|
|
||||||
"aliases": [
|
|
||||||
"square meter",
|
|
||||||
"meter squared",
|
|
||||||
"meters squared",
|
|
||||||
"sq meter",
|
|
||||||
"sq m",
|
|
||||||
"sqm"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"km^2",
|
|
||||||
"aliases": [
|
|
||||||
"square kilometer",
|
|
||||||
"kilometer squared",
|
|
||||||
"kilometers squared",
|
|
||||||
"sq kilometer",
|
|
||||||
"sq km",
|
|
||||||
"sqkm"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"ly",
|
|
||||||
"aliases": [
|
|
||||||
"light year"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"pc",
|
|
||||||
"aliases": [
|
|
||||||
"parsec"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"mi",
|
|
||||||
"aliases": [
|
|
||||||
"mile"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"blue whale length",
|
|
||||||
"aliases": [
|
|
||||||
"bwl",
|
|
||||||
"whales"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"ångström",
|
|
||||||
"aliases": [
|
|
||||||
"angstrom",
|
|
||||||
"Å"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"μm",
|
|
||||||
"aliases": [
|
|
||||||
"micrometers",
|
|
||||||
"micrometres",
|
|
||||||
"microns"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"canonical":"uncle jordan",
|
|
||||||
"aliases":[
|
|
||||||
"uj"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"linearPairs":[
|
|
||||||
{"item1":"kg", "item2":"g", "factor":1000},
|
|
||||||
{"item1":"lb", "item2":"oz", "factor":16},
|
|
||||||
{"item1":"kg", "item2":"lb", "factor":2.204623},
|
|
||||||
{"item1":"kg", "item2":"stone", "factor":0.157473},
|
|
||||||
|
|
||||||
{"item1":"km", "item2":"m", "factor":1000},
|
|
||||||
{"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},
|
|
||||||
{"item1":"rod", "item2":"ft", "factor":16.5},
|
|
||||||
{"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":"uncle jordan", "item2": "cm", "factor":192.405},
|
|
||||||
|
|
||||||
{"item1":"floz", "item2":"mL", "factor":29.57344},
|
|
||||||
{"item1":"L", "item2":"mL", "factor":1000},
|
|
||||||
{"item1":"L", "item2":"floz", "factor":33.81402},
|
|
||||||
{"item1":"hhd", "item2":"gal", "factor":54},
|
|
||||||
{"item1":"barrel", "item2":"kilderkin", "factor":2},
|
|
||||||
{"item1":"barrel", "item2":"firkin", "factor":4},
|
|
||||||
{"item1":"firkin", "item2":"gal", "factor":10.8},
|
|
||||||
{"item1":"pint", "item2":"floz", "factor":16},
|
|
||||||
{"item1":"cup", "item2":"floz", "factor":8},
|
|
||||||
{"item1":"gill", "item2":"floz", "factor":4},
|
|
||||||
{"item1":"tbsp", "item2":"tsp", "factor":3},
|
|
||||||
{"item1":"tbsp", "item2":"floz", "factor":0.5},
|
|
||||||
{"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},
|
|
||||||
{"item1":"atm", "item2":"Pa", "factor":101325},
|
|
||||||
{"item1":"bar", "item2":"psi", "factor":14.5038}
|
|
||||||
]
|
|
||||||
}
|
|
Before Width: | Height: | Size: 16 KiB |
@ -1,78 +0,0 @@
|
|||||||
I got a joke for you: wealth trickles down.
|
|
||||||
Why did the celebrity egg start losing her friends? They called her a shell-out.
|
|
||||||
What's the difference between a hippo and a zippo? One is really heavy and the other is a little lighter.
|
|
||||||
The best time on a watch is 6:30, hands down. (ask your parents, young ones)
|
|
||||||
What killed the painter? He had too many strokes
|
|
||||||
Artists know how to draw the line, so you can’t really peer pressure them.
|
|
||||||
Why did the hand cross the road? To get to the secondhand store.
|
|
||||||
Why do seagulls fly over the ocean? Because if they flew over the bay, we'd call them bagels.
|
|
||||||
Why don't oysters donate to charity? Because they're shellfish
|
|
||||||
I only know 25 letters of the alphabet. I don't know y.
|
|
||||||
What did the fish say when it ran into a wall? Dam.
|
|
||||||
What do you call a factory that makes okay products? A satisfactory.
|
|
||||||
What do you call a fly without wings? A walk.
|
|
||||||
Don't trust those trees. They seem kind of shady.
|
|
||||||
I don't trust stairs. They're up to something.
|
|
||||||
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.
|
|
||||||
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.
|
|
||||||
Don’t you hate it when someone answers their own questions? I do.
|
|
||||||
It takes a lot of balls to golf the way I do.
|
|
||||||
The problem with kleptomaniacs is that they always take things literally.
|
|
||||||
Can you believe I got fired from the calendar factory? All I did was take a day off.
|
|
||||||
Most people are shocked when they find out how bad I am as an electrician.
|
|
||||||
I was addicted to the hokey pokey, but then I turned myself around.
|
|
||||||
A termite walks into the bar and asks; is the bartender here?
|
|
||||||
Just burned 2,000 calories. That’s the last time I leave brownies in the oven while I nap.
|
|
||||||
A recent study has found that women who carry a little extra weight live longer than the men who mention it.
|
|
||||||
I got a new pair of gloves today, but they’re both lefts, which on the one hand is great, but on the other, it’s just not right.
|
|
||||||
I can tell when people are being judgmental just by looking at them.
|
|
||||||
Are people born with photographic memories? or does it take time to develop (ask your parents, young ones)
|
|
||||||
I buy all my guns from a guy called T-Rex. He’s a small arms dealer.
|
|
||||||
A book fell on my head the other day. I only have my shelf to blame though.
|
|
||||||
If you don’t pay your exorcist, do you get repossessed?
|
|
||||||
A ghost walked into a bar and ordered a shot of vodka. The bartender said, ‘Sorry, we don’t serve spirits here.’
|
|
||||||
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!”
|
|
||||||
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.
|
|
||||||
The problem with troubleshooting is that trouble shoots back.
|
|
||||||
Today a man knocked on my door and asked for a small donation towards the local swimming pool. I gave him a glass of water.
|
|
||||||
Apparently I snore so loudly that it scares everyone in the car I'm driving.
|
|
||||||
I think my neighbor is stalking me. she's been googling my name on her computer. I saw it through my telescope last night.
|
|
||||||
I wasn't originally going to get a brain transplant, but then I changed my mind.
|
|
||||||
I just found out I'm colorblind. The diagnosis came completely out of the purple.
|
|
||||||
My girlfriend told me she was leaving me because I keep pretending to be a Transformer. I said, "No, wait! I can change."
|
|
||||||
I started out with nothing, and I still have most of it.
|
|
||||||
eBay is so useless. I tried to look up lighters and all they had was 13,749 matches.
|
|
||||||
About a month before he died, my uncle had his back covered in lard. After that, he went down hill fast.
|
|
||||||
I was addicted to the hokey pokey... but thankfully, I turned myself around.
|
|
||||||
I'm glad I know sign language, it's pretty handy.
|
|
||||||
What did Cinderella say when she got to the ball? "ggggh!"
|
|
||||||
R.I.P boiled water. You will be mist.
|
|
||||||
To the mathematicians who thought of the idea of zero, thanks for nothing!
|
|
||||||
I hate people who use big words just to make themselves look perspicacious.
|
|
||||||
Two wrongs don't make a right, take your parents as an example.
|
|
||||||
People used to laugh at me when I would say "I want to be a comedian", but nobody's laughing now.
|
|
||||||
I threw a ball for my dog... It's a bit extravagant I know, but it was his birthday and he looks great in a dinner jacket.
|
|
||||||
I refused to believe my road worker father was stealing from his job, but when I got home, all the signs were there.
|
|
||||||
Did you hear about the kidnapping at school? It's okay. He woke up.
|
|
||||||
Pavlov walks into a bar. The phone rings, and he says, "Damn, I forgot to feed the dog." (ask your parents, young ones.)
|
|
||||||
Cleaning mirrors is a job I could really see myself doing.
|
|
||||||
What's the difference between a poorly dressed man on a bicycle and a nicely dressed man on a tricycle? Attire.
|
|
||||||
When does a pun become a dad joke? When the punchline becomes apparent.
|
|
||||||
There's 10 kinds of people in the world. Those who think in decimal, those who think in binary, and those who knew this joke would be in base 3.
|
|
||||||
There's 2 kinds of people in the world. Those who divide the entire human population into 2 arbitrary groups, and those who don't.
|
|
||||||
A horse walks into a bar. the bartender says "hey man, you're in here kind of a lot. do you ever think you might be an alcoholic?" the horse says "no" and promptly vanishes. (the joke is a reference the famous philosophical phrase "i think, therefore i am" but if i explained that before the rest of the joke that would be putting descartes before the horse)
|
|
||||||
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.
|
|
Before Width: | Height: | Size: 261 KiB |
36
devuitls.sh
@ -1,36 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
servicename="vassago"
|
|
||||||
pw_developmentdatabase="wnmhOttjA0wCiR9hVoG7jjrf90SxWvAV"
|
|
||||||
connnectionstr="Host=localhost;Database=${servicename}_dev;Username=${servicename};Password=${pw_developmentdatabase};IncludeErrorDetail=true;"
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
"initial")
|
|
||||||
sudo -u postgres psql -c "create database ${servicename}_dev;"
|
|
||||||
sudo -u postgres psql -c "create user $servicename with encrypted password '$pw_developmentdatabase';"
|
|
||||||
sudo -u postgres psql -c "grant all privileges on database ${servicename}_dev to $servicename;"
|
|
||||||
sudo -u postgres psql -d "${servicename}_dev" -c "GRANT ALL ON SCHEMA public TO $servicename"
|
|
||||||
|
|
||||||
cp appsettings.sample.json appsettings.json
|
|
||||||
dotnet ef database update --connection "$connnectionstr"
|
|
||||||
;;
|
|
||||||
|
|
||||||
"add-migration")
|
|
||||||
dotnet ef migrations add "$2"
|
|
||||||
dotnet ef database update --connection "$connnectionstr"
|
|
||||||
;;
|
|
||||||
|
|
||||||
"dbupdate")
|
|
||||||
dotnet ef database update --connection "$connnectionstr"
|
|
||||||
;;
|
|
||||||
|
|
||||||
"db-fullreset")
|
|
||||||
sudo -u postgres psql -c "drop database ${servicename}_dev;"
|
|
||||||
sudo -u postgres psql -c "drop user $servicename"
|
|
||||||
$0 "initial"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unknown command '$1', try 'initial'"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace vassago
|
|
||||||
{
|
|
||||||
public class ExternalProcess
|
|
||||||
{
|
|
||||||
public static bool GoPlz(string commandPath, string commandArguments)
|
|
||||||
{
|
|
||||||
var process = readableProcess(commandPath, commandArguments);
|
|
||||||
var outputData = new StringBuilder();
|
|
||||||
process.OutputDataReceived += new DataReceivedEventHandler((s, e) =>
|
|
||||||
{
|
|
||||||
outputData.Append(e.Data);
|
|
||||||
});
|
|
||||||
var errorData = new StringBuilder();
|
|
||||||
process.ErrorDataReceived += new DataReceivedEventHandler((s, e) =>
|
|
||||||
{
|
|
||||||
errorData.Append(e.Data);
|
|
||||||
});
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
process.Start();
|
|
||||||
process.BeginErrorReadLine();
|
|
||||||
process.BeginOutputReadLine();
|
|
||||||
process.WaitForExit();
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
var dumpDir = $"fail{DateTime.Now.ToFileTimeUtc()}";
|
|
||||||
var outputFilename = $"{dumpDir}/output0.log";
|
|
||||||
var errorFilename = $"{dumpDir}/error0.err";
|
|
||||||
if(!Directory.Exists(dumpDir))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(dumpDir);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var i = 0;
|
|
||||||
foreach(var file in Directory.GetFiles(dumpDir))
|
|
||||||
{
|
|
||||||
var thisNummatch = Regex.Matches(Path.GetFileNameWithoutExtension(file), "[^\\d](\\d+)\\.err$").LastOrDefault().Value;
|
|
||||||
if(!string.IsNullOrWhiteSpace(thisNummatch))
|
|
||||||
{
|
|
||||||
var thisNumval = 0;
|
|
||||||
if(int.TryParse(thisNummatch, out thisNumval) && thisNumval > i)
|
|
||||||
{
|
|
||||||
i = thisNumval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outputFilename = $"{dumpDir}/output{i}.log";
|
|
||||||
errorFilename = $"{dumpDir}/error{i}.err";
|
|
||||||
}
|
|
||||||
File.WriteAllText(outputFilename, outputData.ToString());
|
|
||||||
File.WriteAllText(errorFilename, JsonConvert.SerializeObject(e, Formatting.Indented));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
private static Process readableProcess(string commandPath, string commandArguments)
|
|
||||||
{
|
|
||||||
var pi = new ProcessStartInfo(commandPath, commandArguments);
|
|
||||||
pi.UseShellExecute = false;
|
|
||||||
pi.CreateNoWindow = true;
|
|
||||||
pi.RedirectStandardError = true;
|
|
||||||
pi.RedirectStandardOutput = true;
|
|
||||||
var process = new Process();
|
|
||||||
process.StartInfo = pi;
|
|
||||||
return process;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
21
silverworker-discord.csproj
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
<RootNamespace>silverworker_discord</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="discord.net" Version="2.4.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" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="AppSettings.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
@ -1,51 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.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="112.1.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
@ -1,10 +0,0 @@
|
|||||||
/*
|
|
||||||
@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
@ -1,46 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 8.2 KiB |
10
wwwroot/js/bstreeview.min.js
vendored
@ -1,10 +0,0 @@
|
|||||||
/*
|
|
||||||
@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);
|
|