private async Task <IdQueue> GetOrCreateQueueAsync(CommandContext context, string name, CancellationToken cancellationToken = default) { // first try to get existing queue IdQueue result = await GetQueueAsync(context, name, cancellationToken).ConfigureAwait(false); if (result != null) { return(result); } // if not exist, resolve name for new queue bool claiming = false; string queueName = name; if (name.Equals("my", StringComparison.OrdinalIgnoreCase)) { WolfUser user = await context.Client.GetUserAsync(context.Message.SenderID.Value, cancellationToken).ConfigureAwait(false); queueName = user.Nickname; claiming = true; } // check forbidden name if (IsQueueNameForbidden(queueName)) { await context.ReplyTextAsync($"(n) Queue name \"{queueName}\" is invalid or forbidden.", cancellationToken).ConfigureAwait(false); return(null); } // if used "my", check if one with new name already exists if (claiming) { IdQueue existingQueue = await _idQueueStore.GetIdQueueByNameAsync(queueName, cancellationToken).ConfigureAwait(false); if (existingQueue != null) { if (existingQueue.OwnerID == null) { await context.ReplyTextAsync($"(n) Queue \"{existingQueue.Name}\" already exists, but is not claimed by you.\r\n" + $"Use '{context.Options.Prefix}{queueName}queue claim' to set as yours!", cancellationToken).ConfigureAwait(false); } else { WolfUser queueOwner = await context.Client.GetUserAsync(existingQueue.OwnerID.Value, cancellationToken).ConfigureAwait(false); await context.ReplyTextAsync($"(n) Queue \"{existingQueue.Name}\" already exists, but is claimed by {queueOwner.Nickname}. :(", cancellationToken).ConfigureAwait(false); } return(null); } } // if all checks succeeded, we can create a new one result = new IdQueue(queueName); if (claiming) { result.OwnerID = context.Message.SenderID.Value; } return(result); }
private async Task <string> BuildMentionMessage(ChatMessage message, MentionConfig config, CancellationToken cancellationToken = default) { StringBuilder builder = new StringBuilder(config.MessageTemplate ?? _mentionsOptions.CurrentValue.DefaultMessageTemplate); WolfUser user = await _client.GetUserAsync(message.SenderID.Value, cancellationToken).ConfigureAwait(false); WolfGroup group = await _client.GetGroupAsync(message.RecipientID, cancellationToken).ConfigureAwait(false); // metadata builder.Replace("{{UserID}}", user.ID.ToString()); builder.Replace("{{UserName}}", user.Nickname); builder.Replace("{{GroupID}}", group.ID.ToString()); builder.Replace("{{GroupName}}", group.Name); // trim text if too long string txt = message.Text; if (txt.Length > _mentionsOptions.CurrentValue.MaxTextLength) { txt = txt.Remove(_mentionsOptions.CurrentValue.MaxTextLength) + "..."; } builder.Replace("{{Message}}", txt); // return results return(builder.ToString()); }
private async Task CmdInfoAsync(CommandContext context, string queueName, CancellationToken cancellationToken = default) { IdQueue queue = await GetQueueAsync(context, queueName, cancellationToken).ConfigureAwait(false); if (queue == null) { if (queueName.Equals("my", StringComparison.OrdinalIgnoreCase)) { await context.ReplyTextAsync("(n) Your queue not found.", cancellationToken).ConfigureAwait(false); } else { await context.ReplyTextAsync($"(n) Queue {queueName} not found.", cancellationToken).ConfigureAwait(false); } return; } WolfUser user = null; if (queue.OwnerID != null) { user = await context.Client.GetUserAsync(queue.OwnerID.Value, cancellationToken).ConfigureAwait(false); } await context.ReplyTextAsync( $"Name: {queue.Name}\r\n" + $"Owner ID: {(queue.OwnerID?.ToString() ?? "-")}\r\n" + $"Owner: {(user?.Nickname ?? "-")}\r\n" + $"ID Count: {queue.QueuedIDs?.Count ?? 0}\r\n" + $"\r\nID: {queue.ID}", cancellationToken).ConfigureAwait(false); }
/// <summary>Checks if user has a specified privilege.</summary> /// <param name="context">Context of the command execution.</param> /// <param name="userID">ID of the user.</param> /// <param name="privileges">Required privileges flags.</param> /// <param name="cancellationToken">Cancellation token for cancelling the task.</param> /// <returns>True if user has at least one of specified privileges; otherwise false.</returns> public static async Task <bool> CheckPrivilegeAsync(ICommandContext context, uint userID, WolfPrivilege privileges, CancellationToken cancellationToken = default) { UserProfileResponse response = await context.Client.SendAsync <UserProfileResponse>( new UserProfileMessage(new uint[] { userID }, true, true), cancellationToken).ConfigureAwait(false); WolfUser user = response?.UserProfiles?.FirstOrDefault(u => u.ID == userID); if (user == null) { return(false); } return((privileges & user.Privileges) != 0); }
/// <summary>Create a new builder for <see cref="UserUpdateMessage"/>.</summary> /// <remarks>Ensure that <paramref name="user"/> is always currently connected user, /// as the message is being sent without any user ID, so always updates the current user.</remarks> /// <param name="user">User to update.</param> public Builder(WolfUser user) { this.Nickname = user.Nickname; this.Status = user.Status; this.ProfileName = user.ProfileName; this.About = user.About; this.Gender = user.Gender ?? WolfGender.NotSpecified; this.Language = user.Language ?? WolfLanguage.NotSpecified; this.Relationship = user.Relationship ?? WolfRelationship.NotSpecified; this.LookingFor = user.LookingFor ?? WolfLookingFor.NotSpecified; this.DateOfBirth = user.DateOfBirth; // create new collection to not modify the underlying user this.Links = user.Links == null ? new List <string>() : new List <string>(user.Links); }
private async Task CmdHelpAsync(CommandContext context, CancellationToken cancellationToken = default) { WolfUser owner = await context.Client.GetUserAsync(_botOptions.OwnerID, cancellationToken).ConfigureAwait(false); await context.ReplyTextAsync(string.Format(@"Notes commands: `{0}notes` - get list of your notes `{0}notes <ID>` - get a specific note `{0}notes add <text>` - adds a new note `{0}notes remove <ID>` - delete a specific note `{0}notes clear` - removes all your notes For bug reports or suggestions, contact {1} (ID: {2})", context.Options.Prefix, owner.Nickname, owner.ID), cancellationToken).ConfigureAwait(false); }
private static async void OnWelcome(WelcomeEvent message) { // if reusing the token, user might be already logged in, so check that before requesting login if (message.LoggedInUser == null) { Config config = Config.Load(); await _client.LoginAsync(config.Username, config.Password, WolfLoginType.Email); } await _client.SubscribeAllMessagesAsync(); // without this, bot will not receive any messages // user should not be cached locally - always call GetUserAsync/GetCurrentUserAsync on client! WolfUser user = await _client.GetCurrentUserAsync(); // same applies to groups - always call GetGroupsAsync! IEnumerable <WolfGroup> groups = await _client.GetCurrentUserGroupsAsync(); }
private static async Task <WolfUser> GetUserAsync(ICommandContext context, uint id, CancellationToken cancellationToken = default) { if (context.Client is IWolfClientCacheAccessor cache) { WolfUser result = cache.GetCachedUser(id); if (result != null) { return(result); } } UserProfileResponse response = await context.Client.SendAsync <UserProfileResponse>( new UserProfileMessage(new uint[] { id }, true, true), cancellationToken).ConfigureAwait(false); return(response?.UserProfiles?.FirstOrDefault(u => u.ID == id)); }
private async ValueTask <bool> CheckShouldCheckSizeAsync(CommandContext context, ITargetConfig config, CancellationToken cancellationToken = default) { _log.LogTrace("Determining if should check the image size"); if (config is GroupConfig groupConfig) { // if disabled for all, can return early if (!groupConfig.IsEnabled || (!groupConfig.ListenUsers && !groupConfig.ListenMods && !groupConfig.ListenAdmins && !groupConfig.ListenBots)) { return(false); } // same if enabled for for all if (groupConfig.IsEnabled && groupConfig.ListenUsers && groupConfig.ListenMods && groupConfig.ListenAdmins && groupConfig.ListenBots) { return(true); } // check for all permissions WolfGroupMember member = await GetGroupMemberAsync(context, cancellationToken).ConfigureAwait(false); if (groupConfig.ListenUsers && member.Capabilities == WolfGroupCapabilities.User) { return(true); } if (groupConfig.ListenMods && member.Capabilities == WolfGroupCapabilities.Mod) { return(true); } if (groupConfig.ListenAdmins && member.HasAdminPrivileges) { return(true); } if (groupConfig.ListenBots) { WolfUser user = await context.GetSenderAsync(cancellationToken).ConfigureAwait(false); return(user.Device == WolfDevice.Bot); } // return false if all privilege checks failed return(false); } else { return(true); } }
private async Task CmdTransferAsync(CommandContext context, string queueName, [MissingError("(n) Please provide ID of the user to transfer the queue to.")][ConvertingError("(n) `{{Arg}}` is not a valid user ID.")] uint newOwnerID, CancellationToken cancellationToken = default) { IdQueue queue = await GetOrCreateQueueAsync(context, queueName, cancellationToken).ConfigureAwait(false); if (queue == null) { return; // if null, it means it's a forbidden name } // check if this is owner's queue, or user is bot admin if (queue.OwnerID != null && !await IsQueueOwnerOrBotAdmin(queue, context.Message.SenderID.Value, cancellationToken).ConfigureAwait(false)) { await context.ReplyTextAsync("(n) To transfer a queue, you need to be it's owner or a bot admin.", cancellationToken).ConfigureAwait(false); return; } WolfUser user = await context.Client.GetUserAsync(newOwnerID, cancellationToken).ConfigureAwait(false); if (user == null) { await context.ReplyTextAsync($"(n) User {newOwnerID} not found.", cancellationToken).ConfigureAwait(false); return; } IdQueue userCurrentQueue = await _idQueueStore.GetIdQueueByOwnerAsync(user.ID, cancellationToken).ConfigureAwait(false); if (userCurrentQueue != null) { await context.ReplyTextAsync($"(n) User {user.Nickname} already owns a queue. One user can only own one queue.", cancellationToken).ConfigureAwait(false); return; } queue.OwnerID = user.ID; await SaveQueueAsync(context, queue, cancellationToken).ConfigureAwait(false); _idQueueStore.FlushBatch(); await context.ReplyTextAsync($"(y) Queue `{queue.Name}` transferred to {user.Nickname}.", cancellationToken).ConfigureAwait(false); }
private async Task CmdCacheClear(CommandContext context, CancellationToken cancellationToken = default) { // flush all batches first to prevent data loss _groupConfigStore.FlushBatch(); _idQueueStore.FlushBatch(); _userDataStore.FlushBatch(); // get current counts for reporting int userDataCacheCount = _userDataCache.CachedCount; int groupConfigCacheCount = _groupConfigCache.CachedCount; int idQueueCacheCount = _idQueueCache.CachedCount; int mentionConfigCacheCount = _mentionConfigCache.CachedCount; // clear caches _userDataCache.Clear(); _groupConfigCache.Clear(); _idQueueCache.Clear(); _mentionConfigCache.Clear(); // reply to user await context.ReplyTextAsync("(y) Database caches cleared:\r\n" + $"{nameof(IUserDataCache)}: {userDataCacheCount}\r\n" + $"{nameof(IGroupConfigCache)}: {groupConfigCacheCount}\r\n" + $"{nameof(IIdQueueCache)}: {idQueueCacheCount}\r\n" + $"{nameof(IMentionConfigCache)}: {mentionConfigCacheCount}", cancellationToken).ConfigureAwait(false); // log the change WolfUser user = await context.Client.GetUserAsync(context.Message.SenderID.Value, cancellationToken).ConfigureAwait(false); using IDisposable clearedLogScope = _log.BeginScope(new Dictionary <string, object>() { { "UserDataCacheCount", userDataCacheCount }, { "GroupConfigCacheCount", groupConfigCacheCount }, { "IdQueueCacheCount", idQueueCacheCount }, { "MentionConfigCacheCount", mentionConfigCacheCount } }); _log.LogInformation("All database caches cleared by {UserID} ({UserNickname})", user.ID, user.Nickname); }
private async Task CmdHelpAsync(CommandContext context, CancellationToken cancellationToken = default) { WolfUser owner = await context.Client.GetUserAsync(_botOptions.OwnerID, cancellationToken).ConfigureAwait(false); await context.ReplyTextAsync(string.Format(@"Queue commands: `{0}<queue name> queue next` - pulls the next ID from <queue name> `{0}<queue name> queue add <IDs>` - adds IDs `{0}<queue name> queue show` - shows all IDs `{0}<queue name> queue remove <IDs>` - removes selected IDs `{0}<queue name> queue clear` - removes all IDs `{0}<queue name> queue rename <new name>` - changes name `{0}<queue name> queue claim` - claims the queue, so you can use ""my"" as it's name `{0}<queue name> queue transfer <user ID>` - transfers ownership of the queue `{0}<queue name> info` - shows info about the queue `clear` and `remove` can only be used on your own queue, or a queue without an owner. `rename` and `transfer` can only be used if you own the queue. `claim` can only be used if the queue isn't already claimed. You can check that using `info`. For bug reports or suggestions, contact {1} (ID: {2})", context.Options.Prefix, owner.Nickname, owner.ID), cancellationToken).ConfigureAwait(false); }
/// <inheritdoc/> public override async Task <bool> CheckAsync(ICommandContext context, IServiceProvider services, CancellationToken cancellationToken = default) { WolfUser user = await context.GetSenderAsync(cancellationToken).ConfigureAwait(false); return(user.Reputation >= this.MinimumReputation); }
/// <summary>Downloads bytes of user avatar.</summary> /// <param name="user">User to download avatar of.</param> /// <param name="client">Http Client to request avatar bytes with.</param> /// <param name="size">Size of the avatar to request.</param> /// <param name="cancellationToken">Token to cancel the request.</param> /// <returns>Bytes of user avatar. Null if user of avatar not found.</returns> public static Task <byte[]> DownloadAvatarAsync(this WolfUser user, HttpClient client, uint size = 500, CancellationToken cancellationToken = default) => DownloadAvatarAsync(GetAvatarURL(user, size), client, cancellationToken);
/// <summary>Downloads bytes of user avatar.</summary> /// <param name="user">User to download avatar of.</param> /// <param name="size">Size of the avatar to request.</param> /// <param name="cancellationToken">Token to cancel the request.</param> /// <remarks>This method creates a temporary HttpClient just for the request. This might be performance heavy, and therefore it's recommended to provide your own client from own cache, or using a client factory.</remarks> /// <returns>Bytes of user avatar. Null if user of avatar not found.</returns> public static async Task <byte[]> DownloadAvatarAsync(this WolfUser user, uint size = 500, CancellationToken cancellationToken = default) { using (HttpClient client = GetDefaultClient()) return(await DownloadAvatarAsync(user, client, size, cancellationToken).ConfigureAwait(false)); }
/// <summary>Gets URL for retrieving user avatar.</summary> /// <param name="user">User to get avatar URL for.</param> /// <param name="size">Size of the avatar to retrieve.</param> /// <remarks><para>This method will return URL to user avatar. You can use this URL with <see cref="HttpClient"/> to download the avatar, or use for any other purpose.</para> /// <para><paramref name="size"/> is only a requested size of the avatar. It is not guaranteed that URL will contain avatar with this size.</para></remarks> /// <returns>URL to user's avatar.</returns> public static string GetAvatarURL(this WolfUser user, uint size = 500) => GetUserAvatarURL(user.ID, user.Icon, size);