mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-12 02:08:27 -04:00
Restructured the project structure back to the way it was, there's no reasonable way to split the modules
This commit is contained in:
8
src/NadekoBot/Modules/Utility/Todo/ArchiveTodoResult.cs
Normal file
8
src/NadekoBot/Modules/Utility/Todo/ArchiveTodoResult.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace NadekoBot.Modules.Utility;
|
||||
|
||||
public enum ArchiveTodoResult
|
||||
{
|
||||
MaxLimitReached,
|
||||
NoTodos,
|
||||
Success
|
||||
}
|
7
src/NadekoBot/Modules/Utility/Todo/TodoAddResult.cs
Normal file
7
src/NadekoBot/Modules/Utility/Todo/TodoAddResult.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace NadekoBot.Modules.Utility;
|
||||
|
||||
public enum TodoAddResult
|
||||
{
|
||||
MaxLimitReached,
|
||||
Success
|
||||
}
|
206
src/NadekoBot/Modules/Utility/Todo/TodoCommands.cs
Normal file
206
src/NadekoBot/Modules/Utility/Todo/TodoCommands.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
182
src/NadekoBot/Modules/Utility/Todo/TodoService.cs
Normal file
182
src/NadekoBot/Modules/Utility/Todo/TodoService.cs
Normal 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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user