Transition to namespaced chat/user ids

This commit is contained in:
jetsparrow 2021-04-22 15:42:28 +03:00
parent 40a44145fe
commit 7b0ef9a8e1
9 changed files with 97 additions and 119 deletions

View File

@ -20,7 +20,6 @@ namespace JetHerald.Commands
if (cmd.Parameters.Length < 1) if (cmd.Parameters.Length < 1)
return null; return null;
var msg = messageEventArgs.Message; var msg = messageEventArgs.Message;
var chatid = msg.Chat.Id;
if (msg.Chat.Type != ChatType.Private) if (msg.Chat.Type != ChatType.Private)
return null; return null;
@ -32,7 +31,7 @@ namespace JetHerald.Commands
try try
{ {
var topic = await db.CreateTopic(msg.From.Id, "Telegram", name, descr); var topic = await db.CreateTopic(NamespacedId.Telegram(msg.From.Id), name, descr);
return $"created {topic.Name}\n" + return $"created {topic.Name}\n" +
$"readToken\n{topic.ReadToken}\n" + $"readToken\n{topic.ReadToken}\n" +
$"writeToken\n{topic.WriteToken}\n" + $"writeToken\n{topic.WriteToken}\n" +

View File

@ -18,7 +18,6 @@ namespace JetHerald.Commands
if (cmd.Parameters.Length < 2) if (cmd.Parameters.Length < 2)
return null; return null;
var msg = messageEventArgs.Message; var msg = messageEventArgs.Message;
var chatid = msg.Chat.Id;
if (msg.Chat.Type != ChatType.Private) if (msg.Chat.Type != ChatType.Private)
return null; return null;
@ -26,8 +25,11 @@ namespace JetHerald.Commands
string name = cmd.Parameters[0]; string name = cmd.Parameters[0];
string adminToken = cmd.Parameters[1]; string adminToken = cmd.Parameters[1];
var topic = await db.DeleteTopic(name, adminToken); var changed = await db.DeleteTopic(name, adminToken);
return $"deleted {name} and all its subscriptions"; if (changed > 0)
return ($"deleted {name} and all its subscriptions");
else
return ($"invalid topic name or admin token");
} }
} }
} }

View File

