def test_payin_pages_when_currencies_dont_match(self): self.add_payment_account(self.creator_1, 'stripe') self.add_payment_account(self.creator_2, 'paypal') self.add_payment_account(self.creator_3, 'stripe') self.add_payment_account(self.creator_3, 'paypal') self.donor.set_tip_to(self.creator_1, EUR('11.00')) self.donor.set_tip_to(self.creator_2, JPY('1100')) self.donor.set_tip_to(self.creator_3, USD('11.00')) paypal_path = '/donor/giving/pay/paypal/?beneficiary=%i,%i' % ( self.creator_2.id, self.creator_3.id ) stripe_path = '/donor/giving/pay/stripe/?beneficiary=%i,%i&method=card' % ( self.creator_1.id, self.creator_3.id ) r = self.client.GET('/donor/giving/pay/', auth_as=self.donor) assert r.code == 200, r.text assert str(Markup.escape(paypal_path)) not in r.text assert str(Markup.escape(stripe_path)) not in r.text r = self.client.GxT(paypal_path, auth_as=self.donor) assert r.code == 400, r.text r = self.client.GxT(stripe_path, auth_as=self.donor) assert r.code == 400, r.text
def render_and_scrub(markdown): """Given markdown, return a Markup with tags stripped and everything else escaped. """ u_right_to_left_override = "\u202E" right_to_left_override = "‮" replacements = (right_to_left_override, ''), (u_right_to_left_override, '') rtlo_gone = reduce(lambda a, kv: a.replace(*kv), replacements, markdown) return Markup.escape(render(rtlo_gone).striptags())
def test_02_payin_stripe_card_one_to_many(self): self.db.run("ALTER SEQUENCE payins_id_seq RESTART WITH 102") self.db.run("ALTER SEQUENCE payin_transfers_id_seq RESTART WITH 102") self.add_payment_account(self.creator_1, 'stripe', id=self.acct_switzerland.id) self.add_payment_account(self.creator_3, 'stripe') self.add_payment_account(self.creator_3, 'paypal') tip1 = self.donor.set_tip_to(self.creator_1, JPY('1250')) tip3 = self.donor.set_tip_to(self.creator_3, JPY('1250')) # 1st request: test getting the payment pages expected_uri = '/donor/giving/pay/stripe/?beneficiary=%i,%i&method=card' % ( self.creator_1.id, self.creator_3.id ) r = self.client.GET('/donor/giving/pay/', auth_as=self.donor) assert r.code == 200, r.text assert str(Markup.escape(expected_uri)) in r.text r = self.client.GET(expected_uri, auth_as=self.donor) assert r.code == 200, r.text # 2nd request: prepare the payment form_data = { 'amount': '10000', 'currency': 'JPY', 'tips': '%i,%i' % (tip1['id'], tip3['id']), 'token': 'tok_jp', } r = self.client.PxST('/donor/giving/pay/stripe', form_data, auth_as=self.donor) assert r.code == 200, r.text assert r.headers[b'Refresh'] == b'0;url=/donor/giving/pay/stripe/102' payin = self.db.one("SELECT * FROM payins") assert payin.status == 'pre' assert payin.amount == JPY('10000') payin_transfers = self.db.all("SELECT * FROM payin_transfers ORDER BY id") assert len(payin_transfers) == 2 pt1, pt2 = payin_transfers assert pt1.status == 'pre' assert pt1.amount == JPY('5000') assert pt2.status == 'pre' assert pt2.amount == JPY('5000') # 3rd request: execute the payment r = self.client.GET('/donor/giving/pay/stripe/102', auth_as=self.donor) assert r.code == 200, r.text payin = self.db.one("SELECT * FROM payins") assert payin.status == 'succeeded' assert payin.amount_settled == EUR('78.66') assert payin.fee == EUR('2.53') payin_transfers = self.db.all("SELECT * FROM payin_transfers ORDER BY id") assert len(payin_transfers) == 2 pt1, pt2 = payin_transfers assert pt1.status == 'succeeded' assert pt1.amount == EUR('38.07') assert pt1.remote_id assert pt2.status == 'succeeded' assert pt2.amount == EUR('38.06')
def __repr__(self): if self.object_table == 'microblog': obj = Microblog.query.get(self.object_id) pattern = u'<a href="%s">%s</a> 在微博 <a href="%s">%s</a> 中回复了你' return pattern % ( url_for('frontend.people', id=self.from_id), Markup.escape(self.from_people.nickname), url_for('mblog.comment', mid=self.object_id) if obj else '', Markup.escape(obj.content[:20]) if obj else u'抱歉,该微博已删除' ) elif self.object_table == 'comment': obj = Comment.query.get(self.object_id) pattern = u'<a href="%s">%s</a> 在评论 <a href="%s">%s</a> 中回复了你' return pattern % ( url_for('frontend.people', id=self.from_id), Markup.escape(self.from_people.nickname), url_for('mblog.comment', mid=obj.microblog_id, cid=self.object_id) if obj else '', Markup.escape(obj.parent_comment.content[:20]) if obj else u'抱歉,该评论已删除' ) elif self.object_table == 'photo': obj = Photo.query.get(self.object_id) pattern = u'<a href="%s">%s</a> 在照片 <a href="%s">%s</a> 中回复了你' return pattern % ( url_for('frontend.people', id=self.from_id), Markup.escape(self.from_people.nickname), url_for('photo.show_photo', pid=obj.id, aid=self.album_id) if obj else '', Markup.escape(obj.title[:20]) if obj else u'抱歉,该照片已删除' ) elif self.object_table == 'album': obj = PhotoAlbum.query.get(self.object_id) pattern = u'<a href="%s">%s</a> 在相册 <a href="%s">%s</a> 中回复了你' return pattern % ( url_for('frontend.people', id=self.from_id), Markup.escape(self.from_people.nickname), url_for('photo.show_album', id=obj.id) if obj else '', Markup.escape(obj.title[:20]) if obj else u'抱歉,该相册已删除' ) elif self.object_table == 'chatting': pattern = u'<a href="%s">%s</a> 给你发来了一条 <a href="%s">私信</a>' return pattern % ( url_for('frontend.people', id=self.from_id), Markup.escape(self.from_people.nickname), url_for('friendship.show_chatting_detail', box='inbox', id=self.object_id) ) elif self.object_table == 'friendship': pattern = u'<a href="%s">%s</a> 关注了你' return pattern % ( url_for('frontend.people', id=self.from_id), Markup.escape(self.from_people.nickname), )
def whitelist(value): """Whitelist specific HTML tags and strings. Positional arguments: value -- the string to perform the operation on. Returns: Markup() instance, indicating the string is safe. """ translations = { '&quot;': '"', '&#39;': ''', '&lsquo;': '‘', '&nbsp;': ' ', '<br>': '<br>', } escaped = str(Markup.escape(value)) # Escapes everything. for k, v in translations.items(): escaped = escaped.replace(k, v) # Un-escape specific elements using str.replace. return Markup(escaped) # Return as 'safe'.
def whitelist(value): """Whitelist specific HTML tags and strings. Positional arguments: value -- the string to perform the operation on. Returns: Markup() instance, indicating the string is safe. """ translations = { '&quot;': '"', '&#39;': ''', '&lsquo;': '‘', '&nbsp;': ' ', '<br>': '<br>', } escaped = str(Markup.escape(value)) # Escapes everything. for k, v in translations.items(): escaped = escaped.replace( k, v) # Un-escape specific elements using str.replace. return Markup(escaped) # Return as 'safe'.
def install(request): addon_id = request.GET.get('addon_id', None) if addon_id: try: addon_id = int(addon_id) except ValueError: addon_id = Markup.escape(addon_id) addon_key = request.GET.get('addon_key', None) addon_name = request.GET.get('addon_name', None) if addon_id in addons: addon = addons[addon_id] elif addon_key in addons: addon = addons[addon_key] elif addon_name and addon_id: xpi = 'https://addons.mozilla.org/en-US/firefox/downloads/latest/%s' % addon_id icon = 'https://addons.mozilla.org/en-US/firefox/images/addon_icon/%s' % addon_id addon = { 'name': addon_name, 'xpi': xpi, 'icon': icon } else: return HttpResponseNotFound() addon_link = addon.get('link', None) if addon_link: return HttpResponsePermanentRedirect(addon_link) if not 'xpi' in addon: return HttpResponseNotFound() src = request.GET.get('src', 'installservice') addon['xpi'] = urlparams(addon['xpi'], src=src) addon_params = {'URL': addon['xpi']} if 'icon' in addon: addon_params['IconURL'] = addon['icon'] if 'hash' in addon: addon_params['Hash'] = addon['hash'] referrers = ' || '.join(addon.get('referrers', default_referrers)) return jingo.render(request, 'services/install.html', {'referrers': referrers, 'params': json.dumps({'name': addon_params}), 'addon': addon})
def validated_table(output, items): output.write(""" <table> <tr> <th>Collection</th> <th>Sequence label</th> </tr> """) for r in items: try: output.write("<tr>") output.write( "<td><a href='https://workbench.lugli.arvadosapi.com/collections/%s'>%s</a></td>" % (r["uuid"], r["uuid"])) output.write("<td>%s</td>" % Markup.escape(r["properties"].get("sequence_label"))) output.write("</tr>") except: pass output.write(""" </table> """)
def pending_table(output, items): output.write(""" <table> <tr><th>Collection</th> <th>Sequence label</th></tr> """) for r in items: if r["status"] != "pending": continue try: output.write("<tr>") output.write( "<td><a href='https://workbench.lugli.arvadosapi.com/collections/%s'>%s</a></td>" % (r["uuid"], r["uuid"])) output.write("<td>%s</td>" % Markup.escape(r.get("sequence_label"))) output.write("</tr>") except: pass output.write(""" </table> """)
def install(request): addon_id = request.GET.get('addon_id', None) if addon_id: try: addon_id = int(addon_id) except ValueError: addon_id = Markup.escape(addon_id) addon_key = request.GET.get('addon_key', None) addon_name = request.GET.get('addon_name', None) if addon_id in addons: addon = addons[addon_id] elif addon_key in addons: addon = addons[addon_key] elif addon_name and addon_id: xpi = 'https://addons.mozilla.org/en-US/firefox/downloads/latest/%s' % addon_id icon = 'https://addons.mozilla.org/en-US/firefox/images/addon_icon/%s' % addon_id addon = {'name': addon_name, 'xpi': xpi, 'icon': icon} else: return HttpResponseNotFound() addon_link = addon.get('link', None) if addon_link: return HttpResponsePermanentRedirect(addon_link) if not 'xpi' in addon: return HttpResponseNotFound() src = request.GET.get('src', 'installservice') addon['xpi'] = urlparams(addon['xpi'], src=src) addon_params = {'URL': addon['xpi']} if 'icon' in addon: addon_params['IconURL'] = addon['icon'] if 'hash' in addon: addon_params['Hash'] = addon['hash'] referrers = ' || '.join(addon.get('referrers', default_referrers)) return jingo.render( request, 'services/install.html', { 'referrers': referrers, 'params': json.dumps({'name': addon_params}), 'addon': addon })
def __html__(self): ctx = get_ctx() # If we're in a nested render, we disable the rendering here or we # risk a recursion error. if ctx is None or self in ctx.flow_block_render_stack: return Markup.escape(repr(self)) ctx.flow_block_render_stack.append(self) try: try: return self.pad.db.env.render_template( ['blocks/%s.html' % self._data['_flowblock'], 'blocks/default.html'], pad=self.pad, this=self, alt=self.record.alt, values={'record': self.record} ) except TemplateNotFound: return Markup('[could not find snippet template]') finally: ctx.flow_block_render_stack.pop()
def __html__(self): ctx = get_ctx() # If we're in a nested render, we disable the rendering here or we # risk a recursion error. if ctx is None or self in ctx.flow_block_render_stack: return Markup.escape(repr(self)) ctx.flow_block_render_stack.append(self) try: try: record = find_record_for_flowblock(ctx, self) return self.pad.db.env.render_template( ["blocks/%s.html" % self._data["_flowblock"], "blocks/default.html"], pad=self.pad, this=self, alt=record and record.alt or None, values={"record": record}, ) except TemplateNotFound: return Markup("[could not find snippet template]") finally: ctx.flow_block_render_stack.pop()
def __html__(self): ctx = get_ctx() # If we're in a nested render, we disable the rendering here or we # risk a recursion error. if ctx is None or self in ctx.flow_block_render_stack: return Markup.escape(repr(self)) ctx.flow_block_render_stack.append(self) try: try: return self.pad.db.env.render_template( [ 'blocks/%s.html' % self._data['_flowblock'], 'blocks/default.html' ], pad=self.pad, this=self, alt=self.record.alt, values={'record': self.record}) except TemplateNotFound: return Markup('[could not find snippet template]') finally: ctx.flow_block_render_stack.pop()
def show_knowl_title(self, _external=False, rescheduled=False, blackout=False, preload=False, tz=None): if self.deleted or _external or preload: return r'<a title="{title}" knowl="dynamic_show" kwargs="{content}">{title}</a>'.format( title=self.show_title(), content=Markup.escape( render_template("talk-knowl.html", talk=self, _external=_external, tz=tz)), ) else: return r'<a title="{title}" knowl="talk/{seminar_id}/{talkid}" {style}>{title}</a>{rescheduled}'.format( title=self.show_title(), style='style="text-decoration: line-through;font-style: italic;"' if rescheduled else '', seminar_id=self.seminar_id, talkid=self.seminar_ctr, rescheduled=' (rescheduled)' if rescheduled else '', )
def get_questionary_html(quest_id): questionary = model.Questionary.query.get(_id=ObjectId(quest_id)) questionary_compiled = Template(questionary.document.html) output_values, qa_values = dict(), dict() for output_dict in questionary.document.content: _id = ObjectId(output_dict['content']) if output_dict['content'] in questionary.output_values and \ questionary.output_values[output_dict['content']]['evaluation']: output = model.Output.query.get(_id=_id) output_values['output_' + str(_id)] = output.render( questionary.output_values) else: # this clear useless output placeholder output_values['output_' + str(_id)] = '' questionary_compiled = questionary_compiled.safe_substitute( **output_values) questionary_compiled = Template(questionary_compiled) for qa_id, resp in questionary.qa_values.items(): qa_values['qa_' + qa_id] = Markup.escape(resp['qa_response']) return Markup(questionary_compiled.safe_substitute(**qa_values))
def test_03_payin_stripe_sdd_one_to_many(self): self.db.run("ALTER SEQUENCE payins_id_seq RESTART WITH 203") self.db.run("ALTER SEQUENCE payin_transfers_id_seq RESTART WITH 203") self.add_payment_account(self.creator_1, 'stripe', id=self.acct_switzerland.id) self.add_payment_account(self.creator_3, 'stripe') self.add_payment_account(self.creator_3, 'paypal') tip1 = self.donor.set_tip_to(self.creator_1, EUR('12.00')) tip3 = self.donor.set_tip_to(self.creator_3, EUR('12.00')) # 1st request: test getting the payment pages expected_uri = '/donor/giving/pay/stripe/?beneficiary=%i,%i&method=card' % ( self.creator_1.id, self.creator_3.id ) r = self.client.GET('/donor/giving/pay/', auth_as=self.donor) assert r.code == 200, r.text assert str(Markup.escape(expected_uri)) in r.text r = self.client.GET(expected_uri, auth_as=self.donor) assert r.code == 200, r.text # 2nd request: prepare the payment sepa_direct_debit_token = stripe.Token.create(bank_account=dict( country='FR', currency='EUR', account_number='FR1420041010050500013M02606', account_holder_name='Jane Doe', )) form_data = { 'amount': '100.00', 'currency': 'EUR', 'tips': '%i,%i' % (tip1['id'], tip3['id']), 'token': sepa_direct_debit_token.id, } r = self.client.PxST('/donor/giving/pay/stripe', form_data, auth_as=self.donor) assert r.code == 200, r.text assert r.headers[b'Refresh'] == b'0;url=/donor/giving/pay/stripe/203' payin = self.db.one("SELECT * FROM payins") assert payin.status == 'pre' assert payin.amount == EUR('100.00') payin_transfers = self.db.all("SELECT * FROM payin_transfers ORDER BY id") assert len(payin_transfers) == 2 pt1, pt2 = payin_transfers assert pt1.status == 'pre' assert pt1.amount == EUR('50.00') assert pt2.status == 'pre' assert pt2.amount == EUR('50.00') # 3rd request: execute the payment r = self.client.GET('/donor/giving/pay/stripe/203', auth_as=self.donor) assert r.code == 200, r.text payin = self.db.one("SELECT * FROM payins") assert payin.status == 'pending' assert payin.amount_settled is None assert payin.fee is None payin_transfers = self.db.all("SELECT * FROM payin_transfers ORDER BY id") assert len(payin_transfers) == 2 pt1, pt2 = payin_transfers assert pt1.status == 'pre' assert pt1.amount == EUR('50.00') assert pt1.remote_id is None assert pt2.status == 'pre' assert pt2.amount == EUR('50.00') assert pt2.remote_id is None
def test_05_payin_intent_stripe_card_one_to_many(self): self.db.run("ALTER SEQUENCE payins_id_seq RESTART WITH 105") self.db.run("ALTER SEQUENCE payin_transfers_id_seq RESTART WITH 105") self.add_payment_account(self.creator_1, 'stripe', id=self.acct_switzerland.id) self.add_payment_account(self.creator_3, 'stripe') self.add_payment_account(self.creator_3, 'paypal') tip1 = self.donor.set_tip_to(self.creator_1, EUR('12.50')) tip3 = self.donor.set_tip_to(self.creator_3, EUR('12.50')) # 1st request: test getting the payment pages expected_uri = '/donor/giving/pay/stripe/?beneficiary=%i,%i&method=card' % ( self.creator_1.id, self.creator_3.id) r = self.client.GET('/donor/giving/pay/', auth_as=self.donor) assert r.code == 200, r.text assert str(Markup.escape(expected_uri)) in r.text r = self.client.GET(expected_uri, auth_as=self.donor) assert r.code == 200, r.text # 2nd request: prepare the payment pm = stripe.PaymentMethod.create(type='card', card={'token': 'tok_visa'}) form_data = { 'amount': '100.00', 'currency': 'EUR', 'tips': '%i,%i' % (tip1['id'], tip3['id']), 'stripe_pm_id': pm.id, } r = self.client.PxST('/donor/giving/pay/stripe', form_data, auth_as=self.donor) assert r.code == 200, r.text assert r.headers[b'Refresh'] == b'0;url=/donor/giving/pay/stripe/105' payin = self.db.one("SELECT * FROM payins") assert payin.status == 'pre' assert payin.amount == EUR('100.00') payin_transfers = self.db.all( "SELECT * FROM payin_transfers ORDER BY id") assert len(payin_transfers) == 2 pt1, pt2 = payin_transfers assert pt1.status == 'pre' assert pt1.amount == EUR('50.00') assert pt2.status == 'pre' assert pt2.amount == EUR('50.00') # 3rd request: execute the payment r = self.client.GET('/donor/giving/pay/stripe/105', auth_as=self.donor) assert r.code == 200, r.text payin = self.db.one("SELECT * FROM payins") assert payin.status == 'succeeded' assert payin.amount_settled == EUR('100.00') assert payin.fee == EUR('3.15') payin_transfers = self.db.all( "SELECT * FROM payin_transfers ORDER BY id") assert len(payin_transfers) == 2 pt1, pt2 = payin_transfers assert pt1.status == 'succeeded' assert pt1.amount == EUR('48.43') assert pt1.remote_id assert pt2.status == 'succeeded' assert pt2.amount == EUR('48.42')
def redirect_link(short, text=None): text = Markup.escape(text if text else short.target) return Markup(f""" <a rel="nofollow" href="{short.target}">{text}</a> """.strip())
def __call__(self, field, **kwargs): html = super(CustomFileSelectWidget, self).__call__(field, **kwargs) file_format = self.file_format file_format_regex = '' if file_format and file_format == 'image': file_format_regex = '^image\/(gif|jpe?g|png|tif?f|tga)$' button = [u'<div class="form-upload-file">'] if field.data: api = system_util.pillar_api() try: # Load the existing file attached to the field file_item = File.find(field.data, api=api) except ResourceNotFound: pass else: filename = Markup.escape(file_item.filename) if file_item.content_type.split('/')[0] == 'image': # If a file of type image is available, display the preview button.append(u'<img class="preview-thumbnail" src="{0}" />'.format( file_item.thumbnail('s', api=api))) else: button.append(u'<p>{}</p>'.format(filename)) button.append(u'<ul class="form-upload-file-meta">') # File name button.append(u'<li class="name">{0}</li>'.format(filename)) # File size button.append(u'<li class="size">({0} MB)</li>'.format( round((file_item.length / 1024) * 0.001, 2))) # Image resolution (if image) button.append(u'<li class="dimensions">{0}x{1}</li>'.format( file_item.width, file_item.height)) # Delete button button.append(u'<li class="delete">' u'<a href="#" class="file_delete" ' u'data-field-name="{field_name}" ' u'data-file_id="{file_id}"> ' u'<i class="pi-trash"></i> Delete</a></li>'.format( field_name=field.name, file_id=field.data)) # Download button for original file button.append(u'<li class="original">' u'<a href="{}" class="file_original"> ' u'<i class="pi-download"></i>Original</a></li>' .format(file_item.link)) button.append(u'</ul>') upload_url = u'%s/storage/stream/{project_id}' % current_app.config[ 'PILLAR_SERVER_ENDPOINT'] button.append(u'<input class="fileupload" type="file" name="file" ' u'data-url="{url}" ' u'data-field-name="{name}" ' u'data-token="{token}" ' u'data-file-format="{file_format}">' u'<div class="form-upload-progress"> ' u'<div class="form-upload-progress-bar" role="progressbar" ' u'aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" ' u'style="width: 0%;"> ' u'</div> ' u'</div>'.format(url=upload_url, name=field.name, token=Markup.escape(current_user.id), file_format=Markup.escape(file_format_regex))) button.append(u'</div>') return HTMLString(html + u''.join(button))
def variants(institute_id, case_name): """Display a list of SNV variants.""" page = int(Markup.escape(request.form.get("page", "1"))) category = "snv" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) variant_type = request.args.get("variant_type", "clinical") variants_stats = store.case_variants_count(case_obj["_id"], institute_id, variant_type, False) if request.form.get("hpo_clinical_filter"): case_obj["hpo_clinical_filter"] = True user_obj = store.user(current_user.email) if request.method == "POST": if "dismiss_submit" in request.form: # dismiss a list of variants controllers.dismiss_variant_list( store, institute_obj, case_obj, "variant.variant", request.form.getlist("dismiss"), request.form.getlist("dismiss_choices"), ) form = controllers.populate_filters_form( store, institute_obj, case_obj, user_obj, category, request.form ) else: form = FiltersForm(request.args) # set form variant data type the first time around form.variant_type.data = variant_type # set chromosome to all chromosomes form.chrom.data = request.args.get("chrom", "") if form.gene_panels.data == [] and variant_type == "clinical": form.gene_panels.data = controllers.case_default_panels(case_obj) # populate filters dropdown available_filters = list(store.filters(institute_id, category)) form.filters.choices = [ (filter.get("_id"), filter.get("display_name")) for filter in available_filters ] # Populate chromosome select choices controllers.populate_chrom_choices(form, case_obj) # populate available panel choices form.gene_panels.choices = controllers.gene_panel_choices(store, institute_obj, case_obj) # update status of case if visited for the first time controllers.activate_case(store, institute_obj, case_obj, current_user) # upload gene panel if symbol file exists if request.files: file = request.files[form.symbol_file.name] if request.files and file and file.filename != "": LOG.debug("Upload file request files: {0}".format(request.files.to_dict())) try: stream = io.StringIO(file.stream.read().decode("utf-8"), newline=None) except UnicodeDecodeError as error: flash("Only text files are supported!", "warning") return redirect(request.referrer) hgnc_symbols_set = set(form.hgnc_symbols.data) LOG.debug("Symbols prior to upload: {0}".format(hgnc_symbols_set)) new_hgnc_symbols = controllers.upload_panel(store, institute_id, case_name, stream) hgnc_symbols_set.update(new_hgnc_symbols) form.hgnc_symbols.data = hgnc_symbols_set # reset gene panels form.gene_panels.data = "" controllers.update_form_hgnc_symbols(store, case_obj, form) cytobands = store.cytoband_by_chrom(case_obj.get("genome_build")) variants_query = store.variants(case_obj["_id"], query=form.data, category=category) result_size = store.count_variants(case_obj["_id"], form.data, None, category) if request.form.get("export"): return controllers.download_variants(store, case_obj, variants_query) data = controllers.variants( store, institute_obj, case_obj, variants_query, result_size, page, query_form=form.data ) expand_search = request.method == "POST" and request.form.get("expand_search") in [ "True", "", ] return dict( institute=institute_obj, case=case_obj, form=form, filters=available_filters, manual_rank_options=MANUAL_RANK_OPTIONS, dismiss_variant_options=DISMISS_VARIANT_OPTIONS, cancer_tier_options=CANCER_TIER_OPTIONS, severe_so_terms=SEVERE_SO_TERMS, cytobands=cytobands, page=page, expand_search=expand_search, result_size=result_size, total_variants=variants_stats.get(variant_type, {}).get(category, "NA"), **data, )
def nl2br(val): result = soft_unicode(Markup.escape(val)).replace("\n", Markup("<br />\n")) return Markup(result)
def test(): ts = TAINTED_STRING # class `Markup` can be used for things that are already safe. # if used with any text in a string operation, that other text will be escaped. # # see https://markupsafe.palletsprojects.com/en/2.0.x/ m_unsafe = Markup(TAINTED_STRING) m_safe = Markup(SAFE) # this 3 tests might look strange, but the purpose is to check we still treat `ts` # as tainted even after it has been escaped in some place. This _might_ not be the # case since data-flow library has taint-steps from adjacent uses... ensure_tainted(ts) # $ tainted ensure_not_tainted( escape(ts)) # $ escapeInput=ts escapeKind=html escapeOutput=escape(..) ensure_tainted(ts) # $ tainted ensure_tainted( ts, # $ tainted m_unsafe, # $ tainted m_unsafe + SAFE, # $ escapeInput=SAFE escapeKind=html escapeOutput=BinaryExpr MISSING: tainted SAFE + m_unsafe, # $ escapeInput=SAFE escapeKind=html escapeOutput=BinaryExpr MISSING: tainted m_unsafe.format( SAFE ), # $ escapeInput=SAFE escapeKind=html escapeOutput=m_unsafe.format(..) MISSING: tainted m_unsafe % SAFE, # $ escapeInput=SAFE escapeKind=html escapeOutput=BinaryExpr MISSING: tainted m_unsafe + ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr MISSING: tainted m_safe.format(m_unsafe), # $ tainted m_safe % m_unsafe, # $ tainted escape(ts).unescape( ), # $ escapeInput=ts escapeKind=html escapeOutput=escape(..) MISSING: tainted escape_silent(ts).unescape( ), # $ escapeInput=ts escapeKind=html escapeOutput=escape_silent(..) MISSING: tainted ) ensure_not_tainted( escape(ts), # $ escapeInput=ts escapeKind=html escapeOutput=escape(..) escape_silent( ts ), # $ escapeInput=ts escapeKind=html escapeOutput=escape_silent(..) Markup.escape( ts ), # $ escapeInput=ts escapeKind=html escapeOutput=Markup.escape(..) m_safe, m_safe + ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr ts + m_safe, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr m_safe.format( ts ), # $ escapeInput=ts escapeKind=html escapeOutput=m_safe.format(..) m_safe % ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr escape(ts) + ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr escapeOutput=escape(..) escape_silent(ts) + ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr escapeOutput=escape_silent(..) Markup.escape(ts) + ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr escapeOutput=Markup.escape(..) ) # flask re-exports these, as: # flask.escape = markupsafe.escape # flask.Markup = markupsafe.Markup import flask ensure_tainted( flask.Markup(ts), # $ tainted ) ensure_not_tainted( flask.escape( ts ), # $ escapeInput=ts escapeKind=html escapeOutput=flask.escape(..) flask.Markup.escape( ts ), # $ escapeInput=ts escapeKind=html escapeOutput=flask.Markup.escape(..) )
def sanitize_fragment(fragment, *, naucse_urls=None): if isinstance(fragment, str): return Markup.escape(fragment) else: sanitize_element(fragment, naucse_urls=naucse_urls) return Markup(lxml.etree.tounicode(fragment, method='html'))
def variant_update(institute_id, case_name, variant_id): """Update user-defined information about a variant: manual rank & ACMG.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) variant_obj = store.variant(variant_id) user_obj = store.user(current_user.email) link = request.referrer manual_rank = (Markup.escape(request.form.get("manual_rank")) if request.form.get("manual_rank") else None) cancer_tier = (Markup.escape(request.form.get("cancer_tier")) if request.form.get("cancer_tier") else None) if manual_rank: try: new_manual_rank = int(manual_rank) if manual_rank != "-1" else None except ValueError: LOG.warning( "Attempt to update manual rank with invalid value {}".format( manual_rank)) manual_rank = "-1" new_manual_rank = -1 store.update_manual_rank(institute_obj, case_obj, user_obj, link, variant_obj, new_manual_rank) if new_manual_rank: flash("updated variant tag: {}".format(new_manual_rank), "info") else: flash( "reset variant tag: {}".format( variant_obj.get("manual_rank", "NA")), "info", ) elif cancer_tier: try: new_cancer_tier = cancer_tier if cancer_tier != "-1" else None except ValueError: LOG.warning( "Attempt to update cancer tier with invalid value {}".format( cancer_tier)) cancer_tier = "-1" new_cancer_tier = "-1" store.update_cancer_tier(institute_obj, case_obj, user_obj, link, variant_obj, new_cancer_tier) if new_cancer_tier: flash("updated variant tag: {}".format(new_cancer_tier), "info") else: flash( "reset variant tag: {}".format( variant_obj.get("cancer_tier", "NA")), "info", ) elif request.form.get("acmg_classification"): new_acmg = request.form["acmg_classification"] acmg_classification = variant_obj.get("acmg_classification") # If there already is a classification and the same one is sent again this means that # We want to remove the classification if isinstance(acmg_classification, int) and (new_acmg == ACMG_MAP[acmg_classification]): new_acmg = None store.submit_evaluation( variant_obj=variant_obj, user_obj=user_obj, institute_obj=institute_obj, case_obj=case_obj, link=link, classification=new_acmg, ) flash("updated ACMG classification: {}".format(new_acmg), "info") new_dismiss = request.form.getlist("dismiss_variant") if new_dismiss: store.update_dismiss_variant(institute_obj, case_obj, user_obj, link, variant_obj, new_dismiss) flash("Dismissed variant: {}".format(new_dismiss), "info") variant_dismiss = variant_obj.get("dismiss_variant") if variant_dismiss and not new_dismiss: if "dismiss" in request.form: store.update_dismiss_variant(institute_obj, case_obj, user_obj, link, variant_obj, new_dismiss) flash( "Reset variant dismissal: {}".format( variant_obj.get("dismiss_variant")), "info", ) else: LOG.debug("DO NOT reset variant dismissal: {}".format( ",".join(variant_dismiss), "info")) mosaic_tags = request.form.getlist("mosaic_tags") if mosaic_tags: store.update_mosaic_tags(institute_obj, case_obj, user_obj, link, variant_obj, mosaic_tags) flash("Added mosaic tags: {}".format(mosaic_tags), "info") variant_mosaic = variant_obj.get("mosaic_tags") if variant_mosaic and not mosaic_tags: if "mosaic" in request.form: store.update_mosaic_tags(institute_obj, case_obj, user_obj, link, variant_obj, mosaic_tags) flash("Reset mosaic tags: {}".format(",".join(variant_mosaic), "info")) return redirect(request.referrer)
def review_decisions_formatter(view, context, model, name): output = '' authors = [] is_details = 'details' in context.name comments = getattr(model, 'review_decisions') last_commit_short_hash = model.last_commit_short_hash for comment in comments: if comment.author.login in authors: continue if comment.review_decision == ReviewDecision.CONCEPT_ACK: label = 'label-primary' elif comment.review_decision == ReviewDecision.TESTED_ACK: label = 'label-success' elif comment.review_decision == ReviewDecision.UNTESTED_ACK: label = 'label-warning' elif comment.review_decision == ReviewDecision.NACK: label = 'label-danger' else: continue is_stale = last_commit_short_hash and last_commit_short_hash not in comment.body if comment.review_decision == ReviewDecision.TESTED_ACK and is_stale: style = 'background-color: #2d672d;' elif comment.review_decision == ReviewDecision.UNTESTED_ACK and is_stale: style = 'background-color: #b06d0f' else: style = '' # Show comments in detail view only if is_details: outer_style = '' comment_markup = '<div style="color: #000000;"> {body}</div>'.format( body=comment.body) # Don't add <hr/> after the last comment if comments.index(comment) < len(comments) - 1: comment_markup += '<hr/>' else: outer_style = 'white-space: nowrap; overflow: hidden;' comment_markup = '' full_text = Markup.escape(comment.body) output += '<a target=blank href={comment_url} style="color: #FFFFFF; text-decoration: none;">' \ '<div style="{outer_style}">' \ '<img src="{avatar_url}" style="height:16px; border-radius: 50%;">' \ ' <span title="{full_text}" class="label {label}" style="{style}">{author_login}</span>' \ '{comment_markup}' \ '</div>' \ '</a>'.format(full_text=full_text, label=label, avatar_url=comment.author.avatar_url, author_login=comment.author.login, comment_url=comment.url, comment_markup=comment_markup, style=style, outer_style=outer_style) authors.append(comment.author.login) if len(authors) >= 4 and not is_details: output += '<div class="text-center">' \ '<small><em>Total: {reviews_count}</em></small>' \ '</div>'.format(reviews_count=len(authors)) return Markup(output)
def str_variants(institute_id, case_name): """Display a list of STR variants.""" page = int(Markup.escape(request.form.get("page", "1"))) variant_type = Markup.escape(request.args.get("variant_type", "clinical")) category = "str" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) variants_stats = store.case_variants_count(case_obj["_id"], institute_id, variant_type, False) user_obj = store.user(current_user.email) if request.method == "POST": form = controllers.populate_filters_form( store, institute_obj, case_obj, user_obj, category, request.form ) else: form = StrFiltersForm(request.args) if form.gene_panels.data == [] and variant_type == "clinical": form.gene_panels.data = controllers.case_default_panels(case_obj) # set form variant data type the first time around form.variant_type.data = variant_type # set chromosome to all chromosomes form.chrom.data = request.args.get("chrom", "") # populate filters dropdown available_filters = list(store.filters(institute_id, category)) form.filters.choices = [ (filter.get("_id"), filter.get("display_name")) for filter in available_filters ] # Populate chromosome select choices controllers.populate_chrom_choices(form, case_obj) # populate available panel choices form.gene_panels.choices = controllers.gene_panel_choices(store, institute_obj, case_obj) controllers.activate_case(store, institute_obj, case_obj, current_user) cytobands = store.cytoband_by_chrom(case_obj.get("genome_build")) query = form.data query["variant_type"] = variant_type variants_query = store.variants(case_obj["_id"], category=category, query=query).sort( [ ("str_repid", pymongo.ASCENDING), ("chromosome", pymongo.ASCENDING), ("position", pymongo.ASCENDING), ] ) result_size = store.count_variants(case_obj["_id"], query, None, category) if request.form.get("export"): return controllers.download_str_variants(case_obj, variants_query) data = controllers.str_variants( store, institute_obj, case_obj, variants_query, result_size, page ) return dict( institute=institute_obj, case=case_obj, dismiss_variant_options=DISMISS_VARIANT_OPTIONS, variant_type=variant_type, manual_rank_options=MANUAL_RANK_OPTIONS, cytobands=cytobands, form=form, page=page, filters=available_filters, expand_search=str(request.method == "POST"), result_size=result_size, total_variants=variants_stats.get(variant_type, {}).get(category, "NA"), **data, )
def cancer_variants(institute_id, case_name): """Show cancer variants overview.""" category = "cancer" variant_type = Markup.escape(request.args.get("variant_type", "clinical")) institute_obj, case_obj = institute_and_case(store, institute_id, case_name) variants_stats = store.case_variants_count(case_obj["_id"], institute_id, variant_type, False) user_obj = store.user(current_user.email) if request.method == "POST": if "dismiss_submit" in request.form: # dismiss a list of variants controllers.dismiss_variant_list( store, institute_obj, case_obj, "variant.variant", request.form.getlist("dismiss"), request.form.getlist("dismiss_choices"), ) form = controllers.populate_filters_form( store, institute_obj, case_obj, user_obj, category, request.form ) # if user is not loading an existing filter, check filter form if ( request.form.get("load_filter") is None and request.form.get("audit_filter") is None and form.validate_on_submit() is False ): # Flash a message with errors for field, err_list in form.errors.items(): for err in err_list: flash(f"Content of field '{field}' does not have a valid format", "warning") # And do not submit the form return redirect( url_for( ".cancer_variants", institute_id=institute_id, case_name=case_name, expand_search=True, ) ) page = int(Markup.escape(request.form.get("page", "1"))) else: page = int(Markup.escape(request.args.get("page", "1"))) form = CancerFiltersForm(request.args) # set chromosome to all chromosomes form.chrom.data = request.args.get("chrom", "") if form.gene_panels.data == []: form.gene_panels.data = controllers.case_default_panels(case_obj) # update status of case if visited for the first time controllers.activate_case(store, institute_obj, case_obj, current_user) # populate filters dropdown available_filters = list(store.filters(institute_id, category)) form.filters.choices = [ (filter.get("_id"), filter.get("display_name")) for filter in available_filters ] # Populate chromosome select choices controllers.populate_chrom_choices(form, case_obj) form.gene_panels.choices = controllers.gene_panel_choices(store, institute_obj, case_obj) genome_build = "38" if "38" in str(case_obj.get("genome_build")) else "37" cytobands = store.cytoband_by_chrom(genome_build) controllers.update_form_hgnc_symbols(store, case_obj, form) variants_query = store.variants( case_obj["_id"], category="cancer", query=form.data, build=genome_build ) result_size = store.count_variants(case_obj["_id"], form.data, None, category) if request.form.get("export"): return controllers.download_variants(store, case_obj, variants_query) data = controllers.cancer_variants( store, institute_id, case_name, variants_query, result_size, form, page=page, ) expand_search = request.method == "POST" and request.form.get("expand_search") in [ "True", "", ] return dict( variant_type=variant_type, cytobands=cytobands, filters=available_filters, dismiss_variant_options={ **DISMISS_VARIANT_OPTIONS, **CANCER_SPECIFIC_VARIANT_DISMISS_OPTIONS, }, expand_search=expand_search, result_size=result_size, total_variants=variants_stats.get(variant_type, {}).get(category, "NA"), **data, )
def opt_get_model_rest_api(model_id): """Retrieve model data """ model_id = Markup.escape(model_id) return retrieve_model_data(model_id)
from markupsafe import Markup, escape escape_code1 = escape('<script>alert(hello world!);</script>') print(escape_code1) print(escape_code1.unescape()) escape_code2 = Markup.escape('<script>alert(hello world!);</script>') print(escape_code2) print(escape_code2.unescape()) markup_code1 = Markup('<script>alert(hello world!);</script>') print(markup_code1) template = Markup("Hello <em>%s</em>") markup_code2 = template % '"World"' print(markup_code2) class Image: def __init__(self, url): self.url = url def __html__(self): return '<img src="%s">' % self.url img = Image('logo.png') img_code = Markup(img) print(img_code)
def show_knowl_title(self): return r'<a title="{title}" knowl="dynamic_show" kwargs="{content}">{title}</a>'.format( title=self.show_title(), content=Markup.escape(render_template("talk-knowl.html", talk=self)), )
def linebreaks(value): return re.sub('\r\n|\r|\n', Markup('<br />\n'), Markup.escape(value))
def __call__(self, field, **kwargs): html = super(CustomFileSelectWidget, self).__call__(field, **kwargs) file_format = self.file_format file_format_regex = '' if file_format and file_format == 'image': file_format_regex = '^image\/(gif|jpe?g|png|tif?f|tga)$' button = ['<div class="form-upload-file">'] if field.data: api = system_util.pillar_api() try: # Load the existing file attached to the field file_item = File.find(field.data, api=api) except ResourceNotFound: pass else: button.append('<div class="form-upload-file-meta-container">') filename = Markup.escape(file_item.filename) if file_item.content_type.split('/')[0] == 'image': # If a file of type image is available, display the preview button.append( '<img class="preview-thumbnail" src="{0}" />'.format( file_item.thumbnail('s', api=api))) button.append('<ul class="form-upload-file-meta">') # File name button.append('<li class="name">{0}</li>'.format(filename)) # File size button.append('<li class="size">({0} MB)</li>'.format( round((file_item.length / 1024) * 0.001, 2))) # Image resolution (if image) if file_item.content_type.split('/')[0] == 'image': button.append('<li class="dimensions">{0}x{1}</li>'.format( file_item.width, file_item.height)) button.append('</ul>') button.append('<ul class="form-upload-file-actions">') # Download button for original file button.append( '<li class="original">' '<a href="{}" class="file_original"> ' '<i class="pi-download"></i>Original</a></li>'.format( file_item.link)) # Delete button button.append( '<li class="delete">' '<a href="#" class="file_delete" ' 'data-field-name="{field_name}" ' 'data-file_id="{file_id}"> ' '<i class="pi-trash"></i> Delete</a></li>'.format( field_name=field.name, file_id=field.data)) button.append('</ul>') button.append('</div>') upload_url = '%sstorage/stream/{project_id}' % current_app.config[ 'PILLAR_SERVER_ENDPOINT'] button.append( '<input class="fileupload" type="file" name="file" ' 'data-url="{url}" ' 'data-field-name="{name}" ' 'data-field-slug="{slug}" ' 'data-token="{token}" ' 'data-file-format="{file_format}">' '<div class="form-upload-progress"> ' '<div class="form-upload-progress-bar" role="progressbar" ' 'aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" ' 'style="width: 0%;"> ' '</div> ' '</div>'.format(url=upload_url, name=field.name, slug=field.name.replace('oid', 'slug'), token=Markup.escape(current_user.id), file_format=Markup.escape(file_format_regex))) button.append('</div>') return HTMLString(html + ''.join(button))
def cancer_sv_variants(institute_id, case_name): """Display a list of cancer structural variants.""" page = int(Markup.escape(request.form.get("page", "1"))) variant_type = Markup.escape(request.args.get("variant_type", "clinical")) category = "cancer_sv" # Define case and institute objects institute_obj, case_obj = institute_and_case(store, institute_id, case_name) variants_stats = store.case_variants_count(case_obj["_id"], institute_id, variant_type, False) if request.form.get("hpo_clinical_filter"): case_obj["hpo_clinical_filter"] = True if request.form.getlist("dismiss"): # dismiss a list of variants controllers.dismiss_variant_list( store, institute_obj, case_obj, "variant.sv_variant", request.form.getlist("dismiss"), request.form.getlist("dismiss_choices"), ) # update status of case if visited for the first time controllers.activate_case(store, institute_obj, case_obj, current_user) form = controllers.populate_sv_filters_form(store, institute_obj, case_obj, category, request) # populate filters dropdown available_filters = list(store.filters(institute_obj["_id"], category)) form.filters.choices = [ (filter.get("_id"), filter.get("display_name")) for filter in available_filters ] # Populate chromosome select choices controllers.populate_chrom_choices(form, case_obj) genome_build = "38" if "38" in str(case_obj.get("genome_build")) else "37" cytobands = store.cytoband_by_chrom(genome_build) controllers.update_form_hgnc_symbols(store, case_obj, form) variants_query = store.variants(case_obj["_id"], category=category, query=form.data) result_size = store.count_variants(case_obj["_id"], form.data, None, category) # if variants should be exported if request.form.get("export"): return controllers.download_variants(store, case_obj, variants_query) data = controllers.sv_variants( store, institute_obj, case_obj, variants_query, result_size, page ) expand_search = request.method == "POST" and request.form.get("expand_search") in [ "True", "", ] return dict( institute=institute_obj, case=case_obj, dismiss_variant_options={ **DISMISS_VARIANT_OPTIONS, **CANCER_SPECIFIC_VARIANT_DISMISS_OPTIONS, }, variant_type=variant_type, form=form, filters=available_filters, severe_so_terms=SEVERE_SO_TERMS, cancer_tier_options=CANCER_TIER_OPTIONS, manual_rank_options=MANUAL_RANK_OPTIONS, cytobands=cytobands, page=page, expand_search=expand_search, result_size=result_size, total_variants=variants_stats.get(variant_type, {}).get(category, "NA"), **data, )
from markupsafe import Markup from flask import render_template from flask.app import Flask app = Flask(__name__) app.debug = True @app.route('/hello') @app.route('/hello/<name>') def hello(name=None): return render_template('hello.html', name=name) print(Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>') print(Markup.escape('<blink>hacker</blink>')) print(Markup('<em>Marked up</em> » HTML').striptags()) print(globals())
from markupsafe import Markup # inside template ?? mk = Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>' print(mk) #Markup(u'<strong>Hello <blink>hacker</blink>!</strong>') mk = Markup.escape('<blink>hacker</blink>') print(mk) #Markup(u'<blink>hacker</blink>') mk = Markup('<em>Marked up</em> » HTML').striptags() print(mk) #u'Marked up \xbb HTML'
def test_03_payin_stripe_sdd_one_to_many(self): self.db.run("ALTER SEQUENCE payins_id_seq RESTART WITH 203") self.db.run("ALTER SEQUENCE payin_transfers_id_seq RESTART WITH 203") self.add_payment_account(self.creator_1, 'stripe', id=self.acct_switzerland.id) self.add_payment_account(self.creator_3, 'stripe') self.add_payment_account(self.creator_3, 'paypal') tip1 = self.donor.set_tip_to(self.creator_1, EUR('12.00')) tip3 = self.donor.set_tip_to(self.creator_3, EUR('12.00')) # 1st request: test getting the payment pages expected_uri = '/donor/giving/pay/stripe/?beneficiary=%i,%i&method=card' % ( self.creator_1.id, self.creator_3.id) r = self.client.GET('/donor/giving/pay/', auth_as=self.donor) assert r.code == 200, r.text assert str(Markup.escape(expected_uri)) in r.text r = self.client.GET(expected_uri, auth_as=self.donor) assert r.code == 200, r.text # 2nd request: prepare the payment sepa_direct_debit_token = stripe.Token.create(bank_account=dict( country='FR', currency='EUR', account_number='FR1420041010050500013M02606', account_holder_name='Jane Doe', )) form_data = { 'amount': '100.00', 'currency': 'EUR', 'tips': '%i,%i' % (tip1['id'], tip3['id']), 'token': sepa_direct_debit_token.id, } r = self.client.PxST('/donor/giving/pay/stripe', form_data, auth_as=self.donor) assert r.code == 200, r.text assert r.headers[b'Refresh'] == b'0;url=/donor/giving/pay/stripe/203' payin = self.db.one("SELECT * FROM payins") assert payin.status == 'pre' assert payin.amount == EUR('100.00') payin_transfers = self.db.all( "SELECT * FROM payin_transfers ORDER BY id") assert len(payin_transfers) == 2 pt1, pt2 = payin_transfers assert pt1.status == 'pre' assert pt1.amount == EUR('50.00') assert pt2.status == 'pre' assert pt2.amount == EUR('50.00') # 3rd request: execute the payment r = self.client.GET('/donor/giving/pay/stripe/203', auth_as=self.donor) assert r.code == 200, r.text payin = self.db.one("SELECT * FROM payins") assert payin.status == 'pending' assert payin.amount_settled is None assert payin.fee is None payin_transfers = self.db.all( "SELECT * FROM payin_transfers ORDER BY id") assert len(payin_transfers) == 2 pt1, pt2 = payin_transfers assert pt1.status == 'pre' assert pt1.amount == EUR('50.00') assert pt1.remote_id is None assert pt2.status == 'pre' assert pt2.amount == EUR('50.00') assert pt2.remote_id is None
def to_dict(self) -> Dict: return { 'id': self.id, 'name': Markup.escape(self.name), 'added': self.added.isoformat() }
def show_knowl_embed(self, daterange, uniqstr='0'): return r'<a knowl="dynamic_show" kwargs="{content}">Embed this schedule</a>'.format( content=Markup.escape(render_template("seminar-embed-code-knowl.html", seminar=self, daterange=daterange, uniqstr=uniqstr)), )
def render_and_scrub(markdown): """Given markdown, return a Markup with tags stripped and everything else escaped. """ return Markup.escape(render(markdown).striptags())