Repository: Pycord-Development/pycord

Issue:
Paginators cannot be used after an extended period of time
### Summary

Trying to using a paginator after some extended period of time will cause an error.

### Reproduction Steps

Create a paginator and wait an extended period of time.  In my case I waited 24 hours (without disabling/turning off the bot).  Then try using the paginator.

### Minimal Reproducible Code

```python
from discord.ext.pages import Paginator
from typing import List, Tuple

import discord

debug_guilds: List[int] = ...
assert debug_guilds is not ..., 'Fill in debug_guild(s)'
bot = discord.Bot(debug_guilds=debug_guilds)

@bot.slash_command()
async def create(ctx: discord.ApplicationContext):
    paginator = Paginator(['Hello!', 'There!'], timeout=None, disable_on_timeout=False)
    await paginator.respond(ctx.interaction)

@bot.event
async def on_ready():
    print(f"{bot.user} is ready!")

token = ...
assert token is not ..., 'Use a valid token!'
bot.run(token)

# NOTE: Now try using the paginator after an extended period of time.
```


### Expected Results

The paginator should work as normal.

### Actual Results

The following error occured:
```py
Traceback (most recent call last):
  File "/home/clovis/clovis/env/lib/python3.8/site-packages/discord/ui/view.py", line 365, in _scheduled_task
    await item.callback(interaction)
  File "/home/clovis/clovis/env/lib/python3.8/site-packages/discord/ext/pages/pagination.py", line 107, in callback
    await self.paginator.goto_page(page_number=self.paginator.current_page)
  File "/home/clovis/clovis/clovis/utils.py", line 173, in goto_page
    return await super().goto_page(page_number)
  File "/home/clovis/clovis/env/lib/python3.8/site-packages/discord/ext/pages/pagination.py", line 472, in goto_page
    return await self.message.edit(
  File "/home/clovis/clovis/env/lib/python3.8/site-packages/discord/interactions.py", line 898, in edit
    return await self._state._interaction.edit_original_message(
  File "/home/clovis/clovis/env/lib/python3.8/site-packages/discord/interactions.py", line 355, in edit_original_message
    data = await adapter.edit_original_interaction_response(
  File "/home/clovis/clovis/env/lib/python3.8/site-packages/discord/webhook/async_.py", line 194, in request
    raise HTTPException(response, data)
discord.errors.HTTPException: 401 Unauthorized (error code: 50027): Invalid Webhook Token
```

### Intents

I don't think intents are relevant here, if they are, here's the intents I used: `discord.Intents(guilds=True, members=True)`

### System Information

OS: Windows 10
Python Version: 3.8.11
Pycord Version: 2.0.0b4

### Checklist

- [X] I have searched the open issues for duplicates.
- [X] I have shown the entire traceback, if possible.
- [X] I have removed my token from display, if visible.

### Additional Context

I'm not sure if this is a Discord issue or a Pycord issue or both.  It seems like this functionality should work because the bot did get a message from the Discord that a button was pushed but for some reason the bot errors out.


Discussion:
This is related to the unchangeable Webhook expiration time of 15 minutes. Testing a potential fix now.

Resolving patch:
diff --git a/discord/ext/pages/pagination.py b/discord/ext/pages/pagination.py
--- a/discord/ext/pages/pagination.py
+++ b/discord/ext/pages/pagination.py
@@ -374,7 +374,7 @@ async def disable(
         """
         page = self.get_page_content(page)
         for item in self.children:
-            if item not in self.custom_view.children or include_custom:
+            if include_custom or not self.custom_view or item not in self.custom_view.children:
                 item.disabled = True
         if page:
             await self.message.edit(
@@ -402,7 +402,7 @@ async def cancel(
         items = self.children.copy()
         page = self.get_page_content(page)
         for item in items:
-            if item not in self.custom_view.children or include_custom:
+            if include_custom or not self.custom_view or item not in self.custom_view.children:
                 self.remove_item(item)
         if page:
             await self.message.edit(
@@ -701,7 +701,8 @@ async def respond(
                     view=self,
                     ephemeral=ephemeral,
                 )
-
+                # convert from WebhookMessage to Message reference to bypass 15min webhook token timeout
+                msg = msg.channel.get_partial_message(msg.id) or await msg.channel.fetch_message(msg.id)
             else:
                 msg = await interaction.response.send_message(
                     content=page if isinstance(page, str) else None,
@@ -709,10 +710,13 @@ async def respond(
                     view=self,
                     ephemeral=ephemeral,
                 )
-            if isinstance(msg, (discord.WebhookMessage, discord.Message)):
+            if isinstance(msg, discord.WebhookMessage):
+                self.message = await msg.channel.fetch_message(msg.id)
+            elif isinstance(msg, discord.Message):
                 self.message = msg
             elif isinstance(msg, discord.Interaction):
-                self.message = await msg.original_message()
+                msg = await msg.original_message()
+                self.message = await msg.channel.fetch_message(msg.id)
 
         return self.message
 


Test patch: