UAC descriptions
All checks were successful
gitea.arg.rip/vassago/pipeline/head This commit looks good

see #40
This commit is contained in:
adam 2025-05-23 15:17:44 -04:00
parent 8dd8b599bd
commit 22ee1d2567
9 changed files with 515 additions and 62 deletions

View File

@ -1,7 +1,7 @@
namespace vassago; namespace vassago;
#pragma warning disable 4014 #pragma warning disable 4014 //the "not awaited" error
using gray_messages.chat; using gray_messages.chat;
using franz;//the "not awaited" error using franz;
using vassago.Behavior; using vassago.Behavior;
using vassago.Models; using vassago.Models;
using System; using System;

View File

@ -17,14 +17,16 @@ public class TwitchSummon : Behavior
public TwitchSummon() public TwitchSummon()
{ {
myUAC = Rememberer.SearchUAC(uac => uac.OwnerId == uacID); myUAC = Rememberer.SearchUAC(uac => uac.OwnerId == uacID);
if(myUAC == null) if (myUAC == null)
{ {
myUAC = new() myUAC = new()
{ {
OwnerId = uacID, OwnerId = uacID,
DisplayName = Name DisplayName = Name,
Description = @"matching this means you can summon the bot <i>to</i> <b>any</b> twitch channel"
}; };
} }
Rememberer.RememberUAC(myUAC);
} }
public override bool ShouldAct(Message message) public override bool ShouldAct(Message message)
{ {
@ -44,7 +46,7 @@ public class TwitchSummon : Behavior
public override async Task<bool> ActOn(Message message) public override async Task<bool> ActOn(Message message)
{ {
var ti = ProtocolInterfaces.ProtocolList.twitchs.FirstOrDefault(); var ti = ProtocolInterfaces.ProtocolList.twitchs.FirstOrDefault();
if(ti != null) if (ti != null)
{ {
var channelTarget = message.Content.Substring(message.Content.IndexOf(Trigger) + Trigger.Length + 1).Trim(); var channelTarget = message.Content.Substring(message.Content.IndexOf(Trigger) + Trigger.Length + 1).Trim();
await message.Channel.SendMessage(ti.AttemptJoin(channelTarget)); await message.Channel.SendMessage(ti.AttemptJoin(channelTarget));
@ -55,4 +57,44 @@ public class TwitchSummon : Behavior
} }
return true; return true;
} }
[StaticPlz]
public class TwitchDismiss : Behavior
{
public override string Name => "Twitch Dismiss";
public override string Trigger => "begone, @[me]";
public override bool ShouldAct(Message message)
{
var ti = 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;
}
}
} }

View File

@ -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;
}
}

View File

