# Copyright 2016 OpenMarket Ltd # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Contains all the sections for the spec.""" from batesian import AccessKeyStore from batesian.sections import Sections import inspect import json import os import logging import re logger = logging.getLogger(__name__) class MatrixSections(Sections): # pass through git ver so it'll be dropped in the input file def render_git_version(self): return self.units.get("git_version")["string"] def render_git_rev(self): return self.units.get("git_version")["revision"] def render_changelogs(self): rendered = {} changelogs = self.units.get("changelogs") for spec, changelog_text in changelogs.items(): spec_var = "%s_changelog" % spec logger.info("Rendering changelog for spec: %s" % spec) rendered[spec_var] = changelog_text return rendered def _render_events(self, filterFn, sortFn): template = self.env.get_template("events.tmpl") examples = self.units.get("event_examples") schemas = self.units.get("event_schemas") subtitle_title_char = self.units.get("spec_targets")[ "relative_title_styles" ]["subtitle"] sections = [] for event_name in sortFn(schemas): if not filterFn(event_name): continue sections.append(template.render( examples=examples[event_name], event=schemas[event_name], title_kind=subtitle_title_char )) return "\n\n".join(sections) def _render_http_api_group(self, group, sortPathList=None): template = self.env.get_template("http-api.tmpl") http_api = self.units.get("swagger_apis")[group]["__meta"] subtitle_title_char = self.units.get("spec_targets")[ "relative_title_styles" ]["subtitle"] sections = [] endpoints = [] if sortPathList: # list of substrings to sort by sorted_endpoints = [] for path_substr in sortPathList: for e in http_api["endpoints"]: if path_substr in e["path"]: sorted_endpoints.append(e) # could have multiple # dump rest rest = [ e for e in http_api["endpoints"] if e not in sorted_endpoints ] endpoints = sorted_endpoints + rest else: # sort alphabetically based on path endpoints = http_api["endpoints"] for endpoint in endpoints: sections.append(template.render( endpoint=endpoint, title_kind=subtitle_title_char )) return "\n\n".join(sections) # Special function: Returning a dict will specify multiple sections where # the key is the section name and the value is the value of the section def render_group_http_apis(self): # map all swagger_apis to the form $GROUP_http_api swagger_groups = self.units.get("swagger_apis").keys() renders = {} for group in swagger_groups: sortFnOrPathList = None if group == "presence_cs": sortFnOrPathList = ["status"] elif group == "profile_cs": sortFnOrPathList=["displayname", "avatar_url"] renders[group + "_http_api"] = self._render_http_api_group( group, sortFnOrPathList ) return renders # Special function: Returning a dict will specify multiple sections where # the key is the section name and the value is the value of the section def render_group_events(self): # map all event schemata to the form $EVENTTYPE_event with s/.#/_/g # e.g. m_room_topic_event or m_room_message_m_text_event schemas = self.units.get("event_schemas") renders = {} for event_type in schemas: underscored_event_type = event_type.replace(".", "_").replace("$", "_") renders[underscored_event_type + "_event"] = self._render_events( lambda x: x == event_type, sorted ) return renders def render_room_events(self): def filterFn(eventType): return ( eventType.startswith("m.room") and not eventType.startswith("m.room.message$m.") ) return self._render_events(filterFn, sorted) def render_msgtype_events(self): template = self.env.get_template("msgtypes.tmpl") examples = self.units.get("event_examples") schemas = self.units.get("event_schemas") subtitle_title_char = self.units.get("spec_targets")[ "relative_title_styles" ]["subtitle"] sections = [] msgtype_order = [ "m.room.message$m.text", "m.room.message$m.emote", "m.room.message$m.notice", "m.room.message$m.image", "m.room.message$m.file" ] excluded_types = [ # We exclude server notices from here because we handle them in a # dedicated module. We do not want to confuse developers this early # in the spec. "m.room.message$m.server_notice", ] other_msgtypes = [ k for k in schemas.keys() if k.startswith("m.room.message$") and k not in msgtype_order and k not in excluded_types ] for event_name in (msgtype_order + other_msgtypes): if not event_name.startswith("m.room.message$m."): continue sections.append(template.render( example=examples[event_name][0], event=schemas[event_name], title_kind=subtitle_title_char )) return "\n\n".join(sections) def render_voip_events(self): def filterFn(eventType): return eventType.startswith("m.call") def sortFn(eventTypes): ordering = [ "m.call.invite", "m.call.candidates", "m.call.answer", "m.call.hangup" ] rest = [ k for k in eventTypes if k not in ordering ] return ordering + rest return self._render_events(filterFn, sortFn) def render_presence_events(self): def filterFn(eventType): return eventType.startswith("m.presence") return self._render_events(filterFn, sorted) def _render_ce_type(self, type): template = self.env.get_template("common-event-fields.tmpl") ce_types = self.units.get("common_event_fields") subtitle_title_char = self.units.get("spec_targets")[ "relative_title_styles" ]["subtitle"] return template.render( common_event=ce_types[type], title_kind=subtitle_title_char ) def render_common_event_fields(self): return self._render_ce_type("event") def render_common_room_event_fields(self): return self._render_ce_type("room_event") def render_common_state_event_fields(self): return self._render_ce_type("state_event") def render_apis(self): template = self.env.get_template("apis.tmpl") apis = self.units.get("apis") return template.render(apis=apis) def render_unstable_warnings(self): rendered = {} blocks = self.units.get("unstable_warnings") for var, text in blocks.items(): rendered["unstable_warning_block_" + var] = text return rendered def render_swagger_definition(self): rendered = {} template = self.env.get_template("schema-definition.tmpl") subtitle_title_char = self.units.get("spec_targets")[ "relative_title_styles" ]["subtitle"] definitions = self.units.get("swagger_definitions") for group, swagger_def in definitions.items(): rendered["definition_" + group] = template.render( definition=swagger_def['definition'], examples=swagger_def['examples'], title_kind=subtitle_title_char) return rendered def render_sas_emoji_table(self): emoji = self.units.get("sas_emoji") rendered = ".. csv-table::\n" rendered += " :header: \"Number\", \"Emoji\", \"Unicode\", \"Description\"\n" rendered += " :widths: 10, 10, 15, 20\n" rendered += "\n" for row in emoji: rendered += " %d, \"%s\", \"``%s``\", \"%s\"\n" % ( row['number'], row['emoji'], row['unicode'], row['description'], ) rendered += "\n" return rendered