html.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. """
  2. All the functions in this file should produce pure HTML, as
  3. opposed to Markdown or other similar languages.
  4. Some folks want to work with systems that don't necessarily
  5. support markdown (or deal with incompabilities between
  6. different flavors of markdown), so when possible, we should
  7. strive for pure HTML in our output in the future.
  8. (Producing pure HTML doesn't have to be a burden--we can
  9. add helpers/converters as necessary.)
  10. """
  11. import html
  12. from .date_helper import format_date1
  13. from .url import (
  14. sanitize_stream,
  15. sanitize,
  16. )
  17. from .url import (
  18. archive_message_url,
  19. archive_stream_url,
  20. archive_topic_url,
  21. zulip_post_url,
  22. )
  23. from .zulip_data import (
  24. num_topics_string,
  25. sorted_streams,
  26. sorted_topics,
  27. topic_info_string,
  28. )
  29. def topic_page_links_html(
  30. site_url,
  31. html_root,
  32. zulip_url,
  33. sanitized_stream_name,
  34. sanitized_topic_name,
  35. stream_name,
  36. topic_name,
  37. ):
  38. stream_url = archive_stream_url(site_url, html_root, sanitized_stream_name)
  39. topic_url = archive_topic_url(
  40. site_url, html_root, sanitized_stream_name, sanitized_topic_name
  41. )
  42. return f"""\
  43. <h2>Stream: <a href="{html.escape(stream_url)}">{html.escape(stream_name)}</a></h2>
  44. <h3>Topic: <a href="{html.escape(topic_url)}">{html.escape(topic_name)}</a></h3>
  45. <hr>
  46. <base href="{html.escape(zulip_url)}">
  47. """
  48. def format_message_html(
  49. site_url,
  50. html_root,
  51. zulip_url,
  52. zulip_icon_url,
  53. stream_name,
  54. stream_id,
  55. topic_name,
  56. msg,
  57. ):
  58. msg_id = str(msg["id"])
  59. zulip_link_html = link_to_zulip_html(
  60. zulip_url,
  61. zulip_icon_url,
  62. stream_id,
  63. stream_name,
  64. topic_name,
  65. msg_id,
  66. )
  67. user_name = msg["sender_full_name"]
  68. date = format_date1(msg["timestamp"])
  69. msg_content_html = msg["content"]
  70. anchor_url = archive_message_url(
  71. site_url,
  72. html_root,
  73. sanitize_stream(stream_name, stream_id),
  74. sanitize(topic_name),
  75. msg_id,
  76. )
  77. anchor_html = '<a name="{0}"></a>'.format(html.escape(msg_id))
  78. out_html = f"""
  79. {anchor_html}
  80. <h4>{zulip_link_html} {html.escape(user_name)} <a href="{html.escape(anchor_url)}">({html.escape(date)})</a>:</h4>
  81. {msg_content_html}
  82. """
  83. return out_html
  84. def link_to_zulip_html(
  85. zulip_url,
  86. zulip_icon_url,
  87. stream_id,
  88. stream_name,
  89. topic_name,
  90. msg_id,
  91. ):
  92. # format a link to the original post where you click on the Zulip icon
  93. # (if it's available)
  94. post_link = zulip_post_url(zulip_url, stream_id, stream_name, topic_name, msg_id)
  95. if zulip_icon_url:
  96. img_tag_html = f'<img src="{html.escape(zulip_icon_url)}" alt="view this post on Zulip" style="width:20px;height:20px;">'
  97. else:
  98. img_tag_html = ""
  99. zulip_link_html = (
  100. f'<a href="{html.escape(post_link)}" class="zl">{img_tag_html}</a>'
  101. )
  102. return zulip_link_html
  103. def last_updated_footer_html(stream_info):
  104. last_updated = format_date1(stream_info["time"])
  105. date_footer_html = f"\n<hr><p>Last updated: {html.escape(last_updated)} UTC</p>"
  106. return date_footer_html
  107. def stream_list_page_html(streams):
  108. content_html = f"""\
  109. <hr>
  110. <h2>Streams:</h2>
  111. {stream_list_html(streams)}
  112. """
  113. return content_html
  114. def stream_list_html(streams):
  115. """
  116. produce a list like this:
  117. * stream_name (n topics)
  118. * stream_name (n topics)
  119. * stream_name (n topics)
  120. """
  121. def item_html(stream_name, stream_data):
  122. stream_id = stream_data["id"]
  123. sanitized_name = sanitize_stream(stream_name, stream_id)
  124. url = f"stream/{sanitized_name}/index.html"
  125. stream_topic_data = stream_data["topic_data"]
  126. num_topics = num_topics_string(stream_topic_data)
  127. return f'<li> <a href="{html.escape(url)}">{html.escape(stream_name)}</a> ({html.escape(str(num_topics))}) </li>'
  128. the_list = "\n\n".join(
  129. item_html(stream_name, streams[stream_name])
  130. for stream_name in sorted_streams(streams)
  131. )
  132. return "<ul>\n" + the_list + "\n</ul>"
  133. def topic_list_page_html(stream_name, stream_url, topic_data):
  134. content = f"""\
  135. <h2> Stream: <a href="{html.escape(stream_url)}">{html.escape(stream_name)}</a></h2>
  136. <hr>
  137. <h3>Topics:</h3>
  138. {topic_list_html(topic_data)}
  139. """
  140. return content
  141. def topic_list_html(topic_data):
  142. """
  143. produce a list like this:
  144. * topic name (n messages, latest: <date>)
  145. * topic name (n messages, latest: <date>)
  146. * topic name (n messages, latest: <date>)
  147. """
  148. def item_html(topic_name, message_data):
  149. link_html = f'<a href="topic/{html.escape(sanitize(topic_name))}.html">{html.escape(topic_name)}</a>'
  150. topic_info = topic_info_string(message_data)
  151. return f"<li> {link_html} ({html.escape(topic_info)}) </li>"
  152. the_list_html = "\n".join(
  153. item_html(topic_name, topic_data[topic_name])
  154. for topic_name in sorted_topics(topic_data)
  155. )
  156. return "<ul>\n" + the_list_html + "\n</ul>"