mirror of https://github.com/zulip/zulip.git
freshdesk: Remove unsafe TicketDict class.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
cce142c61a
commit
6d1b68c61b
|
@ -1,5 +1,5 @@
|
||||||
"""Webhooks for external integrations."""
|
"""Webhooks for external integrations."""
|
||||||
from typing import Any, List
|
from typing import List
|
||||||
|
|
||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ from zerver.decorator import authenticated_rest_api_view
|
||||||
from zerver.lib.email_notifications import convert_html_to_markdown
|
from zerver.lib.email_notifications import convert_html_to_markdown
|
||||||
from zerver.lib.request import REQ, has_request_variables
|
from zerver.lib.request import REQ, has_request_variables
|
||||||
from zerver.lib.response import json_success
|
from zerver.lib.response import json_success
|
||||||
from zerver.lib.validator import WildValue, WildValueDict, check_string, to_wild_value
|
from zerver.lib.validator import WildValue, check_string, to_wild_value
|
||||||
from zerver.lib.webhooks.common import check_send_webhook_message
|
from zerver.lib.webhooks.common import check_send_webhook_message
|
||||||
from zerver.models import UserProfile
|
from zerver.models import UserProfile
|
||||||
|
|
||||||
|
@ -30,19 +30,6 @@ TICKET_CREATION_TEMPLATE = """
|
||||||
""".strip()
|
""".strip()
|
||||||
|
|
||||||
|
|
||||||
class TicketDict(WildValueDict):
|
|
||||||
"""
|
|
||||||
A helper class to turn a dictionary with ticket information into
|
|
||||||
an object where each of the keys is an attribute for easy access.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __getattr__(self, field: str) -> Any:
|
|
||||||
if "_" in field:
|
|
||||||
return self.get(field)
|
|
||||||
else:
|
|
||||||
return self.get("ticket_" + field)
|
|
||||||
|
|
||||||
|
|
||||||
def property_name(property: str, index: int) -> str:
|
def property_name(property: str, index: int) -> str:
|
||||||
"""The Freshdesk API is currently pretty broken: statuses are customizable
|
"""The Freshdesk API is currently pretty broken: statuses are customizable
|
||||||
but the API will only tell you the number associated with the status, not
|
but the API will only tell you the number associated with the status, not
|
||||||
|
@ -94,30 +81,30 @@ def parse_freshdesk_event(event_string: str) -> List[str]:
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def format_freshdesk_note_message(ticket: TicketDict, event_info: List[str]) -> str:
|
def format_freshdesk_note_message(ticket: WildValue, event_info: List[str]) -> str:
|
||||||
"""There are public (visible to customers) and private note types."""
|
"""There are public (visible to customers) and private note types."""
|
||||||
note_type = event_info[1]
|
note_type = event_info[1]
|
||||||
content = NOTE_TEMPLATE.format(
|
content = NOTE_TEMPLATE.format(
|
||||||
name=ticket.requester_name.tame(check_string),
|
name=ticket["requester_name"].tame(check_string),
|
||||||
email=ticket.requester_email.tame(check_string),
|
email=ticket["requester_email"].tame(check_string),
|
||||||
note_type=note_type,
|
note_type=note_type,
|
||||||
ticket_id=ticket.id.tame(check_string),
|
ticket_id=ticket["ticket_id"].tame(check_string),
|
||||||
ticket_url=ticket.url.tame(check_string),
|
ticket_url=ticket["ticket_url"].tame(check_string),
|
||||||
)
|
)
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
||||||
def format_freshdesk_property_change_message(ticket: TicketDict, event_info: List[str]) -> str:
|
def format_freshdesk_property_change_message(ticket: WildValue, event_info: List[str]) -> str:
|
||||||
"""Freshdesk will only tell us the first event to match our webhook
|
"""Freshdesk will only tell us the first event to match our webhook
|
||||||
configuration, so if we change multiple properties, we only get the before
|
configuration, so if we change multiple properties, we only get the before
|
||||||
and after data for the first one.
|
and after data for the first one.
|
||||||
"""
|
"""
|
||||||
content = PROPERTY_CHANGE_TEMPLATE.format(
|
content = PROPERTY_CHANGE_TEMPLATE.format(
|
||||||
name=ticket.requester_name.tame(check_string),
|
name=ticket["requester_name"].tame(check_string),
|
||||||
email=ticket.requester_email.tame(check_string),
|
email=ticket["requester_email"].tame(check_string),
|
||||||
ticket_id=ticket.id.tame(check_string),
|
ticket_id=ticket["ticket_id"].tame(check_string),
|
||||||
ticket_url=ticket.url.tame(check_string),
|
ticket_url=ticket["ticket_url"].tame(check_string),
|
||||||
property_name=event_info[0].capitalize(),
|
property_name=event_info[0].capitalize(),
|
||||||
old=event_info[1],
|
old=event_info[1],
|
||||||
new=event_info[2],
|
new=event_info[2],
|
||||||
|
@ -126,18 +113,18 @@ def format_freshdesk_property_change_message(ticket: TicketDict, event_info: Lis
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
||||||
def format_freshdesk_ticket_creation_message(ticket: TicketDict) -> str:
|
def format_freshdesk_ticket_creation_message(ticket: WildValue) -> str:
|
||||||
"""They send us the description as HTML."""
|
"""They send us the description as HTML."""
|
||||||
cleaned_description = convert_html_to_markdown(ticket.description.tame(check_string))
|
cleaned_description = convert_html_to_markdown(ticket["ticket_description"].tame(check_string))
|
||||||
content = TICKET_CREATION_TEMPLATE.format(
|
content = TICKET_CREATION_TEMPLATE.format(
|
||||||
name=ticket.requester_name.tame(check_string),
|
name=ticket["requester_name"].tame(check_string),
|
||||||
email=ticket.requester_email.tame(check_string),
|
email=ticket["requester_email"].tame(check_string),
|
||||||
ticket_id=ticket.id.tame(check_string),
|
ticket_id=ticket["ticket_id"].tame(check_string),
|
||||||
ticket_url=ticket.url.tame(check_string),
|
ticket_url=ticket["ticket_url"].tame(check_string),
|
||||||
description=cleaned_description,
|
description=cleaned_description,
|
||||||
type=ticket.type.tame(check_string),
|
type=ticket["ticket_type"].tame(check_string),
|
||||||
priority=ticket.priority.tame(check_string),
|
priority=ticket["ticket_priority"].tame(check_string),
|
||||||
status=ticket.status.tame(check_string),
|
status=ticket["ticket_status"].tame(check_string),
|
||||||
)
|
)
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
@ -150,12 +137,12 @@ def api_freshdesk_webhook(
|
||||||
user_profile: UserProfile,
|
user_profile: UserProfile,
|
||||||
payload: WildValue = REQ(argument_type="body", converter=to_wild_value),
|
payload: WildValue = REQ(argument_type="body", converter=to_wild_value),
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
ticket_data = payload["freshdesk_webhook"]
|
ticket = payload["freshdesk_webhook"]
|
||||||
|
|
||||||
ticket = TicketDict("freshdesk_webhook", ticket_data)
|
subject = (
|
||||||
|
f"#{ticket['ticket_id'].tame(check_string)}: {ticket['ticket_subject'].tame(check_string)}"
|
||||||
subject = f"#{ticket.id.tame(check_string)}: {ticket.subject.tame(check_string)}"
|
)
|
||||||
event_info = parse_freshdesk_event(ticket.triggered_event.tame(check_string))
|
event_info = parse_freshdesk_event(ticket["triggered_event"].tame(check_string))
|
||||||
|
|
||||||
if event_info[1] == "created":
|
if event_info[1] == "created":
|
||||||
content = format_freshdesk_ticket_creation_message(ticket)
|
content = format_freshdesk_ticket_creation_message(ticket)
|
||||||
|
|
Loading…
Reference in New Issue