mirror of https://gitlab.com/bashrc2/epicyon
				
				
				
			
		
			
				
	
	
		
			750 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			750 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Python
		
	
	
| __filename__ = "webapp_column_right.py"
 | |
| __author__ = "Bob Mottram"
 | |
| __license__ = "AGPL3+"
 | |
| __version__ = "1.3.0"
 | |
| __maintainer__ = "Bob Mottram"
 | |
| __email__ = "bob@libreserver.org"
 | |
| __status__ = "Production"
 | |
| __module_group__ = "Web Interface Columns"
 | |
| 
 | |
| import os
 | |
| from datetime import datetime
 | |
| from content import remove_long_words
 | |
| from content import limit_repeated_words
 | |
| from utils import get_fav_filename_from_url
 | |
| from utils import get_base_content_from_post
 | |
| from utils import remove_html
 | |
| from utils import locate_post
 | |
| from utils import load_json
 | |
| from utils import votes_on_newswire_item
 | |
| from utils import get_nickname_from_actor
 | |
| from utils import is_editor
 | |
| from utils import get_config_param
 | |
| from utils import remove_domain_port
 | |
| from utils import acct_dir
 | |
| from posts import is_moderator
 | |
| from newswire import get_newswire_favicon_url
 | |
| from webapp_utils import get_right_image_file
 | |
| from webapp_utils import html_header_with_external_style
 | |
| from webapp_utils import html_footer
 | |
| from webapp_utils import get_banner_file
 | |
| from webapp_utils import html_post_separator
 | |
| from webapp_utils import header_buttons_front_screen
 | |
| from webapp_utils import edit_text_field
 | |
| 
 | |
| 
 | |
| def _votes_indicator(total_votes: int, positive_voting: bool) -> str:
 | |
|     """Returns an indicator of the number of votes on a newswire item
 | |
|     """
 | |
|     if total_votes <= 0:
 | |
|         return ''
 | |
|     total_votes_str = ' '
 | |
|     for _ in range(total_votes):
 | |
|         if positive_voting:
 | |
|             total_votes_str += '✓'
 | |
|         else:
 | |
|             total_votes_str += '✗'
 | |
|     return total_votes_str
 | |
| 
 | |
| 
 | |
| def get_right_column_content(base_dir: str, nickname: str, domain_full: str,
 | |
|                              http_prefix: str, translate: {},
 | |
|                              moderator: bool, editor: bool,
 | |
|                              newswire: {}, positive_voting: bool,
 | |
|                              show_back_button: bool, timeline_path: str,
 | |
|                              show_publish_button: bool,
 | |
|                              show_publish_as_icon: bool,
 | |
|                              rss_icon_at_top: bool,
 | |
|                              publish_button_at_top: bool,
 | |
|                              authorized: bool,
 | |
|                              show_header_image: bool,
 | |
|                              theme: str,
 | |
|                              default_timeline: str,
 | |
|                              access_keys: {}) -> str:
 | |
|     """Returns html content for the right column
 | |
|     """
 | |
|     html_str = ''
 | |
| 
 | |
|     domain = remove_domain_port(domain_full)
 | |
| 
 | |
|     if authorized:
 | |
|         # only show the publish button if logged in, otherwise replace it with
 | |
|         # a login button
 | |
|         title_str = translate['Publish a blog article']
 | |
|         if default_timeline == 'tlfeatures':
 | |
|             title_str = translate['Publish a news article']
 | |
|         publish_button_str = \
 | |
|             '        <a href="' + \
 | |
|             '/users/' + nickname + '/newblog?nodropdown" ' + \
 | |
|             'title="' + title_str + '" ' + \
 | |
|             'accesskey="' + access_keys['menuNewBlog'] + '">' + \
 | |
|             '<button class="publishbtn" tabindex="4">' + \
 | |
|             translate['Publish'] + '</button></a>\n'
 | |
|     else:
 | |
|         # if not logged in then replace the publish button with
 | |
|         # a login button
 | |
|         publish_button_str = \
 | |
|             '        <a href="/login">' + \
 | |
|             '<button class="publishbtn" tabindex="4">' + \
 | |
|             translate['Login'] + '</button></a>\n'
 | |
| 
 | |
|     # show publish button at the top if needed
 | |
|     if publish_button_at_top:
 | |
|         html_str += '<center>' + publish_button_str + '</center>'
 | |
| 
 | |
|     # show a column header image, eg. title of the theme or newswire banner
 | |
|     edit_image_class = ''
 | |
|     if show_header_image:
 | |
|         right_image_file, right_column_image_filename = \
 | |
|             get_right_image_file(base_dir, nickname, domain, theme)
 | |
