diff --git a/Behavior/Behavior.cs b/Behavior/Behavior.cs index 82949e0..4c77304 100644 --- a/Behavior/Behavior.cs +++ b/Behavior/Behavior.cs @@ -24,5 +24,8 @@ public abstract class Behavior public virtual string Description => Name; } - +/// +///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. +/// public class StaticPlzAttribute : Attribute {} \ No newline at end of file diff --git a/Behavior/TwitchSummon.cs b/Behavior/TwitchSummon.cs new file mode 100644 index 0000000..b1a0900 --- /dev/null +++ b/Behavior/TwitchSummon.cs @@ -0,0 +1,30 @@ +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"; + + //TODO: Permission! + + public override async Task 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; + } +} diff --git a/Behavior/TwitchUnsummon.cs b/Behavior/TwitchUnsummon.cs new file mode 100644 index 0000000..c123763 --- /dev/null +++ b/Behavior/TwitchUnsummon.cs @@ -0,0 +1,39 @@ +namespace vassago.Behavior; + +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using vassago.Models; + +[StaticPlz] +public class TwitchDismiss : Behavior +{ + public override string Name => "Twitch Dismiss"; + + public override string Trigger => "begone, @[me]"; + + public override bool ShouldAct(Message message) + { + if(message.MentionsMe && + (Regex.IsMatch(message.Content.ToLower(), "\\bbegone\\b") || Regex.IsMatch(message.Content.ToLower(), "\\bfuck off\\b"))) + { + //TODO: PERMISSION! + return true; + } + return false; + } + + public override async Task 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; + } +} diff --git a/Configuration.cs b/Configuration.cs index 90b4eff..b34253c 100644 --- a/Configuration.cs +++ b/Configuration.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using Newtonsoft.Json; +using vassago.TwitchInterface; namespace vassago { diff --git a/ConsoleService.cs b/ConsoleService.cs index 427aa0b..b21fe72 100644 --- a/ConsoleService.cs +++ b/ConsoleService.cs @@ -2,12 +2,11 @@ namespace vassago { using vassago; using vassago.Models; + using vassago.TwitchInterface; internal class ConsoleService : IHostedService { Configuration config = new Configuration(); - private List discords = new List(); - private List twitchs = new List(); public ConsoleService(IConfiguration aspConfig) { @@ -30,7 +29,7 @@ namespace vassago { var d = new DiscordInterface.DiscordInterface(); await d.Init(dt); - discords.Add(d); + ProtocolInterfaces.ProtocolList.discords.Add(d); } if (config.TwitchConfigs?.Any() ?? false) @@ -38,7 +37,7 @@ namespace vassago { var t = new TwitchInterface.TwitchInterface(); await t.Init(tc); - twitchs.Add(t); + ProtocolInterfaces.ProtocolList.twitchs.Add(t); } } diff --git a/Migrations/20230704203907_permissionTagsOnUsers.Designer.cs b/Migrations/20230704203907_permissionTagsOnUsers.Designer.cs new file mode 100644 index 0000000..4d6cc59 --- /dev/null +++ b/Migrations/20230704203907_permissionTagsOnUsers.Designer.cs @@ -0,0 +1,296 @@ +// +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 + { + /// + 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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("text"); + + b.Property("IsBot") + .HasColumnType("boolean"); + + b.Property("IsUserId") + .HasColumnType("uuid"); + + b.Property("PermissionTags") + .HasColumnType("integer[]"); + + b.Property("Protocol") + .HasColumnType("text"); + + b.Property("SeenInChannelId") + .HasColumnType("uuid"); + + b.Property("Username") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("IsUserId"); + + b.HasIndex("SeenInChannelId"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("vassago.Models.Attachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Content") + .HasColumnType("bytea"); + + b.Property("ContentType") + .HasColumnType("text"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("numeric(20,0)"); + + b.Property("Filename") + .HasColumnType("text"); + + b.Property("MessageId") + .HasColumnType("uuid"); + + b.Property("Size") + .HasColumnType("integer"); + + b.Property("Source") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("MessageId"); + + b.ToTable("Attachments"); + }); + + modelBuilder.Entity("vassago.Models.Channel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("text"); + + b.Property("IsDM") + .HasColumnType("boolean"); + + b.Property("ParentChannelId") + .HasColumnType("uuid"); + + b.Property("PermissionsId") + .HasColumnType("integer"); + + b.Property("Protocol") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ParentChannelId"); + + b.HasIndex("PermissionsId"); + + b.ToTable("Channels"); + }); + + modelBuilder.Entity("vassago.Models.Message", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ActedOn") + .HasColumnType("boolean"); + + b.Property("AuthorId") + .HasColumnType("uuid"); + + b.Property("ChannelId") + .HasColumnType("uuid"); + + b.Property("Content") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("text"); + + b.Property("MentionsMe") + .HasColumnType("boolean"); + + b.Property("Protocol") + .HasColumnType("text"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("LewdnessFilterLevel") + .HasColumnType("integer"); + + b.Property("LinksAllowed") + .HasColumnType("boolean"); + + b.Property("MaxAttachmentBytes") + .HasColumnType("numeric(20,0)"); + + b.Property("MaxTextChars") + .HasColumnType("bigint"); + + b.Property("MeannessFilterLevel") + .HasColumnType("integer"); + + b.Property("ReactionsPossible") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("PermissionSettings"); + }); + + modelBuilder.Entity("vassago.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("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 + } + } +} diff --git a/Migrations/20230704203907_permissionTagsOnUsers.cs b/Migrations/20230704203907_permissionTagsOnUsers.cs new file mode 100644 index 0000000..197b6d1 --- /dev/null +++ b/Migrations/20230704203907_permissionTagsOnUsers.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace vassago.Migrations +{ + /// + public partial class permissionTagsOnUsers : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "PermissionTags", + table: "Users", + type: "integer[]", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "PermissionTags", + table: "Users"); + } + } +} diff --git a/Migrations/ChattingContextModelSnapshot.cs b/Migrations/ChattingContextModelSnapshot.cs index d87ec09..cf5df66 100644 --- a/Migrations/ChattingContextModelSnapshot.cs +++ b/Migrations/ChattingContextModelSnapshot.cs @@ -207,6 +207,9 @@ namespace vassago.Migrations .ValueGeneratedOnAdd() .HasColumnType("uuid"); + b.Property("PermissionTags") + .HasColumnType("integer[]"); + b.HasKey("Id"); b.ToTable("Users"); diff --git a/Models/Account.cs b/Models/Account.cs index 63554f1..da64499 100644 --- a/Models/Account.cs +++ b/Models/Account.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Reflection; +using System.Threading.Tasks; public class Account { @@ -25,7 +26,7 @@ public class Account } public bool IsBot { get; set; } //webhook counts public Channel SeenInChannel { get; set; } - //permissions are per account-in-channel, and always propagate down. and since protocol will be a channel, I'll set the "is adam" permission on myself 1x/protocol. + //permissions are per account-in-channel or per-user, and always propagate down. and since protocol will be a channel, I'll set the "is adam" permission on myself 1x/protocol. public List PermissionTags{get;set;} public string Protocol { get; set; } public User IsUser {get; set;} diff --git a/Models/Enums.cs b/Models/Enums.cs index 05cce67..6c04a84 100644 --- a/Models/Enums.cs +++ b/Models/Enums.cs @@ -29,7 +29,7 @@ public static class Enumerations public enum WellknownPermissions { Master, //e.g., me. not that I think this would ever be released? - ChannelModerator, + TwitchSummon, } public static string GetDescription(this T enumerationValue) diff --git a/Models/User.cs b/Models/User.cs index b2c93e6..b1db073 100644 --- a/Models/User.cs +++ b/Models/User.cs @@ -10,4 +10,6 @@ public class User [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public Guid Id { get; set; } public List Accounts { get; set; } + //permissions are per account-in-channel or per-user, and always propagate down. and since protocol will be a channel, I'll set the "is adam" permission on myself 1x/protocol. + public List PermissionTags{get;set;} } \ No newline at end of file diff --git a/DiscordInterface/DiscordInterface.cs b/ProtocolInterfaces/DiscordInterface/DiscordInterface.cs similarity index 100% rename from DiscordInterface/DiscordInterface.cs rename to ProtocolInterfaces/DiscordInterface/DiscordInterface.cs diff --git a/DiscordInterface/SlashCommandsHelper.cs b/ProtocolInterfaces/DiscordInterface/SlashCommandsHelper.cs similarity index 100% rename from DiscordInterface/SlashCommandsHelper.cs rename to ProtocolInterfaces/DiscordInterface/SlashCommandsHelper.cs diff --git a/ProtocolInterfaces/ProtocolList.cs b/ProtocolInterfaces/ProtocolList.cs new file mode 100644 index 0000000..b8fcca2 --- /dev/null +++ b/ProtocolInterfaces/ProtocolList.cs @@ -0,0 +1,7 @@ +namespace vassago.ProtocolInterfaces; + +public static class ProtocolList +{ + public static List discords = new List(); + public static List twitchs = new List(); +} \ No newline at end of file diff --git a/TwitchInterface/TwitchConfig.cs b/ProtocolInterfaces/TwitchInterface/TwitchConfig.cs similarity index 82% rename from TwitchInterface/TwitchConfig.cs rename to ProtocolInterfaces/TwitchInterface/TwitchConfig.cs index eb849f4..84f6d32 100644 --- a/TwitchInterface/TwitchConfig.cs +++ b/ProtocolInterfaces/TwitchInterface/TwitchConfig.cs @@ -1,3 +1,5 @@ +namespace vassago.TwitchInterface; + public class TwitchConfig { public string username {get; set;} diff --git a/TwitchInterface/TwitchInterface.cs b/ProtocolInterfaces/TwitchInterface/TwitchInterface.cs similarity index 95% rename from TwitchInterface/TwitchInterface.cs rename to ProtocolInterfaces/TwitchInterface/TwitchInterface.cs index ee499af..1ff9aef 100644 --- a/TwitchInterface/TwitchInterface.cs +++ b/ProtocolInterfaces/TwitchInterface/TwitchInterface.cs @@ -1,3 +1,4 @@ +using System.Security.Cryptography.X509Certificates; using System.Text.RegularExpressions; using RestSharp; using TwitchLib.Api; @@ -36,7 +37,7 @@ public class TwitchInterface { protocolAsChannel = new Channel() { - DisplayName = "discord (itself)", + DisplayName = "twitch (itself)", Permissions = new PermissionSettings() { MeannessFilterLevel = Enumerations.MeannessFilterLevel.Medium, @@ -126,8 +127,6 @@ public class TwitchInterface await _db.SaveChangesAsync(); Behaver.Instance.Selves.Add(selfUser); - client.JoinChannel("#homeburger"); - client.JoinChannel("homeburger"); Console.WriteLine($"Connected to {e.AutoJoinChannel}"); } @@ -250,4 +249,16 @@ public class TwitchInterface m.React = (e) => { throw new InvalidOperationException($"twitch cannot react"); }; return m; } + + public string AttemptJoin(string channelTarget) + { + client.JoinChannel(channelTarget); + return "o7"; + } + + internal void AttemptLeave(string channelTarget) + { + client.SendMessage(channelTarget, "o7"); + client.LeaveChannel(channelTarget); + } } \ No newline at end of file