Skip to content

Commit

Permalink
Fix ticket search, when there are multiple custom fields
Browse files Browse the repository at this point in the history
  • Loading branch information
mozggg committed Apr 28, 2023
1 parent a1bff31 commit f45a8b6
Showing 1 changed file with 175 additions and 0 deletions.
175 changes: 175 additions & 0 deletions helpdesk/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,181 @@
logger = logging.getLogger('helpdesk')


def send_templated_mail(template_name,
context,
recipients,
sender=None,
bcc=None,
fail_silently=False,
files=None):
"""
send_templated_mail() is a wrapper around Django's e-mail routines that
allows us to easily send multipart (text/plain & text/html) e-mails using
templates that are stored in the database. This lets the admin provide
both a text and a HTML template for each message.
template_name is the slug of the template to use for this message (see
models.EmailTemplate)
context is a dictionary to be used when rendering the template
recipients can be either a string, eg 'a@b.com', or a list of strings.
sender should contain a string, eg 'My Site <me@z.com>'. If you leave it
blank, it'll use settings.DEFAULT_FROM_EMAIL as a fallback.
bcc is an optional list of addresses that will receive this message as a
blind carbon copy.
fail_silently is passed to Django's mail routine. Set to 'True' to ignore
any errors at send time.
files can be a list of tuples. Each tuple should be a filename to attach,
along with the File objects to be read. files can be blank.
"""
from django.core.mail import EmailMultiAlternatives
from django.template import engines
from_string = engines['django'].from_string

from helpdesk.models import EmailTemplate
from helpdesk.settings import HELPDESK_EMAIL_SUBJECT_TEMPLATE, \
HELPDESK_EMAIL_FALLBACK_LOCALE

locale = context['queue'].get('locale') or HELPDESK_EMAIL_FALLBACK_LOCALE

try:
t = EmailTemplate.objects.get(template_name__iexact=template_name, locale=locale)
except EmailTemplate.DoesNotExist:
try:
t = EmailTemplate.objects.get(template_name__iexact=template_name, locale__isnull=True)
except EmailTemplate.DoesNotExist:
logger.warning('template "%s" does not exist, no mail sent', template_name)
return # just ignore if template doesn't exist

subject_part = from_string(
HELPDESK_EMAIL_SUBJECT_TEMPLATE % {
"subject": t.subject
}).render(context).replace('\n', '').replace('\r', '')

footer_file = os.path.join('helpdesk', locale, 'email_text_footer.txt')

text_part = from_string(
"%s{%% include '%s' %%}" % (t.plain_text, footer_file)
).render(context)

email_html_base_file = os.path.join('helpdesk', locale, 'email_html_base.html')
# keep new lines in html emails
if 'comment' in context:
context['comment'] = mark_safe(context['comment'].replace('\r\n', '<br>'))

html_part = from_string(
"{%% extends '%s' %%}{%% block title %%}"
"%s"
"{%% endblock %%}{%% block content %%}%s{%% endblock %%}" %
(email_html_base_file, t.heading, t.html)
).render(context)

if isinstance(recipients, str):
if recipients.find(','):
recipients = recipients.split(',')
elif type(recipients) != list:
recipients = [recipients]

msg = EmailMultiAlternatives(subject_part, text_part,
sender or settings.DEFAULT_FROM_EMAIL,
recipients, bcc=bcc)
msg.attach_alternative(html_part, "text/html")

if files:
for filename, filefield in files:
mime = mimetypes.guess_type(filename)
if mime[0] is not None and mime[0] == "text/plain":
with open(filefield.path, 'r') as attachedfile:
content = attachedfile.read()
msg.attach(filename, content)
else:
if six.PY3:
msg.attach_file(filefield.path)
else:
with open(filefield.path, 'rb') as attachedfile:
content = attachedfile.read()
msg.attach(filename, content)

logger.debug('Sending email to: {!r}'.format(recipients))

try:
return msg.send()
except SMTPException as e:
logger.exception('SMTPException raised while sending email to {}'.format(recipients))
if not fail_silently:
raise e
return 0


def query_to_dict(results, descriptions):
"""
Replacement method for cursor.dictfetchall() as that method no longer
exists in psycopg2, and I'm guessing in other backends too.
Converts the results of a raw SQL query into a list of dictionaries, suitable
for use in templates etc.
"""

output = []
for data in results:
row = {}
i = 0
for column in descriptions:
row[column[0]] = data[i]
i += 1

output.append(row)
return output


def apply_query(queryset, params):
"""
Apply a dict-based set of filters & parameters to a queryset.
queryset is a Django queryset, eg MyModel.objects.all() or
MyModel.objects.filter(user=request.user)
params is a dictionary that contains the following:
filtering: A dict of Django ORM filters, eg:
{'user__id__in': [1, 3, 103], 'title__contains': 'foo'}
search_string: A freetext search string
sorting: The name of the column to sort by
"""
for key in params['filtering'].keys():
filter = {key: params['filtering'][key]}
queryset = queryset.filter(**filter)

search = params.get('search_string', None)
if search:
qset = (
Q(title__icontains=search) |
Q(description__icontains=search) |
Q(resolution__icontains=search) |
Q(submitter_email__icontains=search) |
Q(ticketcustomfieldvalue__value__icontains=search)
)

# Distinct works, when there are multiple custom fields
queryset = queryset.filter(qset).distinct()

sorting = params.get('sorting', None)
if sorting:
sortreverse = params.get('sortreverse', None)
if sortreverse:
sorting = "-%s" % sorting
queryset = queryset.order_by(sorting)

return queryset


def ticket_template_context(ticket):
context = {}

Expand Down

0 comments on commit f45a8b6

Please sign in to comment.