| 
 | |
|         # show the image at the top of the column
 | |
|         edit_image_class = 'rightColEdit'
 | |
|         if os.path.isfile(right_column_image_filename):
 | |
|             edit_image_class = 'rightColEditImage'
 | |
|             html_str += \
 | |
|                 '\n      <center>\n' + \
 | |
|                 '          <img class="rightColImg" ' + \
 | |
|                 'alt="" loading="lazy" decoding="async" src="/users/' + \
 | |
|                 nickname + '/' + right_image_file + '" />\n' + \
 | |
|                 '      </center>\n'
 | |
| 
 | |
|     if show_publish_button or editor or rss_icon_at_top:
 | |
|         if not show_header_image:
 | |
|             html_str += '<div class="columnIcons">'
 | |
| 
 | |
|     if edit_image_class == 'rightColEdit':
 | |
|         html_str += '\n      <center>\n'
 | |
| 
 | |
|     # whether to show a back icon
 | |
|     # This is probably going to be osolete soon
 | |
|     if show_back_button:
 | |
|         html_str += \
 | |
|             '      <a href="' + timeline_path + '">' + \
 | |
|             '<button class="cancelbtn">' + \
 | |
|             translate['Go Back'] + '</button></a>\n'
 | |
| 
 | |
|     if show_publish_button and not publish_button_at_top:
 | |
|         if not show_publish_as_icon:
 | |
|             html_str += publish_button_str
 | |
| 
 | |
|     # show the edit icon
 | |
|     if editor:
 | |
|         if os.path.isfile(base_dir + '/accounts/newswiremoderation.txt'):
 | |
|             # show the edit icon highlighted
 | |
|             html_str += \
 | |
|                 '        <a href="' + \
 | |
|                 '/users/' + nickname + '/editnewswire" ' + \
 | |
|                 'accesskey="' + access_keys['menuEdit'] + \
 | |
|                 '" tabindex="4" class="imageAnchor">' + \
 | |
|                 '<img class="' + edit_image_class + \
 | |
|                 '" loading="lazy" decoding="async" alt="' + \
 | |
|                 translate['Edit newswire'] + ' | " title="' + \
 | |
|                 translate['Edit newswire'] + '" src="/' + \
 | |
|                 'icons/edit_notify.png" /></a>\n'
 | |
|         else:
 | |
|             # show the edit icon
 | |
|             html_str += \
 | |
|                 '        <a href="' + \
 | |
|                 '/users/' + nickname + '/editnewswire" ' + \
 | |
|                 'accesskey="' + access_keys['menuEdit'] + \
 | |
|                 '" tabindex="4" class="imageAnchor">' + \
 | |
|                 '<img class="' + edit_image_class + \
 | |
|                 '" loading="lazy" decoding="async" alt="' + \
 | |
|                 translate['Edit newswire'] + ' | " title="' + \
 | |
|                 translate['Edit newswire'] + '" src="/' + \
 | |
|                 'icons/edit.png" /></a>\n'
 | |
| 
 | |
|     # show the RSS icons
 | |
|     rss_icon_str = \
 | |
|         '        <a href="/categories.xml" tabindex="4" ' + \
 | |
|         'class="imageAnchor">' + \
 | |
|         '<img class="' + edit_image_class + \
 | |
|         '" loading="lazy" decoding="async" alt="' + \
 | |
|         translate['Hashtag Categories RSS Feed'] + ' | " title="' + \
 | |
|         translate['Hashtag Categories RSS Feed'] + '" src="/' + \
 | |
|         'icons/categoriesrss.png" /></a>\n'
 | |
|     rss_icon_str += \
 | |
|         '        <a href="/newswire.xml" tabindex="4" class="imageAnchor">' + \
 | |
|         '<img class="' + edit_image_class + \
 | |
|         '" loading="lazy" decoding="async" alt="' + \
 | |
|         translate['Newswire RSS Feed'] + ' | " title="' + \
 | |
|         translate['Newswire RSS Feed'] + '" src="/' + \
 | |
|         'icons/logorss.png" /></a>\n'
 | |
|     if rss_icon_at_top:
 | |
|         html_str += rss_icon_str
 | |
| 
 | |
|     # show publish icon at top
 | |
|     if show_publish_button:
 | |
|         if show_publish_as_icon:
 | |
|             title_str = translate['Publish a blog article']
 | |
|             if default_timeline == 'tlfeatures':
 | |
|                 title_str = translate['Publish a news article']
 | |
|             html_str += \
 | |
|                 '        <a href="' + \
 | |
|                 '/users/' + nickname + '/newblog?nodropdown" ' + \
 | |
