Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save refeed/fd50829315ddd1cebbcacdea1df097d5 to your computer and use it in GitHub Desktop.
Save refeed/fd50829315ddd1cebbcacdea1df097d5 to your computer and use it in GitHub Desktop.
zulip-archive proposal: Jinja2 templating as configuration

Zulip-archive proposal - Use jinja2 templating as config instead of telling the user to edit the internal code

The problem

  • Currently the way of how zulip-archive's users to change the looks of their website is to fork the project then change the internal library, especially lib/website.py
  • I think it would be better to give the responsibility of handling the rendering part to a more reliable and mature library (such as Jinja2) rather than managing the implementation ourselves as zulip-archive becoming a more complex project.

Proposed solution

  • Use templating library like jinja2 to handle how the page will render rather than rendering the pages with a bunch of outfile.write() in the code.
    • It is possible for 1 template to be used by many pages with the use of conditional tags in the template library
    • The core code then will run the render function providing all of the data needed (like topic name, chat, url, etc), how it is positioned and how it looks will all be the responsibility of the template file provided by the user (we can set a default template when the user didn't provide anything though)
  • A YAML configuration
    • The render data can also be customized through a yaml configuration
      • For example when a user wants the topic list in the stream to be sorted in ascending/descending order based on date/number of topic
    • User can specify a template path to use if they want to use another template than the default

Example template: Default template

<html>

# We can also make it modular
# Essentially we can use all of what Jinja2 provides
{% include 'header.jinja2' %}

<body>
# All of the data `page.type` `stream_name`, etc are provided by the renderer (e.g current `write_main_page()`)

{% if page.type == "index" %}
	{% include index.jinja2 %}
{% elif page.type == "stream" %}
	{% include stream.jinja2 %}
{% elif page.type == "topic" %}
	<h2>Stream: <a href="{{stream_url}}">{{stream_name}}</a></h2>
	
	<h3>Topic: <a href="{{topic_url}}">{{topic_name}}</a></h3>
	
	<hr>
	{% for chat_item in chats %}
		<a name="{{ chat_item.id }}"></a>
		
		<h4><a href="{{ chat_item.zulip_near_url }}" class="zl"><img src="{{ global_profile_image }}" alt="view this post on Zulip"></a> {{ chat_item.sender }} <a href="{{ chat_item.archive_url }}">({{ chat_item.sent_time }})</a>:</h4>
		
		{{ chat_item.message_rendered }}
	
	{% endfor %}
{% endif %}
	<hr><p>Last updated: {{last_updated_date}}</p>
</body>

</html>

Impact

  • Users can now just edit the jinja2 template that's used to render the html and submit the template to the software as configuration instead of editing the internal code
  • This will make it easier for the users to upgrade zulip-archive from upstream because they won't have to fork the project
  • We can finally distribute the binary (and the lib) through pip or host it in docker container but still have the convenience of configurability to the users
  • Developer can develop the template easier because the rendered page is guaranteed to be similar to the template

Implementation strategy

Milestone 1: Refactor lib/website.py to render using Jinja2 template

  • Mainly modifying the implementation of write_main_page, write_stream_topics, write_topic_messages in lib/website.py from using for loops and outfile.write() to just pass the data to Jinja2 renderer
    • All of the data must be html-escaped to prevent injection
  • Creating a default template with the CSS.
    • I think it will be much easier to develop because the rendered page's html will be similar to the jinja2 template

Milestone 2: Make the Jinja2 template configurable by users

  • Document what data that can be used in the Jinja2 template
  • Document how user can modify the template and inputting it to zulip-archive
  • Make the design on how it will be configurable
    • I'm currently thinking the user can place a directory like /.zarchive_config that contains:
      • template/
        • main.jinja2
        • // other jinja2 files provided that's needed by main.jinja2, but the main template that will be rendered is main.jinja2
        • assets/
          • contains js, css, and images
      • config.yaml
        • I chose yaml because we can give comments in it
        • It contains the all of the config from streams.yaml and all config from settings.py (except the html configs like page_footer_html because it is the responsibility of the jinja2 template now)
    • Then we can specify the config directory as parameter like archive.py -c ~/.zarchive_config

Related links

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment