feat(core): Add slash command /spend for ticket and ticket comments

ref: #284 closes #286
This commit is contained in:
2024-09-13 21:58:19 +09:30
parent a7e99eb5b4
commit c3307152e8
5 changed files with 153 additions and 1 deletions

View File

@ -0,0 +1,37 @@
import re
from core.lib.slash_commands.duration import Duration
class SlashCommands(
Duration
):
"""Slash Commands Base Class
This class in intended to be included in the following models:
- Ticket
- TicketComment
"""
def slash_command(self, markdown:str) -> str:
""" Slash Commands Processor
Markdown text that contains a slash command is passed to this function and on the processing
of any valid slash command, the slash command will be removed from the markdown.
If any error occurs when attempting to process the slash command, it will not be removed from
the markdown. This is by design so that the "errored" slash command can be inspected.
Args:
markdown (str): un-processed Markdown
Returns:
str: Markdown without the slash command text.
"""
markdown = re.sub(self.time_spent, self.command_duration, markdown)
return markdown

View File

@ -0,0 +1,91 @@
import re
class Duration:
"""Duration Slash Command
The command keyword is `spend` and you can also use `spent`. The formatting for the time
after the command, is <digit> then either `h`, `m`, `s` for hours, minutes and seconds respectively.
Valid commands are as follows:
- /spend 1h1ms
- /spend 1h 1m 1s
For this command to process the following conditions must be met:
- There is either a `<new line>` (`\n`) or a `<space>` char immediatly before the slash `/`
- There is a `<space>` char after the command keyword, i.e. `/spend<space>1h`
- _Optional_ `<space>` char between the time blocks.
"""
time_spent: str = r'[\s|\n]\/(?P<command>[spend|spent]+)\s(?P<time>(?P<hours>\d+h)?\s?(?P<minutes>[\d]{1,2}m)?\s?(?P<seconds>\d+[s])?)[\s|\n]?'
def command_duration(self, match) -> str:
"""/spend, /spent processor
Slash command usage within a ticket description will add an action comment with the
time spent. For a ticket comment, it's duration field is set to the duration valuee calculated.
Args:
match (re.Match): Grouped matches
Returns:
str: The matched string if the duration calculation is `0`
None: On successfully processing the command
"""
a = 'a'
command = match.group('command')
time:str = str(match.group('time')).replace(' ', '')
hours = match.group('hours')
minutes = match.group('minutes')
seconds = match.group('seconds')
duration: int = 0
if hours is not None:
duration += int(hours[:-1])*60*60
if minutes is not None:
duration += int(minutes[:-1])*60
if seconds is not None:
duration += int(seconds[:-1])
if duration > 0:
if str(self._meta.verbose_name).lower() == 'ticket':
from core.models.ticket.ticket_comment import TicketComment
comment_text = f'added {time} of time spent'
TicketComment.objects.create(
ticket = self,
comment_type = TicketComment.CommentType.ACTION,
body = comment_text,
duration = duration,
user = self.opened_by,
)
if str(self._meta.verbose_name).lower() == 'comment':
self.duration = duration
else:
#ToDo: Add logging that the slash command could not be processed.
return str(match.string[match.start():match.end()])
return None