|                 'accesskey="' + access_keys['menuNewBlog'] + \
 | |
|                 '" class="imageAnchor" tabindex="4">' + \
 | |
|                 '<img class="' + edit_image_class + \
 | |
|                 '" loading="lazy" decoding="async" alt="' + \
 | |
|                 title_str + '" title="' + \
 | |
|                 title_str + '" src="/' + \
 | |
|                 'icons/publish.png" /></a>\n'
 | |
| 
 | |
|     if edit_image_class == 'rightColEdit':
 | |
|         html_str += '      </center>\n'
 | |
|     else:
 | |
|         if show_header_image:
 | |
|             html_str += '      <br>\n'
 | |
| 
 | |
|     if show_publish_button or editor or rss_icon_at_top:
 | |
|         if not show_header_image:
 | |
|             html_str += '</div><br>'
 | |
| 
 | |
|     # show the newswire lines
 | |
|     newswire_content_str = \
 | |
|         _html_newswire(base_dir, newswire, nickname, moderator, translate,
 | |
|                        positive_voting)
 | |
|     html_str += newswire_content_str
 | |
| 
 | |
|     # show the rss icon at the bottom, typically on the right hand side
 | |
|     if newswire_content_str and not rss_icon_at_top:
 | |
|         html_str += '<br><div class="columnIcons">' + rss_icon_str + '</div>'
 | |
|     return html_str
 | |
| 
 | |
| 
 | |
| def _get_broken_fav_substitute() -> str:
 | |
|     """Substitute link used if a favicon is not available
 | |
|     """
 | |
|     return " onerror=\"this.onerror=null; this.src='/newswire_favicon.ico'\""
 | |
| 
 | |
| 
 | |
| def _html_newswire(base_dir: str, newswire: {}, nickname: str, moderator: bool,
 | |
|                    translate: {}, positive_voting: bool) -> str:
 | |
|     """Converts a newswire dict into html
 | |
|     """
 | |
|     separator_str = html_post_separator(base_dir, 'right')
 | |
|     html_str = ''
 | |
|     for date_str, item in newswire.items():
 | |
|         item[0] = remove_html(item[0]).strip()
 | |
|         if not item[0]:
 | |
|             continue
 | |
|         # remove any CDATA
 | |
|         if 'CDATA[' in item[0]:
 | |
|             item[0] = item[0].split('CDATA[')[1]
 | |
|             if ']' in item[0]:
 | |
|                 item[0] = item[0].split(']')[0]
 | |
|         try:
 | |
|             published_date = \
 | |
|                 datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S%z")
 | |
|         except BaseException:
 | |
|             print('EX: _html_newswire bad date format ' + date_str)
 | |
|             continue
 | |
|         date_shown = published_date.strftime("%Y-%m-%d %H:%M")
 | |
| 
 | |
|         date_str_link = date_str.replace('T', ' ')
 | |
|         date_str_link = date_str_link.replace('Z', '')
 | |
|         url = item[1]
 | |
|         favicon_url = get_newswire_favicon_url(url)
 | |
|         favicon_link = ''
 | |
|         if favicon_url:
 | |
|             cached_favicon_filename = \
 | |
|                 get_fav_filename_from_url(base_dir, favicon_url)
 | |
|             if os.path.isfile(cached_favicon_filename):
 | |
|                 favicon_url = \
 | |
|                     cached_favicon_filename.replace(base_dir, '')
 | |
|             else:
 | |
|                 extensions = \
 | |
|                     ('png', 'jpg', 'gif', 'avif', 'svg', 'webp', 'jxl')
 | |
|                 for ext in extensions:
 | |
|                     cached_favicon_filename = \
 | |
|                         get_fav_filename_from_url(base_dir, favicon_url)
 | |
|                     cached_favicon_filename = \
 | |
|                         cached_favicon_filename.replace('.ico', '.' + ext)
 | |
|                     if os.path.isfile(cached_favicon_filename):
 | |
|                         favicon_url = \
 | |
|                             cached_favicon_filename.replace(base_dir, '')
 | |
| 
 | |
|             favicon_link = \
 | |
|                 '<img loading="lazy" decoding="async" ' + \
 | |
|                 'src="' + favicon_url + '" ' + \
 | |
|                 'alt="" ' + _get_broken_fav_substitute() + '/>'
 | |
|         moderated_item = item[5]
 | |
|         link_url = url
 | |
| 
 | |
|         # is this a podcast episode?
 | |
|         if len(item) > 8:
 | |
|             # change the link url to a podcast episode screen
 | |
|             podcast_properties = item[8]
 | |
|             if podcast_properties:
 | |
