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);
        }
Beispiel #2
0
        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);
 }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        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);
        }
Beispiel #11
0
        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);
        }
Beispiel #14
0
 /// <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);
Beispiel #15
0
 /// <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));
 }
Beispiel #16
0
 /// <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);