mirror of https://gitlab.com/bashrc2/epicyon
Merge branch 'main' of gitlab.com:bashrc2/epicyon
commit
aead5d2cf9
2
blog.py
2
blog.py
|
@ -313,7 +313,7 @@ def _html_blog_post_content(debug: bool, session, authorized: bool,
|
|||
if citations_str:
|
||||
citations_str = '<p><b>' + translate['Citations'] + \
|
||||
':</b></p>' + \
|
||||
'<ul>\n' + citations_str + '</ul>\n'
|
||||
'<u>\n' + citations_str + '</u>\n'
|
||||
|
||||
blog_str += '<br>\n' + citations_str
|
||||
|
||||
|
|
110
daemon.py
110
daemon.py
|
@ -174,6 +174,7 @@ from webapp_utils import get_pwa_theme_colors
|
|||
from webapp_calendar import html_calendar_delete_confirm
|
||||
from webapp_calendar import html_calendar
|
||||
from webapp_about import html_about
|
||||
from webapp_specification import html_specification
|
||||
from webapp_accesskeys import html_access_keys
|
||||
from webapp_accesskeys import load_access_keys_for_accounts
|
||||
from webapp_confirm import html_confirm_delete
|
||||
|
@ -4782,6 +4783,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
links_filename = base_dir + '/accounts/links.txt'
|
||||
about_filename = base_dir + '/accounts/about.md'
|
||||
tos_filename = base_dir + '/accounts/tos.md'
|
||||
specification_filename = base_dir + '/accounts/activitypub.md'
|
||||
|
||||
# extract all of the text fields into a dict
|
||||
fields = \
|
||||
|
@ -4860,6 +4862,23 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
print('EX: _links_update unable to delete ' +
|
||||
tos_filename)
|
||||
|
||||
if fields.get('editedSpecification'):
|
||||
specification_str = fields['editedSpecification']
|
||||
try:
|
||||
with open(specification_filename, 'w+',
|
||||
encoding='utf-8') as specificationfile:
|
||||
specificationfile.write(specification_str)
|
||||
except OSError:
|
||||
print('EX: unable to write specification ' +
|
||||
specification_filename)
|
||||
else:
|
||||
if os.path.isfile(specification_filename):
|
||||
try:
|
||||
os.remove(specification_filename)
|
||||
except OSError:
|
||||
print('EX: _links_update unable to delete ' +
|
||||
specification_filename)
|
||||
|
||||
# redirect back to the default timeline
|
||||
self._redirect_headers(actor_str + '/' + default_timeline,
|
||||
cookie, calling_domain)
|
||||
|
@ -8212,6 +8231,56 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
return
|
||||
self._404()
|
||||
|
||||
def _show_specification_image(self, path: str,
|
||||
base_dir: str, getreq_start_time) -> None:
|
||||
"""Shows an image within the ActivityPub specification document
|
||||
"""
|
||||
image_filename = path.split('/', 1)[1]
|
||||
if '/' in image_filename:
|
||||
self._404()
|
||||
return
|
||||
media_filename = \
|
||||
base_dir + '/specification/' + image_filename
|
||||
if self._etag_exists(media_filename):
|
||||
# The file has not changed
|
||||
self._304()
|
||||
return
|
||||
if self.server.iconsCache.get(media_filename):
|
||||
media_binary = self.server.iconsCache[media_filename]
|
||||
mime_type_str = media_file_mime_type(media_filename)
|
||||
self._set_headers_etag(media_filename,
|
||||
mime_type_str,
|
||||
media_binary, None,
|
||||
self.server.domain_full,
|
||||
False, None)
|
||||
self._write(media_binary)
|
||||
fitness_performance(getreq_start_time, self.server.fitness,
|
||||
'_GET', '_show_specification_image',
|
||||
self.server.debug)
|
||||
return
|
||||
if os.path.isfile(media_filename):
|
||||
media_binary = None
|
||||
try:
|
||||
with open(media_filename, 'rb') as av_file:
|
||||
media_binary = av_file.read()
|
||||
except OSError:
|
||||
print('EX: unable to read specification image ' +
|
||||
media_filename)
|
||||
if media_binary:
|
||||
mime_type = media_file_mime_type(media_filename)
|
||||
self._set_headers_etag(media_filename,
|
||||
mime_type,
|
||||
media_binary, None,
|
||||
self.server.domain_full,
|
||||
False, None)
|
||||
self._write(media_binary)
|
||||
self.server.iconsCache[media_filename] = media_binary
|
||||
fitness_performance(getreq_start_time, self.server.fitness,
|
||||
'_GET', '_show_specification_image',
|
||||
self.server.debug)
|
||||
return
|
||||
self._404()
|
||||
|
||||
def _show_help_screen_image(self, calling_domain: str, path: str,
|
||||
base_dir: str, getreq_start_time) -> None:
|
||||
"""Shows a help screen image
|
||||
|
@ -16274,6 +16343,39 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.debug)
|
||||
return
|
||||
|
||||
if self.path in ('/specification', '/protocol', '/activitypub'):
|
||||
if calling_domain.endswith('.onion'):
|
||||
msg = \
|
||||
html_specification(self.server.css_cache,
|
||||
self.server.base_dir, 'http',
|
||||
self.server.onion_domain,
|
||||
None, self.server.translate,
|
||||
self.server.system_language)
|
||||
elif calling_domain.endswith('.i2p'):
|
||||
msg = \
|
||||
html_specification(self.server.css_cache,
|
||||
self.server.base_dir, 'http',
|
||||
self.server.i2p_domain,
|
||||
None, self.server.translate,
|
||||
self.server.system_language)
|
||||
else:
|
||||
msg = \
|
||||
html_specification(self.server.css_cache,
|
||||
self.server.base_dir,
|
||||
self.server.http_prefix,
|
||||
self.server.domain_full,
|
||||
self.server.onion_domain,
|
||||
self.server.translate,
|
||||
self.server.system_language)
|
||||
msg = msg.encode('utf-8')
|
||||
msglen = len(msg)
|
||||
self._login_headers('text/html', msglen, calling_domain)
|
||||
self._write(msg)
|
||||
fitness_performance(getreq_start_time, self.server.fitness,
|
||||
'_GET', 'show specification screen',
|
||||
self.server.debug)
|
||||
return
|
||||
|
||||
if html_getreq and users_in_path and authorized and \
|
||||
self.path.endswith('/accesskeys'):
|
||||
nickname = self.path.split('/users/')[1]
|
||||
|
@ -16683,6 +16785,14 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.base_dir, getreq_start_time)
|
||||
return
|
||||
|
||||
# show images within https://instancedomain/activitypub
|
||||
if self.path.startswith('/activitypub-tutorial-'):
|
||||
if self.path.endswith('.png'):
|
||||
self._show_specification_image(self.path,
|
||||
self.server.base_dir,
|
||||
getreq_start_time)
|
||||
return
|
||||
|
||||
# help screen images
|
||||
# Note that this comes before the busy flag to avoid conflicts
|
||||
if self.path.startswith('/helpimages/'):
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -21,6 +21,7 @@
|
|||
--header-bg-color: #282c37;
|
||||
--main-bg-color: #282c37;
|
||||
--post-bg-color: #282c37;
|
||||
--code-color: lightblue;
|
||||
--column-left-color: #282c37;
|
||||
--link-bg-color: #282c37;
|
||||
--dropdown-fg-color: #dddddd;
|
||||
|
@ -127,6 +128,7 @@
|
|||
--quote-font-size-mobile: 120%;
|
||||
--quote-font-size-tiny: 60%;
|
||||
--line-spacing: 180%;
|
||||
--code-spacing: 100%;
|
||||
--line-spacing-newswire: 120%;
|
||||
--newswire-item-moderated-color: white;
|
||||
--newswire-date-moderated-color: white;
|
||||
|
@ -248,6 +250,16 @@ body, html {
|
|||
image-rendering: var(--rendering);
|
||||
}
|
||||
|
||||
code {
|
||||
color: var(--code-color);
|
||||
white-space: pre;
|
||||
line-height: var(--code-spacing);
|
||||
}
|
||||
|
||||
ul.md_list {
|
||||
color: var(--main-fg-color);
|
||||
}
|
||||
|
||||
audio {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
328
markdown.py
328
markdown.py
|
@ -8,6 +8,38 @@ __status__ = "Production"
|
|||
__module_group__ = "Web Interface"
|
||||
|
||||
|
||||
def _markdown_get_sections(markdown: str) -> []:
|
||||
"""Returns a list of sections for markdown
|
||||
"""
|
||||
if '<code>' not in markdown:
|
||||
return [markdown]
|
||||
lines = markdown.split('\n')
|
||||
sections = []
|
||||
section_text = ''
|
||||
section_active = False
|
||||
ctr = 0
|
||||
for line in lines:
|
||||
if ctr > 0:
|
||||
section_text += '\n'
|
||||
|
||||
if not section_active:
|
||||
if '<code>' in line:
|
||||
section_active = True
|
||||
sections.append(section_text)
|
||||
section_text = ''
|
||||
else:
|
||||
if '</code>' in line:
|
||||
section_active = False
|
||||
sections.append(section_text)
|
||||
section_text = ''
|
||||
|
||||
section_text += line
|
||||
ctr += 1
|
||||
if section_text.strip():
|
||||
sections.append(section_text)
|
||||
return sections
|
||||
|
||||
|
||||
def _markdown_emphasis_html(markdown: str) -> str:
|
||||
"""Add italics and bold html markup to the given markdown
|
||||
"""
|
||||
|
@ -17,39 +49,73 @@ def _markdown_emphasis_html(markdown: str) -> str:
|
|||
'**.': '</b>.',
|
||||
'**:': '</b>:',
|
||||
'**;': '</b>;',
|
||||
'?**': '?</b>',
|
||||
'\n**': '\n<b>',
|
||||
'**,': '</b>,',
|
||||
'**\n': '</b>\n',
|
||||
'(**': '(<b>)',
|
||||
'**)': '</b>)',
|
||||
'>**': '><b>',
|
||||
'**<': '</b><',
|
||||
'>*': '><i>',
|
||||
'*<': '</i><',
|
||||
' *': ' <i>',
|
||||
'* ': '</i> ',
|
||||
'?*': '?</i>',
|
||||
'\n*': '\n<i>',
|
||||
'*.': '</i>.',
|
||||
'*:': '</i>:',
|
||||
'*;': '</i>;',
|
||||
'(*': '(<i>)',
|
||||
'*)': '</i>)',
|
||||
'*,': '</i>,',
|
||||
'*\n': '</i>\n',
|
||||
' _': ' <ul>',
|
||||
'_ ': '</ul> ',
|
||||
'_.': '</ul>.',
|
||||
'_:': '</ul>:',
|
||||
'_;': '</ul>;',
|
||||
'_,': '</ul>,',
|
||||
'_\n': '</ul>\n'
|
||||
'(_': '(<u>',
|
||||
'_)': '</u>)',
|
||||
' _': ' <u>',
|
||||
'_ ': '</u> ',
|
||||
'_.': '</u>.',
|
||||
'_:': '</u>:',
|
||||
'_;': '</u>;',
|
||||
'_,': '</u>,',
|
||||
'_\n': '</u>\n',
|
||||
' `': ' <em>',
|
||||
'`.': '</em>.',
|
||||
'`:': '</em>:',
|
||||
"`'": "</em>'",
|
||||
"(`": "(<em>",
|
||||
"`)": "</em>)",
|
||||
'`;': '</em>;',
|
||||
'`,': '</em>,',
|
||||
'`\n': '</em>\n',
|
||||
'` ': '</em> '
|
||||
}
|
||||
|
||||
sections = _markdown_get_sections(markdown)
|
||||
markdown = ''
|
||||
for section_text in sections:
|
||||
if '<code>' in section_text:
|
||||
markdown += section_text
|
||||
continue
|
||||
for md_str, html in replacements.items():
|
||||
markdown = markdown.replace(md_str, html)
|
||||
section_text = section_text.replace(md_str, html)
|
||||
|
||||
if markdown.startswith('**'):
|
||||
markdown = markdown[2:] + '<b>'
|
||||
elif markdown.startswith('*'):
|
||||
markdown = markdown[1:] + '<i>'
|
||||
elif markdown.startswith('_'):
|
||||
markdown = markdown[1:] + '<ul>'
|
||||
if section_text.startswith('**'):
|
||||
section_text = section_text[2:] + '<b>'
|
||||
elif section_text.startswith('*'):
|
||||
section_text = section_text[1:] + '<i>'
|
||||
elif section_text.startswith('_'):
|
||||
section_text = section_text[1:] + '<u>'
|
||||
|
||||
if markdown.endswith('**'):
|
||||
markdown = markdown[:len(markdown) - 2] + '</b>'
|
||||
elif markdown.endswith('*'):
|
||||
markdown = markdown[:len(markdown) - 1] + '</i>'
|
||||
elif markdown.endswith('_'):
|
||||
markdown = markdown[:len(markdown) - 1] + '</ul>'
|
||||
if section_text.endswith('**'):
|
||||
section_text = section_text[:len(section_text) - 2] + '</b>'
|
||||
elif section_text.endswith('*'):
|
||||
section_text = section_text[:len(section_text) - 1] + '</i>'
|
||||
elif section_text.endswith('_'):
|
||||
section_text = section_text[:len(section_text) - 1] + '</u>'
|
||||
|
||||
if section_text.strip():
|
||||
markdown += section_text
|
||||
return markdown
|
||||
|
||||
|
||||
|
@ -61,7 +127,19 @@ def _markdown_replace_quotes(markdown: str) -> str:
|
|||
lines = markdown.split('\n')
|
||||
result = ''
|
||||
prev_quote_line = None
|
||||
code_section = False
|
||||
for line in lines:
|
||||
# avoid code sections
|
||||
if not code_section:
|
||||
if '<code>' in line:
|
||||
code_section = True
|
||||
else:
|
||||
if '</code>' in line:
|
||||
code_section = False
|
||||
if code_section:
|
||||
result += line + '\n'
|
||||
continue
|
||||
|
||||
if '> ' not in line:
|
||||
result += line + '\n'
|
||||
prev_quote_line = None
|
||||
|
@ -90,56 +168,176 @@ def _markdown_replace_quotes(markdown: str) -> str:
|
|||
return result
|
||||
|
||||
|
||||
def _markdown_replace_links(markdown: str, images: bool = False) -> str:
|
||||
def _markdown_replace_links(markdown: str) -> str:
|
||||
"""Replaces markdown links with html
|
||||
Optionally replace image links
|
||||
"""
|
||||
replace_links = {}
|
||||
text = markdown
|
||||
start_chars = '['
|
||||
if images:
|
||||
start_chars = '!['
|
||||
while start_chars in text:
|
||||
if ')' not in text:
|
||||
break
|
||||
text = text.split(start_chars, 1)[1]
|
||||
markdown_link = start_chars + text.split(')')[0] + ')'
|
||||
if ']' not in markdown_link or \
|
||||
'(' not in markdown_link:
|
||||
text = text.split(')', 1)[1]
|
||||
sections = _markdown_get_sections(markdown)
|
||||
result = ''
|
||||
for section_text in sections:
|
||||
if '<code>' in section_text or \
|
||||
'](' not in section_text:
|
||||
result += section_text
|
||||
continue
|
||||
if not images:
|
||||
replace_links[markdown_link] = \
|
||||
'<a href="' + \
|
||||
markdown_link.split('(')[1].split(')')[0] + \
|
||||
'" target="_blank" rel="nofollow noopener noreferrer">' + \
|
||||
markdown_link.split(start_chars)[1].split(']')[0] + \
|
||||
'</a>'
|
||||
else:
|
||||
replace_links[markdown_link] = \
|
||||
sections_links = section_text.split('](')
|
||||
ctr = 0
|
||||
for link_section in sections_links:
|
||||
if ctr == 0:
|
||||
ctr += 1
|
||||
continue
|
||||
if '[' in sections_links[ctr - 1] and \
|
||||
')' in link_section:
|
||||
link_text = sections_links[ctr - 1].split('[')[-1]
|
||||
link_url = link_section.split(')')[0]
|
||||
replace_str = '[' + link_text + '](' + link_url + ')'
|
||||
link_text = link_text.replace('`', '')
|
||||
if '!' + replace_str in section_text:
|
||||
html_link = \
|
||||
'<img class="markdownImage" src="' + \
|
||||
markdown_link.split('(')[1].split(')')[0] + \
|
||||
'" alt="' + \
|
||||
markdown_link.split(start_chars)[1].split(']')[0] + \
|
||||
'" />'
|
||||
text = text.split(')', 1)[1]
|
||||
for md_link, html_link in replace_links.items():
|
||||
markdown = markdown.replace(md_link, html_link)
|
||||
link_url + '" alt="' + link_text + '" />'
|
||||
section_text = \
|
||||
section_text.replace('!' + replace_str, html_link)
|
||||
if replace_str in section_text:
|
||||
html_link = \
|
||||
'<a href="' + link_url + '" target="_blank" ' + \
|
||||
'rel="nofollow noopener noreferrer">' + \
|
||||
link_text + '</a>'
|
||||
section_text = \
|
||||
section_text.replace(replace_str, html_link)
|
||||
ctr += 1
|
||||
result += section_text
|
||||
return result
|
||||
|
||||
|
||||
def _markdown_replace_bullet_points(markdown: str) -> str:
|
||||
"""Replaces bullet points
|
||||
"""
|
||||
lines = markdown.split('\n')
|
||||
bullet_style = ('* ', ' * ', '- ', ' - ')
|
||||
bullet_matched = ''
|
||||
start_line = -1
|
||||
line_ctr = 0
|
||||
changed = False
|
||||
code_section = False
|
||||
for line in lines:
|
||||
if not line.strip():
|
||||
# skip blank lines
|
||||
line_ctr += 1
|
||||
continue
|
||||
|
||||
# skip over code sections
|
||||
if not code_section:
|
||||
if '<code>' in line:
|
||||
code_section = True
|
||||
else:
|
||||
if '</code>' in line:
|
||||
code_section = False
|
||||
if code_section:
|
||||
line_ctr += 1
|
||||
continue
|
||||
|
||||
if not bullet_matched:
|
||||
for test_str in bullet_style:
|
||||
if line.startswith(test_str):
|
||||
bullet_matched = test_str
|
||||
start_line = line_ctr
|
||||
break
|
||||
else:
|
||||
if not line.startswith(bullet_matched):
|
||||
for index in range(start_line, line_ctr):
|
||||
line_text = lines[index].replace(bullet_matched, '', 1)
|
||||
if index == start_line:
|
||||
lines[index] = \
|
||||
'<ul class="md_list">\n<li>' + line_text + '</li>'
|
||||
elif index == line_ctr - 1:
|
||||
lines[index] = '<li>' + line_text + '</li>\n</ul>'
|
||||
else:
|
||||
lines[index] = '<li>' + line_text + '</li>'
|
||||
changed = True
|
||||
start_line = -1
|
||||
bullet_matched = ''
|
||||
line_ctr += 1
|
||||
|
||||
if not changed:
|
||||
return markdown
|
||||
|
||||
markdown = ''
|
||||
for line in lines:
|
||||
markdown += line + '\n'
|
||||
return markdown
|
||||
|
||||
|
||||
def _markdown_replace_code(markdown: str) -> str:
|
||||
"""Replaces code sections within markdown
|
||||
"""
|
||||
lines = markdown.split('\n')
|
||||
start_line = -1
|
||||
line_ctr = 0
|
||||
changed = False
|
||||
section_active = False
|
||||
for line in lines:
|
||||
if not line.strip():
|
||||
# skip blank lines
|
||||
line_ctr += 1
|
||||
continue
|
||||
if line.startswith('```'):
|
||||
if not section_active:
|
||||
start_line = line_ctr
|
||||
section_active = True
|
||||
else:
|
||||
lines[start_line] = '<code>'
|
||||
lines[line_ctr] = '</code>'
|
||||
section_active = False
|
||||
changed = True
|
||||
line_ctr += 1
|
||||
|
||||
if not changed:
|
||||
return markdown
|
||||
|
||||
markdown = ''
|
||||
for line in lines:
|
||||
markdown += line + '\n'
|
||||
return markdown
|
||||
|
||||
|
||||
def markdown_example_numbers(markdown: str) -> str:
|
||||
"""Ensures that example numbers in the ActivityPub specification
|
||||
document are sequential
|
||||
"""
|
||||
lines = markdown.split('\n')
|
||||
example_number = 1
|
||||
line_ctr = 0
|
||||
for line in lines:
|
||||
if not line.strip():
|
||||
# skip blank lines
|
||||
line_ctr += 1
|
||||
continue
|
||||
if line.startswith('##') and '## Example ' in line:
|
||||
header_str = line.split(' Example ')[0]
|
||||
lines[line_ctr] = header_str + ' Example ' + str(example_number)
|
||||
example_number += 1
|
||||
line_ctr += 1
|
||||
|
||||
markdown = ''
|
||||
for line in lines:
|
||||
markdown += line + '\n'
|
||||
return markdown
|
||||
|
||||
|
||||
def markdown_to_html(markdown: str) -> str:
|
||||
"""Converts markdown formatted text to html
|
||||
"""
|
||||
markdown = _markdown_replace_code(markdown)
|
||||
markdown = _markdown_replace_bullet_points(markdown)
|
||||
markdown = _markdown_replace_quotes(markdown)
|
||||
markdown = _markdown_emphasis_html(markdown)
|
||||
markdown = _markdown_replace_links(markdown, True)
|
||||
markdown = _markdown_replace_links(markdown)
|
||||
|
||||
# replace headers
|
||||
lines_list = markdown.split('\n')
|
||||
html_str = ''
|
||||
ctr = 0
|
||||
code_section = False
|
||||
titles = {
|
||||
"h5": '#####',
|
||||
"h4": '####',
|
||||
|
@ -149,13 +347,37 @@ def markdown_to_html(markdown: str) -> str:
|
|||
}
|
||||
for line in lines_list:
|
||||
if ctr > 0:
|
||||
html_str += '<br>'
|
||||
if not code_section:
|
||||
html_str += '<br>\n'
|
||||
else:
|
||||
html_str += '\n'
|
||||
|
||||
# avoid code sections
|
||||
if not code_section:
|
||||
if '<code>' in line:
|
||||
code_section = True
|
||||
else:
|
||||
if '</code>' in line:
|
||||
code_section = False
|
||||
if code_section:
|
||||
html_str += line
|
||||
ctr += 1
|
||||
continue
|
||||
|
||||
for hsh, hashes in titles.items():
|
||||
if line.startswith(hashes):
|
||||
line = line.replace(hashes, '').strip()
|
||||
line = '<' + hsh + '>' + line + '</' + hsh + '>'
|
||||
line = '<' + hsh + '>' + line + '</' + hsh + '>\n'
|
||||
ctr = -1
|
||||
break
|
||||
html_str += line
|
||||
ctr += 1
|
||||
|
||||
html_str = html_str.replace('<code><br>', '<code>')
|
||||
html_str = html_str.replace('</code><br>', '</code>')
|
||||
|
||||
html_str = html_str.replace('<ul class="md_list"><br>',
|
||||
'<ul class="md_list">')
|
||||
html_str = html_str.replace('</li><br>', '</li>')
|
||||
|
||||
return html_str
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
After Width: | Height: | Size: 55 KiB |
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
File diff suppressed because it is too large
Load Diff
75
tests.py
75
tests.py
|
@ -5715,16 +5715,68 @@ def _test_markdown_to_html():
|
|||
|
||||
markdown = 'This is a quotation:\n' + \
|
||||
'> Some quote or other'
|
||||
assert markdown_to_html(markdown) == 'This is a quotation:<br>' + \
|
||||
expected = \
|
||||
'This is a quotation:<br>\n' + \
|
||||
'<blockquote><i>Some quote or other</i></blockquote>'
|
||||
result = markdown_to_html(markdown)
|
||||
if result != expected:
|
||||
print(result)
|
||||
assert result == expected
|
||||
|
||||
markdown = 'This is a multi-line quotation:\n' + \
|
||||
'> The first line\n' + \
|
||||
'> The second line'
|
||||
assert markdown_to_html(markdown) == \
|
||||
'This is a multi-line quotation:<br>' + \
|
||||
'This is a multi-line quotation:<br>\n' + \
|
||||
'<blockquote><i>The first line The second line</i></blockquote>'
|
||||
|
||||
markdown = 'This is a list of points:\n' + \
|
||||
' * Point 1\n' + \
|
||||
' * Point 2\n\n' + \
|
||||
'And some other text.'
|
||||
result = markdown_to_html(markdown)
|
||||
expected = \
|
||||
'This is a list of points:<br>\n<ul class="md_list">' + \
|
||||
'\n<li>Point 1</li>\n' + \
|
||||
'<li>Point 2</li>\n<li></li>\n</ul><br>\n' + \
|
||||
'And some other text.<br>\n'
|
||||
if result != expected:
|
||||
print(result)
|
||||
assert result == expected
|
||||
|
||||
markdown = 'This is a list of points:\n' + \
|
||||
' * **Point 1**\n' + \
|
||||
' * *Point 2*\n\n' + \
|
||||
'And some other text.'
|
||||
result = markdown_to_html(markdown)
|
||||
expected = \
|
||||
'This is a list of points:<br>\n<ul class="md_list">\n' + \
|
||||
'<li><b>Point 1</b></li>\n' + \
|
||||
'<li><i>Point 2</i></li>\n<li></li>\n</ul><br>\n' + \
|
||||
'And some other text.<br>\n'
|
||||
if result != expected:
|
||||
print(result)
|
||||
assert result == expected
|
||||
|
||||
markdown = 'This is a code section:\n' + \
|
||||
'``` json\n' + \
|
||||
'10 PRINT "YOLO"\n' + \
|
||||
'20 GOTO 10\n' + \
|
||||
'```\n\n' + \
|
||||
'And some other text.'
|
||||
result = markdown_to_html(markdown)
|
||||
expected = \
|
||||
'This is a code section:<br>\n' + \
|
||||
'<code>\n' + \
|
||||
'10 PRINT "YOLO"\n' + \
|
||||
'20 GOTO 10\n' + \
|
||||
'</code>\n' + \
|
||||
'<br>\n' + \
|
||||
'And some other text.<br>\n'
|
||||
if result != expected:
|
||||
print(result)
|
||||
assert result == expected
|
||||
|
||||
markdown = 'This is **bold**'
|
||||
assert markdown_to_html(markdown) == 'This is <b>bold</b>'
|
||||
|
||||
|
@ -5732,27 +5784,34 @@ def _test_markdown_to_html():
|
|||
assert markdown_to_html(markdown) == 'This is <i>italic</i>'
|
||||
|
||||
markdown = 'This is _underlined_'
|
||||
assert markdown_to_html(markdown) == 'This is <ul>underlined</ul>'
|
||||
assert markdown_to_html(markdown) == 'This is <u>underlined</u>'
|
||||
|
||||
markdown = 'This is **just** plain text'
|
||||
assert markdown_to_html(markdown) == 'This is <b>just</b> plain text'
|
||||
|
||||
markdown = '# Title1\n### Title3\n## Title2\n'
|
||||
assert markdown_to_html(markdown) == \
|
||||
'<h1>Title1</h1><h3>Title3</h3><h2>Title2</h2>'
|
||||
expected = '<h1>Title1</h1>\n<h3>Title3</h3>\n<h2>Title2</h2>\n'
|
||||
result = markdown_to_html(markdown)
|
||||
if result != expected:
|
||||
print(result)
|
||||
assert result == expected
|
||||
|
||||
markdown = \
|
||||
'This is [a link](https://something.somewhere) to something.\n' + \
|
||||
'And [something else](https://cat.pic).\n' + \
|
||||
'Or .'
|
||||
assert markdown_to_html(markdown) == \
|
||||
expected = \
|
||||
'This is <a href="https://something.somewhere" ' + \
|
||||
'target="_blank" rel="nofollow noopener noreferrer">' + \
|
||||
'a link</a> to something.<br>' + \
|
||||
'a link</a> to something.<br>\n' + \
|
||||
'And <a href="https://cat.pic" ' + \
|
||||
'target="_blank" rel="nofollow noopener noreferrer">' + \
|
||||
'something else</a>.<br>' + \
|
||||
'something else</a>.<br>\n' + \
|
||||
'Or <img class="markdownImage" src="/cat.jpg" alt="pounce" />.'
|
||||
result = markdown_to_html(markdown)
|
||||
if result != expected:
|
||||
print(result)
|
||||
assert result == expected
|
||||
|
||||
|
||||
def _test_extract_text_fields_from_post():
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"code-color": "white",
|
||||
"pwa-theme-color": "apple-mobile-web-app-status-bar-style",
|
||||
"pwa-theme-background-color": "black-translucent",
|
||||
"newswire-publish-icon": "True",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"code-color": "blue",
|
||||
"diff-add": "#111",
|
||||
"diff-remove": "#333",
|
||||
"pwa-theme-color": "apple-mobile-web-app-status-bar-style",
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
"liker-names-margin": "2%",
|
||||
"liker-names-vertical-spacing1": "50px",
|
||||
"liker-names-vertical-spacing2": "100px",
|
||||
"code-color": "lightblue",
|
||||
"pwa-theme-color": "apple-mobile-web-app-status-bar-style",
|
||||
"pwa-theme-background-color": "black-translucent",
|
||||
"avatar-rounding": "10%",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"code-color": "lightblue",
|
||||
"pwa-theme-color": "apple-mobile-web-app-status-bar-style",
|
||||
"pwa-theme-background-color": "black-translucent",
|
||||
"dropdown-fg-color": "#9ad791",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"code-color": "blue",
|
||||
"pwa-theme-color": "apple-mobile-web-app-status-bar-style",
|
||||
"pwa-theme-background-color": "black-translucent",
|
||||
"dropdown-fg-color": "white",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"code-color": "lightblue",
|
||||
"pwa-theme-color": "apple-mobile-web-app-status-bar-style",
|
||||
"pwa-theme-background-color": "black-translucent",
|
||||
"dropdown-fg-color": "white",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"code-color": "blue",
|
||||
"diff-add": "#111",
|
||||
"diff-remove": "#333",
|
||||
"pwa-theme-color": "apple-mobile-web-app-status-bar-style",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"code-color": "blue",
|
||||
"pwa-theme-color": "apple-mobile-web-app-status-bar-style",
|
||||
"pwa-theme-background-color": "black-translucent",
|
||||
"dropdown-fg-color": "#33390d",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"diff-add": "#111",
|
||||
"diff-remove": "#333",
|
||||
"code-color": "blue",
|
||||
"pwa-theme-color": "apple-mobile-web-app-status-bar-style",
|
||||
"pwa-theme-background-color": "black-translucent",
|
||||
"dropdown-fg-color": "#2d2c37",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"code-color": "lightblue",
|
||||
"pwa-theme-color": "apple-mobile-web-app-status-bar-style",
|
||||
"pwa-theme-background-color": "black-translucent",
|
||||
"dropdown-fg-color": "#0481f5",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"code-color": "blue",
|
||||
"diff-add": "#111",
|
||||
"diff-remove": "#333",
|
||||
"pwa-theme-color": "apple-mobile-web-app-status-bar-style",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"code-color": "lightblue",
|
||||
"pwa-theme-color": "apple-mobile-web-app-status-bar-style",
|
||||
"pwa-theme-background-color": "black-translucent",
|
||||
"dropdown-fg-color": "#f98bb0",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"code-color": "lightblue",
|
||||
"pwa-theme-color": "apple-mobile-web-app-status-bar-style",
|
||||
"pwa-theme-background-color": "black-translucent",
|
||||
"dropdown-fg-color": "white",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"code-color": "blue",
|
||||
"pwa-theme-color": "apple-mobile-web-app-status-bar-style",
|
||||
"pwa-theme-background-color": "black-translucent",
|
||||
"dropdown-fg-color": "#2d2c37",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"code-color": "lightblue",
|
||||
"pwa-theme-color": "apple-mobile-web-app-status-bar-style",
|
||||
"pwa-theme-background-color": "black-translucent",
|
||||
"dropdown-fg-color": "#ffc4bc",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"code-color": "blue",
|
||||
"font-size-likes-mobile": "64px",
|
||||
"likes-margin-left-mobile": "20px",
|
||||
"likes-margin-right-mobile": "0px",
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "يحفظ",
|
||||
"Switch to moderation view": "قم بالتبديل إلى عرض الاعتدال",
|
||||
"Minimize attached images": "تصغير الصور المرفقة",
|
||||
"SHOW MEDIA": "عرض الوسائط"
|
||||
"SHOW MEDIA": "عرض الوسائط",
|
||||
"ActivityPub Specification": "مواصفات ActivityPub"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "সংরক্ষণ",
|
||||
"Switch to moderation view": "সংযম দৃশ্যে স্যুইচ করুন",
|
||||
"Minimize attached images": "সংযুক্ত ছবি ছোট করুন",
|
||||
"SHOW MEDIA": "মিডিয়া দেখান"
|
||||
"SHOW MEDIA": "মিডিয়া দেখান",
|
||||
"ActivityPub Specification": "ActivityPub স্পেসিফিকেশন"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Desa",
|
||||
"Switch to moderation view": "Canvia a la visualització de moderació",
|
||||
"Minimize attached images": "Minimitzar les imatges adjuntes",
|
||||
"SHOW MEDIA": "MOSTRA ELS MITJANS"
|
||||
"SHOW MEDIA": "MOSTRA ELS MITJANS",
|
||||
"ActivityPub Specification": "Especificació d'ActivityPub"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Arbed",
|
||||
"Switch to moderation view": "Newid i wedd safoni",
|
||||
"Minimize attached images": "Lleihau delweddau sydd ynghlwm",
|
||||
"SHOW MEDIA": "DANGOS CYFRYNGAU"
|
||||
"SHOW MEDIA": "DANGOS CYFRYNGAU",
|
||||
"ActivityPub Specification": "Manyleb GweithgareddPub"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Speichern",
|
||||
"Switch to moderation view": "Wechseln Sie zur Moderationsansicht",
|
||||
"Minimize attached images": "Angehängte Bilder minimieren",
|
||||
"SHOW MEDIA": "MEDIEN ZEIGEN"
|
||||
"SHOW MEDIA": "MEDIEN ZEIGEN",
|
||||
"ActivityPub Specification": "ActivityPub-Spezifikation"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Αποθηκεύσετε",
|
||||
"Switch to moderation view": "Μετάβαση σε προβολή εποπτείας",
|
||||
"Minimize attached images": "Ελαχιστοποιήστε τις συνημμένες εικόνες",
|
||||
"SHOW MEDIA": "ΔΕΙΤΕ ΜΕΣΑ"
|
||||
"SHOW MEDIA": "ΔΕΙΤΕ ΜΕΣΑ",
|
||||
"ActivityPub Specification": "Προδιαγραφές ActivityPub"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Save",
|
||||
"Switch to moderation view": "Switch to moderation view",
|
||||
"Minimize attached images": "Minimize attached images",
|
||||
"SHOW MEDIA": "SHOW MEDIA"
|
||||
"SHOW MEDIA": "SHOW MEDIA",
|
||||
"ActivityPub Specification": "ActivityPub Specification"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Ahorrar",
|
||||
"Switch to moderation view": "Cambiar a la vista de moderación",
|
||||
"Minimize attached images": "Minimizar imágenes adjuntas",
|
||||
"SHOW MEDIA": "MOSTRAR MEDIOS"
|
||||
"SHOW MEDIA": "MOSTRAR MEDIOS",
|
||||
"ActivityPub Specification": "Especificación de ActivityPub"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Sauvegarder",
|
||||
"Switch to moderation view": "Passer en mode modération",
|
||||
"Minimize attached images": "Réduire les images jointes",
|
||||
"SHOW MEDIA": "AFFICHER LES MÉDIAS"
|
||||
"SHOW MEDIA": "AFFICHER LES MÉDIAS",
|
||||
"ActivityPub Specification": "Spécification ActivityPub"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Sábháil",
|
||||
"Switch to moderation view": "Athraigh go dtí an t-amharc modhnóireachta",
|
||||
"Minimize attached images": "Íoslaghdaigh íomhánna ceangailte",
|
||||
"SHOW MEDIA": "Taispeáin MEÁIN"
|
||||
"SHOW MEDIA": "Taispeáin MEÁIN",
|
||||
"ActivityPub Specification": "Sonraíocht ActivityPub"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "बचाना",
|
||||
"Switch to moderation view": "मॉडरेशन दृश्य पर स्विच करें",
|
||||
"Minimize attached images": "संलग्न छवियों को छोटा करें",
|
||||
"SHOW MEDIA": "मीडिया दिखाएं"
|
||||
"SHOW MEDIA": "मीडिया दिखाएं",
|
||||
"ActivityPub Specification": "गतिविधिपब विशिष्टता"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Salva",
|
||||
"Switch to moderation view": "Passa alla visualizzazione moderazione",
|
||||
"Minimize attached images": "Riduci al minimo le immagini allegate",
|
||||
"SHOW MEDIA": "MOSTRA MEDIA"
|
||||
"SHOW MEDIA": "MOSTRA MEDIA",
|
||||
"ActivityPub Specification": "Specifica ActivityPub"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "保存",
|
||||
"Switch to moderation view": "モデレートビューに切り替えます",
|
||||
"Minimize attached images": "添付画像を最小限に抑える",
|
||||
"SHOW MEDIA": "メディアを表示"
|
||||
"SHOW MEDIA": "メディアを表示",
|
||||
"ActivityPub Specification": "ActivityPubの仕様"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "구하다",
|
||||
"Switch to moderation view": "검토 보기로 전환",
|
||||
"Minimize attached images": "첨부된 이미지 최소화",
|
||||
"SHOW MEDIA": "미디어 표시"
|
||||
"SHOW MEDIA": "미디어 표시",
|
||||
"ActivityPub Specification": "ActivityPub 사양"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Rizgarkirin",
|
||||
"Switch to moderation view": "Biguherîne bo dîtina moderatoriyê",
|
||||
"Minimize attached images": "Wêneyên pêvekirî kêm bikin",
|
||||
"SHOW MEDIA": "MEDYA NÎŞAN DE"
|
||||
"SHOW MEDIA": "MEDYA NÎŞAN DE",
|
||||
"ActivityPub Specification": "Specification ActivityPub"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Opslaan",
|
||||
"Switch to moderation view": "Overschakelen naar moderatieweergave",
|
||||
"Minimize attached images": "Bijgevoegde afbeeldingen minimaliseren",
|
||||
"SHOW MEDIA": "TOON MEDIA"
|
||||
"SHOW MEDIA": "TOON MEDIA",
|
||||
"ActivityPub Specification": "ActivityPub-specificatie"
|
||||
}
|
||||
|
|
|
@ -560,5 +560,6 @@
|
|||
"Save": "Save",
|
||||
"Switch to moderation view": "Switch to moderation view",
|
||||
"Minimize attached images": "Minimize attached images",
|
||||
"SHOW MEDIA": "SHOW MEDIA"
|
||||
"SHOW MEDIA": "SHOW MEDIA",
|
||||
"ActivityPub Specification": "ActivityPub Specification"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Ratować",
|
||||
"Switch to moderation view": "Przełącz na widok moderacji",
|
||||
"Minimize attached images": "Zminimalizuj załączone obrazy",
|
||||
"SHOW MEDIA": "POKAŻ MEDIA"
|
||||
"SHOW MEDIA": "POKAŻ MEDIA",
|
||||
"ActivityPub Specification": "Specyfikacja ActivityPub"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Salvar",
|
||||
"Switch to moderation view": "Mudar para a visualização de moderação",
|
||||
"Minimize attached images": "Minimizar imagens anexadas",
|
||||
"SHOW MEDIA": "MOSTRAR MÍDIA"
|
||||
"SHOW MEDIA": "MOSTRAR MÍDIA",
|
||||
"ActivityPub Specification": "Especificação do ActivityPub"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Сохранять",
|
||||
"Switch to moderation view": "Перейти в режим модерации",
|
||||
"Minimize attached images": "Свернуть прикрепленные изображения",
|
||||
"SHOW MEDIA": "ПОКАЗАТЬ МЕДИА"
|
||||
"SHOW MEDIA": "ПОКАЗАТЬ МЕДИА",
|
||||
"ActivityPub Specification": "Спецификация ActivityPub"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Hifadhi",
|
||||
"Switch to moderation view": "Badili hadi mwonekano wa udhibiti",
|
||||
"Minimize attached images": "Punguza picha zilizoambatishwa",
|
||||
"SHOW MEDIA": "ONESHA VYOMBO VYA HABARI"
|
||||
"SHOW MEDIA": "ONESHA VYOMBO VYA HABARI",
|
||||
"ActivityPub Specification": "Vipimo vya ActivityPub"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Kaydetmek",
|
||||
"Switch to moderation view": "Denetleme görünümüne geç",
|
||||
"Minimize attached images": "Ekli resimleri simge durumuna küçült",
|
||||
"SHOW MEDIA": "MEDYA GÖSTER"
|
||||
"SHOW MEDIA": "MEDYA GÖSTER",
|
||||
"ActivityPub Specification": "ActivityPub Spesifikasyonu"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "Зберегти",
|
||||
"Switch to moderation view": "Перейти до режиму модерації",
|
||||
"Minimize attached images": "Мінімізуйте вкладені зображення",
|
||||
"SHOW MEDIA": "ПОКАЗАТИ ЗМІ"
|
||||
"SHOW MEDIA": "ПОКАЗАТИ ЗМІ",
|
||||
"ActivityPub Specification": "Специфікація ActivityPub"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "היט",
|
||||
"Switch to moderation view": "באַשטימען צו מאַדעריישאַן מיינונג",
|
||||
"Minimize attached images": "מינאַמייז אַטאַטשט בילדער",
|
||||
"SHOW MEDIA": "ווייַז מעדיע"
|
||||
"SHOW MEDIA": "ווייַז מעדיע",
|
||||
"ActivityPub Specification": "ActivityPub באַשרייַבונג"
|
||||
}
|
||||
|
|
|
@ -564,5 +564,6 @@
|
|||
"Save": "节省",
|
||||
"Switch to moderation view": "切换到审核视图",
|
||||
"Minimize attached images": "最小化附加图像",
|
||||
"SHOW MEDIA": "展示媒体"
|
||||
"SHOW MEDIA": "展示媒体",
|
||||
"ActivityPub Specification": "ActivityPub 规范"
|
||||
}
|
||||
|
|
|
@ -346,6 +346,9 @@ def get_left_column_content(base_dir: str, nickname: str, domain_full: str,
|
|||
html_str += \
|
||||
'<p class="login-text"><a href="/about">' + \
|
||||
translate['About this Instance'] + '</a></p>'
|
||||
html_str += \
|
||||
'<p class="login-text"><a href="/activitypub">' + \
|
||||
translate['ActivityPub Specification'] + '</a></p>'
|
||||
html_str += \
|
||||
'<p class="login-text"><a href="/terms">' + \
|
||||
translate['Terms of Service'] + '</a></p>'
|
||||
|
@ -505,7 +508,7 @@ def html_edit_links(css_cache: {}, translate: {}, base_dir: str, path: str,
|
|||
edit_links_form += \
|
||||
'</div>'
|
||||
|
||||
# the admin can edit terms of service and about text
|
||||
# the admin can edit terms of service, about and specification text
|
||||
admin_nickname = get_config_param(base_dir, 'admin')
|
||||
if admin_nickname:
|
||||
if nickname == admin_nickname:
|
||||
|
@ -547,5 +550,25 @@ def html_edit_links(css_cache: {}, translate: {}, base_dir: str, path: str,
|
|||
edit_links_form += \
|
||||
'</div>'
|
||||
|
||||
specification_filename = base_dir + '/accounts/activitypub.md'
|
||||
specification_str = ''
|
||||
if os.path.isfile(specification_filename):
|
||||
with open(specification_filename, 'r',
|
||||
encoding='utf-8') as fp_specification:
|
||||
specification_str = fp_specification.read()
|
||||
|
||||
edit_links_form += \
|
||||
'<div class="container">'
|
||||
edit_links_form += \
|
||||
' ' + \
|
||||
translate['ActivityPub Specification'] + \
|
||||
'<br>'
|
||||
edit_links_form += \
|
||||
' <textarea id="message" name="editedSpecification" ' + \
|
||||
'style="height:1000vh" spellcheck="true" ' + \
|
||||
'autocomplete="on">' + specification_str + '</textarea>'
|
||||
edit_links_form += \
|
||||
'</div>'
|
||||
|
||||
edit_links_form += html_footer()
|
||||
return edit_links_form
|
||||
|
|
|
@ -102,7 +102,7 @@ def _html_podcast_chapters(link_url: str,
|
|||
if chapters_html:
|
||||
html_str = \
|
||||
'<div class="chapters">\n' + \
|
||||
' <ul>\n' + chapters_html + ' </ul>\n</div>\n'
|
||||
' <u>\n' + chapters_html + ' </u>\n</div>\n'
|
||||
return html_str
|
||||
|
||||
|
||||
|
|
|
@ -1008,7 +1008,7 @@ def _get_blog_citations_html(box_name: str,
|
|||
if translate.get(translated_citations_str):
|
||||
translated_citations_str = translate[translated_citations_str]
|
||||
citations_str = '<p><b>' + translated_citations_str + ':</b></p>' + \
|
||||
'<ul>\n' + citations_str + '</ul>\n'
|
||||
'<u>\n' + citations_str + '</u>\n'
|
||||
return citations_str
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
__filename__ = "webapp_about.py"
|
||||
__author__ = "Bob Mottram"
|
||||
__license__ = "AGPL3+"
|
||||
__version__ = "1.3.0"
|
||||
__maintainer__ = "Bob Mottram"
|
||||
__email__ = "bob@libreserver.org"
|
||||
__status__ = "Production"
|
||||
__module_group__ = "Web Interface"
|
||||
|
||||
import os
|
||||
from shutil import copyfile
|
||||
from utils import get_config_param
|
||||
from webapp_utils import html_header_with_website_markup
|
||||
from webapp_utils import html_footer
|
||||
from markdown import markdown_example_numbers
|
||||
from markdown import markdown_to_html
|
||||
|
||||
|
||||
def html_specification(css_cache: {}, base_dir: str, http_prefix: str,
|
||||
domain_full: str, onion_domain: str, translate: {},
|
||||
system_language: str) -> str:
|
||||
"""Show the specification screen
|
||||
"""
|
||||
specification_filename = base_dir + '/specification/activitypub.md'
|
||||
admin_nickname = get_config_param(base_dir, 'admin')
|
||||
if os.path.isfile(base_dir + '/accounts/activitypub.md'):
|
||||
specification_filename = base_dir + '/accounts/activitypub.md'
|
||||
|
||||
if os.path.isfile(base_dir + '/accounts/login-background-custom.jpg'):
|
||||
if not os.path.isfile(base_dir + '/accounts/login-background.jpg'):
|
||||
copyfile(base_dir + '/accounts/login-background-custom.jpg',
|
||||
base_dir + '/accounts/login-background.jpg')
|
||||
|
||||
specification_text = 'ActivityPub Protocol Specification.'
|
||||
if os.path.isfile(specification_filename):
|
||||
with open(specification_filename, 'r',
|
||||
encoding='utf-8') as fp_specification:
|
||||
md_text = markdown_example_numbers(fp_specification.read())
|
||||
specification_text = markdown_to_html(md_text)
|
||||
|
||||
specification_form = ''
|
||||
css_filename = base_dir + '/epicyon-profile.css'
|
||||
if os.path.isfile(base_dir + '/epicyon.css'):
|
||||
css_filename = base_dir + '/epicyon.css'
|
||||
|
||||
instance_title = \
|
||||
get_config_param(base_dir, 'instanceTitle')
|
||||
specification_form = \
|
||||
html_header_with_website_markup(css_filename, instance_title,
|
||||
http_prefix, domain_full,
|
||||
system_language)
|
||||
specification_form += \
|
||||
'<div class="container">' + specification_text + '</div>'
|
||||
if onion_domain:
|
||||
specification_form += \
|
||||
'<div class="container"><center>\n' + \
|
||||
'<p class="administeredby">' + \
|
||||
'http://' + onion_domain + '</p>\n</center></div>\n'
|
||||
if admin_nickname:
|
||||
admin_actor = '/users/' + admin_nickname
|
||||
specification_form += \
|
||||
'<div class="container"><center>\n' + \
|
||||
'<p class="administeredby">' + \
|
||||
translate['Administered by'] + ' <a href="' + \
|
||||
admin_actor + '">' + admin_nickname + '</a>. ' + \
|
||||
translate['Version'] + ' ' + __version__ + \
|
||||
'</p>\n</center></div>\n'
|
||||
specification_form += html_footer()
|
||||
return specification_form
|
Loading…
Reference in New Issue