Update.
This commit is contained in:
		
							parent
							
								
									f69586ccf7
								
							
						
					
					
						commit
						bca39a612c
					
				| @ -23,6 +23,7 @@ dependencies = [ | |||||||
|     "wkhtmltopdf", |     "wkhtmltopdf", | ||||||
|     "mistune", |     "mistune", | ||||||
|     "aiohttp-session", |     "aiohttp-session", | ||||||
|     "cryptography" |     "cryptography", | ||||||
|  |     "requests" | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ from snek.system import http | |||||||
| from snek.system.cache import Cache | from snek.system.cache import Cache | ||||||
| from snek.system.markdown import MarkdownExtension | from snek.system.markdown import MarkdownExtension | ||||||
| from snek.system.middleware import cors_middleware | from snek.system.middleware import cors_middleware | ||||||
|  | from snek.system.template import LinkifyExtension, PythonExtension | ||||||
| from snek.view.about import AboutHTMLView, AboutMDView | from snek.view.about import AboutHTMLView, AboutMDView | ||||||
| from snek.view.docs import DocsHTMLView, DocsMDView | from snek.view.docs import DocsHTMLView, DocsMDView | ||||||
| from snek.view.index import IndexView | from snek.view.index import IndexView | ||||||
| @ -51,6 +52,9 @@ class Application(BaseApplication): | |||||||
|         session_setup(self, EncryptedCookieStorage(SESSION_KEY)) |         session_setup(self, EncryptedCookieStorage(SESSION_KEY)) | ||||||
|         self._middlewares.append(session_middleware) |         self._middlewares.append(session_middleware) | ||||||
|         self.jinja2_env.add_extension(MarkdownExtension) |         self.jinja2_env.add_extension(MarkdownExtension) | ||||||
|  |         self.jinja2_env.add_extension(LinkifyExtension) | ||||||
|  |         self.jinja2_env.add_extension(PythonExtension) | ||||||
|  |          | ||||||
|         self.setup_router() |         self.setup_router() | ||||||
|         self.cache = Cache(self) |         self.cache = Cache(self) | ||||||
|         self.services = get_services(app=self) |         self.services = get_services(app=self) | ||||||
|  | |||||||
| @ -209,6 +209,11 @@ message-list { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .message { | .message { | ||||||
|  |   max-width: 100%; | ||||||
|  |   word-wrap: break-word; | ||||||
|  |   overflow-wrap: break-word; | ||||||
|  |   hyphens: auto; | ||||||
|  | 
 | ||||||
|   .avatar { |   .avatar { | ||||||
|       opacity: 0; |       opacity: 0; | ||||||
|   } |   } | ||||||
|  | |||||||
							
								
								
									
										99
									
								
								src/snek/system/template.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/snek/system/template.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,99 @@ | |||||||
|  | from types import SimpleNamespace | ||||||
|  | from bs4 import BeautifulSoup | ||||||
|  | import re  | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def set_link_target_blank(text): | ||||||
|  |     soup = BeautifulSoup(text, 'html.parser') | ||||||
|  | 
 | ||||||
|  |     for element in soup.find_all("a"):   | ||||||
|  |         element.attrs['target'] = '_blank' | ||||||
|  |         element.attrs['rel'] = 'noopener noreferrer' | ||||||
|  |         element.attrs['referrerpolicy'] = 'no-referrer' | ||||||
|  | 
 | ||||||
|  |     return str(soup) | ||||||
|  |      | ||||||
|  | 
 | ||||||
|  | def linkify_https(text): | ||||||
|  |     url_pattern = r'(?<!["\'])\bhttps://[^\s<>()]+' | ||||||
|  | 
 | ||||||
|  |     soup = BeautifulSoup(text, 'html.parser') | ||||||
|  | 
 | ||||||
|  |     for element in soup.find_all(text=True):   | ||||||
|  |         parent = element.parent | ||||||
|  |         if parent.name in ['a', 'script', 'style']:   | ||||||
|  |             continue | ||||||
|  |          | ||||||
|  |         new_text = re.sub(url_pattern, r'<a href="\g<0>">\g<0></a>', element) | ||||||
|  |         element.replace_with(BeautifulSoup(new_text, 'html.parser')) | ||||||
|  | 
 | ||||||
|  |     return set_link_target_blank(str(soup)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | from jinja2 import TemplateSyntaxError, nodes | ||||||
|  | from jinja2.ext import Extension | ||||||
|  | from jinja2.nodes import Const | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class LinkifyExtension(Extension): | ||||||
|  |     tags = {"linkify"} | ||||||
|  | 
 | ||||||
|  |     def __init__(self, environment): | ||||||
|  |         self.app = SimpleNamespace(jinja2_env=environment) | ||||||
|  |         super(LinkifyExtension, self).__init__(environment) | ||||||
|  | 
 | ||||||
|  |     def parse(self, parser): | ||||||
|  |         line_number = next(parser.stream).lineno | ||||||
|  |         md_file = [Const("")] | ||||||
|  |         body = "" | ||||||
|  |         try: | ||||||
|  |             md_file = [parser.parse_expression()] | ||||||
|  |         except TemplateSyntaxError: | ||||||
|  |             body = parser.parse_statements(["name:endlinkify"], drop_needle=True) | ||||||
|  |         return nodes.CallBlock( | ||||||
|  |             self.call_method("_to_html", md_file), [], [], body | ||||||
|  |         ).set_lineno(line_number) | ||||||
|  | 
 | ||||||
|  |     def _to_html(self, md_file, caller): | ||||||
|  |         return linkify_https(caller()) | ||||||
|  | 
 | ||||||
|  | class PythonExtension(Extension): | ||||||
|  |     tags = {"py3"} | ||||||
|  | 
 | ||||||
|  |     def parse(self, parser): | ||||||
|  |         line_number = next(parser.stream).lineno | ||||||
|  |         md_file = [Const("")] | ||||||
|  |         body = "" | ||||||
|  |         try: | ||||||
|  |             md_file = [parser.parse_expression()] | ||||||
|  |         except TemplateSyntaxError: | ||||||
|  |             body = parser.parse_statements(["name:endpy3"], drop_needle=True) | ||||||
|  |         return nodes.CallBlock( | ||||||
|  |             self.call_method("_to_html", md_file), [], [], body | ||||||
|  |         ).set_lineno(line_number) | ||||||
|  | 
 | ||||||
|  |     def _to_html(self, md_file, caller): | ||||||
|  |          | ||||||
|  |         def fn(source): | ||||||
|  |             import subprocess  | ||||||
|  |             import subprocess  | ||||||
|  |             import pathlib  | ||||||
|  |             from pathlib import Path  | ||||||
|  |             import os  | ||||||
|  |             import sys  | ||||||
|  |             import requests | ||||||
|  |             def system(command): | ||||||
|  |                 if isinstance(command): | ||||||
|  |                     command = command.split(" ") | ||||||
|  |                 from io import StringIO  | ||||||
|  |                 stdout = StringIO() | ||||||
|  |                 subprocess.run(command,stderr=stdout,stdout=stdout,text=True) | ||||||
|  |                 return stdout.getvalue() | ||||||
|  |             to_write = [] | ||||||
|  |             def render(text): | ||||||
|  |                 global to_write  | ||||||
|  |                 to_write.append(text) | ||||||
|  |             exec(source) | ||||||
|  |             return "".join(to_write) | ||||||
|  |         return str(fn(caller())) | ||||||
| @ -1,10 +1,14 @@ | |||||||
| <style> | <style> | ||||||
|     {{highlight_styles}} |     {{highlight_styles}} | ||||||
| </style> | </style> | ||||||
|  | 
 | ||||||
| {# | {# | ||||||
|     <div data-uid="{{uid}}" data-color="{{color}}" data-channel_uid="{{channel_uid}}" data-user_nick="{{user_nick}}" data-created_at="{{created_at}}" data-user_uid="{{user_uid}}" data-message="{{message}}" class="message"><div class="avatar" style="background-color: {{color}}; color: black;">{{user_nick[0]}}</div><div class="message-content"><div class="author" style="color: {{color}};">{{user_nick}}</div><div class="text"> |     <div style="max-width:100%;" data-uid="{{uid}}" data-color="{{color}}" data-channel_uid="{{channel_uid}}" data-user_nick="{{user_nick}}" data-created_at="{{created_at}}" data-user_uid="{{user_uid}}" data-message="{{message}}" class="message"><div class="avatar" style="background-color: {{color}}; color: black;">{{user_nick[0]}}</div><div class="message-content"><div class="author" style="color: {{color}};">{{user_nick}}</div><div class="text"> | ||||||
| #}   | #}   | ||||||
|         {% markdown %}{% autoescape false %}{{ message }}{%raw %} {% endraw%}{%endautoescape%}{% endmarkdown %} | {% linkify %} | ||||||
|  | 
 | ||||||
|  | {% markdown %}{% autoescape false %}{{ message }}{%raw %} {% endraw%}{%endautoescape%}{% endmarkdown %} | ||||||
|  | {% endlinkify %} | ||||||
| {# | {# | ||||||
|     </div><div class="time">{{created_at}}</div></div></div> |     </div><div class="time">{{created_at}}</div></div></div> | ||||||
| #} | #} | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user