forked from adam/discord-bot-shtik
Compare commits
3 Commits
0d3a56c8db
...
6881816c94
Author | SHA1 | Date | |
---|---|---|---|
6881816c94 | |||
53753374f0 | |||
50ecfc5867 |
@ -4,6 +4,7 @@ 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
|
||||
@ -27,5 +28,6 @@ public class Account
|
||||
public bool IsBot { get; set; } //webhook counts
|
||||
public Channel SeenInChannel { get; set; }
|
||||
public string Protocol { get; set; }
|
||||
[JsonIgnore]
|
||||
public User IsUser {get; set;}
|
||||
}
|
@ -7,6 +7,7 @@ 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
|
||||
@ -17,6 +18,7 @@ public class Channel
|
||||
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)]
|
||||
@ -82,6 +84,23 @@ public class Channel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///<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
|
||||
|
@ -11,7 +11,10 @@ var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Services.AddControllersWithViews();
|
||||
builder.Services.AddSingleton<IHostedService, vassago.ConsoleService>();
|
||||
builder.Services.AddDbContext<ChattingContext>();
|
||||
builder.Services.AddControllers().AddNewtonsoftJson();
|
||||
builder.Services.AddControllers().AddNewtonsoftJson(options => {
|
||||
options.SerializerSettings.ReferenceLoopHandling =
|
||||
Newtonsoft.Json.ReferenceLoopHandling.Ignore;
|
||||
});
|
||||
builder.Services.AddProblemDetails();
|
||||
builder.Services.Configure<RazorViewEngineOptions>(o => {
|
||||
o.ViewLocationFormats.Clear();
|
||||
|
@ -237,10 +237,12 @@ public class DiscordInterface
|
||||
if (c == null)
|
||||
{
|
||||
Console.WriteLine($"couldn't find channel under protocol {PROTOCOL} with externalId {channel.Id.ToString()}");
|
||||
c = new Channel();
|
||||
c = new Channel()
|
||||
{
|
||||
Users = []
|
||||
};
|
||||
}
|
||||
|
||||
c.DisplayName = channel.Name;
|
||||
c.ExternalId = channel.Id.ToString();
|
||||
c.ChannelType = (channel is IPrivateChannel) ? vassago.Models.Enumerations.ChannelType.DM : vassago.Models.Enumerations.ChannelType.Normal;
|
||||
c.Messages ??= [];
|
||||
@ -263,7 +265,11 @@ public class DiscordInterface
|
||||
switch (c.ChannelType)
|
||||
{
|
||||
case vassago.Models.Enumerations.ChannelType.DM:
|
||||
c.DisplayName = "DM: " + (channel as IPrivateChannel).Recipients?.FirstOrDefault(u => u.Id != client.CurrentUser.Id).Username;
|
||||
var asPriv =(channel as IPrivateChannel);
|
||||
c.DisplayName = "DM: " + asPriv?.Recipients?.FirstOrDefault(u => u.Id != client.CurrentUser.Id).Username;
|
||||
break;
|
||||
default:
|
||||
c.DisplayName = channel.Name;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -286,12 +292,23 @@ public class DiscordInterface
|
||||
Console.Error.WriteLine($"trying to upsert channel {channel.Id}/{channel.Name}, but it's neither guildchannel nor private channel. shrug.jpg");
|
||||
}
|
||||
parentChannel.SubChannels ??= [];
|
||||
parentChannel.SubChannels.Add(c);
|
||||
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); };
|
||||
|
||||
return Rememberer.RememberChannel(c);
|
||||
c = Rememberer.RememberChannel(c);
|
||||
|
||||
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)
|
||||
{
|
||||
@ -316,24 +333,25 @@ public class DiscordInterface
|
||||
|
||||
return Rememberer.RememberChannel(c);
|
||||
}
|
||||
internal static Account UpsertAccount(IUser user, Channel inChannel)
|
||||
internal static Account UpsertAccount(IUser discordUser, Channel inChannel)
|
||||
{
|
||||
var acc = Rememberer.SearchAccount(ui => ui.ExternalId == user.Id.ToString() && ui.SeenInChannel.Id == inChannel.Id);
|
||||
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 = new User() };
|
||||
acc ??= new Account() {
|
||||
IsUser = Rememberer.SearchUser(u => u.Accounts.Any(a => a.ExternalId == discordUser.Id.ToString() && a.Protocol == PROTOCOL))
|
||||
?? new User()
|
||||
};
|
||||
|
||||
acc.Username = user.Username;
|
||||
acc.ExternalId = user.Id.ToString();
|
||||
acc.IsBot = user.IsBot || user.IsWebhook;
|
||||
acc.Username = discordUser.Username;
|
||||
acc.ExternalId = discordUser.Id.ToString();
|
||||
acc.IsBot = discordUser.IsBot || discordUser.IsWebhook;
|
||||
acc.Protocol = PROTOCOL;
|
||||
acc.SeenInChannel = inChannel;
|
||||
|
||||
acc.IsUser = Rememberer.SearchUser(u => u.Accounts.Any(a => a.ExternalId == acc.ExternalId && a.Protocol == acc.Protocol));
|
||||
|
||||
Console.WriteLine($"we asked rememberer to search for acc's user. {acc.IsUser?.Id}");
|
||||
if (acc.IsUser != null)
|
||||
{
|
||||
@ -344,8 +362,13 @@ public class DiscordInterface
|
||||
{
|
||||
Console.WriteLine($"channel has {inChannel.Users.Count} accounts");
|
||||
}
|
||||
inChannel.Users ??= [acc];
|
||||
Rememberer.RememberAccount(acc);
|
||||
inChannel.Users ??= [];
|
||||
if(!inChannel.Users.Contains(acc))
|
||||
{
|
||||
inChannel.Users.Add(acc);
|
||||
Rememberer.RememberChannel(inChannel);
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
|
@ -9,27 +9,27 @@ public static class Rememberer
|
||||
private static readonly ChattingContext db = new();
|
||||
public static Account SearchAccount(Expression<Func<Account, bool>> predicate)
|
||||
{
|
||||
return (new ChattingContext()).Accounts.Include(a => a.IsUser).FirstOrDefault(predicate);
|
||||
return db.Accounts.Include(a => a.IsUser).FirstOrDefault(predicate);
|
||||
}
|
||||
public static List<Account> SearchAccounts(Expression<Func<Account, bool>> predicate)
|
||||
{
|
||||
return (new ChattingContext()).Accounts.Where(predicate).ToList();
|
||||
return db.Accounts.Where(predicate).ToList();
|
||||
}
|
||||
public static Attachment SearchAttachment(Expression<Func<Attachment, bool>> predicate)
|
||||
{
|
||||
return (new ChattingContext()).Attachments.FirstOrDefault(predicate);
|
||||
return db.Attachments.FirstOrDefault(predicate);
|
||||
}
|
||||
public static Channel SearchChannel(Expression<Func<Channel, bool>> predicate)
|
||||
{
|
||||
return (new ChattingContext()).Channels.FirstOrDefault(predicate);
|
||||
return db.Channels.FirstOrDefault(predicate);
|
||||
}
|
||||
public static Message SearchMessage(Expression<Func<Message, bool>> predicate)
|
||||
{
|
||||
return (new ChattingContext()).Messages.FirstOrDefault(predicate);
|
||||
return db.Messages.FirstOrDefault(predicate);
|
||||
}
|
||||
public static User SearchUser(Expression<Func<User, bool>> predicate)
|
||||
{
|
||||
return (new ChattingContext()).Users.Include(u => u.Accounts).FirstOrDefault(predicate);
|
||||
return db.Users.Include(u => u.Accounts).FirstOrDefault(predicate);
|
||||
}
|
||||
public static void RememberAccount(Account toRemember)
|
||||
{
|
||||
@ -61,6 +61,27 @@ public static class Rememberer
|
||||
|
||||
db.SaveChanges();
|
||||
}
|
||||
public static void ForgetAccount(Account toForget)
|
||||
{
|
||||
var user = toForget.IsUser;
|
||||
var usersOnlyAccount = user.Accounts?.Count == 1;
|
||||
|
||||
if(usersOnlyAccount)
|
||||
{
|
||||
Rememberer.ForgetUser(user);
|
||||
}
|
||||
else
|
||||
{
|
||||
db.Accounts.Remove(toForget);
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
public static void ForgetChannel(Channel toForget)
|
||||
{
|
||||
db.Channels.Remove(toForget);
|
||||
|
||||
db.SaveChanges();
|
||||
}
|
||||
public static void ForgetUser(User toForget)
|
||||
{
|
||||
db.Users.Remove(toForget);
|
||||
@ -69,11 +90,11 @@ public static class Rememberer
|
||||
}
|
||||
public static List<Account> AccountsOverview()
|
||||
{
|
||||
return db.Accounts.ToList();
|
||||
return [..db.Accounts];
|
||||
}
|
||||
public static List<Channel> ChannelsOverview()
|
||||
{
|
||||
return db.Channels.Include(u => u.SubChannels).Include(c => c.ParentChannel).ToList();
|
||||
return [..db.Channels.Include(u => u.SubChannels).Include(c => c.ParentChannel)];
|
||||
}
|
||||
public static Channel ChannelDetail(Guid Id)
|
||||
{
|
||||
|
@ -25,7 +25,7 @@ public class HomeController : Controller
|
||||
Console.WriteLine($"accounts: {allAccounts?.Count ?? 0}, channels: {allChannels?.Count ?? 0}");
|
||||
var sb = new StringBuilder();
|
||||
sb.Append('[');
|
||||
sb.Append("{text: \"channels\", nodes: [");
|
||||
sb.Append("{text: \"channels\", expanded:true, nodes: [");
|
||||
|
||||
var first = true;
|
||||
var topLevelChannels = Rememberer.ChannelsOverview().Where(x => x.ParentChannel == null);
|
||||
@ -46,7 +46,7 @@ public class HomeController : Controller
|
||||
|
||||
if (allChannels.Any())
|
||||
{
|
||||
sb.Append(",{text: \"orphaned channels\", nodes: [");
|
||||
sb.Append(",{text: \"orphaned channels\", expanded:true, nodes: [");
|
||||
first = true;
|
||||
while (true)
|
||||
{
|
||||
@ -68,7 +68,7 @@ public class HomeController : Controller
|
||||
}
|
||||
if (allAccounts.Any())
|
||||
{
|
||||
sb.Append(",{text: \"channelless accounts\", nodes: [");
|
||||
sb.Append(",{text: \"channelless accounts\", expanded:true, nodes: [");
|
||||
first = true;
|
||||
foreach (var acc in allAccounts)
|
||||
{
|
||||
@ -87,7 +87,7 @@ public class HomeController : Controller
|
||||
var users = Rememberer.UsersOverview();// _db.Users.ToList();
|
||||
if(users.Any())
|
||||
{
|
||||
sb.Append(",{text: \"users\", nodes: [");
|
||||
sb.Append(",{text: \"users\", expanded:true, nodes: [");
|
||||
first=true;
|
||||
//refresh list; we'll be knocking them out again in serializeUser
|
||||
allAccounts = Rememberer.AccountsOverview();
|
||||
@ -105,7 +105,7 @@ public class HomeController : Controller
|
||||
}
|
||||
sb.Append("]}");
|
||||
}
|
||||
sb.Append("]");
|
||||
sb.Append(']');
|
||||
ViewData.Add("treeString", sb.ToString());
|
||||
return View("Index");
|
||||
}
|
||||
@ -114,6 +114,7 @@ public class HomeController : Controller
|
||||
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;
|
||||
@ -123,7 +124,7 @@ public class HomeController : Controller
|
||||
}
|
||||
if (currentChannel.SubChannels != null)
|
||||
{
|
||||
foreach (var subChannel in currentChannel.SubChannels ?? new List<Channel>())
|
||||
foreach (var subChannel in currentChannel.SubChannels)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
@ -135,7 +136,7 @@ public class HomeController : Controller
|
||||
}
|
||||
serializeChannel(ref sb, ref allChannels, ref allAccounts, subChannel);
|
||||
}
|
||||
if (theseAccounts != null)
|
||||
if (theseAccounts != null && !first) //"first" here tells us that we have at least one subchannel
|
||||
{
|
||||
sb.Append(',');
|
||||
}
|
||||
|
@ -11,49 +11,50 @@ namespace vassago.Controllers.api;
|
||||
public class ChannelsController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<ChannelsController> _logger;
|
||||
private readonly ChattingContext _db;
|
||||
|
||||
public ChannelsController(ILogger<ChannelsController> logger, ChattingContext db)
|
||||
public ChannelsController(ILogger<ChannelsController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
[Produces("application/json")]
|
||||
public Channel Get(Guid id)
|
||||
{
|
||||
return _db.Find<Channel>(id);
|
||||
return Rememberer.ChannelDetail(id);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[Produces("application/json")]
|
||||
public IActionResult Patch([FromBody] Channel channel)
|
||||
{
|
||||
var fromDb = _db.Channels.Find(channel.Id);
|
||||
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;
|
||||
_db.SaveChanges();
|
||||
Rememberer.RememberChannel(fromDb);
|
||||
return Ok(fromDb);
|
||||
}
|
||||
[HttpDelete]
|
||||
[Produces("application/json")]
|
||||
public IActionResult Delete([FromBody] Channel channel)
|
||||
{
|
||||
var fromDb = _db.Channels.Find(channel.Id);
|
||||
var fromDb = Rememberer.ChannelDetail(channel.Id);
|
||||
if (fromDb == null)
|
||||
{
|
||||
_logger.LogError($"attempt to delete channel {channel.Id}, not found");
|
||||
return NotFound();
|
||||
}
|
||||
deleteChannel(fromDb);
|
||||
_db.SaveChanges();
|
||||
return Ok();
|
||||
}
|
||||
private void deleteChannel(Channel channel)
|
||||
@ -74,21 +75,16 @@ public class ChannelsController : ControllerBase
|
||||
}
|
||||
}
|
||||
|
||||
if(channel.Messages?.Count > 0)
|
||||
{
|
||||
_db.Remove(channel.Messages);
|
||||
}
|
||||
|
||||
_db.Remove(channel);
|
||||
Rememberer.ForgetChannel(channel);
|
||||
}
|
||||
private void deleteAccount(Account account)
|
||||
{
|
||||
var user = account.IsUser;
|
||||
var usersOnlyAccount = user.Accounts?.Count == 1;
|
||||
|
||||
_db.Remove(account);
|
||||
Rememberer.ForgetAccount(account);
|
||||
|
||||
if(usersOnlyAccount)
|
||||
_db.Users.Remove(user);
|
||||
Rememberer.ForgetUser(user);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user