From 977cc0552bd71018d874246137f812df14bb4d31 Mon Sep 17 00:00:00 2001 From: Harbys Date: Tue, 24 Nov 2020 14:22:55 +0100 Subject: Added Stream and revokestream commands --- bot/constants.py | 28 +++++++++ bot/exts/moderation/stream.py | 138 ++++++++++++++++++++++++++++++++++++++++++ config-default.yml | 3 + 3 files changed, 169 insertions(+) create mode 100644 bot/exts/moderation/stream.py diff --git a/bot/constants.py b/bot/constants.py index 2126b2b37..744fbd512 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -466,6 +466,7 @@ class Roles(metaclass=YAMLGetter): unverified: int verified: int # This is the Developers role on PyDis, here named verified for readability reasons. voice_verified: int + video: int class Guild(metaclass=YAMLGetter): @@ -701,3 +702,30 @@ ERROR_REPLIES = [ "Noooooo!!", "I can't believe you've done this", ] + +# TIME_FORMATS defines aliases and multipliers for time formats +# key is a standard time unit name like second ,year, decade etc. +# mul is a multiplier where duration of said time unit * multiplier = time in seconds +# eg. 1 day = 1 * multiplier seconds, so mul = 86400 +TIME_FORMATS = { + "second": { + "aliases": ("s", "sec", "seconds", "secs"), + "mul": 1 + }, + "minute": { + "aliases": ("m", "min", "mins", "minutes"), + "mul": 60 + }, + "hour": { + "aliases": ("h", "hr", "hrs", "hours"), + "mul": 3600 + }, + "day": { + "aliases": ("d", "days"), + "mul": 86400 + }, + "year": { + "aliases": ("yr", "yrs", "years"), + "mul": 31536000 + } +} diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py new file mode 100644 index 000000000..673a21b1b --- /dev/null +++ b/bot/exts/moderation/stream.py @@ -0,0 +1,138 @@ +from discord.ext import commands, tasks +import discord + +from bot.constants import Roles, STAFF_ROLES, Guild, TIME_FORMATS +from bot import Bot +import time +from async_rediscache import RedisCache + +# Constant error messages +NO_USER_SPECIFIED = "Please specify a user" +TIME_FORMAT_NOT_VALID = "Please specify a valid time format ex. 10h or 1day" +TIME_LESS_EQ_0 = "Duration can not be a 0 or lower" +USER_ALREADY_ALLOWED_TO_STREAM = "This user can already stream" +USER_ALREADY_NOT_ALLOWED_TO_STREAM = "This user already can't stream" + + +# FORMATS holds a combined list of all allowed time units +# made from TIME_FORMATS constant +FORMATS = [] +for key, entry in TIME_FORMATS.items(): + FORMATS.extend(entry["aliases"]) + FORMATS.append(key) + + +class Stream(commands.Cog): + """Stream class handles giving screen sharing permission with commands""" + + # Data cache storing userid to unix_time relation + # user id is used to get member who's streaming permission need to be revoked after some time + # unix_time is a time when user's streaming permission needs tp be revoked in unix time notation + user_cache = RedisCache() + + def __init__(self, bot: Bot): + self.bot = bot + self.remove_permissions.start() + self.guild_static = None + + @staticmethod + def _link_from_alias(time_format) -> (dict, str): + """Get TIME_FORMATS key and entry by time format or any of its aliases""" + for format_key, val in TIME_FORMATS.items(): + if format_key == time_format or time_format in val["aliases"]: + return TIME_FORMATS[format_key], format_key + + def _parse_time_to_seconds(self, duration, time_format) -> int: + """Get time in seconds from duration and time format""" + return duration * self._link_from_alias(time_format)[0]["mul"] + + @commands.command(aliases=("streaming", "share")) + @commands.has_any_role(*STAFF_ROLES) + async def stream( + self, + ctx: commands.Context, + user: discord.Member = None, + duration: int = 1, + time_format: str = "h", + *_ + ): + """ + stream handles stream command + argument user - required user mention, any errors should be handled by upper level handler + duration - int must be higher than 0 - defaults to 1 + time_format - str defining what time unit you want to use, must be any of FORMATS - defaults to h + + Command give user permission to stream and takes it away after provided duration + """ + # Check for required user argument + # if not provided send NO_USER_SPECIFIED message + if not user: + await ctx.send(NO_USER_SPECIFIED) + return + + # Time can't be negative lol + if duration <= 0: + await ctx.send(TIME_LESS_EQ_0) + return + + # Check if time_format argument is a valid time format + # eg. d, day etc are aliases for day time format + if time_format not in FORMATS: + await ctx.send(TIME_FORMAT_NOT_VALID) + return + + # Check if user already has streaming permission + already_allowed = any(Roles.video == role.id for role in user.roles) + if already_allowed: + await ctx.send(USER_ALREADY_ALLOWED_TO_STREAM) + return + + # Set user id - time in redis cache and add streaming permission role + await self.user_cache.set(user.id, time.time() + self._parse_time_to_seconds(duration, time_format)) + await user.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted") + await ctx.send(f"{user.mention} can now stream for {duration} {self._link_from_alias(time_format)[1]}/s") + + @tasks.loop(seconds=30) + async def remove_permissions(self): + """ + background loop for removing streaming permission + """ + all_entries = await self.user_cache.items() + for user_id, delete_time in all_entries: + if time.time() > delete_time: + member = self.guild_static.fetch_memebr(user_id) + if member: + await member.remove_roles(discord.Object(Roles.video), reason="Temporary streaming access revoked") + await self.user_cache.pop(user_id) + + @remove_permissions.before_loop + async def await_ready(self): + """Wait for bot to be ready before starting remove_permissions loop + and get guild by id + """ + await self.bot.wait_until_ready() + self.guild_static = self.bot.get_guild(Guild.id) + + @commands.command(aliases=("unstream", )) + @commands.has_any_role(*STAFF_ROLES) + async def revokestream( + self, + ctx: commands.Context, + user: discord.Member = None + ): + """ + stream handles revokestream command + argument user - required user mention, any errors should be handled by upper level handler + + command removes streaming permission from a user + """ + not_allowed = not any(Roles.video == role.id for role in user.roles) + if not_allowed: + await user.remove_roles(discord.Object(Roles.video)) + else: + await ctx.send(USER_ALREADY_NOT_ALLOWED_TO_STREAM) + + +def setup(bot: Bot) -> None: + """Loads the Stream cog.""" + bot.add_cog(Stream(bot)) diff --git a/config-default.yml b/config-default.yml index 89493c4de..700406f4e 100644 --- a/config-default.yml +++ b/config-default.yml @@ -251,6 +251,9 @@ guild: jammers: 737249140966162473 team_leaders: 737250302834638889 + # Streaming + video: 764245844798079016 + moderation_roles: - *OWNERS_ROLE - *ADMINS_ROLE -- cgit v1.2.3 From a3aec34b444d75292f17dadc308457490c395620 Mon Sep 17 00:00:00 2001 From: Harbys Date: Tue, 24 Nov 2020 15:03:39 +0100 Subject: import fix --- bot/exts/moderation/stream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 673a21b1b..ceb291027 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -2,7 +2,7 @@ from discord.ext import commands, tasks import discord from bot.constants import Roles, STAFF_ROLES, Guild, TIME_FORMATS -from bot import Bot +from bot.bot import Bot import time from async_rediscache import RedisCache -- cgit v1.2.3 From 91f1962703902fffabbbd7b710373850763e3ed7 Mon Sep 17 00:00:00 2001 From: Harbys Date: Tue, 24 Nov 2020 15:05:50 +0100 Subject: Add additional year alias --- bot/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/constants.py b/bot/constants.py index 744fbd512..6c0ef913b 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -725,7 +725,7 @@ TIME_FORMATS = { "mul": 86400 }, "year": { - "aliases": ("yr", "yrs", "years"), + "aliases": ("yr", "yrs", "years", "y"), "mul": 31536000 } } -- cgit v1.2.3 From b18127c3df9b46a33648a0db376a3587c9fbe6be Mon Sep 17 00:00:00 2001 From: Harbys Date: Tue, 24 Nov 2020 15:22:01 +0100 Subject: Add 2 first unit tests for Stream cog --- tests/bot/exts/moderation/test_stream.py | 45 ++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 tests/bot/exts/moderation/test_stream.py diff --git a/tests/bot/exts/moderation/test_stream.py b/tests/bot/exts/moderation/test_stream.py new file mode 100644 index 000000000..872627fc1 --- /dev/null +++ b/tests/bot/exts/moderation/test_stream.py @@ -0,0 +1,45 @@ +import unittest +from bot.constants import TIME_FORMATS +from bot.exts.moderation.stream import Stream +from tests.helpers import MockContext, MockBot + + +class StreamCommandTest(unittest.IsolatedAsyncioTestCase): + + def setUp(self) -> None: + self.bot = MockBot() + self.cog = Stream(self.bot) + self.ctx = MockContext() + + def test_linking_time_format_from_alias_or_key(self): + FORMATS = [] + for key, entry in TIME_FORMATS.items(): + FORMATS.extend(entry["aliases"]) + FORMATS.append(key) + + test_cases = (("sec", "second"), + ("s", "second"), + ("seconds", "second"), + ("second", "second"), + ("secs", "second"), + ("min", "minute"), + ("m", "minute"), + ("minutes", "minute"), + ("hr", "hour"), + ("hrs", "hour"), + ("hours", "hour"), + ("d", "day"), + ("days", "day"), + ("yr", "year"), + ("yrs", "year"), + ("y", "year")) + + for case in test_cases: + linked = self.cog._link_from_alias(case[0])[1] + self.assertEqual(linked, case[1]) + + def test_parsing_duration_and_time_format_to_seconds(self): + test_cases = ((1, "minute", 60), (5, "second", 5), (2, "day", 172800)) + for case in test_cases: + time_in_seconds = self.cog._parse_time_to_seconds(case[0], case[1]) + self.assertEqual(time_in_seconds, case[2]) -- cgit v1.2.3 From 42c862b49923e30f66632902c86cfd168021b1e8 Mon Sep 17 00:00:00 2001 From: Harbys Date: Tue, 24 Nov 2020 17:55:25 +0100 Subject: Add more tests and some comments --- tests/bot/exts/moderation/test_stream.py | 46 +++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/tests/bot/exts/moderation/test_stream.py b/tests/bot/exts/moderation/test_stream.py index 872627fc1..7aa2fae26 100644 --- a/tests/bot/exts/moderation/test_stream.py +++ b/tests/bot/exts/moderation/test_stream.py @@ -1,7 +1,27 @@ +import asyncio import unittest -from bot.constants import TIME_FORMATS + +from async_rediscache import RedisSession + +from bot.constants import TIME_FORMATS, Roles from bot.exts.moderation.stream import Stream -from tests.helpers import MockContext, MockBot +from tests.helpers import MockBot, MockRole, MockMember + +redis_session = None +redis_loop = asyncio.get_event_loop() + + +def setUpModule(): # noqa: N802 + """Create and connect to the fakeredis session.""" + global redis_session + redis_session = RedisSession(use_fakeredis=True) + redis_loop.run_until_complete(redis_session.connect()) + + +def tearDownModule(): # noqa: N802 + """Close the fakeredis session.""" + if redis_session: + redis_loop.run_until_complete(redis_session.close()) class StreamCommandTest(unittest.IsolatedAsyncioTestCase): @@ -9,9 +29,13 @@ class StreamCommandTest(unittest.IsolatedAsyncioTestCase): def setUp(self) -> None: self.bot = MockBot() self.cog = Stream(self.bot) - self.ctx = MockContext() def test_linking_time_format_from_alias_or_key(self): + """ + User provided time format needs to be lined to a proper entry in TIME_FORMATS + This Test checks _link_from_alias method + Checking for whether alias or key exists in TIME_FORMATS is done before calling this function + """ FORMATS = [] for key, entry in TIME_FORMATS.items(): FORMATS.extend(entry["aliases"]) @@ -39,7 +63,23 @@ class StreamCommandTest(unittest.IsolatedAsyncioTestCase): self.assertEqual(linked, case[1]) def test_parsing_duration_and_time_format_to_seconds(self): + """ + Test calculating time in seconds from duration and time unit + This test is technically dependent on _link_from_alias function, not the best practice but necessary + """ test_cases = ((1, "minute", 60), (5, "second", 5), (2, "day", 172800)) for case in test_cases: time_in_seconds = self.cog._parse_time_to_seconds(case[0], case[1]) self.assertEqual(time_in_seconds, case[2]) + + def test_checking_if_user_has_streaming_permission(self): + """ + Test searching for video role in Member.roles + """ + user1 = MockMember(roles=[MockRole(id=Roles.video)]) + user2 = MockMember() + already_allowed_user1 = any(Roles.video == role.id for role in user1.roles) + self.assertEqual(already_allowed_user1, True) + + already_allowed_user2 = any(Roles.video == role.id for role in user2.roles) + self.assertEqual(already_allowed_user2, False) -- cgit v1.2.3 From 25fe0c919edfffbca5a73554853d076455e2d997 Mon Sep 17 00:00:00 2001 From: Harbys Date: Tue, 24 Nov 2020 19:41:52 +0100 Subject: fixing code to be flake8 compliant --- bot/exts/moderation/stream.py | 43 +++++++++++++++----------------- tests/bot/exts/moderation/test_stream.py | 8 ++---- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index ceb291027..a44095273 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -1,10 +1,11 @@ -from discord.ext import commands, tasks +import time + import discord +from async_rediscache import RedisCache +from discord.ext import commands, tasks -from bot.constants import Roles, STAFF_ROLES, Guild, TIME_FORMATS from bot.bot import Bot -import time -from async_rediscache import RedisCache +from bot.constants import Guild, Roles, STAFF_ROLES, TIME_FORMATS # Constant error messages NO_USER_SPECIFIED = "Please specify a user" @@ -23,7 +24,7 @@ for key, entry in TIME_FORMATS.items(): class Stream(commands.Cog): - """Stream class handles giving screen sharing permission with commands""" + """Stream class handles giving screen sharing permission with commands.""" # Data cache storing userid to unix_time relation # user id is used to get member who's streaming permission need to be revoked after some time @@ -36,14 +37,14 @@ class Stream(commands.Cog): self.guild_static = None @staticmethod - def _link_from_alias(time_format) -> (dict, str): - """Get TIME_FORMATS key and entry by time format or any of its aliases""" + def _link_from_alias(time_format: str) -> (dict, str): + """Get TIME_FORMATS key and entry by time format or any of its aliases.""" for format_key, val in TIME_FORMATS.items(): if format_key == time_format or time_format in val["aliases"]: return TIME_FORMATS[format_key], format_key - def _parse_time_to_seconds(self, duration, time_format) -> int: - """Get time in seconds from duration and time format""" + def _parse_time_to_seconds(self, duration: int, time_format: str) -> int: + """Get time in seconds from duration and time format.""" return duration * self._link_from_alias(time_format)[0]["mul"] @commands.command(aliases=("streaming", "share")) @@ -55,13 +56,13 @@ class Stream(commands.Cog): duration: int = 1, time_format: str = "h", *_ - ): + ) -> None: """ - stream handles stream command + Stream handles stream command. + argument user - required user mention, any errors should be handled by upper level handler duration - int must be higher than 0 - defaults to 1 time_format - str defining what time unit you want to use, must be any of FORMATS - defaults to h - Command give user permission to stream and takes it away after provided duration """ # Check for required user argument @@ -93,10 +94,8 @@ class Stream(commands.Cog): await ctx.send(f"{user.mention} can now stream for {duration} {self._link_from_alias(time_format)[1]}/s") @tasks.loop(seconds=30) - async def remove_permissions(self): - """ - background loop for removing streaming permission - """ + async def remove_permissions(self) -> None: + """Background loop for removing streaming permission.""" all_entries = await self.user_cache.items() for user_id, delete_time in all_entries: if time.time() > delete_time: @@ -106,10 +105,8 @@ class Stream(commands.Cog): await self.user_cache.pop(user_id) @remove_permissions.before_loop - async def await_ready(self): - """Wait for bot to be ready before starting remove_permissions loop - and get guild by id - """ + async def await_ready(self) -> None: + """Wait for bot to be ready before starting remove_permissions loop and get guild by id.""" await self.bot.wait_until_ready() self.guild_static = self.bot.get_guild(Guild.id) @@ -119,11 +116,11 @@ class Stream(commands.Cog): self, ctx: commands.Context, user: discord.Member = None - ): + ) -> None: """ - stream handles revokestream command - argument user - required user mention, any errors should be handled by upper level handler + Revokestream handles revokestream command. + argument user - required user mention, any errors should be handled by upper level handler command removes streaming permission from a user """ not_allowed = not any(Roles.video == role.id for role in user.roles) diff --git a/tests/bot/exts/moderation/test_stream.py b/tests/bot/exts/moderation/test_stream.py index 7aa2fae26..467c373aa 100644 --- a/tests/bot/exts/moderation/test_stream.py +++ b/tests/bot/exts/moderation/test_stream.py @@ -3,9 +3,9 @@ import unittest from async_rediscache import RedisSession -from bot.constants import TIME_FORMATS, Roles +from bot.constants import Roles from bot.exts.moderation.stream import Stream -from tests.helpers import MockBot, MockRole, MockMember +from tests.helpers import MockBot, MockMember, MockRole redis_session = None redis_loop = asyncio.get_event_loop() @@ -36,10 +36,6 @@ class StreamCommandTest(unittest.IsolatedAsyncioTestCase): This Test checks _link_from_alias method Checking for whether alias or key exists in TIME_FORMATS is done before calling this function """ - FORMATS = [] - for key, entry in TIME_FORMATS.items(): - FORMATS.extend(entry["aliases"]) - FORMATS.append(key) test_cases = (("sec", "second"), ("s", "second"), -- cgit v1.2.3 From 39401cd99b4dffc423a88f18a6e08c7cf1bd26e9 Mon Sep 17 00:00:00 2001 From: Harbys <44087388+Harbys@users.noreply.github.com> Date: Wed, 25 Nov 2020 17:15:53 +0100 Subject: removing redundant class names Co-authored-by: Mark --- bot/exts/moderation/stream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index a44095273..92fd9955f 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -24,7 +24,7 @@ for key, entry in TIME_FORMATS.items(): class Stream(commands.Cog): - """Stream class handles giving screen sharing permission with commands.""" + """Grant and revoke streaming permissions from users.""" # Data cache storing userid to unix_time relation # user id is used to get member who's streaming permission need to be revoked after some time -- cgit v1.2.3 From 189f8c31bcf9f58cf72abf7f86061746613dfd7f Mon Sep 17 00:00:00 2001 From: Harbys <44087388+Harbys@users.noreply.github.com> Date: Wed, 25 Nov 2020 17:19:17 +0100 Subject: removing redundant descriptions Co-authored-by: Mark --- bot/exts/moderation/stream.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 92fd9955f..ef52cd107 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -117,12 +117,7 @@ class Stream(commands.Cog): ctx: commands.Context, user: discord.Member = None ) -> None: - """ - Revokestream handles revokestream command. - - argument user - required user mention, any errors should be handled by upper level handler - command removes streaming permission from a user - """ + """Revoke streaming permissions from a user.""" not_allowed = not any(Roles.video == role.id for role in user.roles) if not_allowed: await user.remove_roles(discord.Object(Roles.video)) -- cgit v1.2.3 From 2f97f5705cbc073c9460e3a60cde4d53d7f3d5e0 Mon Sep 17 00:00:00 2001 From: Harbys Date: Wed, 25 Nov 2020 17:11:53 +0100 Subject: spelling fix from fetch_membr to fetch_member --- bot/exts/moderation/stream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index ef52cd107..458559b18 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -99,7 +99,7 @@ class Stream(commands.Cog): all_entries = await self.user_cache.items() for user_id, delete_time in all_entries: if time.time() > delete_time: - member = self.guild_static.fetch_memebr(user_id) + member = self.guild_static.fetch_memeber(user_id) if member: await member.remove_roles(discord.Object(Roles.video), reason="Temporary streaming access revoked") await self.user_cache.pop(user_id) -- cgit v1.2.3 From f823f0e9a48f346a8a2ead7ded03da29104f064e Mon Sep 17 00:00:00 2001 From: Harbys Date: Wed, 25 Nov 2020 17:14:16 +0100 Subject: removed share alias --- bot/exts/moderation/stream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 458559b18..2ce248f03 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -47,7 +47,7 @@ class Stream(commands.Cog): """Get time in seconds from duration and time format.""" return duration * self._link_from_alias(time_format)[0]["mul"] - @commands.command(aliases=("streaming", "share")) + @commands.command(aliases=("streaming",)) @commands.has_any_role(*STAFF_ROLES) async def stream( self, -- cgit v1.2.3 From e4907d6e06f5ac9d94d7dcfe13dc7bb2c33cd65a Mon Sep 17 00:00:00 2001 From: Harbys Date: Wed, 25 Nov 2020 17:18:05 +0100 Subject: fixing required arguments --- bot/exts/moderation/stream.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 2ce248f03..7678c3184 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -8,7 +8,6 @@ from bot.bot import Bot from bot.constants import Guild, Roles, STAFF_ROLES, TIME_FORMATS # Constant error messages -NO_USER_SPECIFIED = "Please specify a user" TIME_FORMAT_NOT_VALID = "Please specify a valid time format ex. 10h or 1day" TIME_LESS_EQ_0 = "Duration can not be a 0 or lower" USER_ALREADY_ALLOWED_TO_STREAM = "This user can already stream" @@ -52,7 +51,7 @@ class Stream(commands.Cog): async def stream( self, ctx: commands.Context, - user: discord.Member = None, + user: discord.Member, duration: int = 1, time_format: str = "h", *_ @@ -65,12 +64,6 @@ class Stream(commands.Cog): time_format - str defining what time unit you want to use, must be any of FORMATS - defaults to h Command give user permission to stream and takes it away after provided duration """ - # Check for required user argument - # if not provided send NO_USER_SPECIFIED message - if not user: - await ctx.send(NO_USER_SPECIFIED) - return - # Time can't be negative lol if duration <= 0: await ctx.send(TIME_LESS_EQ_0) -- cgit v1.2.3 From 9eb729d89e2969d284a546b539ab720e36007fab Mon Sep 17 00:00:00 2001 From: Harbys Date: Wed, 25 Nov 2020 17:25:49 +0100 Subject: fixing punctuation and adding Emojis to messages --- bot/exts/moderation/stream.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 7678c3184..ca4284e77 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -5,13 +5,13 @@ from async_rediscache import RedisCache from discord.ext import commands, tasks from bot.bot import Bot -from bot.constants import Guild, Roles, STAFF_ROLES, TIME_FORMATS +from bot.constants import Guild, Roles, STAFF_ROLES, TIME_FORMATS, Emojis # Constant error messages -TIME_FORMAT_NOT_VALID = "Please specify a valid time format ex. 10h or 1day" -TIME_LESS_EQ_0 = "Duration can not be a 0 or lower" -USER_ALREADY_ALLOWED_TO_STREAM = "This user can already stream" -USER_ALREADY_NOT_ALLOWED_TO_STREAM = "This user already can't stream" +TIME_FORMAT_NOT_VALID = f"{Emojis.cross_mark}Please specify a valid time format ex. 10h or 1day." +TIME_LESS_EQ_0 = f"{Emojis.cross_mark}Duration can not be a 0 or lower." +USER_ALREADY_ALLOWED_TO_STREAM = f"{Emojis.cross_mark}This user can already stream." +USER_ALREADY_NOT_ALLOWED_TO_STREAM = f"{Emojis.cross_mark}This user already can't stream." # FORMATS holds a combined list of all allowed time units @@ -84,7 +84,8 @@ class Stream(commands.Cog): # Set user id - time in redis cache and add streaming permission role await self.user_cache.set(user.id, time.time() + self._parse_time_to_seconds(duration, time_format)) await user.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted") - await ctx.send(f"{user.mention} can now stream for {duration} {self._link_from_alias(time_format)[1]}/s") + await ctx.send(f"{Emojis.check_mark}{user.mention} can now stream for " + f"{duration} {self._link_from_alias(time_format)[1]}/s.") @tasks.loop(seconds=30) async def remove_permissions(self) -> None: -- cgit v1.2.3 From bcbcd3e8b6bc95c96d7c316d032b9f774773e961 Mon Sep 17 00:00:00 2001 From: Harbys Date: Wed, 25 Nov 2020 17:34:55 +0100 Subject: add success message after revokestream command --- bot/exts/moderation/stream.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index ca4284e77..7dd72a95b 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -115,6 +115,7 @@ class Stream(commands.Cog): not_allowed = not any(Roles.video == role.id for role in user.roles) if not_allowed: await user.remove_roles(discord.Object(Roles.video)) + await ctx.send(f"{Emojis.check_mark}Streaming permission taken from {user.display_name}") else: await ctx.send(USER_ALREADY_NOT_ALLOWED_TO_STREAM) -- cgit v1.2.3 From 16936aad19978078a872ce8ebec82f30a3e7442f Mon Sep 17 00:00:00 2001 From: Harbys Date: Fri, 27 Nov 2020 08:44:20 +0100 Subject: move to Scheduler --- Pipfile.lock | 68 +++++++++++--------- bot/constants.py | 27 -------- bot/exts/moderation/stream.py | 106 ++++++++++--------------------- tests/bot/exts/moderation/test_stream.py | 56 ---------------- 4 files changed, 72 insertions(+), 185 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 541db1627..25fcab4b1 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -187,6 +187,7 @@ "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b", "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2" ], + "index": "pypi", "markers": "sys_platform == 'win32'", "version": "==0.4.4" }, @@ -231,10 +232,10 @@ }, "fakeredis": { "hashes": [ - "sha256:8070b7fce16f828beaef2c757a4354af91698685d5232404f1aeeb233529c7a5", - "sha256:f8c8ea764d7b6fd801e7f5486e3edd32ca991d506186f1923a01fc072e33c271" + "sha256:01cb47d2286825a171fb49c0e445b1fa9307087e07cbb3d027ea10dbff108b6a", + "sha256:2c6041cf0225889bc403f3949838b2c53470a95a9e2d4272422937786f5f8f73" ], - "version": "==1.4.4" + "version": "==1.4.5" }, "feedparser": { "hashes": [ @@ -538,6 +539,15 @@ "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.4.7" }, + "pyreadline": { + "hashes": [ + "sha256:4530592fc2e85b25b1a9f79664433da09237c1a270e4d78ea5aa3a2c7229e2d1", + "sha256:65540c21bfe14405a3a77e4c085ecfce88724743a4ead47c66b84defcf82c32e", + "sha256:9ce5fa65b8992dfa373bddc5b6e0864ead8f291c94fbfec05fbd5c836162e67b" + ], + "markers": "sys_platform == 'win32'", + "version": "==2.1" + }, "python-dateutil": { "hashes": [ "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", @@ -555,18 +565,18 @@ }, "pyyaml": { "hashes": [ - "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf", - "sha256:ad9c67312c84def58f3c04504727ca879cb0013b2517c85a9a253f0cb6380c0a", - "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c", + "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97", "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76", + "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2", "sha256:6034f55dab5fea9e53f436aa68fa3ace2634918e8b5994d82f3621c04ff5ed2e", "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648", - "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d", - "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97", + "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf", "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f", - "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2", - "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee", "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2", + "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee", + "sha256:ad9c67312c84def58f3c04504727ca879cb0013b2517c85a9a253f0cb6380c0a", + "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d", + "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c", "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a" ], "index": "pypi", @@ -846,11 +856,11 @@ }, "flake8-bugbear": { "hashes": [ - "sha256:a3ddc03ec28ba2296fc6f89444d1c946a6b76460f859795b35b77d4920a51b63", - "sha256:bd02e4b009fb153fe6072c31c52aeab5b133d508095befb2ffcf3b41c4823162" + "sha256:528020129fea2dea33a466b9d64ab650aa3e5f9ffc788b70ea4bc6cf18283538", + "sha256:f35b8135ece7a014bc0aee5b5d485334ac30a6da48494998cc1fabf7ec70d703" ], "index": "pypi", - "version": "==20.1.4" + "version": "==20.11.1" }, "flake8-docstrings": { "hashes": [ @@ -900,11 +910,11 @@ }, "identify": { "hashes": [ - "sha256:5dd84ac64a9a115b8e0b27d1756b244b882ad264c3c423f42af8235a6e71ca12", - "sha256:c9504ba6a043ee2db0a9d69e43246bc138034895f6338d5aed1b41e4a73b1513" + "sha256:943cd299ac7f5715fcb3f684e2fc1594c1e0f22a90d15398e5888143bd4144b5", + "sha256:cc86e6a9a390879dcc2976cef169dd9cc48843ed70b7380f321d1b118163c60e" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.5.9" + "version": "==1.5.10" }, "idna": { "hashes": [ @@ -938,11 +948,11 @@ }, "pre-commit": { "hashes": [ - "sha256:22e6aa3bd571debb01eb7d34483f11c01b65237be4eebbf30c3d4fb65762d315", - "sha256:905ebc9b534b991baec87e934431f2d0606ba27f2b90f7f652985f5a5b8b6ae6" + "sha256:4aee0db4808fa48d2458cedd5b9a084ef24dda1a0fa504432a11977a4d1cfd0a", + "sha256:b2d106d51c6ba6217e859d81774aae33fd825fe7de0dcf0c46e2586333d7a92e" ], "index": "pypi", - "version": "==2.8.2" + "version": "==2.9.0" }, "pycodestyle": { "hashes": [ @@ -970,18 +980,18 @@ }, "pyyaml": { "hashes": [ - "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf", - "sha256:ad9c67312c84def58f3c04504727ca879cb0013b2517c85a9a253f0cb6380c0a", - "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c", + "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97", "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76", + "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2", "sha256:6034f55dab5fea9e53f436aa68fa3ace2634918e8b5994d82f3621c04ff5ed2e", "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648", - "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d", - "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97", + "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf", "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f", - "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2", - "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee", "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2", + "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee", + "sha256:ad9c67312c84def58f3c04504727ca879cb0013b2517c85a9a253f0cb6380c0a", + "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d", + "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c", "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a" ], "index": "pypi", @@ -1028,11 +1038,11 @@ }, "virtualenv": { "hashes": [ - "sha256:b0011228208944ce71052987437d3843e05690b2f23d1c7da4263fde104c97a2", - "sha256:b8d6110f493af256a40d65e29846c69340a947669eec8ce784fcf3dd3af28380" + "sha256:07cff122e9d343140366055f31be4dcd61fd598c69d11cd33a9d9c8df4546dd7", + "sha256:e0aac7525e880a429764cefd3aaaff54afb5d9f25c82627563603f5d7de5a6e5" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.1.0" + "version": "==20.2.1" } } } diff --git a/bot/constants.py b/bot/constants.py index 33ed29c39..dca83e7ab 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -705,30 +705,3 @@ ERROR_REPLIES = [ "Noooooo!!", "I can't believe you've done this", ] - -# TIME_FORMATS defines aliases and multipliers for time formats -# key is a standard time unit name like second ,year, decade etc. -# mul is a multiplier where duration of said time unit * multiplier = time in seconds -# eg. 1 day = 1 * multiplier seconds, so mul = 86400 -TIME_FORMATS = { - "second": { - "aliases": ("s", "sec", "seconds", "secs"), - "mul": 1 - }, - "minute": { - "aliases": ("m", "min", "mins", "minutes"), - "mul": 60 - }, - "hour": { - "aliases": ("h", "hr", "hrs", "hours"), - "mul": 3600 - }, - "day": { - "aliases": ("d", "days"), - "mul": 86400 - }, - "year": { - "aliases": ("yr", "yrs", "years", "y"), - "mul": 31536000 - } -} diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 7dd72a95b..0fc004d75 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -1,11 +1,11 @@ -import time - import discord -from async_rediscache import RedisCache -from discord.ext import commands, tasks +from discord.ext import commands from bot.bot import Bot -from bot.constants import Guild, Roles, STAFF_ROLES, TIME_FORMATS, Emojis +from bot.constants import Emojis, Roles, STAFF_ROLES +from bot.converters import Expiry +from bot.utils.scheduling import Scheduler +from bot.utils.time import format_infraction_with_duration # Constant error messages TIME_FORMAT_NOT_VALID = f"{Emojis.cross_mark}Please specify a valid time format ex. 10h or 1day." @@ -14,37 +14,17 @@ USER_ALREADY_ALLOWED_TO_STREAM = f"{Emojis.cross_mark}This user can already stre USER_ALREADY_NOT_ALLOWED_TO_STREAM = f"{Emojis.cross_mark}This user already can't stream." -# FORMATS holds a combined list of all allowed time units -# made from TIME_FORMATS constant -FORMATS = [] -for key, entry in TIME_FORMATS.items(): - FORMATS.extend(entry["aliases"]) - FORMATS.append(key) - - class Stream(commands.Cog): """Grant and revoke streaming permissions from users.""" - # Data cache storing userid to unix_time relation - # user id is used to get member who's streaming permission need to be revoked after some time - # unix_time is a time when user's streaming permission needs tp be revoked in unix time notation - user_cache = RedisCache() - def __init__(self, bot: Bot): self.bot = bot - self.remove_permissions.start() - self.guild_static = None + self.scheduler = Scheduler(self.__class__.__name__) @staticmethod - def _link_from_alias(time_format: str) -> (dict, str): - """Get TIME_FORMATS key and entry by time format or any of its aliases.""" - for format_key, val in TIME_FORMATS.items(): - if format_key == time_format or time_format in val["aliases"]: - return TIME_FORMATS[format_key], format_key - - def _parse_time_to_seconds(self, duration: int, time_format: str) -> int: - """Get time in seconds from duration and time format.""" - return duration * self._link_from_alias(time_format)[0]["mul"] + async def _remove_streaming_permission(schedule_user: discord.Member) -> None: + """Remove streaming permission from Member""" + await schedule_user.remove_roles(discord.Object(Roles.video), reason="Temporary streaming access revoked") @commands.command(aliases=("streaming",)) @commands.has_any_role(*STAFF_ROLES) @@ -52,68 +32,48 @@ class Stream(commands.Cog): self, ctx: commands.Context, user: discord.Member, - duration: int = 1, - time_format: str = "h", + duration: Expiry, *_ ) -> None: """ - Stream handles stream command. - - argument user - required user mention, any errors should be handled by upper level handler - duration - int must be higher than 0 - defaults to 1 - time_format - str defining what time unit you want to use, must be any of FORMATS - defaults to h - Command give user permission to stream and takes it away after provided duration + Temporarily grant streaming permissions to a user for a given duration. + A unit of time should be appended to the duration. + Units (∗case-sensitive): + \u2003`y` - years + \u2003`m` - months∗ + \u2003`w` - weeks + \u2003`d` - days + \u2003`h` - hours + \u2003`M` - minutes∗ + \u2003`s` - seconds + Alternatively, an ISO 8601 timestamp can be provided for the duration. """ - # Time can't be negative lol - if duration <= 0: - await ctx.send(TIME_LESS_EQ_0) - return - - # Check if time_format argument is a valid time format - # eg. d, day etc are aliases for day time format - if time_format not in FORMATS: - await ctx.send(TIME_FORMAT_NOT_VALID) - return - # Check if user already has streaming permission already_allowed = any(Roles.video == role.id for role in user.roles) if already_allowed: await ctx.send(USER_ALREADY_ALLOWED_TO_STREAM) return - # Set user id - time in redis cache and add streaming permission role - await self.user_cache.set(user.id, time.time() + self._parse_time_to_seconds(duration, time_format)) + # Schedule task to remove streaming permission from Member + self.scheduler.schedule_at(duration, user.id, self._remove_streaming_permission(user)) await user.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted") - await ctx.send(f"{Emojis.check_mark}{user.mention} can now stream for " - f"{duration} {self._link_from_alias(time_format)[1]}/s.") - - @tasks.loop(seconds=30) - async def remove_permissions(self) -> None: - """Background loop for removing streaming permission.""" - all_entries = await self.user_cache.items() - for user_id, delete_time in all_entries: - if time.time() > delete_time: - member = self.guild_static.fetch_memeber(user_id) - if member: - await member.remove_roles(discord.Object(Roles.video), reason="Temporary streaming access revoked") - await self.user_cache.pop(user_id) - - @remove_permissions.before_loop - async def await_ready(self) -> None: - """Wait for bot to be ready before starting remove_permissions loop and get guild by id.""" - await self.bot.wait_until_ready() - self.guild_static = self.bot.get_guild(Guild.id) + await ctx.send(f"{Emojis.check_mark}{user.mention} can now stream until " + f"{format_infraction_with_duration(str(duration))}.") @commands.command(aliases=("unstream", )) @commands.has_any_role(*STAFF_ROLES) async def revokestream( self, ctx: commands.Context, - user: discord.Member = None + user: discord.Member ) -> None: - """Revoke streaming permissions from a user.""" - not_allowed = not any(Roles.video == role.id for role in user.roles) - if not_allowed: + """Take away streaming permission from a user""" + # Check if user has the streaming permission to begin with + allowed = any(Roles.video == role.id for role in user.roles) + if allowed: + # Cancel scheduled task to take away streaming permission to avoid errors + if user.id in self.scheduler: + self.scheduler.cancel(user.id) await user.remove_roles(discord.Object(Roles.video)) await ctx.send(f"{Emojis.check_mark}Streaming permission taken from {user.display_name}") else: diff --git a/tests/bot/exts/moderation/test_stream.py b/tests/bot/exts/moderation/test_stream.py index 467c373aa..15956a9de 100644 --- a/tests/bot/exts/moderation/test_stream.py +++ b/tests/bot/exts/moderation/test_stream.py @@ -1,28 +1,10 @@ -import asyncio import unittest -from async_rediscache import RedisSession from bot.constants import Roles from bot.exts.moderation.stream import Stream from tests.helpers import MockBot, MockMember, MockRole -redis_session = None -redis_loop = asyncio.get_event_loop() - - -def setUpModule(): # noqa: N802 - """Create and connect to the fakeredis session.""" - global redis_session - redis_session = RedisSession(use_fakeredis=True) - redis_loop.run_until_complete(redis_session.connect()) - - -def tearDownModule(): # noqa: N802 - """Close the fakeredis session.""" - if redis_session: - redis_loop.run_until_complete(redis_session.close()) - class StreamCommandTest(unittest.IsolatedAsyncioTestCase): @@ -30,44 +12,6 @@ class StreamCommandTest(unittest.IsolatedAsyncioTestCase): self.bot = MockBot() self.cog = Stream(self.bot) - def test_linking_time_format_from_alias_or_key(self): - """ - User provided time format needs to be lined to a proper entry in TIME_FORMATS - This Test checks _link_from_alias method - Checking for whether alias or key exists in TIME_FORMATS is done before calling this function - """ - - test_cases = (("sec", "second"), - ("s", "second"), - ("seconds", "second"), - ("second", "second"), - ("secs", "second"), - ("min", "minute"), - ("m", "minute"), - ("minutes", "minute"), - ("hr", "hour"), - ("hrs", "hour"), - ("hours", "hour"), - ("d", "day"), - ("days", "day"), - ("yr", "year"), - ("yrs", "year"), - ("y", "year")) - - for case in test_cases: - linked = self.cog._link_from_alias(case[0])[1] - self.assertEqual(linked, case[1]) - - def test_parsing_duration_and_time_format_to_seconds(self): - """ - Test calculating time in seconds from duration and time unit - This test is technically dependent on _link_from_alias function, not the best practice but necessary - """ - test_cases = ((1, "minute", 60), (5, "second", 5), (2, "day", 172800)) - for case in test_cases: - time_in_seconds = self.cog._parse_time_to_seconds(case[0], case[1]) - self.assertEqual(time_in_seconds, case[2]) - def test_checking_if_user_has_streaming_permission(self): """ Test searching for video role in Member.roles -- cgit v1.2.3 From fae4ad4a614c56f011f64c64b3318f511ccb17eb Mon Sep 17 00:00:00 2001 From: Harbys Date: Fri, 27 Nov 2020 09:10:48 +0100 Subject: fix flake8 and line endings --- bot/exts/moderation/stream.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 0fc004d75..d8c2a8628 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -23,7 +23,7 @@ class Stream(commands.Cog): @staticmethod async def _remove_streaming_permission(schedule_user: discord.Member) -> None: - """Remove streaming permission from Member""" + """Remove streaming permission from Member.""" await schedule_user.remove_roles(discord.Object(Roles.video), reason="Temporary streaming access revoked") @commands.command(aliases=("streaming",)) @@ -37,6 +37,7 @@ class Stream(commands.Cog): ) -> None: """ Temporarily grant streaming permissions to a user for a given duration. + A unit of time should be appended to the duration. Units (∗case-sensitive): \u2003`y` - years @@ -67,7 +68,7 @@ class Stream(commands.Cog): ctx: commands.Context, user: discord.Member ) -> None: - """Take away streaming permission from a user""" + """Take away streaming permission from a user.""" # Check if user has the streaming permission to begin with allowed = any(Roles.video == role.id for role in user.roles) if allowed: -- cgit v1.2.3 From a50239e6fe46e2da36f925967db21c95f940597a Mon Sep 17 00:00:00 2001 From: Harbys Date: Sun, 10 Jan 2021 19:45:25 +0100 Subject: indent fix --- config-default.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config-default.yml b/config-default.yml index 042d80408..03d568285 100644 --- a/config-default.yml +++ b/config-default.yml @@ -255,7 +255,7 @@ guild: team_leaders: 737250302834638889 # Streaming - video: 764245844798079016 + video: 764245844798079016 moderation_roles: - *OWNERS_ROLE -- cgit v1.2.3 From 074ce91205539ca06c1c048c62b7e649c4ae78b5 Mon Sep 17 00:00:00 2001 From: Harbys Date: Sun, 10 Jan 2021 20:08:01 +0100 Subject: add 30 minute default for stream command --- bot/exts/moderation/stream.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index d8c2a8628..d8ffe32ff 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -1,3 +1,5 @@ +import datetime + import discord from discord.ext import commands @@ -32,7 +34,7 @@ class Stream(commands.Cog): self, ctx: commands.Context, user: discord.Member, - duration: Expiry, + duration: Expiry = datetime.datetime.utcnow() + datetime.timedelta(minutes=30), *_ ) -> None: """ -- cgit v1.2.3 From a0e2179da398a9164582e7debb7e139754434385 Mon Sep 17 00:00:00 2001 From: Harbys Date: Sun, 10 Jan 2021 20:31:05 +0100 Subject: move default duration for stream command to config --- bot/constants.py | 6 ++++++ bot/exts/moderation/stream.py | 5 +++-- config-default.yml | 4 ++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/bot/constants.py b/bot/constants.py index dca83e7ab..d912a5a9a 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -635,6 +635,12 @@ class Event(Enum): voice_state_update = "voice_state_update" +class VideoPermission(metaclass=YAMLGetter): + section = "video_permission" + + default_permission_duration: int + + # Debug mode DEBUG_MODE = 'local' in os.environ.get("SITE_URL", "local") diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index d8ffe32ff..b590956a3 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -4,7 +4,7 @@ import discord from discord.ext import commands from bot.bot import Bot -from bot.constants import Emojis, Roles, STAFF_ROLES +from bot.constants import Emojis, Roles, STAFF_ROLES, VideoPermission from bot.converters import Expiry from bot.utils.scheduling import Scheduler from bot.utils.time import format_infraction_with_duration @@ -34,7 +34,8 @@ class Stream(commands.Cog): self, ctx: commands.Context, user: discord.Member, - duration: Expiry = datetime.datetime.utcnow() + datetime.timedelta(minutes=30), + duration: Expiry = + datetime.datetime.utcnow() + datetime.timedelta(minutes=VideoPermission.default_permission_duration), *_ ) -> None: """ diff --git a/config-default.yml b/config-default.yml index 03d568285..ec982b0d3 100644 --- a/config-default.yml +++ b/config-default.yml @@ -533,3 +533,7 @@ voice_gate: config: required_keys: ['bot.token'] + + +video_permission: + default_permission_duration: 30 # Default duration for stream command in minutes -- cgit v1.2.3 From 10ede89b2943d2118fed6448e1eb4383c78b8998 Mon Sep 17 00:00:00 2001 From: Harbys <44087388+Harbys@users.noreply.github.com> Date: Wed, 3 Feb 2021 14:06:39 +0100 Subject: Add a newline for readability. by @MarkKoz Co-authored-by: Mark --- bot/exts/moderation/stream.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index b590956a3..c90c25976 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -50,6 +50,7 @@ class Stream(commands.Cog): \u2003`h` - hours \u2003`M` - minutes∗ \u2003`s` - seconds + Alternatively, an ISO 8601 timestamp can be provided for the duration. """ # Check if user already has streaming permission -- cgit v1.2.3 From 8c75f488848064cd2de01012614a3e1f1c304c6a Mon Sep 17 00:00:00 2001 From: Harbys <44087388+Harbys@users.noreply.github.com> Date: Wed, 3 Feb 2021 14:07:34 +0100 Subject: remove unused constants by @MarkKoz Co-authored-by: Mark --- bot/exts/moderation/stream.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index c90c25976..c2f4d12b4 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -10,8 +10,6 @@ from bot.utils.scheduling import Scheduler from bot.utils.time import format_infraction_with_duration # Constant error messages -TIME_FORMAT_NOT_VALID = f"{Emojis.cross_mark}Please specify a valid time format ex. 10h or 1day." -TIME_LESS_EQ_0 = f"{Emojis.cross_mark}Duration can not be a 0 or lower." USER_ALREADY_ALLOWED_TO_STREAM = f"{Emojis.cross_mark}This user can already stream." USER_ALREADY_NOT_ALLOWED_TO_STREAM = f"{Emojis.cross_mark}This user already can't stream." -- cgit v1.2.3 From 446a89fdd9c193198199d98ddcd4da719cea2c13 Mon Sep 17 00:00:00 2001 From: Harbys Date: Wed, 3 Feb 2021 14:12:16 +0100 Subject: remove constants that were used once --- bot/exts/moderation/stream.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index c2f4d12b4..c9563e085 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -9,10 +9,6 @@ from bot.converters import Expiry from bot.utils.scheduling import Scheduler from bot.utils.time import format_infraction_with_duration -# Constant error messages -USER_ALREADY_ALLOWED_TO_STREAM = f"{Emojis.cross_mark}This user can already stream." -USER_ALREADY_NOT_ALLOWED_TO_STREAM = f"{Emojis.cross_mark}This user already can't stream." - class Stream(commands.Cog): """Grant and revoke streaming permissions from users.""" @@ -54,7 +50,7 @@ class Stream(commands.Cog): # Check if user already has streaming permission already_allowed = any(Roles.video == role.id for role in user.roles) if already_allowed: - await ctx.send(USER_ALREADY_ALLOWED_TO_STREAM) + await ctx.send(f"{Emojis.cross_mark} This user can already stream.") return # Schedule task to remove streaming permission from Member @@ -80,7 +76,7 @@ class Stream(commands.Cog): await user.remove_roles(discord.Object(Roles.video)) await ctx.send(f"{Emojis.check_mark}Streaming permission taken from {user.display_name}") else: - await ctx.send(USER_ALREADY_NOT_ALLOWED_TO_STREAM) + await ctx.send(f"{Emojis.cross_mark} This user already can't stream.") def setup(bot: Bot) -> None: -- cgit v1.2.3 From cd25e1e47079b6e9108a977fd915052c3428c10e Mon Sep 17 00:00:00 2001 From: Harbys Date: Wed, 3 Feb 2021 14:17:49 +0100 Subject: remove unused tests --- tests/bot/exts/moderation/test_stream.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/bot/exts/moderation/test_stream.py b/tests/bot/exts/moderation/test_stream.py index 15956a9de..2ac274699 100644 --- a/tests/bot/exts/moderation/test_stream.py +++ b/tests/bot/exts/moderation/test_stream.py @@ -2,16 +2,11 @@ import unittest from bot.constants import Roles -from bot.exts.moderation.stream import Stream -from tests.helpers import MockBot, MockMember, MockRole +from tests.helpers import MockMember, MockRole class StreamCommandTest(unittest.IsolatedAsyncioTestCase): - def setUp(self) -> None: - self.bot = MockBot() - self.cog = Stream(self.bot) - def test_checking_if_user_has_streaming_permission(self): """ Test searching for video role in Member.roles -- cgit v1.2.3 From 5f76d9e309c3a65ae5ab9bea3c82db29a0553094 Mon Sep 17 00:00:00 2001 From: Harbys <44087388+Harbys@users.noreply.github.com> Date: Wed, 3 Feb 2021 14:21:54 +0100 Subject: add space for readablility Co-authored-by: Mark --- bot/exts/moderation/stream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index c2f4d12b4..7e15864bf 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -78,7 +78,7 @@ class Stream(commands.Cog): if user.id in self.scheduler: self.scheduler.cancel(user.id) await user.remove_roles(discord.Object(Roles.video)) - await ctx.send(f"{Emojis.check_mark}Streaming permission taken from {user.display_name}") + await ctx.send(f"{Emojis.check_mark} Streaming permission taken from {user.display_name}.") else: await ctx.send(USER_ALREADY_NOT_ALLOWED_TO_STREAM) -- cgit v1.2.3 From 898adc69661e06ee6d5bd0962d265bae5faed16c Mon Sep 17 00:00:00 2001 From: Harbys <44087388+Harbys@users.noreply.github.com> Date: Mon, 8 Feb 2021 19:40:07 +0100 Subject: change for style guidelines by @MarkKoz Co-authored-by: Mark --- bot/exts/moderation/stream.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 7e15864bf..6a889fe2f 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -60,8 +60,8 @@ class Stream(commands.Cog): # Schedule task to remove streaming permission from Member self.scheduler.schedule_at(duration, user.id, self._remove_streaming_permission(user)) await user.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted") - await ctx.send(f"{Emojis.check_mark}{user.mention} can now stream until " - f"{format_infraction_with_duration(str(duration))}.") + duration = format_infraction_with_duration(str(duration)) + await ctx.send(f"{Emojis.check_mark} {user.mention} can now stream until {duration}.") @commands.command(aliases=("unstream", )) @commands.has_any_role(*STAFF_ROLES) -- cgit v1.2.3 From 90bf065874be13b77b9390d4378d03a8272d113e Mon Sep 17 00:00:00 2001 From: Harbys Date: Mon, 8 Feb 2021 20:02:42 +0100 Subject: fix default duration --- bot/exts/moderation/stream.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 8b8308925..63bc2c218 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -28,8 +28,7 @@ class Stream(commands.Cog): self, ctx: commands.Context, user: discord.Member, - duration: Expiry = - datetime.datetime.utcnow() + datetime.timedelta(minutes=VideoPermission.default_permission_duration), + duration: Expiry = None, *_ ) -> None: """ @@ -47,6 +46,11 @@ class Stream(commands.Cog): Alternatively, an ISO 8601 timestamp can be provided for the duration. """ + # if duration is none then calculate default duration + if duration is None: + now = datetime.datetime.utcnow() + duration = now + datetime.timedelta(minutes=VideoPermission.default_permission_duration) + # Check if user already has streaming permission already_allowed = any(Roles.video == role.id for role in user.roles) if already_allowed: -- cgit v1.2.3 From 6004b090beede1ad28e2412cdcb41a629a4077e2 Mon Sep 17 00:00:00 2001 From: Harbys Date: Wed, 10 Feb 2021 21:01:03 +0100 Subject: Add redis rescheduling --- bot/exts/moderation/stream.py | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 63bc2c218..af0633bdb 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -1,10 +1,11 @@ import datetime import discord +from async_rediscache import RedisCache from discord.ext import commands from bot.bot import Bot -from bot.constants import Emojis, Roles, STAFF_ROLES, VideoPermission +from bot.constants import Emojis, Guild, Roles, STAFF_ROLES, VideoPermission from bot.converters import Expiry from bot.utils.scheduling import Scheduler from bot.utils.time import format_infraction_with_duration @@ -13,15 +14,36 @@ from bot.utils.time import format_infraction_with_duration class Stream(commands.Cog): """Grant and revoke streaming permissions from users.""" + # Stores tasks to remove streaming permission + # User id : timestamp relation + task_cache = RedisCache() + def __init__(self, bot: Bot): self.bot = bot self.scheduler = Scheduler(self.__class__.__name__) + self.reload_task = self.bot.loop.create_task(self._reload_tasks_from_redis()) - @staticmethod - async def _remove_streaming_permission(schedule_user: discord.Member) -> None: + async def _remove_streaming_permission(self, schedule_user: discord.Member) -> None: """Remove streaming permission from Member.""" + await self._delete_from_redis(schedule_user.id) await schedule_user.remove_roles(discord.Object(Roles.video), reason="Temporary streaming access revoked") + async def _add_to_redis_cache(self, user_id: int, timestamp: float) -> None: + """Adds 'task' to redis cache.""" + await self.task_cache.set(user_id, timestamp) + + async def _reload_tasks_from_redis(self) -> None: + await self.bot.wait_until_guild_available() + items = await self.task_cache.items() + for key, value in items: + member = await self.bot.get_guild(Guild.id).fetch_member(key) + self.scheduler.schedule_at(datetime.datetime.utcfromtimestamp(value), + key, + self._remove_streaming_permission(member)) + + async def _delete_from_redis(self, key: str) -> None: + await self.task_cache.delete(key) + @commands.command(aliases=("streaming",)) @commands.has_any_role(*STAFF_ROLES) async def stream( @@ -57,8 +79,9 @@ class Stream(commands.Cog): await ctx.send(f"{Emojis.cross_mark} This user can already stream.") return - # Schedule task to remove streaming permission from Member + # Schedule task to remove streaming permission from Member and add it to task cache self.scheduler.schedule_at(duration, user.id, self._remove_streaming_permission(user)) + await self._add_to_redis_cache(user.id, duration.timestamp()) await user.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted") duration = format_infraction_with_duration(str(duration)) await ctx.send(f"{Emojis.check_mark} {user.mention} can now stream until {duration}.") @@ -77,11 +100,15 @@ class Stream(commands.Cog): # Cancel scheduled task to take away streaming permission to avoid errors if user.id in self.scheduler: self.scheduler.cancel(user.id) - await user.remove_roles(discord.Object(Roles.video)) + await self._remove_streaming_permission(user) await ctx.send(f"{Emojis.check_mark} Streaming permission taken from {user.display_name}.") else: await ctx.send(f"{Emojis.cross_mark} This user already can't stream.") + def cog_unload(self) -> None: + """Cache and cancel all scheduled tasks.""" + self.scheduler.cancel_all() + def setup(bot: Bot) -> None: """Loads the Stream cog.""" -- cgit v1.2.3 From fb4484ee23a00f0660765675782f1bf44812ca4e Mon Sep 17 00:00:00 2001 From: Harbys Date: Wed, 10 Feb 2021 21:32:41 +0100 Subject: Add permanent streaming command --- bot/exts/moderation/stream.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index af0633bdb..46c68f74b 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -26,7 +26,7 @@ class Stream(commands.Cog): async def _remove_streaming_permission(self, schedule_user: discord.Member) -> None: """Remove streaming permission from Member.""" await self._delete_from_redis(schedule_user.id) - await schedule_user.remove_roles(discord.Object(Roles.video), reason="Temporary streaming access revoked") + await schedule_user.remove_roles(discord.Object(Roles.video), reason="Streaming access revoked") async def _add_to_redis_cache(self, user_id: int, timestamp: float) -> None: """Adds 'task' to redis cache.""" @@ -86,6 +86,29 @@ class Stream(commands.Cog): duration = format_infraction_with_duration(str(duration)) await ctx.send(f"{Emojis.check_mark} {user.mention} can now stream until {duration}.") + @commands.command(aliases=("pstream",)) + @commands.has_any_role(*STAFF_ROLES) + async def permanentstream( + self, + ctx: commands.Context, + user: discord.Member, + *_ + ) -> None: + """Permanently give user a streaming permission.""" + # Check if user already has streaming permission + already_allowed = any(Roles.video == role.id for role in user.roles) + if already_allowed: + if user.id in self.scheduler: + self.scheduler.cancel(user.id) + await self._delete_from_redis(user.id) + await ctx.send(f"{Emojis.check_mark} Moved temporary permission to permanent") + return + await ctx.send(f"{Emojis.cross_mark} This user can already stream.") + return + + await user.add_roles(discord.Object(Roles.video), reason="Permanent streaming access granted") + await ctx.send(f"{Emojis.check_mark} {user.mention} can now stream forever") + @commands.command(aliases=("unstream", )) @commands.has_any_role(*STAFF_ROLES) async def revokestream( -- cgit v1.2.3 From 3b2a509085b0ae79d6ca428960f7b6b82d94be18 Mon Sep 17 00:00:00 2001 From: Harbys Date: Wed, 10 Feb 2021 21:50:18 +0100 Subject: Fix cancelling tasks on cog unload --- bot/exts/moderation/stream.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 46c68f74b..c61599278 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -129,8 +129,9 @@ class Stream(commands.Cog): await ctx.send(f"{Emojis.cross_mark} This user already can't stream.") def cog_unload(self) -> None: - """Cache and cancel all scheduled tasks.""" - self.scheduler.cancel_all() + """Cancel all scheduled tasks.""" + self.reload_task.cancel() + self.reload_task.add_done_callback(lambda _: self.scheduler.cancel_all()) def setup(bot: Bot) -> None: -- cgit v1.2.3 From 2711a8456c3a1b30b0f14d184fcfeba122b07490 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 31 Mar 2021 23:20:42 +0100 Subject: Simplify name of function param in stream cog --- bot/exts/moderation/stream.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index c61599278..a9d0199f4 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -23,10 +23,10 @@ class Stream(commands.Cog): self.scheduler = Scheduler(self.__class__.__name__) self.reload_task = self.bot.loop.create_task(self._reload_tasks_from_redis()) - async def _remove_streaming_permission(self, schedule_user: discord.Member) -> None: + async def _remove_streaming_permission(self, member: discord.Member) -> None: """Remove streaming permission from Member.""" - await self._delete_from_redis(schedule_user.id) - await schedule_user.remove_roles(discord.Object(Roles.video), reason="Streaming access revoked") + await self._delete_from_redis(member.id) + await member.remove_roles(discord.Object(Roles.video), reason="Streaming access revoked") async def _add_to_redis_cache(self, user_id: int, timestamp: float) -> None: """Adds 'task' to redis cache.""" -- cgit v1.2.3 From bb4f4fb3fec316efa8c3775f23115e1a153347eb Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 31 Mar 2021 23:22:11 +0100 Subject: Remove unnessisary functions in stream cog --- bot/exts/moderation/stream.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index a9d0199f4..16e62b5dc 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -28,10 +28,6 @@ class Stream(commands.Cog): await self._delete_from_redis(member.id) await member.remove_roles(discord.Object(Roles.video), reason="Streaming access revoked") - async def _add_to_redis_cache(self, user_id: int, timestamp: float) -> None: - """Adds 'task' to redis cache.""" - await self.task_cache.set(user_id, timestamp) - async def _reload_tasks_from_redis(self) -> None: await self.bot.wait_until_guild_available() items = await self.task_cache.items() @@ -81,7 +77,7 @@ class Stream(commands.Cog): # Schedule task to remove streaming permission from Member and add it to task cache self.scheduler.schedule_at(duration, user.id, self._remove_streaming_permission(user)) - await self._add_to_redis_cache(user.id, duration.timestamp()) + await self.task_cache.set(user.id, duration.timestamp()) await user.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted") duration = format_infraction_with_duration(str(duration)) await ctx.send(f"{Emojis.check_mark} {user.mention} can now stream until {duration}.") @@ -100,7 +96,7 @@ class Stream(commands.Cog): if already_allowed: if user.id in self.scheduler: self.scheduler.cancel(user.id) - await self._delete_from_redis(user.id) + await self.task_cache.delete(user.id) await ctx.send(f"{Emojis.check_mark} Moved temporary permission to permanent") return await ctx.send(f"{Emojis.cross_mark} This user can already stream.") -- cgit v1.2.3 From 92306df643cd51c837a60d346a59e3d52f7d60b3 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 31 Mar 2021 23:24:31 +0100 Subject: Refactor code to match prevailing style, and reword some output in streaming cog --- bot/exts/moderation/stream.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 16e62b5dc..25e0f2c1b 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -33,9 +33,11 @@ class Stream(commands.Cog): items = await self.task_cache.items() for key, value in items: member = await self.bot.get_guild(Guild.id).fetch_member(key) - self.scheduler.schedule_at(datetime.datetime.utcfromtimestamp(value), - key, - self._remove_streaming_permission(member)) + self.scheduler.schedule_at( + datetime.datetime.utcfromtimestamp(value), + key, + self._remove_streaming_permission(member) + ) async def _delete_from_redis(self, key: str) -> None: await self.task_cache.delete(key) @@ -90,20 +92,20 @@ class Stream(commands.Cog): user: discord.Member, *_ ) -> None: - """Permanently give user a streaming permission.""" + """Permanently grant a user the permission to stream.""" # Check if user already has streaming permission already_allowed = any(Roles.video == role.id for role in user.roles) if already_allowed: if user.id in self.scheduler: self.scheduler.cancel(user.id) await self.task_cache.delete(user.id) - await ctx.send(f"{Emojis.check_mark} Moved temporary permission to permanent") + await ctx.send(f"{Emojis.check_mark} Changed temporary permission to permanent.") return await ctx.send(f"{Emojis.cross_mark} This user can already stream.") return await user.add_roles(discord.Object(Roles.video), reason="Permanent streaming access granted") - await ctx.send(f"{Emojis.check_mark} {user.mention} can now stream forever") + await ctx.send(f"{Emojis.check_mark} Permanently granted {user.mention} the permission to stream.") @commands.command(aliases=("unstream", )) @commands.has_any_role(*STAFF_ROLES) @@ -112,7 +114,7 @@ class Stream(commands.Cog): ctx: commands.Context, user: discord.Member ) -> None: - """Take away streaming permission from a user.""" + """Revoke the permissiont to stream from a user.""" # Check if user has the streaming permission to begin with allowed = any(Roles.video == role.id for role in user.roles) if allowed: @@ -120,7 +122,7 @@ class Stream(commands.Cog): if user.id in self.scheduler: self.scheduler.cancel(user.id) await self._remove_streaming_permission(user) - await ctx.send(f"{Emojis.check_mark} Streaming permission taken from {user.display_name}.") + await ctx.send(f"{Emojis.check_mark} Revoked the permission to stream from {user.mention}.") else: await ctx.send(f"{Emojis.cross_mark} This user already can't stream.") -- cgit v1.2.3 From d34b95771f551a7dc1e5b3d422df39f95ff800a0 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 31 Mar 2021 23:54:41 +0100 Subject: Atempt to get member from cache first, and handle errors from API member call --- bot/exts/moderation/stream.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 25e0f2c1b..66ca96339 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -1,4 +1,5 @@ import datetime +import logging import discord from async_rediscache import RedisCache @@ -10,6 +11,8 @@ from bot.converters import Expiry from bot.utils.scheduling import Scheduler from bot.utils.time import format_infraction_with_duration +log = logging.getLogger(__name__) + class Stream(commands.Cog): """Grant and revoke streaming permissions from users.""" @@ -32,7 +35,22 @@ class Stream(commands.Cog): await self.bot.wait_until_guild_available() items = await self.task_cache.items() for key, value in items: - member = await self.bot.get_guild(Guild.id).fetch_member(key) + member = self.bot.get_guild(Guild.id).get_member(key) + + if not member: + try: + member = await self.bot.get_guild(Guild.id).fetch_member(key) + except discord.errors.NotFound: + log.debug( + f"Member {key} left the guild before we could scheudle " + "the revoking of their streaming permissions." + ) + await self.task_cache.delete(key) + continue + except discord.HTTPException as e: + log.exception(f"Exception while trying to retrieve member {key} from discord\n{e}") + continue + self.scheduler.schedule_at( datetime.datetime.utcfromtimestamp(value), key, -- cgit v1.2.3 From 4dc697bfdd2ff064bee7e2a48e61c7136ed30c5c Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 31 Mar 2021 23:56:34 +0100 Subject: Remove empty test for stream cog --- tests/bot/exts/moderation/test_stream.py | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 tests/bot/exts/moderation/test_stream.py diff --git a/tests/bot/exts/moderation/test_stream.py b/tests/bot/exts/moderation/test_stream.py deleted file mode 100644 index 2ac274699..000000000 --- a/tests/bot/exts/moderation/test_stream.py +++ /dev/null @@ -1,20 +0,0 @@ -import unittest - - -from bot.constants import Roles -from tests.helpers import MockMember, MockRole - - -class StreamCommandTest(unittest.IsolatedAsyncioTestCase): - - def test_checking_if_user_has_streaming_permission(self): - """ - Test searching for video role in Member.roles - """ - user1 = MockMember(roles=[MockRole(id=Roles.video)]) - user2 = MockMember() - already_allowed_user1 = any(Roles.video == role.id for role in user1.roles) - self.assertEqual(already_allowed_user1, True) - - already_allowed_user2 = any(Roles.video == role.id for role in user2.roles) - self.assertEqual(already_allowed_user2, False) -- cgit v1.2.3 From 777e269290d84fae3d7a44f6b98b91ce8a478004 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 1 Apr 2021 00:02:57 +0100 Subject: function sig formatting, function ordering and remove unnessisary function --- bot/exts/moderation/stream.py | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 66ca96339..c598ec879 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -26,9 +26,14 @@ class Stream(commands.Cog): self.scheduler = Scheduler(self.__class__.__name__) self.reload_task = self.bot.loop.create_task(self._reload_tasks_from_redis()) + def cog_unload(self) -> None: + """Cancel all scheduled tasks.""" + self.reload_task.cancel() + self.reload_task.add_done_callback(lambda _: self.scheduler.cancel_all()) + async def _remove_streaming_permission(self, member: discord.Member) -> None: """Remove streaming permission from Member.""" - await self._delete_from_redis(member.id) + await self.task_cache.delete(member.id) await member.remove_roles(discord.Object(Roles.video), reason="Streaming access revoked") async def _reload_tasks_from_redis(self) -> None: @@ -57,18 +62,9 @@ class Stream(commands.Cog): self._remove_streaming_permission(member) ) - async def _delete_from_redis(self, key: str) -> None: - await self.task_cache.delete(key) - @commands.command(aliases=("streaming",)) @commands.has_any_role(*STAFF_ROLES) - async def stream( - self, - ctx: commands.Context, - user: discord.Member, - duration: Expiry = None, - *_ - ) -> None: + async def stream(self, ctx: commands.Context, user: discord.Member, duration: Expiry = None) -> None: """ Temporarily grant streaming permissions to a user for a given duration. @@ -104,12 +100,7 @@ class Stream(commands.Cog): @commands.command(aliases=("pstream",)) @commands.has_any_role(*STAFF_ROLES) - async def permanentstream( - self, - ctx: commands.Context, - user: discord.Member, - *_ - ) -> None: + async def permanentstream(self, ctx: commands.Context, user: discord.Member) -> None: """Permanently grant a user the permission to stream.""" # Check if user already has streaming permission already_allowed = any(Roles.video == role.id for role in user.roles) @@ -125,13 +116,9 @@ class Stream(commands.Cog): await user.add_roles(discord.Object(Roles.video), reason="Permanent streaming access granted") await ctx.send(f"{Emojis.check_mark} Permanently granted {user.mention} the permission to stream.") - @commands.command(aliases=("unstream", )) + @commands.command(aliases=("unstream", "rstream")) @commands.has_any_role(*STAFF_ROLES) - async def revokestream( - self, - ctx: commands.Context, - user: discord.Member - ) -> None: + async def revokestream(self, ctx: commands.Context, user: discord.Member) -> None: """Revoke the permissiont to stream from a user.""" # Check if user has the streaming permission to begin with allowed = any(Roles.video == role.id for role in user.roles) @@ -144,11 +131,6 @@ class Stream(commands.Cog): else: await ctx.send(f"{Emojis.cross_mark} This user already can't stream.") - def cog_unload(self) -> None: - """Cancel all scheduled tasks.""" - self.reload_task.cancel() - self.reload_task.add_done_callback(lambda _: self.scheduler.cancel_all()) - def setup(bot: Bot) -> None: """Loads the Stream cog.""" -- cgit v1.2.3 From e840ff6b55a4d0b4aeed2c9011915e9c44d3275f Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 1 Apr 2021 00:05:20 +0100 Subject: Stream cog docstring updates --- bot/exts/moderation/stream.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index c598ec879..55763d6fd 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -32,11 +32,12 @@ class Stream(commands.Cog): self.reload_task.add_done_callback(lambda _: self.scheduler.cancel_all()) async def _remove_streaming_permission(self, member: discord.Member) -> None: - """Remove streaming permission from Member.""" + """Remove the streaming permission from the given Member.""" await self.task_cache.delete(member.id) await member.remove_roles(discord.Object(Roles.video), reason="Streaming access revoked") async def _reload_tasks_from_redis(self) -> None: + """Reload outstanding tasks from redis on startup, delete the task if the member has since left the server.""" await self.bot.wait_until_guild_available() items = await self.task_cache.items() for key, value in items: @@ -101,7 +102,7 @@ class Stream(commands.Cog): @commands.command(aliases=("pstream",)) @commands.has_any_role(*STAFF_ROLES) async def permanentstream(self, ctx: commands.Context, user: discord.Member) -> None: - """Permanently grant a user the permission to stream.""" + """Permanently grants the given user the permission to stream.""" # Check if user already has streaming permission already_allowed = any(Roles.video == role.id for role in user.roles) if already_allowed: @@ -119,7 +120,7 @@ class Stream(commands.Cog): @commands.command(aliases=("unstream", "rstream")) @commands.has_any_role(*STAFF_ROLES) async def revokestream(self, ctx: commands.Context, user: discord.Member) -> None: - """Revoke the permissiont to stream from a user.""" + """Revoke the permission to stream from the given user.""" # Check if user has the streaming permission to begin with allowed = any(Roles.video == role.id for role in user.roles) if allowed: -- cgit v1.2.3 From da9ddfa56d8f89136d8e8ca1e61cc252e9ab0f21 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 1 Apr 2021 00:17:58 +0100 Subject: Sprinkle some logging into the Stream cog --- bot/exts/moderation/stream.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 55763d6fd..87d3a345c 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -56,9 +56,10 @@ class Stream(commands.Cog): except discord.HTTPException as e: log.exception(f"Exception while trying to retrieve member {key} from discord\n{e}") continue - + revoke_time = datetime.datetime.utcfromtimestamp(value) + log.debug(f"Scheduling {member} ({member.id}) to have streaming permission revoked at {revoke_time}") self.scheduler.schedule_at( - datetime.datetime.utcfromtimestamp(value), + revoke_time, key, self._remove_streaming_permission(member) ) @@ -81,6 +82,7 @@ class Stream(commands.Cog): Alternatively, an ISO 8601 timestamp can be provided for the duration. """ + log.trace(f"Attempting to give temporary streaming permission to {user} ({user.id}).") # if duration is none then calculate default duration if duration is None: now = datetime.datetime.utcnow() @@ -90,19 +92,22 @@ class Stream(commands.Cog): already_allowed = any(Roles.video == role.id for role in user.roles) if already_allowed: await ctx.send(f"{Emojis.cross_mark} This user can already stream.") + log.debug(f"{user} ({user.id}) already has permission to stream.") return # Schedule task to remove streaming permission from Member and add it to task cache self.scheduler.schedule_at(duration, user.id, self._remove_streaming_permission(user)) await self.task_cache.set(user.id, duration.timestamp()) await user.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted") - duration = format_infraction_with_duration(str(duration)) - await ctx.send(f"{Emojis.check_mark} {user.mention} can now stream until {duration}.") + revoke_time = format_infraction_with_duration(str(duration)) + await ctx.send(f"{Emojis.check_mark} {user.mention} can now stream until {revoke_time}.") + log.debug(f"Successfully given {user} ({user.id}) permission to stream until {revoke_time}.") @commands.command(aliases=("pstream",)) @commands.has_any_role(*STAFF_ROLES) async def permanentstream(self, ctx: commands.Context, user: discord.Member) -> None: """Permanently grants the given user the permission to stream.""" + log.trace(f"Attempting to give permenant streaming permission to {user} ({user.id}).") # Check if user already has streaming permission already_allowed = any(Roles.video == role.id for role in user.roles) if already_allowed: @@ -110,17 +115,21 @@ class Stream(commands.Cog): self.scheduler.cancel(user.id) await self.task_cache.delete(user.id) await ctx.send(f"{Emojis.check_mark} Changed temporary permission to permanent.") + log.debug(f"Successfully upgraded temporary streaming permission for {user} ({user.id}) to permanent.") return await ctx.send(f"{Emojis.cross_mark} This user can already stream.") + log.debug(f"{user} ({user.id}) already had permanent streaming permission.") return await user.add_roles(discord.Object(Roles.video), reason="Permanent streaming access granted") await ctx.send(f"{Emojis.check_mark} Permanently granted {user.mention} the permission to stream.") + log.debug(f"Successfully given {user} ({user.id}) permanent streaming permission.") @commands.command(aliases=("unstream", "rstream")) @commands.has_any_role(*STAFF_ROLES) async def revokestream(self, ctx: commands.Context, user: discord.Member) -> None: """Revoke the permission to stream from the given user.""" + log.trace(f"Attempting to remove streaming permission from {user} ({user.id}).") # Check if user has the streaming permission to begin with allowed = any(Roles.video == role.id for role in user.roles) if allowed: @@ -129,8 +138,10 @@ class Stream(commands.Cog): self.scheduler.cancel(user.id) await self._remove_streaming_permission(user) await ctx.send(f"{Emojis.check_mark} Revoked the permission to stream from {user.mention}.") + log.debug(f"Successfully revoked streaming permission from {user} ({user.id}).") else: await ctx.send(f"{Emojis.cross_mark} This user already can't stream.") + log.debug(f"{user} ({user.id}) didn't have the streaming permission to remove!") def setup(bot: Bot) -> None: -- cgit v1.2.3 From 15523ae20ded473c56ca4cad18965b45833e5604 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 1 Apr 2021 16:46:58 +0100 Subject: Describe redis cache var better in stream cog --- bot/exts/moderation/stream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 87d3a345c..f2e34e910 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -18,7 +18,7 @@ class Stream(commands.Cog): """Grant and revoke streaming permissions from users.""" # Stores tasks to remove streaming permission - # User id : timestamp relation + # RedisCache[discord.Member.id, UtcPosixTimestamp] task_cache = RedisCache() def __init__(self, bot: Bot): -- cgit v1.2.3 From 4299b473f1b086db3443daf2ce1460d7f4429c9b Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 1 Apr 2021 16:47:35 +0100 Subject: Rename function in stream cog for consistancy --- bot/exts/moderation/stream.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index f2e34e910..587dc6365 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -31,7 +31,7 @@ class Stream(commands.Cog): self.reload_task.cancel() self.reload_task.add_done_callback(lambda _: self.scheduler.cancel_all()) - async def _remove_streaming_permission(self, member: discord.Member) -> None: + async def _revoke_streaming_permission(self, member: discord.Member) -> None: """Remove the streaming permission from the given Member.""" await self.task_cache.delete(member.id) await member.remove_roles(discord.Object(Roles.video), reason="Streaming access revoked") @@ -61,7 +61,7 @@ class Stream(commands.Cog): self.scheduler.schedule_at( revoke_time, key, - self._remove_streaming_permission(member) + self._revoke_streaming_permission(member) ) @commands.command(aliases=("streaming",)) @@ -96,7 +96,7 @@ class Stream(commands.Cog): return # Schedule task to remove streaming permission from Member and add it to task cache - self.scheduler.schedule_at(duration, user.id, self._remove_streaming_permission(user)) + self.scheduler.schedule_at(duration, user.id, self._revoke_streaming_permission(user)) await self.task_cache.set(user.id, duration.timestamp()) await user.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted") revoke_time = format_infraction_with_duration(str(duration)) @@ -136,7 +136,7 @@ class Stream(commands.Cog): # Cancel scheduled task to take away streaming permission to avoid errors if user.id in self.scheduler: self.scheduler.cancel(user.id) - await self._remove_streaming_permission(user) + await self._revoke_streaming_permission(user) await ctx.send(f"{Emojis.check_mark} Revoked the permission to stream from {user.mention}.") log.debug(f"Successfully revoked streaming permission from {user} ({user.id}).") else: -- cgit v1.2.3 From c38886d1bb8d0394166699d6356a5361646dd15f Mon Sep 17 00:00:00 2001 From: ChrisJL Date: Thu, 1 Apr 2021 16:48:15 +0100 Subject: Fix spelling errors in logging statements - Stream cog Co-authored-by: Shivansh-007 --- bot/exts/moderation/stream.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 87d3a345c..f260b9421 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -48,7 +48,7 @@ class Stream(commands.Cog): member = await self.bot.get_guild(Guild.id).fetch_member(key) except discord.errors.NotFound: log.debug( - f"Member {key} left the guild before we could scheudle " + f"Member {key} left the guild before we could schedule " "the revoking of their streaming permissions." ) await self.task_cache.delete(key) @@ -107,7 +107,7 @@ class Stream(commands.Cog): @commands.has_any_role(*STAFF_ROLES) async def permanentstream(self, ctx: commands.Context, user: discord.Member) -> None: """Permanently grants the given user the permission to stream.""" - log.trace(f"Attempting to give permenant streaming permission to {user} ({user.id}).") + log.trace(f"Attempting to give permanent streaming permission to {user} ({user.id}).") # Check if user already has streaming permission already_allowed = any(Roles.video == role.id for role in user.roles) if already_allowed: -- cgit v1.2.3 From 866337ba4f2355e731a0c52df8d1e62275bafff0 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 1 Apr 2021 16:50:38 +0100 Subject: Change references to user's in Stream cog to members --- bot/exts/moderation/stream.py | 82 ++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 6df9b46d2..61dadc358 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -15,7 +15,7 @@ log = logging.getLogger(__name__) class Stream(commands.Cog): - """Grant and revoke streaming permissions from users.""" + """Grant and revoke streaming permissions from members.""" # Stores tasks to remove streaming permission # RedisCache[discord.Member.id, UtcPosixTimestamp] @@ -66,9 +66,9 @@ class Stream(commands.Cog): @commands.command(aliases=("streaming",)) @commands.has_any_role(*STAFF_ROLES) - async def stream(self, ctx: commands.Context, user: discord.Member, duration: Expiry = None) -> None: + async def stream(self, ctx: commands.Context, member: discord.Member, duration: Expiry = None) -> None: """ - Temporarily grant streaming permissions to a user for a given duration. + Temporarily grant streaming permissions to a member for a given duration. A unit of time should be appended to the duration. Units (∗case-sensitive): @@ -82,66 +82,68 @@ class Stream(commands.Cog): Alternatively, an ISO 8601 timestamp can be provided for the duration. """ - log.trace(f"Attempting to give temporary streaming permission to {user} ({user.id}).") - # if duration is none then calculate default duration + log.trace(f"Attempting to give temporary streaming permission to {member} ({member.id}).") + # If duration is none then calculate default duration if duration is None: now = datetime.datetime.utcnow() duration = now + datetime.timedelta(minutes=VideoPermission.default_permission_duration) - # Check if user already has streaming permission - already_allowed = any(Roles.video == role.id for role in user.roles) + # Check if the member already has streaming permission + already_allowed = any(Roles.video == role.id for role in member.roles) if already_allowed: - await ctx.send(f"{Emojis.cross_mark} This user can already stream.") - log.debug(f"{user} ({user.id}) already has permission to stream.") + await ctx.send(f"{Emojis.cross_mark} This member can already stream.") + log.debug(f"{member} ({member.id}) already has permission to stream.") return # Schedule task to remove streaming permission from Member and add it to task cache - self.scheduler.schedule_at(duration, user.id, self._revoke_streaming_permission(user)) - await self.task_cache.set(user.id, duration.timestamp()) - await user.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted") + self.scheduler.schedule_at(duration, member.id, self._revoke_streaming_permission(member)) + await self.task_cache.set(member.id, duration.timestamp()) + await member.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted") revoke_time = format_infraction_with_duration(str(duration)) - await ctx.send(f"{Emojis.check_mark} {user.mention} can now stream until {revoke_time}.") - log.debug(f"Successfully given {user} ({user.id}) permission to stream until {revoke_time}.") + await ctx.send(f"{Emojis.check_mark} {member.mention} can now stream until {revoke_time}.") + log.debug(f"Successfully given {member} ({member.id}) permission to stream until {revoke_time}.") @commands.command(aliases=("pstream",)) @commands.has_any_role(*STAFF_ROLES) - async def permanentstream(self, ctx: commands.Context, user: discord.Member) -> None: - """Permanently grants the given user the permission to stream.""" - log.trace(f"Attempting to give permanent streaming permission to {user} ({user.id}).") - # Check if user already has streaming permission - already_allowed = any(Roles.video == role.id for role in user.roles) + async def permanentstream(self, ctx: commands.Context, member: discord.Member) -> None: + """Permanently grants the given member the permission to stream.""" + log.trace(f"Attempting to give permanent streaming permission to {member} ({member.id}).") + # Check if the member already has streaming permission + already_allowed = any(Roles.video == role.id for role in member.roles) if already_allowed: - if user.id in self.scheduler: - self.scheduler.cancel(user.id) - await self.task_cache.delete(user.id) + if member.id in self.scheduler: + self.scheduler.cancel(member.id) + await self.task_cache.delete(member.id) await ctx.send(f"{Emojis.check_mark} Changed temporary permission to permanent.") - log.debug(f"Successfully upgraded temporary streaming permission for {user} ({user.id}) to permanent.") + log.debug( + f"Successfully upgraded temporary streaming permission for {member} ({member.id}) to permanent." + ) return - await ctx.send(f"{Emojis.cross_mark} This user can already stream.") - log.debug(f"{user} ({user.id}) already had permanent streaming permission.") + await ctx.send(f"{Emojis.cross_mark} This member can already stream.") + log.debug(f"{member} ({member.id}) already had permanent streaming permission.") return - await user.add_roles(discord.Object(Roles.video), reason="Permanent streaming access granted") - await ctx.send(f"{Emojis.check_mark} Permanently granted {user.mention} the permission to stream.") - log.debug(f"Successfully given {user} ({user.id}) permanent streaming permission.") + await member.add_roles(discord.Object(Roles.video), reason="Permanent streaming access granted") + await ctx.send(f"{Emojis.check_mark} Permanently granted {member.mention} the permission to stream.") + log.debug(f"Successfully given {member} ({member.id}) permanent streaming permission.") @commands.command(aliases=("unstream", "rstream")) @commands.has_any_role(*STAFF_ROLES) - async def revokestream(self, ctx: commands.Context, user: discord.Member) -> None: - """Revoke the permission to stream from the given user.""" - log.trace(f"Attempting to remove streaming permission from {user} ({user.id}).") - # Check if user has the streaming permission to begin with - allowed = any(Roles.video == role.id for role in user.roles) + async def revokestream(self, ctx: commands.Context, member: discord.Member) -> None: + """Revoke the permission to stream from the given member.""" + log.trace(f"Attempting to remove streaming permission from {member} ({member.id}).") + # Check if the memeber has the streaming permission to begin with + allowed = any(Roles.video == role.id for role in member.roles) if allowed: # Cancel scheduled task to take away streaming permission to avoid errors - if user.id in self.scheduler: - self.scheduler.cancel(user.id) - await self._revoke_streaming_permission(user) - await ctx.send(f"{Emojis.check_mark} Revoked the permission to stream from {user.mention}.") - log.debug(f"Successfully revoked streaming permission from {user} ({user.id}).") + if member.id in self.scheduler: + self.scheduler.cancel(member.id) + await self._revoke_streaming_permission(member) + await ctx.send(f"{Emojis.check_mark} Revoked the permission to stream from {member.mention}.") + log.debug(f"Successfully revoked streaming permission from {member} ({member.id}).") else: - await ctx.send(f"{Emojis.cross_mark} This user already can't stream.") - log.debug(f"{user} ({user.id}) didn't have the streaming permission to remove!") + await ctx.send(f"{Emojis.cross_mark} This member doesn't have video permissions to remove!") + log.debug(f"{member} ({member.id}) didn't have the streaming permission to remove!") def setup(bot: Bot) -> None: -- cgit v1.2.3 From 9f8ef6cae6eb2137fb0e2a8efdb29c22759f9783 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 1 Apr 2021 16:51:44 +0100 Subject: Remove unnecessary wrapper variable --- bot/exts/moderation/stream.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 61dadc358..008ee8afe 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -85,8 +85,9 @@ class Stream(commands.Cog): log.trace(f"Attempting to give temporary streaming permission to {member} ({member.id}).") # If duration is none then calculate default duration if duration is None: - now = datetime.datetime.utcnow() - duration = now + datetime.timedelta(minutes=VideoPermission.default_permission_duration) + duration = datetime.datetime.utcnow() + datetime.timedelta( + minutes=VideoPermission.default_permission_duration + ) # Check if the member already has streaming permission already_allowed = any(Roles.video == role.id for role in member.roles) -- cgit v1.2.3 From de76dbcb40674573913a6a9b077f5dbffaaff9f0 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 1 Apr 2021 17:05:04 +0100 Subject: Convert to arrow for datetime management --- bot/exts/moderation/stream.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 008ee8afe..4c86219f5 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -1,7 +1,9 @@ -import datetime import logging +from datetime import timedelta +import arrow import discord +from arrow import Arrow from async_rediscache import RedisCache from discord.ext import commands @@ -56,7 +58,7 @@ class Stream(commands.Cog): except discord.HTTPException as e: log.exception(f"Exception while trying to retrieve member {key} from discord\n{e}") continue - revoke_time = datetime.datetime.utcfromtimestamp(value) + revoke_time = Arrow.utcfromtimestamp(value) log.debug(f"Scheduling {member} ({member.id}) to have streaming permission revoked at {revoke_time}") self.scheduler.schedule_at( revoke_time, @@ -85,7 +87,7 @@ class Stream(commands.Cog): log.trace(f"Attempting to give temporary streaming permission to {member} ({member.id}).") # If duration is none then calculate default duration if duration is None: - duration = datetime.datetime.utcnow() + datetime.timedelta( + duration = arrow.utcnow().naive + timedelta( minutes=VideoPermission.default_permission_duration ) @@ -98,7 +100,7 @@ class Stream(commands.Cog): # Schedule task to remove streaming permission from Member and add it to task cache self.scheduler.schedule_at(duration, member.id, self._revoke_streaming_permission(member)) - await self.task_cache.set(member.id, duration.timestamp()) + await self.task_cache.set(member.id, Arrow.fromdatetime(duration).timestamp()) await member.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted") revoke_time = format_infraction_with_duration(str(duration)) await ctx.send(f"{Emojis.check_mark} {member.mention} can now stream until {revoke_time}.") -- cgit v1.2.3 From 3cc04418cee734e3a58dc8d8d453e227085117aa Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 1 Apr 2021 18:50:49 +0100 Subject: Only convert to naive when sending to scheduler, general refactor&comments --- bot/exts/moderation/stream.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 4c86219f5..304b92293 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -87,7 +87,7 @@ class Stream(commands.Cog): log.trace(f"Attempting to give temporary streaming permission to {member} ({member.id}).") # If duration is none then calculate default duration if duration is None: - duration = arrow.utcnow().naive + timedelta( + duration = arrow.utcnow() + timedelta( minutes=VideoPermission.default_permission_duration ) @@ -99,9 +99,12 @@ class Stream(commands.Cog): return # Schedule task to remove streaming permission from Member and add it to task cache - self.scheduler.schedule_at(duration, member.id, self._revoke_streaming_permission(member)) + self.scheduler.schedule_at(duration.naive, member.id, self._revoke_streaming_permission(member)) await self.task_cache.set(member.id, Arrow.fromdatetime(duration).timestamp()) + await member.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted") + + # Convert here for nicer logging and output revoke_time = format_infraction_with_duration(str(duration)) await ctx.send(f"{Emojis.check_mark} {member.mention} can now stream until {revoke_time}.") log.debug(f"Successfully given {member} ({member.id}) permission to stream until {revoke_time}.") @@ -111,17 +114,20 @@ class Stream(commands.Cog): async def permanentstream(self, ctx: commands.Context, member: discord.Member) -> None: """Permanently grants the given member the permission to stream.""" log.trace(f"Attempting to give permanent streaming permission to {member} ({member.id}).") + # Check if the member already has streaming permission - already_allowed = any(Roles.video == role.id for role in member.roles) - if already_allowed: + if any(Roles.video == role.id for role in member.roles): if member.id in self.scheduler: + # Member has temp permission, so cancel the task to revoke later and delete from cache self.scheduler.cancel(member.id) await self.task_cache.delete(member.id) + await ctx.send(f"{Emojis.check_mark} Changed temporary permission to permanent.") log.debug( f"Successfully upgraded temporary streaming permission for {member} ({member.id}) to permanent." ) return + await ctx.send(f"{Emojis.cross_mark} This member can already stream.") log.debug(f"{member} ({member.id}) already had permanent streaming permission.") return @@ -135,18 +141,21 @@ class Stream(commands.Cog): async def revokestream(self, ctx: commands.Context, member: discord.Member) -> None: """Revoke the permission to stream from the given member.""" log.trace(f"Attempting to remove streaming permission from {member} ({member.id}).") - # Check if the memeber has the streaming permission to begin with - allowed = any(Roles.video == role.id for role in member.roles) - if allowed: - # Cancel scheduled task to take away streaming permission to avoid errors + + # Check if the member already has streaming permission + if any(Roles.video == role.id for role in member.roles): if member.id in self.scheduler: + # Member has temp permission, so cancel the task to revoke later and delete from cache self.scheduler.cancel(member.id) + await self.task_cache.delete(member.id) await self._revoke_streaming_permission(member) + await ctx.send(f"{Emojis.check_mark} Revoked the permission to stream from {member.mention}.") log.debug(f"Successfully revoked streaming permission from {member} ({member.id}).") - else: - await ctx.send(f"{Emojis.cross_mark} This member doesn't have video permissions to remove!") - log.debug(f"{member} ({member.id}) didn't have the streaming permission to remove!") + return + + await ctx.send(f"{Emojis.cross_mark} This member doesn't have video permissions to remove!") + log.debug(f"{member} ({member.id}) didn't have the streaming permission to remove!") def setup(bot: Bot) -> None: -- cgit v1.2.3 From 509462b25fcc07430d33e0ddebd7be4ccd2600b5 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 1 Apr 2021 18:52:00 +0100 Subject: Remove redundant traceback log in log.exception --- bot/exts/moderation/stream.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 304b92293..4a624ba2c 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -55,8 +55,8 @@ class Stream(commands.Cog): ) await self.task_cache.delete(key) continue - except discord.HTTPException as e: - log.exception(f"Exception while trying to retrieve member {key} from discord\n{e}") + except discord.HTTPException: + log.exception(f"Exception while trying to retrieve member {key} from Discord.") continue revoke_time = Arrow.utcfromtimestamp(value) log.debug(f"Scheduling {member} ({member.id}) to have streaming permission revoked at {revoke_time}") -- cgit v1.2.3 From ac660e67eab0407b65b6d8cbe0a69181901f06bb Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 1 Apr 2021 19:16:46 +0100 Subject: Update schedule_at() to work with tz aware date times --- bot/utils/scheduling.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bot/utils/scheduling.py b/bot/utils/scheduling.py index 4dd036e4f..b3f62257a 100644 --- a/bot/utils/scheduling.py +++ b/bot/utils/scheduling.py @@ -59,14 +59,18 @@ class Scheduler: def schedule_at(self, time: datetime, task_id: t.Hashable, coroutine: t.Coroutine) -> None: """ - Schedule `coroutine` to be executed at the given naïve UTC `time`. + Schedule `coroutine` to be executed at the given `time`. + + If `time` is timezone aware, then use that timezone to calculate now() when subtracting. + If `time` is naïve, then we use UTC. If `time` is in the past, schedule `coroutine` immediately. If a task with `task_id` already exists, close `coroutine` instead of scheduling it. This prevents unawaited coroutine warnings. Don't pass a coroutine that'll be re-used elsewhere. """ - delay = (time - datetime.utcnow()).total_seconds() + now_datetime = datetime.now(time.tzinfo) if time.tzinfo else datetime.utcnow() + delay = (time - now_datetime).total_seconds() if delay > 0: coroutine = self._await_later(delay, task_id, coroutine) -- cgit v1.2.3 From e07ebebfcbbbe4e530b9bf106e2aa5d2e7ad9838 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 1 Apr 2021 19:18:51 +0100 Subject: Use tz aware timestamps and refactor for readibility - Stream cog --- bot/exts/moderation/stream.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 4a624ba2c..50ed01e78 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -87,9 +87,7 @@ class Stream(commands.Cog): log.trace(f"Attempting to give temporary streaming permission to {member} ({member.id}).") # If duration is none then calculate default duration if duration is None: - duration = arrow.utcnow() + timedelta( - minutes=VideoPermission.default_permission_duration - ) + duration = arrow.utcnow() + timedelta(minutes=VideoPermission.default_permission_duration) # Check if the member already has streaming permission already_allowed = any(Roles.video == role.id for role in member.roles) @@ -99,7 +97,7 @@ class Stream(commands.Cog): return # Schedule task to remove streaming permission from Member and add it to task cache - self.scheduler.schedule_at(duration.naive, member.id, self._revoke_streaming_permission(member)) + self.scheduler.schedule_at(duration, member.id, self._revoke_streaming_permission(member)) await self.task_cache.set(member.id, Arrow.fromdatetime(duration).timestamp()) await member.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted") @@ -134,7 +132,7 @@ class Stream(commands.Cog): await member.add_roles(discord.Object(Roles.video), reason="Permanent streaming access granted") await ctx.send(f"{Emojis.check_mark} Permanently granted {member.mention} the permission to stream.") - log.debug(f"Successfully given {member} ({member.id}) permanent streaming permission.") + log.debug(f"Successfully gave {member} ({member.id}) permanent streaming permission.") @commands.command(aliases=("unstream", "rstream")) @commands.has_any_role(*STAFF_ROLES) -- cgit v1.2.3 From 4962b10b20f90a849af34c4efea3512909616955 Mon Sep 17 00:00:00 2001 From: ChrisJL Date: Thu, 1 Apr 2021 20:44:03 +0100 Subject: Reword logging and docstrings to different mood Co-authored-by: Mark --- bot/exts/moderation/stream.py | 2 +- bot/utils/scheduling.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 50ed01e78..e5b2f2cc7 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -105,7 +105,7 @@ class Stream(commands.Cog): # Convert here for nicer logging and output revoke_time = format_infraction_with_duration(str(duration)) await ctx.send(f"{Emojis.check_mark} {member.mention} can now stream until {revoke_time}.") - log.debug(f"Successfully given {member} ({member.id}) permission to stream until {revoke_time}.") + log.debug(f"Successfully gave {member} ({member.id}) permission to stream until {revoke_time}.") @commands.command(aliases=("pstream",)) @commands.has_any_role(*STAFF_ROLES) diff --git a/bot/utils/scheduling.py b/bot/utils/scheduling.py index b3f62257a..6843bae88 100644 --- a/bot/utils/scheduling.py +++ b/bot/utils/scheduling.py @@ -62,7 +62,7 @@ class Scheduler: Schedule `coroutine` to be executed at the given `time`. If `time` is timezone aware, then use that timezone to calculate now() when subtracting. - If `time` is naïve, then we use UTC. + If `time` is naïve, then use UTC. If `time` is in the past, schedule `coroutine` immediately. -- cgit v1.2.3 From adf2801e1d0f1e2d4608d65ae37c072629ad32dc Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 1 Apr 2021 21:20:04 +0100 Subject: Ensure duration is always tz-aware --- bot/exts/moderation/stream.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 50ed01e78..a54e95fd9 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -1,5 +1,5 @@ import logging -from datetime import timedelta +from datetime import timedelta, timezone import arrow import discord @@ -85,9 +85,14 @@ class Stream(commands.Cog): Alternatively, an ISO 8601 timestamp can be provided for the duration. """ log.trace(f"Attempting to give temporary streaming permission to {member} ({member.id}).") - # If duration is none then calculate default duration + if duration is None: + # If duration is None then calculate default duration duration = arrow.utcnow() + timedelta(minutes=VideoPermission.default_permission_duration) + elif duration.tzinfo is None: + # Make duration tz-aware. + # ISODateTime could already include tzinfo, this check is so it isn't overwritten. + duration.replace(tzinfo=timezone.utc) # Check if the member already has streaming permission already_allowed = any(Roles.video == role.id for role in member.roles) -- cgit v1.2.3 From b21618b544e60e775e7365075e35acbd772795b7 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 1 Apr 2021 21:27:17 +0100 Subject: Mention user when upgrading streaming permissions to permanent --- bot/exts/moderation/stream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index a54e95fd9..eab47465f 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -125,7 +125,7 @@ class Stream(commands.Cog): self.scheduler.cancel(member.id) await self.task_cache.delete(member.id) - await ctx.send(f"{Emojis.check_mark} Changed temporary permission to permanent.") + await ctx.send(f"{Emojis.check_mark} Permanently granted {member.mention} the permission to stream.") log.debug( f"Successfully upgraded temporary streaming permission for {member} ({member.id}) to permanent." ) -- cgit v1.2.3 From 8f97c42f1248a0b678763d38cf2608fff6c87de2 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 3 Apr 2021 21:46:07 +0100 Subject: Remove redundant conversion to Arrow datetime in Stream cog --- bot/exts/moderation/stream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 2d1f12469..dab565e57 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -103,7 +103,7 @@ class Stream(commands.Cog): # Schedule task to remove streaming permission from Member and add it to task cache self.scheduler.schedule_at(duration, member.id, self._revoke_streaming_permission(member)) - await self.task_cache.set(member.id, Arrow.fromdatetime(duration).timestamp()) + await self.task_cache.set(member.id, duration.timestamp()) await member.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted") -- cgit v1.2.3 From 44b74d3fb43ce50bda5e99ddd57146aecf4a5f0b Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 5 Apr 2021 17:21:35 +0100 Subject: Output stream command confimation in embed for automatic tz conversion --- bot/exts/moderation/stream.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index dab565e57..04c15e542 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -8,7 +8,7 @@ from async_rediscache import RedisCache from discord.ext import commands from bot.bot import Bot -from bot.constants import Emojis, Guild, Roles, STAFF_ROLES, VideoPermission +from bot.constants import Colours, Emojis, Guild, Roles, STAFF_ROLES, VideoPermission from bot.converters import Expiry from bot.utils.scheduling import Scheduler from bot.utils.time import format_infraction_with_duration @@ -97,7 +97,7 @@ class Stream(commands.Cog): # Check if the member already has streaming permission already_allowed = any(Roles.video == role.id for role in member.roles) if already_allowed: - await ctx.send(f"{Emojis.cross_mark} This member can already stream.") + await ctx.send(f"{Emojis.cross_mark} {member.mention} can already stream.") log.debug(f"{member} ({member.id}) already has permission to stream.") return @@ -107,9 +107,19 @@ class Stream(commands.Cog): await member.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted") - # Convert here for nicer logging and output + # Use embed as embed timestamps do timezone conversions. + embed = discord.Embed( + description=f"{Emojis.check_mark} {member.mention} can now stream.", + colour=Colours.soft_green + ) + embed.set_footer(text=f"Streaming permission has been given to {member} until") + embed.timestamp = duration + + # Mention in content as mentions in embeds don't ping + await ctx.send(content=member.mention, embed=embed) + + # Convert here for nicer logging revoke_time = format_infraction_with_duration(str(duration)) - await ctx.send(f"{Emojis.check_mark} {member.mention} can now stream until {revoke_time}.") log.debug(f"Successfully gave {member} ({member.id}) permission to stream until {revoke_time}.") @commands.command(aliases=("pstream",)) -- cgit v1.2.3 From 60a73ae2cc033babbef2589bfd729b75f8d8ad12 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 5 Apr 2021 18:03:55 +0100 Subject: Convert back to datetime as Embed.timestamp doesn't support Arrow --- bot/exts/moderation/stream.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 04c15e542..1bdcdc7d8 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -87,8 +87,9 @@ class Stream(commands.Cog): log.trace(f"Attempting to give temporary streaming permission to {member} ({member.id}).") if duration is None: - # If duration is None then calculate default duration + # Use default duration and convert back to datetime as Embed.timestamp doesn't support Arrow duration = arrow.utcnow() + timedelta(minutes=VideoPermission.default_permission_duration) + duration = duration.datetime elif duration.tzinfo is None: # Make duration tz-aware. # ISODateTime could already include tzinfo, this check is so it isn't overwritten. -- cgit v1.2.3 From 8e04705d94299b1c3ed074b825ffb25a3c537d1d Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 6 Apr 2021 16:06:26 +0100 Subject: Add a comment to _reload_tasks_from_redis() in the Stream cog. --- bot/exts/moderation/stream.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 1bdcdc7d8..12e195172 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -46,6 +46,7 @@ class Stream(commands.Cog): member = self.bot.get_guild(Guild.id).get_member(key) if not member: + # Member isn't found in the cache try: member = await self.bot.get_guild(Guild.id).fetch_member(key) except discord.errors.NotFound: @@ -58,6 +59,7 @@ class Stream(commands.Cog): except discord.HTTPException: log.exception(f"Exception while trying to retrieve member {key} from Discord.") continue + revoke_time = Arrow.utcfromtimestamp(value) log.debug(f"Scheduling {member} ({member.id}) to have streaming permission revoked at {revoke_time}") self.scheduler.schedule_at( -- cgit v1.2.3 From 384ac5f9e1b83aa4ad3887d26a6745681d3214ea Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 6 Apr 2021 16:27:28 +0100 Subject: Reduce default duration of stream permission from 30m to 5m --- config-default.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config-default.yml b/config-default.yml index 4178fba32..9b07d026d 100644 --- a/config-default.yml +++ b/config-default.yml @@ -548,4 +548,4 @@ config: video_permission: - default_permission_duration: 30 # Default duration for stream command in minutes + default_permission_duration: 5 # Default duration for stream command in minutes -- cgit v1.2.3 From f66c63b4ae9a219130100b6f01c98e1b079cdf6e Mon Sep 17 00:00:00 2001 From: Ben Soyka Date: Wed, 7 Apr 2021 07:16:48 -0600 Subject: Update YouTube terms in the ytdl tag --- bot/resources/tags/ytdl.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bot/resources/tags/ytdl.md b/bot/resources/tags/ytdl.md index e34ecff44..2d87f75db 100644 --- a/bot/resources/tags/ytdl.md +++ b/bot/resources/tags/ytdl.md @@ -1,12 +1,12 @@ Per [PyDis' Rule 5](https://pythondiscord.com/pages/rules), we are unable to assist with questions related to youtube-dl, commonly used by Discord bots to stream audio, as its use violates YouTube's Terms of Service. -For reference, this usage is covered by the following clauses in [YouTube's TOS](https://www.youtube.com/static?template=terms), as of 2019-07-22: +For reference, this usage is covered by the following clauses in [YouTube's TOS](https://www.youtube.com/static?template=terms), as of 2021-03-17: ``` -The following restrictions apply to your use of the Service. You are not allowed to: +The following restrictions apply to your use of the Service. You are not allowed to: -1. access, reproduce, download, distribute, transmit, broadcast, display, sell, license, alter, modify or otherwise use any part of the Service or any Content except: (a) as specifically permitted by the Service; (b) with prior written permission from YouTube and, if applicable, the respective rights holders; or (c) as permitted by applicable law; +1. access, reproduce, download, distribute, transmit, broadcast, display, sell, license, alter, modify or otherwise use any part of the Service or any Content except: (a) as expressly authorized by the Service; or (b) with prior written permission from YouTube and, if applicable, the respective rights holders; -3. access the Service using any automated means (such as robots, botnets or scrapers) except: (a) in the case of public search engines, in accordance with YouTube’s robots.txt file; (b) with YouTube’s prior written permission; or (c) as permitted by applicable law; +3. access the Service using any automated means (such as robots, botnets or scrapers) except (a) in the case of public search engines, in accordance with YouTube’s robots.txt file; or (b) with YouTube’s prior written permission; 9. use the Service to view or listen to Content other than for personal, non-commercial use (for example, you may not publicly screen videos or stream music from the Service) ``` -- cgit v1.2.3 From e77098f5942de41728b95d4580e6189908deb6f9 Mon Sep 17 00:00:00 2001 From: Ben Soyka Date: Wed, 7 Apr 2021 14:23:46 -0600 Subject: Use the UK version of the YouTube TOS --- bot/resources/tags/ytdl.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bot/resources/tags/ytdl.md b/bot/resources/tags/ytdl.md index 2d87f75db..df28024a0 100644 --- a/bot/resources/tags/ytdl.md +++ b/bot/resources/tags/ytdl.md @@ -1,12 +1,12 @@ Per [PyDis' Rule 5](https://pythondiscord.com/pages/rules), we are unable to assist with questions related to youtube-dl, commonly used by Discord bots to stream audio, as its use violates YouTube's Terms of Service. -For reference, this usage is covered by the following clauses in [YouTube's TOS](https://www.youtube.com/static?template=terms), as of 2021-03-17: +For reference, this usage is covered by the following clauses in [YouTube's TOS](https://www.youtube.com/static?gl=GB&template=terms), as of 2021-03-17: ``` The following restrictions apply to your use of the Service. You are not allowed to: -1. access, reproduce, download, distribute, transmit, broadcast, display, sell, license, alter, modify or otherwise use any part of the Service or any Content except: (a) as expressly authorized by the Service; or (b) with prior written permission from YouTube and, if applicable, the respective rights holders; +1. access, reproduce, download, distribute, transmit, broadcast, display, sell, license, alter, modify or otherwise use any part of the Service or any Content except: (a) as specifically permitted by the Service; (b) with prior written permission from YouTube and, if applicable, the respective rights holders; or (c) as permitted by applicable law; -3. access the Service using any automated means (such as robots, botnets or scrapers) except (a) in the case of public search engines, in accordance with YouTube’s robots.txt file; or (b) with YouTube’s prior written permission; +3. access the Service using any automated means (such as robots, botnets or scrapers) except: (a) in the case of public search engines, in accordance with YouTube’s robots.txt file; (b) with YouTube’s prior written permission; or (c) as permitted by applicable law; 9. use the Service to view or listen to Content other than for personal, non-commercial use (for example, you may not publicly screen videos or stream music from the Service) ``` -- cgit v1.2.3 From f79b7c8668505de059c19820b90e00ae462e3682 Mon Sep 17 00:00:00 2001 From: onerandomusername <71233171+onerandomusername@users.noreply.github.com> Date: Thu, 8 Apr 2021 15:24:46 -0400 Subject: Close voice channels with defcon shutdown --- bot/exts/moderation/defcon.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/moderation/defcon.py b/bot/exts/moderation/defcon.py index bab95405c..dfb1afd19 100644 --- a/bot/exts/moderation/defcon.py +++ b/bot/exts/moderation/defcon.py @@ -181,7 +181,7 @@ class Defcon(Cog): role = ctx.guild.default_role permissions = role.permissions - permissions.update(send_messages=False, add_reactions=False) + permissions.update(send_messages=False, add_reactions=False, connect=False) await role.edit(reason="DEFCON shutdown", permissions=permissions) await ctx.send(f"{Action.SERVER_SHUTDOWN.value.emoji} Server shut down.") @@ -192,7 +192,7 @@ class Defcon(Cog): role = ctx.guild.default_role permissions = role.permissions - permissions.update(send_messages=True, add_reactions=True) + permissions.update(send_messages=True, add_reactions=True, connect=True) await role.edit(reason="DEFCON unshutdown", permissions=permissions) await ctx.send(f"{Action.SERVER_OPEN.value.emoji} Server reopened.") -- cgit v1.2.3