|                 if podcast_properties.get('image'):
 | |
|                     episode_id = date_str.replace(' ', '__')
 | |
|                     episode_id = episode_id.replace(':', 'aa')
 | |
|                     link_url = \
 | |
|                         '/users/' + nickname + '/?podepisode=' + episode_id
 | |
| 
 | |
|         html_str += separator_str
 | |
|         if moderated_item and 'vote:' + nickname in item[2]:
 | |
|             total_votes_str = ''
 | |
|             total_votes = 0
 | |
|             if moderator:
 | |
|                 total_votes = votes_on_newswire_item(item[2])
 | |
|                 total_votes_str = \
 | |
|                     _votes_indicator(total_votes, positive_voting)
 | |
| 
 | |
|             title = remove_long_words(item[0], 16, []).replace('\n', '<br>')
 | |
|             title = limit_repeated_words(title, 6)
 | |
|             html_str += '<p class="newswireItemVotedOn">' + \
 | |
|                 '<a href="' + link_url + '" target="_blank" ' + \
 | |
|                 'rel="nofollow noopener noreferrer">' + \
 | |
|                 '<span class="newswireItemVotedOn">' + \
 | |
|                 favicon_link + title + '</span></a>' + total_votes_str
 | |
|             if moderator:
 | |
|                 html_str += \
 | |
|                     ' ' + date_shown + '<a href="/users/' + nickname + \
 | |
|                     '/newswireunvote=' + date_str_link + '" ' + \
 | |
|                     'title="' + translate['Remove Vote'] + \
 | |
|                     '" class="imageAnchor">'
 | |
|                 html_str += '<img loading="lazy" decoding="async" ' + \
 | |
|                     'class="voteicon" src="/' + \
 | |
|                     'alt="' + translate['Remove Vote'] + '" ' + \
 | |
|                     'icons/vote.png" /></a></p>\n'
 | |
|             else:
 | |
|                 html_str += ' <span class="newswireDateVotedOn">'
 | |
|                 html_str += date_shown + '</span></p>\n'
 | |
|         else:
 | |
|             total_votes_str = ''
 | |
|             total_votes = 0
 | |
|             if moderator:
 | |
|                 if moderated_item:
 | |
|                     total_votes = votes_on_newswire_item(item[2])
 | |
|                     # show a number of ticks or crosses for how many
 | |
|                     # votes for or against
 | |
|                     total_votes_str = \
 | |
|                         _votes_indicator(total_votes, positive_voting)
 | |
| 
 | |
|             title = remove_long_words(item[0], 16, []).replace('\n', '<br>')
 | |
|             title = limit_repeated_words(title, 6)
 | |
|             if moderator and moderated_item:
 | |
|                 html_str += '<p class="newswireItemModerated">' + \
 | |
|                     '<a href="' + link_url + '" target="_blank" ' + \
 | |
|                     'rel="nofollow noopener noreferrer">' + \
 | |
|                     favicon_link + title + '</a>' + total_votes_str
 | |
|                 html_str += ' ' + date_shown
 | |
|                 html_str += '<a href="/users/' + nickname + \
 | |
|                     '/newswirevote=' + date_str_link + '" ' + \
 | |
|                     'title="' + translate['Vote'] + '" class="imageAnchor">'
 | |
|                 html_str += '<img class="voteicon" ' + \
 | |
|                     'alt="' + translate['Vote'] + '" ' + \
 | |
|                     'src="/icons/vote.png" /></a>'
 | |
|                 html_str += '</p>\n'
 | |
|             else:
 | |
|                 html_str += '<p class="newswireItem">' + \
 | |
|                     '<a href="' + link_url + '" target="_blank" ' + \
 | |
|                     'rel="nofollow noopener noreferrer">' + \
 | |
|                     favicon_link + title + '</a>' + total_votes_str
 | |
|                 html_str += ' <span class="newswireDate">'
 | |
|                 html_str += date_shown + '</span></p>\n'
 | |
| 
 | |
|     if html_str:
 | |
|         html_str = \
 | |
|             '<nav itemscope itemtype="http://schema.org/webFeed">\n' + \
 | |
|             html_str + '</nav>\n'
 | |
|     return html_str
 | |
| 
 | |
| 
 | |
| def html_citations(base_dir: str, nickname: str, domain: str,
 | |
|                    http_prefix: str, default_timeline: str,
 | |
|                    translate: {}, newswire: {}, css_cache: {},
 | |
|                    blog_title: str, blog_content: str,
 | |
|                    blog_image_filename: str,
 | |
|                    blog_image_attachment_media_type: str,
 | |
|                    blog_image_description: str,
 | |
|                    theme: str) -> str:
 | |
