Skip to content

Commit

Permalink
Merge pull request #16 from Local-Connectivity-Lab/ticket-614
Browse files Browse the repository at this point in the history
ticket 614 - better UX in ticket thread creation
  • Loading branch information
philion authored Mar 23, 2024
2 parents 8ea5f90 + 286f2b1 commit 4d35682
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 88 deletions.
17 changes: 10 additions & 7 deletions cog_tickets.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from discord.ext import commands

from model import Message
from tickets import Ticket
from redmine import Client


Expand Down Expand Up @@ -146,12 +147,12 @@ async def create_new_ticket(self, ctx: discord.ApplicationContext, title:str):
await ctx.respond(f"error creating ticket with title={title}")


async def create_thread(self, ticket, ctx):
async def create_thread(self, ticket:Ticket, ctx:discord.ApplicationContext):
log.info(f"creating a new thread for ticket #{ticket.id} in channel: {ctx.channel}")
name = f"Ticket #{ticket.id}: {ticket.subject}"
msg_txt = f"Syncing ticket {self.redmine.get_field(ticket, 'url')} to new thread '{name}'"
message = await ctx.send(msg_txt)
thread = await message.create_thread(name=name)
thread_name = f"Ticket #{ticket.id}: {ticket.subject}"
thread = await ctx.channel.create_thread(name=thread_name)
# ticket-614: Creating new thread should post the ticket details to the new thread
await thread.send(self.bot.formatter.format_ticket_details(ticket))
return thread


Expand All @@ -170,6 +171,8 @@ async def thread_ticket(self, ctx: discord.ApplicationContext, ticket_id:int):
log.debug(f">>> found {user} for {ctx.user.name}")
self.redmine.enable_discord_sync(ticket.id, user, note)

await ctx.respond(f"Created new thread for {ticket.id}: {thread}") # todo add some fancy formatting
# ticket-614: add ticket link to thread response
ticket_link = self.bot.formatter.format_link(ticket)
await ctx.respond(f"Created new thread {thread.jump_url} for ticket {ticket_link}")
else:
await ctx.respond(f"ERROR: Unkown ticket ID: {ticket_id}") # todo add some fancy formatting
await ctx.respond(f"ERROR: Unkown ticket ID: {ticket_id}")
37 changes: 2 additions & 35 deletions redmine.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,41 +181,8 @@ def get_updated_field(self, ticket) -> dt.datetime:
# Starting to move fields out to their own methods, to eventually move to
# their own Ticket class.
def get_field(self, ticket, fieldname):
try:
match fieldname:
case "id":
return f"{ticket.id}"
case "url":
return f"{self.url}/issues/{ticket.id}"
case "link":
return f"[{ticket.id}]({self.url}/issues/{ticket.id})"
case "priority":
return ticket.priority.name
case "updated":
return ticket.updated_on # string, or dt?
case "assigned":
return ticket.assigned_to.name
case "status":
return ticket.status.name
case "subject":
return ticket.subject
case "title":
return ticket.title
#case "age":
# updated = dt.datetime.fromisoformat(ticket.updated_on) ### UTC
# age = dt.datetime.now(dt.timezone.utc) - updated
# return humanize.naturaldelta(age)
#case "sync":
# try:
# # Parse custom_field into datetime
# # FIXME: this is fragile: relies on specific index of custom field, add custom field lookup by name
# timestr = ticket.custom_fields[1].value
# return dt.datetime.fromisoformat(timestr) ### UTC
# except Exception as e:
# log.debug(f"sync tag not set")
# return None
except AttributeError:
return "" # or None?
return self.ticket_mgr.get_field(ticket, fieldname)


def get_discord_id(self, user):
if user:
Expand Down
19 changes: 2 additions & 17 deletions test_cog_tickets.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,43 +98,28 @@ async def test_new_ticket(self):

# create thread/sync
async def test_thread_sync(self):

# create a ticket and add a note
note = f"This is a test note tagged with {self.tag}"
old_message = f"This is a sync message with {self.tag}"

ticket = self.create_test_ticket()
self.redmine.append_message(ticket.id, self.user.login, note)

# thread the ticket using
ctx = self.build_context()
ctx.channel = unittest.mock.AsyncMock(discord.TextChannel)
ctx.channel.name = f"Test Channel {self.tag}"
#ctx.channel.id = self.tag

thread = unittest.mock.AsyncMock(discord.Thread)
thread.name = f"Ticket #{ticket.id}: {ticket.subject}"

member = unittest.mock.AsyncMock(discord.Member)
member.name=self.user.discord_id

message = unittest.mock.AsyncMock(discord.Message)
message.channel = ctx.channel
message.content = old_message
message.author = member
message.create_thread = unittest.mock.AsyncMock(return_value=thread)
ctx.channel.create_thread = unittest.mock.AsyncMock(return_value=thread)

# TODO setup history with a message from the user - disabled while I work out the history mock.
#thread.history = unittest.mock.AsyncMock(name="history")
#thread.history.flatten = unittest.mock.AsyncMock(name="flatten", return_value=[message])

ctx.send = unittest.mock.AsyncMock(return_value=message)

await self.cog.thread_ticket(ctx, ticket.id)

response = ctx.send.call_args.args[0]
thread_response = str(message.create_thread.call_args) # FIXME
self.assertIn(str(ticket.id), response)
thread_response = str(ctx.channel.create_thread.call_args) # FIXME
self.assertIn(str(ticket.id), thread_response)
self.assertIn(ticket.subject, thread_response)

Expand Down
35 changes: 6 additions & 29 deletions tickets.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ def get_notes(self, since:dt.datetime|None=None) -> list[TicketNote]:

return notes

def get_field(self, fieldname):
def get_field(self, fieldname:str):
val = getattr(self, fieldname)
#log.debug(f">>> {fieldname} = {val}, type={type(val)}")
return val
Expand Down Expand Up @@ -641,42 +641,19 @@ def get_updated_field(self, ticket) -> dt.datetime:
# NOTE: This implies that ticket should be a full object with methods.
# Starting to move fields out to their own methods, to eventually move to
# their own Ticket class.
def get_field(self, ticket, fieldname):
def get_field(self, ticket:Ticket, fieldname:str) -> str:
try:
match fieldname:
case "id":
return f"{ticket.id}"
case "url":
return f"{self.url}/issues/{ticket.id}"
case "link":
return f"[{ticket.id}]({self.url}/issues/{ticket.id})"
case "priority":
return ticket.priority.name
case "updated":
return ticket.updated_on # string, or dt?
case "assigned":
return ticket.assigned_to.name
case "status":
return ticket.status.name
case "subject":
return ticket.subject
case "title":
return ticket.title
#case "age":
# updated = dt.datetime.fromisoformat(ticket.updated_on) ### UTC
# age = dt.datetime.now(dt.timezone.utc) - updated
# return humanize.naturaldelta(age)
#case "sync":
# try:
# # Parse custom_field into datetime
# # FIXME: this is fragile: relies on specific index of custom field, add custom field lookup by name
# timestr = ticket.custom_fields[1].value
# return dt.datetime.fromisoformat(timestr) ### UTC
# except Exception as e:
# log.debug(f"sync tag not set")
# return None
return str(ticket.updated_on) # formatted string, or dt?
case _:
return str(ticket.get_field(fieldname))
except AttributeError:
return "" # or None?
return None


def main():
Expand Down

0 comments on commit 4d35682

Please sign in to comment.