Restructured the project structure back to the way it was, there's no reasonable way to split the modules

This commit is contained in:
Kwoth
2024-04-26 22:26:24 +00:00
parent 6c9c8bf63e
commit e0819f760c
768 changed files with 192 additions and 1047 deletions

View File

@@ -0,0 +1,8 @@
namespace NadekoBot.Modules.Utility;
public enum ArchiveTodoResult
{
MaxLimitReached,
NoTodos,
Success
}

View File

@@ -0,0 +1,7 @@
namespace NadekoBot.Modules.Utility;
public enum TodoAddResult
{
MaxLimitReached,
Success
}

View File

@@ -0,0 +1,206 @@
using NadekoBot.Db.Models;
namespace NadekoBot.Modules.Utility;
public partial class Utility
{
[Group("todo")]
public partial class Todo : NadekoModule<TodoService>
{
[Cmd]
public async Task TodoAdd([Leftover] string todo)
{
var result = await _service.AddAsync(ctx.User.Id, todo);
if (result == TodoAddResult.MaxLimitReached)
{
await ReplyErrorLocalizedAsync(strs.todo_add_max_limit);
return;
}
await ctx.OkAsync();
}
[Cmd]
public async Task TodoEdit(kwum todoId, [Leftover] string newMessage)
{
if (!await _service.EditAsync(ctx.User.Id, todoId, newMessage))
{
await ReplyErrorLocalizedAsync(strs.todo_not_found);
return;
}
await ctx.OkAsync();
}
[Cmd]
public async Task TodoList()
{
var todos = await _service.GetAllTodosAsync(ctx.User.Id);
if (todos.Length == 0)
{
await ReplyErrorLocalizedAsync(strs.todo_list_empty);
return;
}
await ShowTodosAsync(todos);
}
[Cmd]
public async Task TodoComplete(kwum todoId)
{
if (!await _service.CompleteTodoAsync(ctx.User.Id, todoId))
{
await ReplyErrorLocalizedAsync(strs.todo_not_found);
return;
}
await ctx.OkAsync();
}
[Cmd]
public async Task TodoDelete(kwum todoId)
{
if (!await _service.DeleteTodoAsync(ctx.User.Id, todoId))
{
await ReplyErrorLocalizedAsync(strs.todo_not_found);
return;
}
await ctx.OkAsync();
}
[Cmd]
public async Task TodoClear()
{
await _service.ClearTodosAsync(ctx.User.Id);
await ReplyConfirmLocalizedAsync(strs.todo_cleared);
}
private async Task ShowTodosAsync(TodoModel[] todos)
{
await ctx.SendPaginatedConfirmAsync(0,
(curPage) =>
{
var eb = _eb.Create()
.WithOkColor()
.WithTitle(GetText(strs.todo_list));
ShowTodoItem(todos, curPage, eb);
return eb;
},
todos.Length,
9);
}
private static void ShowTodoItem(IReadOnlyCollection<TodoModel> todos, int curPage, IEmbedBuilder eb)
{
foreach (var todo in todos.Skip(curPage * 9).Take(9))
{
// green circle and yellow circle emojis
eb.AddField($"-",
$"{(todo.IsDone
? ""
: "🟡")} {Format.Code(new kwum(todo.Id).ToString())} {todo.Todo}",
false);
}
}
[Group("archive")]
public partial class ArchiveCommands : NadekoModule<TodoService>
{
[Cmd]
public async Task TodoArchiveAdd([Leftover] string name)
{
var result = await _service.ArchiveTodosAsync(ctx.User.Id, name);
if (result == ArchiveTodoResult.NoTodos)
{
await ReplyErrorLocalizedAsync(strs.todo_no_todos);
return;
}
if (result == ArchiveTodoResult.MaxLimitReached)
{
await ReplyErrorLocalizedAsync(strs.todo_archive_max_limit);
return;
}
await ctx.OkAsync();
}
[Cmd]
public async Task TodoArchiveList(int page = 1)
{
if (--page < 0)
return;
var archivedTodoLists = await _service.GetArchivedTodosAsync(ctx.User.Id);
if (archivedTodoLists.Count == 0)
{
await ReplyErrorLocalizedAsync(strs.todo_archive_empty);
return;
}
await ctx.SendPaginatedConfirmAsync(page,
(curPage) =>
{
var eb = _eb.Create()
.WithTitle(GetText(strs.todo_archive_list))
.WithOkColor();
foreach (var archivedList in archivedTodoLists.Skip(curPage * 9).Take(9))
{
eb.AddField($"id: {archivedList.Id.ToString()}", archivedList.Name, true);
}
return eb;
},
archivedTodoLists.Count,
9,
true);
}
[Cmd]
public async Task TodoArchiveShow(int id)
{
var list = await _service.GetArchivedTodoListAsync(ctx.User.Id, id);
if (list == null || list.Items.Count == 0)
{
await ReplyErrorLocalizedAsync(strs.todo_archive_not_found);
return;
}
await ctx.SendPaginatedConfirmAsync(0,
(curPage) =>
{
var eb = _eb.Create()
.WithOkColor()
.WithTitle(GetText(strs.todo_list));
ShowTodoItem(list.Items, curPage, eb);
return eb;
},
list.Items.Count,
9);
}
[Cmd]
public async Task TodoArchiveDelete(int id)
{
if (!await _service.ArchiveDeleteAsync(ctx.User.Id, id))
{
await ctx.ErrorAsync();
return;
}
await ctx.OkAsync();
}
}
}
}

