Skip to content

Commit 92e7ece

Browse files
Merge branch 'master' into fix_dm_actionlogs
2 parents 4c9691b + 2c563d5 commit 92e7ece

File tree

6 files changed

+318
-206
lines changed

6 files changed

+318
-206
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"""Holder for the custom join/leave messages database class and the associated methods"""
2+
from dozer import db
3+
import discord
4+
from logging import getLogger
5+
6+
DOZER_LOGGER = getLogger(__name__)
7+
8+
9+
async def send_log(member):
10+
"""Sends the message for when a user joins or leave a guild"""
11+
config = await CustomJoinLeaveMessages.get_by(guild_id=member.guild.id)
12+
if len(config):
13+
channel = member.guild.get_channel(config[0].channel_id)
14+
if channel:
15+
embed = discord.Embed(color=0x00FF00)
16+
embed.set_author(name='Member Joined', icon_url=member.avatar_url_as(format='png', size=32))
17+
embed.description = format_join_leave(config[0].join_message, member)
18+
embed.set_footer(text="{} | {} members".format(member.guild.name, member.guild.member_count))
19+
try:
20+
await channel.send(content=member.mention if config[0].ping else None, embed=embed)
21+
except discord.Forbidden:
22+
DOZER_LOGGER.warning(
23+
f"Guild {member.guild}({member.guild.id}) has invalid permissions for join/leave logs")
24+
25+
26+
def format_join_leave(template: str, member: discord.Member):
27+
"""Formats join leave message templates
28+
{guild} = guild name
29+
{user} = user's name plus discriminator ex. SnowPlow#5196
30+
{user_name} = user's name without discriminator
31+
{user_mention} = user's mention
32+
{user_id} = user's ID
33+
"""
34+
if template:
35+
return template.format(guild=member.guild, user=str(member), user_name=member.name,
36+
user_mention=member.mention, user_id=member.id)
37+
else:
38+
return "{user_mention}\n{user} ({user_id})".format(user=str(member), user_mention=member.mention,
39+
user_id=member.id)
40+
41+
42+
class CustomJoinLeaveMessages(db.DatabaseTable):
43+
"""Holds custom join leave messages"""
44+
__tablename__ = 'memberlogconfig'
45+
__uniques__ = 'guild_id'
46+
47+
@classmethod
48+
async def initial_create(cls):
49+
"""Create the table in the database"""
50+
async with db.Pool.acquire() as conn:
51+
await conn.execute(f"""
52+
CREATE TABLE {cls.__tablename__} (
53+
guild_id bigint PRIMARY KEY NOT NULL,
54+
memberlog_channel bigint NOT NULL,
55+
name varchar NOT NULL
56+
)""")
57+
58+
def __init__(self, guild_id, channel_id=None, ping=None, join_message=None, leave_message=None):
59+
super().__init__()
60+
self.guild_id = guild_id
61+
self.channel_id = channel_id
62+
self.ping = ping
63+
self.join_message = join_message
64+
self.leave_message = leave_message
65+
66+
@classmethod
67+
async def get_by(cls, **kwargs):
68+
results = await super().get_by(**kwargs)
69+
result_list = []
70+
for result in results:
71+
obj = CustomJoinLeaveMessages(guild_id=result.get("guild_id"), channel_id=result.get("channel_id"),
72+
ping=result.get("ping"),
73+
join_message=result.get("join_message"),
74+
leave_message=result.get("leave_message"))
75+
result_list.append(obj)
76+
return result_list
77+
78+
async def version_1(self):
79+
"""DB migration v1"""
80+
async with db.Pool.acquire() as conn:
81+
await conn.execute(f"""
82+
alter table memberlogconfig rename column memberlog_channel to channel_id;
83+
alter table memberlogconfig alter column channel_id drop not null;
84+
alter table {self.__tablename__} drop column IF EXISTS name;
85+
alter table {self.__tablename__}
86+
add IF NOT EXISTS ping boolean default False;
87+
alter table {self.__tablename__}
88+
add IF NOT EXISTS join_message text default null;
89+
alter table {self.__tablename__}
90+
add IF NOT EXISTS leave_message text default null;
91+
""")
92+
93+
__versions__ = [version_1]

