async def _delete(ctx, t: Ticket): """ This is to delete a ticket. """ utc = time.time() conf = Confirmation(ctx) await conf.confirm(ctx.translate("you are attempting to delete ticket [ticket]").format(t.id)) if conf.confirmed: author = User.from_discord_user(ctx.author) t.state_enum = enums.State.DELETED t.deleted_by.add(author, properties={'UTC': utc}) t.push() for resp in t.get_responses(): resp.deleted = True resp.deleted_by.add(author, properties={'UTC': utc}) resp.push() await conf.display(ctx.translate("ticket deleted")) if t.scope_enum == enums.Scope.CHANNEL: channel = t.channel if channel is not None: await channel.delete(reason=ctx.translate("ticket has been deleted")) await t.guild.log(ctx.translate("[user] deleted ticket [ticket]").format(ctx.author, t.id)) else: await conf.display((ctx.translate("canceled")))
async def on_member_join(member): db_guild = Guild.from_discord_guild(member.guild) db_user = User.from_discord_user(member) db_guild.joined_users.add(db_user, properties={'UTC': time.time()}) db_guild.push()
async def _create(ctx, t: Ticket, content: str): """ This is to create new responses/to answer tickets. """ if t.scope_enum == enums.Scope.CHANNEL and ctx.channel != t.channel and not ctx.may_fully_access( t): await ctx.send(ctx.translate("the related ticket is channel scope")) return None elif t.scope_enum == enums.Scope.PRIVATE and not ctx.may_fully_access(t): await ctx.send(ctx.translate("this is a private ticket")) return None elif t.state_enum == enums.State.CLOSED: await ctx.send(ctx.translate("this ticket is closed")) return None if t.scope_enum == enums.Scope.PRIVATE: try: await ctx.message.delete() except discord.Forbidden: pass utc = time.time() resp = Response() author = User.from_discord_user(ctx.author) resp.created_by.add(author, properties={'UTC': utc}) resp.located_on.add(ctx.db_guild) resp.refers_to.add(t) resp.content = escaped(content) resp.deleted = False resp.updated = utc highest_id = graph.run( "MATCH (r:Response)-[:REFERS_TO]->(t:Ticket {uuid: '%s'}) RETURN max(r.id)" % t.uuid).evaluate() if highest_id is None: highest_id = 0 resp.id = highest_id + 1 resp.uuid = uuid.uuid4().hex graph.create(resp) await ctx.send(ctx.translate("response created").format(resp.full_id)) resp_msg = ctx.translate( "[user] just responded to your ticket [ticket]").format( ctx.author.name, ctx.author.discriminator, t.id) await notify_author(ctx, resp_msg, t, embed=response_embed(ctx, resp)) await resp.guild.log( ctx.translate("[user] created response [response]").format( ctx.author, f"{resp.ticket.id}-{resp.id}"))
async def _reopen(ctx, t: Ticket): """ This is to reopen a specific support ticket. """ if t.state_enum != enums.State.CLOSED: await ctx.send(ctx.translate("this ticket is not closed")) return None utc = time.time() t.state = enums.State.REOPENED.value user = User.from_discord_user(ctx.author) t.reopened_by.add(user, properties={'UTC': utc}) t.updated = utc graph.push(t) if t.scope_enum == enums.Scope.CHANNEL: category = t.guild.discord.get_channel(t.guild.ticket_category) channel = await t.guild.discord.create_text_channel( str(t.id), overwrites={ t.author.discord: discord.PermissionOverwrite(read_messages=True, send_messages=True) }, category=category, reason=ctx.translate("channel-ticket has been reopened")) await channel.edit(topic=t.title, sync_permissions=True) await ctx.send(ctx.translate("ticket reopened")) if t.guild.channel != ctx.channel.id: await notify_ticket_authority( ctx, t, ctx.translate("[user] just reopened a ticket").format( ctx.author.mention), send_embed=True) await t.guild.log( ctx.translate("[user] reopened ticket [ticket]").format( ctx.author, t.id))
async def on_member_update(before: Member, after: Member): if before.guild.id != CONFIG['home_guild']: return prime_roles = CONFIG['prime_roles'] was_prime = any(r.id in prime_roles for r in before.roles) is_prime = any(r.id in prime_roles for r in after.roles) if was_prime == is_prime: return # abort because nothing has changed db_user = User.from_discord_user(after) db_user.prime = is_prime # update value db_user.push() logger.info( f"{'added' if is_prime else 'removed'} prime member: {db_user.id}")
async def _close(ctx, t: Ticket, response=None): """ This is to close a specific support ticket. """ if t.state_enum == enums.State.CLOSED: await ctx.send(ctx.translate('this ticket is already closed')) return None utc = time.time() t.state = enums.State.CLOSED.value user = User.from_discord_user(ctx.author) t.closed_by.add(user, properties={'UTC': utc}) t.updated = utc graph.push(t) conf_msg = ctx.translate('ticket closed') close_msg = ctx.translate('[user] just closed ticket [ticket]').format( ctx.author.mention, t.id) if response is not None: close_msg += f"\n```{escaped(response)}```" send_success = await notify_author(ctx, close_msg, t) if send_success == 1: conf_msg += ctx.translate("ticket author doesn't allow dms") await ctx.send(conf_msg) if t.guild.channel != ctx.channel.id: await notify_ticket_authority(ctx, t, close_msg, send_embed=True) if t.scope_enum == enums.Scope.CHANNEL: channel = t.channel if channel is not None: await channel.delete(reason=ctx.translate("ticket has been closed") ) await t.guild.log( ctx.translate("[user] closed ticket [ticket]").format( ctx.author, t.id))
async def _delete(ctx, resp: Response): """ This is to delete a response. """ utc = time.time() ticket = resp.ticket if not (ctx.author.id == resp.author.id or ctx.may_fully_access(ticket)): await ctx.send( ctx.translate("you are not allowed to perform this action")) return None resp.deleted = True resp.deleted_by.add(User.from_discord_user(ctx.author), properties={'UTC': utc}) resp.push() await ctx.send(ctx.translate("response deleted")) await resp.guild.log( ctx.translate("[user] deleted response [response]").format( ctx.author, f"{resp.ticket.id}-{resp.id}"))
async def _create(ctx, title: str, description: str="", scope: Scope=None): """ This is to create a support ticket. """ guild = ctx.db_guild t = Ticket(ctx=ctx) if len(title) > enums.TitleLength.MAX: await ctx.send(ctx.translate("title too long").format(enums.TitleLength.MAX.value, len(title))) elif len(title) < enums.TitleLength.MIN: await ctx.send(ctx.translate("title too short").format(enums.TitleLength.MIN.value, len(title))) else: utc = time.time() t.title = escaped(title) t.description = escaped(description) t.state = enums.State.OPEN.value t.updated = utc author = User.from_discord_user(ctx.author) t.created_by.add(author, properties={'UTC': utc}) t.located_on.add(guild) if scope is None: scope = t.guild.default_scope t.scope = scope highest_id = graph.run( "MATCH (t:Ticket)-[:TICKET_LOCATED_ON]->(g:Guild {id: %i}) RETURN max(t.id)" % guild.id ).evaluate() if highest_id is None: highest_id = 0 t.id = highest_id + 1 t.uuid = uuid.uuid4().hex responsible_user = None if t.guild.auto_assigning: support_role: discord.Role = t.guild.discord.get_role(t.guild.support_role) if support_role is not None: responsible_user = random.choice(support_role.members) responsible_user = User.from_discord_user(responsible_user, ctx=ctx) t.assigned_to.add(responsible_user) graph.create(t) send_invokation_channel = False # create text channel (and category if not exist yet) for channel ticket if t.scope_enum == enums.Scope.CHANNEL: supporter = discord.utils.get(guild.discord.roles, id=guild.support_role) if supporter is None: supporter = guild.discord.owner overwrites = { guild.discord.default_role: discord.PermissionOverwrite(read_messages=False), guild.discord.me: discord.PermissionOverwrite(read_messages=True, send_messages=True, manage_messages=True, add_reactions=True, manage_channels=True), supporter: discord.PermissionOverwrite(read_messages=True, send_messages=True) } if guild.ticket_category is None: category = await guild.discord.create_category( ctx.translate("support tickets"), overwrites=overwrites, reason=ctx.translate("first channel-ticket has been created") ) guild.ticket_category = category.id guild.push() else: category = guild.discord.get_channel(guild.ticket_category) overwrites[author.discord] = discord.PermissionOverwrite(read_messages=True, send_messages=True) channel = await guild.discord.create_text_channel( str(t.id), overwrites=overwrites, category=category, reason=ctx.translate("new channel-ticket has been created") ) await channel.edit( topic=t.title ) await channel.send(embed=ticket_embed(ctx, t)) format_id = channel.mention elif t.scope_enum == enums.Scope.PRIVATE: try: await ctx.message.delete() except discord.Forbidden: pass format_id = t.id else: send_invokation_channel = True format_id = t.id msg = ctx.translate("ticket created").format(format_id) try: await ctx.author.send(ctx.translate("your ticket has been created").format(t.id, guild.discord.name)) dm_allowed = True except commands.BotMissingPermissions: dm_allowed = False if not dm_allowed: msg += '\n' + ctx.translate("please allow receiving dms") if responsible_user is not None: msg += '\n\n' + ctx.translate("ticket auto-assigned to [user]").format(responsible_user.discord) await ctx.send(msg) if t.guild.channel != ctx.channel.id: new_ticket_msg = ctx.translate("new ticket") if send_invokation_channel: new_ticket_msg += ctx.translate("created in [channel]").format(ctx.channel.mention) await notify_ticket_authority(ctx, t, new_ticket_msg, send_embed=True) await t.guild.log(ctx.translate("[user] created ticket [ticket]").format(ctx.author, t.id))