|     """Show the citations screen when creating a blog
 | |
|     """
 | |
|     html_str = ''
 | |
| 
 | |
|     # create a list of dates for citations
 | |
|     # these can then be used to re-select checkboxes later
 | |
|     citations_filename = \
 | |
|         acct_dir(base_dir, nickname, domain) + '/.citations.txt'
 | |
|     citations_selected = []
 | |
|     if os.path.isfile(citations_filename):
 | |
|         citations_separator = '#####'
 | |
|         with open(citations_filename, 'r', encoding='utf-8') as fp_cit:
 | |
|             citations = fp_cit.readlines()
 | |
|             for line in citations:
 | |
|                 if citations_separator not in line:
 | |
|                     continue
 | |
|                 sections = line.strip().split(citations_separator)
 | |
|                 if len(sections) != 3:
 | |
|                     continue
 | |
|                 date_str = sections[0]
 | |
|                 citations_selected.append(date_str)
 | |
| 
 | |
|     # the css filename
 | |
|     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')
 | |
|     html_str = \
 | |
|         html_header_with_external_style(css_filename, instance_title, None)
 | |
| 
 | |
|     # top banner
 | |
|     banner_file, _ = \
 | |
|         get_banner_file(base_dir, nickname, domain, theme)
 | |
|     html_str += \
 | |
|         '<a href="/users/' + nickname + '/newblog" title="' + \
 | |
|         translate['Go Back'] + '" alt="' + \
 | |
|         translate['Go Back'] + '" class="imageAnchor">\n'
 | |
|     html_str += '<img loading="lazy" decoding="async" ' + \
 | |
|         'class="timeline-banner" alt="" src="' + \
 | |
|         '/users/' + nickname + '/' + banner_file + '" /></a>\n'
 | |
| 
 | |
|     html_str += \
 | |
|         '<form enctype="multipart/form-data" method="POST" ' + \
 | |
|         'accept-charset="UTF-8" action="/users/' + nickname + \
 | |
|         '/citationsdata">\n'
 | |
|     html_str += '  <center>\n'
 | |
|     html_str += translate['Choose newswire items ' +
 | |
|                           'referenced in your article'] + '<br>'
 | |
|     if blog_title is None:
 | |
|         blog_title = ''
 | |
|     html_str += \
 | |
|         '    <input type="hidden" name="blogTitle" value="' + \
 | |
|         blog_title + '">\n'
 | |
|     if blog_content is None:
 | |
|         blog_content = ''
 | |
|     html_str += \
 | |
|         '    <input type="hidden" name="blogContent" value="' + \
 | |
|         blog_content + '">\n'
 | |
|     # submit button
 | |
|     html_str += \
 | |
|         '    <input type="submit" name="submitCitations" value="' + \
 | |
|         translate['Publish'] + '">\n'
 | |
|     html_str += '  </center>\n'
 | |
| 
 | |
|     citations_separator = '#####'
 | |
| 
 | |
|     # list of newswire items
 | |
|     if newswire:
 | |
|         ctr = 0
 | |
|         for date_str, item in newswire.items():
 | |
|             item[0] = remove_html(item[0]).strip()
 | |
|             if not item[0]:
 | |
|                 continue
 | |
|             # remove any CDATA
 | |
|             if 'CDATA[' in item[0]:
 | |
|                 item[0] = item[0].split('CDATA[')[1]
 | |
|                 if ']' in item[0]:
 | |
|                     item[0] = item[0].split(']')[0]
 | |
|             # should this checkbox be selected?
 | |
|             selected_str = ''
 | |
|             if date_str in citations_selected:
 | |
|                 selected_str = ' checked'
 | |
| 
 | |
|             published_date = \
 | |
|                 datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S%z")
 | |
|             date_shown = published_date.strftime("%Y-%m-%d %H:%M")
 | |
| 
 | |
|             title = remove_long_words(item[0], 16, []).replace('\n', '<br>')
 | |
|             title = limit_repeated_words(title, 6)
 | |
|             link = item[1]
 | |
| 
 | |
|             citation_value = \
 | |
|                 date_str + citations_separator + \
 | |
|                 title + citations_separator + \
 | |
|                 link
 | |
|             html_str += \
 | |
|                 '<input type="checkbox" name="newswire' + str(ctr) + \
 | |
|                 '" value="' + citation_value + '"' + selected_str + '/>' + \
 | |
|                 '<a href="' + link + '"><cite>' + title + '</cite></a> '
 | |
|             html_str += '<span class="newswireDate">' + \
 | |
|                 date_shown + '</span><br>\n'
 | |
