Skip to content

Status command #178

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

The ability to enable typing interactions.
- The ability to enable typing interactions.

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.

- New `status` command, change the bot's status to `online`, `idle`, `dnd`, `invisible`, or `offline`.
- To remove the status (change it back to default), use `status clear`.
- This also introduces a new internal configuration variable: `status`. Possible values are `online`, `idle`, `dnd`, `invisible`, and `offline`.

### Changed
- The internals for `activity` has drastically changed to accommodate the new `status` command.

# 2.13.6

### Fixed
Expand Down
38 changes: 1 addition & 37 deletions bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
SOFTWARE.
"""

__version__ = '2.13.5'
__version__ = '2.13.6'

import asyncio
import logging
Expand All @@ -34,7 +34,6 @@
from types import SimpleNamespace

import discord
from discord.enums import ActivityType
from discord.ext import commands
from discord.ext.commands.view import StringView

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

# activities
activity_type = self.config.get('activity_type', -1)
message = self.config.get('activity_message', '')

try:
activity_type = ActivityType(activity_type)
except ValueError:
activity_type = -1

if activity_type >= 0 and message:
normalized_message = message.strip()
if activity_type == ActivityType.listening:
if message.lower().startswith('to '):
# Must be listening to...
normalized_message = message[3:].strip()
else:
normalized_message = ''

if normalized_message:
if activity_type == ActivityType.streaming:
url = self.config.get('twitch_url',
'https://www.twitch.tv/discord-modmail/')
else:
url = None

activity = discord.Activity(type=activity_type,
name=normalized_message,
url=url)
await self.change_presence(activity=activity)
# TODO: Trim message
logger.info(info('Activity set to: '
f'{activity_type.name} {message}.'))
else:
logger.info(info(f'No activity message set.'))

# closures
closures = self.config.closures.copy()
logger.info(info(f'There are {len(closures)} thread(s) '
Expand Down
186 changes: 157 additions & 29 deletions cogs/utility.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import inspect
import logging
import os
import traceback
from contextlib import redirect_stdout
Expand All @@ -10,7 +11,7 @@

import discord
from discord import Embed, Color, Activity
from discord.enums import ActivityType
from discord.enums import ActivityType, Status
from discord.ext import commands

from aiohttp import ClientResponseError
Expand All @@ -20,7 +21,9 @@
from core.decorators import github_access_token_required, trigger_typing
from core.models import Bot, InvalidConfigError
from core.paginator import PaginatorSession, MessagePaginatorSession
from core.utils import cleanup_code
from core.utils import cleanup_code, info, error

logger = logging.getLogger('Modmail')


class Utility:
Expand Down Expand Up @@ -244,7 +247,7 @@ async def debug(self, ctx):

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

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

try:
async with self.bot.session.post('https://hastebin.com/documents',
Expand Down Expand Up @@ -431,10 +434,10 @@ async def activity(self, ctx, activity_type: str, *, message: str = ''):
it must be followed by a "to": "listening to..."
"""
if activity_type == 'clear':
await self.bot.change_presence(activity=None)
self.bot.config['activity_type'] = None
self.bot.config['activity_message'] = None
await self.bot.config.update()
await self.set_presence(log=False)
embed = Embed(
title='Activity Removed',
color=self.bot.main_color
Expand All @@ -445,42 +448,167 @@ async def activity(self, ctx, activity_type: str, *, message: str = ''):
raise commands.UserInputError

try:
activity_type = ActivityType[activity_type.lower()]
except KeyError:
activity, msg = (await self.set_presence(
activity_identifier=activity_type,
activity_by_key=True,
activity_message=message,
log=False
))['activity']
except ValueError:
raise commands.UserInputError

if activity_type == ActivityType.listening:
if not message.lower().startswith('to '):
# Must be listening to...
raise commands.UserInputError
normalized_message = message[3:].strip()
else:
# Discord does not allow leading/trailing spaces anyways
normalized_message = message.strip()
self.bot.config['activity_type'] = activity.type.value
self.bot.config['activity_message'] = message
await self.bot.config.update()

if activity_type == ActivityType.streaming:
url = self.bot.config.get('twitch_url',
'https://www.twitch.tv/discord-Modmail/')
else:
url = None
embed = Embed(
title='Activity Changed',
description=msg,
color=self.bot.main_color
)
return await ctx.send(embed=embed)

activity = Activity(type=activity_type,
name=normalized_message,
url=url)
await self.bot.change_presence(activity=activity)
@commands.command()
@checks.has_permissions(administrator=True)
async def status(self, ctx, *, status_type: str):
"""
Set a custom status for the bot.

Possible status types:
- `online`
- `idle`
- `dnd`
- `do_not_disturb` or `do not disturb`
- `invisible` or `offline`
- `clear`

self.bot.config['activity_type'] = activity_type
self.bot.config['activity_message'] = message
When status type is set to `clear`, the current status is removed.
"""
if status_type == 'clear':
self.bot.config['status'] = None
await self.bot.config.update()
await self.set_presence(log=False)
embed = Embed(
title='Status Removed',
color=self.bot.main_color
)
return await ctx.send(embed=embed)
status_type = status_type.replace(' ', '_')

try:
status, msg = (await self.set_presence(
status_identifier=status_type,
status_by_key=True,
log=False
))['status']
except ValueError:
raise commands.UserInputError

self.bot.config['status'] = status.value
await self.bot.config.update()

desc = f'Current activity is: {activity_type.name} {message}.'
embed = Embed(
title='Activity Changed',
description=desc,
title='Status Changed',
description=msg,
color=self.bot.main_color
)
return await ctx.send(embed=embed)

async def set_presence(self, *,
status_identifier=None,
status_by_key=True,
activity_identifier=None,
activity_by_key=True,
activity_message=None,
log=True):

activity = status = None
if status_identifier is None:
status_identifier = self.bot.config.get('status', None)
status_by_key = False

try:
if status_by_key:
status = Status[status_identifier]
else:
status = Status(status_identifier)
except (KeyError, ValueError):
if status_identifier is not None:
msg = f'Invalid status type: {status_identifier}'
if log:
logger.warning(error(msg))
else:
raise ValueError(msg)

if activity_identifier is None:
if activity_message is not None:
raise ValueError('activity_message must be None '
'if activity_identifier is None.')
activity_identifier = self.bot.config.get('activity_type', None)
activity_by_key = False

try:
if activity_by_key:
activity_type = ActivityType[activity_identifier]
else:
activity_type = ActivityType(activity_identifier)
except (KeyError, ValueError):
if activity_identifier is not None:
msg = f'Invalid activity type: {activity_identifier}'
if log:
logger.warning(error(msg))
else:
raise ValueError(msg)
else:
url = None
activity_message = (
activity_message or
self.bot.config.get('activity_message', '')
).strip()

if activity_type == ActivityType.listening:
if activity_message.lower().startswith('to '):
# The actual message is after listening to [...]
# discord automatically add the "to"
activity_message = activity_message[3:].strip()
elif activity_type == ActivityType.streaming:
url = self.bot.config.get(
'twitch_url', 'https://www.twitch.tv/discord-modmail/'
)

if activity_message:
activity = Activity(type=activity_type,
name=activity_message,
url=url)
else:
msg = 'You must supply an activity message to use custom activity.'
if log:
logger.warning(error(msg))
else:
raise ValueError(msg)

await self.bot.change_presence(activity=activity, status=status)

presence = {'activity': (None, 'No activity has been set.'),
'status': (None, 'No status has been set.')}
if activity is not None:
# TODO: Trim message
to = 'to ' if activity.type == ActivityType.listening else ''
msg = f'Activity set to: {activity.type.name.capitalize()} '
msg += f'{to}{activity.name}.'
presence['activity'] = (activity, msg)
if status is not None:
msg = f'Status set to: {status.value}.'
presence['status'] = (status, msg)
return presence

async def on_ready(self):
# Wait until config cache is populated with stuff from db
await self.bot.config.wait_until_ready()
presence = await self.set_presence()
logger.info(info(presence['activity'][1]))
logger.info(info(presence['status'][1]))

@commands.command()
@trigger_typing
@checks.has_permissions(administrator=True)
Expand Down
9 changes: 3 additions & 6 deletions core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ class ConfigManager(ConfigManagerABC):
}

internal_keys = {
# activity
'activity_message', 'activity_type',
# bot presence
'activity_message', 'activity_type', 'status',
# moderation
'blocked',
# threads
Expand All @@ -38,10 +38,7 @@ class ConfigManager(ConfigManagerABC):
protected_keys = {
# Modmail
'modmail_api_token', 'modmail_guild_id', 'guild_id', 'owners',
# logs
'log_url',
# database
'mongo_uri',
'log_url', 'mongo_uri',
# bot
'token',
# GitHub
Expand Down