This repository has been archived by the owner on Sep 21, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
/
apollo.py
202 lines (168 loc) · 6.92 KB
/
apollo.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
import asyncio
from datetime import datetime
from discord import Message, Member
from discord.abc import GuildChannel
from discord.ext.commands import Bot, when_mentioned_or
from config import CONFIG
from karma.karma import process_karma
from models import User, db_session, LoggedMessage, MessageDiff, Reminder
DESCRIPTION = """
Apollo is the Discord bot for the University of Warwick Computing Society, designed to augment the server with a number of utilities and website services.
To verify your account please set your Discord tag (name and 4 digit number e.g.: Foo#1337) in account settings on the UWCS website and then PM the bot your university number.
"""
WELCOME_MESSAGE = """
Hey <@{user_id}>!
I'm Apollo, the UWCS Discord's friendly bot. I'd like to welcome you to the University of Warwick Computing Society Discord server!
If you're not already a member of the society, you can join through the Warwick student's union website.
GLHF! :rocket:
"""
# The command extensions to be loaded by the bot
EXTENSIONS = [
"commands.karma",
"commands.say",
"commands.flip",
"commands.misc",
"commands.admin",
"commands.blacklist",
"commands.fact",
"commands.reminders",
"commands.lcalc",
"commands.widen",
"commands.tex",
]
bot = Bot(command_prefix=when_mentioned_or("!"), description=DESCRIPTION)
def pluralise(l, word, single="", plural="s"):
if len(l) > 1:
return word + plural
else:
return word + single
async def reminder_check():
await bot.wait_until_ready()
while not bot.is_closed():
now = datetime.now()
# I have this useless variable because its not pep8 if you compare directly to False lol
not_triggered = False
reminders = (
db_session.query(Reminder)
.filter(Reminder.trigger_at <= now, Reminder.triggered == not_triggered)
.all()
)
for r in reminders:
if r.irc_name:
display_name = r.irc_name
else:
author_uid = (
db_session.query(User).filter(User.id == r.user_id).first().user_uid
)
display_name = f"<@{author_uid}>"
channel = bot.get_channel(r.playback_channel_id)
message = f"Reminding {display_name}: " + r.reminder_content
await channel.send(message)
r.triggered = True
db_session.commit()
await asyncio.sleep(CONFIG["REMINDER_SEARCH_INTERVAL"])
@bot.event
async def on_ready():
if CONFIG["BOT_LOGGING"]:
# TODO: Write this to a logging file?
print("Logged in as")
print(str(bot.user))
print("------")
@bot.event
async def on_message(message: Message):
# If the message is by a bot thats not irc then ignore it
if message.author.bot and message.author.id != CONFIG["UWCS_DISCORD_BRIDGE_BOT_ID"]:
return
user = db_session.query(User).filter(User.user_uid == message.author.id).first()
if not user:
user = User(user_uid=message.author.id, username=str(message.author))
db_session.add(user)
else:
user.last_seen = message.created_at
# Commit the session so the user is available now
db_session.commit()
# Only log messages that were in a public channel
if isinstance(message.channel, GuildChannel):
# Log the message to the database
logged_message = LoggedMessage(
message_uid=message.id,
message_content=message.clean_content,
author=user.id,
created_at=message.created_at,
channel_name=message.channel.name,
)
db_session.add(logged_message)
db_session.commit()
# Get all specified command prefixes for the bot
command_prefixes = bot.command_prefix(bot, message)
# Only process karma if the message was not a command (ie did not start with a command prefix)
if True not in [
message.content.startswith(prefix) for prefix in command_prefixes
]:
reply = process_karma(
message, logged_message.id, db_session, CONFIG["KARMA_TIMEOUT"]
)
if reply:
await message.channel.send(reply)
# allow irc users to use commands by altering content to remove the nick before sending for command processing
# note that clean_content is *not* altered and everything relies on this fact for it to work without having to go back and lookup the message in the db
# if message.content.startswith("**<"): <-- FOR TESTING
if message.author.id == CONFIG["UWCS_DISCORD_BRIDGE_BOT_ID"]:
# Search for first "> " and strip the message from there (Since irc nicks cant have <, > in them
idx = message.content.find(">** ")
idx += 4
message.content = message.content[idx:]
await bot.process_commands(message)
@bot.event
async def on_message_edit(before: Message, after: Message):
# Only care about messages that are in public channels
if isinstance(before.channel, GuildChannel):
# Message wasn't pinned
if before.pinned == after.pinned:
# Log any edits to messages
original_message = (
db_session.query(LoggedMessage)
.filter(LoggedMessage.message_uid == before.id)
.first()
)
if original_message:
message_diff = MessageDiff(
original_message=original_message.id,
new_content=after.clean_content,
created_at=(after.edited_at or datetime.utcnow()),
)
db_session.add(message_diff)
db_session.commit()
@bot.event
async def on_message_delete(message: Message):
# Get the message from the database
db_message = (
db_session.query(LoggedMessage)
.filter(LoggedMessage.message_uid == message.id)
.one_or_none()
)
# Can't really do anything if the message isn't in the logs so only handle when it is
if db_message:
# Update the message deleted_at and commit the changes made
db_message.deleted_at = datetime.utcnow()
db_session.commit()
@bot.event
async def on_member_join(member: Member):
# Add the user to our database if they've never joined before
user = db_session.query(User).filter(User.user_uid == member.id).first()
if not user:
user = User(user_uid=member.id, username=str(member))
db_session.add(user)
else:
user.last_seen = datetime.utcnow()
db_session.commit()
# await member.send(WELCOME_MESSAGE.format(user_id=member.id))
if __name__ == "__main__":
for extension in EXTENSIONS:
try:
bot.load_extension(extension)
except Exception as e:
exc = "{}: {}".format(type(e).__name__, e)
print("Failed to load extension {}\n{}".format(extension, exc))
bot.loop.create_task(reminder_check())
bot.run(CONFIG["DISCORD_TOKEN"])