We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Default duration for !superstar command if no duration is specified
## Context
The `!superstar` command currently requires a duration to be specified when invoked. 

Often we want to change someone's nickname from something very noisy or that takes up a lot of room until the user can respond and change it themselves. The duration in these cases is not usually that important as we want it to be a quick change.

## Proposal
It would be useful if there was a short default duration for this command. Something like 5 or 15 minutes. It would function similarly to the `!mute` command where if no duration is given, it opts for a 1 hour duration.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bot/exts/moderation/infraction/superstarify.py`
Content:
```
1 import json
2 import logging
3 import random
4 import textwrap
5 import typing as t
6 from pathlib import Path
7 
8 from discord import Embed, Member
9 from discord.ext.commands import Cog, Context, command, has_any_role
10 from discord.utils import escape_markdown
11 
12 from bot import constants
13 from bot.bot import Bot
14 from bot.converters import Expiry
15 from bot.exts.moderation.infraction import _utils
16 from bot.exts.moderation.infraction._scheduler import InfractionScheduler
17 from bot.utils.messages import format_user
18 from bot.utils.time import format_infraction
19 
20 log = logging.getLogger(__name__)
21 NICKNAME_POLICY_URL = "https://pythondiscord.com/pages/rules/#nickname-policy"
22 
23 with Path("bot/resources/stars.json").open(encoding="utf-8") as stars_file:
24     STAR_NAMES = json.load(stars_file)
25 
26 
27 class Superstarify(InfractionScheduler, Cog):
28     """A set of commands to moderate terrible nicknames."""
29 
30     def __init__(self, bot: Bot):
31         super().__init__(bot, supported_infractions={"superstar"})
32 
33     @Cog.listener()
34     async def on_member_update(self, before: Member, after: Member) -> None:
35         """Revert nickname edits if the user has an active superstarify infraction."""
36         if before.display_name == after.display_name:
37             return  # User didn't change their nickname. Abort!
38 
39         log.trace(
40             f"{before} ({before.display_name}) is trying to change their nickname to "
41             f"{after.display_name}. Checking if the user is in superstar-prison..."
42         )
43 
44         active_superstarifies = await self.bot.api_client.get(
45             "bot/infractions",
46             params={
47                 "active": "true",
48                 "type": "superstar",
49                 "user__id": str(before.id)
50             }
51         )
52 
53         if not active_superstarifies:
54             log.trace(f"{before} has no active superstar infractions.")
55             return
56 
57         infraction = active_superstarifies[0]
58         forced_nick = self.get_nick(infraction["id"], before.id)
59         if after.display_name == forced_nick:
60             return  # Nick change was triggered by this event. Ignore.
61 
62         log.info(
63             f"{after.display_name} ({after.id}) tried to escape superstar prison. "
64             f"Changing the nick back to {before.display_name}."
65         )
66         await after.edit(
67             nick=forced_nick,
68             reason=f"Superstarified member tried to escape the prison: {infraction['id']}"
69         )
70 
71         notified = await _utils.notify_infraction(
72             user=after,
73             infr_type="Superstarify",
74             expires_at=format_infraction(infraction["expires_at"]),
75             reason=(
76                 "You have tried to change your nickname on the **Python Discord** server "
77                 f"from **{before.display_name}** to **{after.display_name}**, but as you "
78                 "are currently in superstar-prison, you do not have permission to do so."
79             ),
80             icon_url=_utils.INFRACTION_ICONS["superstar"][0]
81         )
82 
83         if not notified:
84             log.info("Failed to DM user about why they cannot change their nickname.")
85 
86     @Cog.listener()
87     async def on_member_join(self, member: Member) -> None:
88         """Reapply active superstar infractions for returning members."""
89         active_superstarifies = await self.bot.api_client.get(
90             "bot/infractions",
91             params={
92                 "active": "true",
93                 "type": "superstar",
94                 "user__id": member.id
95             }
96         )
97 
98         if active_superstarifies:
99             infraction = active_superstarifies[0]
100             action = member.edit(
101                 nick=self.get_nick(infraction["id"], member.id),
102                 reason=f"Superstarified member tried to escape the prison: {infraction['id']}"
103             )
104 
105             await self.reapply_infraction(infraction, action)
106 
107     @command(name="superstarify", aliases=("force_nick", "star", "starify", "superstar"))
108     async def superstarify(
109         self,
110         ctx: Context,
111         member: Member,
112         duration: Expiry,
113         *,
114         reason: str = '',
115     ) -> None:
116         """
117         Temporarily force a random superstar name (like Taylor Swift) to be the user's nickname.
118 
119         A unit of time should be appended to the duration.
120         Units (∗case-sensitive):
121         \u2003`y` - years
122         \u2003`m` - months∗
123         \u2003`w` - weeks
124         \u2003`d` - days
125         \u2003`h` - hours
126         \u2003`M` - minutes∗
127         \u2003`s` - seconds
128 
129         Alternatively, an ISO 8601 timestamp can be provided for the duration.
130 
131         An optional reason can be provided, which would be added to a message stating their old nickname
132         and linking to the nickname policy.
133         """
134         if await _utils.get_active_infraction(ctx, member, "superstar"):
135             return
136 
137         # Post the infraction to the API
138         old_nick = member.display_name
139         infraction_reason = f'Old nickname: {old_nick}. {reason}'
140         infraction = await _utils.post_infraction(ctx, member, "superstar", infraction_reason, duration, active=True)
141         id_ = infraction["id"]
142 
143         forced_nick = self.get_nick(id_, member.id)
144         expiry_str = format_infraction(infraction["expires_at"])
145 
146         # Apply the infraction
147         async def action() -> None:
148             log.debug(f"Changing nickname of {member} to {forced_nick}.")
149             self.mod_log.ignore(constants.Event.member_update, member.id)
150             await member.edit(nick=forced_nick, reason=reason)
151 
152         old_nick = escape_markdown(old_nick)
153         forced_nick = escape_markdown(forced_nick)
154 
155         nickname_info = textwrap.dedent(f"""
156             Old nickname: `{old_nick}`
157             New nickname: `{forced_nick}`
158         """).strip()
159 
160         user_message = (
161             f"Your previous nickname, **{old_nick}**, "
162             f"was so bad that we have decided to change it. "
163             f"Your new nickname will be **{forced_nick}**.\n\n"
164             "{reason}"
165             f"You will be unable to change your nickname until **{expiry_str}**. "
166             "If you're confused by this, please read our "
167             f"[official nickname policy]({NICKNAME_POLICY_URL})."
168         ).format
169 
170         successful = await self.apply_infraction(
171             ctx, infraction, member, action(),
172             user_reason=user_message(reason=f'**Additional details:** {reason}\n\n' if reason else ''),
173             additional_info=nickname_info
174         )
175 
176         # Send an embed with to the invoking context if superstar was successful.
177         if successful:
178             log.trace(f"Sending superstar #{id_} embed.")
179             embed = Embed(
180                 title="Superstarified!",
181                 colour=constants.Colours.soft_orange,
182                 description=user_message(reason='')
183             )
184             await ctx.send(embed=embed)
185 
186     @command(name="unsuperstarify", aliases=("release_nick", "unstar", "unstarify", "unsuperstar"))
187     async def unsuperstarify(self, ctx: Context, member: Member) -> None:
188         """Remove the superstarify infraction and allow the user to change their nickname."""
189         await self.pardon_infraction(ctx, "superstar", member)
190 
191     async def _pardon_action(self, infraction: _utils.Infraction) -> t.Optional[t.Dict[str, str]]:
192         """Pardon a superstar infraction and return a log dict."""
193         if infraction["type"] != "superstar":
194             return
195 
196         guild = self.bot.get_guild(constants.Guild.id)
197         user = guild.get_member(infraction["user"])
198 
199         # Don't bother sending a notification if the user left the guild.
200         if not user:
201             log.debug(
202                 "User left the guild and therefore won't be notified about superstar "
203                 f"{infraction['id']} pardon."
204             )
205             return {}
206 
207         # DM the user about the expiration.
208         notified = await _utils.notify_pardon(
209             user=user,
210             title="You are no longer superstarified",
211             content="You may now change your nickname on the server.",
212             icon_url=_utils.INFRACTION_ICONS["superstar"][1]
213         )
214 
215         return {
216             "Member": format_user(user),
217             "DM": "Sent" if notified else "**Failed**"
218         }
219 
220     @staticmethod
221     def get_nick(infraction_id: int, member_id: int) -> str:
222         """Randomly select a nickname from the Superstarify nickname list."""
223         log.trace(f"Choosing a random nickname for superstar #{infraction_id}.")
224 
225         rng = random.Random(str(infraction_id) + str(member_id))
226         return rng.choice(STAR_NAMES)
227 
228     # This cannot be static (must have a __func__ attribute).
229     async def cog_check(self, ctx: Context) -> bool:
230         """Only allow moderators to invoke the commands in this cog."""
231         return await has_any_role(*constants.MODERATION_ROLES).predicate(ctx)
232 
233 
234 def setup(bot: Bot) -> None:
235     """Load the Superstarify cog."""
236     bot.add_cog(Superstarify(bot))
237
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/bot/exts/moderation/infraction/superstarify.py b/bot/exts/moderation/infraction/superstarify.py
--- a/bot/exts/moderation/infraction/superstarify.py
+++ b/bot/exts/moderation/infraction/superstarify.py
@@ -11,7 +11,7 @@
 
 from bot import constants
 from bot.bot import Bot
