def integration_doc( request: HttpRequest, integration_name: str = REQ()) -> HttpResponse: # FIXME: This check is jQuery-specific. if request.headers.get("x-requested-with") != "XMLHttpRequest": return HttpResponseNotFound() try: integration = INTEGRATIONS[integration_name] except KeyError: return HttpResponseNotFound() context: Dict[str, Any] = {} add_api_uri_context(context, request) context["integration_name"] = integration.name context["integration_display_name"] = integration.display_name context["recommended_stream_name"] = integration.stream_name if isinstance(integration, WebhookIntegration): context["integration_url"] = integration.url[3:] if isinstance(integration, HubotIntegration): context["hubot_docs_url"] = integration.hubot_docs_url doc_html_str = render_markdown_path(integration.doc, context) return HttpResponse(doc_html_str)
def integration_doc(request: HttpRequest, integration_name: str = REQ()) -> HttpResponse: if not request.is_ajax(): return HttpResponseNotFound() try: integration = INTEGRATIONS[integration_name] except KeyError: return HttpResponseNotFound() context: Dict[str, Any] = {} add_api_uri_context(context, request) context["integration_name"] = integration.name context["integration_display_name"] = integration.display_name context["recommended_stream_name"] = integration.stream_name if isinstance(integration, WebhookIntegration): context["integration_url"] = integration.url[3:] if isinstance(integration, HubotIntegration): context["hubot_docs_url"] = integration.hubot_docs_url doc_html_str = render_markdown_path(integration.doc, context) return HttpResponse(doc_html_str)
def send_custom_email(users: List[UserProfile], options: Dict[str, Any]) -> None: """ Can be used directly with from a management shell with send_custom_email(user_profile_list, dict( markdown_template_path="/path/to/markdown/file.md", subject="Email subject", from_name="Sender Name") ) """ with open(options["markdown_template_path"]) as f: text = f.read() parsed_email_template = Parser(policy=default).parsestr(text) email_template_hash = hashlib.sha256(text.encode()).hexdigest()[0:32] email_filename = f"custom/custom_email_{email_template_hash}.source.html" email_id = f"zerver/emails/custom/custom_email_{email_template_hash}" markdown_email_base_template_path = "templates/zerver/emails/custom_email_base.pre.html" html_source_template_path = f"templates/{email_id}.source.html" plain_text_template_path = f"templates/{email_id}.txt" subject_path = f"templates/{email_id}.subject.txt" os.makedirs(os.path.dirname(html_source_template_path), exist_ok=True) # First, we render the Markdown input file just like our # user-facing docs with render_markdown_path. with open(plain_text_template_path, "w") as f: f.write(parsed_email_template.get_payload()) from zerver.lib.templates import render_markdown_path rendered_input = render_markdown_path( plain_text_template_path.replace("templates/", "")) # And then extend it with our standard email headers. with open(html_source_template_path, "w") as f: with open(markdown_email_base_template_path) as base_template: # Note that we're doing a hacky non-Jinja2 substitution here; # we do this because the normal render_markdown_path ordering # doesn't commute properly with inline_email_css. f.write(base_template.read().replace("{{ rendered_input }}", rendered_input)) with open(subject_path, "w") as f: f.write( get_header(options.get("subject"), parsed_email_template.get("subject"), "subject")) inline_template(email_filename) # Finally, we send the actual emails. for user_profile in users: if options.get("admins_only") and not user_profile.is_realm_admin: continue context = { "realm_uri": user_profile.realm.uri, "realm_name": user_profile.realm.name, "unsubscribe_link": one_click_unsubscribe_link(user_profile, "marketing"), } send_email( email_id, to_user_ids=[user_profile.id], from_address=FromAddress.SUPPORT, reply_to_email=options.get("reply_to"), from_name=get_header(options.get("from_name"), parsed_email_template.get("from"), "from_name"), context=context, dry_run=options["dry_run"], ) if options["dry_run"]: break