zulip/zerver/views/webhooks/trello/card_actions.py

212 lines
8.5 KiB
Python
Raw Normal View History

from typing import Dict, Tuple, Any, Optional, MutableMapping, Mapping, Text
from datetime import datetime
from .exceptions import UnknownUpdateCardAction
from .templates import TRELLO_SUBJECT_TEMPLATE, TRELLO_MESSAGE_TEMPLATE
SUPPORTED_CARD_ACTIONS = [
u'updateCard',
u'createCard',
u'addLabelToCard',
u'removeLabelFromCard',
u'addMemberToCard',
u'removeMemberFromCard',
u'addAttachmentToCard',
u'addChecklistToCard',
u'commentCard'
]
CREATE = u'createCard'
CHANGE_LIST = u'changeList'
CHANGE_NAME = u'changeName'
ARCHIVE = u'archiveCard'
REOPEN = u'reopenCard'
SET_DUE_DATE = u'setDueDate'
CHANGE_DUE_DATE = u'changeDueDate'
REMOVE_DUE_DATE = u'removeDueDate'
ADD_LABEL = u'addLabelToCard'
REMOVE_LABEL = u'removeLabelFromCard'
ADD_MEMBER = u'addMemberToCard'
REMOVE_MEMBER = u'removeMemberFromCard'
ADD_ATTACHMENT = u'addAttachmentToCard'
ADD_CHECKLIST = u'addChecklistToCard'
COMMENT = u'commentCard'
TRELLO_CARD_URL_TEMPLATE = u'[{card_name}]({card_url})'
ACTIONS_TO_MESSAGE_MAPPER = {
CREATE: u'created {card_url_template}',
CHANGE_LIST: u'moved {card_url_template} from {old_list} to {new_list}',
CHANGE_NAME: u'renamed the card from "{old_name}" to {card_url_template}',
ARCHIVE: u'archived {card_url_template}',
REOPEN: u'reopened {card_url_template}',
SET_DUE_DATE: u'set due date for {card_url_template} to {due_date}',
CHANGE_DUE_DATE: u'changed due date for {card_url_template} from {old_due_date} to {due_date}',
REMOVE_DUE_DATE: u'removed the due date from {card_url_template}',
ADD_LABEL: u'added a {color} label with \"{text}\" to {card_url_template}',
REMOVE_LABEL: u'removed a {color} label with \"{text}\" from {card_url_template}',
ADD_MEMBER: u'added {member_name} to {card_url_template}',
REMOVE_MEMBER: u'removed {member_name} from {card_url_template}',
ADD_ATTACHMENT: u'added [{attachment_name}]({attachment_url}) to {card_url_template}',
ADD_CHECKLIST: u'added the {checklist_name} checklist to {card_url_template}',
COMMENT: u'commented on {card_url_template}'
}
def process_card_action(payload, action_type):
# type: (Mapping[str, Any], Text) -> Tuple[Text, Text]
action_type = get_proper_action(payload, action_type)
return get_subject(payload), get_body(payload, action_type)
def get_proper_action(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
if action_type == 'updateCard':
data = get_action_data(payload)
if data.get('listBefore'):
return CHANGE_LIST
if data.get('old').get('name'):
return CHANGE_NAME
if data.get('old').get('due', False) is None:
return SET_DUE_DATE
if data.get('old').get('due'):
if data.get('card').get('due', False) is None:
return REMOVE_DUE_DATE
else:
return CHANGE_DUE_DATE
if data.get('old').get('closed') is False and data.get('card').get('closed'):
return ARCHIVE
if data.get('old').get('closed') and data.get('card').get('closed') is False:
return REOPEN
raise UnknownUpdateCardAction()
return action_type
def get_subject(payload):
# type: (Mapping[str, Any]) -> Text
data = {
'board_name': get_action_data(payload).get('board').get('name')
}
return TRELLO_SUBJECT_TEMPLATE.format(**data)
def get_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
message_body = ACTIONS_TO_FILL_BODY_MAPPER.get(action_type)(payload, action_type)
creator = payload.get('action').get('memberCreator').get('fullName')
return TRELLO_MESSAGE_TEMPLATE.format(full_name=creator, rest=message_body)
def get_added_checklist_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
data = {
'checklist_name': get_action_data(payload).get('checklist').get('name'),
}
return fill_appropriate_message_content(payload, action_type, data)
def get_added_attachment_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
data = {
'attachment_url': get_action_data(payload).get('attachment').get('url'),
'attachment_name': get_action_data(payload).get('attachment').get('name'),
}
return fill_appropriate_message_content(payload, action_type, data)
def get_updated_card_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
data = {
'card_name': get_card_name(payload),
'old_list': get_action_data(payload).get('listBefore').get('name'),
'new_list': get_action_data(payload).get('listAfter').get('name'),
}
return fill_appropriate_message_content(payload, action_type, data)
def get_renamed_card_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
data = {
'old_name': get_action_data(payload).get('old').get('name'),
'new_name': get_action_data(payload).get('card').get('name'),
}
return fill_appropriate_message_content(payload, action_type, data)
def get_added_label_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
data = {
'color': get_action_data(payload).get('value'),
'text': get_action_data(payload).get('text'),
}
return fill_appropriate_message_content(payload, action_type, data)
def get_managed_member_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
data = {
'member_name': payload.get('action').get('member').get('fullName')
}
return fill_appropriate_message_content(payload, action_type, data)
def get_managed_due_date_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
date_format = "%Y-%m-%dT%H:%M:%S.000Z"
display_date_format = '%m/%d/%Y %I:%M%p'
new_date = datetime.strptime(get_action_data(payload).get('card').get('due'), date_format)
data = {
'due_date': new_date.strftime(display_date_format),
}
return fill_appropriate_message_content(payload, action_type, data)
def get_changed_due_date_body(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
date_format = "%Y-%m-%dT%H:%M:%S.000Z"
display_date_format = '%m/%d/%Y %I:%M%p'
new_date = datetime.strptime(get_action_data(payload).get('card').get('due'), date_format)
old_date = datetime.strptime(get_action_data(payload).get('old').get('due'), date_format)
data = {
'due_date': new_date.strftime(display_date_format),
'old_due_date': old_date.strftime(display_date_format)
}
return fill_appropriate_message_content(payload, action_type, data)
def get_body_by_action_type_without_data(payload, action_type):
# type: (Mapping[str, Any], Text) -> Text
return fill_appropriate_message_content(payload, action_type)
def fill_appropriate_message_content(payload, action_type, data=None):
# type: (Mapping[str, Any], Text, Optional[Dict[str, Any]]) -> Text
data = {} if data is None else data
data['card_url_template'] = data.get('card_url_template', get_filled_card_url_template(payload))
message_body = get_message_body(action_type)
return message_body.format(**data)
def get_filled_card_url_template(payload):
# type: (Mapping[str, Any]) -> Text
return TRELLO_CARD_URL_TEMPLATE.format(card_name=get_card_name(payload), card_url=get_card_url(payload))
def get_card_url(payload):
# type: (Mapping[str, Any]) -> Text
return u'https://trello.com/c/{}'.format(get_action_data(payload).get('card').get('shortLink'))
def get_message_body(action_type):
# type: (Text) -> Text
return ACTIONS_TO_MESSAGE_MAPPER.get(action_type)
def get_card_name(payload):
# type: (Mapping[str, Any]) -> Text
return get_action_data(payload).get('card').get('name')
def get_action_data(payload):
# type: (Mapping[str, Any]) -> Mapping[str, Any]
return payload.get('action').get('data')
ACTIONS_TO_FILL_BODY_MAPPER = {
CREATE: get_body_by_action_type_without_data,
CHANGE_LIST: get_updated_card_body,
CHANGE_NAME: get_renamed_card_body,
ARCHIVE: get_body_by_action_type_without_data,
REOPEN: get_body_by_action_type_without_data,
SET_DUE_DATE: get_managed_due_date_body,
CHANGE_DUE_DATE: get_changed_due_date_body,
REMOVE_DUE_DATE: get_body_by_action_type_without_data,
ADD_LABEL: get_added_label_body,
REMOVE_LABEL: get_added_label_body,
ADD_MEMBER: get_managed_member_body,
REMOVE_MEMBER: get_managed_member_body,
ADD_ATTACHMENT: get_added_attachment_body,
ADD_CHECKLIST: get_added_checklist_body,
COMMENT: get_body_by_action_type_without_data,
}