|             ctr += 1
 | |
| 
 | |
|     html_str += '</form>\n'
 | |
|     return html_str + html_footer()
 | |
| 
 | |
| 
 | |
| def html_newswire_mobile(css_cache: {}, base_dir: str, nickname: str,
 | |
|                          domain: str, domain_full: str,
 | |
|                          http_prefix: str, translate: {},
 | |
|                          newswire: {},
 | |
|                          positive_voting: bool,
 | |
|                          timeline_path: str,
 | |
|                          show_publish_as_icon: bool,
 | |
|                          authorized: bool,
 | |
|                          rss_icon_at_top: bool,
 | |
|                          icons_as_buttons: bool,
 | |
|                          default_timeline: str,
 | |
|                          theme: str,
 | |
|                          access_keys: {}) -> str:
 | |
|     """Shows the mobile version of the newswire right column
 | |
|     """
 | |
|     html_str = ''
 | |
| 
 | |
|     # the css filename
 | |
|     css_filename = base_dir + '/epicyon-profile.css'
 | |
|     if os.path.isfile(base_dir + '/epicyon.css'):
 | |
|         css_filename = base_dir + '/epicyon.css'
 | |
| 
 | |
|     if nickname == 'news':
 | |
|         editor = False
 | |
|         moderator = False
 | |
|     else:
 | |
|         # is the user a moderator?
 | |
|         moderator = is_moderator(base_dir, nickname)
 | |
| 
 | |
|         # is the user a site editor?
 | |
|         editor = is_editor(base_dir, nickname)
 | |
| 
 | |
|     show_publish_button = editor
 | |
| 
 | |
|     instance_title = \
 | |
|         get_config_param(base_dir, 'instanceTitle')
 | |
|     html_str = \
 | |
|         html_header_with_external_style(css_filename, instance_title, None)
 | |
| 
 | |
|     banner_file, _ = \
 | |
|         get_banner_file(base_dir, nickname, domain, theme)
 | |
|     html_str += \
 | |
|         '<a href="/users/' + nickname + '/' + default_timeline + '" ' + \
 | |
|         'accesskey="' + access_keys['menuTimeline'] + '" ' + \
 | |
|         'class="imageAnchor">' + \
 | |
|         '<img loading="lazy" decoding="async" class="timeline-banner" ' + \
 | |
|         'alt="' + translate['Timeline banner image'] + '" ' + \
 | |
|         'src="/users/' + nickname + '/' + banner_file + '" /></a>\n'
 | |
| 
 | |
|     html_str += '<div class="col-right-mobile">\n'
 | |
| 
 | |
|     html_str += '<center>' + \
 | |
|         header_buttons_front_screen(translate, nickname,
 | |
|                                     'newswire', authorized,
 | |
|                                     icons_as_buttons) + '</center>'
 | |
|     html_str += \
 | |
|         get_right_column_content(base_dir, nickname, domain_full,
 | |
|                                  http_prefix, translate,
 | |
|                                  moderator, editor,
 | |
|                                  newswire, positive_voting,
 | |
|                                  False, timeline_path, show_publish_button,
 | |
|                                  show_publish_as_icon, rss_icon_at_top, False,
 | |
|                                  authorized, False, theme,
 | |
|                                  default_timeline, access_keys)
 | |
|     if editor and not newswire:
 | |
|         html_str += '<br><br><br>\n'
 | |
|         html_str += '<center>\n  '
 | |
|         html_str += translate['Select the edit icon to add RSS feeds']
 | |
|         html_str += '\n</center>\n'
 | |
|     # end of col-right-mobile
 | |
|     html_str += '</div\n>'
 | |
| 
 | |
|     html_str += html_footer()
 | |
|     return html_str
 | |
| 
 | |
| 
 | |
| def html_edit_newswire(css_cache: {}, translate: {}, base_dir: str, path: str,
 | |
|                        domain: str, port: int, http_prefix: str,
 | |
|                        default_timeline: str, theme: str,
 | |
|                        access_keys: {}) -> str:
 | |
|     """Shows the edit newswire screen
 | |
|     """
 | |
|     if '/users/' not in path:
 | |
|         return ''
 | |
|     path = path.replace('/inbox', '').replace('/outbox', '')
 | |
|     path = path.replace('/shares', '').replace('/wanted', '')
 | |
| 
 | |
|     nickname = get_nickname_from_actor(path)
 | |
|     if not nickname:
 | |
|         return ''
 | |
| 
 | |
|     # is the user a moderator?
 | |
|     if not is_moderator(base_dir, nickname):
 | |
|         return ''
 | |
| 
 | |
