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)
return null;
var msg = messageEventArgs.Message;
var chatid = msg.Chat.Id;
if (msg.Chat.Type != ChatType.Private)
return null;
@ -32,7 +31,7 @@ namespace JetHerald.Commands
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" +
$"readToken\n{topic.ReadToken}\n" +
$"writeToken\n{topic.WriteToken}\n" +

View File

@ -18,7 +18,6 @@ namespace JetHerald.Commands
if (cmd.Parameters.Length < 2)
return null;
var msg = messageEventArgs.Message;
var chatid = msg.Chat.Id;
if (msg.Chat.Type != ChatType.Private)
return null;
@ -26,8 +25,11 @@ namespace JetHerald.Commands
string name = cmd.Parameters[0];
string adminToken = cmd.Parameters[1];
var topic = await db.DeleteTopic(name, adminToken);
return $"deleted {name} and all its subscriptions";
var changed = await db.DeleteTopic(name, adminToken);
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)]
public class DiscordCommands : BaseCommandModule
{
public Db db { private get; set; }
public Db Db { get; set; }
[Command("createtopic")]
[Description("Creates a topic.")]
@ -28,7 +28,7 @@ namespace JetHerald
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" +
$"readToken\n{topic.ReadToken}\n" +
$"writeToken\n{topic.WriteToken}\n" +
@ -51,7 +51,7 @@ namespace JetHerald
string adminToken)
{
_ = ctx.TriggerTypingAsync();
var changed = await db.DeleteTopic(name, adminToken);
var changed = await Db.DeleteTopic(name, adminToken);
if (changed > 0)
await ctx.RespondAsync($"deleted {name} and all its subscriptions");
else
@ -64,7 +64,7 @@ namespace JetHerald
{
_ = 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()
? "Topics:\n" + string.Join("\n", topics)
@ -81,17 +81,18 @@ namespace JetHerald
{
_ = 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)
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}");
else if (topic.ReadToken != token)
await ctx.RespondAsync("token mismatch");
else
{
await db.CreateSubscription(topic.TopicId, (long)ctx.Channel.Id, "Discord");
await Db.CreateSubscription(topic.TopicId, chat);
await ctx.RespondAsync($"subscribed to {topic.Name}");
}
}
@ -106,7 +107,7 @@ namespace JetHerald
{
_ = 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)
await ctx.RespondAsync($"unsubscribed from {name}");
else

View File

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

View File

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

View File

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

View File

@ -13,8 +13,7 @@ namespace JetHerald
public class Topic
{
public uint TopicId { get; set; }
public long CreatorId { get; set; }
public string CreatorService { get; set; }
public NamespacedId Creator { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string ReadToken { get; set; }
@ -23,8 +22,7 @@ namespace JetHerald
public DateTime? ExpiryTime { get; set; }
public bool ExpiryMessageSent { get; set; }
public long? ChatId { get; set; }
public string Service { get; set; }
public NamespacedId? Chat { get; set; }
public override string ToString()
=> Name == Description ? Name : $"{Name}: {Description}";
@ -32,18 +30,11 @@ namespace JetHerald
public class ExpiredTopicChat
{
public long ChatId;
public string Service;
public NamespacedId Chat;
public string Description;
public DateTime ExpiryTime { get; set; }
}
public class ChatData
{
public long ChatId;
public string Service;
}
public async Task<int> DeleteTopic(string name, string adminToken)
{
using (var c = GetConnection())
@ -66,81 +57,78 @@ namespace JetHerald
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>(
" SELECT t.*, tc.ChatId " +
" SELECT t.*, tc.Chat " +
" 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",
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
{
CreatorId = userId,
Creator = user,
Name = name,
Description = descr,
ReadToken = TokenHelper.GetToken(),
WriteToken = TokenHelper.GetToken(),
AdminToken = TokenHelper.GetToken(),
Service = service
AdminToken = TokenHelper.GetToken()
};
using (var c = GetConnection())
{
using var c = GetConnection();
return await c.QuerySingleOrDefaultAsync<Topic>(
" INSERT INTO herald.topic " +
" ( CreatorId, Name, Description, ReadToken, WriteToken, AdminToken, Service) " +
" ( Creator, Name, Description, ReadToken, WriteToken, AdminToken) " +
" VALUES " +
" (@CreatorId, @Name, @Description, @ReadToken, @WriteToken, @AdminToken, @Service); " +
" (@Creator, @Name, @Description, @ReadToken, @WriteToken, @AdminToken); " +
" SELECT * FROM topic WHERE TopicId = LAST_INSERT_ID(); ",
t);
}
}
public async Task<IEnumerable<ChatData>> GetChatIdsForTopic(uint topicid)
public async Task<IEnumerable<NamespacedId>> GetChatsForTopic(uint topicid)
{
using (var c = GetConnection())
return await c.QueryAsync<ChatData>(
" SELECT ChatId, Service" +
using var c = GetConnection();
return await c.QueryAsync<NamespacedId>(
" SELECT Chat " +
" FROM topic_chat " +
" WHERE TopicId = @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>(
" SELECT t.*" +
" FROM topic_chat ct" +
" JOIN topic t on t.TopicId = ct.TopicId" +
" WHERE ct.ChatId = @chatid AND ct.Service = @service",
new { chatid, service });
" WHERE ct.Chat = @chat",
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(
" INSERT INTO topic_chat" +
" (ChatId, TopicId, Service)" +
" (Chat, TopicId)" +
" VALUES" +
" (@chatId, @topicId, @service)",
new { topicId, chatId, service });
" (@chat, @topicId)",
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(
" DELETE tc " +
" FROM topic_chat tc" +
" JOIN topic t ON tc.TopicId = t.TopicId " +
" WHERE t.Name = @topicName AND tc.ChatId = @chatId AND tc.Service = @service;",
new { topicName, chatId, service });
" WHERE t.Name = @topicName AND tc.Chat = @chat;",
new { topicName, chat });
}
public Task AddExpiry(string topicName, int addedTime)
@ -154,17 +142,6 @@ namespace JetHerald
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)
{
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
{
foreach (var chatSent in await Db.GetExpiredTopics(token))
{
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 SendMessageImpl(chatSent.Chat, $"!{chatSent.Description}!:\nTimeout expired at {chatSent.ExpiryTime}");
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 formatted = $"!{topic.Description}!:\nA heartbeat has been sent.";
var chatIds = await Db.GetChatsForTopic(topic.TopicId);
foreach (var c in chatIds)
{
if (c.Service == "Telegram")
await TelegramBot.SendTextMessageAsync(c.ChatId, formatted);
else if (c.Service == "Discord")
await SendMessageToDiscordChannel(c.ChatId, formatted);
}
await SendMessageImpl(c, formatted);
}
public async Task PublishMessage(Db.Topic topic, string message)
async Task SendMessageImpl(NamespacedId chat, string formatted)
{
var chatIds = await Db.GetChatIdsForTopic(topic.TopicId);
var formatted = $"|{topic.Description}|:\n{message}";
foreach (var c in chatIds)
try
{
if (c.Service == "Telegram")
await TelegramBot.SendTextMessageAsync(c.ChatId, formatted);
else if (c.Service == "Discord")
await SendMessageToDiscordChannel(c.ChatId, formatted);
if (chat.Namespace == "telegram")
{
await TelegramBot.SendTextMessageAsync(long.Parse(chat.Id), 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)