Skip to content

Commit 1cb485e

Browse files
author
Paul Philion
committed
Adding /ticket status command for ticket resolve #1801.
1 parent 744a357 commit 1cb485e

File tree

3 files changed

+83
-2
lines changed

3 files changed

+83
-2
lines changed

netbot/cog_tickets.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ def get_priorities(ctx: discord.AutocompleteContext):
4343
return [priority for priority in priorities.keys() if priority.lower().startswith(ctx.value.lower())]
4444

4545

46+
def get_statuses(ctx: discord.AutocompleteContext):
47+
"""Returns a list of priorities that begin with the characters entered so far."""
48+
statuses = ["New", "In Progress", "Standing", "Resolved", "Backburner"]
49+
# .lower() is used to make the autocomplete case-insensitive
50+
return [status for status in statuses if status.lower().startswith(ctx.value.lower())]
51+
52+
4653
class PrioritySelect(discord.ui.Select):
4754
"""Popup menu to select ticket priority"""
4855
def __init__(self, bot_: discord.Bot):
@@ -108,6 +115,31 @@ async def callback(self, interaction: discord.Interaction):
108115
)
109116

110117

118+
class StatusSelect(discord.ui.Select):
119+
"""Popup menu to select ticket status"""
120+
def __init__(self, bot: discord.Bot):
121+
self.bot = bot
122+
123+
super().__init__(
124+
placeholder="Select ticket status...",
125+
min_values=1,
126+
max_values=1,
127+
options=[
128+
discord.SelectOption("New"),
129+
discord.SelectOption("In Progress"),
130+
discord.SelectOption("Standing"),
131+
discord.SelectOption("Resolved"),
132+
discord.SelectOption("Backburner"),
133+
],
134+
)
135+
136+
async def callback(self, interaction: discord.Interaction):
137+
log.info(f"{interaction.user} {interaction.data}")
138+
await interaction.response.send_message(
139+
f"TrackerSelect.callback() - selected tracker {self.values[0]}"
140+
)
141+
142+
111143
class SubjectEdit(discord.ui.InputText, Item[V]):
112144
"""Popup menu to select ticket tracker"""
113145
def __init__(self, bot_: discord.Bot, ticket: Ticket):
@@ -560,7 +592,7 @@ async def thread(self, ctx: discord.ApplicationContext, ticket_id:int):
560592

561593
@ticket.command(name="tracker", description="Update the tracker of a ticket")
562594
@option("ticket_id", description="ID of ticket to update", autocomplete=basic_autocomplete(default_ticket))
563-
@option("tracker", description="Track to assign to ticket", autocomplete=get_trackers)
595+
@option("tracker", description="Tracker to assign to ticket", autocomplete=get_trackers)
564596
async def tracker(self, ctx: discord.ApplicationContext, ticket_id:int, tracker:str):
565597
user = self.redmine.user_mgr.find_discord_user(ctx.user.name)
566598
ticket = self.redmine.ticket_mgr.get(ticket_id)
@@ -581,6 +613,29 @@ async def tracker(self, ctx: discord.ApplicationContext, ticket_id:int, tracker:
581613
await ctx.respond(f"ERROR: Unkown ticket ID: {ticket_id}")
582614

583615

616+
@ticket.command(name="status", description="Update the status of a ticket")
617+
@option("ticket_id", description="ID of ticket to update", autocomplete=basic_autocomplete(default_ticket))
618+
@option("status", description="Status to assign to ticket", autocomplete=get_statuses)
619+
async def status(self, ctx: discord.ApplicationContext, ticket_id:int, status:str):
620+
user = self.redmine.user_mgr.find_discord_user(ctx.user.name)
621+
ticket = self.redmine.ticket_mgr.get(ticket_id)
622+
if ticket:
623+
ticket_link = self.bot.formatter.redmine_link(ticket)
624+
625+
# look up the tracker string
626+
status_rec = self.bot.redmine.ticket_mgr.get_status(status)
627+
fields = {
628+
"status_id": status_rec.id,
629+
}
630+
updated = self.bot.redmine.ticket_mgr.update(ticket_id, fields, user.login)
631+
632+
await ctx.respond(
633+
f"Updated tracker of {ticket_link}: {ticket.tracker} -> {updated.tracker}",
634+
embed=self.bot.formatter.ticket_embed(ctx, updated))
635+
else:
636+
await ctx.respond(f"ERROR: Unkown ticket ID: {ticket_id}")
637+
638+
584639
@ticket.command(name="priority", description="Update the priority of a ticket")
585640
@option("ticket_id", description="ID of ticket to update", autocomplete=basic_autocomplete(default_ticket))
586641
@option("priority", description="Priority to assign to ticket", autocomplete=get_priorities)

redmine/model.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ class TicketStatus(NamedId):
116116
id: int
117117
name: str
118118
is_closed: bool
119+
description: str | None = None
119120

120121
def __str__(self):
121122
return self.name

redmine/tickets.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import json
88
import urllib.parse
99

10-
from redmine.model import TO_CC_FIELD_NAME, User, Message, NamedId, Team, Ticket, TicketNote, TicketsResult, SYNC_FIELD_NAME
10+
from redmine.model import TO_CC_FIELD_NAME, User, Message, NamedId, Team, Ticket, TicketNote, TicketsResult, TicketStatus, SYNC_FIELD_NAME
1111
from redmine.session import RedmineSession, RedmineException
1212
from redmine import synctime
1313

@@ -36,13 +36,15 @@ def __init__(self, session: RedmineSession, default_project:int):
3636
self.priorities = {}
3737
self.trackers = {}
3838
self.custom_fields = {}
39+
self.statuses = {}
3940
self.default_project:int = default_project
4041

4142
self.reindex()
4243

4344

4445
def reindex(self):
4546
self.priorities = self.load_priorities()
47+
self.statuses = self.load_statuses()
4648
self.trackers = self.load_trackers()
4749
self.custom_fields = self.load_custom_fields()
4850

@@ -116,6 +118,29 @@ def get_trackers(self) -> dict[str,NamedId]:
116118
return self.trackers
117119

118120

121+
def load_statuses(self) -> dict[str,TicketStatus]:
122+
"""load active priorities"""
123+
124+
statuses: dict[str,TicketStatus] = {}
125+
126+
resp = self.session.get("/issue_statuses.json")
127+
if resp:
128+
for status in reversed(resp['issue_statuses']):
129+
statuses[status['name']] = TicketStatus(**status)
130+
else:
131+
log.warning("No statuses to load")
132+
133+
return statuses
134+
135+
136+
def get_status(self, name:str) -> TicketStatus | None:
137+
return self.statuses.get(name, None)
138+
139+
140+
def get_statuses(self) -> dict[str,TicketStatus]:
141+
return self.statuses
142+
143+
119144
def create(self, user: User, message: Message, project_id: int = None, **params) -> Ticket:
120145
"""create a redmine ticket"""
121146
# https://www.redmine.org/projects/redmine/wiki/Rest_Issues#Creating-an-issue

0 commit comments

Comments
 (0)