dozer/Components/TeamNumbers.py

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from dozer import db
2+
3+
4+
class TeamNumbers(db.DatabaseTable):
5+
"""Database operations for tracking team associations."""
6+
__tablename__ = 'team_numbers'
7+
__uniques__ = 'user_id, team_number, team_type'
8+
9+
@classmethod
10+
async def initial_create(cls):
11+
"""Create the table in the database"""
12+
async with db.Pool.acquire() as conn:
13+
await conn.execute(f"""
14+
CREATE TABLE {cls.__tablename__} (
15+
user_id bigint NOT NULL,
16+
team_number bigint NOT NULL,
17+
team_type VARCHAR NOT NULL,
18+
PRIMARY KEY (user_id, team_number, team_type)
19+
)""")
20+
21+
def __init__(self, user_id, team_number, team_type):
22+
super().__init__()
23+
self.user_id = user_id
24+
self.team_number = team_number
25+
self.team_type = team_type
26+
27+
async def update_or_add(self):
28+
"""Assign the attribute to this object, then call this method to either insert the object if it doesn't exist in
29+
the DB or update it if it does exist. It will update every column not specified in __uniques__."""
30+
# This is its own functions because all columns must be unique, which breaks the syntax of the other one
31+
keys = []
32+
values = []
33+
for var, value in self.__dict__.items():
34+
# Done so that the two are guaranteed to be in the same order, which isn't true of keys() and values()
35+
if value is not None:
36+
keys.append(var)
37+
values.append(value)
38+
async with db.Pool.acquire() as conn:
39+
statement = f"""
40+
INSERT INTO {self.__tablename__} ({", ".join(keys)})
41+
VALUES({','.join(f'${i+1}' for i in range(len(values)))})
42+
"""
43+
await conn.execute(statement, *values)
44+
45+
@classmethod
46+
async def get_by(cls, **kwargs):
47+
results = await super().get_by(**kwargs)
48+
result_list = []
49+
for result in results:
50+
obj = TeamNumbers(user_id=result.get("user_id"),
51+
team_number=result.get("team_number"),
52+
team_type=result.get("team_type"))
53+
result_list.append(obj)
54+
return result_list
55+
56+
# noinspection SqlResolve
57+
@classmethod
58+
async def top10(cls, user_ids):
59+
"""Returns the top 10 team entries"""
60+
query = f"""SELECT team_type, team_number, count(*)
61+
FROM {cls.__tablename__}
62+
WHERE user_id = ANY($1) --first param: list of user IDs
63+
GROUP BY team_type, team_number
64+
ORDER BY count DESC, team_type, team_number
65+
LIMIT 10"""
66+
async with db.Pool.acquire() as conn:
67+
return await conn.fetch(query, user_ids)

dozer/cogs/actionlogs.py

+21-92
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77

88
import discord
99
from discord.ext.commands import has_permissions, BadArgument
10-
10+
from ..Components.CustomJoinLeaveMessages import CustomJoinLeaveMessages, format_join_leave, send_log
11+
from .moderation import GuildNewMember
1112
from ._utils import *
1213
from .general import blurple
1314
from .. import db
@@ -21,7 +22,8 @@ async def embed_paginatorinator(content_name, embed, text):
2122
c_embed = embed.copy()
2223
c_embed.add_field(name=content_name, value=text[0:1023], inline=False)
2324
for n in range(1, required_chunks):
24-
c_embed.add_field(name=f"{content_name} Continued ({n})", value=text[1024*n:(1024*(n+1))-1], inline=False)
25+
c_embed.add_field(name=f"{content_name} Continued ({n})", value=text[1024 * n:(1024 * (n + 1)) - 1],
26+
inline=False)
2527
return c_embed
2628

2729

@@ -43,38 +45,17 @@ async def check_audit(guild, event_type, event_time=None):
4345
except discord.Forbidden:
4446
return None
4547

46-
@staticmethod
47-
def format_join_leave(template: str, member: discord.Member):
48-
"""Formats join leave message templates
49-
{guild} = guild name
50-
{user} = user's name plus discriminator ex. SnowPlow#5196
51-
{user_name} = user's name without discriminator
52-
{user_mention} = user's mention
53-
{user_id} = user's ID
54-
"""
55-
if template:
56-
return template.format(guild=member.guild, user=str(member), user_name=member.name,
57-
user_mention=member.mention, user_id=member.id)
58-
else:
59-
return "{user_mention}\n{user} ({user_id})".format(user=str(member), user_mention=member.mention,
60-
user_id=member.id)
61-
6248
@Cog.listener('on_member_join')
6349
async def on_member_join(self, member):
6450
"""Logs that a member joined, with optional custom message"""
65-
config = await CustomJoinLeaveMessages.get_by(guild_id=member.guild.id)
66-
if len(config):
67-
channel = member.guild.get_channel(config[0].channel_id)
68-
if channel:
69-
embed = discord.Embed(color=0x00FF00)
70-
embed.set_author(name='Member Joined', icon_url=member.avatar_url_as(format='png', size=32))
71-
embed.description = self.format_join_leave(config[0].join_message, member)
72-
embed.set_footer(text="{} | {} members".format(member.guild.name, member.guild.member_count))
73-
try:
74-
await channel.send(content=member.mention if config[0].ping else None, embed=embed)
75-
except discord.Forbidden:
76-
DOZER_LOGGER.warning(
77-
f"Guild {member.guild}({member.guild.id}) has invalid permissions for join/leave logs")
51+
nm_config = await GuildNewMember.get_by(guild_id=member.guild.id)
52+
if len(nm_config) == 0:
53+
await send_log(member)
54+
else:
55+
if nm_config[0].require_team:
56+
return
57+
else:
58+
await send_log(member)
7859

