__filename__ = "webapp_column_left.py" __author__ = "Bob Mottram" __license__ = "AGPL3+" __version__ = "1.2.0" __maintainer__ = "Bob Mottram" __email__ = "bob@libreserver.org" __status__ = "Production" __module_group__ = "Web Interface Columns" import os from utils import getConfigParam from utils import getNicknameFromActor from utils import isEditor from utils import isArtist from utils import removeDomainPort from utils import localActorUrl from webapp_utils import sharesTimelineJson from webapp_utils import htmlPostSeparator from webapp_utils import getLeftImageFile from webapp_utils import headerButtonsFrontScreen from webapp_utils import htmlHeaderWithExternalStyle from webapp_utils import htmlFooter from webapp_utils import getBannerFile from webapp_utils import editTextField from shares import shareCategoryIcon def _linksExist(baseDir: str) -> bool: """Returns true if links have been created """ linksFilename = baseDir + '/accounts/links.txt' return os.path.isfile(linksFilename) def _getLeftColumnShares(baseDir: str, httpPrefix: str, domain: str, domainFull: str, nickname: str, maxSharesInLeftColumn: int, translate: {}, sharedItemsFederatedDomains: []) -> []: """get any shares and turn them into the left column links format """ pageNumber = 1 actor = localActorUrl(httpPrefix, nickname, domainFull) # NOTE: this could potentially be slow if the number of federated # shared items is large sharesJson, lastPage = \ sharesTimelineJson(actor, pageNumber, maxSharesInLeftColumn, baseDir, domain, nickname, maxSharesInLeftColumn, sharedItemsFederatedDomains, 'shares') if not sharesJson: return [] linksList = [] ctr = 0 for published, item in sharesJson.items(): sharedesc = item['displayName'] if '<' in sharedesc or '?' in sharedesc: continue shareId = item['shareId'] # selecting this link calls htmlShowShare shareLink = actor + '?showshare=' + shareId if item.get('category'): shareLink += '?category=' + item['category'] shareCategory = shareCategoryIcon(item['category']) linksList.append(shareCategory + sharedesc + ' ' + shareLink) ctr += 1 if ctr >= maxSharesInLeftColumn: break if linksList: linksList = ['* ' + translate['Shares']] + linksList return linksList def _getLeftColumnWanted(baseDir: str, httpPrefix: str, domain: str, domainFull: str, nickname: str, maxSharesInLeftColumn: int, translate: {}, sharedItemsFederatedDomains: []) -> []: """get any wanted items and turn them into the left column links format """ pageNumber = 1 actor = localActorUrl(httpPrefix, nickname, domainFull) # NOTE: this could potentially be slow if the number of federated # wanted items is large sharesJson, lastPage = \ sharesTimelineJson(actor, pageNumber, maxSharesInLeftColumn, baseDir, domain, nickname, maxSharesInLeftColumn, sharedItemsFederatedDomains, 'wanted') if not sharesJson: return [] linksList = [] ctr = 0 for published, item in sharesJson.items(): sharedesc = item['displayName'] if '<' in sharedesc or ';' in sharedesc: continue shareId = item['shareId'] # selecting this link calls htmlShowShare shareLink = actor + '?showwanted=' + shareId linksList.append(sharedesc + ' ' + shareLink) ctr += 1 if ctr >= maxSharesInLeftColumn: break if linksList: linksList = ['* ' + translate['Wanted']] + linksList return linksList def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str, httpPrefix: str, translate: {}, editor: bool, artist: bool, showBackButton: bool, timelinePath: str, rssIconAtTop: bool, showHeaderImage: bool, frontPage: bool, theme: str, accessKeys: {}, sharedItemsFederatedDomains: []) -> str: """Returns html content for the left column """ htmlStr = '' separatorStr = htmlPostSeparator(baseDir, 'left') domain = removeDomainPort(domainFull) editImageClass = '' if showHeaderImage: leftImageFile, leftColumnImageFilename = \ getLeftImageFile(baseDir, nickname, domain, theme) # show the image at the top of the column editImageClass = 'leftColEdit' if os.path.isfile(leftColumnImageFilename): editImageClass = 'leftColEditImage' htmlStr += \ '\n
\n \n' + \ '
\n' if showBackButton: htmlStr += \ '
' + \ '\n' if (editor or rssIconAtTop) and not showHeaderImage: htmlStr += '
' if editImageClass == 'leftColEdit': htmlStr += '\n
\n' htmlStr += '
\n' if editor: # show the edit icon htmlStr += \ ' ' + \ '' + \
            translate['Edit Links'] + ' | \n' if artist: # show the theme designer icon htmlStr += \ ' ' + \ '' + \
            translate['Theme Designer'] + ' | \n' # RSS icon if nickname != 'news': # rss feed for this account rssUrl = httpPrefix + '://' + domainFull + \ '/blog/' + nickname + '/rss.xml' else: # rss feed for all accounts on the instance rssUrl = httpPrefix + '://' + domainFull + '/blog/rss.xml' if not frontPage: rssTitle = translate['RSS feed for your blog'] else: rssTitle = translate['RSS feed for this site'] rssIconStr = \ ' ' + rssTitle + '\n' if rssIconAtTop: htmlStr += rssIconStr htmlStr += '
\n' if editImageClass == 'leftColEdit': htmlStr += '
\n' if (editor or rssIconAtTop) and not showHeaderImage: htmlStr += '