|     css_filename = base_dir + '/epicyon-links.css'
 | |
|     if os.path.isfile(base_dir + '/links.css'):
 | |
|         css_filename = base_dir + '/links.css'
 | |
| 
 | |
|     # filename of the banner shown at the top
 | |
|     banner_file, _ = \
 | |
|         get_banner_file(base_dir, nickname, domain, theme)
 | |
| 
 | |
|     instance_title = \
 | |
|         get_config_param(base_dir, 'instanceTitle')
 | |
|     edit_newswire_form = \
 | |
|         html_header_with_external_style(css_filename, instance_title, None)
 | |
| 
 | |
|     # top banner
 | |
|     edit_newswire_form += \
 | |
|         '<header>' + \
 | |
|         '<a href="/users/' + nickname + '/' + default_timeline + \
 | |
|         '" title="' + \
 | |
|         translate['Switch to timeline view'] + '" alt="' + \
 | |
|         translate['Switch to timeline view'] + '" ' + \
 | |
|         'accesskey="' + access_keys['menuTimeline'] + '">\n'
 | |
|     edit_newswire_form += \
 | |
|         '<img loading="lazy" decoding="async" ' + \
 | |
|         'class="timeline-banner" src="' + \
 | |
|         '/users/' + nickname + '/' + banner_file + '" ' + \
 | |
|         'alt="" /></a>\n</header>'
 | |
| 
 | |
|     edit_newswire_form += \
 | |
|         '<form enctype="multipart/form-data" method="POST" ' + \
 | |
|         'accept-charset="UTF-8" action="' + path + '/newswiredata">\n'
 | |
|     edit_newswire_form += \
 | |
|         '  <div class="vertical-center">\n'
 | |
|     edit_newswire_form += \
 | |
|         '    <h1>' + translate['Edit newswire'] + '</h1>'
 | |
|     edit_newswire_form += \
 | |
|         '    <div class="containerSubmitNewPost">\n'
 | |
|     edit_newswire_form += \
 | |
|         '      <input type="submit" name="submitNewswire" value="' + \
 | |
|         translate['Publish'] + '" ' + \
 | |
|         'accesskey="' + access_keys['submitButton'] + '">\n'
 | |
|     edit_newswire_form += \
 | |
|         '    </div>\n'
 | |
| 
 | |
|     newswire_filename = base_dir + '/accounts/newswire.txt'
 | |
|     newswire_str = ''
 | |
|     if os.path.isfile(newswire_filename):
 | |
|         with open(newswire_filename, 'r', encoding='utf-8') as fp_news:
 | |
|             newswire_str = fp_news.read()
 | |
| 
 | |
|     edit_newswire_form += \
 | |
|         '<div class="container">'
 | |
| 
 | |
|     edit_newswire_form += \
 | |
|         '  ' + \
 | |
|         translate['Add RSS feed links below.'] + \
 | |
|         '<br>'
 | |
|     new_feed_str = translate['New feed URL']
 | |
|     edit_newswire_form += \
 | |
|         edit_text_field(None, 'newNewswireFeed', '', new_feed_str)
 | |
|     edit_newswire_form += \
 | |
|         '  <textarea id="message" name="editedNewswire" ' + \
 | |
|         'style="height:80vh" spellcheck="false">' + \
 | |
|         newswire_str + '</textarea>'
 | |
| 
 | |
|     filter_str = ''
 | |
|     filter_filename = \
 | |
|         base_dir + '/accounts/news@' + domain + '/filters.txt'
 | |
|     if os.path.isfile(filter_filename):
 | |
|         with open(filter_filename, 'r', encoding='utf-8') as filterfile:
 | |
|             filter_str = filterfile.read()
 | |
| 
 | |
|     edit_newswire_form += \
 | |
|         '      <br><b><label class="labels">' + \
 | |
|         translate['Filtered words'] + '</label></b>\n'
 | |
|     edit_newswire_form += '      <br><label class="labels">' + \
 | |
|         translate['One per line'] + '</label>'
 | |
|     edit_newswire_form += '      <textarea id="message" ' + \
 | |
|         'name="filteredWordsNewswire" style="height:50vh" ' + \
 | |
|         'spellcheck="true">' + filter_str + '</textarea>\n'
 | |
| 
 | |
|     hashtag_rules_str = ''
 | |
|     hashtag_rules_filename = \
 | |
|         base_dir + '/accounts/hashtagrules.txt'
 | |
|     if os.path.isfile(hashtag_rules_filename):
 | |
|         with open(hashtag_rules_filename, 'r', encoding='utf-8') as rulesfile:
 | |
|             hashtag_rules_str = rulesfile.read()
 | |
