Skip to content

Commit 189f241

Browse files
authored
Merge pull request #178 from kyb3r/status
Status command
2 parents 0597e4e + 5ca8e50 commit 189f241

File tree

4 files changed

+169
-73
lines changed

4 files changed

+169
-73
lines changed

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88

99
### Added
1010

11-
The ability to enable typing interactions.
11+
- The ability to enable typing interactions.
1212

1313
If you want the bot to type in the thread channel if the user is also typing, add the config variable `user_typing`, the value doesnt matter, just it's presence. use `config del` to disable the functionality. The same thing in reverse is also possible, if you want the use to see the bot type when someone is typing in the thread channel add the `mod_typing` config variable.
1414

15+
- New `status` command, change the bot's status to `online`, `idle`, `dnd`, `invisible`, or `offline`.
16+
- To remove the status (change it back to default), use `status clear`.
17+
- This also introduces a new internal configuration variable: `status`. Possible values are `online`, `idle`, `dnd`, `invisible`, and `offline`.
18+
19+
### Changed
20+
- The internals for `activity` has drastically changed to accommodate the new `status` command.
21+
1522
# 2.13.6
1623

1724
### Fixed

bot.py

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
SOFTWARE.
2323
"""
2424

25-
__version__ = '2.13.5'
25+
__version__ = '2.13.6'
2626

2727
import asyncio
2828
import logging
@@ -34,7 +34,6 @@
3434
from types import SimpleNamespace
3535

3636
import discord
37-
from discord.enums import ActivityType
3837
from discord.ext import commands
3938
from discord.ext.commands.view import StringView
4039

@@ -401,41 +400,6 @@ async def on_ready(self):
401400
# Wait until config cache is populated with stuff from db
402401
await self.config.wait_until_ready()
403402

404-
# activities
405-
activity_type = self.config.get('activity_type', -1)
406-
message = self.config.get('activity_message', '')
407-
408-
try:
409-
activity_type = ActivityType(activity_type)
410-
except ValueError:
411-
activity_type = -1
412-
413-
if activity_type >= 0 and message:
414-
normalized_message = message.strip()
415-
if activity_type == ActivityType.listening:
416-
if message.lower().startswith('to '):
417-
# Must be listening to...
418-
normalized_message = message[3:].strip()
419-
else:
420-
normalized_message = ''
421-
422-
if normalized_message:
423-
if activity_type == ActivityType.streaming:
424-
url = self.config.get('twitch_url',
425-
'https://www.twitch.tv/discord-modmail/')
426-
else:
427-
url = None
428-
429-
activity = discord.Activity(type=activity_type,
430-
name=normalized_message,
431-
url=url)
432-
await self.change_presence(activity=activity)
433-
# TODO: Trim message
434-
logger.info(info('Activity set to: '
435-
f'{activity_type.name} {message}.'))
436-
else:
437-
logger.info(info(f'No activity message set.'))
438-
439403
# closures
440404
closures = self.config.closures.copy()
441405
logger.info(info(f'There are {len(closures)} thread(s) '

cogs/utility.py

Lines changed: 157 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import inspect
2+
import logging
23
import os
34
import traceback
45
from contextlib import redirect_stdout
@@ -10,7 +11,7 @@
1011

1112
import discord
1213
from discord import Embed, Color, Activity
13-
from discord.enums import ActivityType
14+
from discord.enums import ActivityType, Status
1415
from discord.ext import commands
1516

1617
from aiohttp import ClientResponseError
@@ -20,7 +21,9 @@
2021
from core.decorators import github_access_token_required, trigger_typing
2122
from core.models import Bot, InvalidConfigError
2223
from core.paginator import PaginatorSession, MessagePaginatorSession
23-
from core.utils import cleanup_code
24+
from core.utils import cleanup_code, info, error
25+
26+
logger = logging.getLogger('Modmail')
2427

2528

2629
class Utility:
@@ -244,7 +247,7 @@ async def debug(self, ctx):
244247

245248
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)),
246249
'../temp/logs.log'), 'r+') as f:
247-
logs = f.read().strip(' \n\r')
250+
logs = f.read().strip()
248251

249252
if not logs:
250253
embed = Embed(
@@ -299,7 +302,7 @@ async def hastebin(self, ctx):
299302
"""Upload logs to hastebin."""
300303
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)),
301304
'../temp/logs.log'), 'r+') as f:
302-
logs = f.read().strip(' \n\r')
305+
logs = f.read().strip()
303306

304307
try:
305308
async with self.bot.session.post('https://hastebin.com/documents',
@@ -431,10 +434,10 @@ async def activity(self, ctx, activity_type: str, *, message: str = ''):
431434
it must be followed by a "to": "listening to..."
432435
"""
433436
if activity_type == 'clear':
434-
await self.bot.change_presence(activity=None)
435437
self.bot.config['activity_type'] = None
436438
self.bot.config['activity_message'] = None
437439
await self.bot.config.update()
440+
await self.set_presence(log=False)
438441
embed = Embed(
439442
title='Activity Removed',
440443
color=self.bot.main_color
@@ -445,42 +448,167 @@ async def activity(self, ctx, activity_type: str, *, message: str = ''):
445448
raise commands.UserInputError
446449

447450
try:
448-
activity_type = ActivityType[activity_type.lower()]
449-
except KeyError:
451+
activity, msg = (await self.set_presence(
452+
activity_identifier=activity_type,
453+
activity_by_key=True,
454+
activity_message=message,
455+
log=False
456+
))['activity']
457+
except ValueError:
450458
raise commands.UserInputError
451459

452-
if activity_type == ActivityType.listening:
453-
if not message.lower().startswith('to '):
454-
# Must be listening to...
455-
raise commands.UserInputError
456-
normalized_message = message[3:].strip()
457-
else:
458-
# Discord does not allow leading/trailing spaces anyways
459-
normalized_message = message.strip()
460+
self.bot.config['activity_type'] = activity.type.value
461+
self.bot.config['activity_message'] = message
462+
await self.bot.config.update()
460463

461-
if activity_type == ActivityType.streaming:
462-
url = self.bot.config.get('twitch_url',
463-
'https://www.twitch.tv/discord-Modmail/')
464-
else:
465-
url = None
464+
embed = Embed(
465+
title='Activity Changed',
466+
description=msg,
467+
color=self.bot.main_color
468+
)
469+
return await ctx.send(embed=embed)
466470

467-
activity = Activity(type=activity_type,
468-
name=normalized_message,
469-
url=url)
470-
await self.bot.change_presence(activity=activity)
471+
@commands.command()
472+
@checks.has_permissions(administrator=True)
473+
async def status(self, ctx, *, status_type: str):
474+
"""
475+
Set a custom status for the bot.
476+
477+
Possible status types:
478+
- `online`
479+
- `idle`
480+
- `dnd`
481+
- `do_not_disturb` or `do not disturb`
482+
- `invisible` or `offline`
483+
- `clear`
471484
472-
self.bot.config['activity_type'] = activity_type
473-
self.bot.config['activity_message'] = message
485+
When status type is set to `clear`, the current status is removed.
486+
"""
487+
if status_type == 'clear':
488+
self.bot.config['status'] = None
489+
await self.bot.config.update()
490+
await self.set_presence(log=False)
491+
embed = Embed(
492+
title='Status Removed',
493+
color=self.bot.main_color
494+
)
495+
return await ctx.send(embed=embed)
496+
status_type = status_type.replace(' ', '_')
497+
498+
try:
499+
status, msg = (await self.set_presence(
500+
status_identifier=status_type,
501+
status_by_key=True,
502+
log=False
503+
))['status']
504+
except ValueError:
505+
raise commands.UserInputError
506+
507+
self.bot.config['status'] = status.value
474508
await self.bot.config.update()
475509

476-
desc = f'Current activity is: {activity_type.name} {message}.'
477510
embed = Embed(
478-
title='Activity Changed',
479-
description=desc,
511+
title='Status Changed',
512+
description=msg,
480513
color=self.bot.main_color
481514
)
482515
return await ctx.send(embed=embed)
483516

517+
async def set_presence(self, *,
518+
status_identifier=None,
519+
status_by_key=True,
520+
activity_identifier=None,
521+
activity_by_key=True,
522+
activity_message=None,
523+
log=True):
524+
525+
activity = status = None
526+
if status_identifier is None:
527+
status_identifier = self.bot.config.get('status', None)
528+
status_by_key = False
529+
530+
try:
531+
if status_by_key:
532+
status = Status[status_identifier]
533+
else:
534+
status = Status(status_identifier)
535+
except (KeyError, ValueError):
536+
if status_identifier is not None:
537+
msg = f'Invalid status type: {status_identifier}'
538+
if log:
539+
logger.warning(error(msg))
540+
else:
541+
raise ValueError(msg)
542+
543+
if activity_identifier is None:
544+
if activity_message is not None:
545+
raise ValueError('activity_message must be None '
546+
'if activity_identifier is None.')
547+
activity_identifier = self.bot.config.get('activity_type', None)
548+
activity_by_key = False
549+
550+
try:
551+
if activity_by_key:
552+
activity_type = ActivityType[activity_identifier]
553+
else:
554+
activity_type = ActivityType(activity_identifier)
555+
except (KeyError, ValueError):
556+
if activity_identifier is not None:
557+
msg = f'Invalid activity type: {activity_identifier}'
558+
if log:
559+
logger.warning(error(msg))
560+
else:
561+
raise ValueError(msg)
562+
else:
563+
url = None
564+
activity_message = (
565+
activity_message or
566+
self.bot.config.get('activity_message', '')
567+
).strip()
568+
569+
if activity_type == ActivityType.listening:
570+
if activity_message.lower().startswith('to '):
571+
# The actual message is after listening to [...]
572+
# discord automatically add the "to"
573+
activity_message = activity_message[3:].strip()
574+
elif activity_type == ActivityType.streaming:
575+
url = self.bot.config.get(
576+
'twitch_url', 'https://www.twitch.tv/discord-modmail/'
577+
)
578+
579+
if activity_message:
580+
activity = Activity(type=activity_type,
581+
name=activity_message,
582+
url=url)
583+
else:
584+
msg = 'You must supply an activity message to use custom activity.'
585+
if log:
586+
logger.warning(error(msg))
587+
else:
588+
raise ValueError(msg)
589+
590+
await self.bot.change_presence(activity=activity, status=status)
591+
592+
presence = {'activity': (None, 'No activity has been set.'),
593+
'status': (None, 'No status has been set.')}
594+
if activity is not None:
595+
# TODO: Trim message
596+
to = 'to ' if activity.type == ActivityType.listening else ''
597+
msg = f'Activity set to: {activity.type.name.capitalize()} '
598+
msg += f'{to}{activity.name}.'
599+
presence['activity'] = (activity, msg)
600+
if status is not None:
601+
msg = f'Status set to: {status.value}.'
602+
presence['status'] = (status, msg)
603+
return presence
604+
605+
async def on_ready(self):
606+
# Wait until config cache is populated with stuff from db
607+
await self.bot.config.wait_until_ready()
608+
presence = await self.set_presence()
609+
logger.info(info(presence['activity'][1]))
610+
logger.info(info(presence['status'][1]))
611+
484612
@commands.command()
485613
@trigger_typing
486614
@checks.has_permissions(administrator=True)

core/config.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ class ConfigManager(ConfigManagerABC):
2525
}
2626

2727
internal_keys = {
28-
# activity
29-
'activity_message', 'activity_type',
28+
# bot presence
29+
'activity_message', 'activity_type', 'status',
3030
# moderation
3131
'blocked',
3232
# threads
@@ -38,10 +38,7 @@ class ConfigManager(ConfigManagerABC):
3838
protected_keys = {
3939
# Modmail
4040
'modmail_api_token', 'modmail_guild_id', 'guild_id', 'owners',
41-
# logs
42-
'log_url',
43-
# database
44-
'mongo_uri',
41+
'log_url', 'mongo_uri',
4542
# bot
4643
'token',
4744
# GitHub

0 commit comments

Comments
 (0)