' # if showHeaderImage: # htmlStr += '
' # flag used not to show the first separator firstSeparatorAdded = False linksFilename = baseDir + '/accounts/links.txt' linksFileContainsEntries = False linksList = None if os.path.isfile(linksFilename): with open(linksFilename, 'r') as f: linksList = f.readlines() if not frontPage: # show a number of shares maxSharesInLeftColumn = 3 sharesList = \ _getLeftColumnShares(baseDir, httpPrefix, domain, domainFull, nickname, maxSharesInLeftColumn, translate, sharedItemsFederatedDomains) if linksList and sharesList: linksList = sharesList + linksList wantedList = \ _getLeftColumnWanted(baseDir, httpPrefix, domain, domainFull, nickname, maxSharesInLeftColumn, translate, sharedItemsFederatedDomains) if linksList and wantedList: linksList = wantedList + linksList newTabStr = ' target="_blank" rel="nofollow noopener noreferrer"' if linksList: htmlStr += '\n' if firstSeparatorAdded: htmlStr += separatorStr htmlStr += \ '

' + translate['Shares Catalog'] + '

' htmlStr += \ '

' + \ translate['Key Shortcuts'] + '

' htmlStr += \ '

' + \ translate['About this Instance'] + '

' htmlStr += \ '

' + \ translate['Terms of Service'] + '

' if linksFileContainsEntries and not rssIconAtTop: htmlStr += '
' + rssIconStr + '
' return htmlStr def htmlLinksMobile(cssCache: {}, baseDir: str, nickname: str, domainFull: str, httpPrefix: str, translate, timelinePath: str, authorized: bool, rssIconAtTop: bool, iconsAsButtons: bool, defaultTimeline: str, theme: str, accessKeys: {}, sharedItemsFederatedDomains: []) -> str: """Show the left column links within mobile view """ htmlStr = '' # the css filename cssFilename = baseDir + '/epicyon-profile.css' if os.path.isfile(baseDir + '/epicyon.css'): cssFilename = baseDir + '/epicyon.css' # is the user a site editor? if nickname == 'news': editor = False artist = False else: editor = isEditor(baseDir, nickname) artist = isArtist(baseDir, nickname) domain = removeDomainPort(domainFull) instanceTitle = \ getConfigParam(baseDir, 'instanceTitle') htmlStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle, None) bannerFile, bannerFilename = \ getBannerFile(baseDir, nickname, domain, theme) htmlStr += \ '' + \ '\n' htmlStr += '
\n' htmlStr += '
' + \ headerButtonsFrontScreen(translate, nickname, 'links', authorized, iconsAsButtons) + '
' htmlStr += \ getLeftColumnContent(baseDir, nickname, domainFull, httpPrefix, translate, editor, artist, False, timelinePath, rssIconAtTop, False, False, theme, accessKeys, sharedItemsFederatedDomains) if editor and not _linksExist(baseDir): htmlStr += '


\n
\n ' htmlStr += translate['Select the edit icon to add web links'] htmlStr += '\n
\n' # end of col-left-mobile htmlStr += '
\n' htmlStr += '
\n' + htmlFooter() return htmlStr def htmlEditLinks(cssCache: {}, translate: {}, baseDir: str, path: str, domain: str, port: int, httpPrefix: str, defaultTimeline: str, theme: str, accessKeys: {}) -> str: """Shows the edit links screen """ if '/users/' not in path: return '' path = path.replace('/inbox', '').replace('/outbox', '') path = path.replace('/shares', '').replace('/wanted', '') nickname = getNicknameFromActor(path) if not nickname: return '' # is the user a moderator? if not isEditor(baseDir, nickname): return '' cssFilename = baseDir + '/epicyon-links.css' if os.path.isfile(baseDir + '/links.css'): cssFilename = baseDir + '/links.css' # filename of the banner shown at the top bannerFile, bannerFilename = \ getBannerFile(baseDir, nickname, domain, theme) instanceTitle = \ getConfigParam(baseDir, 'instanceTitle') editLinksForm = \ htmlHeaderWithExternalStyle(cssFilename, instanceTitle, None) # top banner editLinksForm += \ '
\n' + \ '\n' editLinksForm += \ '\n' + \ '
\n' editLinksForm += \ '
\n' editLinksForm += \ '
\n' editLinksForm += \ '
\n' editLinksForm += \ '

' + translate['Edit Links'] + '

' editLinksForm += \ ' \n' editLinksForm += \ '
\n' linksFilename = baseDir + '/accounts/links.txt' linksStr = '' if os.path.isfile(linksFilename): with open(linksFilename, 'r') as fp: linksStr = fp.read() editLinksForm += \ '
' editLinksForm += \ ' ' + \ translate['One link per line. Description followed by the link.'] + \ '
' newColLinkStr = translate['New link title and URL'] editLinksForm += editTextField(None, 'newColLink', '', newColLinkStr) editLinksForm += \ ' ' editLinksForm += \ '
' # the admin can edit terms of service and about text adminNickname = getConfigParam(baseDir, 'admin') if adminNickname: if nickname == adminNickname: aboutFilename = baseDir + '/accounts/about.md' aboutStr = '' if os.path.isfile(aboutFilename): with open(aboutFilename, 'r') as fp: aboutStr = fp.read() editLinksForm += \ '
' editLinksForm += \ ' ' + \ translate['About this Instance'] + \ '
' editLinksForm += \ ' ' editLinksForm += \ '
' TOSFilename = baseDir + '/accounts/tos.md' TOSStr = '' if os.path.isfile(TOSFilename): with open(TOSFilename, 'r') as fp: TOSStr = fp.read() editLinksForm += \ '
' editLinksForm += \ ' ' + \ translate['Terms of Service'] + \ '
' editLinksForm += \ ' ' editLinksForm += \ '
' editLinksForm += htmlFooter() return editLinksForm