@ -9,7 +9,7 @@ namespace JetHerald
[ModuleLifespan(ModuleLifespan.Transient)] [ModuleLifespan(ModuleLifespan.Transient)]
public class DiscordCommands : BaseCommandModule public class DiscordCommands : BaseCommandModule
{ {
public Db db { private get; set; } public Db Db { get; set; }
[Command("createtopic")] [Command("createtopic")]
[Description("Creates a topic.")] [Description("Creates a topic.")]
@ -28,7 +28,7 @@ namespace JetHerald
try try
{ {
var topic = await db.CreateTopic((long)ctx.User.Id, "Discord", name, description); var topic = await Db.CreateTopic(NamespacedId.Discord(ctx.User.Id), name, description);
await ctx.RespondAsync($"created {topic.Name}\n" + await ctx.RespondAsync($"created {topic.Name}\n" +
$"readToken\n{topic.ReadToken}\n" + $"readToken\n{topic.ReadToken}\n" +
$"writeToken\n{topic.WriteToken}\n" + $"writeToken\n{topic.WriteToken}\n" +
@ -51,7 +51,7 @@ namespace JetHerald
string adminToken) string adminToken)
{ {
_ = ctx.TriggerTypingAsync(); _ = ctx.TriggerTypingAsync();
var changed = await db.DeleteTopic(name, adminToken); var changed = await Db.DeleteTopic(name, adminToken);
if (changed > 0) if (changed > 0)
await ctx.RespondAsync($"deleted {name} and all its subscriptions"); await ctx.RespondAsync($"deleted {name} and all its subscriptions");
else else
@ -64,7 +64,7 @@ namespace JetHerald
{ {
_ = ctx.TriggerTypingAsync(); _ = ctx.TriggerTypingAsync();
var topics = await db.GetTopicsForChat((long)ctx.Channel.Id, "Discord"); var topics = await Db.GetTopicsForChat(NamespacedId.Discord(ctx.Channel.Id));
await ctx.RespondAsync(topics.Any() await ctx.RespondAsync(topics.Any()
? "Topics:\n" + string.Join("\n", topics) ? "Topics:\n" + string.Join("\n", topics)
@ -81,17 +81,18 @@ namespace JetHerald
{ {
_ = ctx.TriggerTypingAsync(); _ = ctx.TriggerTypingAsync();
var topic = await db.GetTopic(token, (long)ctx.Channel.Id, "Discord"); var chat = NamespacedId.Discord(ctx.Channel.Id);
var topic = await Db.GetTopicForSub(token, chat);
if (topic == null) if (topic == null)
await ctx.RespondAsync("topic not found"); await ctx.RespondAsync("topic not found");
else if (topic.ChatId == (long)ctx.Channel.Id) else if (topic.Chat.HasValue && topic.Chat.Value == chat)
await ctx.RespondAsync($"already subscribed to {topic.Name}"); await ctx.RespondAsync($"already subscribed to {topic.Name}");
else if (topic.ReadToken != token) else if (topic.ReadToken != token)
await ctx.RespondAsync("token mismatch"); await ctx.RespondAsync("token mismatch");
else else
{ {
await db.CreateSubscription(topic.TopicId, (long)ctx.Channel.Id, "Discord"); await Db.CreateSubscription(topic.TopicId, chat);
await ctx.RespondAsync($"subscribed to {topic.Name}"); await ctx.RespondAsync($"subscribed to {topic.Name}");
} }
} }
@ -106,7 +107,7 @@ namespace JetHerald
{ {
_ = ctx.TriggerTypingAsync(); _ = ctx.TriggerTypingAsync();
int affected = await db.RemoveSubscription(name, (long)ctx.Channel.Id, "Discord"); int affected = await Db.RemoveSubscription(name, NamespacedId.Discord(ctx.Channel.Id));
if (affected >= 1) if (affected >= 1)
await ctx.RespondAsync($"unsubscribed from {name}"); await ctx.RespondAsync($"unsubscribed from {name}");
else else

View File

@ -17,7 +17,7 @@ namespace JetHerald
{ {
var msg = messageEventArgs.Message; var msg = messageEventArgs.Message;
var chatid = msg.Chat.Id; var chatid = msg.Chat.Id;
var topics = await db.GetTopicsForChat(chatid, "Telegram"); var topics = await db.GetTopicsForChat(NamespacedId.Telegram(chatid));
return topics.Any() return topics.Any()
? "Topics:\n" + string.Join("\n", topics) ? "Topics:\n" + string.Join("\n", topics)

View File

@ -17,20 +17,20 @@ namespace JetHerald
if (cmd.Parameters.Length < 1) if (cmd.Parameters.Length < 1)
return null; return null;
var chatid = args.Message.Chat.Id; var chat = NamespacedId.Telegram(args.Message.Chat.Id);
var token = cmd.Parameters[0]; var token = cmd.Parameters[0];
var topic = await db.GetTopic(token, chatid, "Telegram"); var topic = await db.GetTopicForSub(token, chat);
if (topic == null) if (topic == null)
return "topic not found"; return "topic not found";
else if (topic.ChatId == chatid) else if (topic.Chat == chat)
return $"already subscribed to {topic.Name}"; return $"already subscribed to {topic.Name}";
else if (topic.ReadToken != token) else if (topic.ReadToken != token)
return "token mismatch"; return "token mismatch";
else else
{ {
await db.CreateSubscription(topic.TopicId, chatid, "Telegram"); await db.CreateSubscription(topic.TopicId, chat);
return $"subscribed to {topic.Name}"; return $"subscribed to {topic.Name}";
} }
} }

View File

@ -18,9 +18,10 @@ namespace JetHerald
return null; return null;
var msg = messageEventArgs.Message; var msg = messageEventArgs.Message;
var chatid = msg.Chat.Id; var chat = NamespacedId.Telegram(msg.Chat.Id);
var topicName = cmd.Parameters[0]; var topicName = cmd.Parameters[0];
int affected = await db.RemoveSubscription(topicName, chatid, "Telegram"); int affected = await db.RemoveSubscription(topicName, chat);
if (affected >= 1) if (affected >= 1)
return $"unsubscribed from {topicName}"; return $"unsubscribed from {topicName}";
else else

View File

@ -13,8 +13,7 @@ namespace JetHerald
public class Topic public class Topic
{ {
public uint TopicId { get; set; } public uint TopicId { get; set; }
public long CreatorId { get; set; } public NamespacedId Creator { get; set; }
public string CreatorService { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string ReadToken { get; set; } public string ReadToken { get; set; }
@ -23,8 +22,7 @@ namespace JetHerald
public DateTime? ExpiryTime { get; set; } public DateTime? ExpiryTime { get; set; }
public bool ExpiryMessageSent { get; set; } public bool ExpiryMessageSent { get; set; }
public long? ChatId { get; set; } public NamespacedId? Chat { get; set; }
public string Service { get; set; }
public override string ToString() public override string ToString()
=> Name == Description ? Name : $"{Name}: {Description}"; => Name == Description ? Name : $"{Name}: {Description}";
@ -32,18 +30,11 @@ namespace JetHerald
public class ExpiredTopicChat public class ExpiredTopicChat
{ {
public long ChatId; public NamespacedId Chat;
public string Service;
public string Description; public string Description;
public DateTime ExpiryTime { get; set; } public DateTime ExpiryTime { get; set; }
} }
public class ChatData
{
public long ChatId;
public string Service;
}
public async Task<int> DeleteTopic(string name, string adminToken) public async Task<int> DeleteTopic(string name, string adminToken)
{ {
using (var c = GetConnection()) using (var c = GetConnection())
@ -66,81 +57,78 @@ namespace JetHerald
new { name }); new { name });
} }
public async Task<Topic> GetTopic(string token, long chatId, string service) public async Task<Topic> GetTopicForSub(string token, NamespacedId chat)
{ {
using (var c = GetConnection()) using var c = GetConnection();
return await c.QuerySingleOrDefaultAsync<Topic>( return await c.QuerySingleOrDefaultAsync<Topic>(
" SELECT t.*, tc.ChatId " + " SELECT t.*, tc.Chat " +
" FROM topic t " + " FROM topic t " +
" LEFT JOIN topic_chat tc ON t.TopicId = tc.TopicId AND tc.ChatId = @chatId AND tc.Service = @service " + " LEFT JOIN topic_chat tc ON t.TopicId = tc.TopicId AND tc.Chat = @chat " +
" WHERE ReadToken = @token", " WHERE ReadToken = @token",
new { token, chatId, service }); new { token, chat });
} }
public async Task<Topic> CreateTopic(long userId, string service, string name, string descr) public async Task<Topic> CreateTopic(NamespacedId user, string name, string descr)
{ {
var t = new Topic var t = new Topic
{ {
CreatorId = userId, Creator = user,
Name = name, Name = name,
Description = descr, Description = descr,
ReadToken = TokenHelper.GetToken(), ReadToken = TokenHelper.GetToken(),
WriteToken = TokenHelper.GetToken(), WriteToken = TokenHelper.GetToken(),
AdminToken = TokenHelper.GetToken(), AdminToken = TokenHelper.GetToken()
Service = service
}; };
using (var c = GetConnection()) using var c = GetConnection();
{ return await c.QuerySingleOrDefaultAsync<Topic>(
return await c.QuerySingleOrDefaultAsync<Topic>(
" INSERT INTO herald.topic " + " INSERT INTO herald.topic " +
" ( CreatorId, Name, Description, ReadToken, WriteToken, AdminToken, Service) " + " ( Creator, Name, Description, ReadToken, WriteToken, AdminToken) " +
" VALUES " + " VALUES " +
" (@CreatorId, @Name, @Description, @ReadToken, @WriteToken, @AdminToken, @Service); " + " (@Creator, @Name, @Description, @ReadToken, @WriteToken, @AdminToken); " +
" SELECT * FROM topic WHERE TopicId = LAST_INSERT_ID(); ", " SELECT * FROM topic WHERE TopicId = LAST_INSERT_ID(); ",
t); t);
}
} }
public async Task<IEnumerable<ChatData>> GetChatIdsForTopic(uint topicid) public async Task<IEnumerable<NamespacedId>> GetChatsForTopic(uint topicid)
{ {
using (var c = GetConnection()) using var c = GetConnection();
return await c.QueryAsync<ChatData>( return await c.QueryAsync<NamespacedId>(
" SELECT ChatId, Service" + " SELECT Chat " +
" FROM topic_chat" + " FROM topic_chat " +
" WHERE TopicId = @topicid", " WHERE TopicId = @topicid",
new { topicid }); new { topicid });
} }
public async Task<IEnumerable<Topic>> GetTopicsForChat(long chatid, string service) public async Task<IEnumerable<Topic>> GetTopicsForChat(NamespacedId chat)
{ {
using (var c = GetConnection()) using var c = GetConnection();
return await c.QueryAsync<Topic>( return await c.QueryAsync<Topic>(
" SELECT t.*" + " SELECT t.*" +
" FROM topic_chat ct" + " FROM topic_chat ct" +
" JOIN topic t on t.TopicId = ct.TopicId" + " JOIN topic t on t.TopicId = ct.TopicId" +
" WHERE ct.ChatId = @chatid AND ct.Service = @service", " WHERE ct.Chat = @chat",
new { chatid, service }); new { chat });
} }
public async Task CreateSubscription(uint topicId, long chatId, string service) public async Task CreateSubscription(uint topicId, NamespacedId chat)
{ {
using (var c = GetConnection()) using var c = GetConnection();
await c.ExecuteAsync( await c.ExecuteAsync(
" INSERT INTO topic_chat" + " INSERT INTO topic_chat" +
" (ChatId, TopicId, Service)" + " (Chat, TopicId)" +
" VALUES" + " VALUES" +
" (@chatId, @topicId, @service)", " (@chat, @topicId)",
new { topicId, chatId, service }); new { topicId, chat });
} }
public async Task<int> RemoveSubscription(string topicName, long chatId, string service) public async Task<int> RemoveSubscription(string topicName, NamespacedId chat)
{ {
using (var c = GetConnection()) using var c = GetConnection();
return await c.ExecuteAsync( return await c.ExecuteAsync(
" DELETE tc " + " DELETE tc " +
" FROM topic_chat tc" + " FROM topic_chat tc" +
" JOIN topic t ON tc.TopicId = t.TopicId " + " JOIN topic t ON tc.TopicId = t.TopicId " +
" WHERE t.Name = @topicName AND tc.ChatId = @chatId AND tc.Service = @service;", " WHERE t.Name = @topicName AND tc.Chat = @chat;",
new { topicName, chatId, service }); new { topicName, chat });
} }
public Task AddExpiry(string topicName, int addedTime) public Task AddExpiry(string topicName, int addedTime)
@ -154,17 +142,6 @@ namespace JetHerald
new { topicName, addedTime }); new { topicName, addedTime });
} }
public Task DisableExpiry(string name, string adminToken)
{
using var c = GetConnection();
return c.ExecuteAsync(
" UPDATE topic" +
" SET ExpiryTime = NULL," +
" ExpiryMessageSent = 0" +
" WHERE Name = @name AND AdminToken = @adminToken",
new { name, adminToken });
}
public Task<IEnumerable<ExpiredTopicChat>> GetExpiredTopics(CancellationToken token = default) public Task<IEnumerable<ExpiredTopicChat>> GetExpiredTopics(CancellationToken token = default)
{ {
using var c = GetConnection(); using var c = GetConnection();

View File

@ -30,9 +30,10 @@ namespace JetHerald
} }
private async Task SendMessageToDiscordChannel(long chatId, string formatted) async Task SendMessageToDiscordChannel(NamespacedId chat, string formatted)
{ {
await DiscordBot.SendMessageAsync(await DiscordBot.GetChannelAsync((ulong)chatId), formatted); var id = ulong.Parse(chat.Id);
await DiscordBot.SendMessageAsync(await DiscordBot.GetChannelAsync(id), formatted);
} }
} }
} }

View File

@ -92,13 +92,7 @@ namespace JetHerald
try try
{ {
foreach (var chatSent in await Db.GetExpiredTopics(token)) foreach (var chatSent in await Db.GetExpiredTopics(token))
{ await SendMessageImpl(chatSent.Chat, $"!{chatSent.Description}!:\nTimeout expired at {chatSent.ExpiryTime}");
var formatted = $"!{chatSent.Description}!:\nTimeout expired at {chatSent.ExpiryTime}";
if (chatSent.Service == "Telegram")
await TelegramBot.SendTextMessageAsync(chatSent.ChatId, formatted, cancellationToken: token);
else if (chatSent.Service == "Discord")
await SendMessageToDiscordChannel(chatSent.ChatId, formatted);
}
await Db.MarkExpiredTopics(token); await Db.MarkExpiredTopics(token);
} }
@ -109,30 +103,33 @@ namespace JetHerald
} }
} }
public async Task HeartbeatSent(Db.Topic topic) public Task HeartbeatSent(Db.Topic topic)
=> BroadcastMessageImpl(topic, $"!{topic.Description}!:\nA heartbeat has been sent.");
public Task PublishMessage(Db.Topic topic, string message)
=> BroadcastMessageImpl(topic, $"|{topic.Description}|:\n{message}");
async Task BroadcastMessageImpl(Db.Topic topic, string formatted)
{ {
var chatIds = await Db.GetChatIdsForTopic(topic.TopicId); var chatIds = await Db.GetChatsForTopic(topic.TopicId);
var formatted = $"!{topic.Description}!:\nA heartbeat has been sent.";
foreach (var c in chatIds) foreach (var c in chatIds)
{ await SendMessageImpl(c, formatted);
if (c.Service == "Telegram")
await TelegramBot.SendTextMessageAsync(c.ChatId, formatted);
else if (c.Service == "Discord")
await SendMessageToDiscordChannel(c.ChatId, formatted);
}
} }
public async Task PublishMessage(Db.Topic topic, string message) async Task SendMessageImpl(NamespacedId chat, string formatted)
{ {
var chatIds = await Db.GetChatIdsForTopic(topic.TopicId); try
var formatted = $"|{topic.Description}|:\n{message}";
foreach (var c in chatIds)
{ {
if (c.Service == "Telegram") if (chat.Namespace == "telegram")
await TelegramBot.SendTextMessageAsync(c.ChatId, formatted); {
else if (c.Service == "Discord") await TelegramBot.SendTextMessageAsync(long.Parse(chat.Id), formatted);
await SendMessageToDiscordChannel(c.ChatId, formatted); }
else if (chat.Namespace == "discord")
{
await SendMessageToDiscordChannel(chat, formatted);
}
} }
catch (Exception e) { Log.LogError(e, $"Error while sending message \"{formatted}\" to {chat}"); }
} }
async void BotOnMessageReceived(object sender, MessageEventArgs messageEventArgs) async void BotOnMessageReceived(object sender, MessageEventArgs messageEventArgs)