| 
 | |
|     edit_newswire_form += \
 | |
|         '      <br><b><label class="labels">' + \
 | |
|         translate['News tagging rules'] + '</label></b>\n'
 | |
|     edit_newswire_form += '      <br><label class="labels">' + \
 | |
|         translate['One per line'] + '.</label>\n'
 | |
|     edit_newswire_form += \
 | |
|         '      <a href="' + \
 | |
|         'https://gitlab.com/bashrc2/epicyon/-/raw/main/hashtagrules.txt' + \
 | |
|         '">' + translate['See instructions'] + '</a>\n'
 | |
|     edit_newswire_form += '      <textarea id="message" ' + \
 | |
|         'name="hashtagRulesList" style="height:80vh" spellcheck="false">' + \
 | |
|         hashtag_rules_str + '</textarea>\n'
 | |
| 
 | |
|     edit_newswire_form += \
 | |
|         '</div>'
 | |
| 
 | |
|     edit_newswire_form += html_footer()
 | |
|     return edit_newswire_form
 | |
| 
 | |
| 
 | |
| def html_edit_news_post(css_cache: {}, translate: {}, base_dir: str, path: str,
 | |
|                         domain: str, port: int, http_prefix: str, postUrl: str,
 | |
|                         system_language: str) -> str:
 | |
|     """Edits a news post on the news/features timeline
 | |
|     """
 | |
|     if '/users/' not in path:
 | |
|         return ''
 | |
|     path_original = path
 | |
| 
 | |
|     nickname = get_nickname_from_actor(path)
 | |
|     if not nickname:
 | |
|         return ''
 | |
| 
 | |
|     # is the user an editor?
 | |
|     if not is_editor(base_dir, nickname):
 | |
|         return ''
 | |
| 
 | |
|     postUrl = postUrl.replace('/', '#')
 | |
|     post_filename = locate_post(base_dir, nickname, domain, postUrl)
 | |
|     if not post_filename:
 | |
|         return ''
 | |
|     post_json_object = load_json(post_filename)
 | |
|     if not post_json_object:
 | |
|         return ''
 | |
| 
 | |
|     css_filename = base_dir + '/epicyon-links.css'
 | |
|     if os.path.isfile(base_dir + '/links.css'):
 | |
|         css_filename = base_dir + '/links.css'
 | |
| 
 | |
|     instance_title = \
 | |
|         get_config_param(base_dir, 'instanceTitle')
 | |
|     edit_news_post_form = \
 | |
|         html_header_with_external_style(css_filename, instance_title, None)
 | |
|     edit_news_post_form += \
 | |
|         '<form enctype="multipart/form-data" method="POST" ' + \
 | |
|         'accept-charset="UTF-8" action="' + path + '/newseditdata">\n'
 | |
|     edit_news_post_form += \
 | |
|         '  <div class="vertical-center">\n'
 | |
|     edit_news_post_form += \
 | |
|         '    <h1>' + translate['Edit News Post'] + '</h1>'
 | |
|     edit_news_post_form += \
 | |
|         '    <div class="container">\n'
 | |
|     edit_news_post_form += \
 | |
|         '      <a href="' + path_original + '/tlnews">' + \
 | |
|         '<button class="cancelbtn">' + translate['Go Back'] + '</button></a>\n'
 | |
|     edit_news_post_form += \
 | |
|         '      <input type="submit" name="submitEditedNewsPost" value="' + \
 | |
|         translate['Publish'] + '">\n'
 | |
|     edit_news_post_form += \
 | |
|         '    </div>\n'
 | |
| 
 | |
|     edit_news_post_form += \
 | |
|         '<div class="container">'
 | |
| 
 | |
|     edit_news_post_form += \
 | |
|         '  <input type="hidden" name="newsPostUrl" value="' + \
 | |
|         postUrl + '">\n'
 | |
| 
 | |
|     news_post_title = post_json_object['object']['summary']
 | |
|     edit_news_post_form += \
 | |
|         '  <input type="text" name="newsPostTitle" value="' + \
 | |
|         news_post_title + '"><br>\n'
 | |
| 
 | |
|     news_post_content = get_base_content_from_post(post_json_object,
 | |
|                                                    system_language)
 | |
|     edit_news_post_form += \
 | |
|         '  <textarea id="message" name="editedNewsPost" ' + \
 | |
|         'style="height:600px" spellcheck="true">' + \
 | |
|         news_post_content + '</textarea>'
 | |
| 
 | |
|     edit_news_post_form += \
 | |
|         '</div>'
 | |
| 
 | |
|     edit_news_post_form += html_footer()
 | |
|     return edit_news_post_form
 |