mirror of
				https://gitlab.com/Kwoth/nadekobot.git
				synced 2025-11-03 16:24:27 -05:00 
			
		
		
		
	Merge branch 'force-add' into 'v4'
Implemented command to force users into the database, closes #425 Closes #425 See merge request Kwoth/nadekobot!312
This commit is contained in:
		@@ -4,11 +4,60 @@ using LinqToDB.EntityFrameworkCore;
 | 
				
			|||||||
using Microsoft.EntityFrameworkCore;
 | 
					using Microsoft.EntityFrameworkCore;
 | 
				
			||||||
using NadekoBot.Db.Models;
 | 
					using NadekoBot.Db.Models;
 | 
				
			||||||
using NadekoBot.Services.Database;
 | 
					using NadekoBot.Services.Database;
 | 
				
			||||||
 | 
					using System.Collections.Immutable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace NadekoBot.Db;
 | 
					namespace NadekoBot.Db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public static class DiscordUserExtensions
 | 
					public static class DiscordUserExtensions
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Adds the specified <paramref name="users"/> to the database. If a database user with placeholder name
 | 
				
			||||||
 | 
					    /// and discriminator is present in <paramref name="users"/>, their name and discriminator get updated accordingly.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="ctx">This database context.</param>
 | 
				
			||||||
 | 
					    /// <param name="users">The users to add or update in the database.</param>
 | 
				
			||||||
 | 
					    /// <returns>A tuple with the amount of new users added and old users updated.</returns>
 | 
				
			||||||
 | 
					    public static async Task<(long UsersAdded, long UsersUpdated)> RefreshUsersAsync(this NadekoContext ctx, List<IUser> users)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var presentDbUsers = await ctx.DiscordUser
 | 
				
			||||||
 | 
					            .Select(x => new { x.UserId, x.Username, x.Discriminator })
 | 
				
			||||||
 | 
					            .Where(x => users.Select(y => y.Id).Contains(x.UserId))
 | 
				
			||||||
 | 
					            .ToArrayAsyncEF();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var usersToAdd = users
 | 
				
			||||||
 | 
					            .Where(x => !presentDbUsers.Select(x => x.UserId).Contains(x.Id))
 | 
				
			||||||
 | 
					            .Select(x => new DiscordUser()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                UserId = x.Id,
 | 
				
			||||||
 | 
					                AvatarId = x.AvatarId,
 | 
				
			||||||
 | 
					                Username = x.Username,
 | 
				
			||||||
 | 
					                Discriminator = x.Discriminator
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var added = (await ctx.BulkCopyAsync(usersToAdd)).RowsCopied;
 | 
				
			||||||
 | 
					        var toUpdateUserIds = presentDbUsers
 | 
				
			||||||
 | 
					            .Where(x => x.Username == "Unknown" && x.Discriminator == "????")
 | 
				
			||||||
 | 
					            .Select(x => x.UserId)
 | 
				
			||||||
 | 
					            .ToArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach (var user in users.Where(x => toUpdateUserIds.Contains(x.Id)))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ctx.DiscordUser
 | 
				
			||||||
 | 
					                .Where(x => x.UserId == user.Id)
 | 
				
			||||||
 | 
					                .UpdateAsync(x => new DiscordUser()
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Username = user.Username,
 | 
				
			||||||
 | 
					                    Discriminator = user.Discriminator,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // .award tends to set AvatarId and DateAdded to NULL, so account for that.
 | 
				
			||||||
 | 
					                    AvatarId = user.AvatarId,
 | 
				
			||||||
 | 
					                    DateAdded = x.DateAdded ?? DateTime.UtcNow
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return (added, toUpdateUserIds.Length);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static Task<DiscordUser> GetByUserIdAsync(
 | 
					    public static Task<DiscordUser> GetByUserIdAsync(
 | 
				
			||||||
        this IQueryable<DiscordUser> set,
 | 
					        this IQueryable<DiscordUser> set,
 | 
				
			||||||
        ulong userId)
 | 
					        ulong userId)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
#nullable disable
 | 
					#nullable disable
 | 
				
			||||||
using Nadeko.Medusa;
 | 
					using Nadeko.Medusa;
 | 
				
			||||||
 | 
					using NadekoBot.Db;
 | 
				
			||||||
using NadekoBot.Modules.Administration.Services;
 | 
					using NadekoBot.Modules.Administration.Services;
 | 
				
			||||||
using NadekoBot.Services.Database.Models;
 | 
					using NadekoBot.Services.Database.Models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -22,19 +23,53 @@ public partial class Administration
 | 
				
			|||||||
        private readonly IBotStrings _strings;
 | 
					        private readonly IBotStrings _strings;
 | 
				
			||||||
        private readonly IMedusaLoaderService _medusaLoader;
 | 
					        private readonly IMedusaLoaderService _medusaLoader;
 | 
				
			||||||
        private readonly ICoordinator _coord;
 | 
					        private readonly ICoordinator _coord;
 | 
				
			||||||
 | 
					        private readonly DbService _db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public SelfCommands(
 | 
					        public SelfCommands(
 | 
				
			||||||
            DiscordSocketClient client,
 | 
					            DiscordSocketClient client,
 | 
				
			||||||
 | 
					            DbService db,
 | 
				
			||||||
            IBotStrings strings,
 | 
					            IBotStrings strings,
 | 
				
			||||||
            ICoordinator coord,
 | 
					            ICoordinator coord,
 | 
				
			||||||
            IMedusaLoaderService medusaLoader)
 | 
					            IMedusaLoaderService medusaLoader)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _client = client;
 | 
					            _client = client;
 | 
				
			||||||
 | 
					            _db = db;
 | 
				
			||||||
            _strings = strings;
 | 
					            _strings = strings;
 | 
				
			||||||
            _coord = coord;
 | 
					            _coord = coord;
 | 
				
			||||||
            _medusaLoader = medusaLoader;
 | 
					            _medusaLoader = medusaLoader;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Cmd]
 | 
				
			||||||
 | 
					        [RequireContext(ContextType.Guild)]
 | 
				
			||||||
 | 
					        [OwnerOnly]
 | 
				
			||||||
 | 
					        public Task CacheUsers()
 | 
				
			||||||
 | 
					            => CacheUsers(ctx.Guild);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Cmd]
 | 
				
			||||||
 | 
					        [OwnerOnly]
 | 
				
			||||||
 | 
					        public async Task CacheUsers(IGuild guild)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var downloadUsersTask = guild.DownloadUsersAsync();
 | 
				
			||||||
 | 
					            var message = await ReplyPendingLocalizedAsync(strs.cache_users_pending);
 | 
				
			||||||
 | 
					            using var dbContext = _db.GetDbContext();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            await downloadUsersTask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var users = (await guild.GetUsersAsync(CacheMode.CacheOnly))
 | 
				
			||||||
 | 
					                .Cast<IUser>()
 | 
				
			||||||
 | 
					                .ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var (added, updated) = await dbContext.RefreshUsersAsync(users);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            await message.ModifyAsync(x =>
 | 
				
			||||||
 | 
					                x.Embed = _eb.Create()
 | 
				
			||||||
 | 
					                    .WithDescription(GetText(strs.cache_users_done(added, updated)))
 | 
				
			||||||
 | 
					                    .WithOkColor()
 | 
				
			||||||
 | 
					                    .Build()
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Cmd]
 | 
					        [Cmd]
 | 
				
			||||||
        [OwnerOnly]
 | 
					        [OwnerOnly]
 | 
				
			||||||
        public async Task DoAs(IUser user, [Leftover] string message)
 | 
					        public async Task DoAs(IUser user, [Leftover] string message)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1391,3 +1391,5 @@ autopublish:
 | 
				
			|||||||