View File

@@ -0,0 +1,182 @@
using LinqToDB;
using LinqToDB.EntityFrameworkCore;
using NadekoBot.Db.Models;
namespace NadekoBot.Modules.Utility;
public sealed class TodoService
{
private const int ARCHIVE_MAX_COUNT = 9;
private const int TODO_MAX_COUNT = 27;
private readonly DbService _db;
public TodoService(DbService db)
{
_db = db;
}
public async Task<TodoAddResult> AddAsync(ulong userId, string todo)
{
await using var ctx = _db.GetDbContext();
if (await ctx
.GetTable<TodoModel>()
.Where(x => x.UserId == userId && x.ArchiveId == null)
.CountAsync() >= TODO_MAX_COUNT)
{
return TodoAddResult.MaxLimitReached;
}
await ctx
.GetTable<TodoModel>()
.InsertAsync(() => new TodoModel()
{
UserId = userId,
Todo = todo,
DateAdded = DateTime.UtcNow,
IsDone = false,
});
return TodoAddResult.Success;
}
public async Task<bool> EditAsync(ulong userId, int todoId, string newMessage)
{
await using var ctx = _db.GetDbContext();
return await ctx
.GetTable<TodoModel>()
.Where(x => x.UserId == userId && x.Id == todoId)
.Set(x => x.Todo, newMessage)
.UpdateAsync() > 0;
}
public async Task<TodoModel[]> GetAllTodosAsync(ulong userId)
{
await using var ctx = _db.GetDbContext();
return await ctx
.GetTable<TodoModel>()
.Where(x => x.UserId == userId && x.ArchiveId == null)
.ToArrayAsyncLinqToDB();
}
public async Task<bool> CompleteTodoAsync(ulong userId, int todoId)
{
await using var ctx = _db.GetDbContext();
var count = await ctx
.GetTable<TodoModel>()
.Where(x => x.UserId == userId && x.Id == todoId)
.Set(x => x.IsDone, true)
.UpdateAsync();
return count > 0;
}
public async Task<bool> DeleteTodoAsync(ulong userId, int todoId)
{
await using var ctx = _db.GetDbContext();
var count = await ctx
.GetTable<TodoModel>()
.Where(x => x.UserId == userId && x.Id == todoId)
.DeleteAsync();
return count > 0;
}
public async Task ClearTodosAsync(ulong userId)
{
await using var ctx = _db.GetDbContext();
await ctx
.GetTable<TodoModel>()
.Where(x => x.UserId == userId && x.ArchiveId == null)
.DeleteAsync();
}
public async Task<ArchiveTodoResult> ArchiveTodosAsync(ulong userId, string name)
{
// create a new archive
await using var ctx = _db.GetDbContext();
await using var tr = await ctx.Database.BeginTransactionAsync();
// check if the user reached the limit
var count = await ctx
.GetTable<ArchivedTodoListModel>()
.Where(x => x.UserId == userId)
.CountAsync();
if (count >= ARCHIVE_MAX_COUNT)
return ArchiveTodoResult.MaxLimitReached;
var inserted = await ctx
.GetTable<ArchivedTodoListModel>()
.InsertWithOutputAsync(() => new ArchivedTodoListModel()
{
UserId = userId,
Name = name,
});
// mark all existing todos as archived
var updated = await ctx
.GetTable<TodoModel>()
.Where(x => x.UserId == userId && x.ArchiveId == null)
.Set(x => x.ArchiveId, inserted.Id)
.UpdateAsync();
if (updated == 0)
{
await tr.RollbackAsync();
// // delete the empty archive
// await ctx
// .GetTable<ArchivedTodoListModel>()
// .Where(x => x.Id == inserted.Id)
// .DeleteAsync();
return ArchiveTodoResult.NoTodos;
}
await tr.CommitAsync();
return ArchiveTodoResult.Success;
}
public async Task<IReadOnlyCollection<ArchivedTodoListModel>> GetArchivedTodosAsync(ulong userId)
{
await using var ctx = _db.GetDbContext();
return await ctx
.GetTable<ArchivedTodoListModel>()
.Where(x => x.UserId == userId)
.ToArrayAsyncLinqToDB();
}
public async Task<ArchivedTodoListModel?> GetArchivedTodoListAsync(ulong userId, int archiveId)
{
await using var ctx = _db.GetDbContext();
return await ctx
.GetTable<ArchivedTodoListModel>()
.Where(x => x.UserId == userId && x.Id == archiveId)
.LoadWith(x => x.Items)
.FirstOrDefaultAsyncLinqToDB();
}
public async Task<bool> ArchiveDeleteAsync(ulong userId, int archiveId)
{
await using var ctx = _db.GetDbContext();
var count = await ctx
.GetTable<ArchivedTodoListModel>()
.Where(x => x.UserId == userId && x.Id == archiveId)
.DeleteAsync();
return count > 0;
}
}