async def makeparent(self, ctx: utils.Context, *, target: localutils.converters.UnblockedMember): """ Picks a user that you want to be your parent. """ # Variables we're gonna need for later family_guild_id = localutils.get_family_guild_id(ctx) author_tree, target_tree = localutils.FamilyTreeMember.get_multiple( ctx.author.id, target.id, guild_id=family_guild_id) # Check they're not themselves if target.id == ctx.author.id: return await ctx.send( "That's you. You can't make yourself your parent.") # Check they're not a bot if target.id == self.bot.user.id: return await ctx.send( "I think I could do better actually, but thank you!") # Lock those users re = await self.bot.redis.get_connection() try: lock = await localutils.ProposalLock.lock(re, ctx.author.id, target.id) except localutils.ProposalInProgress: return await ctx.send( "Aren't you popular! One of you is already waiting on a proposal - please try again later." ) # See if the *target* is already married if author_tree.parent: await lock.unlock() return await ctx.send( f"Hey! {ctx.author.mention}, you already have a parent \N{ANGRY FACE}", allowed_mentions=localutils.only_mention(ctx.author), ) # See if we're already married if ctx.author.id in target_tree._children: await lock.unlock() return await ctx.send( f"Hey isn't {target.mention} already your child? \N{FACE WITH ROLLING EYES}", allowed_mentions=localutils.only_mention(ctx.author), ) # See if they're already related async with ctx.channel.typing(): relation = author_tree.get_relation(target_tree) if relation and localutils.guild_allows_incest(ctx) is False: await lock.unlock() return await ctx.send( f"Woah woah woah, it looks like you guys are already related! {target.mention} is your {relation}!", allowed_mentions=localutils.only_mention(ctx.author), ) # Manage children children_amount = await self.get_max_children_for_member( ctx.guild, target) if len(author_tree._children) >= children_amount: return await ctx.send( f"You're currently at the maximum amount of children you can have - see `{ctx.prefix}perks` for more information." ) # Check the size of their trees # TODO I can make this a util because I'm going to use it a couple times max_family_members = localutils.get_max_family_members(ctx) async with ctx.channel.typing(): family_member_count = 0 for i in author_tree.span(add_parent=True, expand_upwards=True): if family_member_count >= max_family_members: break family_member_count += 1 for i in target_tree.span(add_parent=True, expand_upwards=True): if family_member_count >= max_family_members: break family_member_count += 1 if family_member_count >= max_family_members: await lock.unlock() return await ctx.send( f"If you added {target.mention} to your family, you'd have over {max_family_members} in your family. Sorry!", allowed_mentions=localutils.only_mention(ctx.author), ) # Set up the proposal try: result = await localutils.send_proposal_message( ctx, target, f"Hey, {target.mention}, {ctx.author.mention} wants to be your child! What do you think?", allow_bots=True, ) except Exception: result = None if result is None: return await lock.unlock() # Database it up async with self.bot.database() as db: try: await db( """INSERT INTO parents (parent_id, child_id, guild_id, timestamp) VALUES ($1, $2, $3, $4)""", target.id, ctx.author.id, family_guild_id, dt.utcnow(), ) except asyncpg.UniqueViolationError: await lock.unlock() return await ctx.send( "I ran into an error saving your family data - please try again later." ) await ctx.send( f"I'm happy to introduce {ctx.author.mention} as your child, {target.mention}!", ignore_error=True) # And we're done target_tree._children.append(author_tree.id) author_tree._parent = target.id await re.publish('TreeMemberUpdate', author_tree.to_json()) await re.publish('TreeMemberUpdate', target_tree.to_json()) await re.disconnect() await lock.unlock()
async def propose(self, ctx:utils.Context, *, target:localutils.converters.UnblockedMember): """ Lets you propose to another Discord user. """ # Get the family tree member objects family_guild_id = localutils.get_family_guild_id(ctx) author_tree, target_tree = localutils.FamilyTreeMember.get_multiple(ctx.author.id, target.id, guild_id=family_guild_id) # Check they're not themselves if target.id == ctx.author.id: return await ctx.send("That's you. You can't marry yourself.") # Check they're not a bot if target.bot: if target.id == self.bot.user.id: return await ctx.send("I think I could do better actually, but thank you!") return await ctx.send("That is a robot. Robots cannot consent to marriage.") # Lock those users re = await self.bot.redis.get_connection() try: lock = await localutils.ProposalLock.lock(re, ctx.author.id, target.id) except localutils.ProposalInProgress: return await ctx.send("Aren't you popular! One of you is already waiting on a proposal - please try again later.") # See if we're already married if author_tree._partner: await lock.unlock() return await ctx.send( f"Hey, {ctx.author.mention}, you're already married! Try divorcing your partner first \N{FACE WITH ROLLING EYES}", allowed_mentions=localutils.only_mention(ctx.author), ) # See if the *target* is already married if target_tree._partner: await lock.unlock() return await ctx.send( f"Sorry, {ctx.author.mention}, it looks like {target.mention} is already married \N{PENSIVE FACE}", allowed_mentions=localutils.only_mention(ctx.author), ) # See if they're already related async with ctx.channel.typing(): relation = author_tree.get_relation(target_tree) if relation and localutils.guild_allows_incest(ctx) is False: await lock.unlock() return await ctx.send( f"Woah woah woah, it looks like you guys are already related! {target.mention} is your {relation}!", allowed_mentions=localutils.only_mention(ctx.author), ) # Check the size of their trees # TODO I can make this a util because I'm going to use it a couple times max_family_members = localutils.get_max_family_members(ctx) async with ctx.channel.typing(): family_member_count = 0 for i in author_tree.span(add_parent=True, expand_upwards=True): if family_member_count >= max_family_members: break family_member_count += 1 for i in target_tree.span(add_parent=True, expand_upwards=True): if family_member_count >= max_family_members: break family_member_count += 1 if family_member_count >= max_family_members: await lock.unlock() return await ctx.send( f"If you added {target.mention} to your family, you'd have over {max_family_members} in your family. Sorry!", allowed_mentions=localutils.only_mention(ctx.author), ) # Set up the proposal try: result = await localutils.send_proposal_message( ctx, target, f"Hey, {target.mention}, it would make {ctx.author.mention} really happy if you would marry them. What do you say?", ) except Exception: result = None if result is None: return await lock.unlock() # They said yes! async with self.bot.database() as db: try: await db.start_transaction() await db( "INSERT INTO marriages (user_id, partner_id, guild_id, timestamp) VALUES ($1, $2, $3, $4), ($2, $1, $3, $4)", ctx.author.id, target.id, family_guild_id, dt.utcnow(), ) await db.commit_transaction() except asyncpg.UniqueViolationError: await lock.unlock() return await ctx.send("I ran into an error saving your family data.") await ctx.send(f"I'm happy to introduce {target.mention} into the family of {ctx.author.mention}!") # Ping over redis author_tree._partner = target.id target_tree._partner = ctx.author.id await re.publish('TreeMemberUpdate', author_tree.to_json()) await re.publish('TreeMemberUpdate', target_tree.to_json()) await re.disconnect() await lock.unlock()