doas:
 | 
					doas:
 | 
				
			||||||
  - doas
 | 
					  - doas
 | 
				
			||||||
  - execas
 | 
					  - execas
 | 
				
			||||||
 | 
					cacheusers:
 | 
				
			||||||
 | 
					  - cacheusers
 | 
				
			||||||
@@ -2363,3 +2363,8 @@ doas:
 | 
				
			|||||||
  desc: "Execute the command as if you were the target user. Requires bot ownership and server administrator permission."
 | 
					  desc: "Execute the command as if you were the target user. Requires bot ownership and server administrator permission."
 | 
				
			||||||
  args:
 | 
					  args:
 | 
				
			||||||
    - "@Thief .give all @Admin"
 | 
					    - "@Thief .give all @Admin"
 | 
				
			||||||
 | 
					cacheusers:
 | 
				
			||||||
 | 
					  desc: Caches users of a Discord server and saves them to the database.
 | 
				
			||||||
 | 
					  args:
 | 
				
			||||||
 | 
					    - ""
 | 
				
			||||||
 | 
					    - "serverId"
 | 
				
			||||||
@@ -1058,5 +1058,7 @@
 | 
				
			|||||||
  "sticker_missing_name": "Please specify a name for the sticker.",
 | 
					  "sticker_missing_name": "Please specify a name for the sticker.",
 | 
				
			||||||
  "thread_deleted": "Thread Deleted",
 | 
					  "thread_deleted": "Thread Deleted",
 | 
				
			||||||
  "thread_created": "Thread Created",
 | 
					  "thread_created": "Thread Created",
 | 
				
			||||||
  "supported_languages": "Supported Languages"
 | 
					  "supported_languages": "Supported Languages",
 | 
				
			||||||
 | 
					  "cache_users_pending": "Updating users, please wait...",
 | 
				
			||||||
 | 
					  "cache_users_done": "{0} users were added and {1} users were updated."
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user