diff --git a/JetHerald/Commands/CreateTopicCommand.cs b/JetHerald/Commands/CreateTopicCommand.cs index 351f43a..58cf14c 100644 --- a/JetHerald/Commands/CreateTopicCommand.cs +++ b/JetHerald/Commands/CreateTopicCommand.cs @@ -27,13 +27,24 @@ public class CreateTopicCommand : IChatCommand if (cmd.Parameters.Length > 1) descr = string.Join(' ', cmd.Parameters.Skip(1)); + var user = await Db.GetUser(NamespacedId.Telegram(msg.From.Id)); + + if (user == null) return null; + try { - 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" + - $"adminToken\n{topic.AdminToken}\n"; + var topic = await Db.CreateTopic(user.UserId, name, descr); + + if (topic == null) + { + return "you have reached the limit of topics"; + } + else + { + return $"created {topic.Name}\n" + + $"readToken\n{topic.ReadToken}\n" + + $"writeToken\n{topic.WriteToken}\n"; + } } catch (MySqlException myDuplicate) when (myDuplicate.Number == 1062) { diff --git a/JetHerald/Commands/DeleteTopicCommand.cs b/JetHerald/Commands/DeleteTopicCommand.cs index 60e8693..feb5e21 100644 --- a/JetHerald/Commands/DeleteTopicCommand.cs +++ b/JetHerald/Commands/DeleteTopicCommand.cs @@ -14,7 +14,7 @@ public class DeleteTopicCommand : IChatCommand public async Task Execute(CommandString cmd, Update update) { - if (cmd.Parameters.Length < 2) + if (cmd.Parameters.Length < 1) return null; var msg = update.Message; @@ -22,13 +22,16 @@ public class DeleteTopicCommand : IChatCommand return null; string name = cmd.Parameters[0]; - string adminToken = cmd.Parameters[1]; - var changed = await Db.DeleteTopic(name, adminToken); + var user = await Db.GetUser(NamespacedId.Telegram(msg.From.Id)); + + if (user == null) return null; + + var changed = await Db.DeleteTopic(name, user.UserId); if (changed > 0) - return ($"deleted {name} and all its subscriptions"); + return $"deleted {name} and all its subscriptions"; else - return ($"invalid topic name or admin token"); + return $"invalid topic name"; } } diff --git a/JetHerald/Contracts/IDb.cs b/JetHerald/Contracts/IDb.cs index 91b931d..7bc27c7 100644 --- a/JetHerald/Contracts/IDb.cs +++ b/JetHerald/Contracts/IDb.cs @@ -1,14 +1,13 @@ namespace JetHerald.Contracts; - + public class Topic { public uint TopicId { get; set; } - public NamespacedId Creator { get; set; } + public uint CreatorId { get; set; } public string Name { get; set; } public string Description { get; set; } public string ReadToken { get; set; } public string WriteToken { get; set; } - public string AdminToken { get; set; } public NamespacedId? Sub { get; set; } @@ -25,3 +24,13 @@ public class HeartEvent public string Description { get; set; } } + +public class User +{ + public uint UserId { get; set; } + public NamespacedId? ForeignId { get; set; } + public uint PlanId { get; set; } + + public int? MaxTopics { get; set; } + public int? TimeoutMultiplier { get; set; } +} diff --git a/JetHerald/Services/Db.cs b/JetHerald/Services/Db.cs index 9fa9720..3b635cc 100644 --- a/JetHerald/Services/Db.cs +++ b/JetHerald/Services/Db.cs @@ -6,14 +6,15 @@ using JetHerald.Contracts; namespace JetHerald.Services; public class Db { - public async Task DeleteTopic(string name, string adminToken) + public async Task DeleteTopic(string name, uint userId) { using var c = GetConnection(); return await c.ExecuteAsync( - " DELETE" + - " FROM topic" + - " WHERE Name = @name AND AdminToken = @adminToken", - new { name, adminToken }); + " DELETE t" + + " FROM topic t" + + " LEFT JOIN user u ON t.CreatorId = u.UserId" + + " WHERE t.Name = @name AND u.UserId = @userId", + new { name, userId }); } public async Task GetTopic(string name) @@ -37,24 +38,59 @@ public class Db new { token, sub }); } - public async Task CreateTopic(NamespacedId user, string name, string descr) + public async Task GetUser(NamespacedId foreignId) { using var c = GetConnection(); - return await c.QuerySingleOrDefaultAsync( + return await c.QuerySingleOrDefaultAsync( + " SELECT u.*, p.* " + + " FROM user u " + + " LEFT JOIN plan p ON p.PlanId = u.PlanId " + + " WHERE u.ForeignId = @foreignId", + new { foreignId }); + } + + public async Task CreateTopic(uint user, string name, string descr) + { + using var c = GetConnection(); + + await c.OpenAsync(); + + await using var tx = await c.BeginTransactionAsync(); + + var topicsCount = await c.QuerySingleAsync( + " SELECT COUNT(t.TopicId) " + + " FROM user u " + + " LEFT JOIN topic t ON t.CreatorId = u.UserId ", + transaction: tx + ); + + var planTopicsCount = await c.QuerySingleAsync( + " SELECT p.MaxTopics " + + " FROM user u " + + " LEFT JOIN plan p ON p.PlanId = u.PlanId ", + transaction: tx + ); + + if (topicsCount >= planTopicsCount) return null; + + var topic = await c.QuerySingleOrDefaultAsync( " INSERT INTO topic " + - " ( Creator, Name, Description, ReadToken, WriteToken, AdminToken) " + + " ( CreatorId, Name, Description, ReadToken, WriteToken) " + " VALUES " + - " (@Creator, @Name, @Description, @ReadToken, @WriteToken, @AdminToken); " + + " (@CreatorId, @Name, @Description, @ReadToken, @WriteToken); " + " SELECT * FROM topic WHERE TopicId = LAST_INSERT_ID(); ", new Topic { - Creator = user, + CreatorId = user, Name = name, Description = descr, ReadToken = TokenHelper.GetToken(), - WriteToken = TokenHelper.GetToken(), - AdminToken = TokenHelper.GetToken() - }); + WriteToken = TokenHelper.GetToken() + }, transaction: tx); + + await tx.CommitAsync(); + + return topic; } public async Task> GetSubsForTopic(uint topicId) { diff --git a/JetHerald/Services/DiscordCommands.cs b/JetHerald/Services/DiscordCommands.cs index 90090ce..8e531ee 100644 --- a/JetHerald/Services/DiscordCommands.cs +++ b/JetHerald/Services/DiscordCommands.cs @@ -24,13 +24,24 @@ public class DiscordCommands : BaseCommandModule _ = ctx.TriggerTypingAsync(); + var user = await Db.GetUser(NamespacedId.Discord(ctx.User.Id)); + + if (user == null) return; + try { - 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" + - $"adminToken\n{topic.AdminToken}\n"); + var topic = await Db.CreateTopic(user.UserId, name, description); + + if (topic == null) + { + await ctx.RespondAsync("you have reached the limit of topics"); + } + else + { + await ctx.RespondAsync($"created {topic.Name}\n" + + $"readToken\n{topic.ReadToken}\n" + + $"writeToken\n{topic.WriteToken}\n"); + } } catch (MySqlException myDuplicate) when (myDuplicate.Number == 1062) { @@ -44,16 +55,19 @@ public class DiscordCommands : BaseCommandModule public async Task DeleteTopic( CommandContext ctx, [Description("The name of the topic to be deleted.")] - string name, - [Description("The admin token of the topic to be deleted.")] - string adminToken) + string name) { _ = ctx.TriggerTypingAsync(); - var changed = await Db.DeleteTopic(name, adminToken); + + var user = await Db.GetUser(NamespacedId.Discord(ctx.User.Id)); + + if (user == null) return; + + var changed = await Db.DeleteTopic(name, user.UserId); if (changed > 0) await ctx.RespondAsync($"deleted {name} and all its subscriptions"); else - await ctx.RespondAsync($"invalid topic name or admin token"); + await ctx.RespondAsync($"invalid topic name"); } [Command("list")]