Skip to content

Commit 67a50cb

Browse files
committed
Status command
1 parent b345564 commit 67a50cb

File tree

4 files changed

+170
-71
lines changed

4 files changed

+170
-71
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
# [Unreleased]
8+
9+
### Added
10+
- New `status` command, change the bot's status to `online`, `idle`, `dnd`, `invisible`, or `offline`.
11+
- To remove the status (change it back to default), use `status clear`.
12+
13+
### Changed
14+
- The internals for `activity` has drastically changed to accommodate the new `status` command.
15+
716
# 2.13.5
817

918
### Added

bot.py

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -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: 158 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,168 @@ 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, 'status': None}
593+
if activity is not None:
594+
# TODO: Trim message
595+
to = 'to ' if activity.type == ActivityType.listening else ''
596+
msg = f'Activity set to: {activity.type.name.capitalize()} '
597+
msg += f'{to}{activity.name}.'
598+
if log:
599+
logger.info(info(msg))
600+
presence['activity'] = (activity, msg)
601+
if status is not None:
602+
msg = f'Status set to: {status.value}.'
603+
if log:
604+
logger.info(info(msg))
605+
presence['status'] = (status, msg)
606+
return presence
607+
608+
async def on_ready(self):
609+
# Wait until config cache is populated with stuff from db
610+
await self.bot.config.wait_until_ready()
611+
await self.set_presence()
612+
484613
@commands.command()
485614
@trigger_typing
486615
@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+
# activity + status
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)