-from bot.converters import Expiry
+from bot.converters import Duration, Expiry
 from bot.exts.moderation.infraction import _utils
 from bot.exts.moderation.infraction._scheduler import InfractionScheduler
 from bot.utils.messages import format_user
@@ -19,6 +19,7 @@
 
 log = logging.getLogger(__name__)
 NICKNAME_POLICY_URL = "https://pythondiscord.com/pages/rules/#nickname-policy"
+SUPERSTARIFY_DEFAULT_DURATION = "1h"
 
 with Path("bot/resources/stars.json").open(encoding="utf-8") as stars_file:
     STAR_NAMES = json.load(stars_file)
@@ -109,7 +110,7 @@
         self,
         ctx: Context,
         member: Member,
-        duration: Expiry,
+        duration: t.Optional[Expiry],
         *,
         reason: str = '',
     ) -> None:
@@ -134,6 +135,9 @@
         if await _utils.get_active_infraction(ctx, member, "superstar"):
             return
 
+        # Set to default duration if none was provided.
+        duration = duration or await Duration().convert(ctx, SUPERSTARIFY_DEFAULT_DURATION)
+
         # Post the infraction to the API
         old_nick = member.display_name
         infraction_reason = f'Old nickname: {old_nick}. {reason}'

{"golden_diff": "diff --git a/bot/exts/moderation/infraction/superstarify.py b/bot/exts/moderation/infraction/superstarify.py\n--- a/bot/exts/moderation/infraction/superstarify.py\n+++ b/bot/exts/moderation/infraction/superstarify.py\n@@ -11,7 +11,7 @@\n \n from bot import constants\n from bot.bot import Bot\n-from bot.converters import Expiry\n+from bot.converters import Duration, Expiry\n from bot.exts.moderation.infraction import _utils\n from bot.exts.moderation.infraction._scheduler import InfractionScheduler\n from bot.utils.messages import format_user\n@@ -19,6 +19,7 @@\n \n log = logging.getLogger(__name__)\n NICKNAME_POLICY_URL = \"https://pythondiscord.com/pages/rules/#nickname-policy\"\n+SUPERSTARIFY_DEFAULT_DURATION = \"1h\"\n \n with Path(\"bot/resources/stars.json\").open(encoding=\"utf-8\") as stars_file:\n     STAR_NAMES = json.load(stars_file)\n@@ -109,7 +110,7 @@\n         self,\n         ctx: Context,\n         member: Member,\n-        duration: Expiry,\n+        duration: t.Optional[Expiry],\n         *,\n         reason: str = '',\n     ) -> None:\n@@ -134,6 +135,9 @@\n         if await _utils.get_active_infraction(ctx, member, \"superstar\"):\n             return\n \n+        # Set to default duration if none was provided.\n+        duration = duration or await Duration().convert(ctx, SUPERSTARIFY_DEFAULT_DURATION)\n+\n         # Post the infraction to the API\n         old_nick = member.display_name\n         infraction_reason = f'Old nickname: {old_nick}. {reason}'\n", "issue": "Default duration for !superstar command if no duration is specified\n## Context\r\nThe `!superstar` command currently requires a duration to be specified when invoked. \r\n\r\nOften we want to change someone's nickname from something very noisy or that takes up a lot of room until the user can respond and change it themselves. The duration in these cases is not usually that important as we want it to be a quick change.\r\n\r\n## Proposal\r\nIt would be useful if there was a short default duration for this command. Something like 5 or 15 minutes. It would function similarly to the `!mute` command where if no duration is given, it opts for a 1 hour duration.\n", "before_files": [{"content": "import json\nimport logging\nimport random\nimport textwrap\nimport typing as t\nfrom pathlib import Path\n\nfrom discord import Embed, Member\nfrom discord.ext.commands import Cog, Context, command, has_any_role\nfrom discord.utils import escape_markdown\n\nfrom bot import constants\nfrom bot.bot import Bot\nfrom bot.converters import Expiry\nfrom bot.exts.moderation.infraction import _utils\nfrom bot.exts.moderation.infraction._scheduler import InfractionScheduler\nfrom bot.utils.messages import format_user\nfrom bot.utils.time import format_infraction\n\nlog = logging.getLogger(__name__)\nNICKNAME_POLICY_URL = \"https://pythondiscord.com/pages/rules/#nickname-policy\"\n\nwith Path(\"bot/resources/stars.json\").open(encoding=\"utf-8\") as stars_file:\n    STAR_NAMES = json.load(stars_file)\n\n\nclass Superstarify(InfractionScheduler, Cog):\n    \"\"\"A set of commands to moderate terrible nicknames.\"\"\"\n\n    def __init__(self, bot: Bot):\n        super().__init__(bot, supported_infractions={\"superstar\"})\n\n    @Cog.listener()\n    async def on_member_update(self, before: Member, after: Member) -> None:\n        \"\"\"Revert nickname edits if the user has an active superstarify infraction.\"\"\"\n        if before.display_name == after.display_name:\n            return  # User didn't change their nickname. Abort!\n\n        log.trace(\n            f\"{before} ({before.display_name}) is trying to change their nickname to \"\n            f\"{after.display_name}. Checking if the user is in superstar-prison...\"\n        )\n\n        active_superstarifies = await self.bot.api_client.get(\n            \"bot/infractions\",\n            params={\n                \"active\": \"true\",\n                \"type\": \"superstar\",\n                \"user__id\": str(before.id)\n            }\n        )\n\n        if not active_superstarifies:\n            log.trace(f\"{before} has no active superstar infractions.\")\n            return\n\n        infraction = active_superstarifies[0]\n        forced_nick = self.get_nick(infraction[\"id\"], before.id)\n        if after.display_name == forced_nick:\n            return  # Nick change was triggered by this event. Ignore.\n\n        log.info(\n            f\"{after.display_name} ({after.id}) tried to escape superstar prison. \"\n            f\"Changing the nick back to {before.display_name}.\"\n        )\n        await after.edit(\n            nick=forced_nick,\n            reason=f\"Superstarified member tried to escape the prison: {infraction['id']}\"\n        )\n\n        notified = await _utils.notify_infraction(\n            user=after,\n            infr_type=\"Superstarify\",\n            expires_at=format_infraction(infraction[\"expires_at\"]),\n            reason=(\n                \"You have tried to change your nickname on the **Python Discord** server \"\n                f\"from **{before.display_name}** to **{after.display_name}**, but as you \"\n                \"are currently in superstar-prison, you do not have permission to do so.\"\n            ),\n            icon_url=_utils.INFRACTION_ICONS[\"superstar\"][0]\n        )\n\n        if not notified:\n            log.info(\"Failed to DM user about why they cannot change their nickname.\")\n\n    @Cog.listener()\n    async def on_member_join(self, member: Member) -> None:\n        \"\"\"Reapply active superstar infractions for returning members.\"\"\"\n        active_superstarifies = await self.bot.api_client.get(\n            \"bot/infractions\",\n            params={\n                \"active\": \"true\",\n                \"type\": \"superstar\",\n                \"user__id\": member.id\n            }\n        )\n\n        if active_superstarifies:\n            infraction = active_superstarifies[0]\n            action = member.edit(\n                nick=self.get_nick(infraction[\"id\"], member.id),\n                reason=f\"Superstarified member tried to escape the prison: {infraction['id']}\"\n            )\n\n            await self.reapply_infraction(infraction, action)\n\n    @command(name=\"superstarify\", aliases=(\"force_nick\", \"star\", \"starify\", \"superstar\"))\n    async def superstarify(\n        self,\n        ctx: Context,\n        member: Member,\n        duration: Expiry,\n        *,\n        reason: str = '',\n    ) -> None:\n        \"\"\"\n        Temporarily force a random superstar name (like Taylor Swift) to be the user's nickname.\n\n        A unit of time should be appended to the duration.\n        Units (\u2217case-sensitive):\n        \\u2003`y` - years\n        \\u2003`m` - months\u2217\n        \\u2003`w` - weeks\n        \\u2003`d` - days\n        \\u2003`h` - hours\n        \\u2003`M` - minutes\u2217\n        \\u2003`s` - seconds\n\n        Alternatively, an ISO 8601 timestamp can be provided for the duration.\n\n        An optional reason can be provided, which would be added to a message stating their old nickname\n        and linking to the nickname policy.\n        \"\"\"\n        if await _utils.get_active_infraction(ctx, member, \"superstar\"):\n            return\n\n        # Post the infraction to the API\n        old_nick = member.display_name\n        infraction_reason = f'Old nickname: {old_nick}. {reason}'\n        infraction = await _utils.post_infraction(ctx, member, \"superstar\", infraction_reason, duration, active=True)\n        id_ = infraction[\"id\"]\n\n        forced_nick = self.get_nick(id_, member.id)\n        expiry_str = format_infraction(infraction[\"expires_at\"])\n\n        # Apply the infraction\n        async def action() -> None:\n            log.debug(f\"Changing nickname of {member} to {forced_nick}.\")\n            self.mod_log.ignore(constants.Event.member_update, member.id)\n            await member.edit(nick=forced_nick, reason=reason)\n\n        old_nick = escape_markdown(old_nick)\n        forced_nick = escape_markdown(forced_nick)\n\n        nickname_info = textwrap.dedent(f\"\"\"\n            Old nickname: `{old_nick}`\n            New nickname: `{forced_nick}`\n        \"\"\").strip()\n\n        user_message = (\n            f\"Your previous nickname, **{old_nick}**, \"\n            f\"was so bad that we have decided to change it. \"\n            f\"Your new nickname will be **{forced_nick}**.\\n\\n\"\n            \"{reason}\"\n            f\"You will be unable to change your nickname until **{expiry_str}**. \"\n            \"If you're confused by this, please read our \"\n            f\"[official nickname policy]({NICKNAME_POLICY_URL}).\"\n        ).format\n\n        successful = await self.apply_infraction(\n            ctx, infraction, member, action(),\n            user_reason=user_message(reason=f'**Additional details:** {reason}\\n\\n' if reason else ''),\n            additional_info=nickname_info\n        )\n\n        # Send an embed with to the invoking context if superstar was successful.\n        if successful:\n            log.trace(f\"Sending superstar #{id_} embed.\")\n            embed = Embed(\n                title=\"Superstarified!\",\n                colour=constants.Colours.soft_orange,\n                description=user_message(reason='')\n            )\n            await ctx.send(embed=embed)\n\n    @command(name=\"unsuperstarify\", aliases=(\"release_nick\", \"unstar\", \"unstarify\", \"unsuperstar\"))\n    async def unsuperstarify(self, ctx: Context, member: Member) -> None:\n        \"\"\"Remove the superstarify infraction and allow the user to change their nickname.\"\"\"\n        await self.pardon_infraction(ctx, \"superstar\", member)\n\n    async def _pardon_action(self, infraction: _utils.Infraction) -> t.Optional[t.Dict[str, str]]:\n        \"\"\"Pardon a superstar infraction and return a log dict.\"\"\"\n        if infraction[\"type\"] != \"superstar\":\n            return\n\n        guild = self.bot.get_guild(constants.Guild.id)\n        user = guild.get_member(infraction[\"user\"])\n\n        # Don't bother sending a notification if the user left the guild.\n        if not user:\n            log.debug(\n                \"User left the guild and therefore won't be notified about superstar \"\n                f\"{infraction['id']} pardon.\"\n            )\n            return {}\n\n        # DM the user about the expiration.\n        notified = await _utils.notify_pardon(\n            user=user,\n            title=\"You are no longer superstarified\",\n            content=\"You may now change your nickname on the server.\",\n            icon_url=_utils.INFRACTION_ICONS[\"superstar\"][1]\n        )\n\n        return {\n            \"Member\": format_user(user),\n            \"DM\": \"Sent\" if notified else \"**Failed**\"\n        }\n\n    @staticmethod\n    def get_nick(infraction_id: int, member_id: int) -> str:\n        \"\"\"Randomly select a nickname from the Superstarify nickname list.\"\"\"\n        log.trace(f\"Choosing a random nickname for superstar #{infraction_id}.\")\n\n        rng = random.Random(str(infraction_id) + str(member_id))\n        return rng.choice(STAR_NAMES)\n\n    # This cannot be static (must have a __func__ attribute).\n    async def cog_check(self, ctx: Context) -> bool:\n        \"\"\"Only allow moderators to invoke the commands in this cog.\"\"\"\n        return await has_any_role(*constants.MODERATION_ROLES).predicate(ctx)\n\n\ndef setup(bot: Bot) -> None:\n    \"\"\"Load the Superstarify cog.\"\"\"\n    bot.add_cog(Superstarify(bot))\n", "path": "bot/exts/moderation/infraction/superstarify.py"}], "after_files": [{"content": "import json\nimport logging\nimport random\nimport textwrap\nimport typing as t\nfrom pathlib import Path\n\nfrom discord import Embed, Member\nfrom discord.ext.commands import Cog, Context, command, has_any_role\nfrom discord.utils import escape_markdown\n\nfrom bot import constants\nfrom bot.bot import Bot\nfrom bot.converters import Duration, Expiry\nfrom bot.exts.moderation.infraction import _utils\nfrom bot.exts.moderation.infraction._scheduler import InfractionScheduler\nfrom bot.utils.messages import format_user\nfrom bot.utils.time import format_infraction\n\nlog = logging.getLogger(__name__)\nNICKNAME_POLICY_URL = \"https://pythondiscord.com/pages/rules/#nickname-policy\"\nSUPERSTARIFY_DEFAULT_DURATION = \"1h\"\n\nwith Path(\"bot/resources/stars.json\").open(encoding=\"utf-8\") as stars_file:\n    STAR_NAMES = json.load(stars_file)\n\n\nclass Superstarify(InfractionScheduler, Cog):\n    \"\"\"A set of commands to moderate terrible nicknames.\"\"\"\n\n    def __init__(self, bot: Bot):\n        super().__init__(bot, supported_infractions={\"superstar\"})\n\n    @Cog.listener()\n    async def on_member_update(self, before: Member, after: Member) -> None:\n        \"\"\"Revert nickname edits if the user has an active superstarify infraction.\"\"\"\n        if before.display_name == after.display_name:\n            return  # User didn't change their nickname. Abort!\n\n        log.trace(\n            f\"{before} ({before.display_name}) is trying to change their nickname to \"\n            f\"{after.display_name}. Checking if the user is in superstar-prison...\"\n        )\n\n        active_superstarifies = await self.bot.api_client.get(\n            \"bot/infractions\",\n            params={\n                \"active\": \"true\",\n                \"type\": \"superstar\",\n                \"user__id\": str(before.id)\n            }\n        )\n\n        if not active_superstarifies:\n            log.trace(f\"{before} has no active superstar infractions.\")\n            return\n\n        infraction = active_superstarifies[0]\n        forced_nick = self.get_nick(infraction[\"id\"], before.id)\n        if after.display_name == forced_nick:\n            return  # Nick change was triggered by this event. Ignore.\n\n        log.info(\n            f\"{after.display_name} ({after.id}) tried to escape superstar prison. \"\n            f\"Changing the nick back to {before.display_name}.\"\n        )\n        await after.edit(\n            nick=forced_nick,\n            reason=f\"Superstarified member tried to escape the prison: {infraction['id']}\"\n        )\n\n        notified = await _utils.notify_infraction(\n            user=after,\n            infr_type=\"Superstarify\",\n            expires_at=format_infraction(infraction[\"expires_at\"]),\n            reason=(\n                \"You have tried to change your nickname on the **Python Discord** server \"\n                f\"from **{before.display_name}** to **{after.display_name}**, but as you \"\n                \"are currently in superstar-prison, you do not have permission to do so.\"\n            ),\n            icon_url=_utils.INFRACTION_ICONS[\"superstar\"][0]\n        )\n\n        if not notified:\n            log.info(\"Failed to DM user about why they cannot change their nickname.\")\n\n    @Cog.listener()\n    async def on_member_join(self, member: Member) -> None:\n        \"\"\"Reapply active superstar infractions for returning members.\"\"\"\n        active_superstarifies = await self.bot.api_client.get(\n            \"bot/infractions\",\n            params={\n                \"active\": \"true\",\n                \"type\": \"superstar\",\n                \"user__id\": member.id\n            }\n        )\n\n        if active_superstarifies:\n            infraction = active_superstarifies[0]\n            action = member.edit(\n                nick=self.get_nick(infraction[\"id\"], member.id),\n                reason=f\"Superstarified member tried to escape the prison: {infraction['id']}\"\n            )\n\n            await self.reapply_infraction(infraction, action)\n\n    @command(name=\"superstarify\", aliases=(\"force_nick\", \"star\", \"starify\", \"superstar\"))\n    async def superstarify(\n        self,\n        ctx: Context,\n        member: Member,\n        duration: t.Optional[Expiry],\n        *,\n        reason: str = '',\n    ) -> None:\n        \"\"\"\n        Temporarily force a random superstar name (like Taylor Swift) to be the user's nickname.\n\n        A unit of time should be appended to the duration.\n        Units (\u2217case-sensitive):\n        \\u2003`y` - years\n        \\u2003`m` - months\u2217\n        \\u2003`w` - weeks\n        \\u2003`d` - days\n        \\u2003`h` - hours\n        \\u2003`M` - minutes\u2217\n        \\u2003`s` - seconds\n\n        Alternatively, an ISO 8601 timestamp can be provided for the duration.\n\n        An optional reason can be provided, which would be added to a message stating their old nickname\n        and linking to the nickname policy.\n        \"\"\"\n        if await _utils.get_active_infraction(ctx, member, \"superstar\"):\n            return\n\n        # Set to default duration if none was provided.\n        duration = duration or await Duration().convert(ctx, SUPERSTARIFY_DEFAULT_DURATION)\n\n        # Post the infraction to the API\n        old_nick = member.display_name\n        infraction_reason = f'Old nickname: {old_nick}. {reason}'\n        infraction = await _utils.post_infraction(ctx, member, \"superstar\", infraction_reason, duration, active=True)\n        id_ = infraction[\"id\"]\n\n        forced_nick = self.get_nick(id_, member.id)\n        expiry_str = format_infraction(infraction[\"expires_at\"])\n\n        # Apply the infraction\n        async def action() -> None:\n            log.debug(f\"Changing nickname of {member} to {forced_nick}.\")\n            self.mod_log.ignore(constants.Event.member_update, member.id)\n            await member.edit(nick=forced_nick, reason=reason)\n\n        old_nick = escape_markdown(old_nick)\n        forced_nick = escape_markdown(forced_nick)\n\n        nickname_info = textwrap.dedent(f\"\"\"\n            Old nickname: `{old_nick}`\n            New nickname: `{forced_nick}`\n        \"\"\").strip()\n\n        user_message = (\n            f\"Your previous nickname, **{old_nick}**, \"\n            f\"was so bad that we have decided to change it. \"\n            f\"Your new nickname will be **{forced_nick}**.\\n\\n\"\n            \"{reason}\"\n            f\"You will be unable to change your nickname until **{expiry_str}**. \"\n            \"If you're confused by this, please read our \"\n            f\"[official nickname policy]({NICKNAME_POLICY_URL}).\"\n        ).format\n\n        successful = await self.apply_infraction(\n            ctx, infraction, member, action(),\n            user_reason=user_message(reason=f'**Additional details:** {reason}\\n\\n' if reason else ''),\n            additional_info=nickname_info\n        )\n\n        # Send an embed with to the invoking context if superstar was successful.\n        if successful:\n            log.trace(f\"Sending superstar #{id_} embed.\")\n            embed = Embed(\n                title=\"Superstarified!\",\n                colour=constants.Colours.soft_orange,\n                description=user_message(reason='')\n            )\n            await ctx.send(embed=embed)\n\n    @command(name=\"unsuperstarify\", aliases=(\"release_nick\", \"unstar\", \"unstarify\", \"unsuperstar\"))\n    async def unsuperstarify(self, ctx: Context, member: Member) -> None:\n        \"\"\"Remove the superstarify infraction and allow the user to change their nickname.\"\"\"\n        await self.pardon_infraction(ctx, \"superstar\", member)\n\n    async def _pardon_action(self, infraction: _utils.Infraction) -> t.Optional[t.Dict[str, str]]:\n        \"\"\"Pardon a superstar infraction and return a log dict.\"\"\"\n        if infraction[\"type\"] != \"superstar\":\n            return\n\n        guild = self.bot.get_guild(constants.Guild.id)\n        user = guild.get_member(infraction[\"user\"])\n\n        # Don't bother sending a notification if the user left the guild.\n        if not user:\n            log.debug(\n                \"User left the guild and therefore won't be notified about superstar \"\n                f\"{infraction['id']} pardon.\"\n            )\n            return {}\n\n        # DM the user about the expiration.\n        notified = await _utils.notify_pardon(\n            user=user,\n            title=\"You are no longer superstarified\",\n            content=\"You may now change your nickname on the server.\",\n            icon_url=_utils.INFRACTION_ICONS[\"superstar\"][1]\n        )\n\n        return {\n            \"Member\": format_user(user),\n            \"DM\": \"Sent\" if notified else \"**Failed**\"\n        }\n\n    @staticmethod\n    def get_nick(infraction_id: int, member_id: int) -> str:\n        \"\"\"Randomly select a nickname from the Superstarify nickname list.\"\"\"\n        log.trace(f\"Choosing a random nickname for superstar #{infraction_id}.\")\n\n        rng = random.Random(str(infraction_id) + str(member_id))\n        return rng.choice(STAR_NAMES)\n\n    # This cannot be static (must have a __func__ attribute).\n    async def cog_check(self, ctx: Context) -> bool:\n        \"\"\"Only allow moderators to invoke the commands in this cog.\"\"\"\n        return await has_any_role(*constants.MODERATION_ROLES).predicate(ctx)\n\n\ndef setup(bot: Bot) -> None:\n    \"\"\"Load the Superstarify cog.\"\"\"\n    bot.add_cog(Superstarify(bot))\n", "path": "bot/exts/moderation/infraction/superstarify.py"}]}