From a6b83def8f8aa90d867ce1ccdf567006a641bf41 Mon Sep 17 00:00:00 2001 From: Marco Matarazzo Date: Tue, 4 Jul 2017 19:24:59 +0200 Subject: [PATCH] webhooks/trello: Support updating Card descriptions. We now support events that add, change or remove Trello Card descriptions. Minor fixes by eeshangarg. --- .../fixtures/adding_description_to_card.json | 96 ++++++++++++++++++ .../changing_description_on_card.json | 97 +++++++++++++++++++ .../removing_description_from_card.json | 97 +++++++++++++++++++ zerver/webhooks/trello/tests.py | 15 +++ zerver/webhooks/trello/view/card_actions.py | 32 +++++- 5 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 zerver/webhooks/trello/fixtures/adding_description_to_card.json create mode 100644 zerver/webhooks/trello/fixtures/changing_description_on_card.json create mode 100644 zerver/webhooks/trello/fixtures/removing_description_from_card.json diff --git a/zerver/webhooks/trello/fixtures/adding_description_to_card.json b/zerver/webhooks/trello/fixtures/adding_description_to_card.json new file mode 100644 index 0000000000..746b066230 --- /dev/null +++ b/zerver/webhooks/trello/fixtures/adding_description_to_card.json @@ -0,0 +1,96 @@ +{ + "model": { + "id": "55351ade1ed595cfa1bddf81", + "name": "Welcome Board", + "desc": "", + "descData": null, + "closed": false, + "idOrganization": null, + "pinned": false, + "url": "https://trello.com/b/BDlkcF4E/welcome-board", + "shortUrl": "https://trello.com/b/BDlkcF4E", + "prefs": { + "permissionLevel": "private", + "voting": "disabled", + "comments": "members", + "invitations": "members", + "selfJoin": true, + "cardCovers": true, + "calendarFeedEnabled": false, + "background": "blue", + "backgroundImage": null, + "backgroundImageScaled": null, + "backgroundTile": false, + "backgroundBrightness": "dark", + "backgroundColor": "#0079BF", + "canBePublic": true, + "canBeOrg": true, + "canBePrivate": true, + "canInvite": true + }, + "labelNames": { + "green": "", + "yellow": "", + "orange": "", + "red": "", + "purple": "", + "blue": "", + "sky": "", + "lime": "", + "pink": "", + "black": "" + } + }, + "action": { + "id": "595940d7ba919afcb0db1e8f", + "idMemberCreator": "55351ade1ed595cfa1bddf80", + "data": { + "list": { + "name": "List", + "id": "595940919403b0cd052718c6" + }, + "board": { + "shortLink": "BDlkcF4E", + "name": "Welcome Board", + "id": "55351ade1ed595cfa1bddf81" + }, + "card": { + "shortLink": "P2r0z66z", + "idShort": 8, + "name": "New Card", + "id": "595940ccdd7b429f714ac9f3", + "desc": "New Description" + }, + "old": { + "desc": "" + } + }, + "type": "updateCard", + "date": "2017-07-02T18:52:07.432Z", + "memberCreator": { + "id": "55351ade1ed595cfa1bddf80", + "avatarHash": "bcf3f3d2c214f269da2a483abc82524d", + "fullName": "Marco Matarazzo", + "initials": "MM", + "username": "marcomatarazzo1" + }, + "display": { + "translationKey": "action_changed_description_of_card", + "entities": { + "card": { + "type": "card", + "desc": "New Description", + "id": "595940ccdd7b429f714ac9f3", + "shortLink": "P2r0z66z", + "text": "New Card" + }, + "memberCreator": { + "type": "member", + "id": "55351ade1ed595cfa1bddf80", + "username": "marcomatarazzo1", + "text": "Marco Matarazzo" + } + } + } + } +} diff --git a/zerver/webhooks/trello/fixtures/changing_description_on_card.json b/zerver/webhooks/trello/fixtures/changing_description_on_card.json new file mode 100644 index 0000000000..92d8b4c2ac --- /dev/null +++ b/zerver/webhooks/trello/fixtures/changing_description_on_card.json @@ -0,0 +1,97 @@ +{ + "model": { + "id": "55351ade1ed595cfa1bddf81", + "name": "Welcome Board", + "desc": "", + "descData": null, + "closed": false, + "idOrganization": null, + "pinned": false, + "url": "https://trello.com/b/BDlkcF4E/welcome-board", + "shortUrl": "https://trello.com/b/BDlkcF4E", + "prefs": { + "permissionLevel": "private", + "voting": "disabled", + "comments": "members", + "invitations": "members", + "selfJoin": true, + "cardCovers": true, + "calendarFeedEnabled": false, + "background": "blue", + "backgroundImage": null, + "backgroundImageScaled": null, + "backgroundTile": false, + "backgroundBrightness": "dark", + "backgroundColor": "#0079BF", + "canBePublic": true, + "canBeOrg": true, + "canBePrivate": true, + "canInvite": true + }, + "labelNames": { + "green": "", + "yellow": "", + "orange": "", + "red": "", + "purple": "", + "blue": "", + "sky": "", + "lime": "", + "pink": "", + "black": "" + } + }, + "action": { + "id": "595940dd9907aab7445c3faa", + "idMemberCreator": "55351ade1ed595cfa1bddf80", + "data": { + "list": { + "name": "List", + "id": "595940919403b0cd052718c6" + }, + "board": { + "shortLink": "BDlkcF4E", + "name": "Welcome Board", + "id": "55351ade1ed595cfa1bddf81" + }, + "card": { + "shortLink": "P2r0z66z", + "idShort": 8, + "name": "New Card", + "id": "595940ccdd7b429f714ac9f3", + "desc": "Changed Description" + }, + "old": { + "desc": "New Description" + } + }, + "type": "updateCard", + "date": "2017-07-02T18:52:13.184Z", + "memberCreator": { + "id": "55351ade1ed595cfa1bddf80", + "avatarHash": "bcf3f3d2c214f269da2a483abc82524d", + "fullName": "Marco Matarazzo", + "initials": "MM", + "username": "marcomatarazzo1" + }, + "display": { + "translationKey": "action_changed_description_of_card", + "entities": { + "card": { + "type": "card", + "desc": "Changed Description", + "id": "595940ccdd7b429f714ac9f3", + "shortLink": "P2r0z66z", + "text": "New Card" + }, + "memberCreator": { + "type": "member", + "id": "55351ade1ed595cfa1bddf80", + "username": "marcomatarazzo1", + "text": "Marco Matarazzo" + } + } + } + } +} + diff --git a/zerver/webhooks/trello/fixtures/removing_description_from_card.json b/zerver/webhooks/trello/fixtures/removing_description_from_card.json new file mode 100644 index 0000000000..30f3c7d249 --- /dev/null +++ b/zerver/webhooks/trello/fixtures/removing_description_from_card.json @@ -0,0 +1,97 @@ +{ + "model": { + "id": "55351ade1ed595cfa1bddf81", + "name": "Welcome Board", + "desc": "", + "descData": null, + "closed": false, + "idOrganization": null, + "pinned": false, + "url": "https://trello.com/b/BDlkcF4E/welcome-board", + "shortUrl": "https://trello.com/b/BDlkcF4E", + "prefs": { + "permissionLevel": "private", + "voting": "disabled", + "comments": "members", + "invitations": "members", + "selfJoin": true, + "cardCovers": true, + "calendarFeedEnabled": false, + "background": "blue", + "backgroundImage": null, + "backgroundImageScaled": null, + "backgroundTile": false, + "backgroundBrightness": "dark", + "backgroundColor": "#0079BF", + "canBePublic": true, + "canBeOrg": true, + "canBePrivate": true, + "canInvite": true + }, + "labelNames": { + "green": "", + "yellow": "", + "orange": "", + "red": "", + "purple": "", + "blue": "", + "sky": "", + "lime": "", + "pink": "", + "black": "" + } + }, + "action": { + "id": "595940e3153c06dd27fc27a6", + "idMemberCreator": "55351ade1ed595cfa1bddf80", + "data": { + "list": { + "name": "List", + "id": "595940919403b0cd052718c6" + }, + "board": { + "shortLink": "BDlkcF4E", + "name": "Welcome Board", + "id": "55351ade1ed595cfa1bddf81" + }, + "card": { + "shortLink": "P2r0z66z", + "idShort": 8, + "name": "New Card", + "id": "595940ccdd7b429f714ac9f3", + "desc": "" + }, + "old": { + "desc": "Changed Description" + } + }, + "type": "updateCard", + "date": "2017-07-02T18:52:19.020Z", + "memberCreator": { + "id": "55351ade1ed595cfa1bddf80", + "avatarHash": "bcf3f3d2c214f269da2a483abc82524d", + "fullName": "Marco Matarazzo", + "initials": "MM", + "username": "marcomatarazzo1" + }, + "display": { + "translationKey": "action_changed_description_of_card", + "entities": { + "card": { + "type": "card", + "desc": "", + "id": "595940ccdd7b429f714ac9f3", + "shortLink": "P2r0z66z", + "text": "New Card" + }, + "memberCreator": { + "type": "member", + "id": "55351ade1ed595cfa1bddf80", + "username": "marcomatarazzo1", + "text": "Marco Matarazzo" + } + } + } + } +} + diff --git a/zerver/webhooks/trello/tests.py b/zerver/webhooks/trello/tests.py index 1b3e94a309..54c3946e59 100644 --- a/zerver/webhooks/trello/tests.py +++ b/zerver/webhooks/trello/tests.py @@ -124,3 +124,18 @@ class TrelloHookTests(WebhookTestCase): result = self.client_post(self.url, payload, content_type="application/json") self.assertFalse(check_send_message_mock.called) self.assert_json_success(result) + + def test_trello_webhook_when_description_was_added_to_card(self): + # type: () -> None + expected_message = u"Marco Matarazzo set description for [New Card](https://trello.com/c/P2r0z66z) to\n~~~ quote\nNew Description\n~~~." + self.send_and_test_stream_message('adding_description_to_card', u"Welcome Board.", expected_message) + + def test_trello_webhook_when_description_was_removed_from_card(self): + # type: () -> None + expected_message = u"Marco Matarazzo removed description from [New Card](https://trello.com/c/P2r0z66z)." + self.send_and_test_stream_message('removing_description_from_card', u"Welcome Board.", expected_message) + + def test_trello_webhook_when_description_was_changed_on_card(self): + # type: () -> None + expected_message = u"Marco Matarazzo changed description for [New Card](https://trello.com/c/P2r0z66z) from\n~~~ quote\nNew Description\nto\n~~~ quote\nChanged Description\n~~~." + self.send_and_test_stream_message('changing_description_on_card', u"Welcome Board.", expected_message) diff --git a/zerver/webhooks/trello/view/card_actions.py b/zerver/webhooks/trello/view/card_actions.py index 1034eb3798..38fe624760 100644 --- a/zerver/webhooks/trello/view/card_actions.py +++ b/zerver/webhooks/trello/view/card_actions.py @@ -18,6 +18,9 @@ SUPPORTED_CARD_ACTIONS = [ CREATE = u'createCard' CHANGE_LIST = u'changeList' CHANGE_NAME = u'changeName' +SET_DESC = u'setDesc' +CHANGE_DESC = u'changeDesc' +REMOVE_DESC = u'removeDesc' ARCHIVE = u'archiveCard' REOPEN = u'reopenCard' SET_DUE_DATE = u'setDueDate' @@ -37,6 +40,9 @@ 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}', + SET_DESC: u'set description for {card_url_template} to\n~~~ quote\n{desc}\n~~~\n', + CHANGE_DESC: u'changed description for {card_url_template} from\n~~~ quote\n{old_desc}\n~~~\nto\n~~~ quote\n{desc}\n~~~\n', + REMOVE_DESC: u'removed description from {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}', @@ -72,12 +78,18 @@ def get_proper_action(payload, action_type): return CHANGE_LIST if old_data.get('name'): return CHANGE_NAME + if old_data.get('desc') == "": + return SET_DESC + if old_data.get('desc'): + if card_data.get('desc') == "": + return REMOVE_DESC + else: + return CHANGE_DESC if old_data.get('due', False) is None: return SET_DUE_DATE if old_data.get('due'): if card_data.get('due', False) is None: return REMOVE_DUE_DATE - else: return CHANGE_DUE_DATE if old_data.get('closed') is False and card_data.get('closed'): @@ -175,6 +187,21 @@ def get_changed_due_date_body(payload, action_type): } return fill_appropriate_message_content(payload, action_type, data) +def get_managed_desc_body(payload, action_type): + # type: (Mapping[str, Any], Text) -> Text + data = { + 'desc': prettify_date(get_action_data(payload)['card']['desc']) + } + return fill_appropriate_message_content(payload, action_type, data) + +def get_changed_desc_body(payload, action_type): + # type: (Mapping[str, Any], Text) -> Text + data = { + 'desc': prettify_date(get_action_data(payload)['card']['desc']), + 'old_desc': prettify_date(get_action_data(payload)['old']['desc']) + } + 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) @@ -210,6 +237,9 @@ 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, + SET_DESC: get_managed_desc_body, + CHANGE_DESC: get_changed_desc_body, + REMOVE_DESC: get_body_by_action_type_without_data, ARCHIVE: get_body_by_action_type_without_data, REOPEN: get_body_by_action_type_without_data, SET_DUE_DATE: get_managed_due_date_body,