@ -36,14 +36,17 @@ public class Webhook : Behavior
{ {
Console.WriteLine($"{kvp[0]}: {kvp[1]}"); Console.WriteLine($"{kvp[0]}: {kvp[1]}");
} }
var changed = false;
var myUAC = Rememberer.SearchUAC(uac => uac.OwnerId == conf.uacID); var myUAC = Rememberer.SearchUAC(uac => uac.OwnerId == conf.uacID);
if (myUAC == null) if (myUAC == null)
{ {
myUAC = new() myUAC = new()
{ {
OwnerId = conf.uacID, OwnerId = conf.uacID,
DisplayName = confName DisplayName = confName,
Description = conf.Description
}; };
changed = true;
Rememberer.RememberUAC(myUAC); Rememberer.RememberUAC(myUAC);
} }
else else
@ -51,9 +54,16 @@ public class Webhook : Behavior
if (myUAC.DisplayName != confName) if (myUAC.DisplayName != confName)
{ {
myUAC.DisplayName = confName; myUAC.DisplayName = confName;
Rememberer.RememberUAC(myUAC); changed = true;
}
if (myUAC.Description != conf.Description)
{
myUAC.Description = conf.Description;
changed = true;
} }
} }
if (changed)
Rememberer.RememberUAC(myUAC);
} }
} }
@ -160,7 +170,7 @@ public class Webhook : Behavior
} }
private string translate(WebhookActionOrder actionOrder, Message message) private string translate(WebhookActionOrder actionOrder, Message message)
{ {
if(string.IsNullOrWhiteSpace(actionOrder.Conf.Content)) if (string.IsNullOrWhiteSpace(actionOrder.Conf.Content))
return ""; return "";
var msgContent = actionOrder.Conf.Content.Replace("{text}", actionOrder.webhookContent); var msgContent = actionOrder.Conf.Content.Replace("{text}", actionOrder.webhookContent);
msgContent = msgContent.Replace("{msgid}", message.Id.ToString()); msgContent = msgContent.Replace("{msgid}", message.Id.ToString());
@ -179,6 +189,7 @@ public class WebhookConf
public Enumerations.HttpVerb Method { get; set; } public Enumerations.HttpVerb Method { get; set; }
public List<List<string>> Headers { get; set; } public List<List<string>> Headers { get; set; }
public string Content { get; set; } public string Content { get; set; }
public string Description { get; set; }
} }
public class WebhookActionOrder public class WebhookActionOrder
{ {

View File

@ -0,0 +1,386 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using vassago.Models;
#nullable disable
namespace vassago.Migrations
{
[DbContext(typeof(ChattingContext))]
[Migration("20250523181842_channelAliases")]
partial class channelAliases
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore");
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("AccountUAC", b =>
{
b.Property<Guid>("AccountInChannelsId")
.HasColumnType("uuid");
b.Property<Guid>("UACsId")
.HasColumnType("uuid");
b.HasKey("AccountInChannelsId", "UACsId");
b.HasIndex("UACsId");
b.ToTable("AccountUAC");
});
modelBuilder.Entity("ChannelUAC", b =>
{
b.Property<Guid>("ChannelsId")
.HasColumnType("uuid");
b.Property<Guid>("UACsId")
.HasColumnType("uuid");
b.HasKey("ChannelsId", "UACsId");
b.HasIndex("UACsId");
b.ToTable("ChannelUAC");
});
modelBuilder.Entity("UACUser", b =>
{
b.Property<Guid>("UACsId")
.HasColumnType("uuid");
b.Property<Guid>("UsersId")
.HasColumnType("uuid");
b.HasKey("UACsId", "UsersId");
b.HasIndex("UsersId");
b.ToTable("UACUser");
});
modelBuilder.Entity("vassago.Models.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("DisplayName")
.HasColumnType("text");
b.Property<string>("ExternalId")
.HasColumnType("text");
b.Property<bool>("IsBot")
.HasColumnType("boolean");
b.Property<Guid?>("IsUserId")
.HasColumnType("uuid");
b.Property<string>("Protocol")
.HasColumnType("text");
b.Property<Guid?>("SeenInChannelId")
.HasColumnType("uuid");
b.Property<string>("Username")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("IsUserId");
b.HasIndex("SeenInChannelId");
b.ToTable("Accounts");
});
modelBuilder.Entity("vassago.Models.Attachment", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte[]>("Content")
.HasColumnType("bytea");
b.Property<string>("ContentType")
.HasColumnType("text");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<decimal?>("ExternalId")
.HasColumnType("numeric(20,0)");
b.Property<string>("Filename")
.HasColumnType("text");
b.Property<Guid?>("MessageId")
.HasColumnType("uuid");
b.Property<int>("Size")
.HasColumnType("integer");
b.Property<string>("Source")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("MessageId");
b.ToTable("Attachments");
});
modelBuilder.Entity("vassago.Models.Channel", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Dictionary<string, string>>("Aliases")
.HasColumnType("hstore");
b.Property<int>("ChannelType")
.HasColumnType("integer");
b.Property<string>("DisplayName")
.HasColumnType("text");
b.Property<string>("ExternalId")
.HasColumnType("text");
b.Property<int?>("LewdnessFilterLevel")
.HasColumnType("integer");
b.Property<bool?>("LinksAllowed")
.HasColumnType("boolean");
b.Property<decimal?>("MaxAttachmentBytes")
.HasColumnType("numeric(20,0)");
b.Property<long?>("MaxTextChars")
.HasColumnType("bigint");
b.Property<int?>("MeannessFilterLevel")
.HasColumnType("integer");
b.Property<Guid?>("ParentChannelId")
.HasColumnType("uuid");
b.Property<string>("Protocol")
.HasColumnType("text");
b.Property<bool?>("ReactionsPossible")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("ParentChannelId");
b.ToTable("Channels");
});
modelBuilder.Entity("vassago.Models.Message", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("ActedOn")
.HasColumnType("boolean");
b.Property<Guid?>("AuthorId")
.HasColumnType("uuid");
b.Property<Guid?>("ChannelId")
.HasColumnType("uuid");
b.Property<string>("Content")
.HasColumnType("text");
b.Property<string>("ExternalId")
.HasColumnType("text");
b.Property<bool>("MentionsMe")
.HasColumnType("boolean");
b.Property<string>("Protocol")
.HasColumnType("text");
b.Property<DateTimeOffset>("Timestamp")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("AuthorId");
b.HasIndex("ChannelId");
b.ToTable("Messages");
});
modelBuilder.Entity("vassago.Models.UAC", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<string>("DisplayName")
.HasColumnType("text");
b.Property<Guid>("OwnerId")
.HasColumnType("uuid");
b.HasKey("Id");
b.ToTable("UACs");
});
modelBuilder.Entity("vassago.Models.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.HasKey("Id");
b.ToTable("Users");
});
modelBuilder.Entity("AccountUAC", b =>
{
b.HasOne("vassago.Models.Account", null)
.WithMany()
.HasForeignKey("AccountInChannelsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("vassago.Models.UAC", null)
.WithMany()
.HasForeignKey("UACsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ChannelUAC", b =>
{
b.HasOne("vassago.Models.Channel", null)
.WithMany()
.HasForeignKey("ChannelsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("vassago.Models.UAC", null)
.WithMany()
.HasForeignKey("UACsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("UACUser", b =>
{
b.HasOne("vassago.Models.UAC", null)
.WithMany()
.HasForeignKey("UACsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("vassago.Models.User", null)
.WithMany()
.HasForeignKey("UsersId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("vassago.Models.Account", b =>
{
b.HasOne("vassago.Models.User", "IsUser")
.WithMany("Accounts")
.HasForeignKey("IsUserId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("vassago.Models.Channel", "SeenInChannel")
.WithMany("Users")
.HasForeignKey("SeenInChannelId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("IsUser");
b.Navigation("SeenInChannel");
});
modelBuilder.Entity("vassago.Models.Attachment", b =>
{
b.HasOne("vassago.Models.Message", "Message")
.WithMany("Attachments")
.HasForeignKey("MessageId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Message");
});
modelBuilder.Entity("vassago.Models.Channel", b =>
{
b.HasOne("vassago.Models.Channel", "ParentChannel")
.WithMany("SubChannels")
.HasForeignKey("ParentChannelId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("ParentChannel");
});
modelBuilder.Entity("vassago.Models.Message", b =>
{
b.HasOne("vassago.Models.Account", "Author")
.WithMany()
.HasForeignKey("AuthorId");
b.HasOne("vassago.Models.Channel", "Channel")
.WithMany("Messages")
.HasForeignKey("ChannelId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Author");
b.Navigation("Channel");
});
modelBuilder.Entity("vassago.Models.Channel", b =>
{
b.Navigation("Messages");
b.Navigation("SubChannels");
b.Navigation("Users");
});
modelBuilder.Entity("vassago.Models.Message", b =>
{
b.Navigation("Attachments");
});
modelBuilder.Entity("vassago.Models.User", b =>
{
b.Navigation("Accounts");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,45 @@
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace vassago.Migrations
{
/// <inheritdoc />
public partial class channelAliases : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterDatabase()
.Annotation("Npgsql:PostgresExtension:hstore", ",,");
migrationBuilder.AddColumn<string>(
name: "Description",
table: "UACs",
type: "text",
nullable: true);
migrationBuilder.AddColumn<Dictionary<string, string>>(
name: "Aliases",
table: "Channels",
type: "hstore",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Description",
table: "UACs");
migrationBuilder.DropColumn(
name: "Aliases",
table: "Channels");
migrationBuilder.AlterDatabase()
.OldAnnotation("Npgsql:PostgresExtension:hstore", ",,");
}
}
}

View File

@ -1,5 +1,6 @@
// <auto-generated /> // <auto-generated />
using System; using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
@ -20,6 +21,7 @@ namespace vassago.Migrations
.HasAnnotation("ProductVersion", "7.0.5") .HasAnnotation("ProductVersion", "7.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63); .HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore");
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("AccountUAC", b => modelBuilder.Entity("AccountUAC", b =>
@ -146,6 +148,9 @@ namespace vassago.Migrations
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("uuid"); .HasColumnType("uuid");
b.Property<Dictionary<string, string>>("Aliases")
.HasColumnType("hstore");
b.Property<int>("ChannelType") b.Property<int>("ChannelType")
.HasColumnType("integer"); .HasColumnType("integer");
@ -231,6 +236,9 @@ namespace vassago.Migrations
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("uuid"); .HasColumnType("uuid");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<string>("DisplayName") b.Property<string>("DisplayName")
.HasColumnType("text"); .HasColumnType("text");

View File

@ -25,7 +25,7 @@ public class Channel
public List<Message> Messages { get; set; } public List<Message> Messages { get; set; }
[DeleteBehavior(DeleteBehavior.Cascade)] [DeleteBehavior(DeleteBehavior.Cascade)]
public List<Account> Users { get; set; } public List<Account> Users { get; set; }
public ChannelType ChannelType {get; set; } public ChannelType ChannelType { get; set; }
//Permissions //Permissions
public ulong? MaxAttachmentBytes { get; set; } public ulong? MaxAttachmentBytes { get; set; }
@ -34,8 +34,9 @@ public class Channel
public bool? ReactionsPossible { get; set; } public bool? ReactionsPossible { get; set; }
public Enumerations.LewdnessFilterLevel? LewdnessFilterLevel { get; set; } public Enumerations.LewdnessFilterLevel? LewdnessFilterLevel { get; set; }
public Enumerations.MeannessFilterLevel? MeannessFilterLevel { get; set; } public Enumerations.MeannessFilterLevel? MeannessFilterLevel { get; set; }
public List<UAC> UACs { get; set; } public List<UAC> UACs { get; set; }
//both incoming and outgoing
//public Dictionary<string, string> Aliases { get; set; }
[NonSerialized] [NonSerialized]
public Func<string, string, Task> SendFile; public Func<string, string, Task> SendFile;
@ -51,14 +52,14 @@ public class Channel
var path = new Stack<Channel>(); //omg i actually get to use a data structure from university var path = new Stack<Channel>(); //omg i actually get to use a data structure from university
var walker = this; var walker = this;
path.Push(this); path.Push(this);
while(walker.ParentChannel != null) while (walker.ParentChannel != null)
{ {
walker = walker.ParentChannel; walker = walker.ParentChannel;
path.Push(walker); path.Push(walker);
} }
DefinitePermissionSettings toReturn = new DefinitePermissionSettings(); DefinitePermissionSettings toReturn = new DefinitePermissionSettings();
while(path.Count > 0) while (path.Count > 0)
{ {
walker = path.Pop(); walker = path.Pop();
toReturn.LewdnessFilterLevel = walker.LewdnessFilterLevel ?? toReturn.LewdnessFilterLevel; toReturn.LewdnessFilterLevel = walker.LewdnessFilterLevel ?? toReturn.LewdnessFilterLevel;
@ -76,7 +77,7 @@ public class Channel
{ {
get get
{ {
if(this.ParentChannel != null) if (this.ParentChannel != null)
{ {
return this.ParentChannel.LineageSummary + '/' + this.DisplayName; return this.ParentChannel.LineageSummary + '/' + this.DisplayName;
} }
@ -94,7 +95,7 @@ public class Channel
{ {
var toReturn = this.MemberwiseClone() as Channel; var toReturn = this.MemberwiseClone() as Channel;
toReturn.ParentChannel = null; toReturn.ParentChannel = null;
if(toReturn.Users?.Count > 0) if (toReturn.Users?.Count > 0)
{ {
foreach (var account in toReturn.Users) foreach (var account in toReturn.Users)
{ {

View File

@ -19,7 +19,13 @@
{ {
"uacID": "9a94855a-e5a2-43b5-8420-ce670472ce95", "uacID": "9a94855a-e5a2-43b5-8420-ce670472ce95",
"Trigger": "test", "Trigger": "test",
"Uri": "http://localhost" "Description": "<i>test</i>",
"Uri": "http://localhost",
"Method": "POST",
"Headers": [
["Content-Type", "application/json"]
],
"Content": "{\"content\": \"Hello, this is a message from my webhook: {text}. username: {account}, user: {user}\"}"
} }
], ],
"KafkaBootstrap":"http://localhost:9092", "KafkaBootstrap":"http://localhost:9092",