7960
@Cog.listener('on_member_remove')
8061
async def on_member_remove(self, member):
@@ -85,7 +66,7 @@ async def on_member_remove(self, member):
8566
if channel:
8667
embed = discord.Embed(color=0xFF0000)
8768
embed.set_author(name='Member Left', icon_url=member.avatar_url_as(format='png', size=32))
88-
embed.description = self.format_join_leave(config[0].leave_message, member)
69+
embed.description = format_join_leave(config[0].leave_message, member)
8970
embed.set_footer(text="{} | {} members".format(member.guild.name, member.guild.member_count))
9071
try:
9172
await channel.send(embed=embed)
@@ -367,11 +348,13 @@ async def on_message_edit(self, before, after):
367348
first_message = await channel.send(embed=first_embed)
368349
if second_embed:
369350
second_message = await channel.send(embed=second_embed)
370-
first_embed.add_field(name="Edited", value=f"[CONTINUED](https://discordapp.com/channels/{guild_id}"
371-
f"/{second_message.channel.id}/{second_message.id})", inline=False)
351+
first_embed.add_field(name="Edited",
352+
value=f"[CONTINUED](https://discordapp.com/channels/{guild_id}"
353+
f"/{second_message.channel.id}/{second_message.id})", inline=False)
372354
await first_message.edit(embed=first_embed)
373-
embed.set_field_at(0, name="Original", value=f"[CONTINUED](https://discordapp.com/channels/{guild_id}"
374-
f"/{first_message.channel.id}/{first_message.id})", inline=False)
355+
embed.set_field_at(0, name="Original",
356+
value=f"[CONTINUED](https://discordapp.com/channels/{guild_id}"
357+
f"/{first_message.channel.id}/{first_message.id})", inline=False)
375358
await second_message.edit(embed=second_embed)
376359

377360
@Cog.listener('on_member_ban')
@@ -426,9 +409,9 @@ async def memberlogconfig(self, ctx):
426409
embed.add_field(name="Message Channel", value=channel.mention if channel else "None")
427410
embed.add_field(name="Ping on join", value=config[0].ping)
428411
embed.add_field(name="Join template", value=config[0].join_message, inline=False)
429-
embed.add_field(name="Join Example", value=self.format_join_leave(config[0].join_message, ctx.author))
412+
embed.add_field(name="Join Example", value=format_join_leave(config[0].join_message, ctx.author))
430413
embed.add_field(name="Leave template", value=config[0].leave_message, inline=False)
431-
embed.add_field(name="Leave Example", value=self.format_join_leave(config[0].leave_message, ctx.author))
414+
embed.add_field(name="Leave Example", value=format_join_leave(config[0].leave_message, ctx.author))
432415
await ctx.send(embed=embed)
433416
else:
434417
await ctx.send("This guild has no member log configured")
@@ -623,60 +606,6 @@ async def get_by(cls, **kwargs):
623606
return result_list
624607

625608

626-
class CustomJoinLeaveMessages(db.DatabaseTable):
627-
"""Holds custom join leave messages"""
628-
__tablename__ = 'memberlogconfig'
629-
__uniques__ = 'guild_id'
630-
631-
@classmethod
632-
async def initial_create(cls):
633-
"""Create the table in the database"""
634-
async with db.Pool.acquire() as conn:
635-
await conn.execute(f"""
636-
CREATE TABLE {cls.__tablename__} (
637-
guild_id bigint PRIMARY KEY NOT NULL,
638-
memberlog_channel bigint NOT NULL,
639-
name varchar NOT NULL
640-
)""")
641-
642-
def __init__(self, guild_id, channel_id=None, ping=None, join_message=None, leave_message=None):
643-
super().__init__()
644-
self.guild_id = guild_id
645-
self.channel_id = channel_id
646-
self.ping = ping
647-
self.join_message = join_message
648-
self.leave_message = leave_message
649-
650-
@classmethod
651-
async def get_by(cls, **kwargs):
652-
results = await super().get_by(**kwargs)
653-
result_list = []
654-
for result in results:
655-
obj = CustomJoinLeaveMessages(guild_id=result.get("guild_id"), channel_id=result.get("channel_id"),
656-
ping=result.get("ping"),
657-
join_message=result.get("join_message"),
658-
leave_message=result.get("leave_message"))
659-
result_list.append(obj)
660-
return result_list
661-
662-
async def version_1(self):
663-
"""DB migration v1"""
664-
async with db.Pool.acquire() as conn:
665-
await conn.execute(f"""
666-
alter table memberlogconfig rename column memberlog_channel to channel_id;
667-
alter table memberlogconfig alter column channel_id drop not null;
668-
alter table {self.__tablename__} drop column IF EXISTS name;
669-
alter table {self.__tablename__}
670-
add IF NOT EXISTS ping boolean default False;
671-
alter table {self.__tablename__}
672-
add IF NOT EXISTS join_message text default null;
673-
alter table {self.__tablename__}
674-
add IF NOT EXISTS leave_message text default null;
675-
""")
676-
677-
__versions__ = [version_1]
678-
679-
680609
class GuildMessageLog(db.DatabaseTable):
681610
"""Holds config info for message logs"""
682611
__tablename__ = 'messagelogconfig'

0 commit comments

Comments
 (0)