I have the function which builds and return Slack message with text
and attachments
. How can I refactor this function to make it easier to test? Should I split it into multiple functions?
def build_list_message(team_id, user_id, msg_state=None, chl_state=None):
if not msg_state:
msg_state = {}
if not chl_state:
chl_state = {}
resource_type = msg_state.get('resource_type', 'all')
availability = msg_state.get('resource_availability', 'all')
pages = Page.objects.none()
async_tasks = AsyncTask.objects.none()
if resource_type in ['web_pages', 'all']:
pages = Page.objects.filter(
user__team__team_id=team_id).order_by('title')
if resource_type in ['async_tasks', 'all']:
async_tasks = AsyncTask.objects.filter(
user__team__team_id=team_id).order_by('title')
if availability == 'available':
pages = pages.filter(available=True)
async_tasks = async_tasks.filter(available=True)
elif availability == 'unavailable':
pages = pages.filter(available=False)
async_tasks = async_tasks.filter(available=False)
channel_id = chl_state.get('channel_id')
if channel_id:
pages = pages.filter(alert_channel=channel_id)
async_tasks = async_tasks.filter(alert_channel=channel_id)
user = SlackUser.retrieve(team_id, user_id)
attachments = [
_build_filters(resource_type, availability),
*[_build_page_item(p, user) for p in pages],
*[_build_async_task_item(at, user) for at in async_tasks]
]
return {
'text': "Here's the list of all monitoring resources",
'attachments': attachments
}
Here is private functions:
def _build_filters(resource_type, availability):
resource_types = [
{"text": "All types", "value": "all"},
{"text": ":link: Webpages", "value": "web_pages"}
]
availability_choices = [
{"text": "Available / Unavailable", "value": "all"},
{"text": ":white_circle: Available", "value": "available"},
{"text": ":red_circle: Unavaliable", "value": "unavailable"}
]
selected_resource_types = list(filter(
lambda t: t['value'] == resource_type, resource_types))
selected_availability_choices = list(filter(
lambda a: a['value'] == availability, availability_choices))
return {
"fallback": "Resource filters",
"color": "#d2dde1",
"mrkdwn_in": ["text"],
"callback_id": "resource_filters",
"actions": [
{
"name": "resource_type",
"text": "Type",
"type": "select",
"options": resource_types,
"selected_options": selected_resource_types
},
{
"name": "resource_availability",
"text": "Available",
"type": "select",
"options": availability_choices,
"selected_options": selected_availability_choices
}
]
}
def _build_page_item(page, user):
return {
"fallback": "Page",
"color": page.status_color,
"mrkdwn_in": ["fields"],
"callback_id": 'page_change',
"fields": [
{
"title": page.title,
"value": f"_Page_ ({page.status})"
},
{
"title": "URL",
"value": page.url
}
],
"footer": _build_resource_footer(page),
"actions": _build_resource_item_actions(page, user)
}
def _build_async_task_item(async_task, user):
return {
"fallback": "Async task",
"color": async_task.status_color,
"mrkdwn_in": ["fields"],
"callback_id": 'async_task_change',
"fields": [
{
"title": async_task.title,
"value": f"_Async task_ ({async_task.status})"
},
{
"title": "URL",
"value": async_task.url
}
],
"footer": _build_resource_footer(async_task),
"actions": _build_resource_item_actions(async_task, user)
}
Page
,AsyncTask
andSlackUser
are undefined. Are they from some module or die you write them yourself? \$\endgroup\$Page
,AsyncTask
andSlackUser
are simply Django models. \$\endgroup\$