Repository: python-discord/bot

Issue:
Restricting/redirecting output of commands to bot-commands for regular users
**Edit:** I've decided to make this a general issue, since the `!free` command turns out to be a bit disruptive as well. In python-discussions, there have just been four consecutive calls to `!free` and it looks very disruptive (see below).

My idea would be to create an easy way to redirect the output of certain commands, free and help, to bot commands for regular users, with the bot sending a temporary message to the user in channel redirecting them there. The bot could then delete that message (and, maybe, the invoking message as well) after a certain amount of time has passed.

**Four times !free in python-discussion:**
![2019-01-18_17-38-32](https://user-images.githubusercontent.com/33516116/51400480-c8aeb980-1b48-11e9-838e-515904e62776.png)

**Old message for context:**
Now the `!help` command works outside of bot-commands again, we may want to think about restricting the use/output to bot-commands for regular users. The help-embeds are quite sizeable and, therefore, quite disruptive in on-topic channels.

I want to propose to redirect the **output** of help (the help-embed) to bot-commands for non-staff members, prepended by a mention of the user invoking the command. In addition, we could display a small, non-disruptive embed in the original context channel redirecting the user to bot commands. I think this should also be the case for help-calls on specific commands, as the embeds for those can be quite sizeable as well (e.g., `!help site`).

Personally, I'd like this restriction to only apply to regular users, so staff can pull up help on a command quickly in channel and use help in the staff channels.


Discussion:
What about a DM from the bot?
That's also an interesting idea. 

Do you mean a DM for the full help embed or just for the message pointing the user to bot-commands? I kinda like pointing users to that channel so they'll notice that channel and start using it for bot commands. We can't mention a channel in a DM, though. Guess we also do still need a fallback for when users have DMs disabled. 

I wouldn't mind a single line (embed? just a message?) from the bot with a `TextChannel.mention` for bot-commands in channel. That isn't really disruptive and certainly less disruptive than having the entire help embed in a topic/help channel.  
hate the DM idea, love the original proposal.
My idea for a DM is user sends !help, the bot DMs with help, and the bot deletes the user's !help message from the channel. The exception to this is in bot commands, in which case it'll be sent in the channel like normal.
> We can't mention a channel in a DM, though

Yes you can. Just the user clients don't resolve it in the auto-complete. You can simply send the mention string manually and it works. Naturally this isn't an issue with bots, as they always send the raw string.

I think redirecting to #bot-commands is fine, we don't have to worry about the whole issue of user privacy settings this way. Just adding a mention to the message contents will be enough to get their attention usually, but a small, temp message in the original channel saying where it went is ok too, especially for those on mobile who wouldn't immediately see the ping location. It can just be auto-deleted in 10 seconds.
Since the `!free` command has now been included in this issue I feel I should speak on the issue as well. I think redirecting the output is a good idea. Perhaps increasing the cooldown time from 1min to 10min or more, and that when users try to invoke `!free` when the cooldown is active, that this is when the message should be redirected. I think maybe this should just be applied in the help channels themselves though, I don't like seeing this command used by normal users in #python-discussion at all, as it only serves as clutter.

When I was writing this command, I was considering the idea of auto deleting the message after a minute or so to specifically avoid this clutter issue. I think that should be implemented as well.

I saw someone make an interesting suggestion that there could be a separate channel with only the `!free` embed in it and nothing else, and it constantly updates either on a schedule, from user reactions (or both). Though I know we're likely all hesitant to add an entire channel for this.

Ultimately the brand new help system is the true solution to all this, but I'm not sure how close or far away we are from that.
I don't agree with restricting it to the help channels, "where do I ask a question" comes up quite often in many other channels, including #python-discussion.

Having it time out is a compelling addition.

I'm not opposed to having a dedicated "what's free" channel inside of the help channel category. Outputting the command in a singular place is more desirable than the current behavior, and having it co-located with the help channels is a better user experience than bringing them down into #bot-commands and back up to a help channel. It would also give a more intuitive place to look for recent status of the help channels.

I'm less a fan of the auto-update and reaction updates. Conceptually they're a good idea but they're not exactly the most robust things in the API.
Right, I think I agree with @sco1, a dedicated channel right next to the actual help channels to redirect the output to seems like a good idea. 

The only thing I'm a bit unsure of is how to handle that channel: Do we want to allow the users to invoke the `!free` command from inside that channel? And how do we keep it from turning into another help channel? Auto-delete everything that isn't `!free`? Not being able to "refresh"/get a new free channel embed from inside that channel also feels a bit weird to me. However, if we leave it unrestricted, I fear it will need a lot of moderation.

Regarding the `!help` command, I think that should still be redirected to `bot-commands`. That's the ideal place for that, as people are then at the right place to use `!help <command>` to get help on specific commands and explore the bot a bit.

Finally, regarding the auto-delete: It's a great way to clean the clutter, but I think it has a major drawback. What I see now is that people see others using the `!free` and the `!help` commands and that's how they discover their existence. That's why that situation in python-discussion probably came into existence: People came, people saw, and people monkeyed. Obviously, this would be mitigated by only deleting an embed when the next one gets requested, but that means keeping track of the current embeds in channel. Redirecting is probably the better option, in my opinion.
Instead of creating new channels for results from `!free` or rate limiting them per user how about we rate limit per channel? We could add a 5 minute limit to 1 channel so that if people keep using the `!free` command (as demonstrated in that screenshot) we can send a message like `This command has already been called here in the past 5 minutes. Please use this embed to check the activity of help channels.` and then cleanup messages from there (remove the !free command & remove the error response after a few seconds).
The cooldown is already on a per channel basis. It's just set to 1 invocation per minute, which is why I mentioned increasing that to 10min or something.
Ah, I assumed it was a user bucket, in that case I agree with you about increasing that, also I don't know if I agree with auto-delete but maybe auto-delete of any rate limited invocation messages.
I don't really like the idea of a what's free channel. we already have a channel for that, it's called #bot-commands. 

I think if we took the steps we've talked about before in regards to shortening the free command output (only showing the best channels rather than everything for `!free` and adding a `!free all` to show everything), it wouldn't be such a big problem. We could probably increase the channel cooldown a little bit, and then redirect output to #bot-commands if the cooldown is active. This combination of steps should more than curb the problem.
I also agree with autodelete, btw.
Instead of a dedicated channel, the live embed could live in in the `rules-information` channel.
I agree that redirection to bot-commands is the go, and it seems most agree with this now. This prevents the usage being actually restricted from where it's invoked, but keeps clear the non-spam channels.

I also agree with autodeletion of the original command invocation as it follows suit of the current behaviour of `!help` and it's best to keep things consistent. Plus it does generally make sense.

People will see the usage of `!free` throughout the day, or will have others use it for them as a form of introduction, plus an explanation of it's usage should be present in the `#rules-information` channel to ensure those who read that channel know of it too.

I do generally agree the embed could do with reducing its size, as it's unnecessarily large as it is for the moment, but it should not be restricted to a single channel on output.

At the point of the original PR, I didn't mind what was there, but I feel over time I've come to notice alternative styling would be preferred:  
- 3 channels max on output
- Remove the newlines between each listed channel
- Remove the list numbering as there's already inactive duration for context
- Remove `The following channels look free:`
- Rewording the ending sentence and placing it in the footer field for the smaller text size
- Better humanized duration

As a visual example, this would be the current style:
![image](https://user-images.githubusercontent.com/29337040/51534502-a5aa3f80-1e91-11e9-9ffb-6254011062c2.png)

Something like this would be kinda applying my previous points:
![image](https://user-images.githubusercontent.com/29337040/51534398-6b40a280-1e91-11e9-9993-d9a5e3e3168e.png)

So, where do we stand on the `!free` command? As far as I can see, there have been a number of suggestions:

1. Have a live embed live in rules-information that regularly updated
2. Making the embed compact and limiting the number of shown channels to three
3. Increasing the per-channel cooldown period, possibly combined with a redirect during cooldown
4. Redirecting output for regular users to bot-commands, with auto-deleting redirect message
5. Auto-delete the embed after x seconds since it has lost it use and is not longer up to date

Do want to do anything with any of those suggestions? If we have a definite approach in mind, it may be a good idea to open a new issue detailing the strategy, referencing the discussion here.
2-5 seem pretty well agreed on. It would be nice to have them relatively quickly because the messages are becoming quite a chore.
I'm in favour of option 3, 4 or 5. I think that !free is rather disruptive and I have some issues with implementing a channel for this.

My main concern is that people will skip right over it. People get told in #python-discussion to go to a help channel and people just pick a random help channel, people are unlikely to check a channel to see what is free. At least if a user calls !free they get a personalised output (which users like) and are probably more likely to go to a channel which isn't in use.

As was pointed out in the help channel users are pretty used to the command now so it might not be something we can easily remove at this point.

<img width="362" alt="image" src="https://user-images.githubusercontent.com/20439493/51930648-f28e9880-23f2-11e9-807e-528418302bc2.png">

_406 uses since introduction_

Here is my proposal:
- users runs !free in an on topic channel
- bot redirects output to #bot-commands 
- bot pings user in #bot-commands about redirection
- bot pings in the original channel to say "you got redirected, go to #xyz" (they can click it as well, no need to scroll)
- after 30s or 1m or something the bot deletes the invoking message & the redirection notice

Some concerns have been raised about the accessibility of #bot-commands so maybe we should think about the position of that before we start redirecting stuff there.
The moving of #bot-commands to a more convenient location alleviates my concerns. Having it in the Discussions category would make it easy for folks in #python-discussion to point people to it, and then the natural transition down to the appropriate help channel is much easier.  On top of that, it would make #bot-commands more appealing for use, since you don't have to go digging for it further down in other categories.
> Here is my proposal:
> 
>     * users runs !free in an on topic channel
> 
>     * bot redirects output to #bot-commands
> 
>     * bot pings user in #bot-commands about redirection
> 
>     * bot pings in the original channel to say "you got redirected, go to #xyz" (they can click it as well, no need to scroll)
> 
>     * after 30s or 1m or something the bot deletes the invoking message & the redirection notice
> 
> 
> Some concerns have been raised about the accessibility of #bot-commands so maybe we should think about the position of that before we start redirecting stuff there.

I agree with this. I just want to note that recently added redirect decorator (used for `!help` for instance) does exactly what you propose. This is my preferred solution as well and I wouldn't mind moving bot-commands to a more visible location.

Personally, I'm not in favor of a cooldown-based redirect; I would like to have it redirected every time. We can implement an exception for helpers and up, as I think we should be able to trust staff to not use it when it disrupts an ongoing conversation. (The decorator supports bypass roles, so that shouldn't be a problem. The `!help` command is currently implemented in a similar way.)

If people agree, then we can have this set up very quickly, as it's just adding the decorator and moving the channel.
Not in favour of cooldown-based redirect either. the issue we are experiencing is not with multiple calls of it (although that does happen) but it does also disrupt conversations when called once.
I really like @scragly's suggestion for how we can make the embed more compact. I think we could do exactly that. Seems like most of us have kinda glossed over that comment, but the illustration provided looks great to me:

![image](https://user-images.githubusercontent.com/2098517/52266780-84d4f600-2937-11e9-8d06-6b0ff86db1a9.png)

As for moving the channel to Discussion, this kind of irks me a little since it absolutely is not a discussion channel. I think it's fine where it is, personally, especially now that we're redirecting with a link that the user can click.
Looks like the only remaining action on this is to reduce the spacing of the embed.
> Looks like the only remaining action on this is to reduce the spacing of the embed.

If there is only this left to do, I could work on it.

Resolving patch:
diff --git a/bot/cogs/free.py b/bot/cogs/free.py
--- a/bot/cogs/free.py
+++ b/bot/cogs/free.py
@@ -72,30 +72,27 @@ async def free(self, ctx: Context, user: Member = None, seek: int = 2) -> None:
         # Display all potentially inactive channels
         # in descending order of inactivity
         if free_channels:
-            embed.description += "**The following channel{0} look{1} free:**\n\n**".format(
-                's' if len(free_channels) > 1 else '',
-                '' if len(free_channels) > 1 else 's'
-            )
-
             # Sort channels in descending order by seconds
             # Get position in list, inactivity, and channel object
             # For each channel, add to embed.description
             sorted_channels = sorted(free_channels, key=itemgetter(0), reverse=True)
-            for i, (inactive, channel) in enumerate(sorted_channels, 1):
+
+            for (inactive, channel) in sorted_channels[:3]:
                 minutes, seconds = divmod(inactive, 60)
                 if minutes > 59:
                     hours, minutes = divmod(minutes, 60)
-                    embed.description += f"{i}. {channel.mention} inactive for {hours}h{minutes}m{seconds}s\n\n"
+                    embed.description += f"{channel.mention} **{hours}h {minutes}m {seconds}s** inactive\n"
                 else:
-                    embed.description += f"{i}. {channel.mention} inactive for {minutes}m{seconds}s\n\n"
+                    embed.description += f"{channel.mention} **{minutes}m {seconds}s** inactive\n"
 
-            embed.description += ("**\nThese channels aren't guaranteed to be free, "
-                                  "so use your best judgement and check for yourself.")
+            embed.set_footer(text="Please confirm these channels are free before posting")
         else:
-            embed.description = ("**Doesn't look like any channels are available right now. "
-                                 "You're welcome to check for yourself to be sure. "
-                                 "If all channels are truly busy, please be patient "
-                                 "as one will likely be available soon.**")
+            embed.description = (
+                "Doesn't look like any channels are available right now. "
+                "You're welcome to check for yourself to be sure. "
+                "If all channels are truly busy, please be patient "
+                "as one will likely be available soon."
+            )
 
         await ctx.send(embed=embed)
 


Test patch: