mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	slack_incoming: Support "fields" in "section"s.
This is a best-effort rendering of the "fields" of Slack incoming hooks, which Slack renders in two columns. We approximate them in a Markdown table, with some minor in-place replacements. Fixes #22228.
This commit is contained in:
		
				
					committed by
					
						
						Tim Abbott
					
				
			
			
				
	
			
			
			
						parent
						
							4dc57dadd6
						
					
				
				
					commit
					1b692984ce
				
			@@ -74,6 +74,9 @@ Danny Torrence left the following *review* for your property:
 | 
			
		||||
[Overlook Hotel](https://google.com) \n :star: \n Doors had too many axe holes, guest in room 237 was far too rowdy, whole place felt stuck in the 1920s.
 | 
			
		||||
 | 
			
		||||
[Haunted hotel image](https://is5-ssl.mzstatic.com/image/thumb/Purple3/v4/d3/72/5c/d3725c8f-c642-5d69-1904-aa36e4297885/source/256x256bb.jpg)
 | 
			
		||||
 | 
			
		||||
**Average Rating**
 | 
			
		||||
1.0
 | 
			
		||||
""".strip()
 | 
			
		||||
 | 
			
		||||
        self.check_webhook(
 | 
			
		||||
@@ -90,6 +93,9 @@ Danny Torrence left the following review for your property:
 | 
			
		||||
[Overlook Hotel](https://example.com) \n :star: \n Doors had too many axe holes, guest in room 237 was far too rowdy, whole place felt stuck in the 1920s.
 | 
			
		||||
 | 
			
		||||
[Haunted hotel image](https://is5-ssl.mzstatic.com/image/thumb/Purple3/v4/d3/72/5c/d3725c8f-c642-5d69-1904-aa36e4297885/source/256x256bb.jpg)
 | 
			
		||||
 | 
			
		||||
**Average Rating**
 | 
			
		||||
1.0
 | 
			
		||||
""".strip()
 | 
			
		||||
 | 
			
		||||
        self.check_webhook(
 | 
			
		||||
@@ -175,6 +181,12 @@ This is a section block with an accessory image.
 | 
			
		||||
[cute cat](https://pbs.twimg.com/profile_images/625633822235693056/lNGUneLX_400x400.jpg)
 | 
			
		||||
 | 
			
		||||
This is a section block with a button.
 | 
			
		||||
 | 
			
		||||
| | |
 | 
			
		||||
|-|-|
 | 
			
		||||
| one | two |
 | 
			
		||||
| three | four |
 | 
			
		||||
| five |  |
 | 
			
		||||
        """.strip()
 | 
			
		||||
 | 
			
		||||
        self.check_webhook(
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
# Webhooks for external integrations.
 | 
			
		||||
import re
 | 
			
		||||
from itertools import zip_longest
 | 
			
		||||
from typing import Literal, Optional, TypedDict, cast
 | 
			
		||||
 | 
			
		||||
from django.http import HttpRequest, HttpResponse
 | 
			
		||||
@@ -14,6 +15,7 @@ from zerver.lib.validator import (
 | 
			
		||||
    WildValue,
 | 
			
		||||
    check_dict,
 | 
			
		||||
    check_int,
 | 
			
		||||
    check_list,
 | 
			
		||||
    check_string,
 | 
			
		||||
    check_string_in,
 | 
			
		||||
    check_url,
 | 
			
		||||
@@ -122,11 +124,26 @@ def render_block(block: WildValue) -> str:
 | 
			
		||||
            pieces.append(render_block_element(block["accessory"]))
 | 
			
		||||
 | 
			
		||||
        if "fields" in block:
 | 
			
		||||
            # TODO -- these should be rendered in two columns,
 | 
			
		||||
            # left-to-right.  We could render them sequentially,
 | 
			
		||||
            # except some may be Title1 / Title2 / value1 / value2,
 | 
			
		||||
            # which would be nonsensical when rendered sequentially.
 | 
			
		||||
            pass
 | 
			
		||||
            fields = block["fields"].tame(check_list(check_text_block()))
 | 
			
		||||
            if len(fields) == 1:
 | 
			
		||||
                # Special-case a single field to display a bit more
 | 
			
		||||
                # nicely, without extraneous borders and limitations
 | 
			
		||||
                # on its contents.
 | 
			
		||||
                pieces.append(fields[0]["text"])
 | 
			
		||||
            else:
 | 
			
		||||
                # It is not possible to have newlines in a table, nor
 | 
			
		||||
                # escape the pipes that make it up; replace them with
 | 
			
		||||
                # whitespace.
 | 
			
		||||
                field_text = [f["text"].replace("\n", " ").replace("|", " ") for f in fields]
 | 
			
		||||
                # Because Slack formats this as two columns, but not
 | 
			
		||||
                # necessarily a table with a bold header, we emit a
 | 
			
		||||
                # blank header row first.
 | 
			
		||||
                table = "| | |\n|-|-|\n"
 | 
			
		||||
                # Then take the fields two-at-a-time to make the table
 | 
			
		||||
                iters = [iter(field_text)] * 2
 | 
			
		||||
                for left, right in zip_longest(*iters, fillvalue=""):
 | 
			
		||||
                    table += f"| {left} | {right} |\n"
 | 
			
		||||
                pieces.append(table)
 | 
			
		||||
 | 
			
		||||
        return "\n\n".join(piece.strip() for piece in pieces if piece.strip() != "")
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user